Semantic model APIs on declaration expressions and discards#16153
Conversation
219545b to
ce28bd6
Compare
|
@dotnet/roslyn-compiler This is ready for review. Thanks #Resolved |
|
@AlekseyTs If you can find some time, could you do the second review too? Thanks #Resolved |
| { | ||
| get | ||
| { | ||
| return new DiscardSymbol(this.Type); |
There was a problem hiding this comment.
return new DiscardSymbol(this.Type); [](start = 16, length = 36)
Consider adding an assert that this.Type is not null. #Closed
|
|
||
| var type = TupleTypeSymbol.Create(syntax.Location, | ||
| elementsBuilder.ToImmutableAndFree(), locationsBuilder.ToImmutableAndFree(), | ||
| elementNames: default(ImmutableArray<string>), compilation: this.Compilation, shouldCheckConstraints: false); |
There was a problem hiding this comment.
shouldCheckConstraints: false [](start = 94, length = 29)
Consider adding a comment why constraints shouldn't be checked. #Closed
There was a problem hiding this comment.
I'll add a comment.
This makes me think we could construct this final tuple only once. I'll file an issue. #Closed
| private BoundTupleLiteral DeconstructVariablesAsTuple(SyntaxNode syntax, ArrayBuilder<DeconstructionVariable> variables) | ||
| { | ||
| int count = variables.Count; | ||
| var argBuilder = ArrayBuilder<BoundExpression>.GetInstance(count); |
There was a problem hiding this comment.
argBuilder [](start = 16, length = 10)
elementValues or valuesBuilder? #Closed
| { | ||
| int count = variables.Count; | ||
| var argBuilder = ArrayBuilder<BoundExpression>.GetInstance(count); | ||
| var elementsBuilder = ArrayBuilder<TypeSymbol>.GetInstance(count); |
There was a problem hiding this comment.
elementsBuilder [](start = 16, length = 15)
typesBuilder? #Closed
| @@ -690,7 +699,7 @@ internal BoundDeconstructionAssignmentOperator BindDeconstruction( | |||
| { | |||
| DeconstructionVariable locals = BindDeconstructionVariables(left, diagnostics, ref declaration, ref expression); | |||
There was a problem hiding this comment.
BindDeconstructionVariables [](start = 44, length = 27)
Is there still an advantage of using NestedVariables? Could this function produce tuple literal right from the beginning instead of having to translate this structure later on? #Closed
There was a problem hiding this comment.
I think we need NestedVariables because the variables need to be updated (by the inference process). NestedVariables uses a builder, but tuple expression is immutable. #Resolved
| (node is AttributeSyntax) || | ||
| (node is CrefSyntax); | ||
| (node is CrefSyntax) || | ||
| (node is DeclarationExpressionSyntax); |
There was a problem hiding this comment.
(node is DeclarationExpressionSyntax) [](start = 24, length = 37)
Do we really need this extra condition? It feels like the very first condition should be good enough. #Closed
| } | ||
|
|
||
| var symbol = GetDeclaredSymbol((SingleVariableDesignationSyntax)declaration.Designation, cancellationToken); | ||
| return new SymbolInfo(symbol); |
There was a problem hiding this comment.
return new SymbolInfo(symbol) [](start = 16, length = 29)
Do we need to handle null symbol specially here? #Closed
There was a problem hiding this comment.
Thanks. I added it, but I'm having trouble to hit it with a test though.
In reply to: 95017393 [](ancestors = 95017393)
| return GetBindableSyntaxNode(parent); | ||
|
|
||
| case SyntaxKind.DeclarationExpression: | ||
| case SyntaxKind.TupleExpression: |
There was a problem hiding this comment.
case SyntaxKind.TupleExpression: [](start = 20, length = 32)
Are we certain that we can always bind these (both) expressions without knowing context? #Closed
There was a problem hiding this comment.
|
|
||
| var discard1 = GetDiscardDesignations(tree).ElementAt(0); | ||
| Assert.Null(model.GetDeclaredSymbol(discard1)); | ||
| Assert.Null(model.GetTypeInfo(discard1).Type); |
There was a problem hiding this comment.
model.GetTypeInfo(discard1) [](start = 24, length = 27)
Test GetSymbolInfo too? #Closed
| var declaration1 = (DeclarationExpressionSyntax)discard1.Parent; | ||
| Assert.Equal("int _", declaration1.ToString()); | ||
| //Assert.Equal("", model.GetTypeInfo(declaration1).Type.ToTestDisplayString()); // https://github.com/dotnet/roslyn/issues/15450 | ||
| Assert.Equal("System.Int32", model.GetTypeInfo(declaration1).Type.ToTestDisplayString()); |
There was a problem hiding this comment.
model.GetTypeInfo(declaration1) [](start = 41, length = 31)
Test GetSymbolInfo too? #Closed
| var declaration2 = (DeclarationExpressionSyntax)discard2.Parent; | ||
| Assert.Equal("var _", declaration2.ToString()); | ||
| //Assert.Equal("", model.GetTypeInfo(declaration2).Type.ToTestDisplayString()); // https://github.com/dotnet/roslyn/issues/15450 | ||
| Assert.Equal("System.Int32", model.GetTypeInfo(declaration2).Type.ToTestDisplayString()); |
There was a problem hiding this comment.
model.GetTypeInfo(declaration2) [](start = 41, length = 31)
Test GetSymbolInfo too? #Closed
| var declaration1 = (DeclarationExpressionSyntax)discard1.Parent; | ||
| Assert.Equal("int _", declaration1.ToString()); | ||
| //Assert.Equal("System.Int32", model.GetTypeInfo(declaration1).Type.ToTestDisplayString()); // https://github.com/dotnet/roslyn/issues/15450 | ||
| Assert.Equal("System.Int32", model.GetTypeInfo(declaration1).Type.ToTestDisplayString()); |
There was a problem hiding this comment.
model.GetTypeInfo(declaration1) [](start = 41, length = 31)
Test GetSymbolInfo too? #Closed
| var declaration2 = (DeclarationExpressionSyntax)discard2.Parent; | ||
| Assert.Equal("var _", declaration2.ToString()); | ||
| //Assert.Equal("System.Int32", model.GetTypeInfo(declaration2).Type.ToTestDisplayString()); // https://github.com/dotnet/roslyn/issues/15450 | ||
| Assert.Equal("System.Int32", model.GetTypeInfo(declaration2).Type.ToTestDisplayString()); |
There was a problem hiding this comment.
model.GetTypeInfo(declaration2) [](start = 41, length = 31)
Test GetSymbolInfo too? #Closed
| var discard3 = GetDiscardIdentifiers(tree).First(); | ||
| var symbol = (IDiscardSymbol)model.GetSymbolInfo(discard3).Symbol; // returns null https://github.com/dotnet/roslyn/issues/15450 | ||
| //Assert.Equal("System.Int32", symbol.Type.ToTestDisplayString()); | ||
| var discard3Symbol = (IDiscardSymbol)model.GetSymbolInfo(discard3).Symbol; |
There was a problem hiding this comment.
model.GetSymbolInfo(discard3) [](start = 49, length = 29)
Test GetTypeInfo too? #Closed
| var declaration2 = (DeclarationPatternSyntax)discard2.Parent; | ||
| Assert.Equal("var _", declaration2.ToString()); | ||
| //Assert.Equal("", model.GetTypeInfo(declaration2).Type.ToTestDisplayString()); // https://github.com/dotnet/roslyn/issues/15450 | ||
| Assert.Null(model.GetTypeInfo(declaration2).Type); |
There was a problem hiding this comment.
model.GetTypeInfo(declaration2) [](start = 24, length = 31)
Test GetSymbolInfo too, if applicable? #Closed
|
Done with review pass. #Closed |
a80e3b8 to
af52303
Compare
|
|
||
| var discard1 = GetDiscardDesignations(tree).ElementAt(0); | ||
| Assert.Null(model.GetDeclaredSymbol(discard1)); | ||
| Assert.Equal(null, model.GetSymbolInfo(discard1).Symbol); |
There was a problem hiding this comment.
Assert.Equal(null, [](start = 12, length = 18)
Assert.Null? #Closed
| //Assert.Equal("System.Int32", symbol.Type.ToTestDisplayString()); | ||
| Assert.Equal("System.Int32", model.GetTypeInfo(discard3).Type.ToTestDisplayString()); | ||
| var discard3Symbol = (IDiscardSymbol)model.GetSymbolInfo(discard3).Symbol; | ||
| Assert.Equal("System.Int32", discard3Symbol.Type.ToTestDisplayString()); |
There was a problem hiding this comment.
discard3Symbol.Type.ToTestDisplayString() [](start = 41, length = 41)
Print symbol instead? #Closed
| { | ||
| var symbolInfo = model.GetSymbolInfo(decl); | ||
| Assert.Null(symbolInfo.Symbol); | ||
| if (expectedSymbol != null) |
There was a problem hiding this comment.
if (expectedSymbol != null) [](start = 11, length = 28)
Please remove the 'if', we should assert that we get null when null is expected. #Closed
| var typeInfo = model.GetTypeInfo(decl); | ||
| Assert.Null(typeInfo.Type); | ||
| Assert.Null(typeInfo.ConvertedType); | ||
| if (expectedType != null) |
There was a problem hiding this comment.
if (expectedType != null) [](start = 12, length = 25)
Remove if? #Closed
|
LGTM |
… and GlobalExpressionVariable
|
@srivatsn for ask mode approval. Thanks |
Customer scenario
Update semantic model APIs for declaration and discard expressions.
Bugs this fixes:
#15450
Workarounds, if any
Also, why we think they are insufficient for RC vs. RC2, RC3, or RTW
Risk
This is generally a measure our how central the affected code is to adjacent
scenarios and thus how likely your fix is to destabilize a broader area of code
Performance impact
(with a brief justification for that assessment (e.g. "Low perf impact because no extra allocations/no complexity changes" vs. "Low")
Is this a regression from a previous update?
No. Previously the semantic model would return no information for declaration expressions and discards. Now it does.
Root cause analysis:
How did we miss it? What tests are we adding to guard against it in the future?
How was the bug found?
Tracked work item.