-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Fix crash in is operator used with tuples #19413
Conversation
* Fixes crash in `is` operator used with tuples Fixes dotnet#19310 * Unify subsumption implementations Fixes dotnet#19273 * Matching an expression of type `byte?` with a pattern of type `int` should not be allowed Fixes dotnet#19151 * Add documentation for the breaking change matching `int?` against the pattern `long x`
Also fixes #16129. |
That ubuntu_14_debug_prtest failure is a big WTF.
It passed on ubuntu_16. |
@dotnet-bot please test ubuntu_14_debug_prtest |
@@ -14,3 +14,8 @@ For instance, `var t = (a, b.c, this.d);` will produce a tuple with element name | |||
Consider the case where the type of `a` is `System.Func<bool>` and you write `var local = t.a();`. This will now find the first element of the tuple and invoke it, whereas previously it could only mean "invoke an extension method named 'a'". | |||
|
|||
- https://github.com/dotnet/roslyn/issues/16870 In C# 7.0 and before C# 7.1, the compiler accepted self-assignments in deconstruction-assignment. The compiler now produces a warning for that. For instance, in `(x, y) = (x, 2);`. | |||
|
|||
- The compiler is now more precise in detecting erroneous pattern-matching operations because the expression could not possibly match the pattern. The following situations now cause an error: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a link to one representative issue, so that it is easier to pull for more information/details. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is only one issue, and it doesn't have more information, but I'll add a link. #Closed
return _factory.Sequence( | ||
ImmutableArray.Create(s, i), | ||
ImmutableArray.Create<BoundExpression>( | ||
_factory.AssignmentExpression(_factory.Local(i), _factory.Convert(tmpType, loweredInput)), | ||
_factory.AssignmentExpression(_factory.Local(i), _factory.Convert(objectType, loweredInput)), | ||
_factory.AssignmentExpression(loweredTarget, _factory.Conditional( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would it take to remove the need for the boolean local s
? I mean, ideally o is S ? (S)o : e
and o is S s ? s : e
should produce the same code as long as CanChangeValueBetweenReads
for o
is false.
@@ -1468,6 +1468,8 @@ internal enum ErrorCode | |||
ERR_VoidInTuple = 8210, | |||
#endregion more stragglers for C# 7 | |||
|
|||
#region diagnostics introduced for C# 7.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I did some compaction on bottom of the list, I just noticed the gap from 8210 to 8300.
Opened #19523 to compact more. #WontFix
This appears to fix #19122 as well. |
@AlekseyTs @dotnet/roslyn-compiler May I please have a couple of reviews for this fix for 7.1? |
@AlekseyTs @dotnet/roslyn-compiler May I please have a couple of reviews of this fix for 7.1? |
@@ -392,7 +392,8 @@ private void LowerConstantValueDecision(DecisionTree.ByValue byValue) | |||
{ | |||
var loweredRight = kv.Key; | |||
var loweredLeft = kv.Value; | |||
loweredRight = _factory.Convert(loweredLeft.Type, loweredRight); | |||
//loweredRight = _factory.Convert(loweredLeft.Type, loweredRight); | |||
Debug.Assert(loweredLeft.Type.Equals(loweredRight.Type, TypeCompareKind.IgnoreDynamicAndTupleNames)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IgnoreDynamicAndTupleNames [](start = 96, length = 26)
I think we should use AllIgnoreOptions here. #Closed
@@ -392,7 +392,8 @@ private void LowerConstantValueDecision(DecisionTree.ByValue byValue) | |||
{ | |||
var loweredRight = kv.Key; | |||
var loweredLeft = kv.Value; | |||
loweredRight = _factory.Convert(loweredLeft.Type, loweredRight); | |||
//loweredRight = _factory.Convert(loweredLeft.Type, loweredRight); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//loweredRight = _factory.Convert(loweredLeft.Type, loweredRight); [](start = 24, length = 66)
Please remove obsolete code. #Closed
@@ -31,16 +31,7 @@ static class C { | |||
compilation.GetDiagnostics().Verify(); | |||
compilation.GetEmitDiagnostics().Verify( | |||
// warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. | |||
Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1), | |||
// (9,48): error CS0518: Predefined type 'System.Nullable`1' is not defined or imported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// (9,48): error CS0518: Predefined type 'System.Nullable`1' is not defined or imported [](start = 16, length = 87)
It looks like we lost tests for error scenarios like this one, none of them are hitting the interesting code paths. We should come up with new scenarios that do. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We aren't hitting them because those code paths don't exist any longer. We use a different lowering strategy for this code now.
// (9,48): error CS0518: Predefined type 'System.Nullable`1' is not defined or imported | ||
// public static bool M() => ((object)123) is int i; | ||
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int i").WithArguments("System.Nullable`1").WithLocation(9, 48), | ||
// (9,48): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// (9,48): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' [](start = 16, length = 95)
It looks like we lost tests for error scenarios like this one, none of them are hitting the interesting code paths. We should come up with new scenarios that do. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We aren't hitting them because those code paths don't exist any longer. We use a different lowering strategy for this code now.
// (9,48): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' | ||
// public static bool M() => ((object)123) is int i; | ||
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "int i").WithArguments("System.Nullable`1", "GetValueOrDefault").WithLocation(9, 48), | ||
// (9,48): error CS0656: Missing compiler required member 'System.Nullable`1.get_HasValue' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// (9,48): error CS0656: Missing compiler required member 'System.Nullable`1.get_HasValue' [](start = 16, length = 90)
It looks like we lost tests for error scenarios like this one, none of them are hitting the interesting code paths. We should come up with new scenarios that do. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We aren't hitting them because those code paths don't exist any longer. We use a different lowering strategy for this code now.
@MeiChin-Tsai This fixes a few reported crashes. I expect that the compiler after this fix will be much more stable in this area than before the fix. The most significant part of this change replaces recently written code with slightly modified code that had been in production use for a long time. |
}" | ||
); | ||
} | ||
|
||
[Fact, WorkItem(19280, "https://github.com/dotnet/roslyn/issues/19280")] | ||
public void ShareLikeKindedTemps_01() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ShareLikeKindedTemps_01 [](start = 20, length = 23)
I am not sure what happened with this test, it looks like it was deleted. Intentional? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was a merge error. Adding it again (and the next test).
@@ -4780,10 +4800,13 @@ public static void Main(string[] args) | |||
CreateCompilationWithMscorlib45(program).VerifyDiagnostics( | |||
// (10,18): error CS0266: Cannot implicitly convert type 'double' to 'int?'. An explicit conversion exists (are you missing a cast?) | |||
// case double.NaN: | |||
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "double.NaN").WithArguments("double", "int?").WithLocation(10, 18), | |||
// (13,18): error CS8121: An expression of type int? cannot be handled by a pattern of type string. | |||
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "double.NaN").WithArguments("double", "int?"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "double.NaN").WithArguments("double", "int?"), [](start = 16, length = 91)
Location is lost, please restore. #Closed
// case string _: | ||
Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("int?", "string").WithLocation(13, 18) | ||
Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("int?", "string"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("int?", "string"), [](start = 16, length = 85)
Location is lost, please restore. #Closed
@@ -332,7 +350,7 @@ public void foo2(char i) | |||
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "97.0f").WithArguments("float", "char").WithLocation(34, 18), | |||
// (38,18): error CS0266: Cannot implicitly convert type 'int' to 'char'. An explicit conversion exists (are you missing a cast?) | |||
// case 97: | |||
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "97").WithArguments("int", "char").WithLocation(38, 18) | |||
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "97").WithArguments("int", "char") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "97").WithArguments("int", "char") [](start = 16, length = 79)
Location is lost, please restore. #Closed
Done with review pass. #Closed |
approved. |
@AlekseyTs The PR has been modified in response to your review comments. Do you have anything else? @dotnet/roslyn-compiler May I please have a second reviewer? |
retest windows_debug_vs-integration_prtest please |
In order to answer this question or to sign-off, I need to do another review pass. It is on my list of things to do. #Closed |
requiresNullTest = requiresNullTest && MatchConstantValue(loweredInput, type, true) != true; | ||
if (loweredInput.Type.IsNullableType()) | ||
{ | ||
var getValueOrDefault = _factory.SpecialMethod(SpecialMember.System_Nullable_T_GetValueOrDefault).AsMember((NamedTypeSymbol)loweredInput.Type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var getValueOrDefault = _factory.SpecialMethod(SpecialMember.System_Nullable_T_GetValueOrDefault).AsMember((NamedTypeSymbol)loweredInput.Type); [](start = 20, length = 143)
Do we have a test that hits this code path with missing SpecialMember.System_Nullable_T_GetValueOrDefault?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes (see MissingNullable_03
).
//} | ||
|
||
var input = _factory.SynthesizedLocal(loweredInput.Type, syntax); // we copy the input to avoid double evaluation | ||
var getHasValue = _factory.SpecialMethod(SpecialMember.System_Nullable_T_get_HasValue).AsMember((NamedTypeSymbol)loweredInput.Type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var getHasValue = _factory.SpecialMethod(SpecialMember.System_Nullable_T_get_HasValue).AsMember((NamedTypeSymbol)loweredInput.Type); [](start = 24, length = 132)
Do we have a test that hits this code path with missing SpecialMember.System_Nullable_T_get_HasValue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_factory.SpecialMethod handles this one the same way it handles the one you asked about a few lines earlier. Every call to that helper method is handled the same way in LocalRewriter (and causes the rest of the calling method to be skipped).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also see 9e05b04 which adds a test that triggers the requested condition.
Please answer a new question #19413 (comment), the thread appears as "outdated". |
Done with review pass. Just have three questions around test coverage above. |
The question was
That is not possible. There are two call sites for this method, one of which passes parameters such that the extra conditions later do not make a difference in the returned value. The other call site treats |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. LGTM
@dotnet/roslyn-compiler May I please have a second review? |
1 similar comment
@dotnet/roslyn-compiler May I please have a second review? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks for the code walkthrough.
Customer scenario
Certain patterns of erroneous pattern-matching were not previously diagnosed. Specifically, when you match a nullable of one integral type with a declaration pattern of another integral type, there was no error. We introduce this error. This is a breaking change in a scenario related to the recently-released pattern-matching feature, so we would like to take the break as soon as possible so that customers do not rely on being able to write the erroneous code. We do not believe the pattern of code is very likely to arise in practice.
This PR also fixes a crash in the existing
is
operator when used with tuple types.Bugs this fixes:
Fixes crash in
is
operator used with tuplesFixes Crash in
is
operator used with tuple #19310Matching an expression of type
byte?
with a pattern of typeint
should not be allowedFixes Matching an expression of type
byte?
with a pattern of typeint
should not be allowed #19151Unify subsumption implementations
Fixes Merge subsumption implementations #19273
Greatly improved code gen for value type pattern match
Fixes pattern matching with structs causes unnecessary boxing, nullable conversions #16129
Fixes Struct unboxing - very bad performance of pattern matching #18944
Fixes Code generation for type pattern: optimize value type cases #14252
Workarounds, if any
N/A
Risk
The purpose of the change is to reduce future risk. Also, because we now combine what were previously three separate implementations, we have one third fewer places there could be bugs.
Performance impact
None expected, as there are only small changes to the code paths taken during compilation.
Is this a regression from a previous update?
No.
Root cause analysis:
For the crash, we did not test scenarios involving mixing tuples with the existing
is
operator.How was the bug found?
I found the crash reviewing the existing code while preparing the fix for the other two issues.