internal static bool IsSet(this TypeParameterBounds boundsOpt, bool early) { if (boundsOpt == TypeParameterBounds.Unset) { return(false); } if (boundsOpt == null) { return(true); } return(early || !boundsOpt.IsEarly); }
// Based on SymbolLoader::SetOverrideConstraints. private static void CheckOverrideConstraints( TypeParameterSymbol typeParameter, TypeParameterBounds bounds, ArrayBuilder <TypeParameterDiagnosticInfo> diagnosticsBuilder) { var deducedBase = bounds.DeducedBaseType; var constraintTypes = bounds.ConstraintTypes; if (IsValueType(typeParameter, constraintTypes) && IsReferenceType(typeParameter, constraintTypes)) { Debug.Assert(!deducedBase.IsValueType || typeParameter.HasReferenceTypeConstraint); diagnosticsBuilder.Add(GenerateConflictingConstraintsError(typeParameter, deducedBase, classConflict: deducedBase.IsValueType)); } else if (deducedBase.IsNullableType() && (typeParameter.HasValueTypeConstraint || typeParameter.HasReferenceTypeConstraint)) { diagnosticsBuilder.Add(GenerateConflictingConstraintsError(typeParameter, deducedBase, classConflict: typeParameter.HasReferenceTypeConstraint)); } }
// 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; }
// Based on SymbolLoader::SetOverrideConstraints. private static void CheckOverrideConstraints( TypeParameterSymbol typeParameter, TypeParameterBounds bounds, ArrayBuilder<TypeParameterDiagnosticInfo> diagnosticsBuilder) { var deducedBase = bounds.DeducedBaseType; var constraintTypes = bounds.ConstraintTypes; if (IsValueType(typeParameter, constraintTypes) && IsReferenceType(typeParameter, constraintTypes)) { Debug.Assert(!deducedBase.IsValueType || typeParameter.HasReferenceTypeConstraint); diagnosticsBuilder.Add(GenerateConflictingConstraintsError(typeParameter, deducedBase, classConflict: deducedBase.IsValueType)); } else if (deducedBase.IsNullableType() && (typeParameter.HasValueTypeConstraint || typeParameter.HasReferenceTypeConstraint)) { diagnosticsBuilder.Add(GenerateConflictingConstraintsError(typeParameter, deducedBase, classConflict: typeParameter.HasReferenceTypeConstraint)); } }
// 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 static bool IsSet(this TypeParameterBounds boundsOpt) { return(boundsOpt != TypeParameterBounds.Unset); }