Closed AlekseyTs closed 5 years ago
Also see Constraints_27 unit-test
This test behavior has already been updated. Both Constraints_21
and Constraints_27
were updated as a part of 19b50a45ec09d2ac4253d7375f34a03362d4c2a5
Chatted with @AlekseyTs. The specific code was indeed changed but it didn't end up testing the intended behavior here. A test which accurately verifies that constraints are flipped to oblivious in this case can be tested as follows:
Assert.Null(bf1.TypeParameters[0].ReferenceTypeConstraintIsNullable);
That test indeed still fails.
Here is a scenario that reflects the current behavior:
[Fact]
public void ConstraintsChecks_32()
{
var source =
@"
#nullable enable
public class A
{
public virtual void F2<T2>(T2 y) where T2 : class?
{
}
public void M3<T3>(T3 z) where T3 : class { }
}
class B : A
{
#nullable disable
public override void F2<T22>(T22 y)
{
#nullable enable
M3<T22>(y); // 3
M3(y); // 4
}
#nullable disable
void F22<T22>(T22 y) where T22 : class
{
#nullable enable
M3<T22>(y); // 5
M3(y); // 6
}
}
";
var comp1 = CreateCompilation(source);
comp1.VerifyDiagnostics(
// (18,9): warning CS8634: The type 'T22' cannot be used as type parameter 'T3' in the generic type or method 'A.M3<T3>(T3)'. Nullability of type argument 'T22' doesn't match 'class' constraint.
// M3<T22>(y); // 3
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterReferenceTypeConstraint, "M3<T22>").WithArguments("A.M3<T3>(T3)", "T3", "T22").WithLocation(18, 9),
// (19,9): warning CS8634: The type 'T22' cannot be used as type parameter 'T3' in the generic type or method 'A.M3<T3>(T3)'. Nullability of type argument 'T22' doesn't match 'class' constraint.
// M3(y); // 4
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterReferenceTypeConstraint, "M3").WithArguments("A.M3<T3>(T3)", "T3", "T22").WithLocation(19, 9)
);
}
Note, that we get two warnings inside overriding method and none in F22
. The difference is caused by the fact that the overriding method is inheriting class?
constraint, where as F22
gets class~
constraint. Both methods are declared in nullable disable context.
On Apr. 15, 2019, C# LDM decided to keep the current behavior: "The constraint is inherited from the definition."