// Get the type kind of a symbol, going to candidates if possible. internal static TypeKind ExtractNonErrorTypeKind(TypeSymbol oldSymbol) { if (oldSymbol.TypeKind != TypeKind.Error) { return(oldSymbol.TypeKind); } // At this point, we know that oldSymbol is a non-null type symbol with kind error. // Hence, it is either an ErrorTypeSymbol or it has an ErrorTypeSymbol as its // original definition. In the former case, it is its own original definition. // Thus, if there's a CSErrorTypeSymbol in there somewhere, it's returned by // OriginalDefinition. ExtendedErrorTypeSymbol oldError = oldSymbol.OriginalDefinition as ExtendedErrorTypeSymbol; // If the original definition isn't a CSErrorTypeSymbol, then we don't know how to // pull out a non-error type. If it is, then if there is a unambiguous type inside it, // use that. TypeKind commonTypeKind = TypeKind.Error; if ((object)oldError != null && !oldError._candidateSymbols.IsDefault && oldError._candidateSymbols.Length > 0) { foreach (Symbol sym in oldError._candidateSymbols) { TypeSymbol type = sym as TypeSymbol; if ((object)type != null && type.TypeKind != TypeKind.Error) { if (commonTypeKind == TypeKind.Error) { commonTypeKind = type.TypeKind; } else if (commonTypeKind != type.TypeKind) { return(TypeKind.Error); // no common kind. } } } } return(commonTypeKind); }
private void ResolveBases(BaseListSyntax baseList, ConsList <TypeSymbol> newBasesBeingResolved, DiagnosticBag diagnostics, Binder baseBinder, ref NamedTypeSymbol localBase, ArrayBuilder <NamedTypeSymbol> localInterfaces) { int i = -1; var isExtendList = baseList is ExtendListSyntax; var isInterface = TypeKind == TypeKind.Interface; var isClassOrStruct = TypeKind == TypeKind.Class || TypeKind == TypeKind.Struct; foreach (var baseTypeSyntax in baseList.Types) { i++; var typeSyntax = baseTypeSyntax.Type; if (typeSyntax.Kind() != SyntaxKind.PredefinedType && !SyntaxFacts.IsName(typeSyntax.Kind())) { diagnostics.Add(ErrorCode.ERR_BadBaseType, typeSyntax.GetLocation()); } var location = new SourceLocation(typeSyntax); TypeSymbol baseType; if (i == 0 && isClassOrStruct && isExtendList) // allow class in the first position { baseType = baseBinder.BindType(typeSyntax, diagnostics, newBasesBeingResolved).TypeSymbol; if (baseType.TypeKind != TypeKind) { if (TypeKind == TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_NonStructBaseForStruct, location, baseType, this); continue; } else { diagnostics.Add(ErrorCode.ERR_NonClassBaseForClass, location, baseType, this); continue; } } SpecialType baseSpecialType = baseType.SpecialType; if (IsRestrictedBaseType(baseSpecialType)) { // check for one of the specific exceptions required for compiling mscorlib if (this.SpecialType == SpecialType.System_Enum || this.SpecialType == SpecialType.System_MulticastDelegate && baseSpecialType == SpecialType.System_Delegate) { // allowed } else if (baseSpecialType == SpecialType.System_Array && this.ContainingAssembly.CorLibrary == this.ContainingAssembly) { // Specific exception for System.ArrayContracts, which is only built when CONTRACTS_FULL is defined. // (See InheritanceResolver::CheckForBaseClassErrors). } else { // '{0}' cannot derive from special class '{1}' diagnostics.Add(ErrorCode.ERR_DeriveFromEnumOrValueType, Locations[0], baseType, this); continue; } } if (baseType.IsSealed && !this.IsStatic) // Give precedence to ERR_StaticDerivedFromNonObject { diagnostics.Add(ErrorCode.ERR_CantDeriveFromSealedType, Locations[0], baseType, this); continue; } // TODO: log error if base class is not struct/class bool baseTypeIsErrorWithoutInterfaceGuess = false; // If baseType is an error symbol and our best guess is that the desired symbol // is an interface, then put baseType in the interfaces list, rather than the // base type slot, to avoid the frustrating scenario where an error message // indicates that the symbol being returned as the base type was elsewhere // interpreted as an interface. if (baseType.TypeKind == TypeKind.Error) { baseTypeIsErrorWithoutInterfaceGuess = true; TypeKind guessTypeKind = baseType.GetNonErrorTypeKindGuess(); if (guessTypeKind == TypeKind.Interface) { //base type is an error *with* a guessed interface baseTypeIsErrorWithoutInterfaceGuess = false; } } if ((baseType.TypeKind == TypeKind.Class || baseType.TypeKind == TypeKind.Delegate || baseType.TypeKind == TypeKind.Struct || baseTypeIsErrorWithoutInterfaceGuess) && ((object)localBase == null)) { localBase = (NamedTypeSymbol)baseType; Debug.Assert((object)localBase != null); if (this.IsStatic && localBase.SpecialType != SpecialType.System_Object) { // Static class '{0}' cannot derive from type '{1}'. Static classes must derive from object. var info = diagnostics.Add(ErrorCode.ERR_StaticDerivedFromNonObject, location, this, localBase); localBase = new ExtendedErrorTypeSymbol(localBase, LookupResultKind.NotReferencable, info); } continue; } } else { baseType = baseBinder.BindType(typeSyntax, diagnostics, newBasesBeingResolved).TypeSymbol; } // if we have an interface and we have an implements list, this is invalid if (isInterface && !isExtendList) { diagnostics.Add(ErrorCode.ERR_InvalidImplementsForInterface, location, this, baseType); continue; } switch (baseType.TypeKind) { case TypeKind.Interface: // If we have an interface in a extend list of a class, this is not supported if (isClassOrStruct && isExtendList) { diagnostics.Add(ErrorCode.ERR_InvalidInterfaceInExtendList, location, baseType); } foreach (var t in localInterfaces) { if (TypeSymbol.Equals(t, baseType, TypeCompareKind.ConsiderEverything)) { diagnostics.Add(ErrorCode.ERR_DuplicateInterfaceInBaseList, location, baseType); } } if (this.IsStatic) { // '{0}': static classes cannot implement interfaces diagnostics.Add(ErrorCode.ERR_StaticClassInterfaceImpl, location, this, baseType); } if (this.IsRefLikeType) { // '{0}': ref structs cannot implement interfaces diagnostics.Add(ErrorCode.ERR_RefStructInterfaceImpl, location, this, baseType); } if (baseType.ContainsDynamic()) { diagnostics.Add(ErrorCode.ERR_DeriveFromConstructedDynamic, location, this, baseType); } localInterfaces.Add((NamedTypeSymbol)baseType); break; case TypeKind.Struct: if ((object)localBase != null) { if (isExtendList) { diagnostics.Add(ErrorCode.ERR_NoMultipleInheritance, location, this, localBase, baseType); break; } } diagnostics.Add(ErrorCode.ERR_NonInterfaceInImplementsList, location, baseType); break; case TypeKind.Class: if ((object)localBase != null) { if (isExtendList) { diagnostics.Add(ErrorCode.ERR_NoMultipleInheritance, location, this, localBase, baseType); break; } } diagnostics.Add(ErrorCode.ERR_NonInterfaceInImplementsList, location, baseType); break; case TypeKind.TypeParameter: diagnostics.Add(ErrorCode.ERR_DerivingFromATyVar, location, baseType); break; case TypeKind.Error: // put the error type in the interface list so we don't lose track of it localInterfaces.Add((NamedTypeSymbol)baseType); break; case TypeKind.Dynamic: diagnostics.Add(ErrorCode.ERR_DeriveFromDynamic, location, this); break; case TypeKind.Submission: throw ExceptionUtilities.UnexpectedValue(baseType.TypeKind); default: diagnostics.Add(ErrorCode.ERR_NonInterfaceInImplementsList, location, baseType); break; } } }
private Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > MakeDeclaredBases(ConsList <TypeSymbol> basesBeingResolved, DiagnosticBag diagnostics) { if (this.TypeKind == TypeKind.Enum) { // Handled by GetEnumUnderlyingType(). return(new Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> >(null, ImmutableArray <NamedTypeSymbol> .Empty)); } var reportedPartialConflict = false; Debug.Assert(basesBeingResolved == null || !basesBeingResolved.ContainsReference(this.OriginalDefinition)); var newBasesBeingResolved = basesBeingResolved.Prepend(this.OriginalDefinition); var baseInterfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance(); NamedTypeSymbol baseType = null; SourceLocation baseTypeLocation = null; var interfaceLocations = PooledDictionary <NamedTypeSymbol, SourceLocation> .GetInstance(); foreach (var decl in this.declaration.Declarations) { Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > one = MakeOneDeclaredBases(newBasesBeingResolved, decl, diagnostics); if ((object)one == null) { continue; } var partBase = one.Item1; var partInterfaces = one.Item2; if (!reportedPartialConflict) { if ((object)baseType == null) { baseType = partBase; baseTypeLocation = decl.NameLocation; } else if (baseType.TypeKind == TypeKind.Error && (object)partBase != null) { // if the old base was an error symbol, copy it to the interfaces list so it doesn't get lost partInterfaces = partInterfaces.Add(baseType); baseType = partBase; baseTypeLocation = decl.NameLocation; } else if ((object)partBase != null && !TypeSymbol.Equals(partBase, baseType, TypeCompareKind.ConsiderEverything2) && partBase.TypeKind != TypeKind.Error) { // the parts do not agree var info = diagnostics.Add(ErrorCode.ERR_PartialMultipleBases, Locations[0], this); baseType = new ExtendedErrorTypeSymbol(baseType, LookupResultKind.Ambiguous, info); baseTypeLocation = decl.NameLocation; reportedPartialConflict = true; } } foreach (var t in partInterfaces) { if (!interfaceLocations.ContainsKey(t)) { baseInterfaces.Add(t); interfaceLocations.Add(t, decl.NameLocation); } } } HashSet <DiagnosticInfo> useSiteDiagnostics = null; if ((object)baseType != null) { Debug.Assert(baseTypeLocation != null); if (baseType.IsStatic) { // '{1}': cannot derive from static class '{0}' diagnostics.Add(ErrorCode.ERR_StaticBaseClass, baseTypeLocation, baseType, this); } if (!this.IsNoMoreVisibleThan(baseType, ref useSiteDiagnostics)) { // Inconsistent accessibility: base class '{1}' is less accessible than class '{0}' diagnostics.Add(ErrorCode.ERR_BadVisBaseClass, baseTypeLocation, this, baseType); } } var baseInterfacesRO = baseInterfaces.ToImmutableAndFree(); if (DeclaredAccessibility != Accessibility.Private && IsInterface) { foreach (var i in baseInterfacesRO) { if (!i.IsAtLeastAsVisibleAs(this, ref useSiteDiagnostics)) { // Inconsistent accessibility: base interface '{1}' is less accessible than interface '{0}' diagnostics.Add(ErrorCode.ERR_BadVisBaseInterface, interfaceLocations[i], this, i); } } } interfaceLocations.Free(); diagnostics.Add(Locations[0], useSiteDiagnostics); return(new Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> >(baseType, baseInterfacesRO)); }
/// <summary> /// If the extension method is applicable based on the "this" argument type, return /// the method constructed with the inferred type arguments. If the method is not an /// unconstructed generic method, type inference is skipped. If the method is not /// applicable, or if constraints when inferring type parameters from the "this" type /// are not satisfied, the return value is null. /// </summary> public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol method, TypeSymbol thisType, Compilation compilation, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(method.IsExtensionMethod); Debug.Assert((object)thisType != null); if (!method.IsGenericMethod || method != method.ConstructedFrom) { return(method); } // We never resolve extension methods on a dynamic receiver. if (thisType.IsDynamic()) { return(null); } var containingAssembly = method.ContainingAssembly; var errorNamespace = containingAssembly.GlobalNamespace; var conversions = new TypeConversions(containingAssembly.CorLibrary); // There is absolutely no plausible syntax/tree that we could use for these // synthesized literals. We could be speculatively binding a call to a PE method. var syntaxTree = CSharpSyntaxTree.Dummy; var syntax = (CSharpSyntaxNode)syntaxTree.GetRoot(); // Create an argument value for the "this" argument of specific type, // and pass the same bad argument value for all other arguments. var thisArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, thisType) { WasCompilerGenerated = true }; var otherArgumentType = new ExtendedErrorTypeSymbol(errorNamespace, name: string.Empty, arity: 0, errorInfo: null, unreported: false); var otherArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, otherArgumentType) { WasCompilerGenerated = true }; var paramCount = method.ParameterCount; var arguments = new BoundExpression[paramCount]; for (int i = 0; i < paramCount; i++) { var argument = (i == 0) ? thisArgumentValue : otherArgumentValue; arguments[i] = argument; } var typeArgs = MethodTypeInferrer.InferTypeArgumentsFromFirstArgument( conversions, method, arguments.AsImmutable(), useSiteDiagnostics: ref useSiteDiagnostics); if (typeArgs.IsDefault) { return(null); } int firstNullInTypeArgs = -1; // For the purpose of constraint checks we use error type symbol in place of type arguments that we couldn't infer from the first argument. // This prevents constraint checking from failing for corresponding type parameters. var notInferredTypeParameters = PooledHashSet <TypeParameterSymbol> .GetInstance(); var typeParams = method.TypeParameters; var typeArgsForConstraintsCheck = typeArgs; for (int i = 0; i < typeArgsForConstraintsCheck.Length; i++) { if (typeArgsForConstraintsCheck[i].IsNull) { firstNullInTypeArgs = i; var builder = ArrayBuilder <TypeSymbolWithAnnotations> .GetInstance(); builder.AddRange(typeArgsForConstraintsCheck, firstNullInTypeArgs); for (; i < typeArgsForConstraintsCheck.Length; i++) { var typeArg = typeArgsForConstraintsCheck[i]; if (typeArg.IsNull) { notInferredTypeParameters.Add(typeParams[i]); builder.Add(TypeSymbolWithAnnotations.Create(ErrorTypeSymbol.UnknownResultType)); } else { builder.Add(typeArg); } } typeArgsForConstraintsCheck = builder.ToImmutableAndFree(); break; } } // Check constraints. var diagnosticsBuilder = ArrayBuilder <TypeParameterDiagnosticInfo> .GetInstance(); var substitution = new TypeMap(typeParams, typeArgsForConstraintsCheck); ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null; var success = method.CheckConstraints(conversions, substitution, typeParams, typeArgsForConstraintsCheck, compilation, diagnosticsBuilder, warningsBuilderOpt: null, ref useSiteDiagnosticsBuilder, ignoreTypeConstraintsDependentOnTypeParametersOpt: notInferredTypeParameters.Count > 0 ? notInferredTypeParameters : null); diagnosticsBuilder.Free(); notInferredTypeParameters.Free(); if (useSiteDiagnosticsBuilder != null && useSiteDiagnosticsBuilder.Count > 0) { if (useSiteDiagnostics == null) { useSiteDiagnostics = new HashSet <DiagnosticInfo>(); } foreach (var diag in useSiteDiagnosticsBuilder) { useSiteDiagnostics.Add(diag.DiagnosticInfo); } } if (!success) { return(null); } // For the purpose of construction we use original type parameters in place of type arguments that we couldn't infer from the first argument. var typeArgsForConstruct = typeArgs; if (firstNullInTypeArgs != -1) { var builder = ArrayBuilder <TypeSymbolWithAnnotations> .GetInstance(); builder.AddRange(typeArgs, firstNullInTypeArgs); for (int i = firstNullInTypeArgs; i < typeArgsForConstruct.Length; i++) { var typeArgForConstruct = typeArgsForConstruct[i]; builder.Add(!typeArgForConstruct.IsNull ? typeArgForConstruct : TypeSymbolWithAnnotations.Create(typeParams[i])); } typeArgsForConstruct = builder.ToImmutableAndFree(); } return(method.Construct(typeArgsForConstruct)); }