Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use lightweight type constraint binding for IsValueType #48270

Closed
wants to merge 21 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename
jcouv committed Oct 4, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 7c555888b935f6a7f1ad74559e2f15f2978f9eca
8 changes: 4 additions & 4 deletions src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
ImmutableArray<TypeParameterSymbol> typeParameters,
TypeParameterListSyntax typeParameterList,
SyntaxList<TypeParameterConstraintClauseSyntax> clauses,
bool useLightweightTypeConstraintBinding,
bool canUseLightweightTypeConstraintBinding,
ref IReadOnlyDictionary<TypeParameterSymbol, bool> isValueTypeOverride,
DiagnosticBag diagnostics,
bool isForOverride = false)
@@ -67,7 +67,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
Debug.Assert(ordinal < n);

(TypeParameterConstraintClause constraintClause, ArrayBuilder<TypeConstraintSyntax>? typeConstraintNodes) =
this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, useLightweightTypeConstraintBinding: useLightweightTypeConstraintBinding, diagnostics);
this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, canUseLightweightTypeConstraintBinding, diagnostics);
Copy link
Member

@cston cston Oct 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canUseLightweightTypeConstraintBinding [](start = 120, length = 38)

Consider keeping the named argument since there are two bool parameters in a row. #Closed

if (results[ordinal] == null)
{
results[ordinal] = constraintClause;
@@ -119,7 +119,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
/// Bind and return a single type parameter constraint clause along with syntax nodes corresponding to type constraints.
/// </summary>
private (TypeParameterConstraintClause, ArrayBuilder<TypeConstraintSyntax>?) BindTypeParameterConstraints(
TypeParameterSyntax typeParameterSyntax, TypeParameterConstraintClauseSyntax constraintClauseSyntax, bool isForOverride, bool useLightweightTypeConstraintBinding, DiagnosticBag diagnostics)
TypeParameterSyntax typeParameterSyntax, TypeParameterConstraintClauseSyntax constraintClauseSyntax, bool isForOverride, bool canUseLightweightTypeConstraintBinding, DiagnosticBag diagnostics)
Copy link
Member

@cston cston Oct 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canUseLightweightTypeConstraintBinding [](start = 138, length = 38)

Argument is not used. #Closed

{
var constraints = TypeParameterConstraintKind.None;
ArrayBuilder<TypeWithAnnotations>? constraintTypes = null;
@@ -309,7 +309,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
Debug.Assert(!isForOverride ||
(constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)) != (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType));

return (TypeParameterConstraintClause.Create(constraints, constraintTypes?.ToImmutableAndFree() ?? ImmutableArray<TypeWithAnnotations>.Empty, useLightweightTypeConstraintBinding), syntaxBuilder);
return (TypeParameterConstraintClause.Create(constraints, constraintTypes?.ToImmutableAndFree() ?? ImmutableArray<TypeWithAnnotations>.Empty, canUseLightweightTypeConstraintBinding), syntaxBuilder);

static void reportOverrideWithConstraints(ref bool reportedOverrideWithConstraints, TypeParameterConstraintSyntax syntax, DiagnosticBag diagnostics)
{
Original file line number Diff line number Diff line change
@@ -88,7 +88,7 @@ public sealed override ImmutableArray<TypeParameterSymbol> TypeParameters
get { return _typeParameters; }
}

public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

internal override int ParameterCount
Original file line number Diff line number Diff line change
@@ -101,11 +101,11 @@ public override VarianceKind Variance
get { return VarianceKind.None; }
}

internal override void EnsureAllConstraintsAreResolved(bool useLightweightTypeConstraintBinding)
internal override void EnsureAllConstraintsAreResolved(bool canUseLightweightTypeConstraintBinding)
{
}

internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding)
internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding)
{
return ImmutableArray<TypeWithAnnotations>.Empty;
}
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs
Original file line number Diff line number Diff line change
@@ -316,7 +316,7 @@ internal static ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterC
ImmutableArray<TypeParameterSymbol> typeParameters,
TypeParameterListSyntax typeParameterList,
SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses,
bool useLightweightTypeConstraintBinding,
bool canUseLightweightTypeConstraintBinding,
DiagnosticBag diagnostics)
{
if (typeParameters.Length == 0)
@@ -338,7 +338,7 @@ internal static ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterC

IReadOnlyDictionary<TypeParameterSymbol, bool> isValueTypeOverride = null;
return binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses,
useLightweightTypeConstraintBinding,
canUseLightweightTypeConstraintBinding,
ref isValueTypeOverride,
diagnostics);
}
Original file line number Diff line number Diff line change
@@ -134,11 +134,11 @@ public override bool IsImplicitlyDeclared
}
}

internal override void EnsureAllConstraintsAreResolved(bool useLightweightTypeConstraintBinding)
internal override void EnsureAllConstraintsAreResolved(bool canUseLightweightTypeConstraintBinding)
{
}

internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding)
internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding)
{
return ImmutableArray<TypeWithAnnotations>.Empty;
}
Original file line number Diff line number Diff line change
@@ -570,19 +570,19 @@ public override VarianceKind Variance
}
}

internal override void EnsureAllConstraintsAreResolved(bool useLightweightTypeConstraintBinding)
internal override void EnsureAllConstraintsAreResolved(bool canUseLightweightTypeConstraintBinding)
{
useLightweightTypeConstraintBinding = false; // Resolve bounds eagerly.
if (!_lazyBounds.HasValue(useLightweightTypeConstraintBinding))
canUseLightweightTypeConstraintBinding = false; // Resolve bounds eagerly.
if (!_lazyBounds.HasValue(canUseLightweightTypeConstraintBinding))
{
var typeParameters = (_containingSymbol.Kind == SymbolKind.Method) ?
((PEMethodSymbol)_containingSymbol).TypeParameters :
((PENamedTypeSymbol)_containingSymbol).TypeParameters;
EnsureAllConstraintsAreResolved(typeParameters, useLightweightTypeConstraintBinding);
EnsureAllConstraintsAreResolved(typeParameters, canUseLightweightTypeConstraintBinding);
}
}

internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding)
internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding)
{
var bounds = this.GetBounds(inProgress);
return (bounds != null) ? bounds.ConstraintTypes : ImmutableArray<TypeWithAnnotations>.Empty;
@@ -673,7 +673,7 @@ private TypeParameterBounds GetBounds(ConsList<TypeParameterSymbol> inProgress)

internal override DiagnosticInfo GetConstraintsUseSiteErrorInfo()
{
EnsureAllConstraintsAreResolved(useLightweightTypeConstraintBinding: false);
EnsureAllConstraintsAreResolved(canUseLightweightTypeConstraintBinding: false);
Debug.Assert(!ReferenceEquals(_lazyConstraintsUseSiteErrorInfo, CSDiagnosticInfo.EmptyErrorInfo));
return _lazyConstraintsUseSiteErrorInfo;
}
Original file line number Diff line number Diff line change
@@ -81,9 +81,9 @@ internal override ModuleSymbol ContainingModule
}
}

internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding)
internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding)
{
return this.RetargetingTranslator.Retarget(_underlyingTypeParameter.GetConstraintTypes(inProgress, useLightweightTypeConstraintBinding));
return this.RetargetingTranslator.Retarget(_underlyingTypeParameter.GetConstraintTypes(inProgress, canUseLightweightTypeConstraintBinding));
}

internal override bool? IsNotNullable
Original file line number Diff line number Diff line change
@@ -177,11 +177,11 @@ public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
}
}

internal override void EnsureAllConstraintsAreResolved(bool useLightweightTypeConstraintBinding)
internal override void EnsureAllConstraintsAreResolved(bool canUseLightweightTypeConstraintBinding)
{
}

internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding)
internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding)
{
return ImmutableArray<TypeWithAnnotations>.Empty;
}
Original file line number Diff line number Diff line change
@@ -173,11 +173,11 @@ public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
}
}

