提交 cec7a985 编写于 作者: C Charles Stoner

Allow goto in scripts

上级 42da9bd8
...@@ -764,9 +764,9 @@ private InContainerBinder MakeNamespaceBinder(CSharpSyntaxNode node, NameSyntax ...@@ -764,9 +764,9 @@ private InContainerBinder MakeNamespaceBinder(CSharpSyntaxNode node, NameSyntax
public override Binder VisitCompilationUnit(CompilationUnitSyntax parent) public override Binder VisitCompilationUnit(CompilationUnitSyntax parent)
{ {
return VisitCompilationUnit( return VisitCompilationUnit(
parent, parent,
inUsing: IsInUsing(parent), inUsing: IsInUsing(parent),
inScript: InScript); inScript: InScript);
} }
internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilationUnit, bool inUsing, bool inScript) internal InContainerBinder VisitCompilationUnit(CompilationUnitSyntax compilationUnit, bool inUsing, bool inScript)
......
...@@ -852,8 +852,9 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag ...@@ -852,8 +852,9 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
options |= LookupOptions.MustNotBeMethodTypeParameter; options |= LookupOptions.MustNotBeMethodTypeParameter;
} }
var name = node.Identifier.ValueText;
HashSet<DiagnosticInfo> useSiteDiagnostics = null; HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupSymbolsWithFallback(lookupResult, node.Identifier.ValueText, arity: arity, useSiteDiagnostics: ref useSiteDiagnostics, options: options); this.LookupSymbolsWithFallback(lookupResult, name, arity: arity, useSiteDiagnostics: ref useSiteDiagnostics, options: options);
diagnostics.Add(node, useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics);
if (lookupResult.Kind != LookupResultKind.Empty) if (lookupResult.Kind != LookupResultKind.Empty)
...@@ -862,7 +863,7 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag ...@@ -862,7 +863,7 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
bool isError = false; bool isError = false;
bool wasError; bool wasError;
var members = ArrayBuilder<Symbol>.GetInstance(); var members = ArrayBuilder<Symbol>.GetInstance();
Symbol symbol = GetSymbolOrMethodOrPropertyGroup(lookupResult, node, node.Identifier.ValueText, node.Arity, members, diagnostics, out wasError); // reports diagnostics in result. Symbol symbol = GetSymbolOrMethodOrPropertyGroup(lookupResult, node, name, node.Arity, members, diagnostics, out wasError); // reports diagnostics in result.
isError |= wasError; isError |= wasError;
...@@ -876,7 +877,7 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag ...@@ -876,7 +877,7 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
typeArgumentList, typeArgumentList,
typeArguments, typeArguments,
receiver, receiver,
node.Identifier.ValueText, name,
members, members,
lookupResult, lookupResult,
receiver != null ? BoundMethodGroupFlags.HasImplicitReceiver : BoundMethodGroupFlags.None, receiver != null ? BoundMethodGroupFlags.HasImplicitReceiver : BoundMethodGroupFlags.None,
...@@ -919,15 +920,15 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag ...@@ -919,15 +920,15 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag
} }
else if (IsJoinRangeVariableInLeftKey(node)) else if (IsJoinRangeVariableInLeftKey(node))
{ {
Error(diagnostics, ErrorCode.ERR_QueryOuterKey, node, node.Identifier.ValueText); Error(diagnostics, ErrorCode.ERR_QueryOuterKey, node, name);
} }
else if (IsInJoinRightKey(node)) else if (IsInJoinRightKey(node))
{ {
Error(diagnostics, ErrorCode.ERR_QueryInnerKey, node, node.Identifier.ValueText); Error(diagnostics, ErrorCode.ERR_QueryInnerKey, node, name);
} }
else else
{ {
Error(diagnostics, ErrorCode.ERR_NameNotInContext, node, node.Identifier.ValueText); Error(diagnostics, ErrorCode.ERR_NameNotInContext, node, name);
} }
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
...@@ -106,7 +107,7 @@ internal struct ProcessedFieldInitializers ...@@ -106,7 +107,7 @@ internal struct ProcessedFieldInitializers
firstDebugImports = parentBinder.ImportChain; firstDebugImports = parentBinder.ImportChain;
} }
parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol); parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol);
BoundFieldInitializer boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics); BoundFieldInitializer boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics);
boundInitializers.Add(boundInitializer); boundInitializers.Add(boundInitializer);
...@@ -137,6 +138,8 @@ internal struct ProcessedFieldInitializers ...@@ -137,6 +138,8 @@ internal struct ProcessedFieldInitializers
// factory across siblings. Unfortunately, we cannot reuse the binder itself, because // factory across siblings. Unfortunately, we cannot reuse the binder itself, because
// individual fields might have their own binders (e.g. because of being declared unsafe). // individual fields might have their own binders (e.g. because of being declared unsafe).
BinderFactory binderFactory = null; BinderFactory binderFactory = null;
// Label instances must be shared across all global statements.
ScriptLocalScopeBinder.Labels labels = null;
for (int j = 0; j < siblingInitializers.Length; j++) for (int j = 0; j < siblingInitializers.Length; j++)
{ {
...@@ -150,44 +153,47 @@ internal struct ProcessedFieldInitializers ...@@ -150,44 +153,47 @@ internal struct ProcessedFieldInitializers
} }
var syntaxRef = initializer.Syntax; var syntaxRef = initializer.Syntax;
Debug.Assert(syntaxRef.SyntaxTree.Options.Kind != SourceCodeKind.Regular); var syntaxTree = syntaxRef.SyntaxTree;
Debug.Assert(syntaxTree.Options.Kind != SourceCodeKind.Regular);
var initializerNode = (CSharpSyntaxNode)syntaxRef.GetSyntax(); var syntax = (CSharpSyntaxNode)syntaxRef.GetSyntax();
var syntaxRoot = syntaxTree.GetCompilationUnitRoot();
if (binderFactory == null) if (binderFactory == null)
{ {
binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); binderFactory = compilation.GetBinderFactory(syntaxTree);
labels = new ScriptLocalScopeBinder.Labels(scriptInitializer, syntaxRoot);
} }
Binder scriptClassBinder = binderFactory.GetBinder(initializerNode); Binder scriptClassBinder = binderFactory.GetBinder(syntax);
Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); Debug.Assert(((NamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass);
if (firstDebugImports == null) if (firstDebugImports == null)
{ {
firstDebugImports = scriptClassBinder.ImportChain; firstDebugImports = scriptClassBinder.ImportChain;
} }
Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptInitializer, scriptClassBinder); Binder parentBinder = new ExecutableCodeBinder(
syntaxRoot,
scriptInitializer,
new ScriptLocalScopeBinder(labels, scriptClassBinder));
BoundInitializer boundInitializer; BoundInitializer boundInitializer;
if ((object)fieldSymbol != null) if ((object)fieldSymbol != null)
{ {
boundInitializer = BindFieldInitializer( boundInitializer = BindFieldInitializer(
new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol), parentBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol),
fieldSymbol, fieldSymbol,
(EqualsValueClauseSyntax)initializerNode, (EqualsValueClauseSyntax)syntax,
diagnostics); diagnostics);
} }
else if (initializerNode.Kind() == SyntaxKind.LabeledStatement)
{
// TODO: labels in interactive
var boundStatement = new BoundBadStatement(initializerNode, ImmutableArray<BoundNode>.Empty, true);
boundInitializer = new BoundGlobalStatementInitializer(initializerNode, boundStatement);
}
else else
{ {
var collisionDetector = new LocalScopeBinder(parentBinder); boundInitializer = BindGlobalStatement(
boundInitializer = BindGlobalStatement(collisionDetector, scriptInitializer, (StatementSyntax)initializerNode, diagnostics, parentBinder,
scriptInitializer,
(StatementSyntax)syntax,
diagnostics,
isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1);
} }
......
...@@ -53,31 +53,36 @@ internal void LookupExtensionMethods(LookupResult result, string name, int arity ...@@ -53,31 +53,36 @@ internal void LookupExtensionMethods(LookupResult result, string name, int arity
/// <remarks> /// <remarks>
/// Makes a second attempt if the results are not viable, in order to produce more detailed failure information (symbols and diagnostics). /// Makes a second attempt if the results are not viable, in order to produce more detailed failure information (symbols and diagnostics).
/// </remarks> /// </remarks>
private void LookupSymbolsWithFallback(LookupResult result, string name, int arity, ref HashSet<DiagnosticInfo> useSiteDiagnostics, ConsList<Symbol> basesBeingResolved = null, LookupOptions options = LookupOptions.Default) private Binder LookupSymbolsWithFallback(LookupResult result, string name, int arity, ref HashSet<DiagnosticInfo> useSiteDiagnostics, ConsList<Symbol> basesBeingResolved = null, LookupOptions options = LookupOptions.Default)
{ {
Debug.Assert(options.AreValid()); Debug.Assert(options.AreValid());
// don't create diagnosis instances unless lookup fails // don't create diagnosis instances unless lookup fails
this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics); var binder = this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: false, useSiteDiagnostics: ref useSiteDiagnostics);
Debug.Assert((binder != null) || result.IsClear);
if (result.Kind != LookupResultKind.Viable && result.Kind != LookupResultKind.Empty) if (result.Kind != LookupResultKind.Viable && result.Kind != LookupResultKind.Empty)
{ {
result.Clear(); result.Clear();
// retry to get diagnosis // retry to get diagnosis
this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: true, useSiteDiagnostics: ref useSiteDiagnostics); var otherBinder = this.LookupSymbolsInternal(result, name, arity, basesBeingResolved, options, diagnose: true, useSiteDiagnostics: ref useSiteDiagnostics);
Debug.Assert(binder == otherBinder);
} }
Debug.Assert(result.IsMultiViable || result.IsClear || result.Error != null); Debug.Assert(result.IsMultiViable || result.IsClear || result.Error != null);
return binder;
} }
private void LookupSymbolsInternal( private Binder LookupSymbolsInternal(
LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics) LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{ {
Debug.Assert(result.IsClear); Debug.Assert(result.IsClear);
Debug.Assert(options.AreValid()); Debug.Assert(options.AreValid());
Binder binder = null;
for (var scope = this; scope != null && !result.IsMultiViable; scope = scope.Next) for (var scope = this; scope != null && !result.IsMultiViable; scope = scope.Next)
{ {
if (!result.IsClear) if (binder != null)
{ {
var tmp = LookupResult.GetInstance(); var tmp = LookupResult.GetInstance();
scope.LookupSymbolsInSingleBinder(tmp, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics); scope.LookupSymbolsInSingleBinder(tmp, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics);
...@@ -87,8 +92,13 @@ private void LookupSymbolsWithFallback(LookupResult result, string name, int ari ...@@ -87,8 +92,13 @@ private void LookupSymbolsWithFallback(LookupResult result, string name, int ari
else else
{ {
scope.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics); scope.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, options, this, diagnose, ref useSiteDiagnostics);
if (!result.IsClear)
{
binder = scope;
}
} }
} }
return binder;
} }
internal virtual void LookupSymbolsInSingleBinder( internal virtual void LookupSymbolsInSingleBinder(
......
...@@ -342,7 +342,7 @@ private BoundLabeledStatement BindLabeled(LabeledStatementSyntax node, Diagnosti ...@@ -342,7 +342,7 @@ private BoundLabeledStatement BindLabeled(LabeledStatementSyntax node, Diagnosti
var result = LookupResult.GetInstance(); var result = LookupResult.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null; HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly); var binder = this.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly);
// result.Symbols can be empty in some malformed code, e.g. when a labeled statement is used an embedded statement in an if or foreach statement // result.Symbols can be empty in some malformed code, e.g. when a labeled statement is used an embedded statement in an if or foreach statement
// In this case we create new label symbol on the fly, and an error is reported by parser // In this case we create new label symbol on the fly, and an error is reported by parser
...@@ -357,14 +357,18 @@ private BoundLabeledStatement BindLabeled(LabeledStatementSyntax node, Diagnosti ...@@ -357,14 +357,18 @@ private BoundLabeledStatement BindLabeled(LabeledStatementSyntax node, Diagnosti
} }
// check to see if this label (illegally) hides a label from an enclosing scope // check to see if this label (illegally) hides a label from an enclosing scope
result.Clear(); if (binder != null)
this.Next.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly);
if (result.IsMultiViable)
{ {
// The label '{0}' shadows another label by the same name in a contained scope result.Clear();
Error(diagnostics, ErrorCode.ERR_LabelShadow, node.Identifier, node.Identifier.ValueText); binder.Next.LookupSymbolsWithFallback(result, node.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.LabelsOnly);
hasError = true; if (result.IsMultiViable)
{
// The label '{0}' shadows another label by the same name in a contained scope
Error(diagnostics, ErrorCode.ERR_LabelShadow, node.Identifier, node.Identifier.ValueText);
hasError = true;
}
} }
diagnostics.Add(node, useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics);
result.Free(); result.Free();
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics; using System.Diagnostics;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities; using Roslyn.Utilities;
......
...@@ -159,22 +159,25 @@ protected SourceLocalSymbol MakeLocal(VariableDeclarationSyntax declaration, Var ...@@ -159,22 +159,25 @@ protected SourceLocalSymbol MakeLocal(VariableDeclarationSyntax declaration, Var
protected void BuildLabels(SyntaxList<StatementSyntax> statements, ref ArrayBuilder<LabelSymbol> labels) protected void BuildLabels(SyntaxList<StatementSyntax> statements, ref ArrayBuilder<LabelSymbol> labels)
{ {
var containingMethod = (MethodSymbol)this.ContainingMemberOrLambda; var containingMethod = (MethodSymbol)this.ContainingMemberOrLambda;
foreach (var statement in statements) foreach (var statement in statements)
{ {
var stmt = statement; BuildLabels(containingMethod, statement, ref labels);
while (stmt.Kind() == SyntaxKind.LabeledStatement) }
{ }
var labeledStatement = (LabeledStatementSyntax)stmt;
if (labels == null)
{
labels = ArrayBuilder<LabelSymbol>.GetInstance();
}
var labelSymbol = new SourceLabelSymbol(containingMethod, labeledStatement.Identifier); internal static void BuildLabels(MethodSymbol containingMethod, StatementSyntax statement, ref ArrayBuilder<LabelSymbol> labels)
labels.Add(labelSymbol); {
stmt = labeledStatement.Statement; while (statement.Kind() == SyntaxKind.LabeledStatement)
{
var labeledStatement = (LabeledStatementSyntax)statement;
if (labels == null)
{
labels = ArrayBuilder<LabelSymbol>.GetInstance();
} }
var labelSymbol = new SourceLabelSymbol(containingMethod, labeledStatement.Identifier);
labels.Add(labelSymbol);
statement = labeledStatement.Statement;
} }
} }
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp namespace Microsoft.CodeAnalysis.CSharp
{ {
internal class NameofBinder : Binder internal sealed class NameofBinder : Binder
{ {
private readonly SyntaxNode _nameofArgument; private readonly SyntaxNode _nameofArgument;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class ScriptLocalScopeBinder : LocalScopeBinder
{
private readonly Labels _labels;
internal ScriptLocalScopeBinder(Labels labels, Binder next) : base(next)
{
_labels = labels;
}
internal override Symbol ContainingMemberOrLambda
{
get { return _labels.ScriptInitializer; }
}
protected override ImmutableArray<LabelSymbol> BuildLabels()
{
return _labels.GetLabels();
}
// Labels potentially shared across multiple ScriptLocalScopeBinder instances.
new internal sealed class Labels
{
private readonly SynthesizedInteractiveInitializerMethod _scriptInitializer;
private readonly CompilationUnitSyntax _syntax;
private ImmutableArray<LabelSymbol> _lazyLabels;
internal Labels(SynthesizedInteractiveInitializerMethod scriptInitializer, CompilationUnitSyntax syntax)
{
_scriptInitializer = scriptInitializer;
_syntax = syntax;
}
internal SynthesizedInteractiveInitializerMethod ScriptInitializer
{
get { return _scriptInitializer; }
}
internal ImmutableArray<LabelSymbol> GetLabels()
{
if (_lazyLabels == null)
{
ImmutableInterlocked.InterlockedInitialize(ref _lazyLabels, GetLabels(_scriptInitializer, _syntax));
}
return _lazyLabels;
}
private static ImmutableArray<LabelSymbol> GetLabels(SynthesizedInteractiveInitializerMethod scriptInitializer, CompilationUnitSyntax syntax)
{
var builder = ArrayBuilder<LabelSymbol>.GetInstance();
foreach (var member in syntax.Members)
{
if (member.Kind() != SyntaxKind.GlobalStatement)
{
continue;
}
LocalScopeBinder.BuildLabels(scriptInitializer, ((GlobalStatementSyntax)member).Statement, ref builder);
}
return builder.ToImmutableAndFree();
}
}
}
}
...@@ -141,6 +141,7 @@ ...@@ -141,6 +141,7 @@
<Compile Include="Binder\MethodGroupResolution.cs" /> <Compile Include="Binder\MethodGroupResolution.cs" />
<Compile Include="Binder\NameofBinder.cs" /> <Compile Include="Binder\NameofBinder.cs" />
<Compile Include="Binder\NamespaceOrTypeAndUsingDirective.cs" /> <Compile Include="Binder\NamespaceOrTypeAndUsingDirective.cs" />
<Compile Include="Binder\ScriptLocalScopeBinder.cs" />
<Compile Include="Binder\Semantics\AccessCheck.cs" /> <Compile Include="Binder\Semantics\AccessCheck.cs" />
<Compile Include="Binder\Semantics\BestTypeInferrer.cs" /> <Compile Include="Binder\Semantics\BestTypeInferrer.cs" />
<Compile Include="Binder\Semantics\Conversions\BestIndex.cs" /> <Compile Include="Binder\Semantics\Conversions\BestIndex.cs" />
......
...@@ -1368,10 +1368,11 @@ private void CheckModelAndSyntaxNodeToSpeculate(CSharpSyntaxNode syntax) ...@@ -1368,10 +1368,11 @@ private void CheckModelAndSyntaxNodeToSpeculate(CSharpSyntaxNode syntax)
container = baseType; container = baseType;
} }
if (!binder.IsInMethodBody && (options & LookupOptions.NamespacesOrTypesOnly) == 0) if (!binder.IsInMethodBody &&
(options & (LookupOptions.NamespaceAliasesOnly | LookupOptions.NamespacesOrTypesOnly | LookupOptions.LabelsOnly)) == 0)
{ {
// Method type parameters are not in scope outside a method body unless // Method type parameters are not in scope outside a method
// the position is either: // body unless the position is either:
// a) in a type-only context inside an expression, or // a) in a type-only context inside an expression, or
// b) inside of an XML name attribute in an XML doc comment. // b) inside of an XML name attribute in an XML doc comment.
var parentExpr = token.Parent as ExpressionSyntax; var parentExpr = token.Parent as ExpressionSyntax;
......
...@@ -9,15 +9,13 @@ namespace Microsoft.CodeAnalysis.CSharp ...@@ -9,15 +9,13 @@ namespace Microsoft.CodeAnalysis.CSharp
{ {
internal sealed class MethodBodySemanticModel : MemberSemanticModel internal sealed class MethodBodySemanticModel : MemberSemanticModel
{ {
private DiagnosticBag _ignoredDiagnostics = new DiagnosticBag();
private MethodBodySemanticModel(CSharpCompilation compilation, Symbol owner, Binder rootBinder, CSharpSyntaxNode syntax, SyntaxTreeSemanticModel parentSemanticModelOpt = null, int speculatedPosition = 0) private MethodBodySemanticModel(CSharpCompilation compilation, Symbol owner, Binder rootBinder, CSharpSyntaxNode syntax, SyntaxTreeSemanticModel parentSemanticModelOpt = null, int speculatedPosition = 0)
: base(compilation, syntax, owner, rootBinder, parentSemanticModelOpt, speculatedPosition) : base(compilation, syntax, owner, rootBinder, parentSemanticModelOpt, speculatedPosition)
{ {
Debug.Assert((object)owner != null); Debug.Assert((object)owner != null);
Debug.Assert(owner.Kind == SymbolKind.Method); Debug.Assert(owner.Kind == SymbolKind.Method);
Debug.Assert(syntax != null); Debug.Assert(syntax != null);
Debug.Assert(owner.ContainingType.IsScriptClass || syntax.Kind() != SyntaxKind.CompilationUnit); Debug.Assert(syntax.Kind() != SyntaxKind.CompilationUnit);
} }
/// <summary> /// <summary>
...@@ -29,16 +27,6 @@ internal static MethodBodySemanticModel Create(CSharpCompilation compilation, Me ...@@ -29,16 +27,6 @@ internal static MethodBodySemanticModel Create(CSharpCompilation compilation, Me
return new MethodBodySemanticModel(compilation, owner, executableCodeBinder, syntax); return new MethodBodySemanticModel(compilation, owner, executableCodeBinder, syntax);
} }
/// <summary>
/// Creates a SemanticModel for an ArrowExpressionClause, which includes
/// an ExecutableCodeBinder and a ScopedExpressionBinder.
/// </summary>
internal static MethodBodySemanticModel Create(CSharpCompilation compilation, MethodSymbol owner, Binder rootBinder, ArrowExpressionClauseSyntax syntax)
{
Binder binder = new ExecutableCodeBinder(syntax, owner, rootBinder);
return new MethodBodySemanticModel(compilation, owner, binder, syntax);
}
internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics) internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics)
{ {
if (node.Kind() == SyntaxKind.ArrowExpressionClause) if (node.Kind() == SyntaxKind.ArrowExpressionClause)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
...@@ -26,6 +25,7 @@ internal partial class SyntaxTreeSemanticModel : CSharpSemanticModel ...@@ -26,6 +25,7 @@ internal partial class SyntaxTreeSemanticModel : CSharpSemanticModel
private readonly BinderFactory _binderFactory; private readonly BinderFactory _binderFactory;
private Func<CSharpSyntaxNode, MemberSemanticModel> _createMemberModelFunction; private Func<CSharpSyntaxNode, MemberSemanticModel> _createMemberModelFunction;
private readonly bool _ignoresAccessibility; private readonly bool _ignoresAccessibility;
private ScriptLocalScopeBinder.Labels _globalStatementLabels;
private static readonly Func<CSharpSyntaxNode, bool> s_isMemberDeclarationFunction = IsMemberDeclaration; private static readonly Func<CSharpSyntaxNode, bool> s_isMemberDeclarationFunction = IsMemberDeclaration;
...@@ -979,14 +979,27 @@ private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node) ...@@ -979,14 +979,27 @@ private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node)
case SyntaxKind.GlobalStatement: case SyntaxKind.GlobalStatement:
{ {
Debug.Assert(!this.IsRegularCSharp); Debug.Assert(!this.IsRegularCSharp);
var parent = node.Parent;
// TODO (tomat): handle misplaced global statements // TODO (tomat): handle misplaced global statements
if (node.Parent.Kind() == SyntaxKind.CompilationUnit) if (parent.Kind() == SyntaxKind.CompilationUnit)
{ {
var scriptConstructor = this.Compilation.ScriptClass.InstanceConstructors.First(); var scriptInitializer = _compilation.ScriptClass.GetScriptInitializer();
Debug.Assert((object)scriptInitializer != null);
if ((object)scriptInitializer == null)
{
return null;
}
// Share labels across all global statements.
if (_globalStatementLabels == null)
{
Interlocked.CompareExchange(ref _globalStatementLabels, new ScriptLocalScopeBinder.Labels(scriptInitializer, (CompilationUnitSyntax)parent), null);
}
return MethodBodySemanticModel.Create( return MethodBodySemanticModel.Create(
this.Compilation, this.Compilation,
scriptConstructor, scriptInitializer,
outer, new ScriptLocalScopeBinder(_globalStatementLabels, outer),
node); node);
} }
} }
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics; using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp namespace Microsoft.CodeAnalysis.CSharp
{ {
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities; using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit; using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{ {
public class GotoStatementTest : EmitMetadataTestBase public class GotoTests : EmitMetadataTestBase
{ {
[Fact] [Fact]
public void Goto() public void Goto()
...@@ -804,34 +805,256 @@ public static int Main() ...@@ -804,34 +805,256 @@ public static int Main()
CompileAndVerify(text, expectedOutput: "Catch"); CompileAndVerify(text, expectedOutput: "Catch");
} }
[Fact(Skip = "3712"), WorkItem(3712)] [Fact]
public void Goto_Script() public void OutOfScriptBlock()
{ {
string source = @" string source =
using System; @"bool b = true;
L0: ;
{
{
System.Console.WriteLine(b);
if (b) b = !b;
else goto L1;
goto L0;
}
L1: ;
}";
string expectedOutput =
@"True
False";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: false);
}
Console.WriteLine(""a""); [Fact]
goto C; public void IntoScriptBlock()
Console.Write(""you won't see me""); {
C: Console.WriteLine(""b""); string source =
"; @"goto L0;
string expectedOutput = @"a {
b L0: goto L1;
"; }
CompileAndVerify(source, parseOptions: new CSharpParseOptions(kind: SourceCodeKind.Script), expectedOutput: expectedOutput); {
L1: ;
}";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
// (1,6): error CS0159: No such label 'L0' within the scope of the goto statement
// goto L0;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L0").WithArguments("L0").WithLocation(1, 6),
// (3,14): error CS0159: No such label 'L1' within the scope of the goto statement
// L0: goto L1;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L1").WithArguments("L1").WithLocation(3, 14),
// (3,5): warning CS0164: This label has not been referenced
// L0: goto L1;
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L0").WithLocation(3, 5),
// (6,5): warning CS0164: This label has not been referenced
// L1: ;
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L1").WithLocation(6, 5));
}
[Fact]
public void AcrossScriptDeclarations()
{
string source =
@"int P { get; } = G(""P"");
L:
int F = G(""F"");
int Q { get; } = G(""Q"");
static int x = 2;
static int G(string s)
{
System.Console.WriteLine(""{0}: {1}"", x, s);
x++;
return x;
}
if (Q < 4) goto L;";
string expectedOutput =
@"2: P
3: F
4: Q";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: false);
}
[Fact]
public void AcrossSubmissions()
{
var references = new[] { MscorlibRef_v4_0_30316_17626, SystemCoreRef };
var source0 =
@"bool b = false;
L: ;
if (b)
{
goto L;
}";
var source1 =
@"goto L;";
var s0 = CSharpCompilation.CreateScriptCompilation("s0.dll", SyntaxFactory.ParseSyntaxTree(source0, options: TestOptions.Script), references);
s0.VerifyDiagnostics();
var s1 = CSharpCompilation.CreateScriptCompilation("s1.dll", SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.Script), references, previousScriptCompilation: s0);
s1.VerifyDiagnostics(
// (1,6): error CS0159: No such label 'L' within the scope of the goto statement
// goto L;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L").WithArguments("L").WithLocation(1, 6));
}
[Fact]
public void OutOfScriptMethod()
{
string source =
@"static void F(bool b)
{
if (b) goto L;
}
L:
F(true);";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script);
compilation.VerifyDiagnostics(
// (5,1): warning CS0164: This label has not been referenced
// L:
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L").WithLocation(5, 1),
// (3,17): error CS0159: No such label 'L' within the scope of the goto statement
// if (b) goto L;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L").WithArguments("L").WithLocation(3, 17));
}
[Fact]
public void IntoScriptMethod()
{
string source =
@"static void F()
{
L:
return;
}
goto L;";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script);
compilation.VerifyDiagnostics(
// (6,6): error CS0159: No such label 'L' within the scope of the goto statement
// goto L;
Diagnostic(ErrorCode.ERR_LabelNotFound, "L").WithArguments("L").WithLocation(6, 6),
// (3,1): warning CS0164: This label has not been referenced
// L:
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "L").WithLocation(3, 1));
}
[Fact]
public void InScriptSwitch()
{
string source =
@"int x = 3;
switch (x)
{
case 1:
break;
case 2:
System.Console.WriteLine(x);
break;
default:
goto case 2;
}";
string expectedOutput =
@"3";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: false);
}
[Fact]
public void DuplicateLabelInScript()
{
string source =
@"bool b = false;
L: ;
if (b)
{
goto L;
}
else
{
b = !b;
if (b) goto L;
L: ;
}";
var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
// (11,1): error CS0158: The label 'L' shadows another label by the same name in a contained scope
// L: ;
Diagnostic(ErrorCode.ERR_LabelShadow, "L").WithArguments("L").WithLocation(11, 1));
}
[Fact]
public void DuplicateLabelInSeparateSubmissions()
{
var references = new[] { MscorlibRef_v4_0_30316_17626, SystemCoreRef };
var source0 =
@"bool b = false;
L: ;
if (b)
{
goto L;
}";
var source1 =
@"if (!b)
{
b = !b;
if (b) goto L;
L: ;
}";
var s0 = CSharpCompilation.CreateScriptCompilation("s0.dll", SyntaxFactory.ParseSyntaxTree(source0, options: TestOptions.Script), references);
s0.VerifyDiagnostics();
var s1 = CSharpCompilation.CreateScriptCompilation("s1.dll", SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.Script), references, previousScriptCompilation: s0);
s1.VerifyDiagnostics();
}
[Fact]
public void LoadedFile()
{
var sourceA =
@"goto A;
A: goto B;";
var sourceB =
@"#load ""a.csx""
goto B;
B: goto A;";
var resolver = TestSourceReferenceResolver.Create(KeyValuePair.Create("a.csx", sourceA));
var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver);
var compilation = CreateCompilationWithMscorlib45(sourceB, options: options, parseOptions: TestOptions.Script);
compilation.GetDiagnostics().Verify(
// a.csx(2,9): error CS0159: No such label 'B' within the scope of the goto statement
// A: goto B;
Diagnostic(ErrorCode.ERR_LabelNotFound, "B").WithArguments("B").WithLocation(2, 9),
// (3,9): error CS0159: No such label 'A' within the scope of the goto statement
// B: goto A;
Diagnostic(ErrorCode.ERR_LabelNotFound, "A").WithArguments("A").WithLocation(3, 9));
}
[Fact, WorkItem(3712)]
public void Label_GetDeclaredSymbol_Script()
{
string source =
@"L0: goto L1;
static void F() { }
L1: goto L0;";
var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var label = (LabeledStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LabeledStatement);
var symbol = model.GetDeclaredSymbol(label);
Assert.Equal("L0", symbol.Name);
} }
[Fact(Skip = "3712"), WorkItem(3712)] [Fact, WorkItem(3712)]
public void Label_GetDeclaredSymbol_Error_Script() public void Label_GetDeclaredSymbol_Error_Script()
{ {
string source = @" string source = @"
C: \a\b\ C: \a\b\
"; ";
var tree = Parse(source, options: new CSharpParseOptions(kind: SourceCodeKind.Script)); var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var label = (LabeledStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LabeledStatement); var label = (LabeledStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LabeledStatement);
var symbol = model.GetDeclaredSymbol(label); var symbol = model.GetDeclaredSymbol(label);
// TODO: Add some verification for symbol... Assert.Equal("C", symbol.Name);
} }
} }
} }
...@@ -298,6 +298,38 @@ public void LabelLookup() ...@@ -298,6 +298,38 @@ public void LabelLookup()
Assert.Empty(model.LookupLabels(source.Length - 1)); // Used to assert. Assert.Empty(model.LookupLabels(source.Length - 1)); // Used to assert.
} }
[Fact]
public void Labels()
{
string source =
@"L0: ;
goto L0;";
var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var root = tree.GetCompilationUnitRoot();
var statements = root.ChildNodes().Select(n => ((GlobalStatementSyntax)n).Statement).ToArray();
var symbol0 = model.GetDeclaredSymbol((LabeledStatementSyntax)statements[0]);
Assert.NotNull(symbol0);
var symbol1 = model.GetSymbolInfo(((GotoStatementSyntax)statements[1]).Expression).Symbol;
Assert.Same(symbol0, symbol1);
}
[Fact]
public void Variables()
{
string source =
@"int x = 1;
object y = x;";
var tree = Parse(source, options: TestOptions.Script);
var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false);
var root = tree.GetCompilationUnitRoot();
var declarations = root.ChildNodes().Select(n => ((FieldDeclarationSyntax)n).Declaration.Variables[0]).ToArray();
var symbol0 = model.GetDeclaredSymbol(declarations[0]);
Assert.NotNull(symbol0);
var symbol1 = model.GetSymbolInfo(declarations[1].Initializer.Value).Symbol;
Assert.Same(symbol0, symbol1);
}
[WorkItem(543890)] [WorkItem(543890)]
[Fact] [Fact]
public void ThisIndexerAccessInSubmission() public void ThisIndexerAccessInSubmission()
......
...@@ -2115,7 +2115,7 @@ static int Main() ...@@ -2115,7 +2115,7 @@ static int Main()
} }
[Fact] [Fact]
public void SwitchFallOut_Script1() public void SwitchFallOut_Script()
{ {
var source = var source =
@"using System; @"using System;
...@@ -2137,7 +2137,7 @@ public void SwitchFallOut_Script1() ...@@ -2137,7 +2137,7 @@ public void SwitchFallOut_Script1()
} }
[Fact] [Fact]
public void SwitchFallOut_Script2() public void SwitchFallOut_Submission()
{ {
var source = var source =
@"using System; @"using System;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Xunit;
using Roslyn.Test.Utilities; using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{ {
...@@ -39,8 +39,8 @@ public void MissingFile() ...@@ -39,8 +39,8 @@ public void MissingFile()
public void FileWithErrors() public void FileWithErrors()
{ {
var code = "#load \"a.csx\""; var code = "#load \"a.csx\"";
var resolver = CreateResolver( var resolver = TestSourceReferenceResolver.Create(
Script("a.csx", @" KeyValuePair.Create("a.csx", @"
#load ""b.csx"" #load ""b.csx""
asdf();")); asdf();"));
var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver); var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver);
...@@ -72,20 +72,5 @@ public void NoSourceReferenceResolver() ...@@ -72,20 +72,5 @@ public void NoSourceReferenceResolver()
// #load "test" // #load "test"
Diagnostic(ErrorCode.ERR_SourceFileReferencesNotSupported, @"#load ""test""").WithLocation(1, 1)); Diagnostic(ErrorCode.ERR_SourceFileReferencesNotSupported, @"#load ""test""").WithLocation(1, 1));
} }
private static SourceReferenceResolver CreateResolver(params KeyValuePair<string, string>[] scripts)
{
var sources = new Dictionary<string, string>();
foreach (var script in scripts)
{
sources.Add(script.Key, script.Value);
}
return TestSourceReferenceResolver.Create(sources);
}
private static KeyValuePair<string, string> Script(string path, string source)
{
return new KeyValuePair<string, string>(path, source);
}
} }
} }
...@@ -398,6 +398,20 @@ System.Console.Write("complete") ...@@ -398,6 +398,20 @@ System.Console.Write("complete")
}") }")
End Sub End Sub
<Fact>
Public Sub ScriptEntryPoint_MissingMethods()
Dim comp = CreateCompilationWithMscorlib(
<compilation>
<file name="a.vbx"><![CDATA[
System.Console.WriteLine(1)
]]></file>
</compilation>,
parseOptions:=TestOptions.Script,
options:=TestOptions.DebugExe)
comp.VerifyDiagnostics(
Diagnostic(ERRID.ERR_MissingRuntimeHelper).WithArguments("Task.GetAwaiter").WithLocation(1, 1))
End Sub
End Class End Class
End Namespace End Namespace
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
...@@ -12,6 +13,11 @@ public sealed class TestSourceReferenceResolver : SourceReferenceResolver ...@@ -12,6 +13,11 @@ public sealed class TestSourceReferenceResolver : SourceReferenceResolver
{ {
public static readonly SourceReferenceResolver Default = new TestSourceReferenceResolver(sources: null); public static readonly SourceReferenceResolver Default = new TestSourceReferenceResolver(sources: null);
public static SourceReferenceResolver Create(params KeyValuePair<string, string>[] sources)
{
return TestSourceReferenceResolver.Create(sources.ToDictionary(p => p.Key, p => p.Value));
}
public static SourceReferenceResolver Create(Dictionary<string, string> sources = null) public static SourceReferenceResolver Create(Dictionary<string, string> sources = null)
{ {
return (sources == null || sources.Count == 0) ? Default : new TestSourceReferenceResolver(sources); return (sources == null || sources.Count == 0) ? Default : new TestSourceReferenceResolver(sources);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册