diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
index 900844049d7ca..322bf0061e311 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
@@ -16,6 +16,10 @@ namespace Microsoft.CodeAnalysis.CSharp
///
internal partial class Binder
{
+ ///
+ /// Only handles assignment-only or declaration-only deconstructions at this point.
+ /// Issue https://github.com/dotnet/roslyn/issues/15050 tracks allowing mixed deconstructions
+ ///
private BoundExpression BindDeconstruction(AssignmentExpressionSyntax node, DiagnosticBag diagnostics)
{
var left = node.Left;
@@ -26,7 +30,6 @@ private BoundExpression BindDeconstruction(AssignmentExpressionSyntax node, Diag
return BindDeconstructionDeclaration(node, left, right, diagnostics);
}
- // We only parse assignment-only or declaration-only deconstructions at this point
AssertDeconstructionIsAssignment(left);
var tuple = (TupleExpressionSyntax)left;
diff --git a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs
index 8421f63797b38..b10a6c90eb35e 100644
--- a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs
@@ -445,6 +445,15 @@ protected override LocalSymbol MakeDeconstructionVariable(
SingleVariableDesignationSyntax designation,
AssignmentExpressionSyntax deconstruction)
{
+ NamedTypeSymbol container = _scopeBinder.ContainingType;
+
+ if ((object)container != null && container.IsScriptClass &&
+ (object)_scopeBinder.LookupDeclaredField(designation) != null)
+ {
+ // This is a field declaration
+ return null;
+ }
+
return SourceLocalSymbol.MakeDeconstructionLocal(
containingSymbol: _scopeBinder.ContainingMemberOrLambda,
scopeBinder: _scopeBinder,
diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
index ddff5f3fae0af..d3fa565c35c13 100644
--- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
+++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
@@ -252,17 +252,6 @@ private static Binder GetEnclosingBinder(SyntaxNode node, int position, Binder r
{
binder = rootBinder.GetBinder(current);
}
- else if ((kind == SyntaxKind.DeclarationExpression || kind == SyntaxKind.TupleExpression) &&
- (current.Parent as ForEachVariableStatementSyntax)?.Variable == current)
- {
- binder = rootBinder.GetBinder(current.Parent);
- }
- else if ((kind == SyntaxKind.DeclarationExpression || kind == SyntaxKind.TupleExpression) &&
- (current.Parent is AssignmentExpressionSyntax) &&
- (current.Parent.Parent as ForStatementSyntax)?.Initializers.Contains(current.Parent) == true)
- {
- binder = rootBinder.GetBinder(current.Parent.Parent);
- }
else
{
// If this ever breaks, make sure that all callers of
@@ -321,7 +310,8 @@ private static Binder AdjustBinderForPositionWithinStatement(int position, Binde
case SyntaxKind.ForEachStatement:
case SyntaxKind.ForEachVariableStatement:
var foreachStmt = (CommonForEachStatementSyntax)stmt;
- if (LookupPosition.IsBetweenTokens(position, foreachStmt.OpenParenToken, foreachStmt.Statement.GetFirstToken()))
+ var start = stmt.Kind() == SyntaxKind.ForEachVariableStatement ? foreachStmt.InKeyword : foreachStmt.OpenParenToken;
+ if (LookupPosition.IsBetweenTokens(position, start, foreachStmt.Statement.GetFirstToken()))
{
binder = binder.GetBinder(foreachStmt.Expression);
Debug.Assert(binder != null);
@@ -1457,7 +1447,7 @@ private static Binder GetQueryEnclosingBinder(int position, CSharpSyntaxNode sta
}
}
- done:
+done:
return GetEnclosingBinder(AdjustStartingNodeAccordingToNewRoot(startingNode, queryClause.Syntax),
position, queryClause.Binder, queryClause.Syntax);
}
@@ -1690,28 +1680,34 @@ internal protected virtual CSharpSyntaxNode GetBindableSyntaxNode(CSharpSyntaxNo
/// If this declaration is part of a deconstruction, find the deconstruction.
/// Returns null otherwise.
///
- private AssignmentExpressionSyntax GetContainingDeconstruction(ExpressionSyntax expr)
+ private static AssignmentExpressionSyntax GetContainingDeconstruction(ExpressionSyntax expr)
{
- Debug.Assert(expr.Kind() == SyntaxKind.TupleExpression || expr.Kind() == SyntaxKind.DeclarationExpression);
-
- if (expr.Parent.Kind() == SyntaxKind.Argument)
+ while (true)
{
- if (expr.Parent.Parent.Kind() == SyntaxKind.TupleExpression)
+ Debug.Assert(expr.Kind() == SyntaxKind.TupleExpression || expr.Kind() == SyntaxKind.DeclarationExpression);
+ var parent = expr.Parent;
+ if (parent == null) { return null; }
+
+ if (parent.Kind() == SyntaxKind.Argument)
{
- return GetContainingDeconstruction((TupleExpressionSyntax)expr.Parent.Parent);
+ if (parent.Parent?.Kind() == SyntaxKind.TupleExpression)
+ {
+ expr = (TupleExpressionSyntax)parent.Parent;
+ continue;
+ }
+ else
+ {
+ return null;
+ }
}
- else
+ else if (parent.Kind() == SyntaxKind.SimpleAssignmentExpression &&
+ (object)((AssignmentExpressionSyntax)parent).Left == expr)
{
- return null;
+ return (AssignmentExpressionSyntax)parent;
}
- }
- else if (expr.Parent.Kind() == SyntaxKind.SimpleAssignmentExpression &&
- (object)((AssignmentExpressionSyntax)expr.Parent).Left == expr)
- {
- return (AssignmentExpressionSyntax)expr.Parent;
- }
- return null;
+ return null;
+ }
}
///
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/VariablesDeclaredWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/VariablesDeclaredWalker.cs
index 1ada036ea507a..502d282d9ee69 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/VariablesDeclaredWalker.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/VariablesDeclaredWalker.cs
@@ -170,10 +170,14 @@ protected override void VisitLvalue(BoundLocal node)
private void CheckOutVarDeclaration(BoundLocal node)
{
if (IsInside &&
- !node.WasCompilerGenerated && node.Syntax.Kind() == SyntaxKind.DeclarationExpression &&
- ((SingleVariableDesignationSyntax)((DeclarationExpressionSyntax)node.Syntax).Designation).Identifier == node.LocalSymbol.IdentifierToken)
+ !node.WasCompilerGenerated && node.Syntax.Kind() == SyntaxKind.DeclarationExpression)
{
- _variablesDeclared.Add(node.LocalSymbol);
+ var declaration = (DeclarationExpressionSyntax)node.Syntax;
+ if (((SingleVariableDesignationSyntax)declaration.Designation).Identifier == node.LocalSymbol.IdentifierToken &&
+ ((ArgumentSyntax)declaration.Parent).RefOrOutKeyword.Kind() == SyntaxKind.OutKeyword)
+ {
+ _variablesDeclared.Add(node.LocalSymbol);
+ }
}
}
diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
index 51ace3a34fa98..3b3ed301b1cda 100644
--- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
@@ -11,6 +11,7 @@
namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
{
using Microsoft.CodeAnalysis.Syntax.InternalSyntax;
+ using System.Linq;
internal partial class LanguageParser : SyntaxParser
{
@@ -7534,6 +7535,19 @@ private StatementSyntax ParseEmbeddedStatement(bool complexCheck)
case SyntaxKind.LocalFunctionStatement:
statement = this.AddError(statement, ErrorCode.ERR_BadEmbeddedStmt);
break;
+ case SyntaxKind.ExpressionStatement:
+ // Deconstruction-declaration is only allowed as top-level statement
+ // see https://github.com/dotnet/roslyn/issues/15049
+ var expression = ((ExpressionStatementSyntax)statement).Expression;
+ if (expression.Kind == SyntaxKind.SimpleAssignmentExpression)
+ {
+ var assignment = (AssignmentExpressionSyntax)expression;
+ if (assignment.Left.EnumerateNodes().Any(x => x.RawKind == (int)SyntaxKind.DeclarationExpression))
+ {
+ statement = this.AddError(statement, ErrorCode.ERR_BadEmbeddedStmt);
+ }
+ }
+ break;
}
return statement;
diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
index e3959c6129d36..dc898854a46c6 100644
--- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
+++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
@@ -157,17 +157,17 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.CasePatternSwitchLabel = 9009 -> Micros
Microsoft.CodeAnalysis.CSharp.SyntaxKind.ConstantPattern = 9002 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.DeclarationExpression = 9040 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.DeclarationPattern = 9000 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
-Microsoft.CodeAnalysis.CSharp.SyntaxKind.ForEachVariableStatement = 8934 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.ForEachVariableStatement = 8929 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.IsPatternExpression = 8657 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.LocalFunctionStatement = 8830 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
-Microsoft.CodeAnalysis.CSharp.SyntaxKind.ParenthesizedVariableDesignation = 8931 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.ParenthesizedVariableDesignation = 8928 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefExpression = 9050 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefType = 9051 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
-Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleVariableDesignation = 8930 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleVariableDesignation = 8927 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.ThrowExpression = 9052 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
-Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleElement = 8926 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
-Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleExpression = 8927 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
-Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleType = 8925 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleElement = 8925 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleExpression = 8926 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleType = 8924 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.WhenClause = 9013 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
abstract Microsoft.CodeAnalysis.CSharp.Syntax.BaseMethodDeclarationSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax
abstract Microsoft.CodeAnalysis.CSharp.Syntax.CommonForEachStatementSyntax.CloseParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken
diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml
index 9a7ccaf2a99c1..f156a84e9133b 100644
--- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml
+++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml
@@ -2110,7 +2110,10 @@
-
+
+
+
+
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs
index dc9d9761078e9..33a7df4b0cdd4 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxExtensions.cs
@@ -206,7 +206,10 @@ internal static SyntaxNode SkipParens(this SyntaxNode expression)
return expression;
}
- private static bool IsDeconstructionDeclaration(this ExpressionSyntax self)
+ ///
+ /// Is this expression composed only of declaration expressions nested in tuple expressions?
+ ///
+ private static bool IsDeconstructionDeclarationLeft(this ExpressionSyntax self)
{
switch (self.Kind())
{
@@ -214,7 +217,7 @@ private static bool IsDeconstructionDeclaration(this ExpressionSyntax self)
return true;
case SyntaxKind.TupleExpression:
var tuple = (TupleExpressionSyntax)self;
- return tuple.Arguments.All(a => IsDeconstructionDeclaration(a.Expression));
+ return tuple.Arguments.All(a => IsDeconstructionDeclarationLeft(a.Expression));
default:
return false;
}
@@ -222,7 +225,7 @@ private static bool IsDeconstructionDeclaration(this ExpressionSyntax self)
internal static bool IsDeconstructionDeclaration(this AssignmentExpressionSyntax self)
{
- return self.Left.IsDeconstructionDeclaration();
+ return self.Left.IsDeconstructionDeclarationLeft();
}
private static bool IsInContextWhichNeedsDynamicAttribute(CSharpSyntaxNode node)
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs
index ab293071094ee..e320389a42bbd 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs
@@ -401,9 +401,8 @@ internal static bool IsVarOrPredefinedType(this Syntax.InternalSyntax.SyntaxToke
internal static bool IsDeclarationExpressionType(SyntaxNode node, out DeclarationExpressionSyntax parent)
{
- var component = node.Parent as DeclarationExpressionSyntax;
- parent = component as DeclarationExpressionSyntax;
- return node == component?.Type;
+ parent = node.Parent as DeclarationExpressionSyntax;
+ return node == parent?.Type;
}
}
}
\ No newline at end of file
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
index 217dc04c617d0..670594c473c54 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
@@ -539,12 +539,12 @@ public enum SyntaxKind : ushort
// Changes after C# 6
// tuples
- TupleType = 8925,
- TupleElement = 8926,
- TupleExpression = 8927,
- SingleVariableDesignation = 8930,
- ParenthesizedVariableDesignation = 8931,
- ForEachVariableStatement = 8934,
+ TupleType = 8924,
+ TupleElement = 8925,
+ TupleExpression = 8926,
+ SingleVariableDesignation = 8927,
+ ParenthesizedVariableDesignation = 8928,
+ ForEachVariableStatement = 8929,
// patterns (for pattern-matching)
DeclarationPattern = 9000,
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs
index 274eebdfd4d75..4adb04a7b7f43 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs
@@ -1163,6 +1163,40 @@ public void Deconstruct(out int a, out int b)
);
}
+ [Fact]
+ public void MixedDeconstructionCannotBeParsed()
+ {
+ string source = @"
+class C
+{
+ public static void Main()
+ {
+ int x;
+ (x, int y) = new C();
+ }
+
+ public void Deconstruct(out int a, out int b)
+ {
+ a = 1;
+ b = 2;
+ }
+}
+";
+
+ var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
+ comp.VerifyDiagnostics(
+ // (7,10): error CS1031: Type expected
+ // (x, int y) = new C();
+ Diagnostic(ErrorCode.ERR_TypeExpected, "x").WithLocation(7, 10),
+ // (7,10): error CS0128: A local variable or function named 'x' is already defined in this scope
+ // (x, int y) = new C();
+ Diagnostic(ErrorCode.ERR_LocalDuplicate, "x").WithArguments("x").WithLocation(7, 10),
+ // (6,13): warning CS0168: The variable 'x' is declared but never used
+ // int x;
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(6, 13)
+ );
+ }
+
[Fact]
public void DeconstructionWithTupleNamesCannotBeParsed()
{
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs
index 0ea0808711de5..6af5812985acd 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs
@@ -2434,7 +2434,7 @@ static void Test(int arg1, (byte, byte) arg2)
}
[Fact]
- public void DeclarationCanBeEmbedded()
+ public void DeclarationCannotBeEmbedded()
{
var source = @"
class C1
@@ -2445,30 +2445,12 @@ void M()
var (x, y) = (1, 2);
}
}
-";
- var comp = CreateCompilationWithMscorlib(source, references: s_valueTupleRefs);
- comp.VerifyDiagnostics();
- }
-
- [Fact]
- public void EmbeddedDeclarationIsScoped()
- {
- var source = @"
-class C1
-{
- void M()
- {
- if (true)
- var (x, y) = (1, 2);
- System.Console.WriteLine(x);
- }
-}
";
var comp = CreateCompilationWithMscorlib(source, references: s_valueTupleRefs);
comp.VerifyDiagnostics(
- // (8,34): error CS0103: The name 'x' does not exist in the current context
- // System.Console.WriteLine(x);
- Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(8, 34)
+ // (7,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
+ // var (x, y) = (1, 2);
+ Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "var (x, y) = (1, 2);").WithLocation(7, 13)
);
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs
index 345d8dfe24d94..6754ed0a7d027 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs
@@ -8981,6 +8981,9 @@ static bool TakeOutParam(object y, out object x)
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
options: TestOptions.DebugExe, parseOptions: TestOptions.Regular);
compilation.VerifyDiagnostics(
+ // (11,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
+ // var (d, dd) = (TakeOutParam(true, out var x1), x1);
+ Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "var (d, dd) = (TakeOutParam(true, out var x1), x1);").WithLocation(11, 13),
// (13,9): error CS0103: The name 'x1' does not exist in the current context
// x1++;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(13, 9)
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs
index d0e1ea399ef10..6c75f3301f6c9 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs
@@ -6756,6 +6756,9 @@ void Test1()
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
options: TestOptions.DebugExe, parseOptions: TestOptions.Regular);
compilation.VerifyDiagnostics(
+ // (11,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
+ // var (d, dd) = ((true is var x1), x1);
+ Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "var (d, dd) = ((true is var x1), x1);").WithLocation(11, 13),
// (13,9): error CS0103: The name 'x1' does not exist in the current context
// x1++;
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(13, 9)
diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs
index eacb1dcfbbfc6..2402708b8a884 100644
--- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs
+++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs
@@ -303,6 +303,7 @@ private static CSharpSyntaxNode Parse(
statementDiagnostics.Free();
// Prefer to parse expression statements (except deconstruction-declarations) as expressions.
+ // Once https://github.com/dotnet/roslyn/issues/15049 is fixed, we should parse d-declarations as expressions.
var isExpressionStatement = statementSyntax.IsKind(SyntaxKind.ExpressionStatement);
var isDeconstructionDeclaration = isExpressionStatement &&
IsDeconstructionDeclaration((ExpressionStatementSyntax)statementSyntax);
diff --git a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs
index dae1b6011ed26..9f3adf5152a86 100644
--- a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs
+++ b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs
@@ -879,8 +879,6 @@ private IEnumerable InferTypeInBinaryOrAssignmentExpression(E
if (operatorToken.Kind() == SyntaxKind.EqualsToken &&
(left.Kind() == SyntaxKind.TupleExpression || left.Kind() == SyntaxKind.DeclarationExpression))
{
- // TODO REVIEW Once GetTypeInfo works on the left-hand-side expression in a deconstruction declaration,
- // this may not be needed
return InferTypeInVariableComponentAssignment(left);
}