internal override void EnsureAllConstraintsAreResolved(bool useLightweightTypeConstraintBinding)
internal override void EnsureAllConstraintsAreResolved(bool canUseLightweightTypeConstraintBinding)
{
}

internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding)
internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding)
{
return ImmutableArray<TypeWithAnnotations>.Empty;
}
Original file line number Diff line number Diff line change
@@ -417,7 +417,7 @@ internal override bool GenerateDebugInfo

internal override bool IsInitOnly => false;

public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding) => ImmutableArray<TypeParameterConstraintClause>.Empty;
public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding) => ImmutableArray<TypeParameterConstraintClause>.Empty;

internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree)
{
Original file line number Diff line number Diff line change
@@ -459,9 +459,9 @@ private ImmutableArray<SourceMethodTypeParameterSymbol> MakeTypeParameters(Diagn
return result.ToImmutableAndFree();
}

public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
{
if (!_lazyTypeParameterConstraints.HasValue(useLightweightTypeConstraintBinding))
if (!_lazyTypeParameterConstraints.HasValue(canUseLightweightTypeConstraintBinding))
{
var syntax = Syntax;
var diagnostics = DiagnosticBag.GetInstance();
@@ -470,19 +470,19 @@ public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterCo
TypeParameters,
syntax.TypeParameterList,
syntax.ConstraintClauses,
useLightweightTypeConstraintBinding,
canUseLightweightTypeConstraintBinding,
diagnostics);

lock (_declarationDiagnostics)
{
//useLightweightTypeConstraintBinding = constraints.UsedLightweightTypeConstraintBinding(); // TODO2 why do we have this here and only here?
if (!_lazyTypeParameterConstraints.HasValue(useLightweightTypeConstraintBinding))
//canUseLightweightTypeConstraintBinding = constraints.UsedLightweightTypeConstraintBinding(); // TODO2 why do we have this here and only here?
if (!_lazyTypeParameterConstraints.HasValue(canUseLightweightTypeConstraintBinding))
{
if (!useLightweightTypeConstraintBinding)
if (!canUseLightweightTypeConstraintBinding)
{
_declarationDiagnostics.AddRange(diagnostics);
}
_lazyTypeParameterConstraints = new TypeParameterConstraintClauses(constraints, useLightweightTypeConstraintBinding);
_lazyTypeParameterConstraints = new TypeParameterConstraintClauses(constraints, canUseLightweightTypeConstraintBinding);
}
}
diagnostics.Free();
Original file line number Diff line number Diff line change
@@ -138,7 +138,7 @@ public sealed override ImmutableArray<TypeParameterSymbol> TypeParameters
get { return ImmutableArray<TypeParameterSymbol>.Empty; }
}

public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

public override RefKind RefKind
Original file line number Diff line number Diff line change
@@ -138,7 +138,7 @@ public override ImmutableArray<TypeParameterSymbol> TypeParameters
}
}

public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

public sealed override TypeWithAnnotations ReturnTypeWithAnnotations
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ public override ImmutableArray<TypeParameterSymbol> TypeParameters
get { return ImmutableArray<TypeParameterSymbol>.Empty; }
}

public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

public override RefKind RefKind
Original file line number Diff line number Diff line change
@@ -208,7 +208,7 @@ public sealed override ImmutableArray<TypeParameterSymbol> TypeParameters
get { return ImmutableArray<TypeParameterSymbol>.Empty; }
}

public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

internal Location Location
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ internal abstract class SourceMethodSymbol : MethodSymbol
/// array of clauses, indexed by the constrained type parameter in <see cref="MethodSymbol.TypeParameters"/>.
/// If a type parameter does not have constraints, the corresponding entry in the array is null.
/// </summary>
public abstract ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding);
public abstract ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding);

