Addressed pr feedback.

上级 ba3c9b5e
......@@ -298,17 +298,16 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
deconstructStep = new BoundForEachDeconstructStep(variables, deconstruction, valuePlaceholder).MakeCompilerGenerated();
}
else if (!node.HasErrors)
{
// error: must declare foreach loop iteration variables.
Error(diagnostics, ErrorCode.ERR_MustDeclareForeachIteration, variables);
hasErrors = true;
}
else
{
// Bind the expression for error recovery, but discard all new diagnostics
iterationErrorExpression = originalBinder.BindExpression(node.Variable, new DiagnosticBag());
iterationErrorExpression = BindExpression(node.Variable, new DiagnosticBag());
hasErrors = true;
if (!node.HasErrors)
{
Error(diagnostics, ErrorCode.ERR_MustDeclareForeachIteration, variables);
}
}
boundIterationVariableType = new BoundTypeExpression(variables, aliasOpt: null, type: iterationVariableType).MakeCompilerGenerated();
......
......@@ -1450,20 +1450,17 @@ private IForEachLoopOperation CreateBoundForEachStatementOperation(BoundForEachS
{
loopControlVariable = new Lazy<IOperation>(() => Create(boundForEachStatement.DeconstructionOpt.DeconstructionAssignment.Left));
}
else if (locals.Length == 1)
{
var local = (LocalSymbol)locals.Single();
// We use iteration variable type syntax as the underlying syntax node as there is no variable declarator syntax in the syntax tree.
var declaratorSyntax = boundForEachStatement.IterationVariableType.Syntax;
loopControlVariable = new Lazy<IOperation>(() => new VariableDeclarator(local, initializer: null, ignoredArguments: ImmutableArray<IOperation>.Empty, semanticModel: _semanticModel, syntax: declaratorSyntax, type: null, constantValue: default, isImplicit: false));
}
else if (boundForEachStatement.IterationErrorExpressionOpt != null)
{
loopControlVariable = new Lazy<IOperation>(() => Create(boundForEachStatement.IterationErrorExpressionOpt));
}
else
{
loopControlVariable = OperationFactory.NullOperation;
Debug.Assert(locals.Length == 1);
var local = (LocalSymbol)locals[0];
// We use iteration variable type syntax as the underlying syntax node as there is no variable declarator syntax in the syntax tree.
var declaratorSyntax = boundForEachStatement.IterationVariableType.Syntax;
loopControlVariable = new Lazy<IOperation>(() => new VariableDeclarator(local, initializer: null, ignoredArguments: ImmutableArray<IOperation>.Empty, semanticModel: _semanticModel, syntax: declaratorSyntax, type: null, constantValue: default, isImplicit: false));
}
Lazy<IOperation> collection = new Lazy<IOperation>(() => Create(boundForEachStatement.Expression));
......
......@@ -1220,12 +1220,13 @@ public static void M(int[] x)
IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '{ ... }')
IForEachLoopOperation (LoopKind.ForEach) (OperationKind.Loop, Type: null, IsInvalid) (Syntax: 'foreach (x[ ... }')
LoopControlVariable:
null
Collection:
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Collections.IEnumerable, IsImplicit) (Syntax: 'x')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
Operand:
IArrayElementReferenceOperation (OperationKind.ArrayElementReference, Type: System.Int32) (Syntax: 'x[0]')
Array reference:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32[]) (Syntax: 'x')
Indices(1):
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0')
Collection:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32[]) (Syntax: 'x')
Body:
IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }')
NextVariables(0)
......@@ -1283,7 +1284,7 @@ public static void M(int[] x)
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(19996, "https://github.com/dotnet/roslyn/issues/19996")]
public void IForEachLoopStatement_InvalidLoopControlVariableExpression()
public void IForEachLoopStatement_InvalidLoopControlVariableExpression_01()
{
string source = @"
class C
......@@ -1326,5 +1327,95 @@ void M(int a, int b)
VerifyOperationTreeAndDiagnosticsForTest<ForEachVariableStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(17602, "https://github.com/dotnet/roslyn/issues/17602")]
public void IForEachLoopStatement_InvalidLoopControlVariableExpression_02()
{
string source = @"
class C
{
void M(int a, int b)
{
int[] arr = new int[10];
/*<bind>*/foreach (M2(out var x) in arr)
{
}/*</bind>*/
}
void M2(out int x)
{
x = 0;
}
}
";
string expectedOperationTree = @"
IForEachLoopOperation (LoopKind.ForEach) (OperationKind.Loop, Type: null, IsInvalid) (Syntax: 'foreach (M2 ... }')
Locals: Local_1: System.Int32 x
LoopControlVariable:
IInvocationOperation ( void C.M2(out System.Int32 x)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'M2(out var x)')
Instance Receiver:
IInstanceReferenceOperation (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'M2')
Arguments(1):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: 'out var x')
IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: System.Int32) (Syntax: 'var x')
ILocalReferenceOperation: x (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x')
InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Collection:
ILocalReferenceOperation: arr (OperationKind.LocalReference, Type: System.Int32[]) (Syntax: 'arr')
Body:
IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }')
NextVariables(0)
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(7,42): error CS0230: Type and identifier are both required in a foreach statement
// /*<bind>*/foreach (M2(out var x) in arr)
Diagnostic(ErrorCode.ERR_BadForeachDecl, "in").WithLocation(7, 42)
};
VerifyOperationTreeAndDiagnosticsForTest<ForEachVariableStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation)]
[Fact, WorkItem(17602, "https://github.com/dotnet/roslyn/issues/17602")]
public void IForEachLoopStatement_InvalidLoopControlVariableExpression_03()
{
string source = @"
class C
{
void M(object o)
{
int[] arr = new int[10];
/*<bind>*/foreach (o is int x in arr)
{
}/*</bind>*/
}
}
";
string expectedOperationTree = @"
IForEachLoopOperation (LoopKind.ForEach) (OperationKind.Loop, Type: null, IsInvalid) (Syntax: 'foreach (o ... }')
Locals: Local_1: System.Int32 x
LoopControlVariable:
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'o is int x')
Expression:
IParameterReferenceOperation: o (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'o')
Pattern:
IDeclarationPatternOperation (Declared Symbol: System.Int32 x) (OperationKind.DeclarationPattern, Type: null) (Syntax: 'int x')
Collection:
ILocalReferenceOperation: arr (OperationKind.LocalReference, Type: System.Int32[]) (Syntax: 'arr')
Body:
IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }')
NextVariables(0)
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(7,39): error CS0230: Type and identifier are both required in a foreach statement
// /*<bind>*/foreach (o is int x in arr)
Diagnostic(ErrorCode.ERR_BadForeachDecl, "in").WithLocation(7, 39)
};
VerifyOperationTreeAndDiagnosticsForTest<ForEachVariableStatementSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册