From 50de29ac6f55223bb0d78aa62001d5d1bf2253af Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Mon, 12 Oct 2020 19:47:41 -0700 Subject: [PATCH 1/2] Revert https://github.com/dotnet/roslyn/pull/47968 Revert 1f53c66ae5a562542f8a48e339c94dd36d3fed6d (https://github.com/dotnet/roslyn/commit/1f53c66ae5a562542f8a48e339c94dd36d3fed6d) --- .../CSharp/Portable/Binder/Binder.cs | 4 - .../CSharp/Portable/Binder/BinderFlags.cs | 5 - .../Portable/Binder/Binder_Constraints.cs | 11 +- .../Portable/Binder/Semantics/AccessCheck.cs | 2 +- .../Lowering/SynthesizedMethodBaseSymbol.cs | 2 +- .../AnonymousType.TypeParameterSymbol.cs | 4 +- .../Portable/Symbols/ConstraintsHelper.cs | 9 +- ...rrorTypeSymbol.ErrorTypeParameterSymbol.cs | 4 +- .../Metadata/PE/PETypeParameterSymbol.cs | 13 +- .../Portable/Symbols/NamedTypeSymbol.cs | 9 +- .../RetargetingTypeParameterSymbol.cs | 4 +- .../Symbols/Source/CrefTypeParameterSymbol.cs | 4 +- .../Source/IndexedTypeParameterSymbol.cs | 4 +- .../Portable/Symbols/Source/LambdaSymbol.cs | 2 +- .../Symbols/Source/LocalFunctionSymbol.cs | 14 +- .../Source/SourceConstructorSymbolBase.cs | 2 +- .../Source/SourceDelegateMethodSymbol.cs | 2 +- .../Symbols/Source/SourceDestructorSymbol.cs | 2 +- .../Source/SourceEventAccessorSymbol.cs | 2 +- .../Symbols/Source/SourceMethodSymbol.cs | 2 +- .../Symbols/Source/SourceNamedTypeSymbol.cs | 16 +- .../Source/SourceOrdinaryMethodSymbol.cs | 10 +- .../Source/SourcePropertyAccessorSymbol.cs | 2 +- .../Source/SourceTypeParameterSymbol.cs | 87 +++++----- .../SourceUserDefinedOperatorSymbolBase.cs | 2 +- .../Source/TypeParameterConstraintClause.cs | 52 +----- .../Symbols/SubstitutedTypeParameterSymbol.cs | 8 +- .../CSharp/Portable/Symbols/Symbol.cs | 2 +- .../SynthesizedRecordOrdinaryMethod.cs | 2 +- ...ynthesizedSimpleProgramEntryPointSymbol.cs | 2 +- .../Portable/Symbols/TypeParameterBounds.cs | 46 +---- .../Portable/Symbols/TypeParameterSymbol.cs | 32 ++-- .../Portable/Symbols/TypeWithAnnotations.cs | 13 +- .../Wrapped/WrappedTypeParameterSymbol.cs | 4 +- .../Semantics/NullableReferenceTypesTests.cs | 159 +----------------- .../Symbol/DocumentationComments/CrefTests.cs | 2 +- .../Symbols/EETypeParameterSymbol.cs | 8 +- .../Symbols/SimpleTypeParameterSymbol.cs | 4 +- 38 files changed, 143 insertions(+), 409 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index 630406496854e..ecebb6640f181 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -251,10 +251,6 @@ internal bool AreNullableAnnotationsEnabled(SyntaxTree syntaxTree, int position) internal bool AreNullableAnnotationsEnabled(SyntaxToken token) { RoslynDebug.Assert(token.SyntaxTree is object); - if ((Flags & BinderFlags.IgnoreNullableContext) != 0) - { - return false; - } return AreNullableAnnotationsEnabled(token.SyntaxTree, token.SpanStart); } diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs b/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs index 225f3af98d981..28e210564a60b 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs @@ -112,11 +112,6 @@ internal enum BinderFlags : uint /// InEEMethodBinder = 1 << 30, - /// - /// Assume '#nullable disable' context. - /// - IgnoreNullableContext = 1u << 31, - // Groups AllClearedAtExecutableCodeBoundary = InLockBody | InCatchBlock | InCatchFilter | InFinallyBlock | InTryBlockOfTryCatch | InNestedFinallyBlock, diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs index 0b5148f1419c3..443413a095dd5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs @@ -25,7 +25,6 @@ internal ImmutableArray BindTypeParameterConstrai ImmutableArray typeParameters, TypeParameterListSyntax typeParameterList, SyntaxList clauses, - bool canIgnoreNullableContext, ref IReadOnlyDictionary isValueTypeOverride, DiagnosticBag diagnostics, bool isForOverride = false) @@ -66,8 +65,7 @@ internal ImmutableArray BindTypeParameterConstrai Debug.Assert(ordinal >= 0); Debug.Assert(ordinal < n); - (TypeParameterConstraintClause constraintClause, ArrayBuilder? typeConstraintNodes) = - this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, canIgnoreNullableContext: canIgnoreNullableContext, diagnostics); + (TypeParameterConstraintClause constraintClause, ArrayBuilder? typeConstraintNodes) = this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, diagnostics); if (results[ordinal] == null) { results[ordinal] = constraintClause; @@ -118,8 +116,7 @@ internal ImmutableArray BindTypeParameterConstrai /// /// Bind and return a single type parameter constraint clause along with syntax nodes corresponding to type constraints. /// - private (TypeParameterConstraintClause, ArrayBuilder?) BindTypeParameterConstraints( - TypeParameterSyntax typeParameterSyntax, TypeParameterConstraintClauseSyntax constraintClauseSyntax, bool isForOverride, bool canIgnoreNullableContext, DiagnosticBag diagnostics) + private (TypeParameterConstraintClause, ArrayBuilder?) BindTypeParameterConstraints(TypeParameterSyntax typeParameterSyntax, TypeParameterConstraintClauseSyntax constraintClauseSyntax, bool isForOverride, DiagnosticBag diagnostics) { var constraints = TypeParameterConstraintKind.None; ArrayBuilder? constraintTypes = null; @@ -309,7 +306,7 @@ internal ImmutableArray BindTypeParameterConstrai Debug.Assert(!isForOverride || (constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)) != (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)); - return (TypeParameterConstraintClause.Create(constraints, constraintTypes?.ToImmutableAndFree() ?? ImmutableArray.Empty, canIgnoreNullableContext), syntaxBuilder); + return (TypeParameterConstraintClause.Create(constraints, constraintTypes?.ToImmutableAndFree() ?? ImmutableArray.Empty), syntaxBuilder); static void reportOverrideWithConstraints(ref bool reportedOverrideWithConstraints, TypeParameterConstraintSyntax syntax, DiagnosticBag diagnostics) { @@ -392,7 +389,7 @@ private static TypeParameterConstraintClause RemoveInvalidConstraints( if (constraintTypeBuilder.Count < n) { - return TypeParameterConstraintClause.Create(constraintClause.Constraints, constraintTypeBuilder.ToImmutableAndFree(), constraintClause.IgnoresNullableContext); + return TypeParameterConstraintClause.Create(constraintClause.Constraints, constraintTypeBuilder.ToImmutableAndFree()); } constraintTypeBuilder.Free(); diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/AccessCheck.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/AccessCheck.cs index c31f09c7060a0..fb933b116b560 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/AccessCheck.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/AccessCheck.cs @@ -236,7 +236,7 @@ private static bool IsNamedTypeAccessible(NamedTypeSymbol type, Symbol within, r { // type parameters are always accessible, so don't check those (so common it's // worth optimizing this). - if (typeArg.DefaultType.TypeKind != TypeKind.TypeParameter && !IsSymbolAccessibleCore(typeArg.Type, within, null, out unused, compilation, ref useSiteDiagnostics, basesBeingResolved)) + if (typeArg.Type.Kind != SymbolKind.TypeParameter && !IsSymbolAccessibleCore(typeArg.Type, within, null, out unused, compilation, ref useSiteDiagnostics, basesBeingResolved)) { return false; } diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index 623e758614ddf..032a1bb84861b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -88,7 +88,7 @@ public sealed override ImmutableArray TypeParameters get { return _typeParameters; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public sealed override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; internal override int ParameterCount diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs index 8adfadaea31b6..c1e06411964db 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs @@ -101,11 +101,11 @@ public override VarianceKind Variance get { return VarianceKind.None; } } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { return ImmutableArray.Empty; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs index 1b9bb10ed3fa4..b7f3a5dd27011 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs @@ -71,13 +71,12 @@ public static TypeParameterBounds ResolveBounds( ConsList inProgress, ImmutableArray constraintTypes, bool inherited, - bool ignoresNullableContext, CSharpCompilation currentCompilation, DiagnosticBag diagnostics) { var diagnosticsBuilder = ArrayBuilder.GetInstance(); ArrayBuilder useSiteDiagnosticsBuilder = null; - var bounds = typeParameter.ResolveBounds(corLibrary, inProgress, constraintTypes, inherited, ignoresNullableContext: ignoresNullableContext, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder); + var bounds = typeParameter.ResolveBounds(corLibrary, inProgress, constraintTypes, inherited, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder); if (useSiteDiagnosticsBuilder != null) { @@ -100,7 +99,6 @@ public static TypeParameterBounds ResolveBounds( ConsList inProgress, ImmutableArray constraintTypes, bool inherited, - bool ignoresNullableContext, CSharpCompilation currentCompilation, ArrayBuilder diagnosticsBuilder, ref ArrayBuilder useSiteDiagnosticsBuilder) @@ -299,7 +297,7 @@ public static TypeParameterBounds ResolveBounds( return null; } - var bounds = new TypeParameterBounds(constraintTypes, interfaces, effectiveBaseClass, deducedBaseType, ignoresNullableContext); + var bounds = new TypeParameterBounds(constraintTypes, interfaces, effectiveBaseClass, deducedBaseType); // Additional constraint checks for overrides. if (inherited) @@ -316,7 +314,7 @@ internal static ImmutableArray MakeTypeParameterC ImmutableArray typeParameters, TypeParameterListSyntax typeParameterList, SyntaxList constraintClauses, - bool canIgnoreNullableContext, + Location location, DiagnosticBag diagnostics) { if (typeParameters.Length == 0) @@ -338,7 +336,6 @@ internal static ImmutableArray MakeTypeParameterC IReadOnlyDictionary isValueTypeOverride = null; return binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses, - canIgnoreNullableContext, ref isValueTypeOverride, diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs index 7c9e2c5bbf36a..23c3530a8eb31 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs @@ -131,11 +131,11 @@ public override bool IsImplicitlyDeclared } } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { return ImmutableArray.Empty; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs index 59f70c45addb3..d754c690bc674 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs @@ -570,19 +570,18 @@ public override VarianceKind Variance } } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { - canIgnoreNullableContext = false; // Resolve bounds eagerly. - if (!_lazyBounds.HasValue(canIgnoreNullableContext)) + if (!_lazyBounds.IsSet()) { var typeParameters = (_containingSymbol.Kind == SymbolKind.Method) ? ((PEMethodSymbol)_containingSymbol).TypeParameters : ((PENamedTypeSymbol)_containingSymbol).TypeParameters; - EnsureAllConstraintsAreResolved(typeParameters, canIgnoreNullableContext); + EnsureAllConstraintsAreResolved(typeParameters); } } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { var bounds = this.GetBounds(inProgress); return (bounds != null) ? bounds.ConstraintTypes : ImmutableArray.Empty; @@ -637,7 +636,7 @@ private TypeParameterBounds GetBounds(ConsList inProgress) var diagnostics = ArrayBuilder.GetInstance(); ArrayBuilder useSiteDiagnosticsBuilder = null; bool inherited = (_containingSymbol.Kind == SymbolKind.Method) && ((MethodSymbol)_containingSymbol).IsOverride; - var bounds = this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited, ignoresNullableContext: false, currentCompilation: null, + var bounds = this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited, currentCompilation: null, diagnosticsBuilder: diagnostics, useSiteDiagnosticsBuilder: ref useSiteDiagnosticsBuilder); DiagnosticInfo errorInfo = null; @@ -673,7 +672,7 @@ private TypeParameterBounds GetBounds(ConsList inProgress) internal override DiagnosticInfo GetConstraintsUseSiteErrorInfo() { - EnsureAllConstraintsAreResolved(canIgnoreNullableContext: false); + EnsureAllConstraintsAreResolved(); Debug.Assert(!ReferenceEquals(_lazyConstraintsUseSiteErrorInfo, CSDiagnosticInfo.EmptyErrorInfo)); return _lazyConstraintsUseSiteErrorInfo; } diff --git a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs index db3af4e24bfee..1ecf96a2f9ca4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs @@ -65,7 +65,7 @@ internal ImmutableArray TypeArgumentsWithDefinitionUseSiteD foreach (var typeArgument in result) { - AddDefinitionUseSiteDiagnostics(typeArgument, ref useSiteDiagnostics); + typeArgument.Type.OriginalDefinition.AddUseSiteDiagnostics(ref useSiteDiagnostics); } return result; @@ -74,15 +74,10 @@ internal ImmutableArray TypeArgumentsWithDefinitionUseSiteD internal TypeWithAnnotations TypeArgumentWithDefinitionUseSiteDiagnostics(int index, ref HashSet useSiteDiagnostics) { var result = TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[index]; - AddDefinitionUseSiteDiagnostics(result, ref useSiteDiagnostics); + result.Type.OriginalDefinition.AddUseSiteDiagnostics(ref useSiteDiagnostics); return result; } - private static void AddDefinitionUseSiteDiagnostics(TypeWithAnnotations type, ref HashSet useSiteDiagnostics) - { - type.DefaultType.OriginalDefinition.AddUseSiteDiagnostics(ref useSiteDiagnostics); - } - /// /// Returns the type symbol that this type was constructed from. This type symbol /// has the same containing type (if any), but has type arguments that are the same diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingTypeParameterSymbol.cs index 2aa4ba2582d18..2ff127565b8d0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingTypeParameterSymbol.cs @@ -81,9 +81,9 @@ internal override ModuleSymbol ContainingModule } } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { - return this.RetargetingTranslator.Retarget(_underlyingTypeParameter.GetConstraintTypes(inProgress, canIgnoreNullableContext)); + return this.RetargetingTranslator.Retarget(_underlyingTypeParameter.GetConstraintTypes(inProgress)); } internal override bool? IsNotNullable diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs index 7afe51cd7308f..42dd2f0445822 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs @@ -177,11 +177,11 @@ public override ImmutableArray DeclaringSyntaxReferences } } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { return ImmutableArray.Empty; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs index 9a00eec1ce2cc..2b9b7d9fa66cd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs @@ -173,11 +173,11 @@ public override ImmutableArray DeclaringSyntaxReferences } } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { return ImmutableArray.Empty; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 2ec0efa7c70e7..c52f9a8c209ed 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -417,7 +417,7 @@ internal override bool GenerateDebugInfo internal override bool IsInitOnly => false; - public override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) => ImmutableArray.Empty; + public override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 7ebbfd84eec8b..9051337634a86 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -459,9 +459,9 @@ private ImmutableArray MakeTypeParameters(Diagn return result.ToImmutableAndFree(); } - public override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public override ImmutableArray GetTypeParameterConstraintClauses() { - if (!_lazyTypeParameterConstraints.HasValue(canIgnoreNullableContext)) + if (_lazyTypeParameterConstraints.IsDefault) { var syntax = Syntax; var diagnostics = DiagnosticBag.GetInstance(); @@ -470,17 +470,13 @@ public override ImmutableArray GetTypeParameterCo TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, - canIgnoreNullableContext, + syntax.Identifier.GetLocation(), diagnostics); lock (_declarationDiagnostics) { - canIgnoreNullableContext = constraints.IgnoresNullableContext(); - if (!_lazyTypeParameterConstraints.HasValue(canIgnoreNullableContext)) + if (_lazyTypeParameterConstraints.IsDefault) { - if (!canIgnoreNullableContext) - { - _declarationDiagnostics.AddRange(diagnostics); - } + _declarationDiagnostics.AddRange(diagnostics); _lazyTypeParameterConstraints = constraints; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs index 197607346231a..77588066eb2ac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs @@ -138,7 +138,7 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public sealed override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; public override RefKind RefKind diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs index 93915560f3af9..661cfb7fe19c5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs @@ -138,7 +138,7 @@ public override ImmutableArray TypeParameters } } - public override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; public sealed override TypeWithAnnotations ReturnTypeWithAnnotations diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs index 80d5677a29fcf..1702cd5e785f6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs @@ -98,7 +98,7 @@ public override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; public override RefKind RefKind diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs index 79624b769ff14..ac0c74448647c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs @@ -208,7 +208,7 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public sealed override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; internal Location Location diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs index 75efa7a39e371..929f3d24f05c6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs @@ -20,7 +20,7 @@ internal abstract class SourceMethodSymbol : MethodSymbol /// array of clauses, indexed by the constrained type parameter in . /// If a type parameter does not have constraints, the corresponding entry in the array is null. /// - public abstract ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext); + public abstract ImmutableArray GetTypeParameterConstraintClauses(); protected static void ReportBadRefToken(TypeSyntax returnTypeSyntax, DiagnosticBag diagnostics) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 793b0c9fcb0e9..f69f7ff5fae00 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -253,14 +253,13 @@ private ImmutableArray MakeTypeParameters(DiagnosticBag dia /// /// Returns the constraint clause for the given type parameter. /// - internal TypeParameterConstraintClause GetTypeParameterConstraintClause(bool canIgnoreNullableContext, int ordinal) + internal TypeParameterConstraintClause GetTypeParameterConstraintClause(int ordinal) { var clauses = _lazyTypeParameterConstraints; - if (!clauses.HasValue(canIgnoreNullableContext)) + if (clauses.IsDefault) { var diagnostics = DiagnosticBag.GetInstance(); - if (TypeParameterConstraintClauseExtensions.InterlockedUpdate(ref _lazyTypeParameterConstraints, MakeTypeParameterConstraints(canIgnoreNullableContext, diagnostics)) && - _lazyTypeParameterConstraints.HasValue(canIgnoreNullableContext: false)) + if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraints, MakeTypeParameterConstraints(diagnostics))) { this.AddDeclarationDiagnostics(diagnostics); } @@ -271,7 +270,7 @@ internal TypeParameterConstraintClause GetTypeParameterConstraintClause(bool can return (clauses.Length > 0) ? clauses[ordinal] : TypeParameterConstraintClause.Empty; } - private ImmutableArray MakeTypeParameterConstraints(bool canIgnoreNullableContext, DiagnosticBag diagnostics) + private ImmutableArray MakeTypeParameterConstraints(DiagnosticBag diagnostics) { var typeParameters = this.TypeParameters; var results = ImmutableArray.Empty; @@ -320,10 +319,9 @@ private ImmutableArray MakeTypeParameterConstrain // Wrap binder from factory in a generic constraints specific binder // to avoid checking constraints when binding type names. Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause)); - binder = binder.WithContainingMemberOrLambda(this).WithAdditionalFlags( - BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks | (canIgnoreNullableContext ? BinderFlags.IgnoreNullableContext : 0)); + binder = binder.WithContainingMemberOrLambda(this).WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks); - constraints = binder.BindTypeParameterConstraintClauses(this, typeParameters, typeParameterList, constraintClauses, canIgnoreNullableContext, ref isValueTypeOverride, diagnostics); + constraints = binder.BindTypeParameterConstraintClauses(this, typeParameters, typeParameterList, constraintClauses, ref isValueTypeOverride, diagnostics); } Debug.Assert(constraints.Length == arity); @@ -442,7 +440,7 @@ private ImmutableArray MergeConstraintsForPartial } builder[i] = TypeParameterConstraintClause.Create(mergedKind, - mergedConstraintTypes?.ToImmutableAndFree() ?? originalConstraintTypes, ignoresNullableContext: constraint.IgnoresNullableContext); + mergedConstraintTypes?.ToImmutableAndFree() ?? originalConstraintTypes); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index 4fc98acf1df89..bcbadaf5bac39 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -166,7 +166,6 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray isValueTypeOverride = null; declaredConstraints = signatureBinder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks). BindTypeParameterConstraintClauses(this, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, - canIgnoreNullableContext: false, ref isValueTypeOverride, diagnostics, isForOverride: true); } @@ -283,9 +282,9 @@ protected override void CompleteAsyncMethodChecksBetweenStartAndFinish() } } - public override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public override ImmutableArray GetTypeParameterConstraintClauses() { - if (!_lazyTypeParameterConstraints.HasValue(canIgnoreNullableContext)) + if (_lazyTypeParameterConstraints.IsDefault) { var diagnostics = DiagnosticBag.GetInstance(); var syntax = GetSyntax(); @@ -298,10 +297,9 @@ public override ImmutableArray GetTypeParameterCo TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, - canIgnoreNullableContext, + syntax.Identifier.GetLocation(), diagnostics); - if (TypeParameterConstraintClauseExtensions.InterlockedUpdate(ref _lazyTypeParameterConstraints, constraints) && - _lazyTypeParameterConstraints.HasValue(canIgnoreNullableContext: false)) + if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraints, constraints)) { this.AddDeclarationDiagnostics(diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index a9d6380c959ca..32f87d58feaab 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -452,7 +452,7 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public sealed override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; public sealed override RefKind RefKind diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs index be48267a75b48..f51384be91489 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs @@ -88,27 +88,27 @@ public override string Name } } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { - var bounds = this.GetBounds(inProgress, canIgnoreNullableContext); + var bounds = this.GetBounds(inProgress); return (bounds != null) ? bounds.ConstraintTypes : ImmutableArray.Empty; } internal override ImmutableArray GetInterfaces(ConsList inProgress) { - var bounds = this.GetBounds(inProgress, canIgnoreNullableContext: false); + var bounds = this.GetBounds(inProgress); return (bounds != null) ? bounds.Interfaces : ImmutableArray.Empty; } internal override NamedTypeSymbol GetEffectiveBaseClass(ConsList inProgress) { - var bounds = this.GetBounds(inProgress, canIgnoreNullableContext: false); + var bounds = this.GetBounds(inProgress); return (bounds != null) ? bounds.EffectiveBaseClass : this.GetDefaultBaseType(); } internal override TypeSymbol GetDeducedBaseType(ConsList inProgress) { - var bounds = this.GetBounds(inProgress, canIgnoreNullableContext: false); + var bounds = this.GetBounds(inProgress); return (bounds != null) ? bounds.DeducedBaseType : this.GetDefaultBaseType(); } @@ -204,11 +204,11 @@ internal virtual CustomAttributesBag GetAttributesBag() return _lazyCustomAttributesBag; } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { - if (!_lazyBounds.HasValue(canIgnoreNullableContext)) + if (!_lazyBounds.IsSet()) { - EnsureAllConstraintsAreResolved(this.ContainerTypeParameters, canIgnoreNullableContext); + EnsureAllConstraintsAreResolved(this.ContainerTypeParameters); } } @@ -217,18 +217,17 @@ protected abstract ImmutableArray ContainerTypeParameters get; } - private TypeParameterBounds GetBounds(ConsList inProgress, bool canIgnoreNullableContext) + private TypeParameterBounds GetBounds(ConsList inProgress) { Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); - if (!_lazyBounds.HasValue(canIgnoreNullableContext)) + if (!_lazyBounds.IsSet()) { var diagnostics = DiagnosticBag.GetInstance(); - var bounds = this.ResolveBounds(inProgress, canIgnoreNullableContext, diagnostics); + var bounds = this.ResolveBounds(inProgress, diagnostics); - if (TypeParameterBoundsExtensions.InterlockedUpdate(ref _lazyBounds, bounds) && - _lazyBounds.HasValue(canIgnoreNullableContext: false)) + if (ReferenceEquals(Interlocked.CompareExchange(ref _lazyBounds, bounds, TypeParameterBounds.Unset), TypeParameterBounds.Unset)) { this.CheckConstraintTypeConstraints(diagnostics); this.CheckUnmanagedConstraint(diagnostics); @@ -243,7 +242,7 @@ private TypeParameterBounds GetBounds(ConsList inProgress, return _lazyBounds; } - protected abstract TypeParameterBounds ResolveBounds(ConsList inProgress, bool canIgnoreNullableContext, DiagnosticBag diagnostics); + protected abstract TypeParameterBounds ResolveBounds(ConsList inProgress, DiagnosticBag diagnostics); /// /// Check constraints of generic types referenced in constraint types. For instance, @@ -489,7 +488,7 @@ public override bool HasConstructorConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.Constructor) != 0; } } @@ -498,7 +497,7 @@ public override bool HasValueTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.AllValueTypeKinds) != 0; } } @@ -507,7 +506,7 @@ public override bool HasReferenceTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.ReferenceType) != 0; } } @@ -516,7 +515,7 @@ internal override bool? ReferenceTypeConstraintIsNullable { get { - return CalculateReferenceTypeConstraintIsNullable(this.GetDeclaredConstraints(canIgnoreNullableContext: false)); + return CalculateReferenceTypeConstraintIsNullable(this.GetDeclaredConstraints()); } } @@ -524,7 +523,7 @@ public override bool HasNotNullConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: false); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.NotNull) != 0; } } @@ -533,7 +532,7 @@ internal override bool? IsNotNullable { get { - if ((this.GetDeclaredConstraints(canIgnoreNullableContext: false) & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) + if ((this.GetDeclaredConstraints() & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) { return null; } @@ -546,7 +545,7 @@ public override bool HasUnmanagedTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.Unmanaged) != 0; } } @@ -556,26 +555,26 @@ protected override ImmutableArray ContainerTypeParameters get { return _owner.TypeParameters; } } - private TypeParameterConstraintClause GetTypeParameterConstraintClause(bool canIgnoreNullableContext) + private TypeParameterConstraintClause GetTypeParameterConstraintClause() { - return _owner.GetTypeParameterConstraintClause(canIgnoreNullableContext, this.Ordinal); + return _owner.GetTypeParameterConstraintClause(this.Ordinal); } - protected override TypeParameterBounds ResolveBounds(ConsList inProgress, bool canIgnoreNullableContext, DiagnosticBag diagnostics) + protected override TypeParameterBounds ResolveBounds(ConsList inProgress, DiagnosticBag diagnostics) { - var constraintClause = GetTypeParameterConstraintClause(canIgnoreNullableContext); + var constraintClause = GetTypeParameterConstraintClause(); if (constraintClause.IsEmpty) { return null; } var constraintTypes = constraintClause.ConstraintTypes; - return this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited: false, ignoresNullableContext: constraintClause.IgnoresNullableContext, this.DeclaringCompilation, diagnostics); + return this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited: false, this.DeclaringCompilation, diagnostics); } - private TypeParameterConstraintKind GetDeclaredConstraints(bool canIgnoreNullableContext) + private TypeParameterConstraintKind GetDeclaredConstraints() { - var constraintClause = GetTypeParameterConstraintClause(canIgnoreNullableContext); + var constraintClause = GetTypeParameterConstraintClause(); return constraintClause.Constraints; } } @@ -610,7 +609,7 @@ public override bool HasConstructorConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.Constructor) != 0; } } @@ -619,7 +618,7 @@ public override bool HasValueTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.AllValueTypeKinds) != 0; } } @@ -628,7 +627,7 @@ public override bool HasReferenceTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.ReferenceType) != 0; } } @@ -637,7 +636,7 @@ public override bool HasNotNullConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: false); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.NotNull) != 0; } } @@ -646,7 +645,7 @@ internal override bool? ReferenceTypeConstraintIsNullable { get { - return CalculateReferenceTypeConstraintIsNullable(this.GetDeclaredConstraints(canIgnoreNullableContext: false)); + return CalculateReferenceTypeConstraintIsNullable(this.GetDeclaredConstraints()); } } @@ -654,7 +653,7 @@ internal override bool? IsNotNullable { get { - if ((this.GetDeclaredConstraints(canIgnoreNullableContext: false) & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) + if ((this.GetDeclaredConstraints() & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) { return null; } @@ -667,7 +666,7 @@ public override bool HasUnmanagedTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(canIgnoreNullableContext: true); + var constraints = this.GetDeclaredConstraints(); return (constraints & TypeParameterConstraintKind.Unmanaged) != 0; } } @@ -677,27 +676,27 @@ protected override ImmutableArray ContainerTypeParameters get { return _owner.TypeParameters; } } - private TypeParameterConstraintClause GetTypeParameterConstraintClause(bool canIgnoreNullableContext) + private TypeParameterConstraintClause GetTypeParameterConstraintClause() { - var constraintClauses = _owner.GetTypeParameterConstraintClauses(canIgnoreNullableContext); + var constraintClauses = _owner.GetTypeParameterConstraintClauses(); return constraintClauses.IsEmpty ? TypeParameterConstraintClause.Empty : constraintClauses[Ordinal]; } - protected override TypeParameterBounds ResolveBounds(ConsList inProgress, bool canIgnoreNullableContext, DiagnosticBag diagnostics) + protected override TypeParameterBounds ResolveBounds(ConsList inProgress, DiagnosticBag diagnostics) { - var constraintClause = GetTypeParameterConstraintClause(canIgnoreNullableContext); + var constraintClause = GetTypeParameterConstraintClause(); if (constraintClause.IsEmpty) { return null; } var constraintTypes = constraintClause.ConstraintTypes; - return this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited: false, ignoresNullableContext: constraintClause.IgnoresNullableContext, this.DeclaringCompilation, diagnostics); + return this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited: false, this.DeclaringCompilation, diagnostics); } - internal TypeParameterConstraintKind GetDeclaredConstraints(bool canIgnoreNullableContext) + internal TypeParameterConstraintKind GetDeclaredConstraints() { - var constraintClause = GetTypeParameterConstraintClause(canIgnoreNullableContext); + var constraintClause = GetTypeParameterConstraintClause(); return constraintClause.Constraints; } } @@ -912,7 +911,7 @@ protected override ImmutableArray ContainerTypeParameters get { return this.Owner.TypeParameters; } } - protected override TypeParameterBounds ResolveBounds(ConsList inProgress, bool canIgnoreNullableContext, DiagnosticBag diagnostics) + protected override TypeParameterBounds ResolveBounds(ConsList inProgress, DiagnosticBag diagnostics) { var typeParameter = this.OverriddenTypeParameter; if ((object)typeParameter == null) @@ -923,7 +922,7 @@ protected override TypeParameterBounds ResolveBounds(ConsList diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index a984d38e911e1..10f92a96bcb4c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -645,7 +645,7 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public sealed override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; public sealed override RefKind RefKind diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs index 34feda2ecab28..6f935561f88c1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs @@ -63,21 +63,18 @@ internal sealed class TypeParameterConstraintClause { internal static readonly TypeParameterConstraintClause Empty = new TypeParameterConstraintClause( TypeParameterConstraintKind.None, - ImmutableArray.Empty, - ignoresNullableContext: false); + ImmutableArray.Empty); internal static readonly TypeParameterConstraintClause ObliviousNullabilityIfReferenceType = new TypeParameterConstraintClause( TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType, - ImmutableArray.Empty, - ignoresNullableContext: false); + ImmutableArray.Empty); internal static TypeParameterConstraintClause Create( TypeParameterConstraintKind constraints, - ImmutableArray constraintTypes, - bool ignoresNullableContext) + ImmutableArray constraintTypes) { Debug.Assert(!constraintTypes.IsDefault); - if (!ignoresNullableContext && constraintTypes.IsEmpty) + if (constraintTypes.IsEmpty) { switch (constraints) { @@ -89,13 +86,12 @@ internal static TypeParameterConstraintClause Create( } } - return new TypeParameterConstraintClause(constraints, constraintTypes, ignoresNullableContext); + return new TypeParameterConstraintClause(constraints, constraintTypes); } private TypeParameterConstraintClause( TypeParameterConstraintKind constraints, - ImmutableArray constraintTypes, - bool ignoresNullableContext) + ImmutableArray constraintTypes) { #if DEBUG switch (constraints & TypeParameterConstraintKind.AllReferenceTypeKinds) @@ -115,12 +111,10 @@ private TypeParameterConstraintClause( #endif this.Constraints = constraints; this.ConstraintTypes = constraintTypes; - this.IgnoresNullableContext = ignoresNullableContext; } public readonly TypeParameterConstraintKind Constraints; public readonly ImmutableArray ConstraintTypes; - public readonly bool IgnoresNullableContext; internal bool IsEmpty => Constraints == TypeParameterConstraintKind.None && ConstraintTypes.IsEmpty; @@ -220,43 +214,9 @@ static void adjustConstraintTypes(Symbol container, ImmutableArray constraintClauses, bool canIgnoreNullableContext) - { - if (constraintClauses.IsDefault) - { - return false; - } - return canIgnoreNullableContext || !constraintClauses.IgnoresNullableContext(); - } - - internal static bool IgnoresNullableContext(this ImmutableArray constraintClauses) - { - return constraintClauses.Any(clause => clause.IgnoresNullableContext); - } - internal static bool ContainsOnlyEmptyConstraintClauses(this ImmutableArray constraintClauses) { return constraintClauses.All(clause => clause.IsEmpty); } - - // Returns true if constraintClauses was updated with value. - // Returns false if constraintClauses already had a value with sufficient 'IgnoresNullableContext' - // or was updated to a value with sufficient 'IgnoresNullableContext' on another thread. - internal static bool InterlockedUpdate(ref ImmutableArray constraintClauses, ImmutableArray value) - { - bool canIgnoreNullableContext = value.IgnoresNullableContext(); - while (true) - { - var comparand = constraintClauses; - if (comparand.HasValue(canIgnoreNullableContext)) - { - return false; - } - if (ImmutableInterlocked.InterlockedCompareExchange(ref constraintClauses, value, comparand) == comparand) - { - return true; - } - } - } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedTypeParameterSymbol.cs index 884fd877f90a7..829ec2092306b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedTypeParameterSymbol.cs @@ -96,10 +96,10 @@ public override string Name } } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { var constraintTypes = ArrayBuilder.GetInstance(); - _map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(inProgress, canIgnoreNullableContext), constraintTypes, null); + _map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(inProgress), constraintTypes, null); TypeWithAnnotations bestObjectConstraint = default; @@ -116,7 +116,7 @@ internal override ImmutableArray GetConstraintTypes(ConsLis if (bestObjectConstraint.HasType) { // See if we need to put Object! or Object~ back in order to preserve nullability information for the type parameter. - if (!canIgnoreNullableContext && ConstraintsHelper.IsObjectConstraintSignificant(CalculateIsNotNullableFromNonTypeConstraints(), bestObjectConstraint)) + if (ConstraintsHelper.IsObjectConstraintSignificant(CalculateIsNotNullableFromNonTypeConstraints(), bestObjectConstraint)) { Debug.Assert(!HasNotNullConstraint && !HasValueTypeConstraint); if (constraintTypes.Count == 0) @@ -159,7 +159,7 @@ internal override bool? IsNotNullable else if (!HasNotNullConstraint && !HasValueTypeConstraint && !HasReferenceTypeConstraint) { var constraintTypes = ArrayBuilder.GetInstance(); - _map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(ConsList.Empty, canIgnoreNullableContext: false), constraintTypes, null); + _map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(ConsList.Empty), constraintTypes, null); return IsNotNullableFromConstraintTypes(constraintTypes.ToImmutableAndFree()); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs index ec741991e73b1..e063f8227ea6c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs @@ -1020,7 +1020,7 @@ private DiagnosticInfo GetSymbolSpecificUnsupportedMetadataUseSiteErrorInfo() internal bool DeriveUseSiteDiagnosticFromType(ref DiagnosticInfo result, TypeWithAnnotations type, AllowedRequiredModifierType allowedRequiredModifierType) { - return (type.DefaultType.TypeKind != TypeKind.TypeParameter && DeriveUseSiteDiagnosticFromType(ref result, type.Type)) || + return DeriveUseSiteDiagnosticFromType(ref result, type.Type) || DeriveUseSiteDiagnosticFromCustomModifiers(ref result, type.CustomModifiers, allowedRequiredModifierType); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs index 2303d3fbcff73..877974daa91d7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs @@ -38,7 +38,7 @@ protected SynthesizedRecordOrdinaryMethod(SourceMemberContainerTypeSymbol contai protected sealed override ImmutableArray MakeTypeParameters(CSharpSyntaxNode node, DiagnosticBag diagnostics) => ImmutableArray.Empty; - public sealed override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) => ImmutableArray.Empty; + public sealed override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; protected sealed override void PartialMethodChecks(DiagnosticBag diagnostics) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs index 8bef9bb6b8c53..ff027c279128a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs @@ -175,7 +175,7 @@ protected override void MethodChecks(DiagnosticBag diagnostics) internal override bool IsExpressionBodied => false; - public override ImmutableArray GetTypeParameterConstraintClauses(bool canIgnoreNullableContext) + public override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; protected override object MethodChecksLockObject => _declaration; diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs b/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs index 435d243321204..86e2283eb6ff9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Diagnostics; -using System.Threading; namespace Microsoft.CodeAnalysis.CSharp.Symbols { @@ -18,12 +17,14 @@ internal sealed class TypeParameterBounds { public static readonly TypeParameterBounds Unset = new TypeParameterBounds(); + /// + /// Creates a "late" bound instance with all fields set. + /// public TypeParameterBounds( ImmutableArray constraintTypes, ImmutableArray interfaces, NamedTypeSymbol effectiveBaseClass, - TypeSymbol deducedBaseType, - bool ignoresNullableContext) + TypeSymbol deducedBaseType) { Debug.Assert(!constraintTypes.IsDefault); Debug.Assert(!interfaces.IsDefault); @@ -34,15 +35,12 @@ public TypeParameterBounds( this.Interfaces = interfaces; this.EffectiveBaseClass = effectiveBaseClass; this.DeducedBaseType = deducedBaseType; - this.IgnoresNullableContext = ignoresNullableContext; } private TypeParameterBounds() { } - public readonly bool IgnoresNullableContext; - /// /// The type parameters, classes, and interfaces explicitly declared as /// constraint types on the containing type parameter, with cycles removed. @@ -59,7 +57,7 @@ private TypeParameterBounds() /// /// As defined in 10.1.5 of the specification. /// - public readonly NamedTypeSymbol? EffectiveBaseClass; + public readonly NamedTypeSymbol EffectiveBaseClass; /// /// The "exact" effective base type. @@ -77,42 +75,14 @@ private TypeParameterBounds() /// When computing the deduced type we don't perform this abstraction. We keep the original constraint T. /// Deduced base type is used to check that consistency rules are satisfied. /// - public readonly TypeSymbol? DeducedBaseType; + public readonly TypeSymbol DeducedBaseType; } internal static class TypeParameterBoundsExtensions { - internal static bool HasValue(this TypeParameterBounds? boundsOpt, bool canIgnoreNullableContext) - { - if (boundsOpt == TypeParameterBounds.Unset) - { - return false; - } - if (boundsOpt == null) - { - return true; - } - return canIgnoreNullableContext || !boundsOpt.IgnoresNullableContext; - } - - // Returns true if bounds was updated with value. - // Returns false if bounds already had a value with sufficient 'IgnoresNullableContext' - // or was updated to a value with sufficient 'IgnoresNullableContext' on another thread. - internal static bool InterlockedUpdate(ref TypeParameterBounds? bounds, TypeParameterBounds? value) + internal static bool IsSet(this TypeParameterBounds boundsOpt) { - bool canIgnoreNullableContext = (value?.IgnoresNullableContext == true); - while (true) - { - var comparand = bounds; - if (comparand != TypeParameterBounds.Unset && comparand.HasValue(canIgnoreNullableContext)) - { - return false; - } - if (Interlocked.CompareExchange(ref bounds, value, comparand) == comparand) - { - return true; - } - } + return boundsOpt != TypeParameterBounds.Unset; } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs index 0ec53119e1f2a..4d77bd8a637b9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs @@ -79,15 +79,15 @@ internal virtual DiagnosticInfo GetConstraintsUseSiteErrorInfo() /// Duplicates and cycles are removed, although the collection may include /// redundant constraints where one constraint is a base type of another. /// - internal ImmutableArray GetConstraintTypesNoUseSiteDiagnostics(bool canIgnoreNullableContext) + internal ImmutableArray ConstraintTypesNoUseSiteDiagnostics { - this.EnsureAllConstraintsAreResolved(canIgnoreNullableContext); - return this.GetConstraintTypes(ConsList.Empty, canIgnoreNullableContext); + get + { + this.EnsureAllConstraintsAreResolved(); + return this.GetConstraintTypes(ConsList.Empty); + } } - internal ImmutableArray ConstraintTypesNoUseSiteDiagnostics => - GetConstraintTypesNoUseSiteDiagnostics(canIgnoreNullableContext: false); - internal ImmutableArray ConstraintTypesWithDefinitionUseSiteDiagnostics(ref HashSet useSiteDiagnostics) { var result = ConstraintTypesNoUseSiteDiagnostics; @@ -270,7 +270,7 @@ internal NamedTypeSymbol EffectiveBaseClassNoUseSiteDiagnostics { get { - this.EnsureAllConstraintsAreResolved(canIgnoreNullableContext: false); + this.EnsureAllConstraintsAreResolved(); return this.GetEffectiveBaseClass(ConsList.Empty); } } @@ -295,7 +295,7 @@ internal ImmutableArray EffectiveInterfacesNoUseSiteDiagnostics { get { - this.EnsureAllConstraintsAreResolved(canIgnoreNullableContext: false); + this.EnsureAllConstraintsAreResolved(); return this.GetInterfaces(ConsList.Empty); } } @@ -307,7 +307,7 @@ internal TypeSymbol DeducedBaseTypeNoUseSiteDiagnostics { get { - this.EnsureAllConstraintsAreResolved(canIgnoreNullableContext: false); + this.EnsureAllConstraintsAreResolved(); return this.GetDeducedBaseType(ConsList.Empty); } } @@ -364,21 +364,21 @@ internal ImmutableArray AllEffectiveInterfacesWithDefinitionUse /// type or method are resolved in a consistent order, regardless of the /// order the callers query individual type parameters. /// - internal abstract void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext); + internal abstract void EnsureAllConstraintsAreResolved(); /// /// Helper method to force type parameter constraints to be resolved. /// - protected static void EnsureAllConstraintsAreResolved(ImmutableArray typeParameters, bool canIgnoreNullableContext) + protected static void EnsureAllConstraintsAreResolved(ImmutableArray typeParameters) { foreach (var typeParameter in typeParameters) { // Invoke any method that forces constraints to be resolved. - var unused = typeParameter.GetConstraintTypes(ConsList.Empty, canIgnoreNullableContext); + var unused = typeParameter.GetConstraintTypes(ConsList.Empty); } } - internal abstract ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext); + internal abstract ImmutableArray GetConstraintTypes(ConsList inProgress); internal abstract ImmutableArray GetInterfaces(ConsList inProgress); @@ -390,7 +390,7 @@ private static bool ConstraintImpliesReferenceType(TypeSymbol constraint) { if (constraint.TypeKind == TypeKind.TypeParameter) { - return IsReferenceTypeFromConstraintTypes(((TypeParameterSymbol)constraint).GetConstraintTypesNoUseSiteDiagnostics(canIgnoreNullableContext: true)); + return IsReferenceTypeFromConstraintTypes(((TypeParameterSymbol)constraint).ConstraintTypesNoUseSiteDiagnostics); } else if (!constraint.IsReferenceType) { @@ -514,7 +514,7 @@ public sealed override bool IsReferenceType return true; } - return IsReferenceTypeFromConstraintTypes(this.GetConstraintTypesNoUseSiteDiagnostics(canIgnoreNullableContext: true)); + return IsReferenceTypeFromConstraintTypes(this.ConstraintTypesNoUseSiteDiagnostics); } } @@ -572,7 +572,7 @@ public sealed override bool IsValueType return true; } - return IsValueTypeFromConstraintTypes(this.GetConstraintTypesNoUseSiteDiagnostics(canIgnoreNullableContext: true)); + return IsValueTypeFromConstraintTypes(this.ConstraintTypesNoUseSiteDiagnostics); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs b/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs index d255004489de8..07cd0d7de94c1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs @@ -470,18 +470,9 @@ internal TypeWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap) NullableAnnotation newAnnotation; - Debug.Assert(!IsIndexedTypeParameter(newTypeWithModifiers.DefaultType) || newTypeWithModifiers.NullableAnnotation.IsOblivious()); + Debug.Assert(!IsIndexedTypeParameter(newTypeWithModifiers.Type) || newTypeWithModifiers.NullableAnnotation.IsOblivious()); - if (newTypeWithModifiers.NullableAnnotation.IsAnnotated()) - { - if (newTypeWithModifiers._extensions is LazyNullableTypeParameter) - { - Debug.Assert(newCustomModifiers.IsEmpty); - return newTypeWithModifiers; - } - newAnnotation = NullableAnnotation.Annotated; - } - else if (NullableAnnotation.IsAnnotated()) + if (NullableAnnotation.IsAnnotated() || newTypeWithModifiers.NullableAnnotation.IsAnnotated()) { newAnnotation = NullableAnnotation.Annotated; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs index 41d27d889f2ec..80a52325607d3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs @@ -146,9 +146,9 @@ public override string Name return _underlyingTypeParameter.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { - _underlyingTypeParameter.EnsureAllConstraintsAreResolved(canIgnoreNullableContext); + _underlyingTypeParameter.EnsureAllConstraintsAreResolved(); } public override ImmutableArray GetAttributes() diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 8aad88173bd09..fe1719905f450 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -141217,7 +141217,7 @@ public static C SelectMany(this C source, Fu [Fact] [WorkItem(44348, "https://github.com/dotnet/roslyn/issues/44348")] - public void NestedTypeConstraints_01() + public void Constraints() { var source = @"class A @@ -141236,163 +141236,6 @@ internal interface IB : IA { } comp.VerifyEmitDiagnostics(); } - [Fact] - [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] - public void NestedTypeConstraints_02() - { - var source = -@"class A -{ - internal interface IA { } -} -#nullable enable -class B : A - where T : B.IA -{ -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - } - - [Fact] - [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] - public void NestedTypeConstraints_03() - { - var source = -@"class A -{ - internal interface IA { } -} -#nullable enable -class B : A - where T : B.IA -{ -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - } - - [Fact] - [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] - public void NestedTypeConstraints_04() - { - var source = -@"class A -{ - internal interface IA { } -} -#nullable enable -class B : A -#nullable disable - where T : B.IA -{ -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - } - - [Fact] - [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] - public void NestedTypeConstraints_05() - { - var source = -@"class A -{ - internal interface IA { } -} -#nullable enable -class B : A -#nullable disable - where T : B.IA -{ -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (8,18): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. - // where T : B.IA - Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(8, 18)); - } - - [Fact] - [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] - public void NestedTypeConstraints_06() - { - var source0 = -@"public class A -{ - public interface IA { } -} -#nullable enable -public class B : A - where T : B.IA -{ -}"; - var comp = CreateCompilation(source0); - var ref0 = comp.EmitToImageReference(); - - var source1 = -@"class A : A.IA { } -class Program -{ - static B F() => new(); - static void Main() - { - System.Console.WriteLine(F()); - } -}"; - CompileAndVerify(source1, references: new[] { ref0 }, expectedOutput: "B`1[A]"); - } - - [Fact] - [WorkItem(45863, "https://github.com/dotnet/roslyn/issues/45863")] - public void NestedTypeConstraints_07() - { - var source = -@"#nullable enable -interface IA -{ -} -interface IB : IA - where U : IB.IC -{ - interface IC { } -}"; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics(); - } - - [Fact] - [WorkItem(45863, "https://github.com/dotnet/roslyn/issues/45863")] - public void NestedTypeConstraints_08() - { - var source0 = -@"#nullable enable -public interface IA -{ -} -public interface IB : IA - where U : IB.IC -{ - public interface IC { } -}"; - var comp = CreateCompilation(source0); - var ref0 = comp.EmitToImageReference(); - - var source1 = -@"class C : IB.IC -{ -} -class Program -{ - static C F() => new(); - static void Main() - { - System.Console.WriteLine(F()); - } -}"; - CompileAndVerify(source1, references: new[] { ref0 }, expectedOutput: "C"); - } - [Fact] [WorkItem(46342, "https://github.com/dotnet/roslyn/issues/46342")] public void LambdaNullReturn_01() diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs index e3cbda2d31a90..06521b5931c2d 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs @@ -1564,7 +1564,7 @@ class C AssertEx.None(actualTypeParameters, p => p.HasReferenceTypeConstraint); AssertEx.None(actualTypeParameters, p => p.HasConstructorConstraint); AssertEx.All(actualTypeParameters, p => p.ContainingSymbol == null); - AssertEx.All(actualTypeParameters, p => p.GetConstraintTypes(null, canIgnoreNullableContext: false).Length == 0); + AssertEx.All(actualTypeParameters, p => p.GetConstraintTypes(null).Length == 0); AssertEx.All(actualTypeParameters, p => p.GetInterfaces(null).Length == 0); foreach (var p in actualTypeParameters) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs index 58472bcbff225..b134b17a377ce 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs @@ -117,14 +117,14 @@ public override bool IsImplicitlyDeclared get { return true; } } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { - _sourceTypeParameter.EnsureAllConstraintsAreResolved(canIgnoreNullableContext); + _sourceTypeParameter.EnsureAllConstraintsAreResolved(); } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { - var constraintTypes = _sourceTypeParameter.GetConstraintTypes(inProgress, canIgnoreNullableContext); + var constraintTypes = _sourceTypeParameter.GetConstraintTypes(inProgress); if (constraintTypes.IsEmpty) { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs index 5c960315bbe01..888339058d141 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs @@ -91,11 +91,11 @@ public override ImmutableArray DeclaringSyntaxReferences get { throw ExceptionUtilities.Unreachable; } } - internal override void EnsureAllConstraintsAreResolved(bool canIgnoreNullableContext) + internal override void EnsureAllConstraintsAreResolved() { } - internal override ImmutableArray GetConstraintTypes(ConsList inProgress, bool canIgnoreNullableContext) + internal override ImmutableArray GetConstraintTypes(ConsList inProgress) { return ImmutableArray.Empty; } From a1225040f438841513c5da213f7f3669d286803e Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Tue, 10 Nov 2020 07:32:19 -0800 Subject: [PATCH 2/2] Avoid cycles while binding type parameter constraints --- .../CSharp/Portable/Binder/BinderFlags.cs | 6 + .../Portable/Binder/Binder_Constraints.cs | 38 +- .../CSharp/Portable/Binder/Binder_Symbols.cs | 4 + .../Lowering/SynthesizedMethodBaseSymbol.cs | 7 +- .../AnonymousType.TypePublicSymbol.cs | 4 +- .../AnonymousType.TypeParameterSymbol.cs | 10 + .../Portable/Symbols/ArrayTypeSymbol.cs | 8 +- .../Portable/Symbols/ConstraintsHelper.cs | 121 ++++++- .../Portable/Symbols/DynamicTypeSymbol.cs | 2 +- ...rrorTypeSymbol.ErrorTypeParameterSymbol.cs | 20 +- .../Symbols/ExtendedErrorTypeSymbol.cs | 4 +- .../FunctionPointerMethodSymbol.cs | 14 +- .../FunctionPointerParameterSymbol.cs | 10 +- .../FunctionPointerTypeSymbol.cs | 4 +- .../Symbols/Metadata/PE/PENamedTypeSymbol.cs | 6 +- .../Metadata/PE/PETypeParameterSymbol.cs | 17 + .../Symbols/MissingMetadataTypeSymbol.cs | 6 +- .../Portable/Symbols/NamedTypeSymbol.cs | 12 +- .../Symbols/NativeIntegerTypeSymbol.cs | 4 +- .../NoPiaAmbiguousCanonicalTypeSymbol.cs | 2 +- .../NoPiaIllegalGenericInstantiationSymbol.cs | 2 +- .../NoPiaMissingCanonicalTypeSymbol.cs | 2 +- .../Symbols/PlaceholderTypeArgumentSymbol.cs | 70 ++++ .../Portable/Symbols/PointerTypeSymbol.cs | 8 +- .../Symbols/Source/CrefTypeParameterSymbol.cs | 14 +- .../Source/IndexedTypeParameterSymbol.cs | 12 +- .../Portable/Symbols/Source/LambdaSymbol.cs | 4 +- .../Symbols/Source/LocalFunctionSymbol.cs | 35 +- .../Source/SourceConstructorSymbolBase.cs | 7 +- .../Source/SourceDelegateMethodSymbol.cs | 7 +- .../Symbols/Source/SourceDestructorSymbol.cs | 7 +- .../Source/SourceEventAccessorSymbol.cs | 7 +- .../Symbols/Source/SourceMethodSymbol.cs | 11 +- .../Symbols/Source/SourceNamedTypeSymbol.cs | 331 +++++++++++++----- .../Source/SourceOrdinaryMethodSymbol.cs | 53 ++- .../Source/SourcePropertyAccessorSymbol.cs | 7 +- .../Source/SourceTypeParameterSymbol.cs | 118 +++++-- .../SourceUserDefinedOperatorSymbolBase.cs | 7 +- .../Source/TypeParameterConstraintClause.cs | 123 ++++--- .../SynthesizedRecordOrdinaryMethod.cs | 4 +- ...ynthesizedSimpleProgramEntryPointSymbol.cs | 7 +- .../Portable/Symbols/TypeParameterBounds.cs | 2 + .../Portable/Symbols/TypeParameterSymbol.cs | 32 +- .../CSharp/Portable/Symbols/TypeSymbol.cs | 11 +- .../Portable/Symbols/TypeWithAnnotations.cs | 45 ++- .../Portable/Symbols/UnboundGenericType.cs | 4 +- .../Wrapped/WrappedTypeParameterSymbol.cs | 16 + .../Semantics/NullableReferenceTypesTests.cs | 165 ++++++++- .../Symbols/FunctionPointerTypeSymbolTests.cs | 3 +- .../Symbols/EETypeParameterSymbol.cs | 16 + .../Symbols/SimpleTypeParameterSymbol.cs | 10 + 51 files changed, 1098 insertions(+), 341 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs b/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs index 28e210564a60b..a786f219dbe6d 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFlags.cs @@ -112,6 +112,12 @@ internal enum BinderFlags : uint /// InEEMethodBinder = 1 << 30, + /// + /// Skip binding type arguments (we use instead). + /// For example, currently used when type constraints are bound in some scenarios. + /// + SuppressTypeArgumentBinding = 1u << 31, + // Groups AllClearedAtExecutableCodeBoundary = InLockBody | InCatchBlock | InCatchFilter | InFinallyBlock | InTryBlockOfTryCatch | InNestedFinallyBlock, diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs index 443413a095dd5..da38ec1659837 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs @@ -25,8 +25,8 @@ internal ImmutableArray BindTypeParameterConstrai ImmutableArray typeParameters, TypeParameterListSyntax typeParameterList, SyntaxList clauses, - ref IReadOnlyDictionary isValueTypeOverride, DiagnosticBag diagnostics, + bool performOnlyCycleSafeValidation, bool isForOverride = false) { Debug.Assert(this.Flags.Includes(BinderFlags.GenericConstraintsClause)); @@ -99,9 +99,7 @@ internal ImmutableArray BindTypeParameterConstrai } } - TypeParameterConstraintClause.AdjustConstraintTypes(containingSymbol, typeParameters, results, ref isValueTypeOverride); - - RemoveInvalidConstraints(typeParameters, results!, syntaxNodes, diagnostics); + RemoveInvalidConstraints(typeParameters, results!, syntaxNodes, performOnlyCycleSafeValidation, diagnostics); foreach (var typeConstraintsSyntaxes in syntaxNodes) { @@ -347,6 +345,7 @@ private static void RemoveInvalidConstraints( ImmutableArray typeParameters, ArrayBuilder constraintClauses, ArrayBuilder?> syntaxNodes, + bool performOnlyCycleSafeValidation, DiagnosticBag diagnostics) { Debug.Assert(typeParameters.Length > 0); @@ -354,7 +353,7 @@ private static void RemoveInvalidConstraints( int n = typeParameters.Length; for (int i = 0; i < n; i++) { - constraintClauses[i] = RemoveInvalidConstraints(typeParameters[i], constraintClauses[i], syntaxNodes[i], diagnostics); + constraintClauses[i] = RemoveInvalidConstraints(typeParameters[i], constraintClauses[i], syntaxNodes[i], performOnlyCycleSafeValidation, diagnostics); } } @@ -362,6 +361,7 @@ private static TypeParameterConstraintClause RemoveInvalidConstraints( TypeParameterSymbol typeParameter, TypeParameterConstraintClause constraintClause, ArrayBuilder? syntaxNodesOpt, + bool performOnlyCycleSafeValidation, DiagnosticBag diagnostics) { if (syntaxNodesOpt != null) @@ -380,9 +380,13 @@ private static TypeParameterConstraintClause RemoveInvalidConstraints( // since, in general, it may be difficult to support all invalid types. // In the future, we may want to include some invalid types // though so the public binding API has the most information. - if (IsValidConstraint(typeParameter.Name, syntax, constraintType, constraintClause.Constraints, constraintTypeBuilder, diagnostics)) + if (IsValidConstraint(typeParameter, syntax, constraintType, constraintClause.Constraints, constraintTypeBuilder, performOnlyCycleSafeValidation, diagnostics)) { - CheckConstraintTypeVisibility(containingSymbol, syntax.Location, constraintType, diagnostics); + if (!performOnlyCycleSafeValidation) + { + CheckConstraintTypeVisibility(containingSymbol, syntax.Location, constraintType, diagnostics); + } + constraintTypeBuilder.Add(constraintType); } } @@ -418,26 +422,28 @@ private static void CheckConstraintTypeVisibility( /// returns false and generates a diagnostic. /// private static bool IsValidConstraint( - string typeParameterName, + TypeParameterSymbol typeParameter, TypeConstraintSyntax syntax, TypeWithAnnotations type, TypeParameterConstraintKind constraints, ArrayBuilder constraintTypes, + bool performOnlyCycleSafeValidation, DiagnosticBag diagnostics) { - if (!isValidConstraintType(syntax, type, diagnostics)) + if (!isValidConstraintType(typeParameter, syntax, type, performOnlyCycleSafeValidation, diagnostics)) { return false; } - if (constraintTypes.Contains(c => type.Equals(c, TypeCompareKind.AllIgnoreOptions))) + if (!performOnlyCycleSafeValidation && constraintTypes.Contains(c => type.Equals(c, TypeCompareKind.AllIgnoreOptions))) { // "Duplicate constraint '{0}' for type parameter '{1}'" - Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type.Type.SetUnknownNullabilityForReferenceTypes(), typeParameterName); + Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type.Type.SetUnknownNullabilityForReferenceTypes(), typeParameter.Name); return false; } - if (type.TypeKind == TypeKind.Class) + if (!type.DefaultType.IsTypeParameter() && // Doing an explicit check for type parameter on unresolved type to avoid cycles while calculating TypeKind. An unresolved type parameter cannot resolve to a class. + type.TypeKind == TypeKind.Class) { // If there is already a struct or class constraint (class constraint could be // 'class' or explicit type), report an error and drop this class. If we don't @@ -486,8 +492,14 @@ private static bool IsValidConstraint( // Returns true if the type is a valid constraint type. // Otherwise returns false and generates a diagnostic. - static bool isValidConstraintType(TypeConstraintSyntax syntax, TypeWithAnnotations typeWithAnnotations, DiagnosticBag diagnostics) + static bool isValidConstraintType(TypeParameterSymbol typeParameter, TypeConstraintSyntax syntax, TypeWithAnnotations typeWithAnnotations, bool performOnlyCycleSafeValidation, DiagnosticBag diagnostics) { + if (typeWithAnnotations.NullableAnnotation == NullableAnnotation.Annotated && performOnlyCycleSafeValidation && + typeWithAnnotations.DefaultType is TypeParameterSymbol typeParameterInConstraint && typeParameterInConstraint.ContainingSymbol == (object)typeParameter.ContainingSymbol) + { + return true; + } + TypeSymbol type = typeWithAnnotations.Type; switch (type.SpecialType) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index 8aad0493e3519..a79f20b35559e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -1154,6 +1154,10 @@ private TypeWithAnnotations BindGenericSimpleNamespaceOrTypeOrAliasSymbol( resultType = unconstructedType.AsUnboundGenericType(); } } + else if ((Flags & BinderFlags.SuppressTypeArgumentBinding) != 0) + { + resultType = unconstructedType.Construct(PlaceholderTypeArgumentSymbol.CreateTypeArguments(unconstructedType.TypeParameters)); + } else { // It's not an unbound type expression, so we must have type arguments, and we have a diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs index 032a1bb84861b..e251241fc67c0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs @@ -88,8 +88,11 @@ public sealed override ImmutableArray TypeParameters get { return _typeParameters; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public sealed override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public sealed override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; internal override int ParameterCount { diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.TypePublicSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.TypePublicSymbol.cs index 1904a5bf76d77..0d646b56d8d50 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.TypePublicSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousType.TypePublicSymbol.cs @@ -330,10 +330,8 @@ internal override ImmutableArray GetDeclaredInterfaces(ConsList internal override bool IsRecord => false; - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { - Debug.Assert(isValueTypeOverrideOpt == null); - if (ReferenceEquals(this, t2)) { return true; diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs index c1e06411964db..252080f9666c0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs @@ -72,6 +72,11 @@ public override bool HasReferenceTypeConstraint get { return false; } } + public override bool IsReferenceTypeFromConstraintTypes + { + get { return false; } + } + internal override bool? ReferenceTypeConstraintIsNullable { get { return false; } @@ -86,6 +91,11 @@ public override bool HasValueTypeConstraint get { return false; } } + public override bool IsValueTypeFromConstraintTypes + { + get { return false; } + } + public override bool HasUnmanagedTypeConstraint { get { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs index 29c4693dd516e..5eb13ac1cca3d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs @@ -337,12 +337,12 @@ public override TResult Accept(CSharpSymbolVisitor visitor) return visitor.VisitArrayType(this); } - internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison) { - return this.Equals(t2 as ArrayTypeSymbol, comparison, isValueTypeOverrideOpt); + return this.Equals(t2 as ArrayTypeSymbol, comparison); } - private bool Equals(ArrayTypeSymbol? other, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt) + private bool Equals(ArrayTypeSymbol? other, TypeCompareKind comparison) { if (ReferenceEquals(this, other)) { @@ -350,7 +350,7 @@ private bool Equals(ArrayTypeSymbol? other, TypeCompareKind comparison, IReadOnl } if ((object?)other == null || !other.HasSameShapeAs(this) || - !other.ElementTypeWithAnnotations.Equals(ElementTypeWithAnnotations, comparison, isValueTypeOverrideOpt)) + !other.ElementTypeWithAnnotations.Equals(ElementTypeWithAnnotations, comparison)) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs index b7f3a5dd27011..dc7b407e8f4ca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -308,36 +309,124 @@ public static TypeParameterBounds ResolveBounds( return bounds; } - internal static ImmutableArray MakeTypeParameterConstraints( - this Symbol containingSymbol, + internal static ImmutableArray> MakeTypeParameterConstraintTypes( + this MethodSymbol containingSymbol, Binder binder, ImmutableArray typeParameters, TypeParameterListSyntax typeParameterList, SyntaxList constraintClauses, - Location location, DiagnosticBag diagnostics) + { + if (typeParameters.Length == 0 || constraintClauses.Count == 0) + { + return ImmutableArray>.Empty; + } + + // Wrap binder from factory in a generic constraints specific binder + // to avoid checking constraints when binding type names. + Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause)); + binder = binder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks); + + ImmutableArray clauses; + clauses = binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses, + diagnostics, performOnlyCycleSafeValidation: false); + + if (clauses.All(clause => clause.ConstraintTypes.IsEmpty)) + { + return ImmutableArray>.Empty; + } + + return clauses.SelectAsArray(clause => clause.ConstraintTypes); + } + + internal static ImmutableArray MakeTypeParameterConstraintKinds( + this MethodSymbol containingSymbol, + Binder binder, + ImmutableArray typeParameters, + TypeParameterListSyntax typeParameterList, + SyntaxList constraintClauses) { if (typeParameters.Length == 0) { - return ImmutableArray.Empty; + return ImmutableArray.Empty; } + ImmutableArray clauses; + if (constraintClauses.Count == 0) { - ImmutableArray defaultClauses = binder.GetDefaultTypeParameterConstraintClauses(typeParameterList); + clauses = binder.GetDefaultTypeParameterConstraintClauses(typeParameterList); + } + else + { + // Wrap binder from factory in a generic constraints specific binder + // Also, suppress type argument binding in constraint types, this helps to avoid cycles while we figure out constraint kinds. + // to avoid checking constraints when binding type names. + Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause)); + binder = binder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressTypeArgumentBinding); - return defaultClauses.ContainsOnlyEmptyConstraintClauses() ? ImmutableArray.Empty : defaultClauses; + var discarded = DiagnosticBag.GetInstance(); // We will recompute this diagnostics more accurately later, when binding without BinderFlags.SuppressTypeArgumentBinding + clauses = binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses, + discarded, performOnlyCycleSafeValidation: true); + discarded.Free(); + + clauses = AdjustConstraintKindsBasedOnConstraintTypes(containingSymbol, typeParameters, clauses); } - // Wrap binder from factory in a generic constraints specific binder - // to avoid checking constraints when binding type names. - Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause)); - binder = binder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks); + if (clauses.All(clause => clause.Constraints == TypeParameterConstraintKind.None)) + { + return ImmutableArray.Empty; + } + + return clauses.SelectAsArray(clause => clause.Constraints); + } + + internal static ImmutableArray AdjustConstraintKindsBasedOnConstraintTypes(Symbol container, ImmutableArray typeParameters, ImmutableArray constraintClauses) + { + int arity = typeParameters.Length; + + Debug.Assert(constraintClauses.Length == arity); + + SmallDictionary isValueTypeMap = TypeParameterConstraintClause.BuildIsValueTypeMap(container, typeParameters, constraintClauses); + SmallDictionary isReferenceTypeFromConstraintTypesMap = TypeParameterConstraintClause.BuildIsReferenceTypeFromConstraintTypesMap(container, typeParameters, constraintClauses); + ArrayBuilder builder = null; + + for (int i = 0; i < arity; i++) + { + var constraint = constraintClauses[i]; + var typeParameter = typeParameters[i]; + TypeParameterConstraintKind constraintKind = constraint.Constraints; + + Debug.Assert((constraintKind & (TypeParameterConstraintKind.ValueTypeFromConstraintTypes | TypeParameterConstraintKind.ReferenceTypeFromConstraintTypes)) == 0); + + if ((constraintKind & TypeParameterConstraintKind.AllValueTypeKinds) == 0 && isValueTypeMap[typeParameter]) + { + constraintKind |= TypeParameterConstraintKind.ValueTypeFromConstraintTypes; + } + + if (isReferenceTypeFromConstraintTypesMap[typeParameter]) + { + constraintKind |= TypeParameterConstraintKind.ReferenceTypeFromConstraintTypes; + } + + if (constraint.Constraints != constraintKind) + { + if (builder == null) + { + builder = ArrayBuilder.GetInstance(constraintClauses.Length); + builder.AddRange(constraintClauses); + } + + builder[i] = TypeParameterConstraintClause.Create(constraintKind, constraint.ConstraintTypes); + } + } + + if (builder != null) + { + constraintClauses = builder.ToImmutableAndFree(); + } - IReadOnlyDictionary isValueTypeOverride = null; - return binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses, - ref isValueTypeOverride, - diagnostics); + return constraintClauses; } // Based on SymbolLoader::SetOverrideConstraints. @@ -1144,12 +1233,12 @@ private static bool SatisfiesConstraintType( private static bool IsReferenceType(TypeParameterSymbol typeParameter, ImmutableArray constraintTypes) { - return typeParameter.HasReferenceTypeConstraint || TypeParameterSymbol.IsReferenceTypeFromConstraintTypes(constraintTypes); + return typeParameter.HasReferenceTypeConstraint || TypeParameterSymbol.CalculateIsReferenceTypeFromConstraintTypes(constraintTypes); } private static bool IsValueType(TypeParameterSymbol typeParameter, ImmutableArray constraintTypes) { - return typeParameter.HasValueTypeConstraint || TypeParameterSymbol.IsValueTypeFromConstraintTypes(constraintTypes); + return typeParameter.HasValueTypeConstraint || TypeParameterSymbol.CalculateIsValueTypeFromConstraintTypes(constraintTypes); } private static TypeParameterDiagnosticInfo GenerateConflictingConstraintsError(TypeParameterSymbol typeParameter, TypeSymbol deducedBase, bool classConflict) diff --git a/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs index 667f7d1081e6f..8dfb42522cd38 100644 --- a/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/DynamicTypeSymbol.cs @@ -192,7 +192,7 @@ public override int GetHashCode() return (int)Microsoft.CodeAnalysis.SpecialType.System_Object; } - internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison) { if ((object?)t2 == null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs index 23c3530a8eb31..efe4c2211d380 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.ErrorTypeParameterSymbol.cs @@ -63,6 +63,14 @@ public override bool HasReferenceTypeConstraint } } + public override bool IsReferenceTypeFromConstraintTypes + { + get + { + return false; + } + } + internal override bool? ReferenceTypeConstraintIsNullable { get @@ -83,6 +91,14 @@ public override bool HasValueTypeConstraint } } + public override bool IsValueTypeFromConstraintTypes + { + get + { + return false; + } + } + public override bool HasUnmanagedTypeConstraint { get @@ -160,7 +176,7 @@ public override int GetHashCode() return Hash.Combine(_container.GetHashCode(), _ordinal); } - internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison) { if (ReferenceEquals(this, t2)) { @@ -170,7 +186,7 @@ internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison, IReadO var other = t2 as ErrorTypeParameterSymbol; return (object?)other != null && other._ordinal == _ordinal && - other.ContainingType.Equals(this.ContainingType, comparison, isValueTypeOverrideOpt); + other.ContainingType.Equals(this.ContainingType, comparison); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs index 3eea818368fc5..e9ff594eb1100 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs @@ -280,7 +280,7 @@ internal static TypeKind ExtractNonErrorTypeKind(TypeSymbol oldSymbol) return commonTypeKind; } - internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison) { if (ReferenceEquals(this, t2)) { @@ -294,7 +294,7 @@ internal override bool Equals(TypeSymbol? t2, TypeCompareKind comparison, IReadO } return - ((object)this.ContainingType != null ? this.ContainingType.Equals(other.ContainingType, comparison, isValueTypeOverrideOpt) : + ((object)this.ContainingType != null ? this.ContainingType.Equals(other.ContainingType, comparison) : (object?)this.ContainingSymbol == null ? (object?)other.ContainingSymbol == null : this.ContainingSymbol.Equals(other.ContainingSymbol)) && this.Name == other.Name && this.Arity == other.Arity; } diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs index 0ce9046675abe..e6e39ce81b085 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs @@ -698,22 +698,22 @@ public override bool Equals(Symbol other, TypeCompareKind compareKind) return false; } - return Equals(method, compareKind, isValueTypeOverride: null); + return Equals(method, compareKind); } - internal bool Equals(FunctionPointerMethodSymbol other, TypeCompareKind compareKind, IReadOnlyDictionary? isValueTypeOverride) + internal bool Equals(FunctionPointerMethodSymbol other, TypeCompareKind compareKind) { return ReferenceEquals(this, other) || - (EqualsNoParameters(other, compareKind, isValueTypeOverride) - && _parameters.SequenceEqual(other._parameters, (compareKind, isValueTypeOverride), - (param1, param2, args) => param1.MethodEqualityChecks(param2, args.compareKind, args.isValueTypeOverride))); + (EqualsNoParameters(other, compareKind) + && _parameters.SequenceEqual(other._parameters, compareKind, + (param1, param2, compareKind) => param1.MethodEqualityChecks(param2, compareKind))); } - private bool EqualsNoParameters(FunctionPointerMethodSymbol other, TypeCompareKind compareKind, IReadOnlyDictionary? isValueTypeOverride) + private bool EqualsNoParameters(FunctionPointerMethodSymbol other, TypeCompareKind compareKind) { if (CallingConvention != other.CallingConvention || !FunctionPointerTypeSymbol.RefKindEquals(compareKind, RefKind, other.RefKind) - || !ReturnTypeWithAnnotations.Equals(other.ReturnTypeWithAnnotations, compareKind, isValueTypeOverride)) + || !ReturnTypeWithAnnotations.Equals(other.ReturnTypeWithAnnotations, compareKind)) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs index 46a4d5319994b..7cb664a1fafd4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerParameterSymbol.cs @@ -40,18 +40,18 @@ public override bool Equals(Symbol other, TypeCompareKind compareKind) return false; } - return Equals(param, compareKind, isValueTypeOverride: null); + return Equals(param, compareKind); } - internal bool Equals(FunctionPointerParameterSymbol other, TypeCompareKind compareKind, IReadOnlyDictionary? isValueTypeOverride) + internal bool Equals(FunctionPointerParameterSymbol other, TypeCompareKind compareKind) => other.Ordinal == Ordinal - && _containingSymbol.Equals(other._containingSymbol, compareKind, isValueTypeOverride); + && _containingSymbol.Equals(other._containingSymbol, compareKind); - internal bool MethodEqualityChecks(FunctionPointerParameterSymbol other, TypeCompareKind compareKind, IReadOnlyDictionary? isValueTypeOverride) + internal bool MethodEqualityChecks(FunctionPointerParameterSymbol other, TypeCompareKind compareKind) => FunctionPointerTypeSymbol.RefKindEquals(compareKind, RefKind, other.RefKind) && ((compareKind & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) != 0 || RefCustomModifiers.SequenceEqual(other.RefCustomModifiers)) - && TypeWithAnnotations.Equals(other.TypeWithAnnotations, compareKind, isValueTypeOverride); + && TypeWithAnnotations.Equals(other.TypeWithAnnotations, compareKind); public override int GetHashCode() { diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs index ac6d381fe816b..962e2ecc4d29a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerTypeSymbol.cs @@ -96,7 +96,7 @@ private FunctionPointerTypeSymbol(FunctionPointerMethodSymbol signature) internal override TResult Accept(CSharpSymbolVisitor visitor, TArgument a) => visitor.VisitFunctionPointerType(this, a); internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => ImmutableArray.Empty; - internal override bool Equals(TypeSymbol t2, TypeCompareKind compareKind, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind compareKind) { if (ReferenceEquals(this, t2)) { @@ -108,7 +108,7 @@ internal override bool Equals(TypeSymbol t2, TypeCompareKind compareKind, IReadO return false; } - return Signature.Equals(other.Signature, compareKind, isValueTypeOverrideOpt); + return Signature.Equals(other.Signature, compareKind); } public override int GetHashCode() diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs index 09d6fedf4fb86..d2c250534fe54 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs @@ -2350,11 +2350,11 @@ internal override NamedTypeSymbol AsNativeInteger() internal override NamedTypeSymbol NativeIntegerUnderlyingType => null; - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { return t2 is NativeIntegerTypeSymbol nativeInteger ? - nativeInteger.Equals(this, comparison, isValueTypeOverrideOpt) : - base.Equals(t2, comparison, isValueTypeOverrideOpt); + nativeInteger.Equals(this, comparison) : + base.Equals(t2, comparison); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs index d754c690bc674..b3418c1a6723d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs @@ -453,6 +453,14 @@ public override bool HasReferenceTypeConstraint } } + public override bool IsReferenceTypeFromConstraintTypes + { + get + { + return CalculateIsReferenceTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics); + } + } + /// /// Returns the byte value from the (single byte) NullableAttribute or nearest /// NullableContextAttribute. Returns 0 if neither attribute is specified. @@ -553,6 +561,15 @@ public override bool HasValueTypeConstraint } } + public override bool IsValueTypeFromConstraintTypes + { + get + { + Debug.Assert(!HasValueTypeConstraint); + return CalculateIsValueTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics); + } + } + public override bool HasUnmanagedTypeConstraint { get diff --git a/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs index 34274c1112a95..7536f79854e32 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs @@ -347,7 +347,7 @@ private TopLevel AsNativeInteger(bool asNativeInt) internal sealed override NamedTypeSymbol? NativeIntegerUnderlyingType => _isNativeInt ? AsNativeInteger(asNativeInt: false) : null; - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { if (ReferenceEquals(this, t2)) { @@ -437,7 +437,7 @@ public override int GetHashCode() return Hash.Combine(_containingType, Hash.Combine(MetadataName, arity)); } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { if (ReferenceEquals(this, t2)) { @@ -447,7 +447,7 @@ internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOn var other = t2 as Nested; return (object?)other != null && string.Equals(MetadataName, other.MetadataName, StringComparison.Ordinal) && arity == other.arity && - _containingType.Equals(other._containingType, comparison, isValueTypeOverrideOpt); + _containingType.Equals(other._containingType, comparison); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs index 1ecf96a2f9ca4..3b431ddfbb454 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs @@ -643,7 +643,7 @@ public override int GetHashCode() /// /// Compares this type to another type. /// - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { if ((object)t2 == this) return true; if ((object)t2 == null) return false; @@ -686,23 +686,23 @@ internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOn // symbols. Therefore this code may not behave correctly if 'this' is List // where List`1 is a missing metadata type symbol, and other is similarly List // but for a reference-distinct List`1. - if (!Equals(thisOriginalDefinition, otherOriginalDefinition, comparison, isValueTypeOverrideOpt)) + if (!Equals(thisOriginalDefinition, otherOriginalDefinition, comparison)) { return false; } // The checks above are supposed to handle the vast majority of cases. // More complicated cases are handled in a special helper to make the common case scenario simple/fast (fewer locals and smaller stack frame) - return EqualsComplicatedCases(other, comparison, isValueTypeOverrideOpt); + return EqualsComplicatedCases(other, comparison); } /// /// Helper for more complicated cases of Equals like when we have generic instantiations or types nested within them. /// - private bool EqualsComplicatedCases(NamedTypeSymbol other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt) + private bool EqualsComplicatedCases(NamedTypeSymbol other, TypeCompareKind comparison) { if ((object)this.ContainingType != null && - !this.ContainingType.Equals(other.ContainingType, comparison, isValueTypeOverrideOpt)) + !this.ContainingType.Equals(other.ContainingType, comparison)) { return false; } @@ -742,7 +742,7 @@ private bool EqualsComplicatedCases(NamedTypeSymbol other, TypeCompareKind compa { var typeArgument = typeArguments[i]; var otherTypeArgument = otherTypeArguments[i]; - if (!typeArgument.Equals(otherTypeArgument, comparison, isValueTypeOverrideOpt)) + if (!typeArgument.Equals(otherTypeArgument, comparison)) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs index 27fba0edda5d0..f42a29fdc6bfb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs @@ -166,7 +166,7 @@ ImmutableArray makeMembers(ImmutableArray underlyingMembers) internal sealed override bool IsRecord => false; internal sealed override bool HasPossibleWellKnownCloneMethod() => false; - internal override bool Equals(TypeSymbol? other, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol? other, TypeCompareKind comparison) { if (other is null) { @@ -176,7 +176,7 @@ internal override bool Equals(TypeSymbol? other, TypeCompareKind comparison, IRe { return true; } - if (!_underlyingType.Equals(other, comparison, isValueTypeOverrideOpt)) + if (!_underlyingType.Equals(other, comparison)) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs index e652a6e888cab..0b578b6715240 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs @@ -86,7 +86,7 @@ public override int GetHashCode() return RuntimeHelpers.GetHashCode(this); } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { return ReferenceEquals(this, t2); } diff --git a/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs index 5bc8369126972..f8247bddef230 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs @@ -72,7 +72,7 @@ public override int GetHashCode() return RuntimeHelpers.GetHashCode(this); } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { return ReferenceEquals(this, t2); } diff --git a/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs index 505fad6d2937b..c50c29cbe0fad 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs @@ -110,7 +110,7 @@ public override int GetHashCode() return RuntimeHelpers.GetHashCode(this); } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { return ReferenceEquals(this, t2); } diff --git a/src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs new file mode 100644 index 0000000000000..3c8eb1aa884d2 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + /// + /// Used for lightweight binding of type constraints. Instead of binding type arguments, + /// we'll just use these placeholders instead. That's good enough binding to compute + /// with minimal binding. + /// + internal sealed class PlaceholderTypeArgumentSymbol : ErrorTypeSymbol + { + private static readonly TypeWithAnnotations s_instance = TypeWithAnnotations.Create(new PlaceholderTypeArgumentSymbol()); + + public static ImmutableArray CreateTypeArguments(ImmutableArray typeParameters) + { + return typeParameters.SelectAsArray(_ => s_instance); + } + + private PlaceholderTypeArgumentSymbol() + { + } + + protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) + { + throw ExceptionUtilities.Unreachable; + } + + public override string Name + { + get + { + return string.Empty; + } + } + + internal override bool MangleName + { + get + { + Debug.Assert(Arity == 0); + return false; + } + } + + internal override DiagnosticInfo? ErrorInfo + { + get + { + return null; + } + } + + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) + { + return (object)t2 == this; + } + + public override int GetHashCode() + { + return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); + } + } +} + diff --git a/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs index 49b666168577c..ed886a99c7f43 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs @@ -227,19 +227,19 @@ public override int GetHashCode() return Hash.Combine(current, indirections); } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { - return this.Equals(t2 as PointerTypeSymbol, comparison, isValueTypeOverrideOpt); + return this.Equals(t2 as PointerTypeSymbol, comparison); } - private bool Equals(PointerTypeSymbol other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt) + private bool Equals(PointerTypeSymbol other, TypeCompareKind comparison) { if (ReferenceEquals(this, other)) { return true; } - if ((object)other == null || !other._pointedAtType.Equals(_pointedAtType, comparison, isValueTypeOverrideOpt)) + if ((object)other == null || !other._pointedAtType.Equals(_pointedAtType, comparison)) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs index 42dd2f0445822..fc58366c6ee63 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/CrefTypeParameterSymbol.cs @@ -93,10 +93,8 @@ public override int Ordinal get { return _ordinal; } } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { - Debug.Assert(isValueTypeOverrideOpt == null); - if (ReferenceEquals(this, t2)) { return true; @@ -129,11 +127,21 @@ public override bool HasValueTypeConstraint get { return false; } } + public override bool IsValueTypeFromConstraintTypes + { + get { return false; } + } + public override bool HasReferenceTypeConstraint { get { return false; } } + public override bool IsReferenceTypeFromConstraintTypes + { + get { return false; } + } + internal override bool? ReferenceTypeConstraintIsNullable { get { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs index 2b9b7d9fa66cd..063dfe270c7b7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/IndexedTypeParameterSymbol.cs @@ -105,7 +105,7 @@ public override int Ordinal } // These object are unique (per index). - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { return ReferenceEquals(this, t2); } @@ -125,11 +125,21 @@ public override bool HasValueTypeConstraint get { return false; } } + public override bool IsValueTypeFromConstraintTypes + { + get { return false; } + } + public override bool HasReferenceTypeConstraint { get { return false; } } + public override bool IsReferenceTypeFromConstraintTypes + { + get { return false; } + } + internal override bool? ReferenceTypeConstraintIsNullable { get { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index c52f9a8c209ed..15dac695e754c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -417,7 +417,9 @@ internal override bool GenerateDebugInfo internal override bool IsInitOnly => false; - public override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; + public override ImmutableArray> GetTypeParameterConstraintTypes() => ImmutableArray>.Empty; + + public override ImmutableArray GetTypeParameterConstraintKinds() => ImmutableArray.Empty; internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 9051337634a86..43e3c79da6a07 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -23,7 +23,8 @@ internal sealed class LocalFunctionSymbol : SourceMethodSymbolWithAttributes private ImmutableArray _lazyParameters; private bool _lazyIsVarArg; // Initialized in two steps. Hold a copy if accessing during initialization. - private ImmutableArray _lazyTypeParameterConstraints; + private ImmutableArray> _lazyTypeParameterConstraintTypes; + private ImmutableArray _lazyTypeParameterConstraintKinds; private TypeWithAnnotations.Boxed? _lazyReturnType; private TypeWithAnnotations.Boxed? _lazyIteratorElementType; @@ -459,31 +460,49 @@ private ImmutableArray MakeTypeParameters(Diagn return result.ToImmutableAndFree(); } - public override ImmutableArray GetTypeParameterConstraintClauses() + public override ImmutableArray> GetTypeParameterConstraintTypes() { - if (_lazyTypeParameterConstraints.IsDefault) + if (_lazyTypeParameterConstraintTypes.IsDefault) { + GetTypeParameterConstraintKinds(); + var syntax = Syntax; var diagnostics = DiagnosticBag.GetInstance(); - var constraints = this.MakeTypeParameterConstraints( + var constraints = this.MakeTypeParameterConstraintTypes( _binder, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, - syntax.Identifier.GetLocation(), diagnostics); lock (_declarationDiagnostics) { - if (_lazyTypeParameterConstraints.IsDefault) + if (_lazyTypeParameterConstraintTypes.IsDefault) { _declarationDiagnostics.AddRange(diagnostics); - _lazyTypeParameterConstraints = constraints; + _lazyTypeParameterConstraintTypes = constraints; } } diagnostics.Free(); } - return _lazyTypeParameterConstraints; + return _lazyTypeParameterConstraintTypes; + } + + public override ImmutableArray GetTypeParameterConstraintKinds() + { + if (_lazyTypeParameterConstraintKinds.IsDefault) + { + var syntax = Syntax; + var constraints = this.MakeTypeParameterConstraintKinds( + _binder, + TypeParameters, + syntax.TypeParameterList, + syntax.ConstraintClauses); + + ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintKinds, constraints); + } + + return _lazyTypeParameterConstraintKinds; } public override int GetHashCode() diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs index 77588066eb2ac..4549b43538b32 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs @@ -138,8 +138,11 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public sealed override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public sealed override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; public override RefKind RefKind { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs index 661cfb7fe19c5..029f53d877cc8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs @@ -138,8 +138,11 @@ public override ImmutableArray TypeParameters } } - public override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; public sealed override TypeWithAnnotations ReturnTypeWithAnnotations { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs index 1702cd5e785f6..4b1a2100f3299 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs @@ -98,8 +98,11 @@ public override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; public override RefKind RefKind { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs index ac0c74448647c..fbfccf3e3873a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs @@ -208,8 +208,11 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public sealed override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public sealed override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; internal Location Location { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs index 929f3d24f05c6..a1839c686ef28 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs @@ -17,10 +17,15 @@ internal abstract class SourceMethodSymbol : MethodSymbol { /// /// If there are no constraints, returns an empty immutable array. Otherwise, returns an immutable - /// array of clauses, indexed by the constrained type parameter in . - /// If a type parameter does not have constraints, the corresponding entry in the array is null. + /// array of types, indexed by the constrained type parameter in . /// - public abstract ImmutableArray GetTypeParameterConstraintClauses(); + public abstract ImmutableArray> GetTypeParameterConstraintTypes(); + + /// + /// If there are no constraints, returns an empty immutable array. Otherwise, returns an immutable + /// array of kinds, indexed by the constrained type parameter in . + /// + public abstract ImmutableArray GetTypeParameterConstraintKinds(); protected static void ReportBadRefToken(TypeSyntax returnTypeSyntax, DiagnosticBag diagnostics) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index f69f7ff5fae00..998eb6a00eb2c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -25,10 +25,16 @@ internal sealed partial class SourceNamedTypeSymbol : SourceMemberContainerTypeS private ImmutableArray _lazyTypeParameters; /// - /// A collection of type parameter constraints, populated when - /// constraints for the first type parameter are requested. + /// A collection of type parameter constraint types, populated when + /// constraint types for the first type parameter are requested. /// - private ImmutableArray _lazyTypeParameterConstraints; + private ImmutableArray> _lazyTypeParameterConstraintTypes; + + /// + /// A collection of type parameter constraint kinds, populated when + /// constraint kinds for the first type parameter are requested. + /// + private ImmutableArray _lazyTypeParameterConstraintKinds; private CustomAttributesBag _lazyCustomAttributesBag; @@ -251,26 +257,55 @@ private ImmutableArray MakeTypeParameters(DiagnosticBag dia } /// - /// Returns the constraint clause for the given type parameter. + /// Returns the constraint types for the given type parameter. /// - internal TypeParameterConstraintClause GetTypeParameterConstraintClause(int ordinal) + internal ImmutableArray GetTypeParameterConstraintTypes(int ordinal) { - var clauses = _lazyTypeParameterConstraints; - if (clauses.IsDefault) + var constraintTypes = GetTypeParameterConstraintTypes(); + return (constraintTypes.Length > 0) ? constraintTypes[ordinal] : ImmutableArray.Empty; + } + + private ImmutableArray> GetTypeParameterConstraintTypes() + { + var constraintTypes = _lazyTypeParameterConstraintTypes; + if (constraintTypes.IsDefault) { + GetTypeParameterConstraintKinds(); + var diagnostics = DiagnosticBag.GetInstance(); - if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraints, MakeTypeParameterConstraints(diagnostics))) + if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintTypes, MakeTypeParameterConstraintTypes(diagnostics))) { this.AddDeclarationDiagnostics(diagnostics); } diagnostics.Free(); - clauses = _lazyTypeParameterConstraints; + constraintTypes = _lazyTypeParameterConstraintTypes; + } + + return constraintTypes; + } + + /// + /// Returns the constraint kind for the given type parameter. + /// + internal TypeParameterConstraintKind GetTypeParameterConstraintKind(int ordinal) + { + var constraintKinds = GetTypeParameterConstraintKinds(); + return (constraintKinds.Length > 0) ? constraintKinds[ordinal] : TypeParameterConstraintKind.None; + } + + private ImmutableArray GetTypeParameterConstraintKinds() + { + var constraintKinds = _lazyTypeParameterConstraintKinds; + if (constraintKinds.IsDefault) + { + ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintKinds, MakeTypeParameterConstraintKinds()); + constraintKinds = _lazyTypeParameterConstraintKinds; } - return (clauses.Length > 0) ? clauses[ordinal] : TypeParameterConstraintClause.Empty; + return constraintKinds; } - private ImmutableArray MakeTypeParameterConstraints(DiagnosticBag diagnostics) + private ImmutableArray> MakeTypeParameterConstraintTypes(DiagnosticBag diagnostics) { var typeParameters = this.TypeParameters; var results = ImmutableArray.Empty; @@ -278,18 +313,88 @@ private ImmutableArray MakeTypeParameterConstrain int arity = typeParameters.Length; if (arity > 0) { - bool skipPartialDeclarationsWithoutConstraintClauses = false; + bool skipPartialDeclarationsWithoutConstraintClauses = SkipPartialDeclarationsWithoutConstraintClauses(); + ArrayBuilder> otherPartialClauses = null; foreach (var decl in declaration.Declarations) { - if (GetConstraintClauses((CSharpSyntaxNode)decl.SyntaxReference.GetSyntax(), out _).Count != 0) + var syntaxRef = decl.SyntaxReference; + var constraintClauses = GetConstraintClauses((CSharpSyntaxNode)syntaxRef.GetSyntax(), out TypeParameterListSyntax typeParameterList); + + if (skipPartialDeclarationsWithoutConstraintClauses && constraintClauses.Count == 0) { - skipPartialDeclarationsWithoutConstraintClauses = true; - break; + continue; + } + + var binderFactory = this.DeclaringCompilation.GetBinderFactory(syntaxRef.SyntaxTree); + Binder binder; + ImmutableArray constraints; + + if (constraintClauses.Count == 0) + { + binder = binderFactory.GetBinder(typeParameterList.Parameters[0]); + + constraints = binder.GetDefaultTypeParameterConstraintClauses(typeParameterList); + } + else + { + binder = binderFactory.GetBinder(constraintClauses[0]); + + // Wrap binder from factory in a generic constraints specific binder + // to avoid checking constraints when binding type names. + Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause)); + binder = binder.WithContainingMemberOrLambda(this).WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks); + + constraints = binder.BindTypeParameterConstraintClauses(this, typeParameters, typeParameterList, constraintClauses, diagnostics, performOnlyCycleSafeValidation: false); + } + + Debug.Assert(constraints.Length == arity); + + if (results.Length == 0) + { + results = constraints; } + else + { + (otherPartialClauses ??= ArrayBuilder>.GetInstance()).Add(constraints); + } + } + + results = MergeConstraintTypesForPartialDeclarations(results, otherPartialClauses, diagnostics); + + if (results.All(clause => clause.ConstraintTypes.IsEmpty)) + { + results = ImmutableArray.Empty; + } + + otherPartialClauses?.Free(); + } + + return results.SelectAsArray(clause => clause.ConstraintTypes); + } + + private bool SkipPartialDeclarationsWithoutConstraintClauses() + { + foreach (var decl in declaration.Declarations) + { + if (GetConstraintClauses((CSharpSyntaxNode)decl.SyntaxReference.GetSyntax(), out _).Count != 0) + { + return true; } + } + + return false; + } - IReadOnlyDictionary isValueTypeOverride = null; + private ImmutableArray MakeTypeParameterConstraintKinds() + { + var typeParameters = this.TypeParameters; + var results = ImmutableArray.Empty; + + int arity = typeParameters.Length; + if (arity > 0) + { + bool skipPartialDeclarationsWithoutConstraintClauses = SkipPartialDeclarationsWithoutConstraintClauses(); ArrayBuilder> otherPartialClauses = null; foreach (var decl in declaration.Declarations) @@ -309,7 +414,6 @@ private ImmutableArray MakeTypeParameterConstrain if (constraintClauses.Count == 0) { binder = binderFactory.GetBinder(typeParameterList.Parameters[0]); - constraints = binder.GetDefaultTypeParameterConstraintClauses(typeParameterList); } else @@ -318,10 +422,13 @@ private ImmutableArray MakeTypeParameterConstrain // Wrap binder from factory in a generic constraints specific binder // to avoid checking constraints when binding type names. + // Also, suppress type argument binding in constraint types, this helps to avoid cycles while we figure out constraint kinds. Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause)); - binder = binder.WithContainingMemberOrLambda(this).WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks); + binder = binder.WithContainingMemberOrLambda(this).WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressTypeArgumentBinding); - constraints = binder.BindTypeParameterConstraintClauses(this, typeParameters, typeParameterList, constraintClauses, ref isValueTypeOverride, diagnostics); + var discarded = DiagnosticBag.GetInstance(); // We will recompute this diagnostics more accurately later, when binding without BinderFlags.SuppressTypeArgumentBinding + constraints = binder.BindTypeParameterConstraintClauses(this, typeParameters, typeParameterList, constraintClauses, discarded, performOnlyCycleSafeValidation: true); + discarded.Free(); } Debug.Assert(constraints.Length == arity); @@ -336,9 +443,10 @@ private ImmutableArray MakeTypeParameterConstrain } } - results = MergeConstraintsForPartialDeclarations(results, otherPartialClauses, isValueTypeOverride, diagnostics); + results = MergeConstraintKindsForPartialDeclarations(results, otherPartialClauses); + results = ConstraintsHelper.AdjustConstraintKindsBasedOnConstraintTypes(this, typeParameters, results); - if (results.ContainsOnlyEmptyConstraintClauses()) + if (results.All(clause => clause.Constraints == TypeParameterConstraintKind.None)) { results = ImmutableArray.Empty; } @@ -346,7 +454,7 @@ private ImmutableArray MakeTypeParameterConstrain otherPartialClauses?.Free(); } - return results; + return results.SelectAsArray(clause => clause.Constraints); } private static SyntaxList GetConstraintClauses(CSharpSyntaxNode node, out TypeParameterListSyntax typeParameterList) @@ -372,10 +480,9 @@ private static SyntaxList GetConstraintClau /// /// Note, only nullability aspects are merged if possible, other mismatches are treated as failures. /// - private ImmutableArray MergeConstraintsForPartialDeclarations(ImmutableArray constraintClauses, - ArrayBuilder> otherPartialClauses, - IReadOnlyDictionary isValueTypeOverride, - DiagnosticBag diagnostics) + private ImmutableArray MergeConstraintTypesForPartialDeclarations(ImmutableArray constraintClauses, + ArrayBuilder> otherPartialClauses, + DiagnosticBag diagnostics) { if (otherPartialClauses == null) { @@ -392,17 +499,16 @@ private ImmutableArray MergeConstraintsForPartial { var constraint = constraintClauses[i]; - TypeParameterConstraintKind mergedKind = constraint.Constraints; ImmutableArray originalConstraintTypes = constraint.ConstraintTypes; ArrayBuilder mergedConstraintTypes = null; SmallDictionary originalConstraintTypesMap = null; // Constraints defined on multiple partial declarations. // Report any mismatched constraints. - bool report = false; + bool report = (GetTypeParameterConstraintKind(i) & TypeParameterConstraintKind.PartialMismatch) != 0; foreach (ImmutableArray otherPartialConstraints in otherPartialClauses) { - if (!mergeConstraints(ref mergedKind, originalConstraintTypes, ref originalConstraintTypesMap, ref mergedConstraintTypes, otherPartialConstraints[i], isValueTypeOverride)) + if (!mergeConstraints(originalConstraintTypes, ref originalConstraintTypesMap, ref mergedConstraintTypes, otherPartialConstraints[i])) { report = true; } @@ -414,23 +520,14 @@ private ImmutableArray MergeConstraintsForPartial diagnostics.Add(ErrorCode.ERR_PartialWrongConstraints, Locations[0], this, typeParameters[i]); } - if (constraint.Constraints != mergedKind || mergedConstraintTypes != null) + if (mergedConstraintTypes != null) { - Debug.Assert((constraint.Constraints & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull)) == - (mergedKind & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull))); - Debug.Assert((mergedKind & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) == 0 || - (constraint.Constraints & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0); - Debug.Assert((constraint.Constraints & TypeParameterConstraintKind.AllReferenceTypeKinds) == (mergedKind & TypeParameterConstraintKind.AllReferenceTypeKinds) || - (constraint.Constraints & TypeParameterConstraintKind.AllReferenceTypeKinds) == TypeParameterConstraintKind.ReferenceType); #if DEBUG - if (mergedConstraintTypes != null) - { - Debug.Assert(originalConstraintTypes.Length == mergedConstraintTypes.Count); + Debug.Assert(originalConstraintTypes.Length == mergedConstraintTypes.Count); - for (int j = 0; j < originalConstraintTypes.Length; j++) - { - Debug.Assert(originalConstraintTypes[j].Equals(mergedConstraintTypes[j], TypeCompareKind.ObliviousNullableModifierMatchesAny, isValueTypeOverride)); - } + for (int j = 0; j < originalConstraintTypes.Length; j++) + { + Debug.Assert(originalConstraintTypes[j].Equals(mergedConstraintTypes[j], TypeCompareKind.ObliviousNullableModifierMatchesAny)); } #endif if (builder == null) @@ -439,7 +536,7 @@ private ImmutableArray MergeConstraintsForPartial builder.AddRange(constraintClauses); } - builder[i] = TypeParameterConstraintClause.Create(mergedKind, + builder[i] = TypeParameterConstraintClause.Create(constraint.Constraints, mergedConstraintTypes?.ToImmutableAndFree() ?? originalConstraintTypes); } } @@ -451,50 +548,16 @@ private ImmutableArray MergeConstraintsForPartial return constraintClauses; - static bool mergeConstraints(ref TypeParameterConstraintKind mergedKind, ImmutableArray originalConstraintTypes, + static bool mergeConstraints(ImmutableArray originalConstraintTypes, ref SmallDictionary originalConstraintTypesMap, ref ArrayBuilder mergedConstraintTypes, - TypeParameterConstraintClause clause, IReadOnlyDictionary isValueTypeOverride) + TypeParameterConstraintClause clause) { bool result = true; - if ((mergedKind & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull)) != (clause.Constraints & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull))) - { - result = false; - } - - if ((mergedKind & TypeParameterConstraintKind.ReferenceType) != 0 && (clause.Constraints & TypeParameterConstraintKind.ReferenceType) != 0) - { - // Try merging nullability of a 'class' constraint - TypeParameterConstraintKind clause1Constraints = mergedKind & TypeParameterConstraintKind.AllReferenceTypeKinds; - TypeParameterConstraintKind clause2Constraints = clause.Constraints & TypeParameterConstraintKind.AllReferenceTypeKinds; - if (clause1Constraints != clause2Constraints) - { - if (clause1Constraints == TypeParameterConstraintKind.ReferenceType) // Oblivious - { - // Take nullability from clause2 - mergedKind = (mergedKind & (~TypeParameterConstraintKind.AllReferenceTypeKinds)) | clause2Constraints; - } - else if (clause2Constraints != TypeParameterConstraintKind.ReferenceType) - { - // Neither nullability is oblivious and they do not match. Cannot merge. - result = false; - } - } - } - if (originalConstraintTypes.Length == 0) { if (clause.ConstraintTypes.Length == 0) { - // Try merging nullability of implied 'object' constraint - if (((mergedKind | clause.Constraints) & ~(TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType | TypeParameterConstraintKind.Constructor)) == 0 && - (mergedKind & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0 && // 'object~' - (clause.Constraints & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) == 0) // 'object?' - { - // Merged value is 'object?' - mergedKind &= ~TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType; - } - return result; } @@ -506,7 +569,7 @@ static bool mergeConstraints(ref TypeParameterConstraintKind mergedKind, Immutab } originalConstraintTypesMap ??= toDictionary(originalConstraintTypes, - new TypeWithAnnotations.EqualsComparer(TypeCompareKind.IgnoreNullableModifiersForReferenceTypes, isValueTypeOverride)); + TypeWithAnnotations.EqualsComparer.IgnoreNullableModifiersForReferenceTypesComparer); SmallDictionary clauseConstraintTypesMap = toDictionary(clause.ConstraintTypes, originalConstraintTypesMap.Comparer); foreach (int index1 in originalConstraintTypesMap.Values) @@ -523,14 +586,14 @@ static bool mergeConstraints(ref TypeParameterConstraintKind mergedKind, Immutab TypeWithAnnotations constraintType2 = clause.ConstraintTypes[index2]; - if (!constraintType1.Equals(constraintType2, TypeCompareKind.ObliviousNullableModifierMatchesAny, isValueTypeOverride)) + if (!constraintType1.Equals(constraintType2, TypeCompareKind.ObliviousNullableModifierMatchesAny)) { // Nullability mismatch that doesn't involve oblivious result = false; continue; } - if (!constraintType1.Equals(constraintType2, TypeCompareKind.ConsiderEverything, isValueTypeOverride)) + if (!constraintType1.Equals(constraintType2, TypeCompareKind.ConsiderEverything)) { // Mismatch with oblivious, merge if (mergedConstraintTypes == null) @@ -568,6 +631,102 @@ static SmallDictionary toDictionary(ImmutableArray + /// Note, only nullability aspects are merged if possible, other mismatches are treated as failures. + /// + private ImmutableArray MergeConstraintKindsForPartialDeclarations(ImmutableArray constraintClauses, + ArrayBuilder> otherPartialClauses) + { + if (otherPartialClauses == null) + { + return constraintClauses; + } + + ArrayBuilder builder = null; + var typeParameters = TypeParameters; + int arity = typeParameters.Length; + + Debug.Assert(constraintClauses.Length == arity); + + for (int i = 0; i < arity; i++) + { + var constraint = constraintClauses[i]; + + TypeParameterConstraintKind mergedKind = constraint.Constraints; + ImmutableArray originalConstraintTypes = constraint.ConstraintTypes; + + foreach (ImmutableArray otherPartialConstraints in otherPartialClauses) + { + mergeConstraints(ref mergedKind, originalConstraintTypes, otherPartialConstraints[i]); + } + + if (constraint.Constraints != mergedKind) + { + Debug.Assert((constraint.Constraints & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull)) == + (mergedKind & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull))); + Debug.Assert((mergedKind & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) == 0 || + (constraint.Constraints & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0); + Debug.Assert((constraint.Constraints & TypeParameterConstraintKind.AllReferenceTypeKinds) == (mergedKind & TypeParameterConstraintKind.AllReferenceTypeKinds) || + (constraint.Constraints & TypeParameterConstraintKind.AllReferenceTypeKinds) == TypeParameterConstraintKind.ReferenceType); + + if (builder == null) + { + builder = ArrayBuilder.GetInstance(constraintClauses.Length); + builder.AddRange(constraintClauses); + } + + builder[i] = TypeParameterConstraintClause.Create(mergedKind, originalConstraintTypes); + } + } + + if (builder != null) + { + constraintClauses = builder.ToImmutableAndFree(); + } + + return constraintClauses; + + static void mergeConstraints(ref TypeParameterConstraintKind mergedKind, ImmutableArray originalConstraintTypes, TypeParameterConstraintClause clause) + { + if ((mergedKind & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull)) != (clause.Constraints & (TypeParameterConstraintKind.AllNonNullableKinds | TypeParameterConstraintKind.NotNull))) + { + mergedKind |= TypeParameterConstraintKind.PartialMismatch; + } + + if ((mergedKind & TypeParameterConstraintKind.ReferenceType) != 0 && (clause.Constraints & TypeParameterConstraintKind.ReferenceType) != 0) + { + // Try merging nullability of a 'class' constraint + TypeParameterConstraintKind clause1Constraints = mergedKind & TypeParameterConstraintKind.AllReferenceTypeKinds; + TypeParameterConstraintKind clause2Constraints = clause.Constraints & TypeParameterConstraintKind.AllReferenceTypeKinds; + if (clause1Constraints != clause2Constraints) + { + if (clause1Constraints == TypeParameterConstraintKind.ReferenceType) // Oblivious + { + // Take nullability from clause2 + mergedKind = (mergedKind & (~TypeParameterConstraintKind.AllReferenceTypeKinds)) | clause2Constraints; + } + else if (clause2Constraints != TypeParameterConstraintKind.ReferenceType) + { + // Neither nullability is oblivious and they do not match. Cannot merge. + mergedKind |= TypeParameterConstraintKind.PartialMismatch; + } + } + } + + if (originalConstraintTypes.Length == 0 && clause.ConstraintTypes.Length == 0) + { + // Try merging nullability of implied 'object' constraint + if (((mergedKind | clause.Constraints) & ~(TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType | TypeParameterConstraintKind.Constructor)) == 0 && + (mergedKind & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0 && // 'object~' + (clause.Constraints & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) == 0) // 'object?' + { + // Merged value is 'object?' + mergedKind &= ~TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType; + } + } + } + } + internal sealed override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics { get @@ -1387,11 +1546,11 @@ internal override NamedTypeSymbol AsNativeInteger() internal override NamedTypeSymbol NativeIntegerUnderlyingType => null; - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { return t2 is NativeIntegerTypeSymbol nativeInteger ? - nativeInteger.Equals(this, comparison, isValueTypeOverrideOpt) : - base.Equals(t2, comparison, isValueTypeOverrideOpt); + nativeInteger.Equals(this, comparison) : + base.Equals(t2, comparison); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index bcbadaf5bac39..a66a05a6382d3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -8,6 +8,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; @@ -25,11 +26,18 @@ internal sealed class SourceOrdinaryMethodSymbol : SourceOrdinaryMethodSymbolBas private bool _lazyIsVararg; /// - /// A collection of type parameter constraints, populated when - /// constraints for the first type parameter is requested. + /// A collection of type parameter constraint types, populated when + /// constraint types for the first type parameter is requested. /// Initialized in two steps. Hold a copy if accessing during initialization. /// - private ImmutableArray _lazyTypeParameterConstraints; + private ImmutableArray> _lazyTypeParameterConstraintTypes; + + /// + /// A collection of type parameter constraint kinds, populated when + /// constraint kinds for the first type parameter is requested. + /// Initialized in two steps. Hold a copy if accessing during initialization. + /// + private ImmutableArray _lazyTypeParameterConstraintKinds; /// /// If this symbol represents a partial method definition or implementation part, its other part (if any). @@ -163,11 +171,10 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray isValueTypeOverride = null; declaredConstraints = signatureBinder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks). BindTypeParameterConstraintClauses(this, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, - ref isValueTypeOverride, - diagnostics, isForOverride: true); + diagnostics, performOnlyCycleSafeValidation: false, isForOverride: true); + Debug.Assert(declaredConstraints.All(clause => clause.ConstraintTypes.IsEmpty)); } // Force resolution of nullable type parameter used in the signature of an override or explicit interface implementation @@ -282,31 +289,53 @@ protected override void CompleteAsyncMethodChecksBetweenStartAndFinish() } } - public override ImmutableArray GetTypeParameterConstraintClauses() + public override ImmutableArray> GetTypeParameterConstraintTypes() { - if (_lazyTypeParameterConstraints.IsDefault) + if (_lazyTypeParameterConstraintTypes.IsDefault) { + GetTypeParameterConstraintKinds(); + var diagnostics = DiagnosticBag.GetInstance(); var syntax = GetSyntax(); var withTypeParametersBinder = this.DeclaringCompilation .GetBinderFactory(syntax.SyntaxTree) .GetBinder(syntax.ReturnType, syntax, this); - var constraints = this.MakeTypeParameterConstraints( + var constraints = this.MakeTypeParameterConstraintTypes( withTypeParametersBinder, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, - syntax.Identifier.GetLocation(), diagnostics); - if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraints, constraints)) + if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintTypes, constraints)) { this.AddDeclarationDiagnostics(diagnostics); } diagnostics.Free(); } - return _lazyTypeParameterConstraints; + return _lazyTypeParameterConstraintTypes; + } + + public override ImmutableArray GetTypeParameterConstraintKinds() + { + if (_lazyTypeParameterConstraintKinds.IsDefault) + { + var syntax = GetSyntax(); + var withTypeParametersBinder = + this.DeclaringCompilation + .GetBinderFactory(syntax.SyntaxTree) + .GetBinder(syntax.ReturnType, syntax, this); + var constraints = this.MakeTypeParameterConstraintKinds( + withTypeParametersBinder, + TypeParameters, + syntax.TypeParameterList, + syntax.ConstraintClauses); + + ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintKinds, constraints); + } + + return _lazyTypeParameterConstraintKinds; } public override bool IsVararg diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index 32f87d58feaab..6eac1408f1848 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -452,8 +452,11 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public sealed override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public sealed override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; public sealed override RefKind RefKind { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs index f51384be91489..ff8f1bfd7ff52 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs @@ -488,7 +488,7 @@ public override bool HasConstructorConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.Constructor) != 0; } } @@ -497,25 +497,44 @@ public override bool HasValueTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.AllValueTypeKinds) != 0; } } + public override bool IsValueTypeFromConstraintTypes + { + get + { + Debug.Assert(!HasValueTypeConstraint); + var constraints = this.GetConstraintKinds(); + return (constraints & TypeParameterConstraintKind.ValueTypeFromConstraintTypes) != 0; + } + } + public override bool HasReferenceTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.ReferenceType) != 0; } } + public override bool IsReferenceTypeFromConstraintTypes + { + get + { + var constraints = this.GetConstraintKinds(); + return (constraints & TypeParameterConstraintKind.ReferenceTypeFromConstraintTypes) != 0; + } + } + internal override bool? ReferenceTypeConstraintIsNullable { get { - return CalculateReferenceTypeConstraintIsNullable(this.GetDeclaredConstraints()); + return CalculateReferenceTypeConstraintIsNullable(this.GetConstraintKinds()); } } @@ -523,7 +542,7 @@ public override bool HasNotNullConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.NotNull) != 0; } } @@ -532,7 +551,7 @@ internal override bool? IsNotNullable { get { - if ((this.GetDeclaredConstraints() & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) + if ((this.GetConstraintKinds() & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) { return null; } @@ -545,7 +564,7 @@ public override bool HasUnmanagedTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.Unmanaged) != 0; } } @@ -555,27 +574,20 @@ protected override ImmutableArray ContainerTypeParameters get { return _owner.TypeParameters; } } - private TypeParameterConstraintClause GetTypeParameterConstraintClause() - { - return _owner.GetTypeParameterConstraintClause(this.Ordinal); - } - protected override TypeParameterBounds ResolveBounds(ConsList inProgress, DiagnosticBag diagnostics) { - var constraintClause = GetTypeParameterConstraintClause(); - if (constraintClause.IsEmpty) + var constraintTypes = _owner.GetTypeParameterConstraintTypes(this.Ordinal); + if (constraintTypes.IsEmpty && GetConstraintKinds() == TypeParameterConstraintKind.None) { return null; } - var constraintTypes = constraintClause.ConstraintTypes; return this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited: false, this.DeclaringCompilation, diagnostics); } - private TypeParameterConstraintKind GetDeclaredConstraints() + private TypeParameterConstraintKind GetConstraintKinds() { - var constraintClause = GetTypeParameterConstraintClause(); - return constraintClause.Constraints; + return _owner.GetTypeParameterConstraintKind(this.Ordinal); } } @@ -609,7 +621,7 @@ public override bool HasConstructorConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.Constructor) != 0; } } @@ -618,25 +630,44 @@ public override bool HasValueTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.AllValueTypeKinds) != 0; } } + public override bool IsValueTypeFromConstraintTypes + { + get + { + Debug.Assert(!HasValueTypeConstraint); + var constraints = this.GetConstraintKinds(); + return (constraints & TypeParameterConstraintKind.ValueTypeFromConstraintTypes) != 0; + } + } + public override bool HasReferenceTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.ReferenceType) != 0; } } + public override bool IsReferenceTypeFromConstraintTypes + { + get + { + var constraints = this.GetConstraintKinds(); + return (constraints & TypeParameterConstraintKind.ReferenceTypeFromConstraintTypes) != 0; + } + } + public override bool HasNotNullConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.NotNull) != 0; } } @@ -645,7 +676,7 @@ internal override bool? ReferenceTypeConstraintIsNullable { get { - return CalculateReferenceTypeConstraintIsNullable(this.GetDeclaredConstraints()); + return CalculateReferenceTypeConstraintIsNullable(this.GetConstraintKinds()); } } @@ -653,7 +684,7 @@ internal override bool? IsNotNullable { get { - if ((this.GetDeclaredConstraints() & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) + if ((this.GetConstraintKinds() & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) != 0) { return null; } @@ -666,7 +697,7 @@ public override bool HasUnmanagedTypeConstraint { get { - var constraints = this.GetDeclaredConstraints(); + var constraints = this.GetConstraintKinds(); return (constraints & TypeParameterConstraintKind.Unmanaged) != 0; } } @@ -676,28 +707,23 @@ protected override ImmutableArray ContainerTypeParameters get { return _owner.TypeParameters; } } - private TypeParameterConstraintClause GetTypeParameterConstraintClause() - { - var constraintClauses = _owner.GetTypeParameterConstraintClauses(); - return constraintClauses.IsEmpty ? TypeParameterConstraintClause.Empty : constraintClauses[Ordinal]; - } - protected override TypeParameterBounds ResolveBounds(ConsList inProgress, DiagnosticBag diagnostics) { - var constraintClause = GetTypeParameterConstraintClause(); - if (constraintClause.IsEmpty) + var constraints = _owner.GetTypeParameterConstraintTypes(); + var constraintTypes = constraints.IsEmpty ? ImmutableArray.Empty : constraints[Ordinal]; + + if (constraintTypes.IsEmpty && GetConstraintKinds() == TypeParameterConstraintKind.None) { return null; } - var constraintTypes = constraintClause.ConstraintTypes; return this.ResolveBounds(this.ContainingAssembly.CorLibrary, inProgress.Prepend(this), constraintTypes, inherited: false, this.DeclaringCompilation, diagnostics); } - internal TypeParameterConstraintKind GetDeclaredConstraints() + private TypeParameterConstraintKind GetConstraintKinds() { - var constraintClause = GetTypeParameterConstraintClause(); - return constraintClause.Constraints; + var constraintKinds = _owner.GetTypeParameterConstraintKinds(); + return constraintKinds.IsEmpty ? TypeParameterConstraintKind.None : constraintKinds[Ordinal]; } } @@ -863,6 +889,15 @@ public override bool HasValueTypeConstraint } } + public override bool IsValueTypeFromConstraintTypes + { + get + { + var typeParameter = this.OverriddenTypeParameter; + return ((object)typeParameter != null) && (typeParameter.IsValueTypeFromConstraintTypes || CalculateIsValueTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics)); + } + } + public override bool HasReferenceTypeConstraint { get @@ -872,6 +907,15 @@ public override bool HasReferenceTypeConstraint } } + public override bool IsReferenceTypeFromConstraintTypes + { + get + { + var typeParameter = this.OverriddenTypeParameter; + return ((object)typeParameter != null) && (typeParameter.IsReferenceTypeFromConstraintTypes || CalculateIsReferenceTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics)); + } + } + internal override bool? ReferenceTypeConstraintIsNullable { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index 10f92a96bcb4c..47a5b148584c2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -645,8 +645,11 @@ public sealed override ImmutableArray TypeParameters get { return ImmutableArray.Empty; } } - public sealed override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public sealed override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public sealed override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; public sealed override RefKind RefKind { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs index 6f935561f88c1..930b231cf98b9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterConstraintClause.cs @@ -39,6 +39,13 @@ internal enum TypeParameterConstraintKind NotNull = 0x80, Default = 0x100, + /// + /// mismatch is detected during merging process for partial type declarations. + /// + PartialMismatch = 0x200, + ValueTypeFromConstraintTypes = 0x400, // Not set if any flag from AllValueTypeKinds is set + ReferenceTypeFromConstraintTypes = 0x800, + /// /// All bits involved into describing various aspects of 'class' constraint. /// @@ -107,7 +114,8 @@ private TypeParameterConstraintClause( } Debug.Assert((constraints & TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType) == 0 || - (constraints & ~(TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType | TypeParameterConstraintKind.Constructor | TypeParameterConstraintKind.Default)) == 0); + (constraints & ~(TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType | TypeParameterConstraintKind.Constructor | TypeParameterConstraintKind.Default | + TypeParameterConstraintKind.PartialMismatch | TypeParameterConstraintKind.ValueTypeFromConstraintTypes | TypeParameterConstraintKind.ReferenceTypeFromConstraintTypes)) == 0); #endif this.Constraints = constraints; this.ConstraintTypes = constraintTypes; @@ -116,44 +124,28 @@ private TypeParameterConstraintClause( public readonly TypeParameterConstraintKind Constraints; public readonly ImmutableArray ConstraintTypes; - internal bool IsEmpty => Constraints == TypeParameterConstraintKind.None && ConstraintTypes.IsEmpty; - - /// - /// Adjust unresolved instances of which represent nullable type parameters - /// of the within constraint types according to the IsValueType state inferred - /// from the constraint types. - /// - internal static void AdjustConstraintTypes(Symbol container, ImmutableArray typeParameters, - ArrayBuilder constraintClauses, - ref IReadOnlyDictionary isValueTypeOverride) + internal static SmallDictionary BuildIsValueTypeMap(Symbol container, ImmutableArray typeParameters, + ImmutableArray constraintClauses) { - Debug.Assert(constraintClauses.Count == typeParameters.Length); - - if (isValueTypeOverride == null) - { - var isValueTypeOverrideBuilder = new Dictionary(typeParameters.Length, ReferenceEqualityComparer.Instance); + Debug.Assert(constraintClauses.Length == typeParameters.Length); - foreach (TypeParameterSymbol typeParameter in typeParameters) - { - isValueType(typeParameter, constraintClauses, isValueTypeOverrideBuilder, ConsList.Empty); - } + var isValueTypeMap = new SmallDictionary(ReferenceEqualityComparer.Instance); - isValueTypeOverride = new ReadOnlyDictionary(isValueTypeOverrideBuilder); - } - - foreach (TypeParameterConstraintClause constraintClause in constraintClauses) + foreach (TypeParameterSymbol typeParameter in typeParameters) { - adjustConstraintTypes(container, constraintClause.ConstraintTypes, isValueTypeOverride); + isValueType(typeParameter, constraintClauses, isValueTypeMap, ConsList.Empty); } - static bool isValueType(TypeParameterSymbol thisTypeParameter, ArrayBuilder constraintClauses, Dictionary isValueTypeOverrideBuilder, ConsList inProgress) + return isValueTypeMap; + + static bool isValueType(TypeParameterSymbol thisTypeParameter, ImmutableArray constraintClauses, SmallDictionary isValueTypeMap, ConsList inProgress) { if (inProgress.ContainsReference(thisTypeParameter)) { return false; } - if (isValueTypeOverrideBuilder.TryGetValue(thisTypeParameter, out bool knownIsValueType)) + if (isValueTypeMap.TryGetValue(thisTypeParameter, out bool knownIsValueType)) { return knownIsValueType; } @@ -177,7 +169,7 @@ static bool isValueType(TypeParameterSymbol thisTypeParameter, ArrayBuilder constraintTypes, IReadOnlyDictionary isValueTypeOverride) + internal static SmallDictionary BuildIsReferenceTypeFromConstraintTypesMap(Symbol container, ImmutableArray typeParameters, + ImmutableArray constraintClauses) + { + Debug.Assert(constraintClauses.Length == typeParameters.Length); + + var isReferenceTypeFromConstraintTypesMap = new SmallDictionary(ReferenceEqualityComparer.Instance); + + foreach (TypeParameterSymbol typeParameter in typeParameters) + { + isReferenceTypeFromConstraintTypes(typeParameter, constraintClauses, isReferenceTypeFromConstraintTypesMap, ConsList.Empty); + } + + return isReferenceTypeFromConstraintTypesMap; + + static bool isReferenceTypeFromConstraintTypes(TypeParameterSymbol thisTypeParameter, ImmutableArray constraintClauses, + SmallDictionary isReferenceTypeFromConstraintTypesMap, ConsList inProgress) { - foreach (var constraintType in constraintTypes) + if (inProgress.ContainsReference(thisTypeParameter)) + { + return false; + } + + if (isReferenceTypeFromConstraintTypesMap.TryGetValue(thisTypeParameter, out bool knownIsReferenceTypeFromConstraintTypes)) { - constraintType.VisitType(null, (type, args, unused2) => + return knownIsReferenceTypeFromConstraintTypes; + } + + TypeParameterConstraintClause constraintClause = constraintClauses[thisTypeParameter.Ordinal]; + + bool result = false; + + Symbol container = thisTypeParameter.ContainingSymbol; + inProgress = inProgress.Prepend(thisTypeParameter); + + foreach (TypeWithAnnotations constraintType in constraintClause.ConstraintTypes) + { + TypeSymbol type = constraintType.IsResolved ? constraintType.Type : constraintType.DefaultType; + + if (type is TypeParameterSymbol typeParameter) { - if (type.DefaultType is TypeParameterSymbol typeParameterSymbol && typeParameterSymbol.ContainingSymbol == (object)args.container) + if ((object)typeParameter.ContainingSymbol == (object)container) + { + if (isReferenceTypeFromConstraintTypes(typeParameter, constraintClauses, isReferenceTypeFromConstraintTypesMap, inProgress)) + { + result = true; + break; + } + } + else if (typeParameter.IsReferenceTypeFromConstraintTypes) { - type.TryForceResolve(args.isValueTypeOverride[typeParameterSymbol]); + result = true; + break; } - return false; - }, typePredicate: null, arg: (container, isValueTypeOverride), canDigThroughNullable: false, useDefaultType: true); + } + else if (TypeParameterSymbol.NonTypeParameterConstraintImpliesReferenceType(type)) + { + result = true; + break; + } } - } - } - } - internal static class TypeParameterConstraintClauseExtensions - { - internal static bool ContainsOnlyEmptyConstraintClauses(this ImmutableArray constraintClauses) - { - return constraintClauses.All(clause => clause.IsEmpty); + isReferenceTypeFromConstraintTypesMap.Add(thisTypeParameter, result); + return result; + } } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs index 877974daa91d7..f7677dfb6beae 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs @@ -38,7 +38,9 @@ protected SynthesizedRecordOrdinaryMethod(SourceMemberContainerTypeSymbol contai protected sealed override ImmutableArray MakeTypeParameters(CSharpSyntaxNode node, DiagnosticBag diagnostics) => ImmutableArray.Empty; - public sealed override ImmutableArray GetTypeParameterConstraintClauses() => ImmutableArray.Empty; + public sealed override ImmutableArray> GetTypeParameterConstraintTypes() => ImmutableArray>.Empty; + + public sealed override ImmutableArray GetTypeParameterConstraintKinds() => ImmutableArray.Empty; protected sealed override void PartialMethodChecks(DiagnosticBag diagnostics) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs index ff027c279128a..9fd6eec32669d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs @@ -175,8 +175,11 @@ protected override void MethodChecks(DiagnosticBag diagnostics) internal override bool IsExpressionBodied => false; - public override ImmutableArray GetTypeParameterConstraintClauses() - => ImmutableArray.Empty; + public override ImmutableArray> GetTypeParameterConstraintTypes() + => ImmutableArray>.Empty; + + public override ImmutableArray GetTypeParameterConstraintKinds() + => ImmutableArray.Empty; protected override object MethodChecksLockObject => _declaration; diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs b/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs index 86e2283eb6ff9..2fe750c23b8e8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs @@ -39,6 +39,8 @@ public TypeParameterBounds( private TypeParameterBounds() { + EffectiveBaseClass = null!; + DeducedBaseType = null!; } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs index 4d77bd8a637b9..3eaddba504b24 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs @@ -390,9 +390,17 @@ private static bool ConstraintImpliesReferenceType(TypeSymbol constraint) { if (constraint.TypeKind == TypeKind.TypeParameter) { - return IsReferenceTypeFromConstraintTypes(((TypeParameterSymbol)constraint).ConstraintTypesNoUseSiteDiagnostics); + return ((TypeParameterSymbol)constraint).IsReferenceTypeFromConstraintTypes; } - else if (!constraint.IsReferenceType) + + return NonTypeParameterConstraintImpliesReferenceType(constraint); + } + + internal static bool NonTypeParameterConstraintImpliesReferenceType(TypeSymbol constraint) + { + Debug.Assert(constraint.TypeKind != TypeKind.TypeParameter); + + if (!constraint.IsReferenceType) { return false; } @@ -423,7 +431,7 @@ private static bool ConstraintImpliesReferenceType(TypeSymbol constraint) // > Please note that we do not check the gpReferenceTypeConstraint special constraint here // > because this property does not propagate up the constraining hierarchy. // > (e.g. "class A where S : T, where T : class" does not guarantee that S is ObjRef) - internal static bool IsReferenceTypeFromConstraintTypes(ImmutableArray constraintTypes) + internal static bool CalculateIsReferenceTypeFromConstraintTypes(ImmutableArray constraintTypes) { foreach (var constraintType in constraintTypes) { @@ -493,7 +501,7 @@ internal static bool IsReferenceTypeFromConstraintTypes(ImmutableArray constraintTypes) + internal static bool CalculateIsValueTypeFromConstraintTypes(ImmutableArray constraintTypes) { foreach (var constraintType in constraintTypes) { @@ -514,7 +522,7 @@ public sealed override bool IsReferenceType return true; } - return IsReferenceTypeFromConstraintTypes(this.ConstraintTypesNoUseSiteDiagnostics); + return IsReferenceTypeFromConstraintTypes; } } @@ -572,7 +580,7 @@ public sealed override bool IsValueType return true; } - return IsValueTypeFromConstraintTypes(this.ConstraintTypesNoUseSiteDiagnostics); + return IsValueTypeFromConstraintTypes; } } @@ -606,6 +614,8 @@ internal sealed override ObsoleteAttributeData ObsoleteAttributeData public abstract bool HasReferenceTypeConstraint { get; } + public abstract bool IsReferenceTypeFromConstraintTypes { get; } + /// /// Returns whether the reference type constraint (the 'class' constraint) should also be treated as nullable ('class?') or non-nullable (class!). /// In some cases this aspect is unknown (null value is returned). For example, when 'class' constraint is specified in a NonNullTypes(false) context. @@ -617,6 +627,8 @@ internal sealed override ObsoleteAttributeData ObsoleteAttributeData public abstract bool HasValueTypeConstraint { get; } + public abstract bool IsValueTypeFromConstraintTypes { get; } + public abstract bool HasUnmanagedTypeConstraint { get; } public abstract VarianceKind Variance { get; } @@ -626,9 +638,9 @@ internal sealed override bool GetUnificationUseSiteDiagnosticRecursive(ref Diagn return false; } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { - return this.Equals(t2 as TypeParameterSymbol, comparison, isValueTypeOverrideOpt); + return this.Equals(t2 as TypeParameterSymbol, comparison); } internal bool Equals(TypeParameterSymbol other) @@ -636,7 +648,7 @@ internal bool Equals(TypeParameterSymbol other) return Equals(other, TypeCompareKind.ConsiderEverything); } - private bool Equals(TypeParameterSymbol other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt) + private bool Equals(TypeParameterSymbol other, TypeCompareKind comparison) { if (ReferenceEquals(this, other)) { @@ -649,7 +661,7 @@ private bool Equals(TypeParameterSymbol other, TypeCompareKind comparison, IRead } // Type parameters may be equal but not reference equal due to independent alpha renamings. - return other.ContainingSymbol.ContainingType.Equals(this.ContainingSymbol.ContainingType, comparison, isValueTypeOverrideOpt); + return other.ContainingSymbol.ContainingType.Equals(this.ContainingSymbol.ContainingType, comparison); } public override int GetHashCode() diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index 3b57b44ba16b6..bd250bbd8df86 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -285,13 +285,8 @@ internal bool IsEqualToOrDerivedFrom(TypeSymbol type, TypeCompareKind comparison /// What kind of comparison to use? /// You can ignore custom modifiers, ignore the distinction between object and dynamic, or ignore tuple element names differences. /// - /// - /// A map from a type parameter symbol to a boolean value that should be used as a replacement for a value returned by - /// property. Used when accessing the property for a type parameter symbol - /// that has an entry in the map is not safe and can cause a cycle. - /// /// True if the types are equivalent. - internal virtual bool Equals(TypeSymbol t2, TypeCompareKind compareKind, IReadOnlyDictionary isValueTypeOverrideOpt = null) + internal virtual bool Equals(TypeSymbol t2, TypeCompareKind compareKind) { return ReferenceEquals(this, t2); } @@ -2194,14 +2189,14 @@ internal bool Equals(TypeWithAnnotations other) throw ExceptionUtilities.Unreachable; } - public static bool Equals(TypeSymbol left, TypeSymbol right, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + public static bool Equals(TypeSymbol left, TypeSymbol right, TypeCompareKind comparison) { if (left is null) { return right is null; } - return left.Equals(right, comparison, isValueTypeOverrideOpt); + return left.Equals(right, comparison); } [Obsolete("Use 'TypeSymbol.Equals(TypeSymbol, TypeSymbol, TypeCompareKind)' method.", true)] diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs b/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs index 07cd0d7de94c1..e7796d6cabd64 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs @@ -326,7 +326,7 @@ string IFormattable.ToString(string format, IFormatProvider formatProvider) return ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat); } - public bool Equals(TypeWithAnnotations other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt = null) + public bool Equals(TypeWithAnnotations other, TypeCompareKind comparison) { if (this.IsSameAs(other)) { @@ -340,7 +340,7 @@ public bool Equals(TypeWithAnnotations other, TypeCompareKind comparison, IReadO return false; } } - else if (!other.HasType || !TypeSymbolEquals(other, comparison, isValueTypeOverrideOpt)) + else if (!other.HasType || !TypeSymbolEquals(other, comparison)) { return false; } @@ -366,12 +366,7 @@ public bool Equals(TypeWithAnnotations other, TypeCompareKind comparison, IReadO } TypeSymbol type = Type; - bool isValueType; - - if (isValueTypeOverrideOpt == null || !(type is TypeParameterSymbol typeParameter) || !isValueTypeOverrideOpt.TryGetValue(typeParameter, out isValueType)) - { - isValueType = type.IsValueType && !type.IsNullableType(); - } + bool isValueType = type.IsValueType && !type.IsNullableType(); if (!isValueType) { @@ -385,15 +380,14 @@ public bool Equals(TypeWithAnnotations other, TypeCompareKind comparison, IReadO internal sealed class EqualsComparer : EqualityComparer { - internal static readonly EqualsComparer ConsiderEverythingComparer = new EqualsComparer(TypeCompareKind.ConsiderEverything, isValueTypeOverrideOpt: null); + internal static readonly EqualsComparer ConsiderEverythingComparer = new EqualsComparer(TypeCompareKind.ConsiderEverything); + internal static readonly EqualsComparer IgnoreNullableModifiersForReferenceTypesComparer = new EqualsComparer(TypeCompareKind.IgnoreNullableModifiersForReferenceTypes); private readonly TypeCompareKind _compareKind; - private readonly IReadOnlyDictionary _isValueTypeOverrideOpt; - public EqualsComparer(TypeCompareKind compareKind, IReadOnlyDictionary isValueTypeOverrideOpt) + public EqualsComparer(TypeCompareKind compareKind) { _compareKind = compareKind; - _isValueTypeOverrideOpt = isValueTypeOverrideOpt; } public override int GetHashCode(TypeWithAnnotations obj) @@ -411,12 +405,12 @@ public override bool Equals(TypeWithAnnotations x, TypeWithAnnotations y) { return !y.HasType; } - return x.Equals(y, _compareKind, _isValueTypeOverrideOpt); + return x.Equals(y, _compareKind); } } - internal bool TypeSymbolEquals(TypeWithAnnotations other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt) => - _extensions.TypeSymbolEquals(this, other, comparison, isValueTypeOverrideOpt); + internal bool TypeSymbolEquals(TypeWithAnnotations other, TypeCompareKind comparison) => + _extensions.TypeSymbolEquals(this, other, comparison); public bool GetUnificationUseSiteDiagnosticRecursive(ref DiagnosticInfo result, Symbol owner, ref HashSet checkedTypes) { @@ -468,6 +462,11 @@ internal TypeWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap) return newTypeWithModifiers; } + if (newTypeWithModifiers.Type is PlaceholderTypeArgumentSymbol) + { + return newTypeWithModifiers; + } + NullableAnnotation newAnnotation; Debug.Assert(!IsIndexedTypeParameter(newTypeWithModifiers.Type) || newTypeWithModifiers.NullableAnnotation.IsOblivious()); @@ -511,9 +510,9 @@ internal TypeWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap) public void ReportDiagnosticsIfObsolete(Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics) => _extensions.ReportDiagnosticsIfObsolete(this, binder, syntax, diagnostics); - private bool TypeSymbolEqualsCore(TypeWithAnnotations other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt) + private bool TypeSymbolEqualsCore(TypeWithAnnotations other, TypeCompareKind comparison) { - return Type.Equals(other.Type, comparison, isValueTypeOverrideOpt); + return Type.Equals(other.Type, comparison); } private void ReportDiagnosticsIfObsoleteCore(Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics) @@ -844,7 +843,7 @@ internal static Extensions CreateLazy(CSharpCompilation compilation, TypeWithAnn internal abstract TypeWithAnnotations WithTypeAndModifiers(TypeWithAnnotations type, TypeSymbol typeSymbol, ImmutableArray customModifiers); - internal abstract bool TypeSymbolEquals(TypeWithAnnotations type, TypeWithAnnotations other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt); + internal abstract bool TypeSymbolEquals(TypeWithAnnotations type, TypeWithAnnotations other, TypeCompareKind comparison); internal abstract TypeWithAnnotations SubstituteType(TypeWithAnnotations type, AbstractTypeMap typeMap); internal abstract void ReportDiagnosticsIfObsolete(TypeWithAnnotations type, Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics); @@ -896,9 +895,9 @@ internal override TypeWithAnnotations AsNotNullableReferenceType(TypeWithAnnotat return CreateNonLazyType(defaultType, defaultType.IsNullableType() ? type.NullableAnnotation : NullableAnnotation.NotAnnotated, _customModifiers); } - internal override bool TypeSymbolEquals(TypeWithAnnotations type, TypeWithAnnotations other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt) + internal override bool TypeSymbolEquals(TypeWithAnnotations type, TypeWithAnnotations other, TypeCompareKind comparison) { - return type.TypeSymbolEqualsCore(other, comparison, isValueTypeOverrideOpt); + return type.TypeSymbolEqualsCore(other, comparison); } internal override TypeWithAnnotations SubstituteType(TypeWithAnnotations type, AbstractTypeMap typeMap) @@ -1048,16 +1047,16 @@ internal override void ReportDiagnosticsIfObsolete(TypeWithAnnotations type, Bin } } - internal override bool TypeSymbolEquals(TypeWithAnnotations type, TypeWithAnnotations other, TypeCompareKind comparison, IReadOnlyDictionary isValueTypeOverrideOpt) + internal override bool TypeSymbolEquals(TypeWithAnnotations type, TypeWithAnnotations other, TypeCompareKind comparison) { var otherLazy = other._extensions as LazyNullableTypeParameter; if ((object)otherLazy != null) { - return _underlying.TypeSymbolEquals(otherLazy._underlying, comparison, isValueTypeOverrideOpt); + return _underlying.TypeSymbolEquals(otherLazy._underlying, comparison); } - return type.TypeSymbolEqualsCore(other, comparison, isValueTypeOverrideOpt); + return type.TypeSymbolEqualsCore(other, comparison); } internal override void TryForceResolve(bool asValueType) diff --git a/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs b/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs index ba4b3f729734c..30e4a67d87744 100644 --- a/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs +++ b/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs @@ -99,10 +99,8 @@ internal override DiagnosticInfo ErrorInfo } } - internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary? isValueTypeOverrideOpt = null) + internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison) { - Debug.Assert(isValueTypeOverrideOpt == null); - if ((object)t2 == (object)this) { return true; diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs index 80a52325607d3..f1bd03a8c40ea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedTypeParameterSymbol.cs @@ -77,6 +77,14 @@ public override bool HasReferenceTypeConstraint } } + public override bool IsReferenceTypeFromConstraintTypes + { + get + { + return _underlyingTypeParameter.IsReferenceTypeFromConstraintTypes || CalculateIsReferenceTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics); + } + } + internal override bool? ReferenceTypeConstraintIsNullable { get @@ -109,6 +117,14 @@ public override bool HasValueTypeConstraint } } + public override bool IsValueTypeFromConstraintTypes + { + get + { + return _underlyingTypeParameter.IsValueTypeFromConstraintTypes || CalculateIsValueTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics); + } + } + public override VarianceKind Variance { get diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index fe1719905f450..49c3b51623560 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -96178,9 +96178,6 @@ class C // (16,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // static U?[] F2() where T : class where U : T => throw null!; Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "U?").WithArguments("9.0").WithLocation(16, 12), - // (17,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. - // static U?[] F3() where T : struct where U : T => throw null!; - Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "U?").WithArguments("9.0").WithLocation(17, 12), // (8,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // static T? F4() where T : new() => throw null!; // error Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T?").WithArguments("9.0").WithLocation(8, 12), @@ -96190,9 +96187,6 @@ class C // (10,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // static T? F6() where T : I => throw null!; // error Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T?").WithArguments("9.0").WithLocation(10, 12), - // (19,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. - // static U?[] F5() where T : unmanaged where U : T => throw null!; - Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "U?").WithArguments("9.0").WithLocation(19, 12), // (20,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // static U?[] F6() where T : I where U : T => throw null!; // error Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "U?").WithArguments("9.0").WithLocation(20, 12), @@ -141217,7 +141211,7 @@ public static C SelectMany(this C source, Fu [Fact] [WorkItem(44348, "https://github.com/dotnet/roslyn/issues/44348")] - public void Constraints() + public void NestedTypeConstraints_01() { var source = @"class A @@ -141236,6 +141230,163 @@ internal interface IB : IA { } comp.VerifyEmitDiagnostics(); } + [Fact] + [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] + public void NestedTypeConstraints_02() + { + var source = +@"class A +{ + internal interface IA { } +} +#nullable enable +class B : A + where T : B.IA +{ +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] + public void NestedTypeConstraints_03() + { + var source = +@"class A +{ + internal interface IA { } +} +#nullable enable +class B : A + where T : B.IA +{ +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] + public void NestedTypeConstraints_04() + { + var source = +@"class A +{ + internal interface IA { } +} +#nullable enable +class B : A +#nullable disable + where T : B.IA +{ +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] + public void NestedTypeConstraints_05() + { + var source = +@"class A +{ + internal interface IA { } +} +#nullable enable +class B : A +#nullable disable + where T : B.IA +{ +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,18): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. + // where T : B.IA + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(8, 18)); + } + + [Fact] + [WorkItem(45713, "https://github.com/dotnet/roslyn/issues/45713")] + public void NestedTypeConstraints_06() + { + var source0 = +@"public class A +{ + public interface IA { } +} +#nullable enable +public class B : A + where T : B.IA +{ +}"; + var comp = CreateCompilation(source0); + var ref0 = comp.EmitToImageReference(); + + var source1 = +@"class A : A.IA { } +class Program +{ + static B F() => new(); + static void Main() + { + System.Console.WriteLine(F()); + } +}"; + CompileAndVerify(source1, references: new[] { ref0 }, expectedOutput: "B`1[A]"); + } + + [Fact] + [WorkItem(45863, "https://github.com/dotnet/roslyn/issues/45863")] + public void NestedTypeConstraints_07() + { + var source = +@"#nullable enable +interface IA +{ +} +interface IB : IA + where U : IB.IC +{ + interface IC { } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + [WorkItem(45863, "https://github.com/dotnet/roslyn/issues/45863")] + public void NestedTypeConstraints_08() + { + var source0 = +@"#nullable enable +public interface IA +{ +} +public interface IB : IA + where U : IB.IC +{ + public interface IC { } +}"; + var comp = CreateCompilation(source0); + var ref0 = comp.EmitToImageReference(); + + var source1 = +@"class C : IB.IC +{ +} +class Program +{ + static C F() => new(); + static void Main() + { + System.Console.WriteLine(F()); + } +}"; + CompileAndVerify(source1, references: new[] { ref0 }, expectedOutput: "C"); + } + [Fact] [WorkItem(46342, "https://github.com/dotnet/roslyn/issues/46342")] public void LambdaNullReturn_01() diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/FunctionPointerTypeSymbolTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/FunctionPointerTypeSymbolTests.cs index 72e1f2e6eef52..a0bb24635155c 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/FunctionPointerTypeSymbolTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/FunctionPointerTypeSymbolTests.cs @@ -925,8 +925,7 @@ private void AssertEqualityAndHashCode(FunctionPointerTypeSymbol p1, FunctionPoi if (parameterEqualities[i] == Equality.Equal) { Assert.True(((FunctionPointerParameterSymbol)param1).MethodEqualityChecks((FunctionPointerParameterSymbol)param2, - TypeCompareKind.ConsiderEverything, - isValueTypeOverride: null)); + TypeCompareKind.ConsiderEverything)); } for (int j = 0; j < p1.Signature.ParameterCount; j++) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs index b134b17a377ce..d6631399d085c 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EETypeParameterSymbol.cs @@ -59,6 +59,14 @@ public override bool HasReferenceTypeConstraint get { return _sourceTypeParameter.HasReferenceTypeConstraint; } } + public override bool IsReferenceTypeFromConstraintTypes + { + get + { + return _sourceTypeParameter.IsReferenceTypeFromConstraintTypes || CalculateIsReferenceTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics); + } + } + internal override bool? ReferenceTypeConstraintIsNullable { get { return _sourceTypeParameter.ReferenceTypeConstraintIsNullable; } @@ -87,6 +95,14 @@ public override bool HasValueTypeConstraint get { return _sourceTypeParameter.HasValueTypeConstraint; } } + public override bool IsValueTypeFromConstraintTypes + { + get + { + return _sourceTypeParameter.IsValueTypeFromConstraintTypes || CalculateIsValueTypeFromConstraintTypes(ConstraintTypesNoUseSiteDiagnostics); + } + } + public override bool HasUnmanagedTypeConstraint { get { return _sourceTypeParameter.HasUnmanagedTypeConstraint; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs index 888339058d141..de45ef9551757 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SimpleTypeParameterSymbol.cs @@ -52,6 +52,11 @@ public override bool HasReferenceTypeConstraint get { return false; } } + public override bool IsReferenceTypeFromConstraintTypes + { + get { return false; } + } + internal override bool? ReferenceTypeConstraintIsNullable { get { return false; } @@ -66,6 +71,11 @@ public override bool HasValueTypeConstraint get { return false; } } + public override bool IsValueTypeFromConstraintTypes + { + get { return false; } + } + public override bool HasUnmanagedTypeConstraint { get { return false; }