Skip to content

Commit

Permalink
Merge pull request #9233 from gafter/patterns-frog
Browse files Browse the repository at this point in the history
Implement SymbolInfo for the property name of a property pattern
  • Loading branch information
gafter committed Feb 28, 2016
2 parents 69441d5 + 75aaa92 commit 092bab9
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 86 deletions.
59 changes: 38 additions & 21 deletions src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, BoundExpr
// use a dedicated bound node for that form.
var properties = correspondingMembers;
var boundPatterns = BindRecursiveSubPropertyPatterns(node, properties, type, diagnostics);
return new BoundPropertyPattern(node, type, boundPatterns, properties, hasErrors: hasErrors);
var builder = ArrayBuilder<BoundSubPropertyPattern>.GetInstance(properties.Length);
for (int i = 0; i < properties.Length; i++)
{
builder.Add(new BoundSubPropertyPattern(node.PatternList.SubPatterns[i], properties[i].GetTypeOrReturnType(), properties[i], LookupResultKind.Empty, boundPatterns[i], hasErrors));
}

return new BoundPropertyPattern(node, type, builder.ToImmutableAndFree(), hasErrors: hasErrors);
}

private ImmutableArray<BoundPattern> BindRecursiveSubPropertyPatterns(RecursivePatternSyntax node, ImmutableArray<Symbol> properties, NamedTypeSymbol type, DiagnosticBag diagnostics)
Expand Down Expand Up @@ -162,21 +168,20 @@ private BoundPattern BindPropertyPattern(PropertyPatternSyntax node, BoundExpres
{
var type = (NamedTypeSymbol)this.BindType(node.Type, diagnostics);
hasErrors = hasErrors || CheckValidPatternType(node.Type, operand, operandType, type, false, diagnostics);
var properties = ArrayBuilder<Symbol>.GetInstance();
var boundPatterns = BindSubPropertyPatterns(node, properties, type, diagnostics);
hasErrors |= properties.Count != boundPatterns.Length;
return new BoundPropertyPattern(node, type, boundPatterns, properties.ToImmutableAndFree(), hasErrors: hasErrors);
var boundPatterns = BindSubPropertyPatterns(node, type, diagnostics);
return new BoundPropertyPattern(node, type, boundPatterns, hasErrors: hasErrors);
}

private ImmutableArray<BoundPattern> BindSubPropertyPatterns(PropertyPatternSyntax node, ArrayBuilder<Symbol> properties, TypeSymbol type, DiagnosticBag diagnostics)
private ImmutableArray<BoundSubPropertyPattern> BindSubPropertyPatterns(PropertyPatternSyntax node, TypeSymbol type, DiagnosticBag diagnostics)
{
var boundPatternsBuilder = ArrayBuilder<BoundPattern>.GetInstance();
var result = ArrayBuilder<BoundSubPropertyPattern>.GetInstance();
foreach (var syntax in node.PatternList.SubPatterns)
{
var propName = syntax.Left;
BoundPattern pattern;
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
Symbol property = FindPropertyByName(type, propName, ref useSiteDiagnostics);
LookupResultKind resultKind;
Symbol property = FindPropertyOrFieldByName(type, propName, out resultKind, ref useSiteDiagnostics);
if ((object)property != null)
{
bool hasErrors = false;
Expand All @@ -190,39 +195,51 @@ private ImmutableArray<BoundPattern> BindSubPropertyPatterns(PropertyPatternSynt
diagnostics.Add(node, useSiteDiagnostics);
}

properties.Add(property);
pattern = this.BindPattern(syntax.Pattern, null, property.GetTypeOrReturnType(), hasErrors, diagnostics);
var propertyType = property.GetTypeOrReturnType();
pattern = this.BindPattern(syntax.Pattern, null, propertyType, hasErrors, diagnostics);
result.Add(new BoundSubPropertyPattern(syntax, propertyType, property, resultKind, pattern, hasErrors));
}
else
{
Error(diagnostics, ErrorCode.ERR_NoSuchMember, propName, type, propName.Identifier.ValueText);
Error(diagnostics, ErrorCode.ERR_NoSuchMember, propName, type, propName.ValueText);
pattern = new BoundWildcardPattern(node, hasErrors: true);
result.Add(new BoundSubPropertyPattern(syntax, CreateErrorType(), null, resultKind, pattern, true));
}

boundPatternsBuilder.Add(pattern);
}

return boundPatternsBuilder.ToImmutableAndFree();
return result.ToImmutableAndFree();
}

private Symbol FindPropertyByName(TypeSymbol type, IdentifierNameSyntax name, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
private Symbol FindPropertyOrFieldByName(TypeSymbol type, SyntaxToken name, out LookupResultKind resultKind, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
var symbols = ArrayBuilder<Symbol>.GetInstance();
var result = LookupResult.GetInstance();
this.LookupMembersWithFallback(result, type, name.Identifier.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics);
var lookupResult = LookupResult.GetInstance();
this.LookupMembersWithFallback(lookupResult, type, name.ValueText, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics);
resultKind = lookupResult.Kind;
Symbol result = null;

if (result.IsMultiViable)
if (lookupResult.IsMultiViable)
{
foreach (var symbol in result.Symbols)
foreach (var symbol in lookupResult.Symbols)
{
if (symbol.Kind == SymbolKind.Property || symbol.Kind == SymbolKind.Field)
{
return symbol;
if (result != null && symbol != result)
{
resultKind = LookupResultKind.Ambiguous;
result = null;
break;
}
else
{
result = symbol;
}
}
}
}

return null;
lookupResult.Free();
return result;
}

private BoundPattern BindConstantPattern(ConstantPatternSyntax node, BoundExpression operand, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics)
Expand Down
12 changes: 9 additions & 3 deletions src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1446,10 +1446,16 @@

<Node Name="BoundPropertyPattern" Base="BoundPattern">
<Field Name="Type" Type="TypeSymbol" Null="disallow"/>
<Field Name="Patterns" Type="ImmutableArray&lt;BoundPattern&gt;" Null="disallow"/>
<Field Name="Properties" Type="ImmutableArray&lt;Symbol&gt;" Null="disallow"/>
<Field Name="Subpatterns" Type="ImmutableArray&lt;BoundSubPropertyPattern&gt;" Null="disallow"/>
</Node>


<Node Name="BoundSubPropertyPattern" Base="BoundNode">
<Field Name="Type" Type="TypeSymbol" Null="disallow"/>
<Field Name="Property" Type="Symbol" Null="allow"/>
<Field Name="ResultKind" Type="LookupResultKind"/>
<Field Name="Pattern" Type="BoundPattern" Null="disallow"/>
</Node>

<Node Name="BoundRecursivePattern" Base="BoundPattern">
<Field Name="Type" Type="TypeSymbol" Null="disallow"/>
<Field Name="IsOperator" Type="MethodSymbol" Null="allow"/>
Expand Down
16 changes: 16 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,22 @@ public static Conversion ClassifyConversion(this Compilation compilation, ITypeS
}
}

/// <summary>
/// Gets the symbol information for the property of a sub-property pattern.
/// </summary>
public static SymbolInfo GetSymbolInfo(this SemanticModel semanticModel, SubPropertyPatternSyntax node, CancellationToken cancellationToken = default(CancellationToken))
{
var csmodel = semanticModel as CSharpSemanticModel;
if (csmodel != null)
{
return csmodel.GetSymbolInfo(node, cancellationToken);
}
else
{
return SymbolInfo.None;
}
}

/// <summary>
/// Returns what symbol(s), if any, the given expression syntax bound to in the program.
///
Expand Down
11 changes: 11 additions & 0 deletions src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,11 @@ internal virtual IOperation GetOperationWorker(CSharpSyntaxNode node, GetOperati
/// </summary>
public abstract SymbolInfo GetSymbolInfo(SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken));

/// <summary>
/// Gets the symbol information for the property of a sub-property pattern.
/// </summary>
public abstract SymbolInfo GetSymbolInfo(SubPropertyPatternSyntax node, CancellationToken cancellationToken = default(CancellationToken));

/// <summary>
/// Returns what symbol(s), if any, the given expression syntax bound to in the program.
///
Expand Down Expand Up @@ -4346,6 +4351,12 @@ private SymbolInfo GetSymbolInfoFromNode(SyntaxNode node, CancellationToken canc
return this.GetSymbolInfo(orderingSyntax, cancellationToken);
}

var subPropertyPattern = node as SubPropertyPatternSyntax;
if (subPropertyPattern != null)
{
return this.GetSymbolInfo(subPropertyPattern, cancellationToken);
}

return SymbolInfo.None;
}

