提交 e6b6fce3 编写于 作者: N Neal Gafter

Merge with parent

上级 2ccf5f85
......@@ -772,24 +772,10 @@ internal Binder[] GetAllBinders()
}
#endif
internal void BuildAndAddPatternVariables(
ArrayBuilder<LocalSymbol> builder,
CSharpSyntaxNode node = null,
ImmutableArray<CSharpSyntaxNode> nodes = default(ImmutableArray<CSharpSyntaxNode>))
{
var patterns = ArrayBuilder<DeclarationPatternSyntax>.GetInstance();
PatternVariableFinder.FindPatternVariables(patterns, node, nodes);
foreach (var pattern in patterns)
{
builder.Add(SourceLocalSymbol.MakeLocal(ContainingMemberOrLambda, this, RefKind.None, pattern.Type, pattern.Identifier, LocalDeclarationKind.PatternVariable));
}
patterns.Free();
}
internal BoundExpression WrapWithVariablesIfAny(CSharpSyntaxNode scopeDesignator, BoundExpression expression)
{
var locals = this.GetDeclaredLocalsForScope(scopeDesignator);
return (locals.Length == 0)
return (locals.IsEmpty)
? expression
: new BoundSequence(scopeDesignator, locals, ImmutableArray<BoundExpression>.Empty, expression, expression.Type) { WasCompilerGenerated = true };
}
......
......@@ -2588,12 +2588,37 @@ private bool IsOperatorErrors(CSharpSyntaxNode node, TypeSymbol operandType, Bou
private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBag diagnostics)
{
var resultType = (TypeSymbol)GetSpecialType(SpecialType.System_Boolean, diagnostics, node);
var operand = BindValue(node.Left, diagnostics, BindValueKind.RValue);
AliasSymbol alias;
TypeSymbol targetType = BindType(node.Right, diagnostics, out alias);
TypeSymbol targetType;
{
// try binding as a type, but back off to binding as an expression if that does not work.
var tempBag = DiagnosticBag.GetInstance();
targetType = BindType(node.Right, tempBag, out alias);
if (targetType?.IsErrorType() == true && tempBag.HasAnyResolvedErrors() &&
((CSharpParseOptions)node.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeaturePatternMatching))
{
// it did not bind as a type; try binding as a constant expression pattern
bool wasExpression;
var tempBag2 = DiagnosticBag.GetInstance();
var boundConstantPattern = BindConstantPattern(
node, operand, operand.Type, node.Right, node.Right.HasErrors, tempBag2, out wasExpression, wasSwitch: false);
if (wasExpression)
{
tempBag.Free();
diagnostics.AddRangeAndFree(tempBag2);
return new BoundIsPatternExpression(node, operand, boundConstantPattern, resultType);
}
tempBag2.Free();
}
diagnostics.AddRangeAndFree(tempBag);
}
var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
var targetTypeKind = targetType.TypeKind;
var resultType = (TypeSymbol)GetSpecialType(SpecialType.System_Boolean, diagnostics, node);
if (IsOperandErrors(node, operand, diagnostics) || IsOperatorErrors(node, operand.Type, typeExpression, diagnostics))
{
return new BoundIsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
......
......@@ -25,7 +25,8 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,
BoundExpression operand,
TypeSymbol operandType,
bool hasErrors,
DiagnosticBag diagnostics)
DiagnosticBag diagnostics,
bool wasSwitch = false)
{
switch (node.Kind())
{
......@@ -35,7 +36,7 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,
case SyntaxKind.ConstantPattern:
return BindConstantPattern(
(ConstantPatternSyntax)node, operand, operandType, hasErrors, diagnostics);
(ConstantPatternSyntax)node, operand, operandType, hasErrors, diagnostics, wasSwitch);
case SyntaxKind.PropertyPattern:
return BindPropertyPattern(
......@@ -522,30 +523,34 @@ private bool ApplicableOperatorIs(MethodSymbol candidate, CSharpSyntaxNode node,
BoundExpression operand,
TypeSymbol operandType,
bool hasErrors,
DiagnosticBag diagnostics)
DiagnosticBag diagnostics,
bool wasSwitch = false)
{
var expression = BindPatternConstant(node.Expression, diagnostics);
// PROTOTYPE(patterns): we still need to check that the constant is valid for the given operand or operandType.
return new BoundConstantPattern(node, expression, hasErrors);
bool wasExpression;
return BindConstantPattern(node, operand, operandType, node.Expression, hasErrors, diagnostics, out wasExpression, wasSwitch);
}
internal BoundExpression BindPatternConstant(ExpressionSyntax expression, DiagnosticBag diagnostics)
internal BoundPattern BindConstantPattern(
CSharpSyntaxNode node,
BoundExpression left,
TypeSymbol leftType,
ExpressionSyntax right,
bool hasErrors,
DiagnosticBag diagnostics,
out bool wasExpression,
bool wasSwitch)
{
var result = BindValue(expression, diagnostics, BindValueKind.RValue);
if ((object)result.Type == null && result.ConstantValue?.IsNull == true)
{
// until we've implemeneted covnersions for the case expressions, ensure each has a type.
result = CreateConversion(result, GetSpecialType(SpecialType.System_Object, diagnostics, expression), diagnostics);
}
if (!result.HasAnyErrors && result.ConstantValue == null)
var expression = BindValue(right, diagnostics, BindValueKind.RValue);
wasExpression = expression.Type?.IsErrorType() != true;
if (!node.HasErrors && expression.ConstantValue == null)
{
diagnostics.Add(ErrorCode.ERR_ConstantExpected, expression.Location);
diagnostics.Add(ErrorCode.ERR_ConstantExpected, right.Location);
hasErrors = true;
}
return result;
// PROTOTYPE(patterns): we still need to check that the constant is valid for the given operand or operandType.
// PROTOTYPE(patterns): How that works may depend on the parameter wasSwich.
return new BoundConstantPattern(node, expression, hasErrors);
}
private bool CheckValidPatternType(
......
......@@ -453,7 +453,6 @@ private BoundStatement BindLocalFunctionStatementParts(LocalFunctionStatementSyn
hasErrors |= this.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
}
// Binder could be null in error scenarios (as above)
BoundBlock block;
if (node.Body != null)
{
......
......@@ -31,7 +31,7 @@ override protected ImmutableArray<LocalSymbol> BuildLocals()
if (_syntax.Filter != null)
{
BuildAndAddPatternVariables(locals, _syntax.Filter.FilterExpression);
PatternVariableFinder.FindPatternVariables(this, locals, _syntax.Filter.FilterExpression);
}
return locals.ToImmutableAndFree();
......
......@@ -32,7 +32,7 @@ override protected ImmutableArray<LocalSymbol> BuildLocals()
if (declarator.Initializer != null)
{
BuildAndAddPatternVariables(locals, declarator.Initializer.Value);
PatternVariableFinder.FindPatternVariables(this, locals, declarator.Initializer.Value);
}
}
......
......@@ -39,21 +39,21 @@ override protected ImmutableArray<LocalSymbol> BuildLocals()
if (variable.Initializer != null)
{
BuildAndAddPatternVariables(locals, variable.Initializer.Value);
PatternVariableFinder.FindPatternVariables(this, locals, variable.Initializer.Value);
}
}
}
else
{
BuildAndAddPatternVariables(locals, nodes:_syntax.Initializers.ToImmutableArray<CSharpSyntaxNode>());
PatternVariableFinder.FindPatternVariables(this, locals, _syntax.Initializers);
}
if (_syntax.Condition != null)
{
BuildAndAddPatternVariables(locals, node: _syntax.Condition);
PatternVariableFinder.FindPatternVariables(this, locals, node: _syntax.Condition);
}
BuildAndAddPatternVariables(locals, nodes: _syntax.Incrementors.ToImmutableArray<CSharpSyntaxNode>());
PatternVariableFinder.FindPatternVariables(this, locals, _syntax.Incrementors);
return locals.ToImmutableAndFree();
}
......
......@@ -55,7 +55,7 @@ private void Visit(CSharpSyntaxNode syntax, Binder enclosing)
if (syntax is ExpressionSyntax)
{
var binder = new PatternVariableBinder(syntax, (ExpressionSyntax)syntax, enclosing);
var binder = new PatternVariableBinder(syntax, enclosing);
builder.AddToMap(syntax, binder);
builder.Visit(syntax, binder);
}
......@@ -145,7 +145,7 @@ private void VisitLambdaExpression(LambdaExpressionSyntax node)
}
else
{
var binder = new PatternVariableBinder(body, (ExpressionSyntax)body, _enclosing);
var binder = new PatternVariableBinder(body, _enclosing);
AddToMap(body, binder);
Visit(body, binder);
}
......@@ -227,14 +227,14 @@ public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax no
public override void VisitArrowExpressionClause(ArrowExpressionClauseSyntax node)
{
var arrowBinder = new PatternVariableBinder(node, node.Expression, _enclosing);
var arrowBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, arrowBinder);
Visit(node.Expression, arrowBinder);
}
public override void VisitEqualsValueClause(EqualsValueClauseSyntax node)
{
var valueBinder = new PatternVariableBinder(node, node.Value, _enclosing);
var valueBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, valueBinder);
Visit(node.Value, valueBinder);
}
......@@ -258,7 +258,8 @@ public override void VisitArgumentList(ArgumentListSyntax node)
if (_root == node)
{
// We are supposed to get here only for constructor initializers
var argBinder = new PatternVariableBinder(node, node.Arguments, _enclosing);
Debug.Assert(node.Parent is ConstructorInitializerSyntax);
var argBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, argBinder);
foreach (var arg in node.Arguments)
......@@ -337,7 +338,7 @@ public override void VisitUsingStatement(UsingStatementSyntax node)
public override void VisitWhileStatement(WhileStatementSyntax node)
{
Debug.Assert((object)_containingMemberOrLambda == _enclosing.ContainingMemberOrLambda);
var patternBinder = new PatternVariableBinder(node, node.Condition, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
var whileBinder = new WhileBinder(patternBinder, node);
AddToMap(node, whileBinder);
......@@ -348,7 +349,7 @@ public override void VisitWhileStatement(WhileStatementSyntax node)
public override void VisitDoStatement(DoStatementSyntax node)
{
Debug.Assert((object)_containingMemberOrLambda == _enclosing.ContainingMemberOrLambda);
var patternBinder = new PatternVariableBinder(node, node.Condition, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
var whileBinder = new WhileBinder(patternBinder, node);
AddToMap(node, whileBinder);
......@@ -397,7 +398,7 @@ public override void VisitForStatement(ForStatementSyntax node)
public override void VisitForEachStatement(ForEachStatementSyntax node)
{
Debug.Assert((object)_containingMemberOrLambda == _enclosing.ContainingMemberOrLambda);
var patternBinder = new PatternVariableBinder(node.Expression, node.Expression, _enclosing);
var patternBinder = new PatternVariableBinder(node.Expression, _enclosing);
AddToMap(node.Expression, patternBinder);
Visit(node.Expression, patternBinder);
......@@ -446,7 +447,7 @@ public override void VisitFixedStatement(FixedStatementSyntax node)
public override void VisitLockStatement(LockStatementSyntax node)
{
var patternBinder = new PatternVariableBinder(node, node.Expression, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
var lockBinder = new LockBinder(patternBinder, node);
AddToMap(node, lockBinder);
......@@ -465,7 +466,7 @@ public override void VisitLockStatement(LockStatementSyntax node)
public override void VisitSwitchStatement(SwitchStatementSyntax node)
{
Debug.Assert((object)_containingMemberOrLambda == _enclosing.ContainingMemberOrLambda);
var patternBinder = new PatternVariableBinder(node.Expression, node.Expression, _enclosing);
var patternBinder = new PatternVariableBinder(node.Expression, _enclosing);
AddToMap(node.Expression, patternBinder);
Visit(node.Expression, patternBinder);
......@@ -505,7 +506,7 @@ public override void VisitSwitchSection(SwitchSectionSyntax node)
public override void VisitIfStatement(IfStatementSyntax node)
{
var ifBinder = new PatternVariableBinder(node.Condition, node.Condition, _enclosing);
var ifBinder = new PatternVariableBinder(node.Condition, _enclosing);
AddToMap(node.Condition, ifBinder);
Visit(node.Condition, ifBinder);
VisitPossibleEmbeddedStatement(node.Statement, ifBinder);
......@@ -519,7 +520,7 @@ public override void VisitLetStatement(LetStatementSyntax node)
{
// Note that we do *not* include variables defined in a let statement's pattern in the let statement's scope.
// Those are instead included in the enclosing scope.
var letBinder = new PatternVariableBinder(node, ImmutableArray.Create(node.Expression, node.WhenClause?.Condition), _enclosing);
var letBinder = new PatternVariableBinder(node, _enclosing);
Visit(node.Expression, letBinder);
if (node.WhenClause != null)
......@@ -616,7 +617,7 @@ public override void VisitYieldStatement(YieldStatementSyntax node)
{
if (node.Expression != null)
{
var patternBinder = new PatternVariableBinder(node, node.Expression, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, patternBinder);
Visit(node.Expression, patternBinder);
}
......@@ -626,14 +627,14 @@ public override void VisitYieldStatement(YieldStatementSyntax node)
public override void VisitExpressionStatement(ExpressionStatementSyntax node)
{
var patternBinder = new PatternVariableBinder(node, node.Expression, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, patternBinder);
Visit(node.Expression, patternBinder);
}
public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
{
var patternBinder = new PatternVariableBinder(node, node.Declaration.Variables, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, patternBinder);
foreach (var decl in node.Declaration.Variables)
......@@ -650,7 +651,7 @@ public override void VisitReturnStatement(ReturnStatementSyntax node)
{
if (node.Expression != null)
{
var patternBinder = new PatternVariableBinder(node, node.Expression, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, patternBinder);
Visit(node.Expression, patternBinder);
}
......@@ -660,7 +661,7 @@ public override void VisitThrowStatement(ThrowStatementSyntax node)
{
if (node.Expression != null)
{
var patternBinder = new PatternVariableBinder(node, node.Expression, _enclosing);
var patternBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, patternBinder);
Visit(node.Expression, patternBinder);
}
......@@ -726,7 +727,7 @@ private void AddToMap(CSharpSyntaxNode node, Binder binder)
// rather than add, semantics.
Binder existing;
// Note that a lock statement has two outer binders (a second one for pattern variable scope)
Debug.Assert(!_map.TryGetValue(node, out existing) || existing == binder.Next || existing == binder.Next?.Next);
Debug.Assert(!_map.TryGetValue(node, out existing) || existing == binder || existing == binder.Next || existing == binder.Next?.Next);
_map[node] = binder;
}
......
......@@ -183,7 +183,7 @@ protected ImmutableArray<LocalSymbol> BuildLocals(SyntaxList<StatementSyntax> st
if (decl.Pattern != null)
{
// Patterns from the let statement introduce bindings into the enclosing scope.
BuildAndAddPatternVariables(locals, decl.Pattern);
PatternVariableFinder.FindPatternVariables(this, locals, decl.Pattern);
}
else
{
......
......@@ -11,96 +11,17 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class PatternVariableBinder : LocalScopeBinder
{
private readonly CSharpSyntaxNode _node;
private readonly ImmutableArray<CSharpSyntaxNode> _nodes;
public readonly CSharpSyntaxNode ScopeDesignator;
internal PatternVariableBinder(CSharpSyntaxNode scopeDesignator, ImmutableArray<ExpressionSyntax> expressions, Binder next) : base(next)
internal PatternVariableBinder(CSharpSyntaxNode scopeDesignator, Binder next) : base(next)
{
this.ScopeDesignator = scopeDesignator;
this._nodes = StaticCast<CSharpSyntaxNode>.From(expressions);
}
internal PatternVariableBinder(CSharpSyntaxNode scopeDesignator, IEnumerable<VariableDeclaratorSyntax> declarations, Binder next) : base(next)
{
this.ScopeDesignator = scopeDesignator;
var nodes = ArrayBuilder<CSharpSyntaxNode>.GetInstance();
foreach (var decl in declarations)
{
var value = decl.Initializer?.Value;
if (value != null) nodes.Add(value);
}
this._nodes = nodes.ToImmutableAndFree();
}
internal PatternVariableBinder(CSharpSyntaxNode scopeDesignator, IEnumerable<ArgumentSyntax> arguments, Binder next) : base(next)
{
this.ScopeDesignator = scopeDesignator;
var nodes = ArrayBuilder<CSharpSyntaxNode>.GetInstance();
foreach (var arg in arguments)
{
var value = arg.Expression;
if (value != null) nodes.Add(value);
}
this._nodes = nodes.ToImmutableAndFree();
}
internal PatternVariableBinder(SwitchSectionSyntax scopeDesignator, Binder next) : base(next)
{
this.ScopeDesignator = scopeDesignator;
var nodes = ArrayBuilder<CSharpSyntaxNode>.GetInstance();
foreach (var label in scopeDesignator.Labels)
{
var match = label as CasePatternSwitchLabelSyntax;
if (match != null)
{
nodes.Add(match.Pattern);
if (match.WhenClause != null)
{
nodes.Add(match.WhenClause.Condition);
}
}
}
this._nodes = nodes.ToImmutableAndFree();
}
internal PatternVariableBinder(MatchSectionSyntax scopeDesignator, Binder next) : base(next)
{
this.ScopeDesignator = scopeDesignator;
this._nodes = scopeDesignator.WhenClause != null
? ImmutableArray.Create<CSharpSyntaxNode>(scopeDesignator.Pattern, scopeDesignator.WhenClause.Condition, scopeDesignator.Expression)
: ImmutableArray.Create<CSharpSyntaxNode>(scopeDesignator.Pattern, scopeDesignator.Expression)
;
}
internal PatternVariableBinder(CSharpSyntaxNode scopeDesignator, ExpressionSyntax expression, Binder next) : base(next)
{
this._node = expression;
this.ScopeDesignator = scopeDesignator;
}
internal PatternVariableBinder(AttributeSyntax scopeDesignator, Binder next) : base(next)
{
this.ScopeDesignator = scopeDesignator;
if (scopeDesignator.ArgumentList?.Arguments.Count > 0)
{
var expressions = ArrayBuilder<CSharpSyntaxNode>.GetInstance(scopeDesignator.ArgumentList.Arguments.Count);
foreach (var argument in scopeDesignator.ArgumentList.Arguments)
{
expressions.Add(argument.Expression);
}
this._nodes = expressions.ToImmutableAndFree();
}
}
protected override ImmutableArray<LocalSymbol> BuildLocals()
{
var builder = ArrayBuilder<LocalSymbol>.GetInstance();
BuildAndAddPatternVariables(builder, _node, _nodes);
PatternVariableFinder.FindPatternVariables(this, builder, ScopeDesignator);
return builder.ToImmutableAndFree();
}
......
......@@ -12,31 +12,102 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal class PatternVariableFinder : CSharpSyntaxWalker
{
private ArrayBuilder<DeclarationPatternSyntax> _declarationPatterns;
private Binder _binder;
private ArrayBuilder<LocalSymbol> _declarationPatterns;
internal static void FindPatternVariables(
ArrayBuilder<DeclarationPatternSyntax> builder,
CSharpSyntaxNode node = null,
ImmutableArray<CSharpSyntaxNode> nodes = default(ImmutableArray<CSharpSyntaxNode>))
Binder binder,
ArrayBuilder<LocalSymbol> builder,
CSharpSyntaxNode node)
{
if (node == null)
{
return;
}
var finder = s_poolInstance.Allocate();
finder._binder = binder;
finder._declarationPatterns = builder;
finder.Visit(node);
if (!nodes.IsDefaultOrEmpty)
finder._binder = null;
finder._declarationPatterns = null;
s_poolInstance.Free(finder);
}
internal static void FindPatternVariables(
Binder binder,
ArrayBuilder<LocalSymbol> builder,
SeparatedSyntaxList<ExpressionSyntax> nodes)
{
if (nodes.Count == 0)
{
foreach (var n in nodes)
{
finder.Visit(n);
}
return;
}
var finder = s_poolInstance.Allocate();
finder._binder = binder;
finder._declarationPatterns = builder;
foreach (var n in nodes)
{
finder.Visit(n);
}
finder._binder = null;
finder._declarationPatterns = null;
s_poolInstance.Free(finder);
}
public override void VisitLetStatement(LetStatementSyntax node)
{
Visit(node.Expression);
Visit(node.WhenClause?.Condition);
}
public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
{
foreach (var decl in node.Declaration.Variables)
{
Visit(decl.Initializer?.Value);
}
}
public override void VisitSwitchSection(SwitchSectionSyntax node)
{
foreach (var label in node.Labels)
{
var match = label as CasePatternSwitchLabelSyntax;
if (match != null)
{
Visit(match.Pattern);
if (match.WhenClause != null)
{
Visit(match.WhenClause.Condition);
}
}
}
}
public override void VisitWhileStatement(WhileStatementSyntax node)
{
Visit(node.Condition);
}
public override void VisitDoStatement(DoStatementSyntax node)
{
Visit(node.Condition);
}
public override void VisitLockStatement(LockStatementSyntax node)
{
Visit(node.Expression);
}
public override void VisitDeclarationPattern(DeclarationPatternSyntax node)
{
_declarationPatterns.Add(node);
_declarationPatterns.Add(SourceLocalSymbol.MakeLocal(_binder.ContainingMemberOrLambda, _binder, RefKind.None, node.Type, node.Identifier, LocalDeclarationKind.PatternVariable));
base.VisitDeclarationPattern(node);
}
public override void VisitParenthesizedLambdaExpression(ParenthesizedLambdaExpressionSyntax node) { }
......
......@@ -71,16 +71,15 @@ private static BoundPatternSwitchLabel BindPatternSwitchSectionLabel(Binder sect
{
var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node;
return new BoundPatternSwitchLabel(node,
sectionBinder.BindPattern(matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics),
sectionBinder.BindPattern(matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitch: true),
matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null, node.HasErrors);
}
case SyntaxKind.CaseSwitchLabel:
{
var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
var boundLabelExpression = sectionBinder.BindPatternConstant(caseLabelSyntax.Value, diagnostics);
var pattern = new BoundConstantPattern(node, boundLabelExpression, node.HasErrors);
// PROTOTYPE(patterns): still need to check compatibility of the bound switch expression with the label
bool wasExpression;
var pattern = sectionBinder.BindConstantPattern(node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitch: true);
return new BoundPatternSwitchLabel(node, pattern, null, node.HasErrors);
}
......@@ -92,6 +91,7 @@ private static BoundPatternSwitchLabel BindPatternSwitchSectionLabel(Binder sect
{
diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, "default");
}
defaultLabel = defaultLabelSyntax;
return new BoundPatternSwitchLabel(node, pattern, null, node.HasErrors); // note that this is semantically last!
}
......
......@@ -30,7 +30,7 @@ override protected ImmutableArray<LocalSymbol> BuildLocals()
if (expressionSyntax != null)
{
var locals = ArrayBuilder<LocalSymbol>.GetInstance();
BuildAndAddPatternVariables(locals, expressionSyntax);
PatternVariableFinder.FindPatternVariables(this, locals, expressionSyntax);
return locals.ToImmutableAndFree();
}
else
......@@ -42,7 +42,7 @@ override protected ImmutableArray<LocalSymbol> BuildLocals()
if (declarator.Initializer != null)
{
BuildAndAddPatternVariables(locals, declarator.Initializer.Value);
PatternVariableFinder.FindPatternVariables(this, locals, declarator.Initializer.Value);
}
}
......
......@@ -65,8 +65,8 @@ private CSharpSyntaxNode ParseTypeOrPattern()
if (node == null)
{
Debug.Assert(Precedence.Shift == Precedence.Relational + 1);
if (IsExpectedBinaryOperator(tk) && GetPrecedence(SyntaxFacts.GetBinaryExpression(tk)) > Precedence.Relational ||
tk == SyntaxKind.DotToken)
if ((IsExpectedBinaryOperator(tk) && GetPrecedence(SyntaxFacts.GetBinaryExpression(tk)) > Precedence.Relational) ||
tk == SyntaxKind.DotToken) // member selection is not formally a binary operator but has higher precedence than relational
{
this.Reset(ref resetPoint);
// We parse a shift-expression ONLY (nothing looser) - i.e. not a relational expression
......
......@@ -72,6 +72,7 @@ internal static bool CanHaveAssociatedLocalBinder(this CSharpSyntaxNode syntax)
kind == SyntaxKind.ArgumentList ||
kind == SyntaxKind.ArrowExpressionClause ||
(syntax is ExpressionSyntax &&
// All these nodes are valid scope designators due to the pattern matching feature.
((syntax.Parent as LambdaExpressionSyntax)?.Body == syntax ||
(syntax.Parent as SwitchStatementSyntax)?.Expression == syntax ||
(syntax.Parent as ForEachStatementSyntax)?.Expression == syntax ||
......
......@@ -5371,6 +5371,32 @@ static bool Dummy(int x)
True");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/10487"), WorkItem(10487, "https://github.com/dotnet/roslyn/issues/10487")]
public void FieldInitializers_03()
{
var source =
@"
public class X
{
public static void Main()
{
System.Console.WriteLine(Test1);
}
static bool Test1 = 1 is int x1 && Dummy(() => x1);
static bool Dummy(System.Func<int> x)
{
System.Console.WriteLine(x());
return true;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
CompileAndVerify(compilation, expectedOutput: @"1
True");
}
[Fact]
public void ScopeOfPatternVariables_FieldInitializers_01()
{
......@@ -7658,57 +7684,69 @@ void Test16(int val)
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
compilation.VerifyDiagnostics(
// (19,15): error CS0103: The name 'x1' does not exist in the current context
// Dummy(x1, 1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(19, 15),
// (27,26): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// switch (4 is var x4 ? x4 : 0)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x4").WithArguments("x4").WithLocation(27, 26),
// (37,26): error CS0136: A local or parameter named 'x5' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// switch (5 is var x5 ? x5 : 0)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x5").WithArguments("x5").WithLocation(37, 26),
// (47,17): error CS0841: Cannot use local variable 'x6' before it is declared
// switch (x6 + 6 is var x6 ? x6 : 0)
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x6").WithArguments("x6").WithLocation(47, 17),
// (60,21): error CS0136: A local or parameter named 'x7' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// var x7 = 12;
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x7").WithArguments("x7").WithLocation(60, 21),
// (72,34): error CS0136: A local or parameter named 'x9' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// switch (9 is var x9 ? x9 : 0)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x9").WithArguments("x9").WithLocation(72, 34),
// (85,17): error CS0103: The name 'y10' does not exist in the current context
// switch (y10 + 10 is var x10 ? x10 : 0)
Diagnostic(ErrorCode.ERR_NameNotInContext, "y10").WithArguments("y10").WithLocation(85, 17),
// (87,25): error CS0841: Cannot use local variable 'y10' before it is declared
// case 0 when y10:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y10").WithArguments("y10").WithLocation(87, 25),
// (89,18): error CS0841: Cannot use local variable 'y10' before it is declared
// case y10:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y10").WithArguments("y10").WithLocation(89, 18),
// (98,17): error CS0103: The name 'y11' does not exist in the current context
// switch (y11 + 11 is var x11 ? x11 : 0)
Diagnostic(ErrorCode.ERR_NameNotInContext, "y11").WithArguments("y11").WithLocation(98, 17),
// (100,25): error CS0841: Cannot use local variable 'y11' before it is declared
// case 0 when y11 > 0:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y11").WithArguments("y11").WithLocation(100, 25),
// (102,18): error CS0841: Cannot use local variable 'y11' before it is declared
// case y11:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y11").WithArguments("y11").WithLocation(102, 18),
// (112,28): error CS0128: A local variable named 'x14' is already defined in this scope
// 2 is var x14,
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x14").WithArguments("x14").WithLocation(112, 28),
// (125,25): error CS0841: Cannot use local variable 'y15' before it is declared
// case 0 when y15 > 0:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y15").WithArguments("y15").WithLocation(125, 25),
// (127,18): error CS0841: Cannot use local variable 'y15' before it is declared
// case y15:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y15").WithArguments("y15").WithLocation(127, 18),
// (138,25): error CS0841: Cannot use local variable 'y16' before it is declared
// case 0 when y16 > 0:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y16").WithArguments("y16").WithLocation(138, 25),
// (140,18): error CS0841: Cannot use local variable 'y16' before it is declared
// case y16:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y16").WithArguments("y16").WithLocation(140, 18)
// (19,15): error CS0103: The name 'x1' does not exist in the current context
// Dummy(x1, 1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(19, 15),
// (27,26): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// switch (4 is var x4 ? x4 : 0)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x4").WithArguments("x4").WithLocation(27, 26),
// (37,26): error CS0136: A local or parameter named 'x5' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// switch (5 is var x5 ? x5 : 0)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x5").WithArguments("x5").WithLocation(37, 26),
// (47,17): error CS0841: Cannot use local variable 'x6' before it is declared
// switch (x6 + 6 is var x6 ? x6 : 0)
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x6").WithArguments("x6").WithLocation(47, 17),
// (60,21): error CS0136: A local or parameter named 'x7' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// var x7 = 12;
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x7").WithArguments("x7").WithLocation(60, 21),
// (72,34): error CS0136: A local or parameter named 'x9' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// switch (9 is var x9 ? x9 : 0)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x9").WithArguments("x9").WithLocation(72, 34),
// (85,17): error CS0103: The name 'y10' does not exist in the current context
// switch (y10 + 10 is var x10 ? x10 : 0)
Diagnostic(ErrorCode.ERR_NameNotInContext, "y10").WithArguments("y10").WithLocation(85, 17),
// (87,25): error CS0841: Cannot use local variable 'y10' before it is declared
// case 0 when y10:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y10").WithArguments("y10").WithLocation(87, 25),
// (89,18): error CS0841: Cannot use local variable 'y10' before it is declared
// case y10:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y10").WithArguments("y10").WithLocation(89, 18),
// (89,18): error CS0150: A constant value is expected
// case y10:
Diagnostic(ErrorCode.ERR_ConstantExpected, "y10").WithLocation(89, 18),
// (98,17): error CS0103: The name 'y11' does not exist in the current context
// switch (y11 + 11 is var x11 ? x11 : 0)
Diagnostic(ErrorCode.ERR_NameNotInContext, "y11").WithArguments("y11").WithLocation(98, 17),
// (100,25): error CS0841: Cannot use local variable 'y11' before it is declared
// case 0 when y11 > 0:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y11").WithArguments("y11").WithLocation(100, 25),
// (102,18): error CS0841: Cannot use local variable 'y11' before it is declared
// case y11:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y11").WithArguments("y11").WithLocation(102, 18),
// (102,18): error CS0150: A constant value is expected
// case y11:
Diagnostic(ErrorCode.ERR_ConstantExpected, "y11").WithLocation(102, 18),
// (112,28): error CS0128: A local variable named 'x14' is already defined in this scope
// 2 is var x14,
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x14").WithArguments("x14").WithLocation(112, 28),
// (125,25): error CS0841: Cannot use local variable 'y15' before it is declared
// case 0 when y15 > 0:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y15").WithArguments("y15").WithLocation(125, 25),
// (127,18): error CS0841: Cannot use local variable 'y15' before it is declared
// case y15:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y15").WithArguments("y15").WithLocation(127, 18),
// (127,18): error CS0150: A constant value is expected
// case y15:
Diagnostic(ErrorCode.ERR_ConstantExpected, "y15").WithLocation(127, 18),
// (138,25): error CS0841: Cannot use local variable 'y16' before it is declared
// case 0 when y16 > 0:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y16").WithArguments("y16").WithLocation(138, 25),
// (140,18): error CS0841: Cannot use local variable 'y16' before it is declared
// case y16:
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y16").WithArguments("y16").WithLocation(140, 18),
// (140,18): error CS0150: A constant value is expected
// case y16:
Diagnostic(ErrorCode.ERR_ConstantExpected, "y16").WithLocation(140, 18)
);
var tree = compilation.SyntaxTrees.Single();
......@@ -15191,6 +15229,9 @@ public static void Main()
Console.WriteLine(1 is 1); // true
Console.WriteLine(1L is int.MaxValue); // OK, but false
Console.WriteLine(1 is int.MaxValue); // false
Console.WriteLine(int.MaxValue is int.MaxValue); // true
Console.WriteLine(""foo"" is System.String); // true
Console.WriteLine(Int32.MaxValue is Int32.MaxValue); // true
Console.WriteLine(new int[] {1, 2} is int[] a); // true
object o = null;
switch (o)
......@@ -15215,6 +15256,9 @@ public static void Main()
False
False
True
True
True
True
null");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册