protected static void ReportBadRefToken(TypeSyntax returnTypeSyntax, DiagnosticBag diagnostics)
{
Original file line number Diff line number Diff line change
@@ -255,13 +255,13 @@ private ImmutableArray<TypeParameterSymbol> MakeTypeParameters(DiagnosticBag dia
/// <summary>
/// Returns the constraint clause for the given type parameter.
/// </summary>
internal TypeParameterConstraintClause GetTypeParameterConstraintClause(bool useLightweightTypeConstraintBinding, int ordinal)
internal TypeParameterConstraintClause GetTypeParameterConstraintClause(bool canUseLightweightTypeConstraintBinding, int ordinal)
Copy link
Member

@333fred 333fred Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider nullable enabling this code. #Resolved

{
var clauses = _lazyTypeParameterConstraints;
if (!clauses.HasValue(useLightweightTypeConstraintBinding))
if (!clauses.HasValue(canUseLightweightTypeConstraintBinding))
{
var diagnostics = DiagnosticBag.GetInstance();
var typeParameterConstraints = new TypeParameterConstraintClauses(MakeTypeParameterConstraints(useLightweightTypeConstraintBinding, diagnostics), useLightweightTypeConstraintBinding);
var typeParameterConstraints = new TypeParameterConstraintClauses(MakeTypeParameterConstraints(canUseLightweightTypeConstraintBinding, diagnostics), canUseLightweightTypeConstraintBinding);
Copy link
Member

@cston cston Oct 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new TypeParameterConstraintClauses [](start = 47, length = 34)

Please add a Create() method with two singleton values for the empty collections. #Closed


if (TypeParameterConstraintClausesExtensions.InterlockedUpdate(ref _lazyTypeParameterConstraints, typeParameterConstraints) &&
_lazyTypeParameterConstraints.HasValue(usedLightweightTypeConstraintBinding: false))
@@ -275,7 +275,7 @@ internal TypeParameterConstraintClause GetTypeParameterConstraintClause(bool use
return (clauses.TypeParameterConstraints.Length > 0) ? clauses.TypeParameterConstraints[ordinal] : TypeParameterConstraintClause.Empty;
}

private ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterConstraints(bool useLightweightTypeConstraintBinding, DiagnosticBag diagnostics)
private ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterConstraints(bool canUseLightweightTypeConstraintBinding, DiagnosticBag diagnostics)
{
var typeParameters = this.TypeParameters;
var results = ImmutableArray<TypeParameterConstraintClause>.Empty;
@@ -325,9 +325,9 @@ private ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterConstrain
// to avoid checking constraints when binding type names.
Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause));
binder = binder.WithContainingMemberOrLambda(this).WithAdditionalFlags(
BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks | (useLightweightTypeConstraintBinding ? BinderFlags.LightweightTypeConstraintBinding : 0));
BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks | (canUseLightweightTypeConstraintBinding ? BinderFlags.LightweightTypeConstraintBinding : 0));

constraints = binder.BindTypeParameterConstraintClauses(this, typeParameters, typeParameterList, constraintClauses, useLightweightTypeConstraintBinding, ref isValueTypeOverride, diagnostics);
constraints = binder.BindTypeParameterConstraintClauses(this, typeParameters, typeParameterList, constraintClauses, canUseLightweightTypeConstraintBinding, ref isValueTypeOverride, diagnostics);
}

Debug.Assert(constraints.Length == arity);
Original file line number Diff line number Diff line change
@@ -166,7 +166,7 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray<ParameterSymb
IReadOnlyDictionary<TypeParameterSymbol, bool> isValueTypeOverride = null;
declaredConstraints = signatureBinder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks).
BindTypeParameterConstraintClauses(this, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses,
useLightweightTypeConstraintBinding: false,
canUseLightweightTypeConstraintBinding: false,
ref isValueTypeOverride,
diagnostics, isForOverride: true);
}
@@ -283,10 +283,10 @@ protected override void CompleteAsyncMethodChecksBetweenStartAndFinish()
}
}

