Address PR feedback. Move BoundQueryClause properties to xml as well.

上级 9b059510
......@@ -618,9 +618,9 @@ private BoundBlock CreateLambdaBlockForQueryClause(ExpressionSyntax expression,
return new BoundQueryClause(
syntax: syntax, value: expression,
definedSymbol: definedSymbol,
queryInvocation: queryInvocation,
operation: queryInvocation,
binder: this,
castInvocation: castInvocation, unoptimizedForm: unoptimizedForm,
cast: castInvocation, unoptimizedForm: unoptimizedForm,
type: TypeOrError(expression));
}
......
......@@ -218,33 +218,8 @@ public override Symbol ExpressionSymbol
get { return this.Indexer; }
}
public BoundIndexerAccess Update(bool useSetterForDefaultArgumentGeneration)
{
if (useSetterForDefaultArgumentGeneration != this.UseSetterForDefaultArgumentGeneration)
{
var result = new BoundIndexerAccess(
this.Syntax,
this.ReceiverOpt,
this.Indexer,
this.Arguments,
this.ArgumentNamesOpt,
this.ArgumentRefKindsOpt,
this.Expanded,
this.ArgsToParamsOpt,
this.BinderOpt,
useSetterForDefaultArgumentGeneration,
this.OriginalIndexersOpt,
this.Type,
this.HasErrors)
{
WasCompilerGenerated = this.WasCompilerGenerated,
};
return result;
}
return this;
}
public BoundIndexerAccess Update(bool useSetterForDefaultArgumentGeneration) =>
Update(ReceiverOpt, Indexer, Arguments, ArgumentNamesOpt, ArgumentRefKindsOpt, Expanded, ArgsToParamsOpt, BinderOpt, useSetterForDefaultArgumentGeneration, OriginalIndexersOpt, Type);
public override LookupResultKind ResultKind
{
......
......@@ -269,6 +269,9 @@
<Field Name="Operand" Type="BoundExpression"/>
<Field Name="ConstantValueOpt" Type="ConstantValue?"/>
<Field Name="MethodOpt" Type="MethodSymbol?"/>
<!--The set of method symbols from which this operator's method was chosen.
Only kept in the tree if the operator was an error and overload resolution
was unable to choose a best method.-->
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
<Field Name="OriginalUserDefinedOperatorsOpt" Type="ImmutableArray&lt;MethodSymbol&gt;" Null="Allow"/>
</Node>
......@@ -284,6 +287,9 @@
<Field Name="OperandConversion" Type="Conversion"/>
<Field Name="ResultConversion" Type="Conversion"/>
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
<!--The set of method symbols from which this operator's method was chosen.
Only kept in the tree if the operator was an error and overload resolution
was unable to choose a best method.-->
<Field Name="OriginalUserDefinedOperatorsOpt" Type="ImmutableArray&lt;MethodSymbol&gt;" Null="Allow"/>
</Node>
......@@ -364,6 +370,9 @@
<Field Name="ConstantValueOpt" Type="ConstantValue?"/>
<Field Name="MethodOpt" Type="MethodSymbol?"/>
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
<!--The set of method symbols from which this operator's method was chosen.
Only kept in the tree if the operator was an error and overload resolution
was unable to choose a best method.-->
<Field Name="OriginalUserDefinedOperatorsOpt" Type="ImmutableArray&lt;MethodSymbol&gt;" Null="Allow"/>
</Node>
......@@ -382,6 +391,9 @@
<Field Name="TrueOperator" Type="MethodSymbol"/>
<Field Name="FalseOperator" Type="MethodSymbol"/>
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
<!--The set of method symbols from which this operator's method was chosen.
Only kept in the tree if the operator was an error and overload resolution
was unable to choose a best method.-->
<Field Name="OriginalUserDefinedOperatorsOpt" Type="ImmutableArray&lt;MethodSymbol&gt;" Null="Allow"/>
</Node>
......@@ -420,6 +432,9 @@
<Field Name="Right" Type="BoundExpression"/>
<Field Name="LeftConversion" Type="Conversion"/>
<Field Name="FinalConversion" Type="Conversion"/>
<!--The set of method symbols from which this operator's method was chosen.
Only kept in the tree if the operator was an error and overload resolution
was unable to choose a best method.-->
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
<Field Name="OriginalUserDefinedOperatorsOpt" Type="ImmutableArray&lt;MethodSymbol&gt;" Null="Allow"/>
</Node>
......@@ -645,6 +660,9 @@
Conversion is represented by a single BoundConversion.
-->
<Field Name="ConversionGroupOpt" Type="ConversionGroup?"/>
<!--The set of method symbols from which this conversion's method was chosen.
Only kept in the tree if the conversion was an error and overload resolution
was unable to choose a best method.-->
<Field Name="OriginalUserDefinedConversionsOpt" Type="ImmutableArray&lt;MethodSymbol&gt;" Null="Allow"/>
</Node>
......@@ -1452,6 +1470,9 @@
<Field Name="InvokedAsExtensionMethod" Type="bool"/>
<Field Name="ArgsToParamsOpt" Type="ImmutableArray&lt;int&gt;" Null="allow"/>
<Field Name="ResultKind" PropertyOverrides="true" Type="LookupResultKind"/>
<!--The set of method symbols from which this call's method was chosen.
Only kept in the tree if the call was an error and overload resolution
was unable to choose a best method.-->
<Field Name="OriginalMethodsOpt" Type="ImmutableArray&lt;MethodSymbol&gt;" Null="Allow"/>
<!-- BinderOpt is added as a temporary solution for IOperation implementation and should probably be removed in the future -->
......@@ -1773,6 +1794,9 @@
<!-- Tracked by https://github.com/dotnet/roslyn/issues/20787 -->
<Field Name="BinderOpt" Type="Binder?"/>
<Field Name="UseSetterForDefaultArgumentGeneration" Type="bool"/>
<!--The set of indexer symbols from which this call's indexer was chosen.
Only kept in the tree if the call was an error and overload resolution
was unable to choose a best indexer.-->
<Field Name="OriginalIndexersOpt" Type="ImmutableArray&lt;PropertySymbol&gt;" Null="allow"/>
</Node>
......@@ -1821,8 +1845,15 @@
<Field Name="Value" Type="BoundExpression" Null="disallow"/>
<!-- The query variable introduced by this query clause, if any. -->
<Field Name="DefinedSymbol" Type="RangeVariableSymbol?"/>
<!-- The bound expression that invokes the operation of the query clause. -->
<Field Name="Operation" Type="BoundExpression?" />
<!-- The bound expression that is the invocation of a "Cast" method specified by the query translation. -->
<Field Name="Cast" Type="BoundExpression?" />
<!-- The enclosing binder in which the query clause was evaluated. -->
<Field Name="Binder" Type="Binder" Null="disallow" />
<!-- The bound expression that is the query expression in "unoptimized" form. Specifically, a final ".Select"
invocation that is omitted by the specification is included here. -->
<Field Name="UnoptimizedForm" Type="BoundExpression?" />
</Node>
<!--
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.CSharp.Symbols;
namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class BoundQueryClause
{
/// <summary>
/// The bound expression that invokes the operation of the query clause.
/// </summary>
public BoundExpression Operation { get; }
/// <summary>
/// The bound expression that is the invocation of a "Cast" method specified by the query translation.
/// </summary>
public BoundExpression Cast { get; }
/// <summary>
/// The bound expression that is the query expression in "unoptimized" form. Specifically, a final ".Select"
/// invocation that is omitted by the specification is included here.
/// </summary>
public BoundExpression UnoptimizedForm { get; }
public BoundQueryClause(
SyntaxNode syntax,
BoundExpression value,
RangeVariableSymbol definedSymbol,
BoundExpression queryInvocation,
BoundExpression castInvocation,
Binder binder,
BoundExpression unoptimizedForm,
TypeSymbol type,
bool hasErrors = false)
: this(syntax, value, definedSymbol, binder, type, hasErrors)
{
this.Operation = queryInvocation;
this.Cast = castInvocation;
this.UnoptimizedForm = unoptimizedForm;
}
public BoundQueryClause Update(
BoundExpression value,
RangeVariableSymbol definedSymbol,
BoundExpression queryInvocation,
BoundExpression castInvocation,
Binder binder,
BoundExpression unoptimizedForm,
TypeSymbol type)
{
if (value != this.Value || definedSymbol != this.DefinedSymbol || queryInvocation != this.Operation || castInvocation != this.Cast || binder != this.Binder || unoptimizedForm != this.UnoptimizedForm || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
{
var result = new BoundQueryClause(this.Syntax, value, definedSymbol, queryInvocation, castInvocation, binder, unoptimizedForm, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
result.IsSuppressed = this.IsSuppressed;
return result;
}
return this;
}
}
}
......@@ -6577,8 +6577,8 @@ public UnboundLambda Update(UnboundLambdaState data)
internal sealed partial class BoundQueryClause : BoundExpression
{
public BoundQueryClause(SyntaxNode syntax, BoundExpression value, RangeVariableSymbol? definedSymbol, Binder binder, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.QueryClause, syntax, type, hasErrors || value.HasErrors())
public BoundQueryClause(SyntaxNode syntax, BoundExpression value, RangeVariableSymbol? definedSymbol, BoundExpression? operation, BoundExpression? cast, Binder binder, BoundExpression? unoptimizedForm, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.QueryClause, syntax, type, hasErrors || value.HasErrors() || operation.HasErrors() || cast.HasErrors() || unoptimizedForm.HasErrors())
{
Debug.Assert(value is object, "Field 'value' cannot be null (make the type nullable in BoundNodes.xml to remove this check)");
......@@ -6587,7 +6587,10 @@ public BoundQueryClause(SyntaxNode syntax, BoundExpression value, RangeVariableS
this.Value = value;
this.DefinedSymbol = definedSymbol;
this.Operation = operation;
this.Cast = cast;
this.Binder = binder;
this.UnoptimizedForm = unoptimizedForm;
}
......@@ -6597,15 +6600,21 @@ public BoundQueryClause(SyntaxNode syntax, BoundExpression value, RangeVariableS
public RangeVariableSymbol? DefinedSymbol { get; }
public BoundExpression? Operation { get; }
public BoundExpression? Cast { get; }
public Binder Binder { get; }
public BoundExpression? UnoptimizedForm { get; }
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitQueryClause(this);
public BoundQueryClause Update(BoundExpression value, RangeVariableSymbol? definedSymbol, Binder binder, TypeSymbol type)
public BoundQueryClause Update(BoundExpression value, RangeVariableSymbol? definedSymbol, BoundExpression? operation, BoundExpression? cast, Binder binder, BoundExpression? unoptimizedForm, TypeSymbol type)
{
if (value != this.Value || !SymbolEqualityComparer.ConsiderEverything.Equals(definedSymbol, this.DefinedSymbol) || binder != this.Binder || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
if (value != this.Value || !SymbolEqualityComparer.ConsiderEverything.Equals(definedSymbol, this.DefinedSymbol) || operation != this.Operation || cast != this.Cast || binder != this.Binder || unoptimizedForm != this.UnoptimizedForm || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
{
var result = new BoundQueryClause(this.Syntax, value, definedSymbol, binder, type, this.HasErrors);
var result = new BoundQueryClause(this.Syntax, value, definedSymbol, operation, cast, binder, unoptimizedForm, type, this.HasErrors);
result.CopyAttributes(this);
return result;
}
......@@ -8769,6 +8778,9 @@ internal abstract partial class BoundTreeWalker: BoundTreeVisitor
public override BoundNode? VisitQueryClause(BoundQueryClause node)
{
this.Visit(node.Value);
this.Visit(node.Operation);
this.Visit(node.Cast);
this.Visit(node.UnoptimizedForm);
return null;
}
public override BoundNode? VisitTypeOrInstanceInitializers(BoundTypeOrInstanceInitializers node)
......@@ -9826,8 +9838,11 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor
public override BoundNode? VisitQueryClause(BoundQueryClause node)
{
BoundExpression value = (BoundExpression)this.Visit(node.Value);
BoundExpression? operation = (BoundExpression?)this.Visit(node.Operation);
BoundExpression? cast = (BoundExpression?)this.Visit(node.Cast);
BoundExpression? unoptimizedForm = (BoundExpression?)this.Visit(node.UnoptimizedForm);
TypeSymbol type = this.VisitType(node.Type);
return node.Update(value, node.DefinedSymbol, node.Binder, type);
return node.Update(value, node.DefinedSymbol, operation, cast, node.Binder, unoptimizedForm, type);
}
public override BoundNode? VisitTypeOrInstanceInitializers(BoundTypeOrInstanceInitializers node)
{
......@@ -11582,16 +11597,19 @@ public NullabilityRewriter(ImmutableDictionary<BoundExpression, (NullabilityInfo
public override BoundNode? VisitQueryClause(BoundQueryClause node)
{
BoundExpression value = (BoundExpression)this.Visit(node.Value);
BoundExpression? operation = (BoundExpression?)this.Visit(node.Operation);
BoundExpression? cast = (BoundExpression?)this.Visit(node.Cast);
BoundExpression? unoptimizedForm = (BoundExpression?)this.Visit(node.UnoptimizedForm);
BoundQueryClause updatedNode;
if (_updatedNullabilities.TryGetValue(node, out (NullabilityInfo Info, TypeSymbol Type) infoAndType))
{
updatedNode = node.Update(value, node.DefinedSymbol, node.Binder, infoAndType.Type);
updatedNode = node.Update(value, node.DefinedSymbol, operation, cast, node.Binder, unoptimizedForm, infoAndType.Type);
updatedNode.TopLevelNullability = infoAndType.Info;
}
else
{
updatedNode = node.Update(value, node.DefinedSymbol, node.Binder, node.Type);
updatedNode = node.Update(value, node.DefinedSymbol, operation, cast, node.Binder, unoptimizedForm, node.Type);
}
return updatedNode;
}
......@@ -13277,7 +13295,10 @@ public override TreeDumperNode VisitYieldBreakStatement(BoundYieldBreakStatement
{
new TreeDumperNode("value", null, new TreeDumperNode[] { Visit(node.Value, null) }),
new TreeDumperNode("definedSymbol", node.DefinedSymbol, null),
new TreeDumperNode("operation", null, new TreeDumperNode[] { Visit(node.Operation, null) }),
new TreeDumperNode("cast", null, new TreeDumperNode[] { Visit(node.Cast, null) }),
new TreeDumperNode("binder", node.Binder, null),
new TreeDumperNode("unoptimizedForm", null, new TreeDumperNode[] { Visit(node.UnoptimizedForm, null) }),
new TreeDumperNode("type", node.Type, null),
new TreeDumperNode("isSuppressed", node.IsSuppressed, null),
new TreeDumperNode("hasErrors", node.HasErrors, null)
......
......@@ -2247,5 +2247,43 @@ private class F<T>
Assert.Null(symbolInfo.Symbol);
Assert.Empty(symbolInfo.CandidateSymbols);
}
[Fact, WorkItem(37879, "https://github.com/dotnet/roslyn/issues/37879")]
public void MultipleSymbols_ReinferedParent()
{
var source = @"
using System;
class C
{
public void A<T>(T t) where T : class
{
var c = new F<T>[] { }.Select(v => new { Value = v.Item }).ToArray();
}
private class F<T>
{
public F(T oldItem) => Item = oldItem;
public T Item { get; }
}
}
static class ArrayExtensions
{
public static U Select<T, U>(this T[] arr, Func<T, object, U> mapper, object arg) => throw null!;
public static U Select<T, U, V>(this T[] arr, Func<T, V, U> mapper, V arg) => throw null!;
public static U Select<T, U>(this T[] arr, C mapper) => throw null!;
public static U Select<T, U>(this T[] arr, string mapper) => throw null!;
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
var syntaxTree = comp.SyntaxTrees[0];
var root = syntaxTree.GetRoot();
var model = comp.GetSemanticModel(syntaxTree);
var select = root.DescendantNodes().OfType<IdentifierNameSyntax>().Where(i => i.Identifier.ValueText == "Select").Single();
var symbolInfo = model.GetSymbolInfo(select);
Assert.Null(symbolInfo.Symbol);
Assert.Equal(4, symbolInfo.CandidateSymbols.Length);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册