提交 b043b11b 编写于 作者: A AlekseyTs

Handle Out Variable Declarations in a Script.

Fixes #13450.
Fixes #13590.
上级 3555b2da
......@@ -1401,7 +1401,7 @@ protected virtual BoundExpression BindRangeVariable(SimpleNameSyntax node, Range
return Next.BindRangeVariable(node, qv, diagnostics);
}
private BoundExpression SynthesizeReceiver(SimpleNameSyntax node, Symbol member, DiagnosticBag diagnostics)
private BoundExpression SynthesizeReceiver(CSharpSyntaxNode node, Symbol member, DiagnosticBag diagnostics)
{
// SPEC: Otherwise, if T is the instance type of the immediately enclosing class or
// struct type, if the lookup identifies an instance member, and if the reference occurs
......@@ -2041,44 +2041,83 @@ private BoundExpression BindArgumentValue(DiagnosticBag diagnostics, ArgumentSyn
}
var declarationExpression = (DeclarationExpressionSyntax)argumentSyntax.Expression;
var declaration = (TypedVariableComponentSyntax)declarationExpression.VariableComponent;
var typeSyntax = declaration.Type;
var typeSyntax = declarationExpression.Type();
bool isVar;
// Is this a local?
SourceLocalSymbol localSymbol = this.LookupLocal(declarationExpression.Identifier());
if (InConstructorInitializer || InFieldInitializer)
if ((object)localSymbol != null)
{
Error(diagnostics, ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, declarationExpression);
}
if (InConstructorInitializer || InFieldInitializer)
{
Error(diagnostics, ErrorCode.ERR_ExpressionVariableInConstructorOrFieldInitializer, declarationExpression);
}
bool isConst = false;
bool isVar;
AliasSymbol alias;
TypeSymbol declType = BindVariableType(declarationExpression, diagnostics, typeSyntax, ref isConst, out isVar, out alias);
bool isConst = false;
AliasSymbol alias;
TypeSymbol declType = BindVariableType(declarationExpression, diagnostics, typeSyntax, ref isConst, out isVar, out alias);
SourceLocalSymbol localSymbol = this.LookupLocal(declarationExpression.Identifier());
localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
if ((object)localSymbol == null)
if (isVar)
{
return new OutVariablePendingInference(declarationExpression, localSymbol, null);
}
if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method
&& ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync
&& declType.IsRestrictedType())
{
Error(diagnostics, ErrorCode.ERR_BadSpecialByRefLocal, typeSyntax, declType);
}
return new BoundLocal(declarationExpression, localSymbol, constantValueOpt: null, type: declType);
}
// Is this a field?
SourceMemberFieldSymbolFromDesignation expressionVariableField = LookupDeclaredField(declarationExpression.VariableDesignation());
if ((object)expressionVariableField == null)
{
// We should have the right binder in the chain, cannot continue otherwise.
throw ExceptionUtilities.Unreachable;
}
else
{
localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
}
if (isVar)
BoundExpression receiver = SynthesizeReceiver(declarationExpression.VariableDesignation(), expressionVariableField, diagnostics);
if (typeSyntax.IsVar)
{
return new OutVarLocalPendingInference(declarationExpression, localSymbol);
var ignored = DiagnosticBag.GetInstance();
BindTypeOrAlias(typeSyntax, ignored, out isVar);
ignored.Free();
if (isVar)
{
return new OutVariablePendingInference(declarationExpression, expressionVariableField, receiver);
}
}
if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method
&& ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync
&& declType.IsRestrictedType())
TypeSymbol fieldType = expressionVariableField.GetFieldType(this.FieldsBeingBound);
return new BoundFieldAccess(declarationExpression,
receiver,
expressionVariableField, null, LookupResultKind.Viable, fieldType);
}
internal SourceMemberFieldSymbolFromDesignation LookupDeclaredField(SingleVariableDesignationSyntax variableDesignator)
{
foreach (Symbol member in ContainingType?.GetMembers(variableDesignator.Identifier.ValueText) ?? ImmutableArray<Symbol>.Empty)
{
Error(diagnostics, ErrorCode.ERR_BadSpecialByRefLocal, typeSyntax, declType);
SourceMemberFieldSymbolFromDesignation field;
if (member.Kind == SymbolKind.Field &&
(field = member as SourceMemberFieldSymbolFromDesignation)?.SyntaxTree == variableDesignator.SyntaxTree &&
field.SyntaxNode == variableDesignator)
{
return field;
}
}
return new BoundLocal(declarationExpression, localSymbol, constantValueOpt: null, type: declType);
return null;
}
// Bind a named/positional argument.
......@@ -2231,21 +2270,10 @@ private BoundExpression BindArgumentExpression(DiagnosticBag diagnostics, Expres
arguments[arg] = CreateConversion(argument.Syntax, argument, kind, false, type, diagnostics);
}
else if (argument.Kind == BoundKind.OutVarLocalPendingInference)
else if (argument.Kind == BoundKind.OutVariablePendingInference)
{
TypeSymbol parameterType = GetCorrespondingParameterType(ref result, parameters, arg);
bool hasErrors = false;
if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method
&& ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync
&& parameterType.IsRestrictedType())
{
var declaration = (TypedVariableComponentSyntax)((DeclarationExpressionSyntax)argument.Syntax).VariableComponent;
Error(diagnostics, ErrorCode.ERR_BadSpecialByRefLocal, declaration.Type, parameterType);
hasErrors = true;
}
arguments[arg] = ((OutVarLocalPendingInference)argument).SetInferredType(parameterType, success: !hasErrors);
arguments[arg] = ((OutVariablePendingInference)argument).SetInferredType(parameterType, diagnostics);
}
else if (argument.Kind == BoundKind.OutDeconstructVarPendingInference)
{
......@@ -6065,9 +6093,9 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no
{
Debug.Assert(index != null);
if (index.Kind == BoundKind.OutVarLocalPendingInference)
if (index.Kind == BoundKind.OutVariablePendingInference)
{
return ((OutVarLocalPendingInference)index).FailInference(this, diagnostics);
return ((OutVariablePendingInference)index).FailInference(this, diagnostics);
}
var result =
......
......@@ -252,7 +252,7 @@ internal struct ProcessedFieldInitializers
var fieldsBeingBound = binder.FieldsBeingBound;
var sourceField = fieldSymbol as SourceMemberFieldSymbol;
var sourceField = fieldSymbol as SourceMemberFieldSymbolFromDeclarator;
bool isImplicitlyTypedField = (object)sourceField != null && sourceField.FieldTypeInferred(fieldsBeingBound);
// If the type is implicitly typed, the initializer diagnostics have already been reported, so ignore them here:
......
......@@ -114,7 +114,7 @@ private static ImmutableArray<MethodSymbol> GetOriginalMethods(OverloadResolutio
boundExpression.WasCompilerGenerated = true;
var analyzedArguments = AnalyzedArguments.GetInstance();
Debug.Assert(!args.Any(e => e.Kind == BoundKind.OutVarLocalPendingInference || e.Kind == BoundKind.OutDeconstructVarPendingInference));
Debug.Assert(!args.Any(e => e.Kind == BoundKind.OutVariablePendingInference || e.Kind == BoundKind.OutDeconstructVarPendingInference));
analyzedArguments.Arguments.AddRange(args);
BoundExpression result = BindInvocationExpression(
node, node, methodName, boundExpression, analyzedArguments, diagnostics, queryClause,
......@@ -335,7 +335,7 @@ private ImmutableArray<BoundExpression> BuildArgumentsForDynamicInvocation(Analy
{
Debug.Assert(arguments.Arguments[i].Kind != BoundKind.OutDeconstructVarPendingInference);
if (arguments.Arguments[i].Kind == BoundKind.OutVarLocalPendingInference)
if (arguments.Arguments[i].Kind == BoundKind.OutVariablePendingInference)
{
var builder = ArrayBuilder<BoundExpression>.GetInstance(arguments.Arguments.Count);
builder.AddRange(arguments.Arguments);
......@@ -344,9 +344,9 @@ private ImmutableArray<BoundExpression> BuildArgumentsForDynamicInvocation(Analy
{
BoundExpression argument = builder[i];
if (argument.Kind == BoundKind.OutVarLocalPendingInference)
if (argument.Kind == BoundKind.OutVariablePendingInference)
{
builder[i] = ((OutVarLocalPendingInference)argument).FailInference(this, diagnostics);
builder[i] = ((OutVariablePendingInference)argument).FailInference(this, diagnostics);
}
i++;
......@@ -1148,7 +1148,7 @@ private ImmutableArray<BoundExpression> BuildArgumentsForErrorRecovery(AnalyzedA
private ImmutableArray<BoundExpression> BuildArgumentsForErrorRecovery(AnalyzedArguments analyzedArguments, IEnumerable<ImmutableArray<ParameterSymbol>> parameterListList)
{
// Since the purpose is to bind any unbound lambdas, we return early if there are none.
if (!analyzedArguments.Arguments.Any(e => e.Kind == BoundKind.UnboundLambda || e.Kind == BoundKind.OutVarLocalPendingInference || e.Kind == BoundKind.OutDeconstructVarPendingInference))
if (!analyzedArguments.Arguments.Any(e => e.Kind == BoundKind.UnboundLambda || e.Kind == BoundKind.OutVariablePendingInference || e.Kind == BoundKind.OutDeconstructVarPendingInference))
{
return analyzedArguments.Arguments.ToImmutable();
}
......@@ -1175,7 +1175,7 @@ private ImmutableArray<BoundExpression> BuildArgumentsForErrorRecovery(AnalyzedA
// replace the unbound lambda with its best inferred bound version
newArguments[i] = unboundArgument.BindForErrorRecovery();
}
else if (argument.Kind == BoundKind.OutVarLocalPendingInference)
else if (argument.Kind == BoundKind.OutVariablePendingInference)
{
// See if all applicable applicable parameters have the same type
TypeSymbol candidateType = null;
......@@ -1199,11 +1199,11 @@ private ImmutableArray<BoundExpression> BuildArgumentsForErrorRecovery(AnalyzedA
if ((object)candidateType == null)
{
newArguments[i] = ((OutVarLocalPendingInference)argument).FailInference(this, null);
newArguments[i] = ((OutVariablePendingInference)argument).FailInference(this, null);
}
else
{
newArguments[i] = ((OutVarLocalPendingInference)argument).SetInferredType(candidateType, success: true);
newArguments[i] = ((OutVariablePendingInference)argument).SetInferredType(candidateType, null);
}
}
else if (argument.Kind == BoundKind.OutDeconstructVarPendingInference)
......
......@@ -1867,7 +1867,7 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
Debug.Assert(expr.Syntax.Kind() != SyntaxKind.Argument || valueKind == BindValueKind.RefOrOut);
break;
case BoundKind.OutVarLocalPendingInference:
case BoundKind.OutVariablePendingInference:
case BoundKind.OutDeconstructVarPendingInference:
Debug.Assert(valueKind == BindValueKind.RefOrOut);
return expr;
......
......@@ -10,28 +10,19 @@
namespace Microsoft.CodeAnalysis.CSharp
{
internal class ExpressionVariableFinder : CSharpSyntaxWalker
internal abstract class ExpressionVariableFinder<TFieldOrLocalSymbol> : CSharpSyntaxWalker where TFieldOrLocalSymbol : Symbol
{
private Binder _scopeBinder;
private Binder _enclosingBinder;
private ArrayBuilder<LocalSymbol> _localsBuilder;
private ArrayBuilder<TFieldOrLocalSymbol> _localsBuilder;
private SyntaxNode _nodeToBind;
internal static void FindExpressionVariables(
Binder scopeBinder,
ArrayBuilder<LocalSymbol> builder,
CSharpSyntaxNode node,
Binder enclosingBinderOpt = null)
protected void FindExpressionVariables(
ArrayBuilder<TFieldOrLocalSymbol> builder,
CSharpSyntaxNode node)
{
if (node == null)
{
return;
}
Debug.Assert(node != null);
var finder = s_poolInstance.Allocate();
finder._scopeBinder = scopeBinder;
finder._enclosingBinder = enclosingBinderOpt ?? scopeBinder;
finder._localsBuilder = builder;
ArrayBuilder<TFieldOrLocalSymbol> save = _localsBuilder;
_localsBuilder = builder;
#if DEBUG
// These are all of the kinds of nodes we should need to handle in this class.
......@@ -62,12 +53,9 @@ internal class ExpressionVariableFinder : CSharpSyntaxWalker
}
#endif
finder.VisitNodeToBind(node);
VisitNodeToBind(node);
finder._scopeBinder = null;
finder._enclosingBinder = null;
finder._localsBuilder = null;
s_poolInstance.Free(finder);
_localsBuilder = save;
}
public override void VisitVariableDeclarator(VariableDeclaratorSyntax node)
......@@ -91,30 +79,20 @@ private void VisitNodeToBind(CSharpSyntaxNode node)
_nodeToBind = previousNodeToBind;
}
internal static void FindExpressionVariables(
Binder binder,
ArrayBuilder<LocalSymbol> builder,
protected void FindExpressionVariables(
ArrayBuilder<TFieldOrLocalSymbol> builder,
SeparatedSyntaxList<ExpressionSyntax> nodes)
{
if (nodes.Count == 0)
{
return;
}
var finder = s_poolInstance.Allocate();
finder._scopeBinder = binder;
finder._enclosingBinder = binder;
finder._localsBuilder = builder;
Debug.Assert(nodes.Count > 0);
ArrayBuilder<TFieldOrLocalSymbol> save = _localsBuilder;
_localsBuilder = builder;
foreach (var n in nodes)
{
finder.VisitNodeToBind(n);
VisitNodeToBind(n);
}
finder._scopeBinder = null;
finder._enclosingBinder = null;
finder._localsBuilder = null;
s_poolInstance.Free(finder);
_localsBuilder = save;
}
public override void VisitEqualsValueClause(EqualsValueClauseSyntax node)
......@@ -205,18 +183,12 @@ public override void VisitSwitchStatement(SwitchStatementSyntax node)
public override void VisitDeclarationPattern(DeclarationPatternSyntax node)
{
_localsBuilder.Add(SourceLocalSymbol.MakeLocalSymbolWithEnclosingContext(
_scopeBinder.ContainingMemberOrLambda,
scopeBinder: _scopeBinder,
nodeBinder: _enclosingBinder,
typeSyntax: node.Type,
identifierToken: node.Identifier,
kind: LocalDeclarationKind.PatternVariable,
nodeToBind: _nodeToBind,
forbiddenZone: null));
_localsBuilder.Add(MakePatternVariable(node, _nodeToBind));
base.VisitDeclarationPattern(node);
}
protected abstract TFieldOrLocalSymbol MakePatternVariable(DeclarationPatternSyntax node, SyntaxNode nodeToBind);
public override void VisitParenthesizedLambdaExpression(ParenthesizedLambdaExpressionSyntax node) { }
public override void VisitSimpleLambdaExpression(SimpleLambdaExpressionSyntax node) { }
public override void VisitAnonymousMethodExpression(AnonymousMethodExpressionSyntax node) { }
......@@ -274,15 +246,97 @@ public override void VisitDeclarationExpression(DeclarationExpressionSyntax node
{
var argumentSyntax = (ArgumentSyntax)node?.Parent;
var argumentListSyntax = (BaseArgumentListSyntax)argumentSyntax?.Parent;
_localsBuilder.Add(SourceLocalSymbol.MakeLocalSymbolWithEnclosingContext(
containingSymbol: _scopeBinder.ContainingMemberOrLambda,
scopeBinder: _scopeBinder,
nodeBinder: _enclosingBinder,
typeSyntax: node.Type(),
identifierToken: node.Identifier(),
kind: LocalDeclarationKind.RegularVariable,
nodeToBind: _nodeToBind,
forbiddenZone: argumentListSyntax));
var variable = MakeOutVariable(node, argumentListSyntax, _nodeToBind);
if ((object)variable != null)
{
_localsBuilder.Add(variable);
}
}
protected abstract TFieldOrLocalSymbol MakeOutVariable(DeclarationExpressionSyntax node, BaseArgumentListSyntax argumentListSyntax, SyntaxNode nodeToBind);
}
internal class ExpressionVariableFinder : ExpressionVariableFinder<LocalSymbol>
{
private Binder _scopeBinder;
private Binder _enclosingBinder;
internal static void FindExpressionVariables(
Binder scopeBinder,
ArrayBuilder<LocalSymbol> builder,
CSharpSyntaxNode node,
Binder enclosingBinderOpt = null)
{
if (node == null)
{
return;
}
var finder = s_poolInstance.Allocate();
finder._scopeBinder = scopeBinder;
finder._enclosingBinder = enclosingBinderOpt ?? scopeBinder;
finder.FindExpressionVariables(builder, node);
finder._scopeBinder = null;
finder._enclosingBinder = null;
s_poolInstance.Free(finder);
}
internal static void FindExpressionVariables(
Binder binder,
ArrayBuilder<LocalSymbol> builder,
SeparatedSyntaxList<ExpressionSyntax> nodes)
{
if (nodes.Count == 0)
{
return;
}
var finder = s_poolInstance.Allocate();
finder._scopeBinder = binder;
finder._enclosingBinder = binder;
finder.FindExpressionVariables(builder, nodes);
finder._scopeBinder = null;
finder._enclosingBinder = null;
s_poolInstance.Free(finder);
}
protected override LocalSymbol MakePatternVariable(DeclarationPatternSyntax node, SyntaxNode nodeToBind)
{
return SourceLocalSymbol.MakeLocalSymbolWithEnclosingContext(
_scopeBinder.ContainingMemberOrLambda,
scopeBinder: _scopeBinder,
nodeBinder: _enclosingBinder,
typeSyntax: node.Type,
identifierToken: node.Identifier,
kind: LocalDeclarationKind.PatternVariable,
nodeToBind: nodeToBind,
forbiddenZone: null);
}
protected override LocalSymbol MakeOutVariable(DeclarationExpressionSyntax node, BaseArgumentListSyntax argumentListSyntax, SyntaxNode nodeToBind)
{
NamedTypeSymbol container = _scopeBinder.ContainingType;
if ((object)container != null && container.IsScriptClass &&
(object)_scopeBinder.LookupDeclaredField(node.VariableDesignation()) != null)
{
// This is a field declaration
return null;
}
return SourceLocalSymbol.MakeLocalSymbolWithEnclosingContext(
containingSymbol: _scopeBinder.ContainingMemberOrLambda,
scopeBinder: _scopeBinder,
nodeBinder: _enclosingBinder,
typeSyntax: node.Type(),
identifierToken: node.Identifier(),
kind: LocalDeclarationKind.RegularVariable,
nodeToBind: nodeToBind,
forbiddenZone: argumentListSyntax);
}
#region pool
......@@ -294,4 +348,54 @@ public static ObjectPool<ExpressionVariableFinder> CreatePool()
}
#endregion
}
internal class ExpressionFieldFinder : ExpressionVariableFinder<Symbol>
{
private SourceMemberContainerTypeSymbol _containingType;
private DeclarationModifiers _modifiers;
private FieldSymbol _containingFieldOpt;
internal static void FindExpressionVariables(
ArrayBuilder<Symbol> builder,
CSharpSyntaxNode node,
SourceMemberContainerTypeSymbol containingType,
DeclarationModifiers modifiers,
FieldSymbol containingFieldOpt)
{
if (node == null)
{
return;
}
var finder = s_poolInstance.Allocate();
finder._containingType = containingType;
finder._modifiers = modifiers;
finder._containingFieldOpt = containingFieldOpt;
finder.FindExpressionVariables(builder, node);
finder._containingType = null;
finder._modifiers = DeclarationModifiers.None;
finder._containingFieldOpt = null;
s_poolInstance.Free(finder);
}
protected override Symbol MakePatternVariable(DeclarationPatternSyntax node, SyntaxNode nodeToBind)
{
throw ExceptionUtilities.Unreachable;
}
protected override Symbol MakeOutVariable(DeclarationExpressionSyntax node, BaseArgumentListSyntax argumentListSyntax, SyntaxNode nodeToBind)
{
return SourceMemberFieldSymbolFromDesignation.Create(_containingType, node.VariableDesignation(), _modifiers, _containingFieldOpt, nodeToBind);
}
#region pool
private static readonly ObjectPool<ExpressionFieldFinder> s_poolInstance = CreatePool();
public static ObjectPool<ExpressionFieldFinder> CreatePool()
{
return new ObjectPool<ExpressionFieldFinder>(() => new ExpressionFieldFinder(), 10);
}
#endregion
}
}
......@@ -1229,7 +1229,7 @@ private static TypeSymbol GetParameterType(int argIndex, MemberAnalysisResult re
bool okToDowngradeToNeither;
BetterResult r;
if (argumentKind == BoundKind.OutVarLocalPendingInference || argumentKind == BoundKind.OutDeconstructVarPendingInference)
if (argumentKind == BoundKind.OutVariablePendingInference || argumentKind == BoundKind.OutDeconstructVarPendingInference)
{
// If argument is an out variable that needs type inference,
// neither candidate is better in this argument.
......@@ -2972,7 +2972,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
return Conversion.ImplicitDynamic;
}
if (argument.Kind == BoundKind.OutVarLocalPendingInference || argument.Kind == BoundKind.OutDeconstructVarPendingInference)
if (argument.Kind == BoundKind.OutVariablePendingInference || argument.Kind == BoundKind.OutDeconstructVarPendingInference)
{
Debug.Assert(argRefKind != RefKind.None);
......
......@@ -921,7 +921,7 @@ private static bool HadLambdaConversionError(DiagnosticBag diagnostics, Analyzed
// If the expression is untyped because it is a lambda, anonymous method, method group or null
// then we never want to report the error "you need a ref on that thing". Rather, we want to
// say that you can't convert "null" to "ref int".
if (!argument.HasExpressionType() && argument.Kind != BoundKind.OutDeconstructVarPendingInference && argument.Kind != BoundKind.OutVarLocalPendingInference)
if (!argument.HasExpressionType() && argument.Kind != BoundKind.OutDeconstructVarPendingInference && argument.Kind != BoundKind.OutVariablePendingInference)
{
// If the problem is that a lambda isn't convertible to the given type, also report why.
// The argument and parameter type might match, but may not have same in/out modifiers
......@@ -969,7 +969,7 @@ private static bool HadLambdaConversionError(DiagnosticBag diagnostics, Analyzed
else
{
Debug.Assert(argument.Kind != BoundKind.OutDeconstructVarPendingInference);
Debug.Assert(argument.Kind != BoundKind.OutVarLocalPendingInference);
Debug.Assert(argument.Kind != BoundKind.OutVariablePendingInference);
Debug.Assert(argument.Display != null);
if (arguments.IsExtensionMethodThisArgument(arg))
......
......@@ -1581,11 +1581,14 @@
<Node Name="BoundWildcardPattern" Base="BoundPattern">
</Node>
<!-- The node is transformed into BoundLocal after inference -->
<Node Name="OutVarLocalPendingInference" Base="BoundExpression">
<!-- The node is transformed into BoundLocal or BoundFieldAccess after inference -->
<Node Name="OutVariablePendingInference" Base="BoundExpression">
<!-- Type is not significant for this node type; always null -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="always"/>
<Field Name="LocalSymbol" Type="SourceLocalSymbol"/>
<!-- A local symbol or a field symbol representing the variable -->
<Field Name="VariableSymbol" Type="Symbol"/>
<!-- A field receiver when VariableSymbol is a field -->
<Field Name="ReceiverOpt" Type="BoundExpression" Null="allow"/>
</Node>
<!-- The node is transformed into BoundDeconstructValuePlaceholder after inference -->
......
......@@ -2974,10 +2974,10 @@ public override void Accept(OperationVisitor visitor)
}
/// <summary>
/// This node represents an out var local.
/// This node represents an out variable.
/// It is only used temporarily during initial binding.
/// </summary>
internal partial class OutVarLocalPendingInference
internal partial class OutVariablePendingInference
{
public override void Accept(OperationVisitor visitor)
{
......
......@@ -96,7 +96,7 @@ public override object Display
}
}
internal partial class OutVarLocalPendingInference
internal partial class OutVariablePendingInference
{
public override object Display
{
......
// 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.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class OutVarLocalPendingInference
{
public BoundLocal SetInferredType(TypeSymbol type, bool success)
{
Debug.Assert((object)type != null);
Debug.Assert(this.Syntax.Kind() == SyntaxKind.DeclarationExpression);
this.LocalSymbol.SetType(type);
return new BoundLocal(this.Syntax, this.LocalSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || !success);
}
public BoundLocal FailInference(Binder binder, DiagnosticBag diagnosticsOpt)
{
if (diagnosticsOpt != null)
{
var declaration = (DeclarationExpressionSyntax)this.Syntax;
Binder.Error(
diagnosticsOpt, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedOutVariable, declaration.Identifier(),
declaration.Identifier().ValueText);
}
return this.SetInferredType(binder.CreateErrorType("var"), success: false);
}
}
}
\ No newline at end of file
// 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 Roslyn.Utilities;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class OutVariablePendingInference
{
public BoundExpression SetInferredType(TypeSymbol type, DiagnosticBag diagnosticsOpt)
{
Debug.Assert((object)type != null);
return SetInferredType(type, null, diagnosticsOpt);
}
private BoundExpression SetInferredType(TypeSymbol type, Binder binderOpt, DiagnosticBag diagnosticsOpt)
{
Debug.Assert(binderOpt != null || (object)type != null);
Debug.Assert(this.Syntax.Kind() == SyntaxKind.DeclarationExpression);
bool inferenceFailed = ((object)type == null);
if (inferenceFailed)
{
type = binderOpt.CreateErrorType("var");
}
switch (this.VariableSymbol.Kind)
{
case SymbolKind.Local:
var localSymbol = (SourceLocalSymbol)this.VariableSymbol;
if (diagnosticsOpt != null)
{
if (inferenceFailed)
{
ReportInferenceFailure(diagnosticsOpt);
}
else if (localSymbol.ContainingSymbol.Kind == SymbolKind.Method &&
((MethodSymbol)localSymbol.ContainingSymbol).IsAsync &&
type.IsRestrictedType())
{
var declaration = (TypedVariableComponentSyntax)((DeclarationExpressionSyntax)this.Syntax).VariableComponent;
Binder.Error(diagnosticsOpt, ErrorCode.ERR_BadSpecialByRefLocal, declaration.Type, type);
}
}
localSymbol.SetType(type);
return new BoundLocal(this.Syntax, localSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed);
case SymbolKind.Field:
var fieldSymbol = (SourceMemberFieldSymbolFromDesignation)this.VariableSymbol;
var inferenceDiagnostics = DiagnosticBag.GetInstance();
if (inferenceFailed)
{
ReportInferenceFailure(inferenceDiagnostics);
}
fieldSymbol.SetType(type, inferenceDiagnostics);
inferenceDiagnostics.Free();
return new BoundFieldAccess(this.Syntax,
this.ReceiverOpt,
fieldSymbol, null, LookupResultKind.Viable, type,
this.HasErrors || inferenceFailed);
default:
throw ExceptionUtilities.Unreachable;
}
}
private void ReportInferenceFailure(DiagnosticBag diagnostics)
{
var declaration = (DeclarationExpressionSyntax)this.Syntax;
Binder.Error(
diagnostics, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedOutVariable, declaration.Identifier(),
declaration.Identifier().ValueText);
}
public BoundExpression FailInference(Binder binder, DiagnosticBag diagnosticsOpt)
{
return this.SetInferredType(null, binder, diagnosticsOpt);
}
}
}
\ No newline at end of file
......@@ -201,7 +201,7 @@
<Compile Include="BoundTree\DecisionTree.cs" />
<Compile Include="BoundTree\Expression.cs" />
<Compile Include="BoundTree\DeconstructionLocalPendingInference.cs" />
<Compile Include="BoundTree\OutVarLocalPendingInference.cs" />
<Compile Include="BoundTree\OutVariablePendingInference.cs" />
<Compile Include="BoundTree\OutDeconstructVarPendingInference.cs" />
<Compile Include="BoundTree\PseudoVariableExpressions.cs" />
<Compile Include="BoundTree\Formatting.cs" />
......@@ -524,6 +524,7 @@
<Compile Include="Symbols\AnonymousTypes\SynthesizedSymbols\AnonymousType.ToStringMethodSymbol.cs" />
<Compile Include="Symbols\AnonymousTypes\SynthesizedSymbols\AnonymousType.TypeParameterSymbol.cs" />
<Compile Include="Symbols\Metadata\PE\TupleTypeDecoder.cs" />
<Compile Include="Symbols\Source\SourceMemberFieldSymbolFromDesignation.cs" />
<Compile Include="Symbols\Tuples\TupleEventSymbol.cs" />
<Compile Include="Symbols\Tuples\TupleFieldSymbol.cs" />
<Compile Include="Symbols\Tuples\TupleMethodSymbol.cs" />
......
......@@ -522,11 +522,7 @@ public SymbolInfo GetSymbolInfo(ExpressionSyntax expression, CancellationToken c
// Named arguments handled in special way.
return this.GetNamedArgumentSymbolInfo((IdentifierNameSyntax)expression, cancellationToken);
}
else if (IsOutVarType(expression, out parent))
{
return TypeFromLocal((VariableDeclarationSyntax)parent, cancellationToken);
}
else if (SyntaxFacts.IsDeconstructionType(expression, out parent))
else if (SyntaxFacts.IsVariableComponentType(expression, out parent))
{
var declaration = (TypedVariableComponentSyntax)parent;
if (declaration.Designation.Kind() != SyntaxKind.SingleVariableDesignation)
......@@ -534,59 +530,44 @@ public SymbolInfo GetSymbolInfo(ExpressionSyntax expression, CancellationToken c
return SymbolInfo.None;
}
return TypeFromLocal((SingleVariableDesignationSyntax)declaration.Designation, cancellationToken);
return TypeFromVariable((SingleVariableDesignationSyntax)declaration.Designation, cancellationToken);
}
return this.GetSymbolInfoWorker(expression, SymbolInfoOptions.DefaultOptions, cancellationToken);
}
/// <summary>
/// Given a variable declaration, figure out its type by looking at the declared symbol of the corresponding local.
/// </summary>
private SymbolInfo TypeFromLocal(VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken)
{
TypeSymbol variableType = (GetDeclaredSymbol(variableDeclaration.Variables.First(), cancellationToken) as LocalSymbol)?.Type;
if (variableType?.IsErrorType() == false)
{
return new SymbolInfo(variableType);
}
return SymbolInfo.None;
}
/// <summary>
/// Given a variable designation (typically in the left-hand-side of a deconstruction declaration statement),
/// figure out its type by looking at the declared symbol of the corresponding local.
/// figure out its type by looking at the declared symbol of the corresponding variable.
/// </summary>
private SymbolInfo TypeFromLocal(SingleVariableDesignationSyntax variableDesignation, CancellationToken cancellationToken)
private SymbolInfo TypeFromVariable(SingleVariableDesignationSyntax variableDesignation, CancellationToken cancellationToken)
{
TypeSymbol variableType = (GetDeclaredSymbol(variableDesignation, cancellationToken) as LocalSymbol)?.Type;
var variable = GetDeclaredSymbol(variableDesignation, cancellationToken);
if (variableType?.IsErrorType() == false)
if (variable != null)
{
return new SymbolInfo(variableType);
}
ITypeSymbol variableType;
return SymbolInfo.None;
}
switch (variable.Kind)
{
case SymbolKind.Local:
variableType = ((ILocalSymbol)variable).Type;
break;
case SymbolKind.Field:
variableType = ((IFieldSymbol)variable).Type;
break;
default:
variableType = null;
break;
}
/// <summary>
/// Figures out if this expression is a type in an out-var ArgumentSyntax.
/// Outputs the VariableDeclarationSyntax directly containing it, if that is the case.
/// </summary>
private static bool IsOutVarType(ExpressionSyntax expression, out SyntaxNode parent)
{
parent = null;
var variableDeclaration = expression.Parent as VariableDeclarationSyntax;
var enclosingDeclaration = variableDeclaration?.Parent as DeclarationExpressionSyntax;
if (enclosingDeclaration?.Parent?.Kind() != SyntaxKind.Argument)
{
return false;
if (variableType?.Kind != SymbolKind.ErrorType)
{
return new SymbolInfo(variableType);
}
}
parent = variableDeclaration;
return variableDeclaration.Type == expression;
return SymbolInfo.None;
}
/// <summary>
......
......@@ -1647,7 +1647,16 @@ public override ISymbol GetDeclaredSymbol(SingleVariableDesignationSyntax declar
{
// Might be a local variable.
var memberModel = this.GetMemberModel(declarationSyntax);
return memberModel?.GetDeclaredSymbol(declarationSyntax, cancellationToken);
ISymbol local = memberModel?.GetDeclaredSymbol(declarationSyntax, cancellationToken);
if (local != null)
{
return local;
}
// Might be a field
Binder binder = GetEnclosingBinder(declarationSyntax.Position);
return binder?.LookupDeclaredField(declarationSyntax);
}
/// <summary>
......
......@@ -2642,7 +2642,7 @@ public override BoundNode VisitDeconstructValuePlaceholder(BoundDeconstructValue
return null;
}
public override sealed BoundNode VisitOutVarLocalPendingInference(OutVarLocalPendingInference node)
public override sealed BoundNode VisitOutVariablePendingInference(OutVariablePendingInference node)
{
throw ExceptionUtilities.Unreachable;
}
......@@ -2651,6 +2651,11 @@ public sealed override BoundNode VisitDeconstructionLocalPendingInference(Decons
{
throw ExceptionUtilities.Unreachable;
}
public override BoundNode VisitVoid(BoundVoid node)
{
return null;
}
#endregion visitors
}
}
......@@ -82,7 +82,7 @@ private BoundStatement InstrumentLocalDeclarationIfNecessary(BoundLocalDeclarati
return rewrittenLocalDeclaration;
}
public override sealed BoundNode VisitOutVarLocalPendingInference(OutVarLocalPendingInference node)
public override sealed BoundNode VisitOutVariablePendingInference(OutVariablePendingInference node)
{
throw ExceptionUtilities.Unreachable;
}
......
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
/// <remarks>
/// SourceFieldSymbol takes care of the initializer (plus "var" in the interactive case).
/// </remarks>
internal sealed class SourceEventFieldSymbol : SourceMemberFieldSymbol
internal sealed class SourceEventFieldSymbol : SourceMemberFieldSymbolFromDeclarator
{
private readonly SourceEventSymbol _associatedEvent;
......
......@@ -12,7 +12,7 @@
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal class SourceFixedFieldSymbol : SourceMemberFieldSymbol
internal class SourceFixedFieldSymbol : SourceMemberFieldSymbolFromDeclarator
{
private const int FixedSizeNotInitialized = -1;
......
......@@ -2885,10 +2885,18 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
foreach (var variable in fieldSyntax.Declaration.Variables)
{
var fieldSymbol = (modifiers & DeclarationModifiers.Fixed) == 0
? new SourceMemberFieldSymbol(this, variable, modifiers, modifierErrors, diagnostics)
? new SourceMemberFieldSymbolFromDeclarator(this, variable, modifiers, modifierErrors, diagnostics)
: new SourceFixedFieldSymbol(this, variable, modifiers, modifierErrors, diagnostics);
builder.NonTypeNonIndexerMembers.Add(fieldSymbol);
if (IsScriptClass)
{
// also gather expression-declared variables from the bracketed argument lists and the initializers
ExpressionFieldFinder.FindExpressionVariables(builder.NonTypeNonIndexerMembers, variable, this,
DeclarationModifiers.Private | (modifiers & DeclarationModifiers.Static),
fieldSymbol);
}
if (variable.Initializer != null)
{
if (fieldSymbol.IsStatic)
......@@ -2976,6 +2984,16 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
var initializer = propertySyntax.Initializer;
if (initializer != null)
{
if (IsScriptClass)
{
// also gather expression-declared variables from the initializer
ExpressionFieldFinder.FindExpressionVariables(builder.NonTypeNonIndexerMembers,
initializer,
this,
DeclarationModifiers.Private | (property.IsStatic ? DeclarationModifiers.Static : 0),
property.BackingField);
}
if (property.IsStatic)
{
AddInitializer(ref staticInitializers, ref builder.StaticSyntaxLength, property.BackingField, initializer);
......@@ -3005,6 +3023,15 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
builder.NonTypeNonIndexerMembers.Add(@event);
FieldSymbol associatedField = @event.AssociatedField;
if (IsScriptClass)
{
// also gather expression-declared variables from the bracketed argument lists and the initializers
ExpressionFieldFinder.FindExpressionVariables(builder.NonTypeNonIndexerMembers, declarator, this,
DeclarationModifiers.Private | (@event.IsStatic ? DeclarationModifiers.Static : 0),
associatedField);
}
if ((object)associatedField != null)
{
// NOTE: specifically don't add the associated field to the members list
......@@ -3108,6 +3135,60 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
diagnostics.Add(ErrorCode.ERR_GlobalStatement, new SourceLocation(globalStatement));
}
if (IsScriptClass)
{
var innerStatement = globalStatement;
// drill into any LabeledStatements
while (innerStatement.Kind() == SyntaxKind.LabeledStatement)
{
innerStatement = ((LabeledStatementSyntax)innerStatement).Statement;
}
switch (innerStatement.Kind())
{
case SyntaxKind.DeconstructionDeclarationStatement:
ExpressionFieldFinder.FindExpressionVariables(builder.NonTypeNonIndexerMembers,
((DeconstructionDeclarationStatementSyntax)innerStatement).Assignment.Value,
this,
DeclarationModifiers.Private,
containingFieldOpt: null);
break;
case SyntaxKind.LocalDeclarationStatement:
// We shouldn't reach this place, but field declarations preceded with a label end up here.
// This is tracked by https://github.com/dotnet/roslyn/issues/13712. Let's do our best for now.
var decl = (LocalDeclarationStatementSyntax)innerStatement;
foreach (var vdecl in decl.Declaration.Variables)
{
// also gather expression-declared variables from the bracketed argument lists and the initializers
ExpressionFieldFinder.FindExpressionVariables(builder.NonTypeNonIndexerMembers, vdecl, this, DeclarationModifiers.Private,
containingFieldOpt: null);
}
break;
case SyntaxKind.ExpressionStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.YieldReturnStatement:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ThrowStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.LockStatement:
ExpressionFieldFinder.FindExpressionVariables(builder.NonTypeNonIndexerMembers,
innerStatement,
this,
DeclarationModifiers.Private,
containingFieldOpt: null);
break;
default:
// no other statement introduces variables into the enclosing scope
break;
}
}
AddInitializer(ref instanceInitializers, ref builder.InstanceSyntaxLength, null, globalStatement);
}
break;
......
// 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.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// Represents expression variables declared in a global statement.
/// </summary>
internal class SourceMemberFieldSymbolFromDesignation : SourceMemberFieldSymbol
{
private TypeSymbol _lazyType;
internal SourceMemberFieldSymbolFromDesignation(
SourceMemberContainerTypeSymbol containingType,
SingleVariableDesignationSyntax designation,
DeclarationModifiers modifiers)
: base(containingType, modifiers, designation.Identifier.ValueText, designation.GetReference(), designation.Identifier.GetLocation())
{
Debug.Assert(DeclaredAccessibility == Accessibility.Private);
}
internal static SourceMemberFieldSymbolFromDesignation Create(
SourceMemberContainerTypeSymbol containingType,
SingleVariableDesignationSyntax designation,
DeclarationModifiers modifiers,
FieldSymbol containingFieldOpt,
SyntaxNode nodeToBind)
{
Debug.Assert(nodeToBind.Kind() == SyntaxKind.VariableDeclarator || nodeToBind is ExpressionSyntax);
var typeSyntax = ((TypedVariableComponentSyntax)designation.Parent).Type;
return typeSyntax.IsVar
? new SourceMemberFieldSymbolFromDesignationWithEnclosingContext(containingType, designation, modifiers, containingFieldOpt, nodeToBind)
: new SourceMemberFieldSymbolFromDesignation(containingType, designation, modifiers);
}
protected override SyntaxList<AttributeListSyntax> AttributeDeclarationSyntaxList
{
get
{
return default(SyntaxList<AttributeListSyntax>);
}
}
public SingleVariableDesignationSyntax VariableDesignation
{
get
{
return (SingleVariableDesignationSyntax)this.SyntaxNode;
}
}
protected override TypeSyntax TypeSyntax
{
get
{
return ((TypedVariableComponentSyntax)VariableDesignation.Parent).Type;
}
}
protected override SyntaxTokenList ModifiersTokenList
{
get
{
return default(SyntaxTokenList);
}
}
internal override TypeSymbol GetFieldType(ConsList<FieldSymbol> fieldsBeingBound)
{
Debug.Assert(fieldsBeingBound != null);
if ((object)_lazyType != null)
{
return _lazyType;
}
var designation = VariableDesignation;
var typeSyntax = TypeSyntax;
var compilation = this.DeclaringCompilation;
var diagnostics = DiagnosticBag.GetInstance();
TypeSymbol type;
var binderFactory = compilation.GetBinderFactory(SyntaxTree);
var binder = binderFactory.GetBinder(typeSyntax);
bool isVar;
type = binder.BindType(typeSyntax, diagnostics, out isVar);
Debug.Assert((object)type != null || isVar);
if (isVar && !fieldsBeingBound.ContainsReference(this))
{
InferFieldType(fieldsBeingBound, binder);
Debug.Assert((object)_lazyType != null);
}
else
{
if (isVar)
{
diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this);
type = binder.CreateErrorType("var");
}
SetType(compilation, diagnostics, type);
}
diagnostics.Free();
return _lazyType;
}
/// <summary>
/// Can add some diagnostics into <paramref name="diagnostics"/>.
/// </summary>
private void SetType(CSharpCompilation compilation, DiagnosticBag diagnostics, TypeSymbol type)
{
TypeSymbol originalType = _lazyType;
// In the event that we race to set the type of a field, we should
// always deduce the same type, unless the cached type is an error.
Debug.Assert((object)originalType == null ||
originalType.IsErrorType() ||
originalType == type);
if ((object)Interlocked.CompareExchange(ref _lazyType, type, null) == null)
{
TypeChecks(type, diagnostics);
compilation.DeclarationDiagnostics.AddRange(diagnostics);
state.NotePartComplete(CompletionPart.Type);
}
}
/// <summary>
/// Can add some diagnostics into <paramref name="diagnostics"/>.
/// </summary>
internal void SetType(TypeSymbol type, DiagnosticBag diagnostics)
{
SetType(DeclaringCompilation, diagnostics, type);
}
protected virtual void InferFieldType(ConsList<FieldSymbol> fieldsBeingBound, Binder binder)
{
throw ExceptionUtilities.Unreachable;
}
protected override ConstantValue MakeConstantValue(HashSet<SourceFieldSymbolWithSyntaxReference> dependencies, bool earlyDecodingWellKnownAttributes, DiagnosticBag diagnostics)
{
return null;
}
public override bool HasInitializer
{
get
{
return false;
}
}
private class SourceMemberFieldSymbolFromDesignationWithEnclosingContext : SourceMemberFieldSymbolFromDesignation
{
private readonly FieldSymbol _containingFieldOpt;
private readonly SyntaxReference _nodeToBind;
internal SourceMemberFieldSymbolFromDesignationWithEnclosingContext(
SourceMemberContainerTypeSymbol containingType,
SingleVariableDesignationSyntax designation,
DeclarationModifiers modifiers,
FieldSymbol containingFieldOpt,
SyntaxNode nodeToBind)
: base(containingType, designation, modifiers)
{
Debug.Assert(nodeToBind.Kind() == SyntaxKind.VariableDeclarator || nodeToBind is ExpressionSyntax);
_containingFieldOpt = containingFieldOpt;
_nodeToBind = nodeToBind.GetReference();
}
protected override void InferFieldType(ConsList<FieldSymbol> fieldsBeingBound, Binder binder)
{
var nodeToBind = _nodeToBind.GetSyntax();
if ((object)_containingFieldOpt != null && nodeToBind.Kind() != SyntaxKind.VariableDeclarator)
{
binder = binder.WithContainingMemberOrLambda(_containingFieldOpt).WithAdditionalFlags(BinderFlags.FieldInitializer);
}
fieldsBeingBound = new ConsList<FieldSymbol>(this, fieldsBeingBound);
binder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound);
var diagnostics = DiagnosticBag.GetInstance();
switch (nodeToBind.Kind())
{
case SyntaxKind.VariableDeclarator:
// This occurs, for example, in
// int x, y[out var Z, 1 is int I];
// for (int x, y[out var Z, 1 is int I]; ;) {}
binder.BindDeclaratorArguments((VariableDeclaratorSyntax)nodeToBind, diagnostics);
break;
default:
binder.BindExpression((ExpressionSyntax)nodeToBind, diagnostics);
break;
}
diagnostics.Free();
}
}
}
}
\ No newline at end of file
......@@ -74,6 +74,15 @@ internal static TypeSyntax Type(this DeclarationExpressionSyntax self)
return component.Type;
}
/// <summary>
/// Return the variable designation of an out declaration argument expression.
/// </summary>
internal static SingleVariableDesignationSyntax VariableDesignation(this DeclarationExpressionSyntax self)
{
var component = (TypedVariableComponentSyntax)self.VariableComponent;
return (SingleVariableDesignationSyntax)component.Designation;
}
/// <summary>
/// Return the identifier of an out declaration argument expression.
/// </summary>
......
......@@ -393,7 +393,7 @@ internal static bool IsVarOrPredefinedType(this Syntax.InternalSyntax.SyntaxToke
return node.IsVar() || IsPredefinedType(node.Kind);
}
internal static bool IsDeconstructionType(SyntaxNode node, out SyntaxNode parent)
internal static bool IsVariableComponentType(SyntaxNode node, out SyntaxNode parent)
{
var component = node.Parent as TypedVariableComponentSyntax;
parent = component;
......
......@@ -407,5 +407,27 @@ protected override IEnumerable<int> M()
var comp = CompileAndVerify(source, expectedOutput: "0,1,2,3", options: TestOptions.DebugExe);
comp.Compilation.VerifyDiagnostics();
}
}
[Fact]
[WorkItem(261047, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=261047&_a=edit")]
public void MissingExpression()
{
var text =
@"using System.Collections.Generic;
class Test
{
IEnumerable<int> I()
{
yield return;
}
}";
var comp = CreateCompilationWithMscorlib(text);
comp.VerifyDiagnostics(
// (7,15): error CS1627: Expression expected after yield return
// yield return;
Diagnostic(ErrorCode.ERR_EmptyYield, "return").WithLocation(7, 15)
);
}
}
}
......@@ -1049,6 +1049,7 @@ private static void VerifyModelForDeclarationPattern(SemanticModel model, Declar
{
var symbol = model.GetDeclaredSymbol(decl);
Assert.Equal(decl.Identifier.ValueText, symbol.Name);
Assert.Equal(decl, symbol.DeclaringSyntaxReferences.Single().GetSyntax());
Assert.Equal(LocalDeclarationKind.PatternVariable, ((LocalSymbol)symbol).DeclarationKind);
Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)decl));
......@@ -1063,6 +1064,9 @@ private static void VerifyModelForDeclarationPattern(SemanticModel model, Declar
Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText));
Assert.True(SyntaxFacts.IsInNamespaceOrTypeContext(decl.Type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(decl.Type));
var type = ((LocalSymbol)symbol).Type;
if (!decl.Type.IsVar || !type.IsErrorType())
{
......@@ -1081,6 +1085,7 @@ private static void VerifyModelForDeclarationPatternDuplicateInSameScope(Semanti
{
var symbol = model.GetDeclaredSymbol(decl);
Assert.Equal(decl.Identifier.ValueText, symbol.Name);
Assert.Equal(decl, symbol.DeclaringSyntaxReferences.Single().GetSyntax());
Assert.Equal(LocalDeclarationKind.PatternVariable, ((LocalSymbol)symbol).DeclarationKind);
Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)decl));
Assert.NotEqual(symbol, model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Single());
......@@ -14487,16 +14492,17 @@ private static void VerifyModelNotSupported(SemanticModel model, DeclarationPatt
Assert.Null(model.GetDeclaredSymbol(decl));
Assert.Null(model.GetDeclaredSymbol((SyntaxNode)decl));
Assert.False(model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Any());
Assert.False(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText));
var identifierText = decl.Identifier.ValueText;
Assert.False(model.LookupSymbols(decl.SpanStart, name: identifierText).Any());
Assert.False(model.LookupNames(decl.SpanStart).Contains(identifierText));
Assert.Null(model.GetSymbolInfo(decl.Type).Symbol);
foreach (var reference in references)
{
Assert.Null(model.GetSymbolInfo(reference).Symbol);
Assert.False(model.LookupSymbols(reference.SpanStart, name: decl.Identifier.ValueText).Any());
Assert.False(model.LookupNames(reference.SpanStart).Contains(decl.Identifier.ValueText));
Assert.False(model.LookupSymbols(reference.SpanStart, name: identifierText).Any());
Assert.False(model.LookupNames(reference.SpanStart).Contains(identifierText));
}
}
......
......@@ -911,5 +911,51 @@ public void DefineExtensionMethods()
// error CS1103: The first parameter of an extension method cannot be of type 'dynamic'
Diagnostic(ErrorCode.ERR_BadTypeforThis, "dynamic").WithArguments("dynamic"));
}
[Fact]
[WorkItem(13590, "https://github.com/dotnet/roslyn/issues/13590")]
public void FixedBuffer_01()
{
string source =
@"fixed int x[3];
";
var tree = Parse(source, options: TestOptions.Script);
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics(
// (1,11): error CS1642: Fixed size buffer fields may only be members of structs
// fixed int x[3];
Diagnostic(ErrorCode.ERR_FixedNotInStruct, "x").WithLocation(1, 11),
// (1,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed int x[3];
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x[3]").WithLocation(1, 11)
);
}
[Fact]
[WorkItem(13590, "https://github.com/dotnet/roslyn/issues/13590")]
public void FixedBuffer_02()
{
string source =
@"fixed var x[3] = 1;
";
var tree = Parse(source, options: TestOptions.Script);
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics(
// (1,16): error CS1003: Syntax error, ',' expected
// fixed var x[3] = 1;
Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(",", "=").WithLocation(1, 16),
// (1,11): error CS1642: Fixed size buffer fields may only be members of structs
// fixed var x[3] = 1;
Diagnostic(ErrorCode.ERR_FixedNotInStruct, "x").WithLocation(1, 11),
// (1,7): error CS1663: Fixed size buffer type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double
// fixed var x[3] = 1;
Diagnostic(ErrorCode.ERR_IllegalFixedType, "var").WithLocation(1, 7),
// (1,11): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
// fixed var x[3] = 1;
Diagnostic(ErrorCode.ERR_UnsafeNeeded, "x[3]").WithLocation(1, 11)
);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册