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
Original file line number Diff line number Diff line change
Expand Up @@ -719,10 +719,13 @@ private NamedTypeSymbol MakeAcyclicBaseType(BindingDiagnosticBag diagnostics)
var typeKind = this.TypeKind;
var compilation = this.DeclaringCompilation;
NamedTypeSymbol declaredBase;
bool reportAtFirstLocation = false;

if (typeKind == TypeKind.Enum)
{
Debug.Assert((object)GetDeclaredBaseType(basesBeingResolved: null) == null, "Computation skipped for enums");
declaredBase = compilation.GetSpecialType(SpecialType.System_Enum);
reportAtFirstLocation = true;
}
else if (typeKind == TypeKind.Extension)
{
Expand All @@ -745,17 +748,20 @@ private NamedTypeSymbol MakeAcyclicBaseType(BindingDiagnosticBag diagnostics)
}

declaredBase = compilation.GetSpecialType(SpecialType.System_Object);
reportAtFirstLocation = true;
break;

case TypeKind.Struct:
declaredBase = compilation.GetSpecialType(SpecialType.System_ValueType);
reportAtFirstLocation = true;
break;

case TypeKind.Interface:
return null;

case TypeKind.Delegate:
declaredBase = compilation.GetSpecialType(SpecialType.System_MulticastDelegate);
reportAtFirstLocation = true;
break;

default:
Expand Down Expand Up @@ -786,7 +792,7 @@ private NamedTypeSymbol MakeAcyclicBaseType(BindingDiagnosticBag diagnostics)
}
while ((object)current != null);

diagnostics.Add(useSiteInfo.Diagnostics.IsNullOrEmpty() ? Location.None : (FindBaseRefSyntax(declaredBase) ?? GetFirstLocation()), useSiteInfo);
diagnostics.Add(useSiteInfo.Diagnostics.IsNullOrEmpty() ? Location.None : ((reportAtFirstLocation ? null : FindBaseRefSyntax(declaredBase)) ?? GetFirstLocation()), useSiteInfo);
Copy link
Member

@jjonescz jjonescz Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How exactly did FindBaseRefSyntax cause a cycle? If it cannot handle special types for some reason, shouldn't that be fixed instead to avoid similar issues in the future? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How exactly did FindBaseRefSyntax cause a cycle? If it cannot handle special types for some reason, shouldn't that be fixed instead to avoid similar issues in the future?

Enum is the only declaration that syntactically has a base list that never contributes to the declared base value. FindBaseRefSyntax looks for a type reference in a base list. It attempts to bind types in the list, lookup needs to know base type, and for an enum, we end up here again, due to the same reason - base type is not in the base list, when we are binding types in it, we are not resolving bases. For scenarios when declaredBase isn't a result of binding of a name from base list, it doesn't make sense trying to find the type in that list.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we should just have FindBaseRefSyntax bail early for structs and enums instead. That would also have the benefit of preventing such a cycle from sneaking back in in the future if we need to get the base syntax in a new location.

Copy link
Contributor Author

@AlekseyTs AlekseyTs Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we should just have FindBaseRefSyntax bail early for structs and enums instead. That would also have the benefit of preventing such a cycle from sneaking back in in the future if we need to get the base syntax in a new location.

I don't think this is the right thing to do. The purpose of FindBaseRefSyntax is to find type reference in the base list. There is nothing wrong in using it for enum type in general. It is not appropriate for the method to decide whether it is Ok to look into the list. This specific use of the method is troublesome, especially because, in this particular case, we are looking for something that we know isn't there.


