提交 7e09ace3 编写于 作者: N Neal Gafter

Add a "var pattern" corresponding to deconstruction using a parenthesized designation.

We now forbid the use of `var` as a pattern's type except in the var pattern, where it is forbidden to bind to a user-declared type. Requires LDM and compat council review.
上级 e44dde72
......@@ -74,6 +74,9 @@ internal virtual BoundExpression BindSwitchExpressionCore(SwitchExpressionSyntax
case SyntaxKind.PropertyPattern:
return BindPropertyPattern((PropertyPatternSyntax)node, operandType, hasErrors, diagnostics);
case SyntaxKind.VarPattern:
return BindVarPattern((VarPatternSyntax)node, operandType, hasErrors, diagnostics);
default:
throw ExceptionUtilities.UnexpectedValue(node.Kind());
}
......@@ -265,9 +268,22 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
{
var typeSyntax = node.Type;
var boundDeclType = BindPatternType(typeSyntax, operandType, ref hasErrors, out bool isVar, diagnostics);
var declType = boundDeclType.Type;
if (typeSyntax.ToString() == "var" && !isVar)
{
// For compatibility, we temporarily parse the var pattern with a simple designator as a declaration pattern.
// So we implement the semantics of the var pattern here, forbidding "var" to bind to a user-declared type.
if (!hasErrors)
{
diagnostics.Add(ErrorCode.ERR_VarMayNotBindToType, typeSyntax.Location, (boundDeclType.AliasOpt ?? (Symbol)boundDeclType.Type).ToDisplayString());
}
boundDeclType = new BoundTypeExpression(typeSyntax, null, inferredType: true, type: operandType, hasErrors: true);
}
var declType = boundDeclType.Type;
BindPatternDesignation(node, node.Designation, declType, typeSyntax, diagnostics, ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
// PROTOTYPE(patterns2): We could bind the "var" declaration pattern as a var pattern in preparation for changing the parser to parse it as a var pattern.
// PROTOTYPE(patterns2): Eventually we will want to remove "isVar" from the declaration pattern.
return new BoundDeclarationPattern(node, variableSymbol, variableAccess, boundDeclType, isVar, hasErrors);
}
......@@ -423,7 +439,6 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node,
else
{
// It is not a tuple type. Seek an appropriate Deconstruct method.
var inputPlaceholder = new BoundImplicitReceiver(node, declType); // A fake receiver expression to permit us to reuse binding logic
var deconstruct = MakeDeconstructInvocationExpression(
node.SubPatterns.Count, inputPlaceholder, node, diagnostics, out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders, requireTwoOrMoreElements: false);
......@@ -456,6 +471,92 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node,
deconstruction: patterns.ToImmutableAndFree(), propertiesOpt: propertiesOpt, variable: variableSymbol, variableAccess: variableAccess, hasErrors: hasErrors);
}
private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics)
{
TypeSymbol declType = operandType;
var foundType = BindVarType(node.VarIdentifier, diagnostics, out bool isVar, null);
if (!isVar)
{
// Give an error if there is a bindable type "var" in scope
diagnostics.Add(ErrorCode.ERR_VarMayNotBindToType, node.VarIdentifier.GetLocation(), foundType.ToDisplayString());
hasErrors = true;
}
return BindVarDesignation(node, node.Designation, operandType, hasErrors, diagnostics);
}
private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignationSyntax designation, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics)
{
switch (designation.Kind())
{
case SyntaxKind.DiscardDesignation:
{
//return new BoundDiscardPattern(designation);
// PROTOTYPE(patterns2): this should bind as a discard pattern, but for now we'll bind it as a declaration
// pattern for compatibility with the later phases of the compiler that do not yet handle the discard pattern.
var boundOperandType = new BoundTypeExpression(node, null, operandType); // fake a type expression for the variable's type
return new BoundDeclarationPattern(designation, null, null, boundOperandType, isVar: true, hasErrors: hasErrors);
}
case SyntaxKind.SingleVariableDesignation:
{
BindPatternDesignation(node, designation, operandType, null, diagnostics, ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
var boundOperandType = new BoundTypeExpression(node, null, operandType); // fake a type expression for the variable's type
return new BoundDeclarationPattern(designation, variableSymbol, variableAccess, boundOperandType, isVar: true, hasErrors: hasErrors);
}
case SyntaxKind.ParenthesizedVariableDesignation:
{
var tupleDesignation = (ParenthesizedVariableDesignationSyntax)designation;
var patterns = ArrayBuilder<BoundPattern>.GetInstance();
MethodSymbol deconstructMethod = null;
if (operandType.IsTupleType)
{
// It is a tuple type. Work according to its elements
var elementTypes = operandType.TupleElementTypes;
if (elementTypes.Length != tupleDesignation.Variables.Count && !hasErrors)
{
var location = new SourceLocation(node.SyntaxTree, new Text.TextSpan(tupleDesignation.OpenParenToken.SpanStart, tupleDesignation.CloseParenToken.Span.End - tupleDesignation.OpenParenToken.SpanStart));
diagnostics.Add(ErrorCode.ERR_WrongNumberOfSubpatterns, location, operandType.TupleElementTypes, elementTypes.Length, tupleDesignation.Variables.Count);
hasErrors = true;
}
for (int i = 0; i < tupleDesignation.Variables.Count; i++)
{
bool isError = i >= elementTypes.Length;
var elementType = isError ? CreateErrorType() : elementTypes[i];
var boundSubpattern = BindVarDesignation(node, tupleDesignation.Variables[i], elementType, isError, diagnostics);
patterns.Add(boundSubpattern);
}
}
else
{
// It is not a tuple type. Seek an appropriate Deconstruct method.
var inputPlaceholder = new BoundImplicitReceiver(node, operandType); // A fake receiver expression to permit us to reuse binding logic
var deconstruct = MakeDeconstructInvocationExpression(
tupleDesignation.Variables.Count, inputPlaceholder, node, diagnostics, out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders, requireTwoOrMoreElements: false);
deconstructMethod = deconstruct.ExpressionSymbol as MethodSymbol;
// PROTOTYPE(patterns2): Set and check the deconstructMethod
for (int i = 0; i < tupleDesignation.Variables.Count; i++)
{
bool isError = outPlaceholders.IsDefaultOrEmpty || i >= outPlaceholders.Length;
var elementType = isError ? CreateErrorType() : outPlaceholders[i].Type;
var boundSubpattern = BindVarDesignation(node, tupleDesignation.Variables[i], elementType, isError, diagnostics);
patterns.Add(boundSubpattern);
}
// PROTOTYPE(patterns2): If no Deconstruct method is found, try casting to `ITuple`.
}
return new BoundRecursivePattern(
syntax: node, declaredType: null, inputType: operandType, deconstructMethodOpt: deconstructMethod,
deconstruction: patterns.ToImmutableAndFree(), propertiesOpt: default, variable: null, variableAccess: null, hasErrors: hasErrors);
}
default:
{
throw ExceptionUtilities.UnexpectedValue(designation.Kind());
}
}
}
private BoundPattern BindPropertyPattern(PropertyPatternSyntax node, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics)
{
var typeSyntax = node.Type;
......
......@@ -90,111 +90,133 @@ private Symbol BindTypeOrAlias(TypeSyntax syntax, DiagnosticBag diagnostics, out
else
{
// Only IdentifierNameSyntax instances may be 'var'.
var identifierValueText = ((IdentifierNameSyntax)syntax).Identifier.ValueText;
SyntaxToken varToken = ((IdentifierNameSyntax)syntax).Identifier;
var symbol = BindVarType(varToken, diagnostics, out isVar, basesBeingResolved);
if (isVar)
{
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureImplicitLocal, diagnostics);
}
Symbol symbol = null;
return symbol;
}
}
// Perform name lookup without generating diagnostics as it could possibly be
// "var" keyword in the current context.
var lookupResult = LookupResult.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupSymbolsInternal(lookupResult, identifierValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, basesBeingResolved: basesBeingResolved,
options: LookupOptions.NamespacesOrTypesOnly, diagnose: false);
diagnostics.Add(syntax, useSiteDiagnostics);
/// <summary>
/// Bind the use of "var" as a type, where it could possibly be used to be an implicit type.
/// If the syntax binds to an alias symbol to a type, it returns the alias symbol.
/// </summary>
/// <param name="varToken">The token where "var" appeared.</param>
/// <param name="diagnostics">Diagnostics.</param>
/// <param name="isVar">
/// Set to false if syntax binds to a type or alias to a type in the current context and true if
/// it binds to "var" keyword in the current context.
/// </param>
/// <returns>
/// Bound type or alias if "var" binds to a type or alias to a type in the current context and
/// null if syntax binds to "var" keyword in the current context.
/// </returns>
private Symbol BindVarType(SyntaxToken varToken, DiagnosticBag diagnostics, out bool isVar, ConsList<Symbol> basesBeingResolved)
{
var identifierValueText = varToken.ValueText;
Debug.Assert("var" == identifierValueText);
// We have following possible cases for lookup:
Symbol symbol = null;
// 1) LookupResultKind.Empty: isVar = true
// Perform name lookup without generating diagnostics as it could possibly be
// "var" keyword in the current context.
var lookupResult = LookupResult.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupSymbolsInternal(lookupResult, identifierValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, basesBeingResolved: basesBeingResolved,
options: LookupOptions.NamespacesOrTypesOnly, diagnose: false);
diagnostics.Add(varToken, useSiteDiagnostics);
// 2) LookupResultKind.Viable:
// a) Single viable result that corresponds to 1) a non-error type: isVar = false
// 2) an error type: isVar = true
// b) Single viable result that corresponds to namespace: isVar = true
// c) Multi viable result (ambiguous result), we must return an error type: isVar = false
// We have following possible cases for lookup:
// 3) Non viable, non empty lookup result: isVar = true
// 1) LookupResultKind.Empty: isVar = true
// BREAKING CHANGE: Case (2)(c) is a breaking change from the native compiler.
// BREAKING CHANGE: Native compiler interprets lookup with ambiguous result to correspond to bind
// BREAKING CHANGE: to "var" keyword (isVar = true), rather than reporting an error.
// BREAKING CHANGE: See test SemanticErrorTests.ErrorMeansSuccess_var() for an example.
// 2) LookupResultKind.Viable:
// a) Single viable result that corresponds to 1) a non-error type: isVar = false
// 2) an error type: isVar = true
// b) Single viable result that corresponds to namespace: isVar = true
// c) Multi viable result (ambiguous result), we must return an error type: isVar = false
switch (lookupResult.Kind)
{
case LookupResultKind.Empty:
// Case (1)
isVar = true;
symbol = null;
break;
// 3) Non viable, non empty lookup result: isVar = true
case LookupResultKind.Viable:
// Case (2)
DiagnosticBag resultDiagnostics = DiagnosticBag.GetInstance();
bool wasError;
symbol = ResultSymbol(
lookupResult,
identifierValueText,
arity: 0,
where: syntax,
diagnostics: resultDiagnostics,
suppressUseSiteDiagnostics: false,
wasError: out wasError);
// Here, we're mimicking behavior of dev10. If "var" fails to bind
// as a type, even if the reason is (e.g.) a type/alias conflict, then treat
// it as the contextual keyword.
if (wasError && lookupResult.IsSingleViable)
{
// NOTE: don't report diagnostics - we're not going to use the lookup result.
resultDiagnostics.Free();
// Case (2)(a)(2)
goto default;
}
// BREAKING CHANGE: Case (2)(c) is a breaking change from the native compiler.
// BREAKING CHANGE: Native compiler interprets lookup with ambiguous result to correspond to bind
// BREAKING CHANGE: to "var" keyword (isVar = true), rather than reporting an error.
// BREAKING CHANGE: See test SemanticErrorTests.ErrorMeansSuccess_var() for an example.
switch (lookupResult.Kind)
{
case LookupResultKind.Empty:
// Case (1)
isVar = true;
symbol = null;
break;
diagnostics.AddRange(resultDiagnostics);
case LookupResultKind.Viable:
// Case (2)
DiagnosticBag resultDiagnostics = DiagnosticBag.GetInstance();
bool wasError;
symbol = ResultSymbol(
lookupResult,
identifierValueText,
arity: 0,
where: varToken.Parent,
diagnostics: resultDiagnostics,
suppressUseSiteDiagnostics: false,
wasError: out wasError);
// Here, we're mimicking behavior of dev10. If "var" fails to bind
// as a type, even if the reason is (e.g.) a type/alias conflict, then treat
// it as the contextual keyword.
if (wasError && lookupResult.IsSingleViable)
{
// NOTE: don't report diagnostics - we're not going to use the lookup result.
resultDiagnostics.Free();
// Case (2)(a)(2)
goto default;
}
if (lookupResult.IsSingleViable)
{
var type = UnwrapAlias(symbol, diagnostics, syntax) as TypeSymbol;
diagnostics.AddRange(resultDiagnostics);
resultDiagnostics.Free();
if ((object)type != null)
{
// Case (2)(a)(1)
isVar = false;
}
else
{
// Case (2)(b)
Debug.Assert(UnwrapAliasNoDiagnostics(symbol) is NamespaceSymbol);
isVar = true;
symbol = null;
}
if (lookupResult.IsSingleViable)
{
var type = UnwrapAlias(symbol, diagnostics, varToken.Parent) as TypeSymbol;
if ((object)type != null)
{
// Case (2)(a)(1)
isVar = false;
}
else
{
// Case (2)(c)
isVar = false;
// Case (2)(b)
Debug.Assert(UnwrapAliasNoDiagnostics(symbol) is NamespaceSymbol);
isVar = true;
symbol = null;
}
}
else
{
// Case (2)(c)
isVar = false;
}
break;
default:
// Case (3)
isVar = true;
symbol = null;
break;
}
break;
lookupResult.Free();
default:
// Case (3)
isVar = true;
symbol = null;
break;
}
if (isVar)
{
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureImplicitLocal, diagnostics);
}
lookupResult.Free();
return symbol;
}
return symbol;
}
// Binds the given expression syntax as Type.
......
......@@ -208,15 +208,54 @@ public override void VisitSwitchStatement(SwitchStatementSyntax node)
public override void VisitDeclarationPattern(DeclarationPatternSyntax node)
{
var variable = MakePatternVariable(node, _nodeToBind);
if ((object)variable != null)
if (node.Designation?.Kind() == SyntaxKind.SingleVariableDesignation)
{
_variablesBuilder.Add(variable);
var variable = MakePatternVariable(node.Type, (SingleVariableDesignationSyntax)node.Designation, _nodeToBind);
if ((object)variable != null)
{
_variablesBuilder.Add(variable);
}
}
else
{
// The declaration pattern does not permit a ParenthesizedVariableDesignation
Debug.Assert(node.Designation == null || node.Designation.Kind() == SyntaxKind.DiscardDesignation);
}
base.VisitDeclarationPattern(node);
}
public override void VisitVarPattern(VarPatternSyntax node)
{
VisitPatternDesignation(node.Designation);
base.VisitVarPattern(node);
}
private void VisitPatternDesignation(VariableDesignationSyntax node)
{
switch (node.Kind())
{
case SyntaxKind.SingleVariableDesignation:
var variable = MakePatternVariable(null, (SingleVariableDesignationSyntax)node, _nodeToBind);
if ((object)variable != null)
{
_variablesBuilder.Add(variable);
}
break;
case SyntaxKind.DiscardDesignation:
break;
case SyntaxKind.ParenthesizedVariableDesignation:
foreach (VariableDesignationSyntax nested in ((ParenthesizedVariableDesignationSyntax)node).Variables)
{
VisitPatternDesignation(nested);
}
break;
default:
throw ExceptionUtilities.UnexpectedValue(node.Kind());
}
}
public override void VisitDeconstructionPattern(DeconstructionPatternSyntax node)
{
var variable = MakePatternVariable(node, _nodeToBind);
......@@ -239,7 +278,7 @@ public override void VisitPropertyPattern(PropertyPatternSyntax node)
base.VisitPropertyPattern(node);
}
protected abstract TFieldOrLocalSymbol MakePatternVariable(DeclarationPatternSyntax node, SyntaxNode nodeToBind);
protected abstract TFieldOrLocalSymbol MakePatternVariable(TypeSyntax type, SingleVariableDesignationSyntax designation, SyntaxNode nodeToBind);
protected abstract TFieldOrLocalSymbol MakePatternVariable(DeconstructionPatternSyntax node, SyntaxNode nodeToBind);
protected abstract TFieldOrLocalSymbol MakePatternVariable(PropertyPatternSyntax node, SyntaxNode nodeToBind);
......@@ -473,9 +512,9 @@ internal class ExpressionVariableFinder : ExpressionVariableFinder<LocalSymbol>
s_poolInstance.Free(finder);
}
protected override LocalSymbol MakePatternVariable(DeclarationPatternSyntax node, SyntaxNode nodeToBind)
protected override LocalSymbol MakePatternVariable(TypeSyntax type, SingleVariableDesignationSyntax designation, SyntaxNode nodeToBind)
{
return MakePatternVariable(node.Type, node.Designation, nodeToBind);
return MakePatternVariable(type, designation, nodeToBind);
}
protected override LocalSymbol MakePatternVariable(DeconstructionPatternSyntax node, SyntaxNode nodeToBind)
......@@ -603,16 +642,10 @@ internal class ExpressionFieldFinder : ExpressionVariableFinder<Symbol>
s_poolInstance.Free(finder);
}
protected override Symbol MakePatternVariable(DeclarationPatternSyntax node, SyntaxNode nodeToBind)
protected override Symbol MakePatternVariable(TypeSyntax type, SingleVariableDesignationSyntax designation, SyntaxNode nodeToBind)
{
var designation = node.Designation as SingleVariableDesignationSyntax;
if (designation == null)
{
return null;
}
return GlobalExpressionVariable.Create(
_containingType, _modifiers, node.Type,
_containingType, _modifiers, type,
designation.Identifier.ValueText, designation, designation.GetLocation(),
_containingFieldOpt, nodeToBind);
}
......
......@@ -272,9 +272,13 @@ private ErrorCode CheckSubsumed(BoundPattern pattern, DecisionTree decisionTree,
}
}
case BoundKind.DiscardPattern:
// because we always handle `default:` last, and that is the only way to get a wildcard pattern,
// we should never need to see if it subsumes something else.
throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
if (pattern.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel)
{
// The default pattern is always considered reachable (never subsumed).
return 0;
}
return decisionTree.MatchIsComplete ? ErrorCode.ERR_PatternIsSubsumed : 0;
default:
throw ExceptionUtilities.UnexpectedValue(pattern.Kind);
}
......
......@@ -9943,6 +9943,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to The syntax &apos;var&apos; for a pattern is not permitted to bind to a type, but it binds to &apos;{0}&apos; here..
/// </summary>
internal static string ERR_VarMayNotBindToType {
get {
return ResourceManager.GetString("ERR_VarMayNotBindToType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos;: virtual or abstract members cannot be private.
/// </summary>
......@@ -11393,15 +11402,6 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to The type must be &apos;var&apos;..
/// </summary>
internal static string TypeMustBeVar {
get {
return ResourceManager.GetString("TypeMustBeVar", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Literal to create numeric literal tokens..
/// </summary>
......
......@@ -5003,9 +5003,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_DeconstructTooFewElements" xml:space="preserve">
<value>Deconstruction must contain at least two variables.</value>
</data>
<data name="TypeMustBeVar" xml:space="preserve">
<value>The type must be 'var'.</value>
</data>
<data name="WRN_TupleLiteralNameMismatch" xml:space="preserve">
<value>The tuple element name '{0}' is ignored because a different name or no name is specified by the target type '{1}'.</value>
</data>
......@@ -5234,4 +5231,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_SingleElementPositionalPattern" xml:space="preserve">
<value>A single-element deconstruct pattern is ambiguous with a parenthesized pattern; add '{}' after the close paren to disambiguate.</value>
</data>
<data name="ERR_VarMayNotBindToType" xml:space="preserve">
<value>The syntax 'var' for a pattern is not permitted to bind to a type, but it binds to '{0}' here.</value>
</data>
</root>
\ No newline at end of file
......@@ -63,6 +63,17 @@ internal static void Add(this DiagnosticBag diagnostics, DiagnosticInfo info, Lo
return !useSiteDiagnostics.IsNullOrEmpty() && diagnostics.Add(node.Location, useSiteDiagnostics);
}
/// <summary>
/// Adds diagnostics from useSiteDiagnostics into diagnostics and returns True if there were any errors.
/// </summary>
internal static bool Add(
this DiagnosticBag diagnostics,
SyntaxToken token,
HashSet<DiagnosticInfo> useSiteDiagnostics)
{
return !useSiteDiagnostics.IsNullOrEmpty() && diagnostics.Add(token.GetLocation(), useSiteDiagnostics);
}
internal static bool Add(
this DiagnosticBag diagnostics,
Location location,
......
......@@ -1548,6 +1548,7 @@ internal enum ErrorCode
ERR_DefaultPattern = 8405,
ERR_SwitchExpressionNoBestType = 8406,
ERR_SingleElementPositionalPattern = 8407,
ERR_VarMayNotBindToType = 8408,
#endregion diagnostics introduced for recursive patterns
}
......
......@@ -2720,13 +2720,13 @@ public override BoundNode VisitDiscardExpression(BoundDiscardExpression node)
public override BoundNode VisitSwitchExpression(BoundSwitchExpression node)
{
VisitRvalue(node.Expression);
VisitRvalue(node.GoverningExpression);
var dispatchState = this.State;
var endState = UnreachableState();
foreach (var section in node.SwitchSections)
{
SetState(dispatchState.Clone());
VisitPattern(node.Expression, section.Pattern);
VisitPattern(node.GoverningExpression, section.Pattern);
SetState(StateWhenTrue);
if (section.Guard != null)
{
......
......@@ -2934,19 +2934,19 @@ public BoundPatternSwitchStatement2 Update(BoundExpression expression, Immutable
internal sealed partial class BoundSwitchExpression : BoundExpression
{
public BoundSwitchExpression(SyntaxNode syntax, BoundExpression expression, ImmutableArray<BoundSwitchExpressionCase> switchSections, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.SwitchExpression, syntax, type, hasErrors || expression.HasErrors() || switchSections.HasErrors())
public BoundSwitchExpression(SyntaxNode syntax, BoundExpression governingExpression, ImmutableArray<BoundSwitchExpressionCase> switchSections, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.SwitchExpression, syntax, type, hasErrors || governingExpression.HasErrors() || switchSections.HasErrors())
{
Debug.Assert(expression != null, "Field 'expression' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(governingExpression != null, "Field 'governingExpression' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(!switchSections.IsDefault, "Field 'switchSections' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.Expression = expression;
this.GoverningExpression = governingExpression;
this.SwitchSections = switchSections;
}
public BoundExpression Expression { get; }
public BoundExpression GoverningExpression { get; }
public ImmutableArray<BoundSwitchExpressionCase> SwitchSections { get; }
......@@ -2955,11 +2955,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor)
return visitor.VisitSwitchExpression(this);
}
public BoundSwitchExpression Update(BoundExpression expression, ImmutableArray<BoundSwitchExpressionCase> switchSections, TypeSymbol type)
public BoundSwitchExpression Update(BoundExpression governingExpression, ImmutableArray<BoundSwitchExpressionCase> switchSections, TypeSymbol type)
{
if (expression != this.Expression || switchSections != this.SwitchSections || type != this.Type)
if (governingExpression != this.GoverningExpression || switchSections != this.SwitchSections || type != this.Type)
{
var result = new BoundSwitchExpression(this.Syntax, expression, switchSections, type, this.HasErrors);
var result = new BoundSwitchExpression(this.Syntax, governingExpression, switchSections, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
return result;
}
......@@ -8830,7 +8830,7 @@ public override BoundNode VisitPatternSwitchStatement2(BoundPatternSwitchStateme
}
public override BoundNode VisitSwitchExpression(BoundSwitchExpression node)
{
this.Visit(node.Expression);
this.Visit(node.GoverningExpression);
this.VisitList(node.SwitchSections);
return null;
}
......@@ -9743,10 +9743,10 @@ public override BoundNode VisitPatternSwitchStatement2(BoundPatternSwitchStateme
}
public override BoundNode VisitSwitchExpression(BoundSwitchExpression node)
{
BoundExpression expression = (BoundExpression)this.Visit(node.Expression);
BoundExpression governingExpression = (BoundExpression)this.Visit(node.GoverningExpression);
ImmutableArray<BoundSwitchExpressionCase> switchSections = (ImmutableArray<BoundSwitchExpressionCase>)this.VisitList(node.SwitchSections);
TypeSymbol type = this.VisitType(node.Type);
return node.Update(expression, switchSections, type);
return node.Update(governingExpression, switchSections, type);
}
public override BoundNode VisitSwitchExpressionCase(BoundSwitchExpressionCase node)
{
......@@ -11033,7 +11033,7 @@ public override TreeDumperNode VisitSwitchExpression(BoundSwitchExpression node,
{
return new TreeDumperNode("switchExpression", null, new TreeDumperNode[]
{
new TreeDumperNode("expression", null, new TreeDumperNode[] { Visit(node.Expression, null) }),
new TreeDumperNode("governingExpression", null, new TreeDumperNode[] { Visit(node.GoverningExpression, null) }),
new TreeDumperNode("switchSections", null, from x in node.SwitchSections select Visit(x, null)),
new TreeDumperNode("type", node.Type, null)
}
......
......@@ -10962,6 +10962,130 @@ static DeclarationPatternSyntax()
}
}
internal sealed partial class VarPatternSyntax : PatternSyntax
{
internal readonly SyntaxToken varIdentifier;
internal readonly VariableDesignationSyntax designation;
internal VarPatternSyntax(SyntaxKind kind, SyntaxToken varIdentifier, VariableDesignationSyntax designation, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations)
: base(kind, diagnostics, annotations)
{
this.SlotCount = 2;
this.AdjustFlagsAndWidth(varIdentifier);
this.varIdentifier = varIdentifier;
this.AdjustFlagsAndWidth(designation);
this.designation = designation;
}
internal VarPatternSyntax(SyntaxKind kind, SyntaxToken varIdentifier, VariableDesignationSyntax designation, SyntaxFactoryContext context)
: base(kind)
{
this.SetFactoryContext(context);
this.SlotCount = 2;
this.AdjustFlagsAndWidth(varIdentifier);
this.varIdentifier = varIdentifier;
this.AdjustFlagsAndWidth(designation);
this.designation = designation;
}
internal VarPatternSyntax(SyntaxKind kind, SyntaxToken varIdentifier, VariableDesignationSyntax designation)
: base(kind)
{
this.SlotCount = 2;
this.AdjustFlagsAndWidth(varIdentifier);
this.varIdentifier = varIdentifier;
this.AdjustFlagsAndWidth(designation);
this.designation = designation;
}
public SyntaxToken VarIdentifier { get { return this.varIdentifier; } }
public VariableDesignationSyntax Designation { get { return this.designation; } }
internal override GreenNode GetSlot(int index)
{
switch (index)
{
case 0: return this.varIdentifier;
case 1: return this.designation;
default: return null;
}
}
internal override SyntaxNode CreateRed(SyntaxNode parent, int position)
{
return new CSharp.Syntax.VarPatternSyntax(this, parent, position);
}
public override TResult Accept<TResult>(CSharpSyntaxVisitor<TResult> visitor)
{
return visitor.VisitVarPattern(this);
}
public override void Accept(CSharpSyntaxVisitor visitor)
{
visitor.VisitVarPattern(this);
}
public VarPatternSyntax Update(SyntaxToken varIdentifier, VariableDesignationSyntax designation)
{
if (varIdentifier != this.VarIdentifier || designation != this.Designation)
{
var newNode = SyntaxFactory.VarPattern(varIdentifier, designation);
var diags = this.GetDiagnostics();
if (diags != null && diags.Length > 0)
newNode = newNode.WithDiagnosticsGreen(diags);
var annotations = this.GetAnnotations();
if (annotations != null && annotations.Length > 0)
newNode = newNode.WithAnnotationsGreen(annotations);
return newNode;
}
return this;
}
internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics)
{
return new VarPatternSyntax(this.Kind, this.varIdentifier, this.designation, diagnostics, GetAnnotations());
}
internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations)
{
return new VarPatternSyntax(this.Kind, this.varIdentifier, this.designation, GetDiagnostics(), annotations);
}
internal VarPatternSyntax(ObjectReader reader)
: base(reader)
{
this.SlotCount = 2;
var varIdentifier = (SyntaxToken)reader.ReadValue();
if (varIdentifier != null)
{
AdjustFlagsAndWidth(varIdentifier);
this.varIdentifier = varIdentifier;
}
var designation = (VariableDesignationSyntax)reader.ReadValue();
if (designation != null)
{
AdjustFlagsAndWidth(designation);
this.designation = designation;
}
}
internal override void WriteTo(ObjectWriter writer)
{
base.WriteTo(writer);
writer.WriteValue(this.varIdentifier);
writer.WriteValue(this.designation);
}
static VarPatternSyntax()
{
ObjectBinder.RegisterTypeReader(typeof(VarPatternSyntax), r => new VarPatternSyntax(r));
}
}
internal sealed partial class DeconstructionPatternSyntax : PatternSyntax
{
internal readonly TypeSyntax type;
......@@ -35106,6 +35230,11 @@ public virtual TResult VisitDeclarationPattern(DeclarationPatternSyntax node)
return this.DefaultVisit(node);
}
public virtual TResult VisitVarPattern(VarPatternSyntax node)
{
return this.DefaultVisit(node);
}
public virtual TResult VisitDeconstructionPattern(DeconstructionPatternSyntax node)
{
return this.DefaultVisit(node);
......@@ -36165,6 +36294,11 @@ public virtual void VisitDeclarationPattern(DeclarationPatternSyntax node)
this.DefaultVisit(node);
}
public virtual void VisitVarPattern(VarPatternSyntax node)
{
this.DefaultVisit(node);
}
public virtual void VisitDeconstructionPattern(DeconstructionPatternSyntax node)
{
this.DefaultVisit(node);
......@@ -37433,6 +37567,13 @@ public override CSharpSyntaxNode VisitDeclarationPattern(DeclarationPatternSynta
return node.Update(type, designation);
}
public override CSharpSyntaxNode VisitVarPattern(VarPatternSyntax node)
{
var varIdentifier = (SyntaxToken)this.Visit(node.VarIdentifier);
var designation = (VariableDesignationSyntax)this.Visit(node.Designation);
return node.Update(varIdentifier, designation);
}
public override CSharpSyntaxNode VisitDeconstructionPattern(DeconstructionPatternSyntax node)
{
var type = (TypeSyntax)this.Visit(node.Type);
......@@ -41164,6 +41305,35 @@ public DeclarationPatternSyntax DeclarationPattern(TypeSyntax type, VariableDesi
return result;
}
public VarPatternSyntax VarPattern(SyntaxToken varIdentifier, VariableDesignationSyntax designation)
{
#if DEBUG
if (varIdentifier == null)
throw new ArgumentNullException(nameof(varIdentifier));
switch (varIdentifier.Kind)
{
case SyntaxKind.IdentifierToken:
break;
default:
throw new ArgumentException("varIdentifier");
}
if (designation == null)
throw new ArgumentNullException(nameof(designation));
#endif
int hash;
var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.VarPattern, varIdentifier, designation, this.context, out hash);
if (cached != null) return (VarPatternSyntax)cached;
var result = new VarPatternSyntax(SyntaxKind.VarPattern, varIdentifier, designation, this.context);
if (hash >= 0)
{
SyntaxNodeCache.AddNode(result, hash);
}
return result;
}
public DeconstructionPatternSyntax DeconstructionPattern(TypeSyntax type, SyntaxToken openParenToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList<SubpatternElementSyntax> subPatterns, SyntaxToken closeParenToken, PropertySubpatternSyntax propertySubpattern, VariableDesignationSyntax designation)
{
#if DEBUG
......@@ -48276,6 +48446,35 @@ public static DeclarationPatternSyntax DeclarationPattern(TypeSyntax type, Varia
return result;
}
public static VarPatternSyntax VarPattern(SyntaxToken varIdentifier, VariableDesignationSyntax designation)
{
#if DEBUG
if (varIdentifier == null)
throw new ArgumentNullException(nameof(varIdentifier));
switch (varIdentifier.Kind)
{
case SyntaxKind.IdentifierToken:
break;
default:
throw new ArgumentException("varIdentifier");
}
if (designation == null)
throw new ArgumentNullException(nameof(designation));
#endif
int hash;
var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.VarPattern, varIdentifier, designation, out hash);
if (cached != null) return (VarPatternSyntax)cached;
var result = new VarPatternSyntax(SyntaxKind.VarPattern, varIdentifier, designation);
if (hash >= 0)
{
SyntaxNodeCache.AddNode(result, hash);
}
return result;
}
public static DeconstructionPatternSyntax DeconstructionPattern(TypeSyntax type, SyntaxToken openParenToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList<SubpatternElementSyntax> subPatterns, SyntaxToken closeParenToken, PropertySubpatternSyntax propertySubpattern, VariableDesignationSyntax designation)
{
#if DEBUG
......@@ -52964,6 +53163,7 @@ internal static IEnumerable<Type> GetNodeTypes()
typeof(WhenClauseSyntax),
typeof(DiscardPatternSyntax),
typeof(DeclarationPatternSyntax),
typeof(VarPatternSyntax),
typeof(DeconstructionPatternSyntax),
typeof(SubpatternElementSyntax),
typeof(PropertyPatternSyntax),
......@@ -466,6 +466,12 @@ public virtual TResult VisitDeclarationPattern(DeclarationPatternSyntax node)
return this.DefaultVisit(node);
}
/// <summary>Called when the visitor visits a VarPatternSyntax node.</summary>
public virtual TResult VisitVarPattern(VarPatternSyntax node)
{
return this.DefaultVisit(node);
}
/// <summary>Called when the visitor visits a DeconstructionPatternSyntax node.</summary>
public virtual TResult VisitDeconstructionPattern(DeconstructionPatternSyntax node)
{
......@@ -1735,6 +1741,12 @@ public virtual void VisitDeclarationPattern(DeclarationPatternSyntax node)
this.DefaultVisit(node);
}
/// <summary>Called when the visitor visits a VarPatternSyntax node.</summary>
public virtual void VisitVarPattern(VarPatternSyntax node)
{
this.DefaultVisit(node);
}
/// <summary>Called when the visitor visits a DeconstructionPatternSyntax node.</summary>
public virtual void VisitDeconstructionPattern(DeconstructionPatternSyntax node)
{
......@@ -3139,6 +3151,13 @@ public override SyntaxNode VisitDeclarationPattern(DeclarationPatternSyntax node
return node.Update(type, designation);
}
public override SyntaxNode VisitVarPattern(VarPatternSyntax node)
{
var varIdentifier = this.VisitToken(node.VarIdentifier);
var designation = (VariableDesignationSyntax)this.Visit(node.Designation);
return node.Update(varIdentifier, designation);
}
public override SyntaxNode VisitDeconstructionPattern(DeconstructionPatternSyntax node)
{
var type = (TypeSyntax)this.Visit(node.Type);
......@@ -6695,6 +6714,22 @@ public static DeclarationPatternSyntax DeclarationPattern(TypeSyntax type, Varia
}
/// <summary>Creates a new VarPatternSyntax instance.</summary>
public static VarPatternSyntax VarPattern(SyntaxToken varIdentifier, VariableDesignationSyntax designation)
{
switch (varIdentifier.Kind())
{
case SyntaxKind.IdentifierToken:
break;
default:
throw new ArgumentException("varIdentifier");
}
if (designation == null)
throw new ArgumentNullException(nameof(designation));
return (VarPatternSyntax)Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.VarPattern((Syntax.InternalSyntax.SyntaxToken)varIdentifier.Node, designation == null ? null : (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.VariableDesignationSyntax)designation.Green).CreateRed();
}
/// <summary>Creates a new DeconstructionPatternSyntax instance.</summary>
public static DeconstructionPatternSyntax DeconstructionPattern(TypeSyntax type, SyntaxToken openParenToken, SeparatedSyntaxList<SubpatternElementSyntax> subPatterns, SyntaxToken closeParenToken, PropertySubpatternSyntax propertySubpattern, VariableDesignationSyntax designation)
{
......
......@@ -6848,6 +6848,80 @@ public DeclarationPatternSyntax WithDesignation(VariableDesignationSyntax design
}
}
public sealed partial class VarPatternSyntax : PatternSyntax
{
private VariableDesignationSyntax designation;
internal VarPatternSyntax(Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.CSharpSyntaxNode green, SyntaxNode parent, int position)
: base(green, parent, position)
{
}
public SyntaxToken VarIdentifier
{
get { return new SyntaxToken(this, ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.VarPatternSyntax)this.Green).varIdentifier, this.Position, 0); }
}
public VariableDesignationSyntax Designation
{
get
{
return this.GetRed(ref this.designation, 1);
}
}
internal override SyntaxNode GetNodeSlot(int index)
{
switch (index)
{
case 1: return this.GetRed(ref this.designation, 1);
default: return null;
}
}
internal override SyntaxNode GetCachedSlot(int index)
{
switch (index)
{
case 1: return this.designation;
default: return null;
}
}
public override TResult Accept<TResult>(CSharpSyntaxVisitor<TResult> visitor)
{
return visitor.VisitVarPattern(this);
}
public override void Accept(CSharpSyntaxVisitor visitor)
{
visitor.VisitVarPattern(this);
}
public VarPatternSyntax Update(SyntaxToken varIdentifier, VariableDesignationSyntax designation)
{
if (varIdentifier != this.VarIdentifier || designation != this.Designation)
{
var newNode = SyntaxFactory.VarPattern(varIdentifier, designation);
var annotations = this.GetAnnotations();
if (annotations != null && annotations.Length > 0)
return newNode.WithAnnotations(annotations);
return newNode;
}
return this;
}
public VarPatternSyntax WithVarIdentifier(SyntaxToken varIdentifier)
{
return this.Update(varIdentifier, this.Designation);
}
public VarPatternSyntax WithDesignation(VariableDesignationSyntax designation)
{
return this.Update(this.VarIdentifier, designation);
}
}
public sealed partial class DeconstructionPatternSyntax : PatternSyntax
{
private TypeSyntax type;
......
......@@ -28,6 +28,7 @@ private CSharpSyntaxNode CheckRecursivePatternFeature(CSharpSyntaxNode node)
case SyntaxKind.DeconstructionPattern:
case SyntaxKind.DiscardPattern:
case SyntaxKind.PropertyPattern:
case SyntaxKind.VarPattern when ((VarPatternSyntax)node).Designation.Kind == SyntaxKind.ParenthesizedVariableDesignation:
return this.CheckFeatureAvailability(node, MessageID.IDS_FeatureRecursivePatterns);
default:
return node;
......@@ -405,6 +406,30 @@ bool looksLikeCast()
return result;
}
if (type?.Kind == SyntaxKind.IdentifierName)
{
var typeIdentifier = (IdentifierNameSyntax)type;
var typeIdentifierToken = typeIdentifier.Identifier;
if (typeIdentifierToken.Text == "var")
{
// we have a "var" pattern; "var" is not permitted to be a stand-in for a type (or a constant) in a pattern.
var varIdentifier = typeIdentifierToken;
var wasTupleDesignator = this.CurrentToken.Kind == SyntaxKind.OpenParenToken;
var varDesignation = ParseDesignation();
if (wasTupleDesignator)
{
return _syntaxFactory.VarPattern(varIdentifier, varDesignation);
}
else
{
// PROTOTYPE(patterns2): we parse it as a declaration pattern when we have simple designation, for compatibility.
// PROTOTYPE(patterns2): can we change it to use a var pattern in all cases?
//return _syntaxFactory.VarPattern(varIdentifier, varDesignation);
return _syntaxFactory.DeclarationPattern(_syntaxFactory.IdentifierName(varIdentifier), varDesignation);
}
}
}
if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken && (type != null || !looksLikeCast()))
{
// It is possible this is a parenthesized (constant) expression.
......
......@@ -71,6 +71,12 @@ Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax.WithCloseBraceToken(
Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax.WithGoverningExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax governingExpression) -> Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax.WithOpenBraceToken(Microsoft.CodeAnalysis.SyntaxToken openBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax.WithSwitchKeyword(Microsoft.CodeAnalysis.SyntaxToken switchKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax.Designation.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken varIdentifier, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax.VarIdentifier.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax.WithDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax.WithVarIdentifier(Microsoft.CodeAnalysis.SyntaxToken varIdentifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax
Microsoft.CodeAnalysis.CSharp.SyntaxKind.DeconstructionPattern = 9023 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.DiscardPattern = 9024 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.PropertyPattern = 9020 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
......@@ -78,6 +84,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.PropertySubpattern = 9021 -> Microsoft.
Microsoft.CodeAnalysis.CSharp.SyntaxKind.SubpatternElement = 9022 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.SwitchExpression = 9025 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.SwitchExpressionArm = 9026 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.VarPattern = 9027 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitDeconstructionPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitDiscardPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DiscardPatternSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitPropertyPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PropertyPatternSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
......@@ -85,6 +92,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitPropertySubpatt
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSubpatternElement(Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternElementSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSwitchExpression(Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSwitchExpressionArm(Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitVarPattern(Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.DiscardPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
......@@ -99,6 +107,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax.Accept(M
override Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetConversion(this Microsoft.CodeAnalysis.Semantics.IConversionExpression conversionExpression) -> Microsoft.CodeAnalysis.CSharp.Conversion
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DeconstructionPattern(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.SeparatedSyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternElementSyntax> subPatterns, Microsoft.CodeAnalysis.CSharp.Syntax.PropertySubpatternSyntax propertySubpattern, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DeconstructionPattern(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SeparatedSyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternElementSyntax> subPatterns, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.PropertySubpatternSyntax propertySubpattern, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternSyntax
......@@ -117,6 +127,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SwitchExpression(Microsoft.Co
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SwitchExpressionArm(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SwitchExpressionArm(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern, Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax whenClause, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SwitchExpressionArm(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern, Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax whenClause, Microsoft.CodeAnalysis.SyntaxToken equalsGreaterThanToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.VarPattern(Microsoft.CodeAnalysis.SyntaxToken varIdentifier, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDesignationSyntax designation) -> Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDeconstructionPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitDiscardPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DiscardPatternSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitPropertyPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PropertyPatternSyntax node) -> void
......@@ -124,10 +135,12 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitPropertySubpatter
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSubpatternElement(Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternElementSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSwitchExpression(Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSwitchExpressionArm(Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitVarPattern(Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitDeconstructionPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitDiscardPattern(Microsoft.CodeAnalysis.CSharp.Syntax.DiscardPatternSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitPropertyPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PropertyPatternSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitPropertySubpattern(Microsoft.CodeAnalysis.CSharp.Syntax.PropertySubpatternSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitSubpatternElement(Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternElementSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitSwitchExpression(Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitSwitchExpressionArm(Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax node) -> TResult
\ No newline at end of file
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitSwitchExpressionArm(Microsoft.CodeAnalysis.CSharp.Syntax.SwitchExpressionArmSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitVarPattern(Microsoft.CodeAnalysis.CSharp.Syntax.VarPatternSyntax node) -> TResult
\ No newline at end of file
......@@ -1732,6 +1732,13 @@
<Kind Name="DiscardDesignation"/>
</Field>
</Node>
<Node Name="VarPatternSyntax" Base="PatternSyntax">
<Kind Name="VarPattern" />
<Field Name="VarIdentifier" Type="SyntaxToken">
<Kind Name="IdentifierToken"/>
</Field>
<Field Name="Designation" Type="VariableDesignationSyntax"/>
</Node>
<Node Name="DeconstructionPatternSyntax" Base="PatternSyntax">
<Kind Name="DeconstructionPattern" />
<Field Name="Type" Type="TypeSyntax" Optional="true" />
......
......@@ -556,6 +556,7 @@ public enum SyntaxKind : ushort
WhenClause = 9013,
DiscardDesignation = 9014,
// added along with recursive patterns
PropertyPattern = 9020,
PropertySubpattern = 9021,
SubpatternElement = 9022,
......@@ -563,6 +564,7 @@ public enum SyntaxKind : ushort
DiscardPattern = 9024,
SwitchExpression = 9025,
SwitchExpressionArm = 9026,
VarPattern = 9027,
// Kinds between 9000 and 9039 are "reserved" for pattern matching.
// Please start with 9040 if you add more kinds below.
......
......@@ -30,7 +30,7 @@ protected SingleVariableDesignationSyntax GetPatternDeclaration(SyntaxTree tree,
protected IEnumerable<SingleVariableDesignationSyntax> GetPatternDeclarations(SyntaxTree tree)
{
return tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().Where(p => p.Parent.Kind() == SyntaxKind.DeclarationPattern);
return tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().Where(p => p.Parent.Kind() == SyntaxKind.DeclarationPattern || p.Parent.Kind() == SyntaxKind.VarPattern);
}
protected static IEnumerable<DiscardDesignationSyntax> GetDiscardDesignations(SyntaxTree tree)
......@@ -48,17 +48,17 @@ protected static IEnumerable<IdentifierNameSyntax> GetReferences(SyntaxTree tree
return tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == name);
}
protected static void VerifyModelForDeclarationPattern(SemanticModel model, SingleVariableDesignationSyntax decl, params IdentifierNameSyntax[] references)
protected static void VerifyModelForDeclarationOrVarSimplePattern(SemanticModel model, SingleVariableDesignationSyntax decl, params IdentifierNameSyntax[] references)
{
VerifyModelForDeclarationPattern(model, decl, false, references);
VerifyModelForDeclarationOrVarSimplePattern(model, decl, false, references);
}
protected static void VerifyModelForDeclarationPatternWithoutDataFlow(SemanticModel model, SingleVariableDesignationSyntax decl, params IdentifierNameSyntax[] references)
protected static void VerifyModelForDeclarationOrVarSimplePatternWithoutDataFlow(SemanticModel model, SingleVariableDesignationSyntax decl, params IdentifierNameSyntax[] references)
{
VerifyModelForDeclarationPattern(model, decl, false, references);
VerifyModelForDeclarationOrVarSimplePattern(model, decl, false, references);
}
protected static void VerifyModelForDeclarationPattern(
protected static void VerifyModelForDeclarationOrVarSimplePattern(
SemanticModel model,
SingleVariableDesignationSyntax designation,
bool isShadowed,
......@@ -82,23 +82,30 @@ protected static void VerifyModelForDeclarationPatternWithoutDataFlow(SemanticMo
Assert.True(model.LookupNames(designation.SpanStart).Contains(designation.Identifier.ValueText));
var decl = (DeclarationPatternSyntax)designation.Parent;
Assert.True(SyntaxFacts.IsInNamespaceOrTypeContext(decl.Type));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(decl.Type));
var local = ((SourceLocalSymbol)symbol);
var type = local.Type;
if (type.IsErrorType())
switch (designation.Parent)
{
Assert.Null(model.GetSymbolInfo(decl.Type).Symbol);
}
else
{
Assert.Equal(type, model.GetSymbolInfo(decl.Type).Symbol);
case DeclarationPatternSyntax decl:
{
var typeSyntax = decl.Type;
Assert.True(SyntaxFacts.IsInNamespaceOrTypeContext(typeSyntax));
Assert.True(SyntaxFacts.IsInTypeOnlyContext(typeSyntax));
var local = ((SourceLocalSymbol)symbol);
var type = local.Type;
if (type.IsErrorType())
{
Assert.Null(model.GetSymbolInfo(typeSyntax).Symbol);
}
else
{
Assert.Equal(type, model.GetSymbolInfo(typeSyntax).Symbol);
}
AssertTypeInfo(model, typeSyntax, type);
break;
}
}
AssertTypeInfo(model, decl.Type, type);
foreach (var reference in references)
{
Assert.Same(symbol, model.GetSymbolInfo(reference).Symbol);
......@@ -308,31 +315,37 @@ protected static void AssertContainedInDeclaratorArguments(params SingleVariable
Assert.False(model.LookupSymbols(designation.SpanStart, name: identifierText).Any());
Assert.False(model.LookupNames(designation.SpanStart).Contains(identifierText));
var decl = (DeclarationPatternSyntax)designation.Parent;
Assert.Null(model.GetSymbolInfo(decl.Type).Symbol);
Assert.Null(model.GetSymbolInfo(designation).Symbol);
Assert.Null(model.GetTypeInfo(designation).Type);
Assert.Null(model.GetDeclaredSymbol(designation));
var symbol = (Symbol)model.GetDeclaredSymbol(designation);
TypeInfo typeInfo = model.GetTypeInfo(decl.Type);
if ((object)symbol != null)
if (designation.Parent is DeclarationPatternSyntax decl)
{
Assert.Equal(symbol.GetTypeOrReturnType(), typeInfo.Type);
Assert.Equal(symbol.GetTypeOrReturnType(), typeInfo.ConvertedType);
Assert.Null(model.GetSymbolInfo(decl.Type).Symbol);
TypeInfo typeInfo = model.GetTypeInfo(decl.Type);
if ((object)symbol != null)
{
Assert.Equal(symbol.GetTypeOrReturnType(), typeInfo.Type);
Assert.Equal(symbol.GetTypeOrReturnType(), typeInfo.ConvertedType);
}
else
{
Assert.Equal(SymbolKind.ErrorType, typeInfo.Type.Kind);
Assert.Equal(SymbolKind.ErrorType, typeInfo.ConvertedType.Kind);
}
Assert.Equal(typeInfo, ((CSharpSemanticModel)model).GetTypeInfo(decl.Type));
Assert.True(model.GetConversion(decl.Type).IsIdentity);
}
else
else if (designation.Parent is VarPatternSyntax varp)
{
Assert.Equal(SymbolKind.ErrorType, typeInfo.Type.Kind);
Assert.Equal(SymbolKind.ErrorType, typeInfo.ConvertedType.Kind);
// Do we want to add any tests for the var pattern?
}
Assert.Equal(typeInfo, ((CSharpSemanticModel)model).GetTypeInfo(decl.Type));
Assert.True(model.GetConversion(decl.Type).IsIdentity);
VerifyModelNotSupported(model, references);
}
......
......@@ -729,5 +729,123 @@ public ValueTuple(T item1)
Diagnostic(ErrorCode.ERR_SingleElementPositionalPattern, "(int y)").WithLocation(10, 28)
);
}
[Fact]
public void Patterns2_05()
{
// Test parsing the var pattern
// Test binding the var pattern
// Test lowering the var pattern for the is-expression
var source =
@"
using System;
class Program
{
public static void Main()
{
var t = (1, 2);
{ Check(true, t is var (x, y) && x == 1 && y == 2); }
{ Check(false, t is var (x, y) && x == 1 && y == 3); }
}
private static void Check<T>(T expected, T actual)
{
if (!object.Equals(expected, actual)) throw new Exception($""Expected: '{expected}', Actual: '{actual}'"");
}
}
namespace System
{
public struct ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;
public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithRecursivePatterns);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: @"");
}
[Fact]
public void Patterns2_06()
{
// Test that 'var' does not bind to a type
var source =
@"
using System;
namespace N
{
class Program
{
public static void Main()
{
var t = (1, 2);
{ Check(true, t is var (x, y) && x == 1 && y == 2); } // error 1
{ Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
{ Check(true, t is var x); } // error 3
}
private static void Check<T>(T expected, T actual)
{
if (!object.Equals(expected, actual)) throw new Exception($""Expected: '{expected}', Actual: '{actual}'"");
}
}
class var { }
}
namespace System
{
public struct ValueTuple<T1, T2>
{
public T1 Item1;
public T2 Item2;
public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithRecursivePatterns);
compilation.VerifyDiagnostics(
// (9,21): error CS0029: Cannot implicitly convert type '(int, int)' to 'N.var'
// var t = (1, 2);
Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 2)").WithArguments("(int, int)", "N.var").WithLocation(9, 21),
// (10,32): error CS8408: The syntax 'var' for a pattern is not permitted to bind to a type, but it binds to 'N.var' here.
// { Check(true, t is var (x, y) && x == 1 && y == 2); } // error 1
Diagnostic(ErrorCode.ERR_VarMayNotBindToType, "var").WithArguments("N.var").WithLocation(10, 32),
// (10,32): error CS1061: 'var' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'var' could be found (are you missing a using directive or an assembly reference?)
// { Check(true, t is var (x, y) && x == 1 && y == 2); } // error 1
Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "var (x, y)").WithArguments("N.var", "Deconstruct").WithLocation(10, 32),
// (10,32): error CS8129: No suitable Deconstruct instance or extension method was found for type 'var', with 2 out parameters and a void return type.
// { Check(true, t is var (x, y) && x == 1 && y == 2); } // error 1
Diagnostic(ErrorCode.ERR_MissingDeconstruct, "var (x, y)").WithArguments("N.var", "2").WithLocation(10, 32),
// (11,33): error CS8408: The syntax 'var' for a pattern is not permitted to bind to a type, but it binds to 'N.var' here.
// { Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
Diagnostic(ErrorCode.ERR_VarMayNotBindToType, "var").WithArguments("N.var").WithLocation(11, 33),
// (11,33): error CS1061: 'var' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'var' could be found (are you missing a using directive or an assembly reference?)
// { Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "var (x, y)").WithArguments("N.var", "Deconstruct").WithLocation(11, 33),
// (11,33): error CS8129: No suitable Deconstruct instance or extension method was found for type 'var', with 2 out parameters and a void return type.
// { Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
Diagnostic(ErrorCode.ERR_MissingDeconstruct, "var (x, y)").WithArguments("N.var", "2").WithLocation(11, 33),
// (12,32): error CS8408: The syntax 'var' for a pattern is not permitted to bind to a type, but it binds to 'N.var' here.
// { Check(true, t is var x); } // error 3
Diagnostic(ErrorCode.ERR_VarMayNotBindToType, "var").WithArguments("N.var").WithLocation(12, 32)
);
}
// PROTOTYPE(patterns2): Need to have tests that exercise:
// PROTOTYPE(patterns2): Building the decision tree for the var-pattern
// PROTOTYPE(patterns2): Definite assignment for the var-pattern
// PROTOTYPE(patterns2): Variable finder for the var-pattern
// PROTOTYPE(patterns2): Scope binder contains an approprate scope for the var-pattern
// PROTOTYPE(patterns2): Lazily binding types for variables declared in the var-pattern
// PROTOTYPE(patterns2): Error when there is a type or constant named var in scope where the var pattern is used
}
}
......@@ -1789,7 +1789,7 @@ static void Main(string[] args)
var model = compilation.GetSemanticModel(tree);
var x1Decl = GetPatternDeclarations(tree, "x1").Single();
var x1Ref = GetReferences(tree, "x1").Single();
VerifyModelForDeclarationPattern(model, x1Decl, x1Ref);
VerifyModelForDeclarationOrVarSimplePattern(model, x1Decl, x1Ref);
}
[Fact, WorkItem(14717, "https://github.com/dotnet/roslyn/issues/14717")]
......@@ -1824,7 +1824,7 @@ static void Main(string[] args)
var model = compilation.GetSemanticModel(tree);
var x1Decl = GetPatternDeclarations(tree, "x1").Single();
var x1Ref = GetReferences(tree, "x1").Single();
VerifyModelForDeclarationPattern(model, x1Decl, x1Ref);
VerifyModelForDeclarationOrVarSimplePattern(model, x1Decl, x1Ref);
}
[Fact, WorkItem(14296, "https://github.com/dotnet/roslyn/issues/14296")]
......
......@@ -384,6 +384,11 @@ private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.DeclarationPa
return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.DeclarationPattern(GenerateIdentifierName(), GenerateSingleVariableDesignation());
}
private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.VarPatternSyntax GenerateVarPattern()
{
return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.VarPattern(Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Identifier("VarIdentifier"), GenerateSingleVariableDesignation());
}
private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.DeconstructionPatternSyntax GenerateDeconstructionPattern()
{
return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.DeconstructionPattern(null, Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.OpenParenToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SubpatternElementSyntax>(), Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.CloseParenToken), null, null);
......@@ -1951,6 +1956,17 @@ public void TestDeclarationPatternFactoryAndProperties()
AttachAndCheckDiagnostics(node);
}
[Fact]
public void TestVarPatternFactoryAndProperties()
{
var node = GenerateVarPattern();
Assert.Equal(SyntaxKind.IdentifierToken, node.VarIdentifier.Kind);
Assert.NotNull(node.Designation);
AttachAndCheckDiagnostics(node);
}
[Fact]
public void TestDeconstructionPatternFactoryAndProperties()
{
......@@ -5691,6 +5707,32 @@ public void TestDeclarationPatternIdentityRewriter()
Assert.Same(oldNode, newNode);
}
[Fact]
public void TestVarPatternTokenDeleteRewriter()
{
var oldNode = GenerateVarPattern();
var rewriter = new TokenDeleteRewriter();
var newNode = rewriter.Visit(oldNode);
if(!oldNode.IsMissing)
{
Assert.NotEqual(oldNode, newNode);
}
Assert.NotNull(newNode);
Assert.True(newNode.IsMissing, "No tokens => missing");
}
[Fact]
public void TestVarPatternIdentityRewriter()
{
var oldNode = GenerateVarPattern();
var rewriter = new IdentityRewriter();
var newNode = rewriter.Visit(oldNode);
Assert.Same(oldNode, newNode);
}
[Fact]
public void TestDeconstructionPatternTokenDeleteRewriter()
{
......@@ -9607,6 +9649,11 @@ private static DeclarationPatternSyntax GenerateDeclarationPattern()
return SyntaxFactory.DeclarationPattern(GenerateIdentifierName(), GenerateSingleVariableDesignation());
}
private static VarPatternSyntax GenerateVarPattern()
{
return SyntaxFactory.VarPattern(SyntaxFactory.Identifier("VarIdentifier"), GenerateSingleVariableDesignation());
}
private static DeconstructionPatternSyntax GenerateDeconstructionPattern()
{
return SyntaxFactory.DeconstructionPattern(default(TypeSyntax), SyntaxFactory.Token(SyntaxKind.OpenParenToken), new SeparatedSyntaxList<SubpatternElementSyntax>(), SyntaxFactory.Token(SyntaxKind.CloseParenToken), default(PropertySubpatternSyntax), default(VariableDesignationSyntax));
......@@ -11174,6 +11221,17 @@ public void TestDeclarationPatternFactoryAndProperties()
Assert.Equal(node, newNode);
}
[Fact]
public void TestVarPatternFactoryAndProperties()
{
var node = GenerateVarPattern();
Assert.Equal(SyntaxKind.IdentifierToken, node.VarIdentifier.Kind());
Assert.NotNull(node.Designation);
var newNode = node.WithVarIdentifier(node.VarIdentifier).WithDesignation(node.Designation);
Assert.Equal(node, newNode);
}
[Fact]
public void TestDeconstructionPatternFactoryAndProperties()
{
......@@ -14914,6 +14972,32 @@ public void TestDeclarationPatternIdentityRewriter()
Assert.Same(oldNode, newNode);
}
[Fact]
public void TestVarPatternTokenDeleteRewriter()
{
var oldNode = GenerateVarPattern();
var rewriter = new TokenDeleteRewriter();
var newNode = rewriter.Visit(oldNode);
if(!oldNode.IsMissing)
{
Assert.NotEqual(oldNode, newNode);
}
Assert.NotNull(newNode);
Assert.True(newNode.IsMissing, "No tokens => missing");
}
[Fact]
public void TestVarPatternIdentityRewriter()
{
var oldNode = GenerateVarPattern();
var rewriter = new IdentityRewriter();
var newNode = rewriter.Visit(oldNode);
Assert.Same(oldNode, newNode);
}
[Fact]
public void TestDeconstructionPatternTokenDeleteRewriter()
{
......
......@@ -326,6 +326,8 @@ namespace My
break;
case Type (int x, 3) { A: _, B: 7 } identifier:
break;
case var (x, y, (z, w)):
break;
default:
{
return;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册