提交 8f4befcc 编写于 作者: E Evan Hauck

Add local functions to BoundBlock

上级 bd2fa007
......@@ -157,6 +157,14 @@ internal virtual ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(CSharpSyn
return this.Next.GetDeclaredLocalsForScope(node);
}
/// <summary>
/// Get local functions declared immediately in scope represented by the node.
/// </summary>
internal virtual ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode node)
{
return this.Next.GetDeclaredLocalFunctionsForScope(node);
}
/// <summary>
/// The member containing the binding context. Note that for the purposes of the compiler,
/// a lambda expression is considered a "member" of its enclosing method, field, or lambda.
......
......@@ -2132,7 +2132,11 @@ internal static BoundBlock BindBlock(BlockSyntax node, DiagnosticBag diagnostics
}
}
return new BoundBlock(node, blockBinder.GetDeclaredLocalsForScope(node), boundStatements.ToImmutableAndFree());
return new BoundBlock(
node,
blockBinder.GetDeclaredLocalsForScope(node),
blockBinder.GetDeclaredLocalFunctionsForScope(node),
boundStatements.ToImmutableAndFree());
}
internal BoundExpression GenerateConversionForAssignment(TypeSymbol targetType, BoundExpression expression, DiagnosticBag diagnostics, bool isDefaultParameter = false)
......@@ -3271,7 +3275,7 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr
}
// Need to attach the tree for when we generate sequence points.
return new BoundBlock(node, locals, ImmutableArray.Create(statement)) { WasCompilerGenerated = node.Kind() != SyntaxKind.ArrowExpressionClause };
return new BoundBlock(node, locals, ImmutableArray<LocalFunctionSymbol>.Empty, ImmutableArray.Create(statement)) { WasCompilerGenerated = node.Kind() != SyntaxKind.ArrowExpressionClause };
}
/// <summary>
......
......@@ -56,5 +56,22 @@ internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(CSharpSy
throw ExceptionUtilities.Unreachable;
}
internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode node)
{
if (node.Kind() == SyntaxKind.Block)
{
if (((BlockSyntax)node).Statements == _statements)
{
return this.LocalFunctions;
}
}
else if (_statements.Count == 1 && _statements.First() == node)
{
return this.LocalFunctions;
}
throw ExceptionUtilities.Unreachable;
}
}
}
......@@ -154,6 +154,11 @@ internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(CSharpSy
throw ExceptionUtilities.Unreachable;
}
internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode node)
{
throw ExceptionUtilities.Unreachable;
}
internal override BoundSwitchStatement BindSwitchExpressionAndSections(SwitchStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
{
// There's supposed to be a SwitchBinder (or other overrider of this method) in the chain.
......
......@@ -46,5 +46,15 @@ internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(CSharpSy
throw ExceptionUtilities.Unreachable;
}
internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode node)
{
if (node == _syntax)
{
return ImmutableArray<LocalFunctionSymbol>.Empty;
}
throw ExceptionUtilities.Unreachable;
}
}
}
......@@ -46,5 +46,15 @@ internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(CSharpSy
throw ExceptionUtilities.Unreachable;
}
internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode node)
{
if (node == _syntax)
{
return ImmutableArray<LocalFunctionSymbol>.Empty;
}
throw ExceptionUtilities.Unreachable;
}
}
}
......@@ -444,5 +444,10 @@ internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(CSharpSy
{
throw ExceptionUtilities.Unreachable;
}
internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode node)
{
throw ExceptionUtilities.Unreachable;
}
}
}
......@@ -549,6 +549,7 @@
-->
<Node Name="BoundBlock" Base="BoundStatementList">
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="LocalFunctions" Type="ImmutableArray&lt;LocalFunctionSymbol&gt;"/>
</Node>
<!--
......
......@@ -525,21 +525,19 @@ internal partial class BoundBlock
{
public static BoundBlock SynthesizedNoLocals(CSharpSyntaxNode syntax, BoundStatement statement)
{
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty,
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create(statement))
{ WasCompilerGenerated = true };
}
public static BoundBlock SynthesizedNoLocals(CSharpSyntaxNode syntax, ImmutableArray<BoundStatement> statements)
{
Debug.Assert(statements.Length > 0);
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, statements) { WasCompilerGenerated = true };
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty, statements) { WasCompilerGenerated = true };
}
public static BoundBlock SynthesizedNoLocals(CSharpSyntaxNode syntax, params BoundStatement[] statements)
{
Debug.Assert(statements.Length > 0);
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, statements.AsImmutableOrNull()) { WasCompilerGenerated = true };
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty, statements.AsImmutableOrNull()) { WasCompilerGenerated = true };
}
}
......
......@@ -145,7 +145,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
BoundStatement retStatement = F.Return(retExpression);
// Create a bound block
F.CloseMethod(F.Block(ImmutableArray.Create<LocalSymbol>(boundLocal.LocalSymbol), assignment, retStatement));
F.CloseMethod(F.Block(ImmutableArray.Create<LocalSymbol>(boundLocal.LocalSymbol), ImmutableArray<LocalFunctionSymbol>.Empty, assignment, retStatement));
}
internal override bool HasSpecialName
......
......@@ -81,6 +81,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
var body = F.Block(
ImmutableArray.Create<LocalSymbol>(hashCode, i),
ImmutableArray<LocalFunctionSymbol>.Empty,
F.If(
F.Binary(BinaryOperatorKind.ObjectNotEqual, F.SpecialType(SpecialType.System_Boolean),
F.Parameter(text),
......
......@@ -200,7 +200,7 @@ internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMethodSymbol
statement = new BoundSequencePoint(accessor.SyntaxNode, statement) { WasCompilerGenerated = true };
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create<BoundStatement>(statement)) { WasCompilerGenerated = true };
return BoundBlock.SynthesizedNoLocals(syntax, statement);
}
/// <summary>
......@@ -358,10 +358,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEve
memberDescriptor.Name),
syntax.Location));
return new BoundBlock(syntax,
locals: ImmutableArray<LocalSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(@return))
{ WasCompilerGenerated = true };
return BoundBlock.SynthesizedNoLocals(syntax, @return);
}
Binder.ReportUseSiteDiagnostics(updateMethod, diagnostics, syntax);
......@@ -404,12 +401,10 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEve
{ WasCompilerGenerated = true })
{ WasCompilerGenerated = true };
return new BoundBlock(syntax,
locals: ImmutableArray<LocalSymbol>.Empty,
return BoundBlock.SynthesizedNoLocals(syntax,
statements: ImmutableArray.Create<BoundStatement>(
eventUpdate,
@return))
{ WasCompilerGenerated = true };
@return));
}
compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create<TypeSymbol>(delegateType));
......@@ -505,6 +500,7 @@ internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEve
return new BoundBlock(syntax,
locals: tmps.AsImmutable(),
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(
tmp0Init,
loopStart,
......@@ -548,6 +544,7 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo
return new BoundBlock(
syntax,
ImmutableArray<LocalSymbol>.Empty,
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create<BoundStatement>(
new BoundTryStatement(
syntax,
......@@ -556,6 +553,7 @@ internal static BoundBlock ConstructDestructorBody(MethodSymbol method, BoundBlo
new BoundBlock(
syntax,
ImmutableArray<LocalSymbol>.Empty,
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create<BoundStatement>(
baseFinalizeCall)
)
......
......@@ -847,7 +847,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
if (methodSymbol.IsScriptConstructor)
{
body = new BoundBlock(methodSymbol.GetNonNullSyntaxNode(), ImmutableArray<LocalSymbol>.Empty, ImmutableArray<BoundStatement>.Empty) { WasCompilerGenerated = true };
body = BoundBlock.SynthesizedNoLocals(methodSymbol.GetNonNullSyntaxNode(), ImmutableArray<BoundStatement>.Empty);
includeInitializersInBody = false;
importChain = null;
}
......@@ -858,7 +858,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
BoundTypeOrInstanceInitializers initializerStatements = InitializerRewriter.Rewrite(processedInitializers.BoundInitializers, methodSymbol, submissionResultType);
// the lowered script initializers should not be treated as initializers anymore but as a method body:
body = new BoundBlock(initializerStatements.Syntax, ImmutableArray<LocalSymbol>.Empty, initializerStatements.Statements) { WasCompilerGenerated = true };
body = BoundBlock.SynthesizedNoLocals(initializerStatements.Syntax, initializerStatements.Statements);
includeInitializersInBody = false;
importChain = null;
......@@ -883,7 +883,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
if (body != null && methodSymbol.ContainingType.IsStructType() && !methodSymbol.IsImplicitConstructor)
{
// In order to get correct diagnostics, we need to analyze initializers and the body together.
body = body.Update(body.Locals, body.Statements.Insert(0, analyzedInitializers));
body = body.Update(body.Locals, body.LocalFunctions, body.Statements.Insert(0, analyzedInitializers));
includeInitializersInBody = false;
analyzedInitializers = null;
}
......@@ -1592,7 +1592,7 @@ private static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationSta
statements = ImmutableArray.Create(constructorInitializer, body);
}
return new BoundBlock(method.GetNonNullSyntaxNode(), ImmutableArray<LocalSymbol>.Empty, statements) { WasCompilerGenerated = true };
return BoundBlock.SynthesizedNoLocals(method.GetNonNullSyntaxNode(), statements);
}
/// <summary>
......
......@@ -26,6 +26,12 @@ internal partial class DataFlowPass : AbstractFlowPass<DataFlowPass.LocalState>
/// </summary>
private readonly PooledHashSet<LocalSymbol> _usedVariables = PooledHashSet<LocalSymbol>.GetInstance();
/// <summary>
/// Variables that were used anywhere, in the sense required to suppress warnings about
/// unused variables.
/// </summary>
private readonly PooledHashSet<LocalFunctionSymbol> _usedLocalFunctions = PooledHashSet<LocalFunctionSymbol>.GetInstance();
/// <summary>
/// Variables that were initialized or written anywhere.
/// </summary>
......@@ -102,6 +108,7 @@ internal partial class DataFlowPass : AbstractFlowPass<DataFlowPass.LocalState>
protected override void Free()
{
_usedVariables.Free();
_usedLocalFunctions.Free();
_writtenVariables.Free();
_capturedVariables.Free();
_unsafeAddressTakenVariables.Free();
......@@ -394,6 +401,11 @@ protected virtual void NoteRead(Symbol variable, ParameterSymbol rangeVariableUn
{
_usedVariables.Add(local);
}
var localFunction = variable as LocalFunctionSymbol;
if ((object)localFunction != null)
{
_usedLocalFunctions.Add(localFunction);
}
if ((object)variable != null)
{
......@@ -1281,6 +1293,7 @@ public override BoundNode VisitBlock(BoundBlock node)
DeclareVariables(node.Locals);
var result = base.VisitBlock(node);
ReportUnusedVariables(node.Locals);
ReportUnusedVariables(node.LocalFunctions);
return result;
}
......@@ -1455,6 +1468,25 @@ private void ReportIfUnused(LocalSymbol symbol, bool assigned)
}
}
private void ReportUnusedVariables(ImmutableArray<LocalFunctionSymbol> locals)
{
foreach (var symbol in locals)
{
ReportIfUnused(symbol, assigned: true);
}
}
private void ReportIfUnused(LocalFunctionSymbol symbol, bool assigned)
{
if (!_usedLocalFunctions.Contains(symbol))
{
if (!string.IsNullOrEmpty(symbol.Name)) // avoid diagnostics for parser-inserted names
{
Diagnostics.Add(assigned && _writtenVariables.Contains(symbol) ? ErrorCode.WRN_UnreferencedVarAssg : ErrorCode.WRN_UnreferencedVar, symbol.Locations[0], symbol.Name);
}
}
}
public override BoundNode VisitLocal(BoundLocal node)
{
// Note: the caller should avoid allowing this to be called for the left-hand-side of
......@@ -1494,7 +1526,7 @@ public override BoundNode VisitCall(BoundCall node)
{
if (node.Method.MethodKind == MethodKind.LocalFunction)
{
CheckAssigned(node.Method, node.Syntax);
CheckAssigned(node.Method.OriginalDefinition, node.Syntax);
}
return base.VisitCall(node);
}
......@@ -1503,7 +1535,7 @@ public override BoundNode VisitConversion(BoundConversion node)
{
if (node.ConversionKind == ConversionKind.MethodGroup && node.SymbolOpt?.MethodKind == MethodKind.LocalFunction)
{
CheckAssigned(node.SymbolOpt, node.Syntax);
CheckAssigned(node.SymbolOpt.OriginalDefinition, node.Syntax);
}
return base.VisitConversion(node);
}
......@@ -1512,11 +1544,23 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE
{
if (node.MethodOpt?.MethodKind == MethodKind.LocalFunction)
{
CheckAssigned(node.MethodOpt, node.Syntax);
CheckAssigned(node.MethodOpt.OriginalDefinition, node.Syntax);
}
return base.VisitDelegateCreationExpression(node);
}
public override BoundNode VisitMethodGroup(BoundMethodGroup node)
{
foreach (var method in node.Methods)
{
if (method.MethodKind == MethodKind.LocalFunction)
{
CheckAssigned(method, node.Syntax);
}
}
return base.VisitMethodGroup(node);
}
public override BoundNode VisitLambda(BoundLambda node)
{
return VisitLambdaOrLocalFunction(node);
......
......@@ -88,10 +88,10 @@ internal static BoundBlock AppendImplicitReturn(BoundStatement node, MethodSymbo
{
case BoundKind.Block:
var block = (BoundBlock)node;
return block.Update(block.Locals, block.Statements.Add(ret));
return block.Update(block.Locals, block.LocalFunctions, block.Statements.Add(ret));
default:
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create(ret, node));
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty, ImmutableArray.Create(ret, node));
}
}
......
......@@ -226,6 +226,7 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
var completeTry = _F.Block(
locals.ToImmutableAndFree(),
ImmutableArray<LocalFunctionSymbol>.Empty,
statements.ToImmutableAndFree());
return completeTry;
......@@ -402,6 +403,7 @@ private BoundStatement UnpendException(LocalSymbol pendingExceptionLocal)
return _F.Block(
ImmutableArray.Create<LocalSymbol>(obj),
ImmutableArray<LocalFunctionSymbol>.Empty,
objInit,
_F.If(
_F.ObjectNotEqual(
......@@ -430,6 +432,7 @@ private BoundStatement Rethrow(LocalSymbol obj)
// better rethrow
rethrow = _F.Block(
ImmutableArray.Create(ex),
ImmutableArray<LocalFunctionSymbol>.Empty,
assignment,
_F.If(_F.ObjectEqual(_F.Local(ex), _F.Null(ex.Type)), rethrow),
// ExceptionDispatchInfo.Capture(pendingExceptionLocal).Throw();
......@@ -484,6 +487,7 @@ private BoundStatement RewriteFinalizedRegion(BoundTryStatement node)
currentAwaitCatchFrame.pendingCaughtException,
currentAwaitCatchFrame.pendingCatch).
AddRange(currentAwaitCatchFrame.GetHoistedLocals()),
ImmutableArray<LocalFunctionSymbol>.Empty,
_F.HiddenSequencePoint(),
_F.Assignment(
_F.Local(currentAwaitCatchFrame.pendingCatch),
......@@ -616,6 +620,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
var handler = _F.Block(
handlerLocals,
ImmutableArray<LocalFunctionSymbol>.Empty,
handlerStatements.ToImmutableAndFree()
);
......
......@@ -130,6 +130,7 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
bodyBuilder.Add(
F.Try(
F.Block(ImmutableArray<LocalSymbol>.Empty,
ImmutableArray<LocalFunctionSymbol>.Empty,
// switch (state) ...
F.HiddenSequencePoint(),
Dispatch(),
......@@ -201,6 +202,7 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
body.Syntax,
F.Block(
locals.ToImmutableAndFree(),
ImmutableArray<LocalFunctionSymbol>.Empty,
newStatements));
if (rootScopeHoistedLocals.Length > 0)
......@@ -301,6 +303,7 @@ private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpressi
LocalSymbol resultTemp = F.SynthesizedLocal(type);
return F.Block(
ImmutableArray.Create(awaiterTemp, resultTemp),
ImmutableArray<LocalFunctionSymbol>.Empty,
awaitIfIncomplete,
F.Assignment(F.Local(resultTemp), getResultCall),
F.ExpressionStatement(nullAwaiter),
......@@ -312,6 +315,7 @@ private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpressi
// $awaiterTemp = null;
return F.Block(
ImmutableArray.Create(awaiterTemp),
ImmutableArray<LocalFunctionSymbol>.Empty,
awaitIfIncomplete,
F.ExpressionStatement(getResultCall),
F.ExpressionStatement(nullAwaiter));
......@@ -474,6 +478,7 @@ private BoundStatement GenerateAwaitOnCompletedDynamic(LocalSymbol awaiterTemp)
thenClause: F.Block(
ImmutableArray.Create(notifyCompletionTemp),
ImmutableArray<LocalFunctionSymbol>.Empty,
F.Assignment(
F.Local(notifyCompletionTemp),
// Use reference conversion rather than dynamic conversion:
......@@ -505,6 +510,7 @@ private BoundStatement GenerateAwaitOnCompletedDynamic(LocalSymbol awaiterTemp)
return F.Block(
SingletonOrPair(criticalNotifyCompletedTemp, thisTemp),
ImmutableArray<LocalFunctionSymbol>.Empty,
blockBuilder.ToImmutableAndFree());
}
......
......@@ -193,6 +193,7 @@ protected override BoundStatement GenerateStateMachineCreation(LocalSymbol state
return F.Block(
ImmutableArray.Create(builderVariable),
ImmutableArray<LocalFunctionSymbol>.Empty,
bodyBuilder.ToImmutableAndFree());
}
catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex)
......
......@@ -302,7 +302,7 @@ private BoundStatement UpdateStatement(BoundSpillSequenceBuilder builder, BoundS
}
var substituterOpt = (substituteTemps && _tempSubstitution.Count > 0) ? new LocalSubstituter(_tempSubstitution) : null;
var result = _F.Block(builder.GetLocals(), builder.GetStatements(substituterOpt));
var result = _F.Block(builder.GetLocals(), ImmutableArray<LocalFunctionSymbol>.Empty, builder.GetStatements(substituterOpt));
builder.Free();
return result;
......
......@@ -95,7 +95,7 @@ internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImpleme
// state_0:
// state = -1;
// [[rewritten body]]
newBody = F.Block(ImmutableArray.Create(cachedState),
newBody = F.Block(ImmutableArray.Create(cachedState), ImmutableArray<LocalFunctionSymbol>.Empty,
F.Block(
F.HiddenSequencePoint(),
F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField))
......@@ -153,6 +153,7 @@ internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImpleme
var disposeBody = F.Block(
ImmutableArray.Create<LocalSymbol>(stateLocal),
ImmutableArray<LocalFunctionSymbol>.Empty,
F.Assignment(F.Local(stateLocal), F.Field(F.This(), stateField)),
EmitFinallyFrame(rootFrame, state),
F.Return());
......@@ -179,6 +180,7 @@ private BoundStatement HandleReturn(BoundStatement newBody)
// return methodValue;
newBody = F.Block(
ImmutableArray.Create<LocalSymbol>(_methodValue),
ImmutableArray<LocalFunctionSymbol>.Empty,
newBody,
F.Assignment(this.F.Local(_methodValue), this.F.Literal(true)),
F.Label(_exitLabel),
......
......@@ -267,7 +267,7 @@ private void GenerateEnumerableImplementation(ref BoundExpression managedThreadI
}
bodyBuilder.Add(F.Return(F.Local(resultVariable)));
F.CloseMethod(F.Block(ImmutableArray.Create(resultVariable), bodyBuilder.ToImmutableAndFree()));
F.CloseMethod(F.Block(ImmutableArray.Create(resultVariable), ImmutableArray<LocalFunctionSymbol>.Empty, bodyBuilder.ToImmutableAndFree()));
// Generate IEnumerable.GetEnumerator
var getEnumerator = OpenMethodImplementation(IEnumerable_GetEnumerator);
......
......@@ -248,7 +248,7 @@ private BoundStatement AddStatementsIfNeeded(BoundStatement body)
if (_addedLocals != null)
{
_addedStatements.Add(body);
body = new BoundBlock(body.Syntax, _addedLocals.ToImmutableAndFree(), _addedStatements.ToImmutableAndFree()) { WasCompilerGenerated = true };
body = new BoundBlock(body.Syntax, _addedLocals.ToImmutableAndFree(), ImmutableArray<LocalFunctionSymbol>.Empty, _addedStatements.ToImmutableAndFree()) { WasCompilerGenerated = true };
_addedLocals = null;
_addedStatements = null;
}
......@@ -839,7 +839,7 @@ private BoundBlock RewriteBlock(BoundBlock node, ArrayBuilder<BoundExpression> p
}
// TODO: we may not need to update if there was nothing to rewrite.
return node.Update(newLocals.ToImmutableAndFree(), newStatements.ToImmutableAndFree());
return node.Update(newLocals.ToImmutableAndFree(), node.LocalFunctions, newStatements.ToImmutableAndFree());
}
public override BoundNode VisitCatchBlock(BoundCatchBlock node)
......@@ -965,7 +965,7 @@ public override BoundNode VisitStatementList(BoundStatementList node)
newStatements.Add((BoundStatement)this.Visit(s));
}
return new BoundBlock(node.Syntax, newLocals.ToImmutableAndFree(), newStatements.ToImmutableAndFree(), node.HasErrors);
return new BoundBlock(node.Syntax, newLocals.ToImmutableAndFree(), ImmutableArray<LocalFunctionSymbol>.Empty, newStatements.ToImmutableAndFree(), node.HasErrors);
});
}
else
......@@ -986,7 +986,7 @@ public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
InsertAndFreePrologue(newStatements, prologue);
newStatements.Add((BoundStatement)base.VisitSwitchStatement(node));
return new BoundBlock(node.Syntax, newLocals.ToImmutableAndFree(), newStatements.ToImmutableAndFree(), node.HasErrors);
return new BoundBlock(node.Syntax, newLocals.ToImmutableAndFree(), ImmutableArray<LocalFunctionSymbol>.Empty, newStatements.ToImmutableAndFree(), node.HasErrors);
});
}
else
......
......@@ -14,7 +14,7 @@ public override BoundNode VisitBlock(BoundBlock node)
{
if (node.WasCompilerGenerated || !this.GenerateDebugInfo || node.Syntax.Kind() == SyntaxKind.ArrowExpressionClause)
{
return node.Update(node.Locals, VisitList(node.Statements));
return node.Update(node.Locals, node.LocalFunctions, VisitList(node.Statements));
}
BlockSyntax syntax = node.Syntax as BlockSyntax;
......@@ -39,13 +39,13 @@ public override BoundNode VisitBlock(BoundBlock node)
builder.Add(new BoundSequencePointWithSpan(syntax, null, cBspan));
}
return new BoundBlock(syntax, node.Locals, builder.ToImmutableAndFree(), node.HasErrors);
return new BoundBlock(syntax, node.Locals, node.LocalFunctions, builder.ToImmutableAndFree(), node.HasErrors);
}
public override BoundNode VisitNoOpStatement(BoundNoOpStatement node)
{
return (node.WasCompilerGenerated || !this.GenerateDebugInfo)
? new BoundBlock(node.Syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<BoundStatement>.Empty)
? new BoundBlock(node.Syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty, ImmutableArray<BoundStatement>.Empty)
: AddSequencePoint(node);
}
}
......
......@@ -55,6 +55,7 @@ public override BoundNode VisitFixedStatement(BoundFixedStatement node)
{
return _factory.Block(
localBuilder.ToImmutableAndFree(),
ImmutableArray<LocalFunctionSymbol>.Empty,
new BoundTryStatement(
_factory.Syntax,
_factory.Block(statementBuilder.ToImmutableAndFree()),
......@@ -64,7 +65,7 @@ public override BoundNode VisitFixedStatement(BoundFixedStatement node)
else
{
statementBuilder.AddRange(cleanup);
return _factory.Block(localBuilder.ToImmutableAndFree(), statementBuilder.ToImmutableAndFree());
return _factory.Block(localBuilder.ToImmutableAndFree(), ImmutableArray<LocalFunctionSymbol>.Empty, statementBuilder.ToImmutableAndFree());
}
}
......
......@@ -208,6 +208,7 @@ private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement n
finallyBlockOpt = new BoundBlock(forEachSyntax,
locals: ImmutableArray<LocalSymbol>.Empty,
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(disposeStmt));
}
else
......@@ -259,6 +260,7 @@ private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement n
// if (d != null) d.Dispose();
finallyBlockOpt = new BoundBlock(forEachSyntax,
locals: ImmutableArray.Create<LocalSymbol>(disposableVar),
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(disposableVarDecl, ifStmt));
}
......@@ -274,6 +276,7 @@ private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement n
BoundStatement tryFinally = new BoundTryStatement(forEachSyntax,
tryBlock: new BoundBlock(forEachSyntax,
locals: ImmutableArray<LocalSymbol>.Empty,
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(whileLoop)),
catchBlocks: ImmutableArray<BoundCatchBlock>.Empty,
finallyBlockOpt: finallyBlockOpt);
......@@ -284,6 +287,7 @@ private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement n
result = new BoundBlock(
syntax: forEachSyntax,
locals: ImmutableArray.Create(enumeratorVar),
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(enumeratorVarDecl, tryFinally));
}
else
......@@ -296,6 +300,7 @@ private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement n
result = new BoundBlock(
syntax: forEachSyntax,
locals: ImmutableArray.Create(enumeratorVar),
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(enumeratorVarDecl, whileLoop));
}
......@@ -485,7 +490,7 @@ private BoundStatement RewriteStringForEachStatement(BoundForEachStatement node)
}
private static BoundBlock CreateBlockDeclaringIterationVariable(
LocalSymbol iterationVariable,
LocalSymbol iterationVariable,
BoundStatement iteratorVariableInitialization,
BoundStatement rewrittenBody,
ForEachStatementSyntax forEachSyntax)
......@@ -502,6 +507,7 @@ private BoundStatement RewriteStringForEachStatement(BoundForEachStatement node)
return new BoundBlock(
forEachSyntax,
locals: ImmutableArray.Create(iterationVariable),
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create(iteratorVariableInitialization, rewrittenBody));
}
......@@ -605,8 +611,8 @@ private BoundStatement RewriteSingleDimensionalArrayForEachStatement(BoundForEac
// { V v = (V)a[p]; /* node.Body */ }
BoundStatement loopBody = CreateBlockDeclaringIterationVariable(iterationVar, iterationVariableDecl, rewrittenBody, forEachSyntax);
BoundStatement loopBody = CreateBlockDeclaringIterationVariable(iterationVar, iterationVariableDecl, rewrittenBody, forEachSyntax);
// for (A[] a = /*node.Expression*/, int p = 0; p < a.Length; p = p + 1) {
// V v = (V)a[p];
// /*node.Body*/
......@@ -808,6 +814,7 @@ private BoundStatement RewriteMultiDimensionalArrayForEachStatement(BoundForEach
BoundStatement result = new BoundBlock(
forEachSyntax,
ImmutableArray.Create(arrayVar).Concat(upperVar.AsImmutableOrNull()),
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create(arrayVarDecl).Concat(upperVarDecl.AsImmutableOrNull()).Add(forLoop));
AddForEachKeywordSequencePoint(forEachSyntax, ref result);
......
......@@ -150,7 +150,7 @@ public override BoundNode VisitForStatement(BoundForStatement node)
statementBuilder.Add(new BoundLabelStatement(syntax, breakLabel));
var statements = statementBuilder.ToImmutableAndFree();
return new BoundBlock(syntax, outerLocals, statements, hasErrors);
return new BoundBlock(syntax, outerLocals, ImmutableArray<LocalFunctionSymbol>.Empty, statements, hasErrors);
}
}
}
......@@ -120,6 +120,7 @@ public override BoundNode VisitLockStatement(BoundLockStatement node)
return new BoundBlock(
lockSyntax,
ImmutableArray.Create(boundLockTemp.LocalSymbol, boundLockTakenTemp.LocalSymbol),
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create(
MakeInitialLockSequencePoint(boundLockTempInit, lockSyntax),
boundLockTakenTempInit,
......@@ -170,6 +171,7 @@ public override BoundNode VisitLockStatement(BoundLockStatement node)
return new BoundBlock(
lockSyntax,
ImmutableArray.Create(boundLockTemp.LocalSymbol),
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create(
MakeInitialLockSequencePoint(boundLockTempInit, lockSyntax),
enterCall,
......
......@@ -172,7 +172,11 @@ public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
statementBuilder.Add(rewrittenSwitchStatement);
return new BoundBlock(syntax, locals: (object)tempLocal == null ? ImmutableArray<LocalSymbol>.Empty : ImmutableArray.Create<LocalSymbol>(tempLocal), statements: statementBuilder.ToImmutableAndFree());
return new BoundBlock(
syntax,
locals: (object)tempLocal == null ? ImmutableArray<LocalSymbol>.Empty : ImmutableArray.Create<LocalSymbol>(tempLocal),
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: statementBuilder.ToImmutableAndFree());
}
private static LabelSymbol GetNullValueTargetSwitchLabel(ImmutableArray<BoundSwitchSection> sections, GeneratedLabelSymbol breakLabel)
......
......@@ -56,6 +56,7 @@ public override BoundNode VisitUsingStatement(BoundUsingStatement node)
return new BoundBlock(
usingSyntax,
node.Locals,
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create<BoundStatement>(result));
}
}
......@@ -141,6 +142,7 @@ private BoundBlock RewriteExpressionUsingStatement(BoundUsingStatement node, Bou
return new BoundBlock(
syntax: usingSyntax,
locals: node.Locals.Add(boundTemp.LocalSymbol),
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(expressionStatement, tryFinally));
}
......@@ -190,6 +192,7 @@ private BoundBlock RewriteDeclarationUsingStatement(CSharpSyntaxNode usingSyntax
return new BoundBlock(
syntax: usingSyntax,
locals: ImmutableArray.Create<LocalSymbol>(boundTemp.LocalSymbol), //localSymbol will be declared by an enclosing block
localFunctions: ImmutableArray<LocalFunctionSymbol>.Empty,
statements: ImmutableArray.Create<BoundStatement>(
rewrittenDeclaration,
new BoundExpressionStatement(declarationSyntax, tempAssignment),
......
......@@ -131,8 +131,9 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
public override BoundNode VisitBlock(BoundBlock node)
{
var newLocals = RewriteLocals(node.Locals);
var newLocalFunctions = node.LocalFunctions;
var newStatements = VisitList(node.Statements);
return node.Update(newLocals, newStatements);
return node.Update(newLocals, newLocalFunctions, newStatements);
}
public override BoundNode VisitSequence(BoundSequence node)
......
......@@ -269,6 +269,7 @@ private BoundStatement GenerateKickoffMethodBody()
bodyBuilder.Add(GenerateStateMachineCreation(stateMachineVariable, frameType));
return F.Block(
ImmutableArray.Create(stateMachineVariable),
ImmutableArray<LocalFunctionSymbol>.Empty,
bodyBuilder.ToImmutableAndFree());
}
......
......@@ -398,7 +398,7 @@ public BoundBlock Block()
public BoundBlock Block(ImmutableArray<BoundStatement> statements)
{
return Block(ImmutableArray<LocalSymbol>.Empty, statements);
return Block(ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty, statements);
}
public BoundBlock Block(params BoundStatement[] statements)
......@@ -406,14 +406,14 @@ public BoundBlock Block(params BoundStatement[] statements)
return Block(ImmutableArray.Create(statements));
}
public BoundBlock Block(ImmutableArray<LocalSymbol> locals, params BoundStatement[] statements)
public BoundBlock Block(ImmutableArray<LocalSymbol> locals, ImmutableArray<LocalFunctionSymbol> localFunctions, params BoundStatement[] statements)
{
return Block(locals, ImmutableArray.Create(statements));
return Block(locals, localFunctions, ImmutableArray.Create(statements));
}
public BoundBlock Block(ImmutableArray<LocalSymbol> locals, ImmutableArray<BoundStatement> statements)
public BoundBlock Block(ImmutableArray<LocalSymbol> locals, ImmutableArray<LocalFunctionSymbol> localFunctions, ImmutableArray<BoundStatement> statements)
{
return new BoundBlock(Syntax, locals, statements) { WasCompilerGenerated = true };
return new BoundBlock(Syntax, locals, localFunctions, statements) { WasCompilerGenerated = true };
}
public BoundReturnStatement Return(BoundExpression expression = null)
......
......@@ -306,6 +306,7 @@ internal override BoundBlock CreateBody()
return new BoundBlock(syntax,
ImmutableArray.Create<LocalSymbol>(submissionLocal.LocalSymbol),
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create<BoundStatement>(
// var script = new Script();
new BoundExpressionStatement(
......@@ -440,6 +441,7 @@ internal override BoundBlock CreateBody()
return new BoundBlock(syntax,
ImmutableArray.Create<LocalSymbol>(submissionLocal.LocalSymbol),
ImmutableArray<LocalFunctionSymbol>.Empty,
ImmutableArray.Create<BoundStatement>(submissionAssignment, returnStatement))
{ WasCompilerGenerated = true };
}
......
......@@ -2766,7 +2766,10 @@ static void Main(string[] args)
Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(6, 24),
// (6,26): error CS1023: Embedded statement cannot be a declaration or labeled statement
// void f() { if () const int i = 0; }
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "const int i = 0;").WithLocation(6, 26)
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "const int i = 0;").WithLocation(6, 26),
// (6,14): warning CS0168: The variable 'f' is declared but never used
// void f() { if () const int i = 0; }
Diagnostic(ErrorCode.WRN_UnreferencedVar, "f").WithArguments("f").WithLocation(6, 14)
);
}
......
......@@ -168,6 +168,7 @@ void Params(params int x)
{
Console.WriteLine(x);
}
Params(2);
}
}
";
......@@ -190,6 +191,8 @@ void RefOut(ref int x = 2)
{
x++;
}
int y = 2;
RefOut(ref y);
}
}
";
......@@ -214,6 +217,7 @@ void NamedOptional(string x = 2)
{
Console.WriteLine(x);
}
NamedOptional(""2"");
}
}
";
......@@ -239,6 +243,7 @@ void CallerMemberName([CallerMemberName] int s = 2)
{
Console.WriteLine(s);
}
CallerMemberName();
}
}
";
......@@ -2184,11 +2189,13 @@ public void MainLocfuncIsntEntry()
var source = @"
void Main()
{
Console.Write(""bad"");
Console.Write(4);
}
Console.Write(2);
Console.Write(' ');
Main();
";
VerifyOutputInMain(source, "2", "System");
VerifyOutputInMain(source, "2 4", "System");
}
[Fact]
......@@ -2249,6 +2256,7 @@ void Local()
{
Console.WriteLine(2);
}
Local();
}
Local();
......@@ -2261,12 +2269,13 @@ void Local2()
}
";
VerifyDiagnostics(source,
// (15,9): error CS0103: The name 'Local' does not exist in the current context
// (16,9): error CS0103: The name 'Local' does not exist in the current context
// Local();
Diagnostic(ErrorCode.ERR_NameNotInContext, "Local").WithArguments("Local").WithLocation(15, 9),
// (17,9): error CS0841: Cannot use local variable 'Local2' before it is declared
Diagnostic(ErrorCode.ERR_NameNotInContext, "Local").WithArguments("Local").WithLocation(16, 9),
// (18,9): error CS0841: Cannot use local variable 'Local2' before it is declared
// Local2();
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "Local2").WithArguments("Local2").WithLocation(17, 9));
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "Local2").WithArguments("Local2").WithLocation(18, 9)
);
}
[Fact]
......@@ -2279,13 +2288,17 @@ static void Main(string[] args)
{
void Duplicate() { }
void Duplicate() { }
Duplicate();
}
}
";
VerifyDiagnostics(source,
// (7,14): error CS0128: A local variable named 'Duplicate' is already defined in this scope
// void Duplicate() { }
Diagnostic(ErrorCode.ERR_LocalDuplicate, "Duplicate").WithArguments("Duplicate").WithLocation(7, 14)
Diagnostic(ErrorCode.ERR_LocalDuplicate, "Duplicate").WithArguments("Duplicate").WithLocation(7, 14),
// (7,14): warning CS0168: The variable 'Duplicate' is declared but never used
// void Duplicate() { }
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Duplicate").WithArguments("Duplicate").WithLocation(7, 14)
);
}
......@@ -2297,18 +2310,16 @@ class Program
{
static void Main(string[] args)
{
int x;
int x = 2;
void Param(int x) { }
Param(x);
}
}
";
VerifyDiagnostics(source,
// (7,24): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// void Param(int x) { }
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(7, 24),
// (6,13): warning CS0168: The variable 'x' is declared but never used
// int x;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(6, 13)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(7, 24)
);
}
......@@ -2322,6 +2333,7 @@ static void Main(string[] args)
{
int T;
void Generic<T>() { }
Generic<int>();
}
}
";
......@@ -2354,7 +2366,10 @@ static void Main(string[] args)
Diagnostic(ErrorCode.ERR_LocalDuplicate, "Conflict").WithArguments("Conflict").WithLocation(7, 14),
// (6,13): warning CS0168: The variable 'Conflict' is declared but never used
// int Conflict;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(6, 13)
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(6, 13),
// (7,14): warning CS0168: The variable 'Conflict' is declared but never used
// void Conflict() { }
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(7, 14)
);
}
......@@ -2378,7 +2393,10 @@ static void Main(string[] args)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "Conflict").WithArguments("Conflict").WithLocation(6, 14),
// (7,13): warning CS0168: The variable 'Conflict' is declared but never used
// int Conflict;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(7, 13)
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(7, 13),
// (6,14): warning CS0168: The variable 'Conflict' is declared but never used
// void Conflict() { }
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(6, 14)
);
}
......@@ -2676,7 +2694,7 @@ static void Main(string[] args)
);
}
[Fact(Skip = "No usage detection at the moment")]
[Fact]
public void BadNotUsed()
{
var source = @"
......@@ -2693,7 +2711,11 @@ static void Main(string[] args)
A();
}
}";
VerifyDiagnostics(source /*, ... diagnostics ... */);
VerifyDiagnostics(source,
// (6,14): warning CS0168: The variable 'Local' is declared but never used
// void Local()
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Local").WithArguments("Local").WithLocation(6, 14)
);
}
[Fact]
......@@ -2710,6 +2732,7 @@ void Local()
{
Console.WriteLine(x);
}
Local();
}
static void Main()
{
......@@ -2736,6 +2759,7 @@ void Local()
{
Console.WriteLine(__arglist);
}
Local();
}
static void B(__arglist)
{
......@@ -2743,6 +2767,7 @@ void Local()
{
Console.WriteLine(__arglist);
}
Local();
}
static void C() // C and D produce different errors
{
......@@ -2750,6 +2775,7 @@ void Local(__arglist)
{
Console.WriteLine(__arglist);
}
Local(__arglist());
}
static void D(__arglist)
{
......@@ -2757,6 +2783,7 @@ void Local(__arglist)
{
Console.WriteLine(__arglist);
}
Local(__arglist());
}
static void Main()
{
......@@ -2767,15 +2794,15 @@ static void Main()
// (10,31): error CS0190: The __arglist construct is valid only within a variable argument method
// Console.WriteLine(__arglist);
Diagnostic(ErrorCode.ERR_ArgsInvalid, "__arglist").WithLocation(10, 31),
// (17,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method
// (18,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method
// Console.WriteLine(__arglist);
Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(17, 31),
// (24,31): error CS0190: The __arglist construct is valid only within a variable argument method
Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(18, 31),
// (26,31): error CS0190: The __arglist construct is valid only within a variable argument method
// Console.WriteLine(__arglist);
Diagnostic(ErrorCode.ERR_ArgsInvalid, "__arglist").WithLocation(24, 31),
// (31,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method
Diagnostic(ErrorCode.ERR_ArgsInvalid, "__arglist").WithLocation(26, 31),
// (34,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method
// Console.WriteLine(__arglist);
Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(31, 31)
Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(34, 31)
);
}
......@@ -2794,6 +2821,7 @@ void Local()
{
Console.WriteLine(_a);
}
Local();
}
static void Main()
{
......@@ -2821,6 +2849,8 @@ IEnumerable<int> RefEnumerable(ref int x)
{
yield return x;
}
int y = 0;
RefEnumerable(ref y);
}
}
";
......@@ -2835,6 +2865,7 @@ IEnumerable<int> RefEnumerable(ref int x)
public void BadRefAsync()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
......@@ -2845,13 +2876,15 @@ async Task<int> RefAsync(ref int x)
{
return await Task.FromResult(x);
}
int y = 2;
Console.Write(RefAsync(ref y).Result);
}
}
";
VerifyDiagnostics(source,
// (8,42): error CS1988: Async methods cannot have ref or out parameters
// (9,42): error CS1988: Async methods cannot have ref or out parameters
// async Task<int> RefAsync(ref int x)
Diagnostic(ErrorCode.ERR_BadAsyncArgType, "x").WithLocation(8, 42)
Diagnostic(ErrorCode.ERR_BadAsyncArgType, "x").WithLocation(9, 42)
);
}
......@@ -2900,6 +2933,10 @@ static void LocalStatic()
volatile void LocalVolatile()
{
}
LocalConst();
LocalStatic();
LocalReadonly();
LocalVolatile();
}
}
";
......@@ -3069,6 +3106,7 @@ var Local()
{
yield return 2;
}
Local();
}
}
";
......@@ -3091,6 +3129,7 @@ var Local()
{
yield break;
}
Local();
}
}
";
......@@ -3300,6 +3339,7 @@ static void Main(string[] args)
void Local()
{
}
Local();
}
}
";
......
......@@ -42,8 +42,9 @@ internal sealed class CapturedVariableRewriter : BoundTreeRewriter
public override BoundNode VisitBlock(BoundBlock node)
{
var rewrittenLocals = node.Locals.WhereAsArray(local => local.IsCompilerGenerated || local.Name == null || this.GetVariable(local.Name) == null);
var rewrittenLocalFunctions = node.LocalFunctions;
var rewrittenStatements = VisitList(node.Statements);
return node.Update(rewrittenLocals, rewrittenStatements);
return node.Update(rewrittenLocals, rewrittenLocalFunctions, rewrittenStatements);
}
public override BoundNode VisitLocal(BoundLocal node)
......
......@@ -38,7 +38,7 @@ internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymb
if (hasChanged)
{
node = new BoundBlock(node.Syntax, ImmutableArray<LocalSymbol>.Empty, builder.ToImmutable()) { WasCompilerGenerated = true };
node = BoundBlock.SynthesizedNoLocals(node.Syntax, builder.ToImmutable());
}
builder.Free();
......
......@@ -18,6 +18,7 @@ internal EEConstructorSymbol(NamedTypeSymbol containingType)
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
{
var noLocals = ImmutableArray<LocalSymbol>.Empty;
var noLocalFunctions = ImmutableArray<LocalFunctionSymbol>.Empty;
var initializerInvocation = MethodCompiler.BindConstructorInitializer(this, diagnostics, compilationState.Compilation);
var syntax = initializerInvocation.Syntax;
......@@ -25,6 +26,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
new BoundBlock(
syntax,
noLocals,
noLocalFunctions,
ImmutableArray.Create<BoundStatement>(
new BoundExpressionStatement(syntax, initializerInvocation),
new BoundReturnStatement(syntax, null))));
......
......@@ -482,7 +482,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
}
localsSet.Free();
body = new BoundBlock(syntax, localsBuilder.ToImmutableAndFree(), statementsBuilder.ToImmutableAndFree()) { WasCompilerGenerated = true };
body = new BoundBlock(syntax, localsBuilder.ToImmutableAndFree(), ImmutableArray<LocalFunctionSymbol>.Empty, statementsBuilder.ToImmutableAndFree()) { WasCompilerGenerated = true };
Debug.Assert(!diagnostics.HasAnyErrors());
Debug.Assert(!body.HasErrors);
......@@ -600,7 +600,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
localBuilder.Add(local);
}
body = block.Update(localBuilder.ToImmutableAndFree(), block.Statements);
body = block.Update(localBuilder.ToImmutableAndFree(), block.LocalFunctions, block.Statements);
TypeParameterChecker.Check(body, _allTypeParameters);
compilationState.AddSynthesizedMethod(this, body);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册