未验证 提交 81e9db82 编写于 作者: F Fred Silberberg 提交者: GitHub

Merge pull request #33178 from 333fred/rpatterns-33018

Make IPropertySubpattern Internal
......@@ -1996,6 +1996,7 @@ private IOperation CreateBoundDiscardPatternOperation(BoundDiscardPattern boundN
boundNode.Syntax,
isImplicit: boundNode.WasCompilerGenerated);
}
private IOperation CreateUsingLocalDeclarationsOperation(BoundUsingLocalDeclarations boundNode)
{
//TODO: Implement UsingLocalDeclaration operations correctly.
......@@ -2007,5 +2008,40 @@ private IOperation CreateUsingLocalDeclarationsOperation(BoundUsingLocalDeclarat
getChildren: () => ImmutableArray.Create<IOperation>(CreateBoundMultipleLocalDeclarationsOperation((BoundMultipleLocalDeclarations)boundNode)),
isImplicit: false);
}
internal IPropertySubpatternOperation CreatePropertySubpattern(BoundSubpattern subpattern, ITypeSymbol matchedType)
{
SyntaxNode syntax = subpattern.Syntax;
return new CSharpLazyPropertySubpatternOperation(this, subpattern, matchedType, syntax, _semanticModel);
}
internal IOperation CreatePropertySubpatternMember(Symbol symbol, ITypeSymbol matchedType, SyntaxNode syntax)
{
var nameSyntax = (syntax is SubpatternSyntax subpatSyntax ? subpatSyntax.NameColon?.Name : null) ?? syntax;
bool isImplicit = nameSyntax == syntax;
switch (symbol)
{
case FieldSymbol field:
{
var constantValue = field.ConstantValue is null ? default(Optional<object>) : new Optional<object>(field.ConstantValue);
var receiver = new InstanceReferenceOperation(
InstanceReferenceKind.PatternInput, _semanticModel, nameSyntax, matchedType, constantValue, isImplicit: true);
return new FieldReferenceOperation(
field, isDeclaration: false, receiver, _semanticModel, nameSyntax, field.Type.TypeSymbol, constantValue, isImplicit: isImplicit);
}
case PropertySymbol property:
{
var receiver = new InstanceReferenceOperation(
InstanceReferenceKind.PatternInput, _semanticModel, nameSyntax, matchedType, constantValue: default, isImplicit: true);
return new PropertyReferenceOperation(
property, receiver, ImmutableArray<IArgumentOperation>.Empty, _semanticModel, nameSyntax, property.Type.TypeSymbol,
constantValue: default, isImplicit: isImplicit);
}
default:
// We should expose the symbol in this case somehow:
// https://github.com/dotnet/roslyn/issues/33175
return OperationFactory.CreateInvalidOperation(_semanticModel, nameSyntax, ImmutableArray<IOperation>.Empty, isImplicit);
}
}
}
}
......@@ -14,7 +14,7 @@ internal sealed partial class CSharpOperationFactory
{
private static readonly IConvertibleConversion s_boxedIdentityConversion = Conversion.Identity;
private static Optional<object> ConvertToOptional(ConstantValue value)
internal static Optional<object> ConvertToOptional(ConstantValue value)
{
return value != null && !value.IsBad ? new Optional<object>(value.Value) : default(Optional<object>);
}
......
......@@ -1492,7 +1492,10 @@ internal sealed partial class CSharpLazyRecursivePatternOperation : LazyRecursiv
private readonly CSharpOperationFactory _operationFactory;
private readonly BoundRecursivePattern _boundRecursivePattern;
public CSharpLazyRecursivePatternOperation(CSharpOperationFactory operationFactory, BoundRecursivePattern boundRecursivePattern, SemanticModel semanticModel)
public CSharpLazyRecursivePatternOperation(
CSharpOperationFactory operationFactory,
BoundRecursivePattern boundRecursivePattern,
SemanticModel semanticModel)
: base(inputType: boundRecursivePattern.InputType,
matchedType: boundRecursivePattern.DeclaredType?.Type ?? boundRecursivePattern.InputType.StrippedType(),
deconstructSymbol: boundRecursivePattern.DeconstructMethod,
......@@ -1501,8 +1504,8 @@ public CSharpLazyRecursivePatternOperation(CSharpOperationFactory operationFacto
syntax: boundRecursivePattern.Syntax,
isImplicit: boundRecursivePattern.WasCompilerGenerated)
{
this._operationFactory = operationFactory;
this._boundRecursivePattern = boundRecursivePattern;
_operationFactory = operationFactory;
_boundRecursivePattern = boundRecursivePattern;
}
public override ImmutableArray<IPatternOperation> CreateDeconstructionSubpatterns()
......@@ -1510,15 +1513,44 @@ public override ImmutableArray<IPatternOperation> CreateDeconstructionSubpattern
return _boundRecursivePattern.Deconstruction.IsDefault ? ImmutableArray<IPatternOperation>.Empty :
_boundRecursivePattern.Deconstruction.SelectAsArray((p, fac) => (IPatternOperation)fac.Create(p.Pattern), _operationFactory);
}
public override ImmutableArray<(ISymbol, IPatternOperation)> CreatePropertySubpatterns()
public override ImmutableArray<IPropertySubpatternOperation> CreatePropertySubpatterns()
{
return _boundRecursivePattern.Properties.IsDefault ? ImmutableArray<IPropertySubpatternOperation>.Empty :
_boundRecursivePattern.Properties.SelectAsArray((p, recursivePattern) => recursivePattern._operationFactory.CreatePropertySubpattern(p, recursivePattern.MatchedType), this);
}
}
internal sealed partial class CSharpLazyPropertySubpatternOperation : LazyPropertySubpatternOperation
{
private readonly BoundSubpattern _subpattern;
private readonly CSharpOperationFactory _operationFactory;
private readonly ITypeSymbol _matchedType;
public CSharpLazyPropertySubpatternOperation(
CSharpOperationFactory operationFactory,
BoundSubpattern subpattern,
ITypeSymbol matchedType,
SyntaxNode syntax,
SemanticModel semanticModel)
: base(semanticModel, syntax, isImplicit: false)
{
_subpattern = subpattern;
_operationFactory = operationFactory;
_matchedType = matchedType;
}
public override IOperation CreateMember()
{
return _operationFactory.CreatePropertySubpatternMember(_subpattern.Symbol, _matchedType, Syntax);
}
public override IPatternOperation CreatePattern()
{
return _boundRecursivePattern.Properties.IsDefault ? ImmutableArray<(ISymbol, IPatternOperation)>.Empty :
_boundRecursivePattern.Properties.SelectAsArray((p, fac) => ((ISymbol)p.Symbol, (IPatternOperation)fac.Create(p.Pattern)), _operationFactory);
return (IPatternOperation)_operationFactory.Create(_subpattern.Pattern);
}
}
/// <summary>
/// Represents a C# recursive pattern.
/// Represents a C# recursive pattern using ITuple.
/// </summary>
internal sealed partial class CSharpLazyITuplePatternOperation : LazyRecursivePatternOperation
{
......@@ -1534,8 +1566,8 @@ public CSharpLazyITuplePatternOperation(CSharpOperationFactory operationFactory,
syntax: boundITuplePattern.Syntax,
isImplicit: boundITuplePattern.WasCompilerGenerated)
{
this._operationFactory = operationFactory;
this._boundITuplePattern = boundITuplePattern;
_operationFactory = operationFactory;
_boundITuplePattern = boundITuplePattern;
}
public override ImmutableArray<IPatternOperation> CreateDeconstructionSubpatterns()
......@@ -1543,9 +1575,9 @@ public override ImmutableArray<IPatternOperation> CreateDeconstructionSubpattern
return _boundITuplePattern.Subpatterns.IsDefault ? ImmutableArray<IPatternOperation>.Empty :
_boundITuplePattern.Subpatterns.SelectAsArray((p, fac) => (IPatternOperation)fac.Create(p.Pattern), _operationFactory);
}
public override ImmutableArray<(ISymbol, IPatternOperation)> CreatePropertySubpatterns()
public override ImmutableArray<IPropertySubpatternOperation> CreatePropertySubpatterns()
{
return ImmutableArray<(ISymbol, IPatternOperation)>.Empty;
return ImmutableArray<IPropertySubpatternOperation>.Empty;
}
}
......@@ -1603,8 +1635,8 @@ internal sealed class CSharpLazySwitchExpressionOperation : LazySwitchExpression
public CSharpLazySwitchExpressionOperation(CSharpOperationFactory operationFactory, BoundSwitchExpression boundSwitchExpression, SemanticModel semanticModel)
: base(boundSwitchExpression.Type, semanticModel, boundSwitchExpression.Syntax, boundSwitchExpression.WasCompilerGenerated)
{
this._operationFactory = operationFactory;
this._switchExpression = boundSwitchExpression;
_operationFactory = operationFactory;
_switchExpression = boundSwitchExpression;
}
protected override IOperation CreateValue()
......@@ -1625,8 +1657,8 @@ internal sealed class CSharpLazySwitchExpressionArmOperation : LazySwitchExpress
public CSharpLazySwitchExpressionArmOperation(CSharpOperationFactory operationFactory, BoundSwitchExpressionArm boundSwitchExpressionArm, SemanticModel semanticModel)
: base(boundSwitchExpressionArm.Locals.Cast<CSharp.Symbols.LocalSymbol, ILocalSymbol>(), semanticModel, boundSwitchExpressionArm.Syntax, boundSwitchExpressionArm.WasCompilerGenerated)
{
this._operationFactory = operationFactory;
this._switchExpressionArm = boundSwitchExpressionArm;
_operationFactory = operationFactory;
_switchExpressionArm = boundSwitchExpressionArm;
}
protected override IOperation CreateGuard()
......
......@@ -651,7 +651,6 @@ void M(int? x, bool b, int x2, bool b2)
Statements (0)
Next (Regular) Block[B1]
Entering: {R1}
.locals {R1}
{
Locals: [System.Int32? y]
......@@ -669,7 +668,6 @@ void M(int? x, bool b, int x2, bool b2)
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32?) (Syntax: 'x')
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'var y') (InputType: System.Int32?, DeclaredSymbol: System.Int32? y, MatchesNull: True)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b2 = x2 is 1;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b2 = x2 is 1')
......@@ -683,15 +681,14 @@ void M(int? x, bool b, int x2, bool b2)
IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: '1') (InputType: System.Int32)
Value:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
Next (Regular) Block[B2]
Leaving: {R1}
}
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics);
......@@ -710,12 +707,47 @@ void M((int X, int Y)? x, bool b)
}/*</bind>*/
}
";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics();
string expectedOperationTree = @"
IBlockOperation (1 statements, 2 locals) (OperationKind.Block, Type: null) (Syntax: '{ ... }')
Locals: Local_1: (System.Int32 X, System.Int32 Y) p
Local_2: System.Int32 z
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = x is (1 ... var z } p;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = x is (1 ... : var z } p')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'x is (1, _) ... : var z } p')
Value:
IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: (System.Int32 X, System.Int32 Y)?) (Syntax: 'x')
Pattern:
IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null) (Syntax: '(1, _) { It ... : var z } p') (InputType: (System.Int32 X, System.Int32 Y)?, DeclaredSymbol: (System.Int32 X, System.Int32 Y) p, MatchedType: (System.Int32 X, System.Int32 Y), DeconstructSymbol: null)
DeconstructionSubpatterns (2):
IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: '1') (InputType: System.Int32)
Value:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
IDiscardPatternOperation (OperationKind.DiscardPattern, Type: null) (Syntax: '_') (InputType: System.Int32)
PropertySubpatterns (1):
IPropertySubpatternOperation (OperationKind.None, Type: null) (Syntax: 'Item1: var z')
Member:
IFieldReferenceOperation: System.Int32 (System.Int32 X, System.Int32 Y).Item1 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Item1')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: (System.Int32 X, System.Int32 Y), IsImplicit) (Syntax: 'Item1')
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'var z') (InputType: System.Int32, DeclaredSymbol: System.Int32 z, MatchesNull: True)
";
VerifyOperationTreeForTest<BlockSyntax>(compilation, expectedOperationTree);
string expectedFlowGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1}
.locals {R1}
{
Locals: [(System.Int32 X, System.Int32 Y) p] [System.Int32 z]
......@@ -739,17 +771,105 @@ void M((int X, int Y)? x, bool b)
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
IDiscardPatternOperation (OperationKind.DiscardPattern, Type: null) (Syntax: '_') (InputType: System.Int32)
PropertySubpatterns (1):
MatchedSymbol: System.Int32 (System.Int32 X, System.Int32 Y).Item1, Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'var z') (InputType: System.Int32, DeclaredSymbol: System.Int32 z, MatchesNull: True)
IPropertySubpatternOperation (OperationKind.None, Type: null) (Syntax: 'Item1: var z')
Member:
IFieldReferenceOperation: System.Int32 (System.Int32 X, System.Int32 Y).Item1 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Item1')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: (System.Int32 X, System.Int32 Y), IsImplicit) (Syntax: 'Item1')
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'var z') (InputType: System.Int32, DeclaredSymbol: System.Int32 z, MatchesNull: True)
Next (Regular) Block[B2]
Leaving: {R1}
}
Block[B2] - Exit
Predecessors: [B1]
Statements (0)";
VerifyFlowGraphForTest<BlockSyntax>(compilation, expectedFlowGraph);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow, CompilerFeature.Patterns)]
[Fact]
public void IsPattern_NoControlFlow_03()
{
string source = @"
class C
{
void M((int X, (int Y, int Z))? tuple, bool b)
/*<bind>*/{
b = tuple is (1, _) { Item1: var x, Item2: { Y: 1, Z: var z } } p;
}/*</bind>*/
}
";
string expectedFlowGraph = @"
Block[B0] - Entry
Statements (0)
Next (Regular) Block[B1]
Entering: {R1}
.locals {R1}
{
Locals: [(System.Int32 X, (System.Int32 Y, System.Int32 Z)) p] [System.Int32 x] [System.Int32 z]
Block[B1] - Block
Predecessors: [B0]
Statements (1)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = tuple i ... ar z } } p;')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = tuple i ... var z } } p')
Left:
IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b')
Right:
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'tuple is (1 ... var z } } p')
Value:
IParameterReferenceOperation: tuple (OperationKind.ParameterReference, Type: (System.Int32 X, (System.Int32 Y, System.Int32 Z))?) (Syntax: 'tuple')
Pattern:
IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null) (Syntax: '(1, _) { It ... var z } } p') (InputType: (System.Int32 X, (System.Int32 Y, System.Int32 Z))?, DeclaredSymbol: (System.Int32 X, (System.Int32 Y, System.Int32 Z)) p, MatchedType: (System.Int32 X, (System.Int32 Y, System.Int32 Z)), DeconstructSymbol: null)
DeconstructionSubpatterns (2):
IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: '1') (InputType: System.Int32)
Value:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
IDiscardPatternOperation (OperationKind.DiscardPattern, Type: null) (Syntax: '_') (InputType: (System.Int32 Y, System.Int32 Z))
PropertySubpatterns (2):
IPropertySubpatternOperation (OperationKind.None, Type: null) (Syntax: 'Item1: var x')
Member:
IFieldReferenceOperation: System.Int32 (System.Int32 X, (System.Int32 Y, System.Int32 Z)).Item1 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Item1')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: (System.Int32 X, (System.Int32 Y, System.Int32 Z)), IsImplicit) (Syntax: 'Item1')
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'var x') (InputType: System.Int32, DeclaredSymbol: System.Int32 x, MatchesNull: True)
IPropertySubpatternOperation (OperationKind.None, Type: null) (Syntax: 'Item2: { Y: ... Z: var z }')
Member:
IFieldReferenceOperation: (System.Int32 Y, System.Int32 Z) (System.Int32 X, (System.Int32 Y, System.Int32 Z)).Item2 (OperationKind.FieldReference, Type: (System.Int32 Y, System.Int32 Z)) (Syntax: 'Item2')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: (System.Int32 X, (System.Int32 Y, System.Int32 Z)), IsImplicit) (Syntax: 'Item2')
Pattern:
IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null) (Syntax: '{ Y: 1, Z: var z }') (InputType: (System.Int32 Y, System.Int32 Z), DeclaredSymbol: null, MatchedType: (System.Int32 Y, System.Int32 Z), DeconstructSymbol: null)
DeconstructionSubpatterns (0)
PropertySubpatterns (2):
IPropertySubpatternOperation (OperationKind.None, Type: null) (Syntax: 'Y: 1')
Member:
IFieldReferenceOperation: System.Int32 (System.Int32 Y, System.Int32 Z).Y (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Y')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: (System.Int32 Y, System.Int32 Z), IsImplicit) (Syntax: 'Y')
Pattern:
IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: '1') (InputType: System.Int32)
Value:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
IPropertySubpatternOperation (OperationKind.None, Type: null) (Syntax: 'Z: var z')
Member:
IFieldReferenceOperation: System.Int32 (System.Int32 Y, System.Int32 Z).Z (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Z')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: (System.Int32 Y, System.Int32 Z), IsImplicit) (Syntax: 'Z')
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'var z') (InputType: System.Int32, DeclaredSymbol: System.Int32 z, MatchesNull: True)
Next (Regular) Block[B2]
Leaving: {R1}
}
Block[B2] - Exit
Predecessors: [B1]
Statements (0)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics);
......@@ -882,14 +1002,186 @@ void M((int X, int Y) tuple, bool b)
Value:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
PropertySubpatterns (1):
MatchedSymbol: System.Int32 (System.Int32 X, System.Int32 Y).Item1, Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'int x') (InputType: System.Int32, DeclaredSymbol: System.Int32 x, MatchesNull: False)
IPropertySubpatternOperation (OperationKind.None, Type: null) (Syntax: 'Item1: int x')
Member:
IFieldReferenceOperation: System.Int32 (System.Int32 X, System.Int32 Y).Item1 (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Item1')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: (System.Int32 X, System.Int32 Y), IsImplicit) (Syntax: 'Item1')
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'int x') (InputType: System.Int32, DeclaredSymbol: System.Int32 x, MatchesNull: False)
";
var expectedDiagnostics = DiagnosticDescription.None;
VerifyOperationTreeAndDiagnosticsForTest<IsPatternExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Patterns)]
[Fact]
public void IsPattern_BadRecursivePattern_01()
{
string source = @"
class C
{
void M((int X, int Y) tuple, bool b)
{
if (/*<bind>*/tuple is (1, 2) { NotFound: int x } y/*</bind>*/) { }
}
}
";
string expectedOperationTree = @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'tuple is (1 ... : int x } y')
Value:
IParameterReferenceOperation: tuple (OperationKind.ParameterReference, Type: (System.Int32 X, System.Int32 Y)) (Syntax: 'tuple')
Pattern:
IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid) (Syntax: '(1, 2) { No ... : int x } y') (InputType: (System.Int32 X, System.Int32 Y), DeclaredSymbol: (System.Int32 X, System.Int32 Y) y, MatchedType: (System.Int32 X, System.Int32 Y), DeconstructSymbol: null)
DeconstructionSubpatterns (2):
IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: '1') (InputType: System.Int32)
Value:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: '2') (InputType: System.Int32)
Value:
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2')
PropertySubpatterns (1):
IPropertySubpatternOperation (OperationKind.None, Type: null, IsInvalid) (Syntax: 'NotFound: int x')
Member:
IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'NotFound')
Children(0)
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'int x') (InputType: ?, DeclaredSymbol: System.Int32 x, MatchesNull: False)
";
var expectedDiagnostics = new[] {
// file.cs(6,41): error CS0117: '(int X, int Y)' does not contain a definition for 'NotFound'
// if (/*<bind>*/tuple is (1, 2) { NotFound: int x } y/*</bind>*/) { }
Diagnostic(ErrorCode.ERR_NoSuchMember, "NotFound").WithArguments("(int X, int Y)", "NotFound").WithLocation(6, 41)
};
VerifyOperationTreeAndDiagnosticsForTest<IsPatternExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Patterns)]
[Fact]
public void IsPattern_BadRecursivePattern_02()
{
var vbSource = @"
Public Class C1
Public Property Prop(index As Integer) As Integer
Get
Return 1
End Get
Set
End Set
End Property
End Class
";
var vbCompilation = CreateVisualBasicCompilation(vbSource);
var source = @"
class C
{
void M1(object o, bool b)
{
b = /*<bind>*/o is C1 { Prop[1]: var x }/*</bind>*/;
}
}";
var compilation = CreateCompilation(source, new[] { vbCompilation.EmitToImageReference() });
compilation.VerifyDiagnostics(
// (6,33): error CS8503: A property subpattern requires a reference to the property or field to be matched, e.g. '{ Name: Prop[1] }'
// b = /*<bind>*/o is C1 { Prop[1]: var x }/*</bind>*/;
Diagnostic(ErrorCode.ERR_PropertyPatternNameMissing, "Prop[1]").WithArguments("Prop[1]").WithLocation(6, 33),
// (6,33): error CS0103: The name 'Prop' does not exist in the current context
// b = /*<bind>*/o is C1 { Prop[1]: var x }/*</bind>*/;
Diagnostic(ErrorCode.ERR_NameNotInContext, "Prop").WithArguments("Prop").WithLocation(6, 33),
// (6,40): error CS1003: Syntax error, ',' expected
// b = /*<bind>*/o is C1 { Prop[1]: var x }/*</bind>*/;
Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(6, 40),
// (6,42): error CS1003: Syntax error, ',' expected
// b = /*<bind>*/o is C1 { Prop[1]: var x }/*</bind>*/;
Diagnostic(ErrorCode.ERR_SyntaxError, "var").WithArguments(",", "").WithLocation(6, 42));
var expectedOperationTree = @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'o is C1 { P ... 1]: var x }')
Value:
IParameterReferenceOperation: o (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'o')
Pattern:
IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid) (Syntax: 'C1 { Prop[1]: var x }') (InputType: System.Object, DeclaredSymbol: null, MatchedType: C1, DeconstructSymbol: null)
DeconstructionSubpatterns (0)
PropertySubpatterns (2):
IPropertySubpatternOperation (OperationKind.None, Type: null, IsInvalid) (Syntax: 'Prop[1]')
Member:
IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid, IsImplicit) (Syntax: 'Prop[1]')
Children(0)
Pattern:
IConstantPatternOperation (OperationKind.ConstantPattern, Type: null, IsInvalid) (Syntax: 'Prop[1]') (InputType: ?)
Value:
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'Prop[1]')
Children(2):
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1')
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'Prop')
Children(0)
IPropertySubpatternOperation (OperationKind.None, Type: null, IsInvalid) (Syntax: 'var x')
Member:
IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid, IsImplicit) (Syntax: 'var x')
Children(0)
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null, IsInvalid) (Syntax: 'var x') (InputType: ?, DeclaredSymbol: ? x, MatchesNull: True)
";
VerifyOperationTreeForTest<IsPatternExpressionSyntax>(compilation, expectedOperationTree);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Patterns)]
[Fact]
public void IsPattern_BadRecursivePattern_03()
{
var vbSource = @"
Public Class C1
Public Property Prop(index As Integer) As Integer
Get
Return 1
End Get
Set
End Set
End Property
End Class
";
var vbCompilation = CreateVisualBasicCompilation(vbSource);
var source = @"
class C
{
void M1(object o, bool b)
{
b = /*<bind>*/o is C1 { Prop: var x }/*</bind>*/;
}
}";
var compilation = CreateCompilation(source, new[] { vbCompilation.EmitToImageReference() });
compilation.VerifyDiagnostics(
// (6,33): error CS0154: The property or indexer 'Prop' cannot be used in this context because it lacks the get accessor
// b = /*<bind>*/o is C1 { Prop: var x }/*</bind>*/;
Diagnostic(ErrorCode.ERR_PropertyLacksGet, "Prop").WithArguments("Prop").WithLocation(6, 33));
var expectedOperationTree = @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'o is C1 { Prop: var x }')
Value:
IParameterReferenceOperation: o (OperationKind.ParameterReference, Type: System.Object) (Syntax: 'o')
Pattern:
IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid) (Syntax: 'C1 { Prop: var x }') (InputType: System.Object, DeclaredSymbol: null, MatchedType: C1, DeconstructSymbol: null)
DeconstructionSubpatterns (0)
PropertySubpatterns (1):
IPropertySubpatternOperation (OperationKind.None, Type: null, IsInvalid) (Syntax: 'Prop: var x')
Member:
IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'Prop')
Children(0)
Pattern:
IDeclarationPatternOperation (OperationKind.DeclarationPattern, Type: null) (Syntax: 'var x') (InputType: ?, DeclaredSymbol: ? x, MatchesNull: True)";
VerifyOperationTreeForTest<IsPatternExpressionSyntax>(compilation, expectedOperationTree);
}
[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow, CompilerFeature.Patterns)]
[Fact]
public void IsPattern_ControlFlowInPattern()
......
......@@ -6547,20 +6547,30 @@ public override IOperation VisitDeclarationPattern(IDeclarationPatternOperation
operation.Syntax, IsImplicit(operation));
}
public override IOperation VisitRecursivePattern(IRecursivePatternOperation operation, int? argument)
internal override IOperation VisitRecursivePattern(IRecursivePatternOperation operation, int? argument)
{
return new RecursivePatternOperation(
inputType: operation.InputType,
matchedType: operation.MatchedType,
operation.DeconstructSymbol,
operation.DeconstructionSubpatterns.SelectAsArray(p => (IPatternOperation)Visit(p)),
operation.PropertySubpatterns.SelectAsArray(p => (p.Item1, (IPatternOperation)Visit(p.Item2))),
operation.PropertySubpatterns.SelectAsArray(p => (IPropertySubpatternOperation)Visit(p)),
operation.DeclaredSymbol,
semanticModel: null,
operation.Syntax,
IsImplicit(operation));
}
internal override IOperation VisitPropertySubpattern(IPropertySubpatternOperation operation, int? argument)
{
return new PropertySubpatternOperation(
semanticModel: null,
operation.Syntax,
IsImplicit(operation),
Visit(operation.Member),
(IPatternOperation)Visit(operation.Pattern));
}
public override IOperation VisitDelegateCreation(IDelegateCreationOperation operation, int? captureIdForResult)
{
return new DelegateCreationOperation(Visit(operation.Target), semanticModel: null,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Operations
{
/// <summary>
/// Represents an element of a property subpattern, which identifies a member to be matched and the
/// pattern to match it against.
/// </summary>
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
internal interface IPropertySubpatternOperation : IOperation
{
/// <summary>
/// The member being matched in a property subpattern. This can be a <see cref="IMemberReferenceOperation"/>
/// in non-error cases, or an <see cref="IInvalidOperation"/> in error cases.
/// </summary>
// The symbol should be exposed for error cases somehow:
// https://github.com/dotnet/roslyn/issues/33175
IOperation Member { get; }
/// <summary>
/// The pattern to which the member is matched in a property subpattern.
/// </summary>
IPatternOperation Pattern { get; }
}
}
......@@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Operations
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface IRecursivePatternOperation : IPatternOperation
internal interface IRecursivePatternOperation : IPatternOperation
{
/// <summary>
/// The type accepted for the recursive pattern.
......@@ -33,7 +33,7 @@ public interface IRecursivePatternOperation : IPatternOperation
/// <summary>
/// This contains the (symbol, property) pairs within a property subpattern.
/// </summary>
ImmutableArray<(ISymbol, IPatternOperation)> PropertySubpatterns { get; }
ImmutableArray<IPropertySubpatternOperation> PropertySubpatterns { get; }
/// <summary>
/// Symbol declared by the pattern.
......
......@@ -17,5 +17,9 @@ public enum InstanceReferenceKind
/// anonymous type creation initializer, or to the object being referred to in a VB With statement.
/// </summary>
ImplicitReceiver,
/// <summary>
/// Reference to the value being matching in a property subpattern.
/// </summary>
PatternInput,
}
}
......@@ -535,7 +535,7 @@ public override IOperation VisitDeclarationPattern(IDeclarationPatternOperation
((Operation)operation).OwningSemanticModel, operation.Syntax, operation.IsImplicit);
}
public override IOperation VisitRecursivePattern(IRecursivePatternOperation operation, object argument)
internal override IOperation VisitRecursivePattern(IRecursivePatternOperation operation, object argument)
{
return new RecursivePatternOperation(
operation.InputType,
......@@ -549,6 +549,16 @@ public override IOperation VisitRecursivePattern(IRecursivePatternOperation oper
operation.IsImplicit);
}
internal override IOperation VisitPropertySubpattern(IPropertySubpatternOperation operation, object argument)
{
return new PropertySubpatternOperation(
semanticModel: ((Operation)operation).OwningSemanticModel,
operation.Syntax,
operation.IsImplicit,
Visit(operation.Member),
Visit(operation.Pattern));
}
public override IOperation VisitPatternCaseClause(IPatternCaseClauseOperation operation, object argument)
{
return new PatternCaseClauseOperation(operation.Label, Visit(operation.Pattern), Visit(operation.Guard), ((Operation)operation).OwningSemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit);
......
......@@ -7965,7 +7965,8 @@ internal abstract partial class BaseRecursivePatternOperation : Operation, IRecu
ITypeSymbol inputType,
ITypeSymbol matchedType,
ISymbol deconstructSymbol,
ISymbol declaredSymbol, SemanticModel semanticModel,
ISymbol declaredSymbol,
SemanticModel semanticModel,
SyntaxNode syntax,
bool isImplicit)
: base(OperationKind.RecursivePattern, semanticModel, syntax, type: default, constantValue: default, isImplicit)
......@@ -7979,7 +7980,7 @@ internal abstract partial class BaseRecursivePatternOperation : Operation, IRecu
public ITypeSymbol MatchedType { get; }
public ISymbol DeconstructSymbol { get; }
public abstract ImmutableArray<IPatternOperation> DeconstructionSubpatterns { get; }
public abstract ImmutableArray<(ISymbol, IPatternOperation)> PropertySubpatterns { get; }
public abstract ImmutableArray<IPropertySubpatternOperation> PropertySubpatterns { get; }
public ISymbol DeclaredSymbol { get; }
public override IEnumerable<IOperation> Children
{
......@@ -7992,7 +7993,7 @@ public override IEnumerable<IOperation> Children
foreach (var p in PropertySubpatterns)
{
yield return p.Item2;
yield return p;
}
}
}
......@@ -8017,7 +8018,7 @@ internal sealed partial class RecursivePatternOperation : BaseRecursivePatternOp
ITypeSymbol matchedType,
ISymbol deconstructSymbol,
ImmutableArray<IPatternOperation> deconstructionSubpatterns,
ImmutableArray<(ISymbol, IPatternOperation)> propertySubpatterns,
ImmutableArray<IPropertySubpatternOperation> propertySubpatterns,
ISymbol declaredSymbol, SemanticModel semanticModel,
SyntaxNode syntax,
bool isImplicit)
......@@ -8025,32 +8026,30 @@ internal sealed partial class RecursivePatternOperation : BaseRecursivePatternOp
{
SetParentOperation(deconstructionSubpatterns, this);
DeconstructionSubpatterns = deconstructionSubpatterns;
foreach (var p in propertySubpatterns)
{
SetParentOperation(p.Item2, this);
}
SetParentOperation(propertySubpatterns, this);
PropertySubpatterns = propertySubpatterns;
}
public override ImmutableArray<IPatternOperation> DeconstructionSubpatterns { get; }
public override ImmutableArray<(ISymbol, IPatternOperation)> PropertySubpatterns { get; }
public override ImmutableArray<IPropertySubpatternOperation> PropertySubpatterns { get; }
}
internal abstract partial class LazyRecursivePatternOperation : BaseRecursivePatternOperation
{
private ImmutableArray<IPatternOperation> _lazyDeconstructionSubpatterns;
private ImmutableArray<(ISymbol, IPatternOperation)> _lazyPropertySubpatterns;
private ImmutableArray<IPropertySubpatternOperation> _lazyPropertySubpatterns;
public LazyRecursivePatternOperation(
ITypeSymbol inputType,
ITypeSymbol matchedType,
ISymbol deconstructSymbol,
ISymbol declaredSymbol, SemanticModel semanticModel,
ISymbol declaredSymbol,
SemanticModel semanticModel,
SyntaxNode syntax,
bool isImplicit)
: base(inputType, matchedType, deconstructSymbol, declaredSymbol, semanticModel, syntax, isImplicit)
{
}
public abstract ImmutableArray<IPatternOperation> CreateDeconstructionSubpatterns();
public abstract ImmutableArray<(ISymbol, IPatternOperation)> CreatePropertySubpatterns();
public abstract ImmutableArray<IPropertySubpatternOperation> CreatePropertySubpatterns();
public override ImmutableArray<IPatternOperation> DeconstructionSubpatterns
{
get
......@@ -8069,7 +8068,7 @@ public override ImmutableArray<IPatternOperation> DeconstructionSubpatterns
return _lazyDeconstructionSubpatterns;
}
}
public override ImmutableArray<(ISymbol, IPatternOperation)> PropertySubpatterns
public override ImmutableArray<IPropertySubpatternOperation> PropertySubpatterns
{
get
{
......@@ -8078,7 +8077,7 @@ public override ImmutableArray<IPatternOperation> DeconstructionSubpatterns
var propertySubpatterns = CreatePropertySubpatterns();
foreach (var propertySubpattern in propertySubpatterns)
{
SetParentOperation(propertySubpattern.Item2, this);
SetParentOperation(propertySubpattern, this);
}
ImmutableInterlocked.InterlockedInitialize(ref _lazyPropertySubpatterns, propertySubpatterns);
......@@ -8089,6 +8088,100 @@ public override ImmutableArray<IPatternOperation> DeconstructionSubpatterns
}
}
internal abstract partial class BasePropertySubpatternOperation : Operation, IPropertySubpatternOperation
{
public BasePropertySubpatternOperation(
SemanticModel semanticModel,
SyntaxNode syntax,
bool isImplicit)
: base(OperationKind.None, semanticModel, syntax, type: default, constantValue: default, isImplicit)
{
}
public abstract IOperation Member { get; }
public abstract IPatternOperation Pattern { get; }
public override IEnumerable<IOperation> Children
{
get
{
if (Member != null)
yield return Member;
if (Pattern != null)
yield return Pattern;
}
}
public override void Accept(OperationVisitor visitor)
{
visitor.VisitPropertySubpattern(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitPropertySubpattern(this, argument);
}
}
internal sealed partial class PropertySubpatternOperation : BasePropertySubpatternOperation
{
public PropertySubpatternOperation(
SemanticModel semanticModel,
SyntaxNode syntax,
bool isImplicit,
IOperation member,
IPatternOperation pattern)
: base(semanticModel, syntax, isImplicit)
{
SetParentOperation(member, this);
Member = member;
SetParentOperation(pattern, this);
Pattern = pattern;
}
public override IOperation Member { get; }
public override IPatternOperation Pattern { get; }
}
internal abstract partial class LazyPropertySubpatternOperation : BasePropertySubpatternOperation
{
private IOperation _lazyMember = s_unset;
private IPatternOperation _lazyPattern = s_unsetPattern;
public LazyPropertySubpatternOperation(
SemanticModel semanticModel,
SyntaxNode syntax,
bool isImplicit)
: base(semanticModel, syntax, isImplicit)
{
}
public abstract IOperation CreateMember();
public abstract IPatternOperation CreatePattern();
public override IOperation Member
{
get
{
if (_lazyMember == s_unset)
{
var member = CreateMember();
SetParentOperation(member, this);
Interlocked.CompareExchange(ref _lazyMember, member, s_unset);
}
return _lazyMember;
}
}
public override IPatternOperation Pattern
{
get
{
if (_lazyPattern == s_unsetPattern)
{
var pattern = CreatePattern();
SetParentOperation(pattern, this);
Interlocked.CompareExchange(ref _lazyPattern, pattern, s_unsetPattern);
}
return _lazyPattern;
}
}
}
/// <summary>
/// Represents a C# pattern case clause.
/// </summary>
......
......@@ -505,7 +505,12 @@ public virtual void VisitDeclarationPattern(IDeclarationPatternOperation operati
DefaultVisit(operation);
}
public virtual void VisitRecursivePattern(IRecursivePatternOperation operation)
internal virtual void VisitRecursivePattern(IRecursivePatternOperation operation)
{
DefaultVisit(operation);
}
internal virtual void VisitPropertySubpattern(IPropertySubpatternOperation operation)
{
DefaultVisit(operation);
}
......@@ -1113,7 +1118,12 @@ public virtual TResult VisitDeclarationPattern(IDeclarationPatternOperation oper
return DefaultVisit(operation, argument);
}
public virtual TResult VisitRecursivePattern(IRecursivePatternOperation operation, TArgument argument)
internal virtual TResult VisitRecursivePattern(IRecursivePatternOperation operation, TArgument argument)
{
return DefaultVisit(operation, argument);
}
internal virtual TResult VisitPropertySubpattern(IPropertySubpatternOperation operation, TArgument argument)
{
return DefaultVisit(operation, argument);
}
......
......@@ -16,15 +16,10 @@ Microsoft.CodeAnalysis.Operations.IDeclarationPatternOperation.MatchedType.get -
Microsoft.CodeAnalysis.Operations.IDeclarationPatternOperation.MatchesNull.get -> bool
Microsoft.CodeAnalysis.Operations.IDiscardPatternOperation
Microsoft.CodeAnalysis.Operations.IPatternOperation.InputType.get -> Microsoft.CodeAnalysis.ITypeSymbol
Microsoft.CodeAnalysis.Operations.InstanceReferenceKind.PatternInput = 2 -> Microsoft.CodeAnalysis.Operations.InstanceReferenceKind
Microsoft.CodeAnalysis.SymbolDisplayPartKind.ConstantName = 30 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind
Microsoft.CodeAnalysis.SymbolDisplayPartKind.EnumMemberName = 28 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind
Microsoft.CodeAnalysis.SymbolDisplayPartKind.ExtensionMethodName = 29 -> Microsoft.CodeAnalysis.SymbolDisplayPartKind
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.DeclaredSymbol.get -> Microsoft.CodeAnalysis.ISymbol
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.DeconstructSymbol.get -> Microsoft.CodeAnalysis.ISymbol
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.DeconstructionSubpatterns.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Operations.IPatternOperation>
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.MatchedType.get -> Microsoft.CodeAnalysis.ITypeSymbol
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.PropertySubpatterns.get -> System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.ISymbol, Microsoft.CodeAnalysis.Operations.IPatternOperation)>
Microsoft.CodeAnalysis.Operations.ISwitchExpressionArmOperation
Microsoft.CodeAnalysis.Operations.ISwitchExpressionArmOperation.Guard.get -> Microsoft.CodeAnalysis.IOperation
Microsoft.CodeAnalysis.Operations.ISwitchExpressionArmOperation.Locals.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.ILocalSymbol>
......@@ -212,7 +207,6 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitIsNull(Microsoft
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitRangeOperation(Microsoft.CodeAnalysis.Operations.IRangeOperation operation) -> void
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitReDim(Microsoft.CodeAnalysis.Operations.IReDimOperation operation) -> void
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitReDimClause(Microsoft.CodeAnalysis.Operations.IReDimClauseOperation operation) -> void
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitRecursivePattern(Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation operation) -> void
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitStaticLocalInitializationSemaphore(Microsoft.CodeAnalysis.FlowAnalysis.IStaticLocalInitializationSemaphoreOperation operation) -> void
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSwitchExpression(Microsoft.CodeAnalysis.Operations.ISwitchExpressionOperation operation) -> void
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor.VisitSwitchExpressionArm(Microsoft.CodeAnalysis.Operations.ISwitchExpressionArmOperation operation) -> void
......@@ -226,7 +220,6 @@ virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.V
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.VisitRangeOperation(Microsoft.CodeAnalysis.Operations.IRangeOperation operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.VisitReDim(Microsoft.CodeAnalysis.Operations.IReDimOperation operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.VisitReDimClause(Microsoft.CodeAnalysis.Operations.IReDimClauseOperation operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.VisitRecursivePattern(Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.VisitStaticLocalInitializationSemaphore(Microsoft.CodeAnalysis.FlowAnalysis.IStaticLocalInitializationSemaphoreOperation operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.VisitSwitchExpression(Microsoft.CodeAnalysis.Operations.ISwitchExpressionOperation operation, TArgument argument) -> TResult
virtual Microsoft.CodeAnalysis.Operations.OperationVisitor<TArgument, TResult>.VisitSwitchExpressionArm(Microsoft.CodeAnalysis.Operations.ISwitchExpressionArmOperation operation, TArgument argument) -> TResult
......@@ -1728,14 +1728,16 @@ private static bool CanBeInControlFlowGraph(IOperation n)
case OperationKind.InstanceReference:
// Implicit instance receivers, except for anonymous type creations, are expected to have been removed when dealing with creations.
return ((IInstanceReferenceOperation)n).ReferenceKind == InstanceReferenceKind.ContainingTypeInstance ||
((IInstanceReferenceOperation)n).ReferenceKind == InstanceReferenceKind.ImplicitReceiver &&
n.Type.IsAnonymousType &&
n.Parent is IPropertyReferenceOperation propertyReference &&
propertyReference.Instance == n &&
propertyReference.Parent is ISimpleAssignmentOperation simpleAssignment &&
simpleAssignment.Target == propertyReference &&
simpleAssignment.Parent.Kind == OperationKind.AnonymousObjectCreation;
var instanceReference = (IInstanceReferenceOperation)n;
return instanceReference.ReferenceKind == InstanceReferenceKind.ContainingTypeInstance ||
instanceReference.ReferenceKind == InstanceReferenceKind.PatternInput ||
(instanceReference.ReferenceKind == InstanceReferenceKind.ImplicitReceiver &&
n.Type.IsAnonymousType &&
n.Parent is IPropertyReferenceOperation propertyReference &&
propertyReference.Instance == n &&
propertyReference.Parent is ISimpleAssignmentOperation simpleAssignment &&
simpleAssignment.Target == propertyReference &&
simpleAssignment.Parent.Kind == OperationKind.AnonymousObjectCreation);
case OperationKind.None:
return !(n is IPlaceholderOperation);
......
......@@ -1762,7 +1762,7 @@ public override void VisitDeclarationPattern(IDeclarationPatternOperation operat
LogNewLine();
}
public override void VisitRecursivePattern(IRecursivePatternOperation operation)
internal override void VisitRecursivePattern(IRecursivePatternOperation operation)
{
LogString(nameof(IRecursivePatternOperation));
LogPatternProperties(operation);
......@@ -1773,11 +1773,17 @@ public override void VisitRecursivePattern(IRecursivePatternOperation operation)
LogNewLine();
VisitArray(operation.DeconstructionSubpatterns, $"{nameof(operation.DeconstructionSubpatterns)} ", true, true);
VisitArrayCommon(operation.PropertySubpatterns, $"{nameof(operation.PropertySubpatterns)} ", true, true, subpat =>
{
LogSymbol(subpat.Item1, "MatchedSymbol");
Visit(subpat.Item2, ", Pattern");
});
VisitArray(operation.PropertySubpatterns, $"{nameof(operation.PropertySubpatterns)} ", true, true);
}
internal override void VisitPropertySubpattern(IPropertySubpatternOperation operation)
{
LogString(nameof(IPropertySubpatternOperation));
LogCommonProperties(operation);
LogNewLine();
Visit(operation.Member, $"{nameof(operation.Member)}");
Visit(operation.Pattern, $"{nameof(operation.Pattern)}");
}
public override void VisitIsPattern(IIsPatternOperation operation)
......
......@@ -1151,7 +1151,7 @@ public override void VisitDeclarationPattern(IDeclarationPatternOperation operat
Assert.Empty(operation.Children);
}
public override void VisitRecursivePattern(IRecursivePatternOperation operation)
internal override void VisitRecursivePattern(IRecursivePatternOperation operation)
{
Assert.Equal(OperationKind.RecursivePattern, operation.Kind);
VisitPatternCommon(operation);
......@@ -1186,25 +1186,38 @@ public override void VisitRecursivePattern(IRecursivePatternOperation operation)
foreach (var subpat in operation.PropertySubpatterns)
{
var (symbol, pattern) = subpat;
switch (symbol)
{
case null: // error case
break;
case IFieldSymbol field:
case IPropertySymbol prop:
case IErrorTypeSymbol error:
break;
default:
Assert.True(false, $"Unexpected symbol {symbol}");
break;
}
Assert.True(subpat is IPropertySubpatternOperation);
}
IEnumerable<IOperation> children = operation.DeconstructionSubpatterns.Cast<IOperation>();
children = children.Concat(operation.PropertySubpatterns.Select(x => x.Item2));
children = children.Concat(operation.PropertySubpatterns);
AssertEx.Equal(children, operation.Children);
}
internal override void VisitPropertySubpattern(IPropertySubpatternOperation operation)
{
Assert.NotNull(operation.Pattern);
var children = new IOperation[] { operation.Member, operation.Pattern };
AssertEx.Equal(children, operation.Children);
if (operation.Member.Kind == OperationKind.Invalid)
{
return;
}
Assert.True(operation.Member is IMemberReferenceOperation);
var member = (IMemberReferenceOperation)operation.Member;
switch (member.Member)
{
case IFieldSymbol field:
case IPropertySymbol prop:
case IErrorTypeSymbol error:
break;
case var symbol:
Assert.True(false, $"Unexpected symbol {symbol}");
break;
}
}
public override void VisitSwitchExpression(ISwitchExpressionOperation operation)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Operations;
namespace Microsoft.CodeAnalysis
......@@ -57,7 +58,7 @@ public static ValueUsageInfo GetValueUsageInfo(this IOperation operation)
//
return ValueUsageInfo.Write;
case IRecursivePatternOperation _:
case IOperation iop when iop.GetType().GetInterfaces().Any(i => i.Name == "IRecursivePatternOperation"):
// A declaration pattern within a recursive pattern is a
// write for the declared local.
// For example, 'x' is defined and assigned the value from 'obj' below:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册