public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
{
var clauses = _lazyTypeParameterConstraints;
Copy link
Member

@cston cston Oct 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clauses = _lazyTypeParameterConstraints [](start = 16, length = 39)

Please consider inlining this local to avoid risk of using the (stale) local later in the method. #Closed

if (!clauses.HasValue(useLightweightTypeConstraintBinding))
if (!clauses.HasValue(canUseLightweightTypeConstraintBinding))
{
var diagnostics = DiagnosticBag.GetInstance();
var syntax = GetSyntax();
@@ -301,9 +301,9 @@ public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterCo
TypeParameters,
syntax.TypeParameterList,
syntax.ConstraintClauses,
useLightweightTypeConstraintBinding,
canUseLightweightTypeConstraintBinding,
diagnostics),
useLightweightTypeConstraintBinding);
canUseLightweightTypeConstraintBinding);
Copy link
Member

@cston cston Oct 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canUseLightweightTypeConstraintBinding [](start = 20, length = 38)

If syntax.ConstraintClauses is empty, we should pass false rather than canUseLightweightTypeConstraintBinding.

It feels like ConstraintsHelper.MakeTypeParameterConstraints() should be creating the TypeParameterConstraintClauses instance rather than this method. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If syntax.ConstraintClauses is empty, we should pass false rather than canUseLightweightTypeConstraintBinding.

I don't think so. There is still a difference between empty from lightweight vs. full binding. Diagnostics should be produced from the latter, when constraints are removed to produce an empty set.


In reply to: 501252724 [](ancestors = 501252724)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is still a difference between empty from lightweight vs. full binding.

There shouldn't be a difference if syntax.ConstraintClauses is empty. See the .Count == 0 case in ConstraintsHelper.MakeTypeParameterConstraints(). We should treat that case as fully bound. Ideally MakeTypeParameterConstraints() would return TypeParameterConstraintClauses since that method has sufficient context to make that decision.


In reply to: 501281392 [](ancestors = 501281392,501252724)

Copy link
Member Author

@jcouv jcouv Oct 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. That works. Thanks #Resolved


if (TypeParameterConstraintClausesExtensions.InterlockedUpdate(ref _lazyTypeParameterConstraints, constraints) &&
_lazyTypeParameterConstraints.HasValue(usedLightweightTypeConstraintBinding: false))
Original file line number Diff line number Diff line change
@@ -452,7 +452,7 @@ public sealed override ImmutableArray<TypeParameterSymbol> TypeParameters
get { return ImmutableArray<TypeParameterSymbol>.Empty; }
}

public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

public sealed override RefKind RefKind

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -645,7 +645,7 @@ public sealed override ImmutableArray<TypeParameterSymbol> TypeParameters
get { return ImmutableArray<TypeParameterSymbol>.Empty; }
}

public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

public sealed override RefKind RefKind
Original file line number Diff line number Diff line change
@@ -256,15 +256,15 @@ internal static bool ContainsOnlyEmptyConstraintClauses(this ImmutableArray<Type
}

// Returns true if constraintClauses was updated with value.
// Returns false if constraintClauses already had a value with sufficient 'UseLightweightTypeConstraintBinding'
// or was updated to a value with sufficient 'UseLightweightTypeConstraintBinding' on another thread.
// Returns false if constraintClauses already had a value with sufficient 'canUseLightweightTypeConstraintBinding'
// or was updated to a value with sufficient 'canUseLightweightTypeConstraintBinding' on another thread.
internal static bool InterlockedUpdate(ref TypeParameterConstraintClauses constraintClauses, TypeParameterConstraintClauses value)
{
bool useLightweightTypeConstraintBinding = value.UsedLightweightTypeConstraintBinding;
bool canUseLightweightTypeConstraintBinding = value.UsedLightweightTypeConstraintBinding;
while (true)
{
var comparand = constraintClauses;
if (comparand.HasValue(useLightweightTypeConstraintBinding))
if (comparand.HasValue(canUseLightweightTypeConstraintBinding))
{
return false;
}
Original file line number Diff line number Diff line change
@@ -96,10 +96,10 @@ public override string Name
}
}

internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding)
internal override ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding)
{
var constraintTypes = ArrayBuilder<TypeWithAnnotations>.GetInstance();
_map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(inProgress, useLightweightTypeConstraintBinding), constraintTypes, null);
_map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(inProgress, canUseLightweightTypeConstraintBinding), constraintTypes, null);
Copy link
Member

@333fred 333fred Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canUseLightweightTypeConstraintBinding [](start = 149, length = 38)

I feel like can might be the wrong word here. It's not an optional thing: if there are constraints, and we don't use lightweight binding, we'll cause cycles. #ByDesign

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That scenarios that request full binding may not get lightweight results, but other scenarios can use lightweight binding. So we have two scenarios: (1) require full binding, (2) would accept ("can use") lightweight binding.


In reply to: 502585995 [](ancestors = 502585995)


TypeWithAnnotations bestObjectConstraint = default;

@@ -116,7 +116,7 @@ internal override ImmutableArray<TypeWithAnnotations> 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 (!useLightweightTypeConstraintBinding && ConstraintsHelper.IsObjectConstraintSignificant(CalculateIsNotNullableFromNonTypeConstraints(), bestObjectConstraint))
if (!canUseLightweightTypeConstraintBinding && 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<TypeWithAnnotations>.GetInstance();
_map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(ConsList<TypeParameterSymbol>.Empty, useLightweightTypeConstraintBinding: false), constraintTypes, null);
_map.SubstituteConstraintTypesDistinctWithoutModifiers(_underlyingTypeParameter, _underlyingTypeParameter.GetConstraintTypes(ConsList<TypeParameterSymbol>.Empty, canUseLightweightTypeConstraintBinding: false), constraintTypes, null);
return IsNotNullableFromConstraintTypes(constraintTypes.ToImmutableAndFree());
}

Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ protected SynthesizedRecordOrdinaryMethod(SourceMemberContainerTypeSymbol contai

protected sealed override ImmutableArray<TypeParameterSymbol> MakeTypeParameters(CSharpSyntaxNode node, DiagnosticBag diagnostics) => ImmutableArray<TypeParameterSymbol>.Empty;

public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding) => ImmutableArray<TypeParameterConstraintClause>.Empty;
public sealed override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding) => ImmutableArray<TypeParameterConstraintClause>.Empty;

protected sealed override void PartialMethodChecks(DiagnosticBag diagnostics)
{
Original file line number Diff line number Diff line change
@@ -175,7 +175,7 @@ protected override void MethodChecks(DiagnosticBag diagnostics)

internal override bool IsExpressionBodied => false;

public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool useLightweightTypeConstraintBinding)
public override ImmutableArray<TypeParameterConstraintClause> GetTypeParameterConstraintClauses(bool canUseLightweightTypeConstraintBinding)
=> ImmutableArray<TypeParameterConstraintClause>.Empty;

protected override object MethodChecksLockObject => _declaration;
10 changes: 5 additions & 5 deletions src/Compilers/CSharp/Portable/Symbols/TypeParameterBounds.cs
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ private TypeParameterBounds(bool usedLightweightTypeConstraintBinding)