Expand Down
20 changes: 19 additions & 1 deletion src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,23 @@ internal override Optional<object> GetConstantValueWorker(CSharpSyntaxNode node,
return GetTypeInfoForQuery(bound);
}

/// <summary>
/// Gets the symbol information for the property of a sub-property pattern.
/// </summary>
public override SymbolInfo GetSymbolInfo(SubPropertyPatternSyntax node, CancellationToken cancellationToken)
{
var boundNode = GetLowerBoundNode(node) as BoundSubPropertyPattern;
if (boundNode != null)
{
var property = boundNode.Property;
return new SymbolInfo(property, boundNode.ResultKind == LookupResultKind.Viable ? CandidateReason.None : boundNode.ResultKind.ToCandidateReason());
}
else
{
return default(SymbolInfo);
}
}

private void GetBoundNodes(CSharpSyntaxNode node, out CSharpSyntaxNode bindableNode, out BoundNode lowestBoundNode, out BoundNode highestBoundNode, out BoundNode boundParent)
{
bindableNode = this.GetBindableSyntaxNode(node);
Expand Down Expand Up @@ -1609,7 +1626,8 @@ internal protected virtual CSharpSyntaxNode GetBindableSyntaxNode(CSharpSyntaxNo
!(node is OrderingSyntax) &&
!(node is JoinIntoClauseSyntax) &&
!(node is QueryContinuationSyntax) &&
!(node is ArrowExpressionClauseSyntax))
!(node is ArrowExpressionClauseSyntax) &&
!(node is SubPropertyPatternSyntax))
{
return GetBindableSyntaxNode(parent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ internal override Optional<object> GetConstantValueWorker(CSharpSyntaxNode node,
return (model == null) ? default(TypeInfo) : model.GetTypeInfo(node, cancellationToken);
}

public override SymbolInfo GetSymbolInfo(SubPropertyPatternSyntax node, CancellationToken cancellationToken)
{
CheckSyntaxNode(node);
var model = this.GetMemberModel(node);
return (model == null) ? default(SymbolInfo) : model.GetSymbolInfo(node, cancellationToken);
}

public override IPropertySymbol GetDeclaredSymbol(AnonymousObjectMemberDeclaratorSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken))
{
CheckSyntaxNode(declaratorSyntax);
Expand Down
8 changes: 4 additions & 4 deletions src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1332,9 +1332,9 @@ private void AssignPatternVariables(BoundPattern pattern)
case BoundKind.PropertyPattern:
{
var pat = (BoundPropertyPattern)pattern;
foreach (var prop in pat.Patterns)
foreach (var prop in pat.Subpatterns)
{
AssignPatternVariables(prop);
AssignPatternVariables(prop.Pattern);
}
break;
}
Expand Down Expand Up @@ -1407,9 +1407,9 @@ private void CreateSlots(BoundPattern pattern)
case BoundKind.PropertyPattern:
{
var pat = (BoundPropertyPattern)pattern;
foreach (var prop in pat.Patterns)
foreach (var prop in pat.Subpatterns)
{
CreateSlots(prop);
CreateSlots(prop.Pattern);
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,11 @@ public virtual void VisitPattern(BoundExpression expression, BoundPattern patter
{
// so far so good: the expression is known to match the *type* of the property pattern.
// Now check if each subpattern is irrefutable.
Debug.Assert(propPattern.Properties.Length == propPattern.Patterns.Length);
int n = propPattern.Properties.Length;
int n = propPattern.Subpatterns.Length;
for (int i = 0; i < n; i++)
{
var prop = propPattern.Properties[i];
var pat = propPattern.Patterns[i];
var prop = propPattern.Subpatterns[i].Property;
var pat = propPattern.Subpatterns[i].Pattern;
BoundExpression subExpr;
switch (prop.Kind)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ BoundExpression TranslatePattern(BoundExpression input, BoundPattern pattern)
var temp = _factory.SynthesizedLocal(pat.Type);
var matched = DeclPattern(syntax, input, temp);
input = _factory.Local(temp);
for (int i = 0; i < pat.Patterns.Length; i++)
for (int i = 0; i < pat.Subpatterns.Length; i++)
{
var subProperty = pat.Properties[i];
var subPattern = pat.Patterns[i];
var subProperty = pat.Subpatterns[i].Property;
var subPattern = pat.Subpatterns[i].Pattern;
var subExpression =
subProperty.Kind == SymbolKind.Field
? (BoundExpression)_factory.Field(input, (FieldSymbol)subProperty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ private bool IsPossibleSubPropertyPattern()

private SubPropertyPatternSyntax ParseSubPropertyPattern()
{
var name = this.ParseIdentifierName();
var name = this.EatToken(SyntaxKind.IdentifierToken);
var operandToken = this.EatToken(SyntaxKind.IsKeyword);

PatternSyntax pattern = this.CurrentToken.Kind == SyntaxKind.CommaToken ?
Expand Down
Loading

0 comments on commit 092bab9

Please sign in to comment.