Skip to content

Revert two step initialization of constraints#35375

Merged
AlekseyTs merged 3 commits intodotnet:masterfrom
AlekseyTs:Issue28834
May 3, 2019
Merged

Revert two step initialization of constraints#35375
AlekseyTs merged 3 commits intodotnet:masterfrom
AlekseyTs:Issue28834

Conversation

@AlekseyTs
Copy link
Contributor

Closes #28834.
Closes #30061.

@AlekseyTs AlekseyTs requested a review from cston April 30, 2019 20:57
@AlekseyTs AlekseyTs requested a review from a team as a code owner April 30, 2019 20:57
@AlekseyTs AlekseyTs added the Feature - Nullable Reference Types Nullable Reference Types label Apr 30, 2019
@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented May 1, 2019

@cston, @dotnet/roslyn-compiler Please review. #Resolved

@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented May 2, 2019

@cston, @dotnet/roslyn-compiler Please review. #Resolved

// (6,30): error CS0717: 'S': static classes cannot be used as constraints
// partial class C<T> where T : S { }
Diagnostic(ErrorCode.ERR_ConstraintIsStaticClass, "S").WithArguments("S").WithLocation(6, 30),
// (7,15): error CS0265: Partial declarations of 'D<T>' have inconsistent constraints for type parameter 'T'
Copy link
Member

@jcouv jcouv May 2, 2019

Choose a reason for hiding this comment

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

error CS0265: Partial declarations of 'D' have inconsistent constraints for type parameter 'T' [](start = 27, length = 97)

I didn't understand this error. The three partial declarations for D<T> seem to agree: A, I, I, A and I, A. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't understand this error. The three partial declarations for D seem to agree: A, I, I, A and I, A.

See the error below. Invalid constraint types are removed from the set before partials are matched, therefore other partials do not have 'A' among the constraints. I believe this behavior matches C# 7.3 compiler


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

Copy link
Member

Choose a reason for hiding this comment

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

Thanks


In reply to: 280541572 [](ancestors = 280541572,280533172)

}
var map = _map.TypeMap;
Debug.Assert(map != null);
// Use typeParameter.ConstraintTypesNoUseSiteDiagnostics rather than
Copy link
Member

@jcouv jcouv May 2, 2019

Choose a reason for hiding this comment

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

// Use typeParameter.ConstraintTypesNoUseSiteDiagnostics rather than [](start = 12, length = 68)

Feels like this comment is still applicable/useful, no? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Feels like this comment is still applicable/useful, no?

GetConstraintTypesNoUseSiteDiagnostics is removed, ConstraintTypesNoUseSiteDiagnostics has no alternative


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

}

// From typedesc.cpp :
// > A recursive helper that helps determine whether this variable is constrained as ObjRef.
Copy link
Member

@333fred 333fred May 2, 2019

Choose a reason for hiding this comment

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

Is this comment relevant anymore? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this comment relevant anymore?

I think the method is still recursive, indirectly. In any case, I guess this comment is on this method from the beginning of times and refers to relevant parts of native compiler implementation.


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

@@ -300,7 +297,7 @@ internal bool IsEqualToOrDerivedFrom(TypeSymbol type, TypeCompareKind comparison
/// You can ignore custom modifiers, ignore the distinction between object and dynamic, or ignore tuple element names differences.
/// </param>
Copy link
Member

@jcouv jcouv May 2, 2019

Choose a reason for hiding this comment

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

[](start = 12, length = 8)

Consider adding xml doc for new isValueTypeOverrideOpt parameter as well. #Resolved

isValueTypeOverride = new SmallDictionary<TypeParameterSymbol, bool>(ReferenceEqualityComparer.Instance);

internal bool IsEmpty => Constraints == TypeParameterConstraintKind.None && ConstraintTypes.IsEmpty && OtherPartialDeclarations.ContainsOnlyEmptyConstraintClauses();
for (int i = 0; i < typeParameters.Length; i++)
Copy link
Contributor

@cston cston May 2, 2019

Choose a reason for hiding this comment

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

for (int i = 0; i < typeParameters.Length; i++) [](start = 16, length = 47)

Please consider using foreach. #Resolved

}

internal bool IsEarly => !TypeConstraintsSyntax.IsDefault || !OtherPartialDeclarations.IsEmpty;
for (int i = 0; i < typeParameters.Length; i++)
Copy link
Contributor

@cston cston May 2, 2019