internal static class TypeParameterBoundsExtensions
{
internal static bool HasValue(this TypeParameterBounds? boundsOpt, bool useLightweightTypeConstraintBinding)
internal static bool HasValue(this TypeParameterBounds? boundsOpt, bool canUseLightweightTypeConstraintBinding)
{
if (boundsOpt == TypeParameterBounds.Unset)
{
@@ -102,18 +102,18 @@ internal static bool HasValue(this TypeParameterBounds? boundsOpt, bool useLight
{
return true;
}
return useLightweightTypeConstraintBinding || !boundsOpt.UsedLightweightTypeConstraintBinding;
return canUseLightweightTypeConstraintBinding || !boundsOpt.UsedLightweightTypeConstraintBinding;
}

/// <summary>
/// Returns true if bounds was updated with value.
/// Returns false if bounds already had a value with sufficient 'useLightweightTypeConstraintBinding'
/// or was updated to a value with sufficient 'useLightweightTypeConstraintBinding' on another thread.
/// Returns false if bounds already had a value with sufficient 'canUseLightweightTypeConstraintBinding'
Copy link
Member

@333fred 333fred Oct 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sufficient 'canUseLightweightTypeConstraintBinding' [](start = 61, length = 51)

What does sufficient mean? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone asks for fully-bound info, we cannot return light-bound info, it is not sufficient.


In reply to: 502588978 [](ancestors = 502588978)

/// or was updated to a value with sufficient 'canUseLightweightTypeConstraintBinding' on another thread.
/// </summary>
internal static bool InterlockedUpdate(ref TypeParameterBounds? bounds, TypeParameterBounds? value)
{
Debug.Assert(value != TypeParameterBounds.Unset);
bool valueUsedLightweightTypeConstraintBinding = !value.HasValue(useLightweightTypeConstraintBinding: false);
bool valueUsedLightweightTypeConstraintBinding = !value.HasValue(canUseLightweightTypeConstraintBinding: false);

while (true)
{
28 changes: 14 additions & 14 deletions src/Compilers/CSharp/Portable/Symbols/TypeParameterSymbol.cs
Original file line number Diff line number Diff line change
@@ -79,14 +79,14 @@ 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.
/// </summary>
internal ImmutableArray<TypeWithAnnotations> GetConstraintTypesNoUseSiteDiagnostics(bool useLightweightTypeConstraintBinding)
internal ImmutableArray<TypeWithAnnotations> GetConstraintTypesNoUseSiteDiagnostics(bool canUseLightweightTypeConstraintBinding)
{
this.EnsureAllConstraintsAreResolved(useLightweightTypeConstraintBinding);
return this.GetConstraintTypes(ConsList<TypeParameterSymbol>.Empty, useLightweightTypeConstraintBinding);
this.EnsureAllConstraintsAreResolved(canUseLightweightTypeConstraintBinding);
return this.GetConstraintTypes(ConsList<TypeParameterSymbol>.Empty, canUseLightweightTypeConstraintBinding);
}

internal ImmutableArray<TypeWithAnnotations> ConstraintTypesNoUseSiteDiagnostics =>
GetConstraintTypesNoUseSiteDiagnostics(useLightweightTypeConstraintBinding: false);
GetConstraintTypesNoUseSiteDiagnostics(canUseLightweightTypeConstraintBinding: false);

internal ImmutableArray<TypeWithAnnotations> ConstraintTypesWithDefinitionUseSiteDiagnostics(ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
@@ -270,7 +270,7 @@ internal NamedTypeSymbol EffectiveBaseClassNoUseSiteDiagnostics
{
get
{
this.EnsureAllConstraintsAreResolved(useLightweightTypeConstraintBinding: false);
this.EnsureAllConstraintsAreResolved(canUseLightweightTypeConstraintBinding: false);
return this.GetEffectiveBaseClass(ConsList<TypeParameterSymbol>.Empty);
}
}
@@ -295,7 +295,7 @@ internal ImmutableArray<NamedTypeSymbol> EffectiveInterfacesNoUseSiteDiagnostics
{
get
{
this.EnsureAllConstraintsAreResolved(useLightweightTypeConstraintBinding: false);
this.EnsureAllConstraintsAreResolved(canUseLightweightTypeConstraintBinding: false);
return this.GetInterfaces(ConsList<TypeParameterSymbol>.Empty);
}
}
@@ -307,7 +307,7 @@ internal TypeSymbol DeducedBaseTypeNoUseSiteDiagnostics
{
get
{
this.EnsureAllConstraintsAreResolved(useLightweightTypeConstraintBinding: false);
this.EnsureAllConstraintsAreResolved(canUseLightweightTypeConstraintBinding: false);
return this.GetDeducedBaseType(ConsList<TypeParameterSymbol>.Empty);
}
}
@@ -364,21 +364,21 @@ internal ImmutableArray<NamedTypeSymbol> AllEffectiveInterfacesWithDefinitionUse
/// type or method are resolved in a consistent order, regardless of the
/// order the callers query individual type parameters.
/// </summary>
internal abstract void EnsureAllConstraintsAreResolved(bool useLightweightTypeConstraintBinding);
internal abstract void EnsureAllConstraintsAreResolved(bool canUseLightweightTypeConstraintBinding);

/// <summary>
/// Helper method to force type parameter constraints to be resolved.
/// </summary>
protected static void EnsureAllConstraintsAreResolved(ImmutableArray<TypeParameterSymbol> typeParameters, bool useLightweightTypeConstraintBinding)
protected static void EnsureAllConstraintsAreResolved(ImmutableArray<TypeParameterSymbol> typeParameters, bool canUseLightweightTypeConstraintBinding)
{
foreach (var typeParameter in typeParameters)
{
// Invoke any method that forces constraints to be resolved.
var unused = typeParameter.GetConstraintTypes(ConsList<TypeParameterSymbol>.Empty, useLightweightTypeConstraintBinding);
var unused = typeParameter.GetConstraintTypes(ConsList<TypeParameterSymbol>.Empty, canUseLightweightTypeConstraintBinding);
}
}

internal abstract ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool useLightweightTypeConstraintBinding);
internal abstract ImmutableArray<TypeWithAnnotations> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress, bool canUseLightweightTypeConstraintBinding);

internal abstract ImmutableArray<NamedTypeSymbol> GetInterfaces(ConsList<TypeParameterSymbol> inProgress);

@@ -390,7 +390,7 @@ private static bool ConstraintImpliesReferenceType(TypeSymbol constraint)
{
if (constraint.TypeKind == TypeKind.TypeParameter)
{
return IsReferenceTypeFromConstraintTypes(((TypeParameterSymbol)constraint).GetConstraintTypesNoUseSiteDiagnostics(useLightweightTypeConstraintBinding: true));
return IsReferenceTypeFromConstraintTypes(((TypeParameterSymbol)constraint).GetConstraintTypesNoUseSiteDiagnostics(canUseLightweightTypeConstraintBinding: true));
}
else if (!constraint.IsReferenceType)
{
@@ -514,7 +514,7 @@ public sealed override bool IsReferenceType
return true;
}

return IsReferenceTypeFromConstraintTypes(this.GetConstraintTypesNoUseSiteDiagnostics(useLightweightTypeConstraintBinding: true));
return IsReferenceTypeFromConstraintTypes(this.GetConstraintTypesNoUseSiteDiagnostics(canUseLightweightTypeConstraintBinding: true));
}
}

@@ -572,7 +572,7 @@ public sealed override bool IsValueType
return true;
}

return IsValueTypeFromConstraintTypes(this.GetConstraintTypesNoUseSiteDiagnostics(useLightweightTypeConstraintBinding: true));
return IsValueTypeFromConstraintTypes(this.GetConstraintTypesNoUseSiteDiagnostics(canUseLightweightTypeConstraintBinding: true));
}
}

Original file line number Diff line number Diff line change
@@ -146,9 +146,9 @@ public override string Name
return _underlyingTypeParameter.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken);
}

internal override void EnsureAllConstraintsAreResolved(bool useLightweightTypeConstraintBinding)
internal override void EnsureAllConstraintsAreResolved(bool canUseLightweightTypeConstraintBinding)
{
_underlyingTypeParameter.EnsureAllConstraintsAreResolved(useLightweightTypeConstraintBinding);
_underlyingTypeParameter.EnsureAllConstraintsAreResolved(canUseLightweightTypeConstraintBinding);
}

public override ImmutableArray<CSharpAttributeData> GetAttributes()
Original file line number Diff line number Diff line change
@@ -1564,7 +1564,7 @@ class C<T, U, V>
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, useLightweightTypeConstraintBinding: false).Length == 0);
AssertEx.All(actualTypeParameters, p => p.GetConstraintTypes(null, canUseLightweightTypeConstraintBinding: false).Length == 0);
AssertEx.All(actualTypeParameters, p => p.GetInterfaces(null).Length == 0);

foreach (var p in actualTypeParameters)