Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -553,8 +553,7 @@ private Symbol ResolveMultipleSymbolsInAttributeTypeLookup(ArrayBuilder<Symbol>
var mdSymbol = symbols[secondBest.Index];

//if names match, arities match, and containing symbols match (recursively), ...
if (srcSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat) ==
mdSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat))
if (NameAndArityMatchRecursively(srcSymbol, mdSymbol))
{
return originalSymbols[best.Index];
}
Expand All @@ -563,6 +562,29 @@ private Symbol ResolveMultipleSymbolsInAttributeTypeLookup(ArrayBuilder<Symbol>
return null;
}

private static bool NameAndArityMatchRecursively(Symbol x, Symbol y)
{
while (true)
{
if (isRoot(x))
{
return isRoot(y);
}
if (isRoot(y))
{
return false;
}
if (x.Name != y.Name || x.GetArity() != y.GetArity())
{
return false;
}
x = x.ContainingSymbol;
y = y.ContainingSymbol;
}

static bool isRoot(Symbol symbol) => symbol is null || symbol is NamespaceSymbol { IsGlobalNamespace: true };
}

private bool IsSingleViableAttributeType(LookupResult result, out Symbol symbol)
{
if (IsAmbiguousResult(result, out symbol))
Expand Down
6 changes: 2 additions & 4 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1589,8 +1589,7 @@ Symbol resultSymbol(
}

//if names match, arities match, and containing symbols match (recursively), ...
if (srcSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat) ==
mdSymbol.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat))
if (NameAndArityMatchRecursively(srcSymbol, mdSymbol))
{
if (srcSymbol.Kind == SymbolKind.Namespace && mdSymbol.Kind == SymbolKind.NamedType)
{
Expand Down Expand Up @@ -1647,8 +1646,7 @@ Symbol resultSymbol(

//if names match, arities match, and containing symbols match (recursively), ...
if (first != second &&
first.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat) ==
second.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat))
NameAndArityMatchRecursively(first, second))
{
// suppress reporting the error if we found multiple symbols from source module
// since an error has already been reported from the declaration
Expand Down
76 changes: 76 additions & 0 deletions src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7653,6 +7653,82 @@ class Goo: Attribute
Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "X").WithArguments("X"));
}

[Fact]
public void AmbiguousClassNamespaceLookup_Container()
{
var source1 =
@"using System;
public class A : Attribute { }
namespace N1
{
public class B : Attribute { }
public class C : Attribute { }
}";
var comp = CreateCompilation(source1, assemblyName: "A");
var ref1 = comp.EmitToImageReference();

var source2 =
@"using System;
using N1;
using N2;
namespace N1
{
class A : Attribute { }
class B : Attribute { }
}
namespace N2
{
class C : Attribute { }
}
[A]
[B]
[C]
class D
{
}";
comp = CreateCompilation(source2, references: new[] { ref1 }, assemblyName: "B");
comp.VerifyDiagnostics(
// (14,2): warning CS0436: The type 'B' in '' conflicts with the imported type 'B' in 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Using the type defined in ''.
// [B]
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "B").WithArguments("", "N1.B", "A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "N1.B").WithLocation(14, 2),
// (15,2): error CS0104: 'C' is an ambiguous reference between 'N2.C' and 'N1.C'
// [C]
Diagnostic(ErrorCode.ERR_AmbigContext, "C").WithArguments("C", "N2.C", "N1.C").WithLocation(15, 2));
}

[Fact]
public void AmbiguousClassNamespaceLookup_Generic()
{
var source1 =
@"public class A { }
public class B<T> { }
public class C<T, U> { }";
var comp = CreateCompilation(source1);
var ref1 = comp.EmitToImageReference();

var source2 =
@"class A<U> { }
class B<U> { }
class C<U> { }
[A]
[B]
[C]
class D
{
}";
comp = CreateCompilation(source2, references: new[] { ref1 });
comp.VerifyDiagnostics(
// (4,2): error CS0616: 'A' is not an attribute class
// [A]
Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "A").WithArguments("A").WithLocation(4, 2),
// (5,2): error CS0404: Cannot apply attribute class 'B<U>' because it is generic
// [B]
Diagnostic(ErrorCode.ERR_AttributeCantBeGeneric, "B").WithArguments("B<U>").WithLocation(5, 2),
// (6,2): error CS0305: Using the generic type 'C<U>' requires 1 type arguments
// [C]
Diagnostic(ErrorCode.ERR_BadArity, "C").WithArguments("C<U>", "type", "1").WithLocation(6, 2));
}

[WorkItem(546283, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546283")]
[Fact]
public void ApplyIndexerNameAttributeTwice()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5971,5 +5971,38 @@ static void M() { }
Assert.Null(info.Symbol);
Assert.Equal(CandidateReason.NotReferencable, info.CandidateReason);
}

[Fact]
[WorkItem(42840, "https://github.com/dotnet/roslyn/issues/42840")]
public void DuplicateTypeArgument()
{
var source =
@"class A<T>
{
}
class B<T, U, U>
where T : A<U>
where U : class
{
}";

var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,15): error CS0692: Duplicate type parameter 'U'
// class B<T, U, U>
Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "U").WithArguments("U").WithLocation(4, 15),
// (5,17): error CS0229: Ambiguity between 'U' and 'U'
// where T : A<U>
Diagnostic(ErrorCode.ERR_AmbigMember, "U").WithArguments("U", "U").WithLocation(5, 17));

comp = CreateCompilation(source);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var typeParameters = tree.GetRoot().DescendantNodes().OfType<TypeParameterSyntax>().ToArray();
var symbol = model.GetDeclaredSymbol(typeParameters[typeParameters.Length - 1]);
Assert.False(symbol.IsReferenceType);
symbol = model.GetDeclaredSymbol(typeParameters[typeParameters.Length - 2]);
Assert.True(symbol.IsReferenceType);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,11 @@ static void Main() {
public void CanNotReadPropertyFromAmbiguousGenericClass()
{
const string ilSource = @"
.assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) }
.assembly '09f9df97-a228-4ca4-9b71-151909f205e6'
{
}

.class public A`1<T> {
.method public static int32 get_Goo() { ldnull throw }
.property int32 Goo() { .get int32 A`1::get_Goo() }
Expand All @@ -1571,17 +1576,19 @@ .class public A<T> {
.property int32 Goo() { .get int32 A::get_Goo() }
}
";
var ref0 = CompileIL(ilSource, prependDefaultHeader: false);

const string cSharpSource = @"
class B {
static void Main() {
object x = A<int>.Goo;
}
}
";
CreateCompilationWithILAndMscorlib40(cSharpSource, ilSource).VerifyDiagnostics(
// (4,16): error CS0104: 'A<>' is an ambiguous reference between 'A<T>' and 'A<T>'
CreateCompilation(cSharpSource, references: new[] { ref0 }).VerifyDiagnostics(
// (4,16): error CS0433: The type 'A<T>' exists in both '09f9df97-a228-4ca4-9b71-151909f205e6, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and '09f9df97-a228-4ca4-9b71-151909f205e6, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
// object x = A<int>.Goo;
Diagnostic(ErrorCode.ERR_AmbigContext, "A<int>").WithArguments("A<>", "A<T>", "A<T>").WithLocation(4, 16));
Diagnostic(ErrorCode.ERR_SameFullNameAggAgg, "A<int>").WithArguments("09f9df97-a228-4ca4-9b71-151909f205e6, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "A<T>", "09f9df97-a228-4ca4-9b71-151909f205e6, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 16));
}

[WorkItem(538789, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538789")]
Expand Down