Choose a reason for hiding this comment

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

for (int i = 0; i < typeParameters.Length; i++) [](start = 12, length = 47)

Please consider using foreach. #Resolved

internal static bool IsValueTypeFromConstraintTypes(ImmutableArray<TypeWithAnnotations> constraintTypes)
{
if (constraintTypes.IsEmpty)
foreach (var constraintType in constraintTypes)
Copy link
Contributor

@cston cston May 2, 2019

Choose a reason for hiding this comment

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

foreach [](start = 12, length = 7)

return constraintTypes.Any(constraintType => constraintType.Type.IsValueType); #WontFix

});
internal static bool IsReferenceTypeFromConstraintTypes(ImmutableArray<TypeWithAnnotations> constraintTypes)
{
foreach (var constraintType in constraintTypes)
Copy link
Contributor

@cston cston May 2, 2019

Choose a reason for hiding this comment

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

foreach [](start = 12, length = 7)

return constraintTypes.Any(constraintType => ConstraintImpliesReferenceType(constraintType.Type)); #WontFix

internal static readonly EqualsComparer ConsiderEverythingComparer = new EqualsComparer(TypeCompareKind.ConsiderEverything, isValueTypeOverrideOpt: null);

private readonly TypeCompareKind _compareKind;
private readonly SmallDictionary<TypeParameterSymbol, bool> _isValueTypeOverrideOpt;
Copy link
Contributor

@cston cston May 2, 2019

Choose a reason for hiding this comment

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

SmallDictionary [](start = 29, length = 15)

It's unfortunate this is a mutable dictionary. Should all of the Equals() infrastructure use ImmutableDictionary<TypeParameterSymbol, bool> instead? #Resolved


internal abstract TypeSymbol GetDeducedBaseType(ConsList<TypeParameterSymbol> inProgress);

private static bool ConstraintImpliesReferenceType(TypeSymbol constraint)
Copy link
Member

@jcouv jcouv May 2, 2019

Choose a reason for hiding this comment

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

ConstraintImpliesReferenceType [](start = 28, length = 30)

nit: I'd be tempted to name this method like the one below, but singular IsReferenceTypeFromConstraintType. I was thrown off by the distinction between "is" and "implies".
Along those lines, this method could be a local function inside of IsReferenceTypeFromConstraintTypes. #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This method and others in this file are simply restored to their original state prior to #27525.


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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This include names, etc.


In reply to: 280583028 [](ancestors = 280583028,280582299)

/// Populated from early constraint checking step only.
/// </summary>
internal readonly ImmutableArray<TypeParameterConstraintClause> OtherPartialDeclarations;
internal static void AdjustConstraintTypes(Symbol container, ImmutableArray<TypeParameterSymbol> typeParameters,
Copy link
Member

@jcouv jcouv May 2, 2019

Choose a reason for hiding this comment

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

AdjustConstraintTypes [](start = 29, length = 21)

nit: this could probably use a comment too. What is "adjusting"? #Resolved

Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "U?").WithLocation(15, 12),
// (17,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
// static U?[] F3<T, U>() where T : struct where U : T => throw null!;
Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "U?").WithLocation(17, 12),
Copy link
Member

@jcouv jcouv May 2, 2019

Choose a reason for hiding this comment

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

Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "U?").WithLocation(17, 12), [](start = 16, length = 88)

nit: this is a cascading diagnostic. The root cause is below ("Type parameter 'T' has the 'struct' constraint so 'T' cannot be used as a constraint for 'U'"). Might there be a simple way to suppress? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nit: this is a cascading diagnostic. The root cause is below ("Type parameter 'T' has the 'struct' constraint so 'T' cannot be used as a constraint for 'U'"). Might there be a simple way to suppress?

Unfortunately there is no easy way to do that. We are not tracking what constraints were removed as invalid and what impact they otherwise would have if they were valid. Also, now we have a consistent experience across all usages of U?. For example, in the code below prior to this change the CS8627 would be reported only inside method body, but not inside method signature. With this change, method signature gets the same treatment.

    class C1
    {
#nullable enable
        static U?[] F3<T, U>() where T : struct where U : T
        {
            U? x = default;
            Console.WriteLine(x);
            throw null!;
        }
    }

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

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 2)

@AlekseyTs AlekseyTs merged commit 0088a06 into dotnet:master May 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider adding factory method to TypeParameterBounds type Revert two step initialization of constraints and base type

4 participants