提交 92b896ba 编写于 作者: P pgavlin

Change Color Color handling to use binding instead of lookup.

The Color Color handling in the binder originally used lookup to decide the meaning of an ambiguous identifier as a simple name or type name instead of binding. This was done for two reasons:
- Binding is more expensive than lookup
- Binding may have side effects that are undesirable depending on how the Color Color binding is ultimately resolved

Unfortunately, this is not correct: the meaning of an identifier as outlined in the spec is defined by binding. This caused the compiler to incorrectly fail to recognize Color Color in situations where a simple name or type name lookup is ambiguous but a bind of the same is not. This change replaces the lookups used in Color Color with binds, which brings Roslyn's behavior back in line with Dev12 and the spec in cases that fit such cases.

This change is likely to be slightly perf-positive in cases involving a simple name that does not bind to a symbol that qualifies for the Color Color rule: in this case, the old code performed a lookup followed by a bind, whereas the new code simply performs a bind and returns the result. There is likely to be a perf penalty in a true Color Color case, however, as the bound node is larger and the new code is unconditionally binding the type even in the case where the type will not be used (whereas the old code would simply look up the type).
***NO_CI***
 (changeset 1385215)
上级 c3ceca1b
......@@ -319,9 +319,8 @@ private static bool IsMethodGroupWithTypeOrValueReceiver(BoundNode node)
}
private static BoundMethodGroup FixMethodGroupWithTypeOrValue(BoundMethodGroup group, Conversion conversion, DiagnosticBag diagnostics)
private BoundMethodGroup FixMethodGroupWithTypeOrValue(BoundMethodGroup group, Conversion conversion, DiagnosticBag diagnostics)
{
if (!IsMethodGroupWithTypeOrValueReceiver(group))
{
return group;
......
......@@ -1165,8 +1165,8 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
}
else
{
type = localSymbol.Type;
}
type = localSymbol.Type;
}
return new BoundLocal(node, localSymbol, constantValueOpt, type, hasErrors: isError);
}
......@@ -4156,14 +4156,8 @@ private BoundExpression BindCheckedExpression(CheckedExpressionSyntax node, Diag
ExpressionSyntax exprSyntax = node.Expression;
if (node.Kind == SyntaxKind.SimpleMemberAccessExpression)
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
boundLeft =
// First, try to detect the Color Color case.
BindLeftOfPotentialColorColorMemberAccess(exprSyntax, ref useSiteDiagnostics) ??
// Then, if this is definitely not a Color Color case, just bind the expression normally.
// NOTE: CheckValue will be called explicitly in BindMemberAccessWithBoundLeft.
this.BindExpression(exprSyntax, diagnostics);
diagnostics.Add(node, useSiteDiagnostics);
// NOTE: CheckValue will be called explicitly in BindMemberAccessWithBoundLeft.
boundLeft = BindLeftOfPotentialColorColorMemberAccess(exprSyntax, diagnostics);
}
else
{
......@@ -4201,10 +4195,8 @@ private BoundExpression BindCheckedExpression(CheckedExpressionSyntax node, Diag
/// then return a BoundExpression if we can easily disambiguate or a BoundTypeOrValueExpression if we
/// cannot. If this is not a Color Color case, then return null.
/// </summary>
private BoundExpression BindLeftOfPotentialColorColorMemberAccess(ExpressionSyntax left, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
private BoundExpression BindLeftOfPotentialColorColorMemberAccess(ExpressionSyntax left, DiagnosticBag diagnostics)
{
BoundExpression boundLeft = null;
// SPEC: 7.6.4.1 Identical simple names and type names
// SPEC: In a member access of the form E.I, if E is a single identifier, and if the meaning of E as
// SPEC: a simple-name (spec 7.6.2) is a constant, field, property, local variable, or parameter with the
......@@ -4213,85 +4205,66 @@ private BoundExpression BindLeftOfPotentialColorColorMemberAccess(ExpressionSynt
// SPEC: a member of the type E in both cases. In other words, the rule simply permits access to the
// SPEC: static members and nested types of E where a compile-time error would otherwise have occurred.
// NOTE: We don't want to bind left until we know how to interpret it, because binding can have side-effects.
if (left.Kind == SyntaxKind.IdentifierName)
{
LookupResult result = LookupResult.GetInstance();
string leftName = ((IdentifierNameSyntax)left).Identifier.ValueText;
TypeSymbol leftType = null;
this.LookupSymbolsWithFallback(result, leftName, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.AllMethodsOnArityZero);
var node = (IdentifierNameSyntax)left;
var valueDiagnostics = DiagnosticBag.GetInstance();
var boundValue = BindIdentifier(node, invoked: false, diagnostics: valueDiagnostics);
if (result.IsSingleViable)
Symbol leftSymbol;
if (boundValue.Kind == BoundKind.Conversion)
{
// BindFieldAccess may insert a conversion if binding occurs
// within an enum member initializer.
leftSymbol = ((BoundConversion)boundValue).Operand.ExpressionSymbol;
}
else
{
Symbol leftSymbol = result.SingleSymbolOrDefault;
leftSymbol = boundValue.ExpressionSymbol;
}
if ((object)leftSymbol != null)
{
TypeSymbol leftType;
switch (leftSymbol.Kind)
{
case SymbolKind.Local:
{
var localSymbol = (LocalSymbol)leftSymbol;
bool isBindingVar = IsBindingImplicitlyTypedLocal(localSymbol);
if (!isBindingVar)
{
bool usedBeforeDecl =
left.SyntaxTree == localSymbol.Locations[0].SourceTree &&
left.SpanStart < localSymbol.Locations[0].SourceSpan.Start;
if (!usedBeforeDecl)
{
leftType = localSymbol.Type;
}
}
break;
}
case SymbolKind.Parameter:
case SymbolKind.Field:
{
FieldSymbol field = (FieldSymbol)leftSymbol;
TypeSymbol fieldContainingType = field.ContainingType;
if (fieldContainingType.IsEnumType() && this.InEnumMemberInitializer())
{
leftType = fieldContainingType.GetEnumUnderlyingType();
Debug.Assert((object)leftType != null);
}
else
{
leftType = field.GetFieldType(this.FieldsBeingBound);
}
break;
}
case SymbolKind.Property:
leftType = ((PropertySymbol)leftSymbol).Type;
leftType = boundValue.Type;
break;
case SymbolKind.Parameter:
leftType = ((ParameterSymbol)leftSymbol).Type;
break;
// case SymbolKind.Event: //SPEC: 7.6.4.1 (a.k.a. Color Color) doesn't cover events
}
if ((object)leftType != null && (leftType.Name == leftName || IsUsingAliasInScope(leftName)))
{
result.Clear();
// case SymbolKind.Event: //SPEC: 7.6.4.1 (a.k.a. Color Color) doesn't cover events
this.LookupSymbolsWithFallback(result, leftName, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: LookupOptions.NamespacesOrTypesOnly);
default:
// Not a Color Color case. Return the bound member.
goto notColorColor;
}
Symbol leftTypeOrNamespaceSymbol = result.SingleSymbolOrDefault;
if (result.IsSingleViable &&
((leftTypeOrNamespaceSymbol.Kind == SymbolKind.Alias && ((AliasSymbol)leftTypeOrNamespaceSymbol).Target == leftType) ||
leftTypeOrNamespaceSymbol == leftType))
Debug.Assert((object)leftType != null);
var leftName = node.Identifier.ValueText;
if (leftType.Name == leftName || IsUsingAliasInScope(leftName))
{
var typeDiagnostics = DiagnosticBag.GetInstance();
var boundType = BindNamespaceOrType(node, typeDiagnostics);
if (boundType.Type == leftType)
{
// We don't have enough information to determine how the left name should be interpreted.
// Instantiate a placeholder node until overload resolution is done and we know what to replace it with.
boundLeft = new BoundTypeOrValueExpression(left, leftSymbol, this, leftType);
// NOTE: ReplaceTypeOrValueReceiver will call CheckValue explicitly.
return new BoundTypeOrValueExpression(left, leftSymbol, boundValue, valueDiagnostics.ToReadOnlyAndFree(), boundType, typeDiagnostics.ToReadOnlyAndFree(), leftType);
}
}
}
result.Free();
notColorColor:
// NOTE: it is up to the caller to call CheckValue on the result.
diagnostics.AddRangeAndFree(valueDiagnostics);
return boundValue;
}
return boundLeft;
// NOTE: it is up to the caller to call CheckValue on the result.
return BindExpression(left, diagnostics);
}
// returns true if name matches a using alias in scope
......@@ -5848,7 +5821,7 @@ private BoundExpression BindIndexedPropertyAccess(CSharpSyntaxNode syntax, Bound
// Ideally the runtime binder would choose between type and value based on the result of the overload resolution.
// We need to pick one or the other here. Dev11 compiler passes the type only if the value can't be accessed.
bool inStaticContext;
bool useType = IsInstance(typeOrValue.Variable) && !HasThis(isExplicit: false, inStaticContext: out inStaticContext);
bool useType = IsInstance(typeOrValue.ValueSymbol) && !HasThis(isExplicit: false, inStaticContext: out inStaticContext);
receiverOpt = ReplaceTypeOrValueReceiver(typeOrValue, useType, diagnostics);
}
......
......@@ -290,7 +290,7 @@ private BoundExpression BindArgListOperator(InvocationExpressionSyntax node, Dia
// Ideally the runtime binder would choose between type and value based on the result of the overload resolution.
// We need to pick one or the other here. Dev11 compiler passes the type only if the value can't be accessed.
bool inStaticContext;
bool useType = IsInstance(typeOrValue.Variable) && !HasThis(isExplicit: false, inStaticContext: out inStaticContext);
bool useType = IsInstance(typeOrValue.ValueSymbol) && !HasThis(isExplicit: false, inStaticContext: out inStaticContext);
BoundExpression finalReceiver = ReplaceTypeOrValueReceiver(typeOrValue, useType, diagnostics);
......@@ -872,20 +872,27 @@ private Location GetLocationForOverloadResolutionDiagnostic(CSharpSyntaxNode nod
/// Call this once overload resolution has succeeded on the method group of which the BoundTypeOrValueExpression
/// is the receiver. Generally, useType will be true if the chosen method is static and false otherwise.
/// </remarks>
private static BoundExpression ReplaceTypeOrValueReceiver(BoundExpression receiver, bool useType, DiagnosticBag diagnostics)
private BoundExpression ReplaceTypeOrValueReceiver(BoundExpression receiver, bool useType, DiagnosticBag diagnostics)
{
if (receiver == null) return receiver;
if ((object)receiver == null)
{
return null;
}
switch (receiver.Kind)
{
case BoundKind.TypeOrValueExpression:
var typeOrValue = (BoundTypeOrValueExpression)receiver;
Binder binder = typeOrValue.Binder;
ExpressionSyntax syntax = (ExpressionSyntax)receiver.Syntax;
receiver = useType ?
binder.BindNamespaceOrType(syntax, diagnostics) :
binder.BindValue(syntax, diagnostics, BindValueKind.RValue);
return receiver;
if (useType)
{
diagnostics.AddRange(typeOrValue.TypeDiagnostics);
return typeOrValue.TypeExpression;
}
else
{
diagnostics.AddRange(typeOrValue.ValueDiagnostics);
return CheckValue(typeOrValue.ValueExpression, BindValueKind.RValue, diagnostics);
}
case BoundKind.QueryClause:
// a query clause may wrap a TypeOrValueExpression.
......@@ -903,7 +910,7 @@ private static BoundExpression ReplaceTypeOrValueReceiver(BoundExpression receiv
/// </summary>
private static NamedTypeSymbol GetDelegateType(BoundExpression expr)
{
if ((expr != null) && (expr.Kind != BoundKind.TypeExpression))
if ((object)expr != null && expr.Kind != BoundKind.TypeExpression)
{
var type = expr.Type as NamedTypeSymbol;
if (((object)type != null) && type.IsDelegateType())
......@@ -948,7 +955,7 @@ private static NamedTypeSymbol GetDelegateType(BoundExpression expr)
else
{
var returnType = GetCommonTypeOrReturnType(methods) ?? new ExtendedErrorTypeSymbol(this.Compilation, string.Empty, arity: 0, errorInfo: null);
var methodContainer = receiver != null && (object)receiver.Type != null
var methodContainer = (object)receiver != null && (object)receiver.Type != null
? receiver.Type
: this.ContainingType;
method = new ErrorMethodSymbol(methodContainer, returnType, name);
......
......@@ -21,11 +21,7 @@ internal partial class Binder
internal BoundExpression BindQuery(QueryExpressionSyntax node, DiagnosticBag diagnostics)
{
var fromClause = node.FromClause;
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
var boundFromExpression = BindLeftOfPotentialColorColorMemberAccess(fromClause.Expression, ref useSiteDiagnostics) ??
this.BindExpression(fromClause.Expression, diagnostics);
diagnostics.Add(fromClause.Expression, useSiteDiagnostics);
var boundFromExpression = BindLeftOfPotentialColorColorMemberAccess(fromClause.Expression, diagnostics);
// If the from expression is of the type dynamic we can't infer the types for any lambdas that occur in the query.
// Only if there are none we could bind the query but we report an error regardless since such queries are not useful.
......
......@@ -1661,7 +1661,7 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
var typeOrValue = (BoundTypeOrValueExpression)receiver;
receiver = otherSymbol.IsStatic
? null // no receiver required
: typeOrValue.GetValueExpression();
: typeOrValue.ValueExpression;
}
return new BoundBadExpression(
expr.Syntax,
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
......@@ -459,17 +460,6 @@ public override Symbol ExpressionSymbol
}
}
partial class BoundTypeOrValueExpression
{
public BoundExpression GetValueExpression()
{
DiagnosticBag discardedDiagnostics = DiagnosticBag.GetInstance();
BoundExpression valueExpr = this.Binder.BindExpression((ExpressionSyntax)this.Syntax, discardedDiagnostics);
discardedDiagnostics.Free();
return valueExpr;
}
}
partial class BoundObjectInitializerMember
{
public override Symbol ExpressionSymbol
......@@ -518,4 +508,27 @@ public override ConstantValue ConstantValue
}
}
}
internal sealed partial class BoundTypeOrValueExpression : BoundExpression
{
// NOTE: this constructor should always be used instead of the generated constructor, since the generated
// constructor may spuriously set hasErrors to true if valueExpression or typeExpression have errors.
// This node should never have errors if it is present in the tree.
public BoundTypeOrValueExpression(CSharpSyntaxNode syntax, Symbol valueSymbol, BoundExpression valueExpression, ImmutableArray<Diagnostic> valueDiagnostics, BoundExpression typeExpression, ImmutableArray<Diagnostic> typeDiagnostics, TypeSymbol type)
: base(BoundKind.TypeOrValueExpression, syntax, type, hasErrors: false)
{
Debug.Assert(valueSymbol != null, "Field 'valueSymbol' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(valueExpression != null, "Field 'valueExpression' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(!valueDiagnostics.IsDefault, "Field 'valueDiagnostics' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(typeExpression != null, "Field 'typeExpression' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(!typeDiagnostics.IsDefault, "Field 'typeDiagnostics' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(type != null, "Field 'type' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.ValueSymbol = valueSymbol;
this.ValueExpression = valueExpression;
this.ValueDiagnostics = valueDiagnostics;
this.TypeExpression = typeExpression;
this.TypeDiagnostics = typeDiagnostics;
}
}
}
......@@ -26,6 +26,7 @@
<ValueType Name="BinaryOperatorKind"/>
<ValueType Name="LookupResultKind"/>
<ValueType Name="NoOpStatementFlavor"/>
<ValueType Name="TypeOrValueInfo"/>
<AbstractNode Name="BoundInitializer" Base="BoundNode"/>
......@@ -160,12 +161,11 @@
<Node Name="BoundTypeOrValueExpression" Base="BoundExpression">
<!-- Type is required for this node type; may not be null -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="Variable" Type="Symbol" Null="disallow"/>
<!-- In error scenarios, nodes of this kind may appear in the
initial bound tree. With this binder, consumers of the initial
bound tree will be able to determine the fallback interpretation
(i.e. by binding the syntax as an expression).-->
<Field Name="Binder" Type="Binder" Null="disallow" />
<Field Name="ValueSymbol" Type="Symbol" Null="disallow"/>
<Field Name="ValueExpression" Type="BoundExpression" Null="disallow"/>
<Field Name="ValueDiagnostics" Type="ImmutableArray&lt;Microsoft.CodeAnalysis.Diagnostic&gt;" Null="disallow"/>
<Field Name="TypeExpression" Type="BoundExpression" Null="disallow"/>
<Field Name="TypeDiagnostics" Type="ImmutableArray&lt;Microsoft.CodeAnalysis.Diagnostic&gt;" Null="disallow"/>
</Node>
<Node Name="BoundNamespaceExpression" Base="BoundExpression">
......
......@@ -1735,6 +1735,12 @@ private bool IsInTypeofExpression(int position)
resultKind = highestResultKind;
isDynamic = highestIsDynamic;
}
else if (highestBoundExpr.Kind == BoundKind.TypeOrValueExpression)
{
symbols = highestSymbols;
resultKind = highestResultKind;
isDynamic = highestIsDynamic;
}
else if (highestBoundExpr.Kind == BoundKind.UnaryOperator)
{
if (IsUserDefinedTrueOrFalse((BoundUnaryOperator)highestBoundExpr))
......@@ -2878,7 +2884,7 @@ public ILocalSymbol GetDeclaredSymbol(CatchDeclarationSyntax catchDeclaration, C
// If we're seeing a node of this kind, then we failed to resolve the member access
// as either a type or a property/field/event/local/parameter. In such cases,
// the second interpretation applies so just visit the node for that.
BoundExpression valueExpression = ((BoundTypeOrValueExpression)boundNode).GetValueExpression();
BoundExpression valueExpression = ((BoundTypeOrValueExpression)boundNode).ValueExpression;
return GetSemanticSymbols(valueExpression, boundNodeForSyntacticParent, binderOpt, options, out isDynamic, out resultKind, out memberGroup);
}
......
......@@ -1218,7 +1218,7 @@ public override BoundNode VisitTypeOrValueExpression(BoundTypeOrValueExpression
// If we're seeing a node of this kind, then we failed to resolve the member access
// as either a type or a property/field/event/local/parameter. In such cases,
// the second interpretation applies so just visit the node for that.
return this.Visit(node.GetValueExpression());
return this.Visit(node.ValueExpression);
}
public override BoundNode VisitLiteral(BoundLiteral node)
......
......@@ -1540,6 +1540,165 @@ .maxstack 1
");
}
[WorkItem(938389, "DevDiv")]
[Fact]
public void ShadowedTypeReceiver_1()
{
const string source1 = @"
namespace Foo
{
public class A { public static int I { get { return -42; } } }
}";
const string source2 = @"
namespace Foo
{
public class A { public static int I { get { return 42; } } }
class C
{
static A A { get { return new A(); } }
static void Main()
{
System.Console.WriteLine(A.I);
}
}
}";
var comp1 = CreateCompilationWithMscorlib(source1, options: TestOptions.ReleaseDll, assemblyName: System.Guid.NewGuid().ToString());
var ref1 = MetadataReference.CreateFromStream(comp1.EmitToStream());
var refIdentity = ((AssemblyMetadata)ref1.GetMetadata()).GetAssembly().Identity.ToString();
CompileAndVerify(source2, new[] { ref1 }, expectedOutput: "42").VerifyDiagnostics(
// (8,16): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '04f2260a-2ee6-4e74-938a-c47b6dc61d9c, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return null; } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 16),
// (8,39): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '59c700fa-e88d-45e4-acec-fd0bae894f9d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return new A(); } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 39),
// (12,38): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '04f2260a-2ee6-4e74-938a-c47b6dc61d9c, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// System.Console.WriteLine(A.I);
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(12, 38));
}
[WorkItem(938389, "DevDiv")]
[Fact]
public void ShadowedTypeReceiver_2()
{
const string source1 = @"
namespace Foo
{
public class A { public int I { get { return -42; } } }
}";
const string source2 = @"
namespace Foo
{
public class A { public int I { get { return 42; } } }
class C
{
static A A { get { return new A(); } }
static void Main()
{
System.Console.WriteLine(A.I);
}
}
}";
var comp1 = CreateCompilationWithMscorlib(source1, options: TestOptions.ReleaseDll, assemblyName: System.Guid.NewGuid().ToString());
var ref1 = MetadataReference.CreateFromStream(comp1.EmitToStream());
var refIdentity = ((AssemblyMetadata)ref1.GetMetadata()).GetAssembly().Identity.ToString();
CompileAndVerify(source2, new[] { ref1 }, expectedOutput: "42").VerifyDiagnostics(
// (8,16): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '59c700fa-e88d-45e4-acec-fd0bae894f9d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return new A(); } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 16),
// (8,39): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '59c700fa-e88d-45e4-acec-fd0bae894f9d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return new A(); } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 39));
}
[WorkItem(938389, "DevDiv")]
[Fact]
public void ShadowedTypeReceiver_3()
{
const string source1 = @"
namespace Foo
{
public class A { public int I { get { return -42; } } }
}";
const string source2 = @"
namespace Foo
{
public class A { public static int I { get { return 42; } } }
class C
{
static A A { get { return new A(); } }
static void Main()
{
System.Console.WriteLine(A.I);
}
}
}";
var comp1 = CreateCompilationWithMscorlib(source1, options: TestOptions.ReleaseDll, assemblyName: System.Guid.NewGuid().ToString());
var ref1 = MetadataReference.CreateFromStream(comp1.EmitToStream());
var refIdentity = ((AssemblyMetadata)ref1.GetMetadata()).GetAssembly().Identity.ToString();
CompileAndVerify(source2, new[] { ref1 }, expectedOutput: "42").VerifyDiagnostics(
// (8,16): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '499975c2-0b0d-4d9b-8f1f-4d91133627db, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return null; } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 16),
// (8,39): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '59c700fa-e88d-45e4-acec-fd0bae894f9d, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return new A(); } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 39),
// (12,38): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in '499975c2-0b0d-4d9b-8f1f-4d91133627db, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// System.Console.WriteLine(A.I);
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(12, 38));
}
[WorkItem(938389, "DevDiv")]
[Fact]
public void ShadowedTypeReceiver_4()
{
const string source1 = @"
namespace Foo
{
public class A { public static int I { get { return -42; } } }
}";
const string source2 = @"
namespace Foo
{
public class A { public int I { get { return 42; } } }
class C
{
static A A { get { return new A(); } }
static void Main()
{
System.Console.WriteLine(A.I);
}
}
}";
var comp1 = CreateCompilationWithMscorlib(source1, options: TestOptions.ReleaseDll, assemblyName: System.Guid.NewGuid().ToString());
var ref1 = MetadataReference.CreateFromStream(comp1.EmitToStream());
var refIdentity = ((AssemblyMetadata)ref1.GetMetadata()).GetAssembly().Identity.ToString();
CompileAndVerify(source2, new[] { ref1 }, expectedOutput: "42").VerifyDiagnostics(
// (8,16): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in 'cb07e894-1bb8-4db2-93ba-747f45e89f22, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return new A(); } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 16),
// (8,39): warning CS0436: The type 'A' in '' conflicts with the imported type 'A' in 'cb07e894-1bb8-4db2-93ba-747f45e89f22, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// static A A { get { return new A(); } }
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "A").WithArguments("", "Foo.A", refIdentity, "Foo.A").WithLocation(8, 39));
}
#endregion Regression cases
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册