return declaredBase;
}
Expand Down
127 changes: 127 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4273,5 +4273,132 @@ void M(object obj) { }
// M<int>(default!);
Diagnostic(ErrorCode.ERR_BadArity, "M<int>").WithArguments("Program.M<T1, T2>(T1)", "method", "2").WithLocation(5, 9));
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/80987")]
public void MissingCoreReference_01()
{
var source =
@"
namespace Magic
{
public enum Cookie : UInt32;
}
";
var comp = CreateEmptyCompilation(source);
comp.VerifyDiagnostics(
// (4,17): error CS0518: Predefined type 'System.Enum' is not defined or imported
// public enum Cookie : UInt32;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Cookie").WithArguments("System.Enum").WithLocation(4, 17),
// (4,26): error CS0518: Predefined type 'System.Enum' is not defined or imported
// public enum Cookie : UInt32;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "UInt32").WithArguments("System.Enum").WithLocation(4, 26),
// (4,26): error CS0518: Predefined type 'System.Object' is not defined or imported
// public enum Cookie : UInt32;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "UInt32").WithArguments("System.Object").WithLocation(4, 26),
// (4,26): error CS0246: The type or namespace name 'UInt32' could not be found (are you missing a using directive or an assembly reference?)
// public enum Cookie : UInt32;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "UInt32").WithArguments("UInt32").WithLocation(4, 26),
// (4,26): error CS1008: Type byte, sbyte, short, ushort, int, uint, long, or ulong expected
// public enum Cookie : UInt32;
Diagnostic(ErrorCode.ERR_IntegralTypeExpected, "UInt32").WithLocation(4, 26)
);
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/80987")]
public void MissingCoreReference_02()
{
var source =
@"
namespace Magic
{
public enum Cookie : int;
}
";
var comp = CreateEmptyCompilation(source);
comp.VerifyDiagnostics(
// (4,17): error CS0518: Predefined type 'System.Enum' is not defined or imported
// public enum Cookie : int;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Cookie").WithArguments("System.Enum").WithLocation(4, 17),
// (4,26): error CS0518: Predefined type 'System.Int32' is not defined or imported
// public enum Cookie : int;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(4, 26)
);
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/80987")]
public void MissingCoreReference_03()
{
var source =
@"
namespace Magic
{
public class Cookie : UInt32;
}
";
var comp = CreateEmptyCompilation(source);
comp.VerifyDiagnostics(
// (4,27): error CS0246: The type or namespace name 'UInt32' could not be found (are you missing a using directive or an assembly reference?)
// public class Cookie : UInt32;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "UInt32").WithArguments("UInt32").WithLocation(4, 27)
);
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/80987")]
public void MissingCoreReference_04()
{
var source =
@"
namespace Magic
{
public struct Cookie : UInt32;
}
";
var comp = CreateEmptyCompilation(source);
comp.VerifyDiagnostics(
// (4,19): error CS0518: Predefined type 'System.ValueType' is not defined or imported
// public struct Cookie : UInt32;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Cookie").WithArguments("System.ValueType").WithLocation(4, 19),
// (4,28): error CS0246: The type or namespace name 'UInt32' could not be found (are you missing a using directive or an assembly reference?)
// public struct Cookie : UInt32;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "UInt32").WithArguments("UInt32").WithLocation(4, 28)
);
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/80987")]
public void MissingCoreReference_05()
{
var source =
@"
static class Ext
{
extension(Ext)
{
}
}
";
var comp = CreateEmptyCompilation(source);
comp.VerifyDiagnostics(
// (2,14): error CS0518: Predefined type 'System.Object' is not defined or imported
// static class Ext
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Ext").WithArguments("System.Object").WithLocation(2, 14),
// (4,5): error CS0518: Predefined type 'System.Object' is not defined or imported
// extension(Ext)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "extension").WithArguments("System.Object").WithLocation(4, 5),
// (4,5): error CS1110: Cannot define a new extension because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll?
// extension(Ext)
Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "extension").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(4, 5),
// (4,14): error CS0518: Predefined type 'System.Void' is not defined or imported
// extension(Ext)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "(").WithArguments("System.Void").WithLocation(4, 14),
// (4,15): error CS0518: Predefined type 'System.Object' is not defined or imported
// extension(Ext)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Ext").WithArguments("System.Object").WithLocation(4, 15)
);
}
}
}
110 changes: 110 additions & 0 deletions src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb
Original file line number Diff line number Diff line change
Expand Up @@ -26195,5 +26195,115 @@ BC30456: 'ExtensionMethodNotFound2' is not a member of 'String'.
</expected>)
End Sub

<Fact(), WorkItem("https://github.com/dotnet/roslyn/issues/80987")>
Public Sub MissingCoreReference_01()
Dim source =
<compilation name="Lib">
<file name="a.vb"><![CDATA[
Enum E As UInt32
X
End Enum
]]></file>
</compilation>

Dim compilation = CreateEmptyCompilation(source)

compilation.AssertTheseDiagnostics(
<expected>
BC30002: Type 'System.Void' is not defined.
Enum E As UInt32
~~~~~~~~~~~~~~~~~
BC30002: Type 'System.Int32' is not defined.
Enum E As UInt32
~
BC31091: Import of type '[Enum]' from assembly or module 'Lib.dll' failed.
Enum E As UInt32
~
BC30002: Type 'UInt32' is not defined.
Enum E As UInt32
~~~~~~
BC30650: Enums must be declared as an integral type.
Enum E As UInt32
~~~~~~
BC31091: Import of type '[Enum]' from assembly or module 'Lib.dll' failed.
Enum E As UInt32
~~~~~~
</expected>)
End Sub

<Fact(), WorkItem("https://github.com/dotnet/roslyn/issues/80987")>
Public Sub MissingCoreReference_02()
Dim source =
<compilation name="Lib">
<file name="a.vb"><![CDATA[
Enum E As Integer
X
End Enum
]]></file>
</compilation>

Dim compilation = CreateEmptyCompilation(source)

compilation.AssertTheseDiagnostics(
<expected>
BC30002: Type 'System.Void' is not defined.
Enum E As Integer
~~~~~~~~~~~~~~~~~~
BC31091: Import of type '[Enum]' from assembly or module 'Lib.dll' failed.
Enum E As Integer
~
BC30002: Type 'System.Int32' is not defined.
Enum E As Integer
~~~~~~~
</expected>)
End Sub

<Fact(), WorkItem("https://github.com/dotnet/roslyn/issues/80987")>
Public Sub MissingCoreReference_03()
Dim source =
<compilation name="Lib">
<file name="a.vb"><![CDATA[
Class C
Inherits UInt32
End Class
]]></file>
</compilation>

Dim compilation = CreateEmptyCompilation(source)

compilation.AssertTheseDiagnostics(
<expected>
BC30002: Type 'System.Void' is not defined.
Class C
~~~~~~~~
BC30002: Type 'UInt32' is not defined.
Inherits UInt32
~~~~~~
</expected>)
End Sub

<Fact(), WorkItem("https://github.com/dotnet/roslyn/issues/80987")>
Public Sub MissingCoreReference_04()
Dim source =
<compilation name="Lib">
<file name="a.vb"><![CDATA[
Class C
End Class
]]></file>
</compilation>

Dim compilation = CreateEmptyCompilation(source)

compilation.AssertTheseDiagnostics(
<expected>
BC30002: Type 'System.Void' is not defined.
Class C
~~~~~~~~
BC31091: Import of type 'Object' from assembly or module 'Lib.dll' failed.
Class C
~
</expected>)
End Sub

End Class
End Namespace