private bool UsesIsNullable(TypeSymbol type, ConsList <TypeParameterSymbol> inProgress) { if (type is null) { return(false); } switch (type.TypeKind) { case TypeKind.Class: case TypeKind.Delegate: case TypeKind.Interface: case TypeKind.Struct: case TypeKind.Enum: if (UsesIsNullable(type.ContainingType, inProgress)) { return(true); } break; } switch (type.TypeKind) { case TypeKind.Array: return(UsesIsNullable(((ArrayTypeSymbol)type).ElementType, inProgress)); case TypeKind.Class: case TypeKind.Delegate: case TypeKind.Error: case TypeKind.Interface: case TypeKind.Struct: return(UsesIsNullable(((NamedTypeSymbol)type).TypeArgumentsNoUseSiteDiagnostics, inProgress)); case TypeKind.Dynamic: case TypeKind.Enum: return(false); case TypeKind.Pointer: return(UsesIsNullable(((PointerTypeSymbol)type).PointedAtType, inProgress)); case TypeKind.TypeParameter: var typeParameter = (TypeParameterSymbol)type; if (inProgress?.ContainsReference(typeParameter) == true) { return(false); } inProgress = inProgress ?? ConsList <TypeParameterSymbol> .Empty; inProgress = inProgress.Prepend(typeParameter); return(UsesIsNullable(typeParameter.ConstraintTypesNoUseSiteDiagnostics, inProgress) || typeParameter.ReferenceTypeConstraintIsNullable == true); default: throw ExceptionUtilities.UnexpectedValue(type.TypeKind); } }
private bool CheckStruct(ConsList<NamedTypeSymbol> typesWithMembersOfThisType, NamedTypeSymbol nts) { // Break recursive cycles. If we find a member that contains us, it is considered empty if (!typesWithMembersOfThisType.ContainsReference(nts)) { // Remember that we're in the process of doing this type while checking members. typesWithMembersOfThisType = new ConsList<NamedTypeSymbol>(nts, typesWithMembersOfThisType); return CheckStructInstanceFields(typesWithMembersOfThisType, nts); } return true; }
internal override TypeSymbol GetFieldType(ConsList<FieldSymbol> fieldsBeingBound) { Debug.Assert(fieldsBeingBound != null); if ((object)_lazyType != null) { return _lazyType; } var typeSyntax = TypeSyntax; var compilation = this.DeclaringCompilation; var diagnostics = DiagnosticBag.GetInstance(); TypeSymbol type; var binderFactory = compilation.GetBinderFactory(SyntaxTree); var binder = binderFactory.GetBinder(typeSyntax); bool isVar; type = binder.BindType(typeSyntax, diagnostics, out isVar); Debug.Assert((object)type != null || isVar); if (isVar && !fieldsBeingBound.ContainsReference(this)) { InferFieldType(fieldsBeingBound, binder); Debug.Assert((object)_lazyType != null); } else { if (isVar) { diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this); type = binder.CreateErrorType("var"); } SetType(compilation, diagnostics, type); } diagnostics.Free(); return _lazyType; }
/// <summary> /// Gets the set of interfaces that this type directly implements. This set does not include /// interfaces that are base interfaces of directly implemented interfaces. /// </summary> internal sealed override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList<Symbol> basesBeingResolved) { if (_lazyInterfaces.IsDefault) { if (basesBeingResolved != null && basesBeingResolved.ContainsReference(this.OriginalDefinition)) { return ImmutableArray<NamedTypeSymbol>.Empty; } var diagnostics = DiagnosticBag.GetInstance(); var acyclicInterfaces = MakeAcyclicInterfaces(basesBeingResolved, diagnostics); if (ImmutableInterlocked.InterlockedCompareExchange(ref _lazyInterfaces, acyclicInterfaces, default(ImmutableArray<NamedTypeSymbol>)).IsDefault) { AddDeclarationDiagnostics(diagnostics); } diagnostics.Free(); } return _lazyInterfaces; }
private TypeParameterBounds GetBounds(ConsList<TypeParameterSymbol> inProgress) { Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); if (ReferenceEquals(_lazyBounds, TypeParameterBounds.Unset)) { var diagnostics = DiagnosticBag.GetInstance(); var bounds = this.ResolveBounds(inProgress, diagnostics); if (ReferenceEquals(Interlocked.CompareExchange(ref _lazyBounds, bounds, TypeParameterBounds.Unset), TypeParameterBounds.Unset)) { this.CheckConstraintTypeConstraints(diagnostics); this.AddDeclarationDiagnostics(diagnostics); _state.NotePartComplete(CompletionPart.TypeParameterConstraints); } diagnostics.Free(); } return _lazyBounds; }
private static TypeSymbol GetNextDeclaredBase(NamedTypeSymbol type, ConsList<Symbol> basesBeingResolved, CSharpCompilation compilation, ref PooledHashSet<NamedTypeSymbol> visited) { // We shouldn't have visited this type earlier. Debug.Assert(visited == null || !visited.Contains(type.OriginalDefinition)); if (basesBeingResolved != null && basesBeingResolved.ContainsReference(type.OriginalDefinition)) { return null; } if (type.SpecialType == SpecialType.System_Object) { type.SetKnownToHaveNoDeclaredBaseCycles(); return null; } var nextType = type.GetDeclaredBaseType(basesBeingResolved); // types with no declared bases inherit object's members if ((object)nextType == null) { SetKnownToHaveNoDeclaredBaseCycles(ref visited); return GetDefaultBaseOrNull(type, compilation); } var origType = type.OriginalDefinition; if (nextType.KnownToHaveNoDeclaredBaseCycles) { origType.SetKnownToHaveNoDeclaredBaseCycles(); SetKnownToHaveNoDeclaredBaseCycles(ref visited); } else { // start cycle tracking visited = visited ?? PooledHashSet<NamedTypeSymbol>.GetInstance(); visited.Add(origType); if (visited.Contains(nextType.OriginalDefinition)) { return GetDefaultBaseOrNull(type, compilation); } } return nextType; }
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 = SpecializedSymbolCollections.GetPooledSymbolDictionaryInstance <NamedTypeSymbol, SourceLocation>(); 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 (declaration.Kind == DeclarationKind.Record) { var type = DeclaringCompilation.GetWellKnownType(WellKnownType.System_IEquatable_T).Construct(this); if (baseInterfaces.IndexOf(type, SymbolEqualityComparer.AllIgnoreOptions) < 0) { baseInterfaces.Add(type); type.AddUseSiteDiagnostics(ref useSiteDiagnostics); } } 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)); }
internal sealed override TypeSymbol GetFieldType(ConsList <FieldSymbol> fieldsBeingBound) { Debug.Assert(fieldsBeingBound != null); if ((object)lazyType != null) { return(lazyType); } var declarator = VariableDeclaratorNode; var fieldSyntax = GetFieldDeclaration(declarator); var typeSyntax = fieldSyntax.Declaration.Type; var compilation = this.DeclaringCompilation; var diagnostics = DiagnosticBag.GetInstance(); TypeSymbol type; // When we have multiple declarators, we report the type diagnostics on only the first. DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance(); Symbol associatedPropertyOrEvent = this.AssociatedSymbol; if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event) { EventSymbol @event = (EventSymbol)associatedPropertyOrEvent; if (@event.IsWindowsRuntimeEvent) { NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T); Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.Location); // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T> // type that has additional generic constraints? type = tokenTableType.Construct(@event.Type); } else { type = @event.Type; } } else { var binderFactory = compilation.GetBinderFactory(SyntaxTree); var binder = binderFactory.GetBinder(typeSyntax); binder = binder.WithContainingMemberOrLambda(this); if (!ContainingType.IsScriptClass) { type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator); if (IsFixed) { type = new PointerTypeSymbol(type); } } else { bool isVar; type = binder.BindType(typeSyntax, diagnostics, out isVar); Debug.Assert((object)type != null || isVar); if (isVar) { if (this.IsConst) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location); } if (fieldsBeingBound.ContainsReference(this)) { diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.Location, this); type = null; } else if (fieldSyntax.Declaration.Variables.Count > 1) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location); } else { fieldsBeingBound = new ConsList <FieldSymbol>(this, fieldsBeingBound); var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound); var initializerOpt = initializerBinder.BindInferredVariableInitializer(diagnostics, declarator.Initializer, declarator); if (initializerOpt != null) { if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType()) { type = initializerOpt.Type; } this.lazyFieldTypeInferred = 1; } } if ((object)type == null) { type = binder.CreateErrorType("var"); } } } if (IsFixed) { if (ContainingType.TypeKind != TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, Location); } if (IsStatic) { diagnostics.Add(ErrorCode.ERR_BadMemberFlag, Location, SyntaxFacts.GetText(SyntaxKind.StaticKeyword)); } if (IsVolatile) { diagnostics.Add(ErrorCode.ERR_BadMemberFlag, Location, SyntaxFacts.GetText(SyntaxKind.VolatileKeyword)); } var elementType = ((PointerTypeSymbol)type).PointedAtType; int elementSize = elementType.FixedBufferElementSizeInBytes(); if (elementSize == 0) { var loc = typeSyntax.Location; diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc); } if (!binder.InUnsafeRegion) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location); } } } // update the lazyType only if it contains value last seen by the current thread: if ((object)Interlocked.CompareExchange(ref lazyType, type, null) == null) { TypeChecks(type, fieldSyntax, declarator, diagnostics); // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics. compilation.SemanticDiagnostics.AddRange(diagnostics); bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator; if (isFirstDeclarator) { compilation.SemanticDiagnostics.AddRange(diagnosticsForFirstDeclarator); } state.NotePartComplete(CompletionPart.Type); } diagnostics.Free(); diagnosticsForFirstDeclarator.Free(); return(lazyType); }
internal sealed override TypeSymbolWithAnnotations GetFieldType(ConsList <FieldSymbol> fieldsBeingBound) { Debug.Assert(fieldsBeingBound != null); if (!_lazyType.IsNull) { return(_lazyType.ToType()); } var declarator = VariableDeclaratorNode; var fieldSyntax = GetFieldDeclaration(declarator); var typeSyntax = fieldSyntax.Declaration.Type; var compilation = this.DeclaringCompilation; var diagnostics = DiagnosticBag.GetInstance(); TypeSymbolWithAnnotations type; // When we have multiple declarators, we report the type diagnostics on only the first. DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance(); Symbol associatedPropertyOrEvent = this.AssociatedSymbol; if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event) { EventSymbol @event = (EventSymbol)associatedPropertyOrEvent; if (@event.IsWindowsRuntimeEvent) { NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T); Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation); // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T> // type that has additional generic constraints? type = TypeSymbolWithAnnotations.Create(tokenTableType.Construct(ImmutableArray.Create(@event.Type))); } else { type = @event.Type; } } else { var binderFactory = compilation.GetBinderFactory(SyntaxTree); var binder = binderFactory.GetBinder(typeSyntax); binder = binder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); if (!ContainingType.IsScriptClass) { type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator); } else { bool isVar; type = binder.BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar); Debug.Assert(!type.IsNull || isVar); if (isVar) { if (this.IsConst) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location); } if (fieldsBeingBound.ContainsReference(this)) { diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this); type = default; } else if (fieldSyntax.Declaration.Variables.Count > 1) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location); } else if (this.IsConst && this.ContainingType.IsScriptClass) { // For const var in script, we won't try to bind the initializer (case below), as it can lead to an unbound recursion type = default; } else { fieldsBeingBound = new ConsList <FieldSymbol>(this, fieldsBeingBound); var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound); var initializerOpt = initializerBinder.BindInferredVariableInitializer(diagnostics, RefKind.None, (EqualsValueClauseSyntax)declarator.Initializer, declarator); if (initializerOpt != null) { if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType()) { type = TypeSymbolWithAnnotations.Create(initializerOpt.Type); } _lazyFieldTypeInferred = 1; } } if (type.IsNull) { type = TypeSymbolWithAnnotations.Create(binder.CreateErrorType("var")); } } } if (IsFixedSizeBuffer) { type = TypeSymbolWithAnnotations.Create(new PointerTypeSymbol(type)); if (ContainingType.TypeKind != TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, ErrorLocation); } var elementType = ((PointerTypeSymbol)type.TypeSymbol).PointedAtType.TypeSymbol; int elementSize = elementType.FixedBufferElementSizeInBytes(); if (elementSize == 0) { var loc = typeSyntax.Location; diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc); } if (!binder.InUnsafeRegion) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location); } } } // update the lazyType only if it contains value last seen by the current thread: if (_lazyType.InterlockedInitialize(type.WithModifiers(this.RequiredCustomModifiers))) { TypeChecks(type.TypeSymbol, diagnostics); // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics. compilation.DeclarationDiagnostics.AddRange(diagnostics); bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator; if (isFirstDeclarator) { compilation.DeclarationDiagnostics.AddRange(diagnosticsForFirstDeclarator); } state.NotePartComplete(CompletionPart.Type); } diagnostics.Free(); diagnosticsForFirstDeclarator.Free(); return(_lazyType.ToType()); }
private Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol>, ImmutableArray <NamedTypeSymbol> > MakeDeclaredBases(ConsList <Symbol> basesBeingResolved, DiagnosticBag diagnostics) { if (this.TypeKind == TypeKind.Enum) { // Handled by GetEnumUnderlyingType(). return(Tuple.Create((NamedTypeSymbol)null, ImmutableArray <NamedTypeSymbol> .Empty, 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(); var interfaceLocations = PooledDictionary <NamedTypeSymbol, SourceLocation> .GetInstance(); var baseConcepts = ArrayBuilder <NamedTypeSymbol> .GetInstance(); var conceptLocations = PooledDictionary <NamedTypeSymbol, SourceLocation> .GetInstance(); NamedTypeSymbol baseType = null; SourceLocation baseTypeLocation = null; foreach (var decl in this.declaration.Declarations) { var one = MakeOneDeclaredBases(newBasesBeingResolved, decl, diagnostics); if (!one.HasValue) { continue; } (var partBase, var partInterfaces, var partConcepts) = one.Value; 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 && partBase != baseType && 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); } } foreach (var t in partConcepts) { if (!conceptLocations.ContainsKey(t)) { baseConcepts.Add(t); conceptLocations.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(); conceptLocations.Free(); diagnostics.Add(Locations[0], useSiteDiagnostics); return(Tuple.Create(baseType, baseInterfacesRO, baseConcepts.ToImmutableAndFree())); }
private TypeParameterBounds GetBounds(ConsList<TypeParameterSymbol> inProgress) { Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); if (ReferenceEquals(_lazyBounds, TypeParameterBounds.Unset)) { var constraintTypes = GetDeclaredConstraintTypes(); Debug.Assert(!constraintTypes.IsDefault); var diagnostics = ArrayBuilder<TypeParameterDiagnosticInfo>.GetInstance(); ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null; bool inherited = (_containingSymbol.Kind == SymbolKind.Method) && ((MethodSymbol)_containingSymbol).IsOverride; var bounds = this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited, currentCompilation: null, diagnosticsBuilder: diagnostics, useSiteDiagnosticsBuilder: ref useSiteDiagnosticsBuilder); DiagnosticInfo errorInfo = null; if (diagnostics.Count > 0) { errorInfo = diagnostics[0].DiagnosticInfo; } else if (useSiteDiagnosticsBuilder != null && useSiteDiagnosticsBuilder.Count > 0) { foreach (var diag in useSiteDiagnosticsBuilder) { if (diag.DiagnosticInfo.Severity == DiagnosticSeverity.Error) { errorInfo = diag.DiagnosticInfo; break; } else if ((object)errorInfo == null) { errorInfo = diag.DiagnosticInfo; } } } diagnostics.Free(); Interlocked.CompareExchange(ref _lazyBoundsErrorInfo, errorInfo, CSDiagnosticInfo.EmptyErrorInfo); Interlocked.CompareExchange(ref _lazyBounds, bounds, TypeParameterBounds.Unset); } Debug.Assert(!ReferenceEquals(_lazyBoundsErrorInfo, CSDiagnosticInfo.EmptyErrorInfo)); return _lazyBounds; }
// Based on SymbolLoader::ResolveBounds. public static TypeParameterBounds ResolveBounds( this TypeParameterSymbol typeParameter, AssemblySymbol corLibrary, ConsList <TypeParameterSymbol> inProgress, ImmutableArray <TypeSymbol> constraintTypes, bool inherited, CSharpCompilation currentCompilation, ArrayBuilder <TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder) { Debug.Assert(currentCompilation == null || typeParameter.IsFromCompilation(currentCompilation)); ImmutableArray <NamedTypeSymbol> interfaces; NamedTypeSymbol effectiveBaseClass = corLibrary.GetSpecialType(typeParameter.HasValueTypeConstraint ? SpecialType.System_ValueType : SpecialType.System_Object); TypeSymbol deducedBaseType = effectiveBaseClass; DynamicTypeEraser dynamicEraser = null; if (constraintTypes.Length == 0) { interfaces = ImmutableArray <NamedTypeSymbol> .Empty; } else { var constraintTypesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(); var interfacesBuilder = ArrayBuilder <NamedTypeSymbol> .GetInstance(); var conversions = new TypeConversions(corLibrary); HashSet <DiagnosticInfo> useSiteDiagnostics = null; // Resolve base types, determine the effective base class and // interfaces, and filter out any constraint types that cause cycles. foreach (var constraintType in constraintTypes) { NamedTypeSymbol constraintEffectiveBase; TypeSymbol constraintDeducedBase; switch (constraintType.TypeKind) { case TypeKind.Dynamic: Debug.Assert(inherited || currentCompilation == null); continue; case TypeKind.TypeParameter: { var containingSymbol = typeParameter.ContainingSymbol; var constraintTypeParameter = (TypeParameterSymbol)constraintType; ConsList <TypeParameterSymbol> constraintsInProgress; if (constraintTypeParameter.ContainingSymbol == containingSymbol) { // The constraint type parameter is from the same containing type or method. if (inProgress.ContainsReference(constraintTypeParameter)) { // "Circular constraint dependency involving '{0}' and '{1}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(constraintTypeParameter, new CSDiagnosticInfo(ErrorCode.ERR_CircularConstraint, constraintTypeParameter, typeParameter))); continue; } constraintsInProgress = inProgress; } else { // The constraint type parameter is from a different containing symbol so no cycle. constraintsInProgress = ConsList <TypeParameterSymbol> .Empty; } // Use the calculated bounds from the constraint type parameter. constraintEffectiveBase = constraintTypeParameter.GetEffectiveBaseClass(constraintsInProgress); constraintDeducedBase = constraintTypeParameter.GetDeducedBaseType(constraintsInProgress); AddInterfaces(interfacesBuilder, constraintTypeParameter.GetInterfaces(constraintsInProgress)); if (constraintTypeParameter.HasValueTypeConstraint && !inherited && currentCompilation != null && constraintTypeParameter.IsFromCompilation(currentCompilation)) { // "Type parameter '{1}' has the 'struct' constraint so '{1}' cannot be used as a constraint for '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ConWithValCon, typeParameter, constraintTypeParameter))); continue; } } break; case TypeKind.Interface: case TypeKind.Class: case TypeKind.Delegate: NamedTypeSymbol erasedConstraintType; if (inherited || currentCompilation == null) { // only inherited constraints may contain dynamic if (dynamicEraser == null) { dynamicEraser = new DynamicTypeEraser(corLibrary.GetSpecialType(SpecialType.System_Object)); } erasedConstraintType = (NamedTypeSymbol)dynamicEraser.EraseDynamic(constraintType); } else { Debug.Assert(!constraintType.ContainsDynamic()); Debug.Assert(constraintType.TypeKind != TypeKind.Delegate); erasedConstraintType = (NamedTypeSymbol)constraintType; } if (constraintType.IsInterfaceType()) { AddInterface(interfacesBuilder, erasedConstraintType); constraintTypesBuilder.Add(constraintType); continue; } else { constraintEffectiveBase = erasedConstraintType; constraintDeducedBase = constraintType; break; } case TypeKind.Struct: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_ValueType); constraintDeducedBase = constraintType; break; case TypeKind.Enum: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_Enum); constraintDeducedBase = constraintType; break; case TypeKind.Array: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_Array); constraintDeducedBase = constraintType; break; case TypeKind.Error: constraintEffectiveBase = (NamedTypeSymbol)constraintType; constraintDeducedBase = constraintType; break; case TypeKind.Submission: default: throw ExceptionUtilities.UnexpectedValue(constraintType.TypeKind); } CheckEffectiveAndDeducedBaseTypes(conversions, constraintEffectiveBase, constraintDeducedBase); constraintTypesBuilder.Add(constraintType); // Determine the more encompassed of the current effective base // class and the previously computed effective base class. if (!deducedBaseType.IsErrorType() && !constraintDeducedBase.IsErrorType()) { if (!IsEncompassedBy(conversions, deducedBaseType, constraintDeducedBase, ref useSiteDiagnostics)) { if (!IsEncompassedBy(conversions, constraintDeducedBase, deducedBaseType, ref useSiteDiagnostics)) { // "Type parameter '{0}' inherits conflicting constraints '{1}' and '{2}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BaseConstraintConflict, typeParameter, constraintDeducedBase, deducedBaseType))); } else { deducedBaseType = constraintDeducedBase; effectiveBaseClass = constraintEffectiveBase; } } } } AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder); CheckEffectiveAndDeducedBaseTypes(conversions, effectiveBaseClass, deducedBaseType); constraintTypes = constraintTypesBuilder.ToImmutableAndFree(); interfaces = interfacesBuilder.ToImmutableAndFree(); } Debug.Assert((effectiveBaseClass.SpecialType == SpecialType.System_Object) || (deducedBaseType.SpecialType != SpecialType.System_Object)); // Only create a TypeParameterBounds instance for this type // parameter if the bounds are not the default values. if ((constraintTypes.Length == 0) && (deducedBaseType.SpecialType == SpecialType.System_Object)) { Debug.Assert(effectiveBaseClass.SpecialType == SpecialType.System_Object); Debug.Assert(interfaces.Length == 0); return(null); } var bounds = new TypeParameterBounds(constraintTypes, interfaces, effectiveBaseClass, deducedBaseType); // Additional constraint checks for overrides. if (inherited) { CheckOverrideConstraints(typeParameter, bounds, diagnosticsBuilder); } return(bounds); }
private Tuple<NamedTypeSymbol, ImmutableArray<NamedTypeSymbol>> MakeDeclaredBases(ConsList<Symbol> 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; 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; } 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; } else if ((object)partBase != null && partBase != baseType && 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); reportedPartialConflict = true; } } int n = baseInterfaces.Count; foreach (var t in partInterfaces) // this could probably be done more efficiently with a side hash table if it proves necessary { for (int i = 0; i < n; i++) { if (t == baseInterfaces[i]) { goto alreadyInInterfaceList; } } baseInterfaces.Add(t); alreadyInInterfaceList:; } } if ((object)baseType != null && baseType.IsStatic) { // '{1}': cannot derive from static class '{0}' diagnostics.Add(ErrorCode.ERR_StaticBaseClass, Locations[0], baseType, this); } HashSet<DiagnosticInfo> useSiteDiagnostics = null; if ((object)baseType != null && !this.IsNoMoreVisibleThan(baseType, ref useSiteDiagnostics)) { // Inconsistent accessibility: base class '{1}' is less accessible than class '{0}' diagnostics.Add(ErrorCode.ERR_BadVisBaseClass, Locations[0], 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, Locations[0], this, i); } } } diagnostics.Add(Locations[0], useSiteDiagnostics); return new Tuple<NamedTypeSymbol, ImmutableArray<NamedTypeSymbol>>(baseType, baseInterfacesRO); }
private Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > MakeDeclaredBases(ConsList <TypeSymbol> basesBeingResolved, BindingDiagnosticBag 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 = SpecializedSymbolCollections.GetPooledSymbolDictionaryInstance <NamedTypeSymbol, SourceLocation>(); 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.ConsiderEverything) && partBase.TypeKind != TypeKind.Error) { // the parts do not agree if (partBase.Equals(baseType, TypeCompareKind.ObliviousNullableModifierMatchesAny)) { if (containsOnlyOblivious(baseType)) { baseType = partBase; baseTypeLocation = decl.NameLocation; continue; } else if (containsOnlyOblivious(partBase)) { continue; } } var info = diagnostics.Add(ErrorCode.ERR_PartialMultipleBases, Locations[0], this); baseType = new ExtendedErrorTypeSymbol(baseType, LookupResultKind.Ambiguous, info); baseTypeLocation = decl.NameLocation; reportedPartialConflict = true;
private Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > MakeDeclaredBases(ConsList <Symbol> 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; 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; } 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; } else if ((object)partBase != null && partBase != baseType && 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); reportedPartialConflict = true; } } int n = baseInterfaces.Count; foreach (var t in partInterfaces) // this could probably be done more efficiently with a side hash table if it proves necessary { for (int i = 0; i < n; i++) { if (t == baseInterfaces[i]) { goto alreadyInInterfaceList; } } baseInterfaces.Add(t); alreadyInInterfaceList :; } } if ((object)baseType != null && baseType.IsStatic) { // '{1}': cannot derive from static class '{0}' diagnostics.Add(ErrorCode.ERR_StaticBaseClass, Locations[0], baseType, this); } HashSet <DiagnosticInfo> useSiteDiagnostics = null; if ((object)baseType != null && !this.IsNoMoreVisibleThan(baseType, ref useSiteDiagnostics)) { // Inconsistent accessibility: base class '{1}' is less accessible than class '{0}' diagnostics.Add(ErrorCode.ERR_BadVisBaseClass, Locations[0], 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, Locations[0], this, i); } } } diagnostics.Add(Locations[0], useSiteDiagnostics); return(new Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> >(baseType, baseInterfacesRO)); }
// Based on SymbolLoader::ResolveBounds. public static TypeParameterBounds ResolveBounds( this TypeParameterSymbol typeParameter, AssemblySymbol corLibrary, ConsList<TypeParameterSymbol> inProgress, ImmutableArray<TypeSymbol> constraintTypes, bool inherited, CSharpCompilation currentCompilation, ArrayBuilder<TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder) { Debug.Assert(currentCompilation == null || typeParameter.IsFromCompilation(currentCompilation)); ImmutableArray<NamedTypeSymbol> interfaces; NamedTypeSymbol effectiveBaseClass = corLibrary.GetSpecialType(typeParameter.HasValueTypeConstraint ? SpecialType.System_ValueType : SpecialType.System_Object); TypeSymbol deducedBaseType = effectiveBaseClass; DynamicTypeEraser dynamicEraser = null; if (constraintTypes.Length == 0) { interfaces = ImmutableArray<NamedTypeSymbol>.Empty; } else { var constraintTypesBuilder = ArrayBuilder<TypeSymbol>.GetInstance(); var interfacesBuilder = ArrayBuilder<NamedTypeSymbol>.GetInstance(); var conversions = new TypeConversions(corLibrary); HashSet<DiagnosticInfo> useSiteDiagnostics = null; // Resolve base types, determine the effective base class and // interfaces, and filter out any constraint types that cause cycles. foreach (var constraintType in constraintTypes) { NamedTypeSymbol constraintEffectiveBase; TypeSymbol constraintDeducedBase; switch (constraintType.TypeKind) { case TypeKind.Dynamic: Debug.Assert(inherited || currentCompilation == null); continue; case TypeKind.TypeParameter: { var containingSymbol = typeParameter.ContainingSymbol; var constraintTypeParameter = (TypeParameterSymbol)constraintType; ConsList<TypeParameterSymbol> constraintsInProgress; if (constraintTypeParameter.ContainingSymbol == containingSymbol) { // The constraint type parameter is from the same containing type or method. if (inProgress.ContainsReference(constraintTypeParameter)) { // "Circular constraint dependency involving '{0}' and '{1}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(constraintTypeParameter, new CSDiagnosticInfo(ErrorCode.ERR_CircularConstraint, constraintTypeParameter, typeParameter))); continue; } constraintsInProgress = inProgress; } else { // The constraint type parameter is from a different containing symbol so no cycle. constraintsInProgress = ConsList<TypeParameterSymbol>.Empty; } // Use the calculated bounds from the constraint type parameter. constraintEffectiveBase = constraintTypeParameter.GetEffectiveBaseClass(constraintsInProgress); constraintDeducedBase = constraintTypeParameter.GetDeducedBaseType(constraintsInProgress); AddInterfaces(interfacesBuilder, constraintTypeParameter.GetInterfaces(constraintsInProgress)); if (constraintTypeParameter.HasValueTypeConstraint && !inherited && currentCompilation != null && constraintTypeParameter.IsFromCompilation(currentCompilation)) { // "Type parameter '{1}' has the 'struct' constraint so '{1}' cannot be used as a constraint for '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ConWithValCon, typeParameter, constraintTypeParameter))); continue; } } break; case TypeKind.Interface: case TypeKind.Class: case TypeKind.Delegate: NamedTypeSymbol erasedConstraintType; if (inherited || currentCompilation == null) { // only inherited constraints may contain dynamic if (dynamicEraser == null) { dynamicEraser = new DynamicTypeEraser(corLibrary.GetSpecialType(SpecialType.System_Object)); } erasedConstraintType = (NamedTypeSymbol)dynamicEraser.EraseDynamic(constraintType); } else { Debug.Assert(!constraintType.ContainsDynamic()); Debug.Assert(constraintType.TypeKind != TypeKind.Delegate); erasedConstraintType = (NamedTypeSymbol)constraintType; } if (constraintType.IsInterfaceType()) { AddInterface(interfacesBuilder, erasedConstraintType); constraintTypesBuilder.Add(constraintType); continue; } else { constraintEffectiveBase = erasedConstraintType; constraintDeducedBase = constraintType; break; } case TypeKind.Struct: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_ValueType); constraintDeducedBase = constraintType; break; case TypeKind.Enum: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_Enum); constraintDeducedBase = constraintType; break; case TypeKind.Array: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_Array); constraintDeducedBase = constraintType; break; case TypeKind.Error: constraintEffectiveBase = (NamedTypeSymbol)constraintType; constraintDeducedBase = constraintType; break; case TypeKind.Submission: default: throw ExceptionUtilities.UnexpectedValue(constraintType.TypeKind); } CheckEffectiveAndDeducedBaseTypes(conversions, constraintEffectiveBase, constraintDeducedBase); constraintTypesBuilder.Add(constraintType); // Determine the more encompassed of the current effective base // class and the previously computed effective base class. if (!deducedBaseType.IsErrorType() && !constraintDeducedBase.IsErrorType()) { if (!IsEncompassedBy(conversions, deducedBaseType, constraintDeducedBase, ref useSiteDiagnostics)) { if (!IsEncompassedBy(conversions, constraintDeducedBase, deducedBaseType, ref useSiteDiagnostics)) { // "Type parameter '{0}' inherits conflicting constraints '{1}' and '{2}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BaseConstraintConflict, typeParameter, constraintDeducedBase, deducedBaseType))); } else { deducedBaseType = constraintDeducedBase; effectiveBaseClass = constraintEffectiveBase; } } } } AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder); CheckEffectiveAndDeducedBaseTypes(conversions, effectiveBaseClass, deducedBaseType); constraintTypes = constraintTypesBuilder.ToImmutableAndFree(); interfaces = interfacesBuilder.ToImmutableAndFree(); } Debug.Assert((effectiveBaseClass.SpecialType == SpecialType.System_Object) || (deducedBaseType.SpecialType != SpecialType.System_Object)); // Only create a TypeParameterBounds instance for this type // parameter if the bounds are not the default values. if ((constraintTypes.Length == 0) && (deducedBaseType.SpecialType == SpecialType.System_Object)) { Debug.Assert(effectiveBaseClass.SpecialType == SpecialType.System_Object); Debug.Assert(interfaces.Length == 0); return null; } var bounds = new TypeParameterBounds(constraintTypes, interfaces, effectiveBaseClass, deducedBaseType); // Additional constraint checks for overrides. if (inherited) { CheckOverrideConstraints(typeParameter, bounds, diagnosticsBuilder); } return bounds; }
internal sealed override TypeSymbol GetFieldType(ConsList<FieldSymbol> fieldsBeingBound) { Debug.Assert(fieldsBeingBound != null); if ((object)_lazyType != null) { return _lazyType; } var declarator = VariableDeclaratorNode; var fieldSyntax = GetFieldDeclaration(declarator); var typeSyntax = fieldSyntax.Declaration.Type; var compilation = this.DeclaringCompilation; var diagnostics = DiagnosticBag.GetInstance(); TypeSymbol type; // When we have multiple declarators, we report the type diagnostics on only the first. DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance(); Symbol associatedPropertyOrEvent = this.AssociatedSymbol; if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event) { EventSymbol @event = (EventSymbol)associatedPropertyOrEvent; if (@event.IsWindowsRuntimeEvent) { NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T); Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation); // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T> // type that has additional generic constraints? type = tokenTableType.Construct(@event.Type); } else { type = @event.Type; } } else { var binderFactory = compilation.GetBinderFactory(SyntaxTree); var binder = binderFactory.GetBinder(typeSyntax); binder = binder.WithContainingMemberOrLambda(this); if (!ContainingType.IsScriptClass) { type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator); if (IsFixed) { type = new PointerTypeSymbol(type); } } else { bool isVar; type = binder.BindType(typeSyntax, diagnostics, out isVar); Debug.Assert((object)type != null || isVar); if (isVar) { if (this.IsConst) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location); } if (fieldsBeingBound.ContainsReference(this)) { diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this); type = null; } else if (fieldSyntax.Declaration.Variables.Count > 1) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location); } else { fieldsBeingBound = new ConsList<FieldSymbol>(this, fieldsBeingBound); var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound); var initializerOpt = initializerBinder.BindInferredVariableInitializer(diagnostics, declarator.Initializer, declarator); if (initializerOpt != null) { if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType()) { type = initializerOpt.Type; } _lazyFieldTypeInferred = 1; } } if ((object)type == null) { type = binder.CreateErrorType("var"); } } } if (IsFixed) { if (ContainingType.TypeKind != TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, ErrorLocation); } var elementType = ((PointerTypeSymbol)type).PointedAtType; int elementSize = elementType.FixedBufferElementSizeInBytes(); if (elementSize == 0) { var loc = typeSyntax.Location; diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc); } if (!binder.InUnsafeRegion) { diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location); } } } // update the lazyType only if it contains value last seen by the current thread: if ((object)Interlocked.CompareExchange(ref _lazyType, type, null) == null) { TypeChecks(type, fieldSyntax, declarator, diagnostics); // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics. compilation.DeclarationDiagnostics.AddRange(diagnostics); bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator; if (isFirstDeclarator) { compilation.DeclarationDiagnostics.AddRange(diagnosticsForFirstDeclarator); } state.NotePartComplete(CompletionPart.Type); } diagnostics.Free(); diagnosticsForFirstDeclarator.Free(); return _lazyType; }
private ImmutableArray <TypeWithAnnotations> GetDeclaredConstraintTypes(ConsList <PETypeParameterSymbol> inProgress) { Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); if (_lazyDeclaredConstraintTypes.IsDefault) { ImmutableArray <TypeWithAnnotations> declaredConstraintTypes; var moduleSymbol = ((PEModuleSymbol)this.ContainingModule); PEModule peModule = moduleSymbol.Module; GenericParameterConstraintHandleCollection constraints = GetConstraintHandleCollection(peModule); bool hasUnmanagedModreqPattern = false; if (constraints.Count > 0) { var symbolsBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); MetadataDecoder tokenDecoder = GetDecoderForConstraintTypes(moduleSymbol); TypeWithAnnotations bestObjectConstraint = default; var metadataReader = peModule.MetadataReader; foreach (var constraintHandle in constraints) { TypeWithAnnotations type = GetConstraintTypeOrDefault(moduleSymbol, metadataReader, tokenDecoder, constraintHandle, ref hasUnmanagedModreqPattern); if (!type.HasType) { // Dropped 'System.ValueType' constraint type when the 'valuetype' constraint was also specified. continue; } // Drop 'System.Object' constraint type. if (ConstraintsHelper.IsObjectConstraint(type, ref bestObjectConstraint)) { continue; } symbolsBuilder.Add(type); } if (bestObjectConstraint.HasType) { // See if we need to put Object! or Object~ back in order to preserve nullability information for the type parameter. if (ConstraintsHelper.IsObjectConstraintSignificant(CalculateIsNotNullableFromNonTypeConstraints(), bestObjectConstraint)) { Debug.Assert(!HasNotNullConstraint && !HasValueTypeConstraint); if (symbolsBuilder.Count == 0) { if (bestObjectConstraint.NullableAnnotation.IsOblivious() && !HasReferenceTypeConstraint) { bestObjectConstraint = default; } } else { inProgress = inProgress.Prepend(this); foreach (TypeWithAnnotations constraintType in symbolsBuilder) { if (!ConstraintsHelper.IsObjectConstraintSignificant(IsNotNullableFromConstraintType(constraintType, inProgress, out _), bestObjectConstraint)) { bestObjectConstraint = default; break; } } } if (bestObjectConstraint.HasType) { symbolsBuilder.Insert(0, bestObjectConstraint); } } } declaredConstraintTypes = symbolsBuilder.ToImmutableAndFree(); } else { declaredConstraintTypes = ImmutableArray <TypeWithAnnotations> .Empty; } // - presence of unmanaged pattern has to be matched with `valuetype` // - IsUnmanagedAttribute is allowed iff there is an unmanaged pattern if (hasUnmanagedModreqPattern && (_flags & GenericParameterAttributes.NotNullableValueTypeConstraint) == 0 || hasUnmanagedModreqPattern != peModule.HasIsUnmanagedAttribute(_handle)) { // we do not recognize these combinations as "unmanaged" hasUnmanagedModreqPattern = false; Interlocked.CompareExchange(ref _lazyConstraintsUseSiteErrorInfo, new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, this), CSDiagnosticInfo.EmptyErrorInfo); } _lazyHasIsUnmanagedConstraint = hasUnmanagedModreqPattern.ToThreeState(); ImmutableInterlocked.InterlockedInitialize(ref _lazyDeclaredConstraintTypes, declaredConstraintTypes); } return(_lazyDeclaredConstraintTypes); }