Skip to content

Commit 7c0f70d

Browse files
author
Julien Couvreur
authored
Extensions: improve error recovery in older language versions (#80206)
1 parent 984aa24 commit 7c0f70d

File tree

4 files changed

+497
-87
lines changed

4 files changed

+497
-87
lines changed

src/Compilers/CSharp/Portable/Parser/LanguageParser.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3241,7 +3241,9 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind
32413241

32423242
private bool IsExtensionContainerStart()
32433243
{
3244-
return this.CurrentToken.ContextualKind == SyntaxKind.ExtensionKeyword && IsFeatureEnabled(MessageID.IDS_FeatureExtensions);
3244+
// For error recovery, we recognize `extension` followed by `<` even in older language versions
3245+
return this.CurrentToken.ContextualKind == SyntaxKind.ExtensionKeyword &&
3246+
(IsFeatureEnabled(MessageID.IDS_FeatureExtensions) || this.PeekToken(1).Kind == SyntaxKind.LessThanToken);
32453247
}
32463248

32473249
// if the modifiers do not contain async or replace and the type is the identifier "async" or "replace", then

src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,16 @@ private SourceConstructorSymbol(
4747

4848
if (syntax.Identifier.ValueText != containingType.Name)
4949
{
50-
// This is probably a method declaration with the type missing.
51-
diagnostics.Add(ErrorCode.ERR_MemberNeedsType, location);
50+
if (syntax.Identifier.Text == "extension")
51+
{
52+
bool reported = !MessageID.IDS_FeatureExtensions.CheckFeatureAvailability(diagnostics, syntax);
53+
Debug.Assert(reported);
54+
}
55+
else
56+
{
57+
// This is probably a method declaration with the type missing.
58+
diagnostics.Add(ErrorCode.ERR_MemberNeedsType, location);
59+
}
5260
}
5361

5462
bool hasAnyBody = syntax.HasAnyBody();

src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,13 +1843,16 @@ internal override IEnumerable<Symbol> GetInstanceFieldsAndEvents()
18431843
protected void AfterMembersChecks(BindingDiagnosticBag diagnostics)
18441844
{
18451845
var compilation = DeclaringCompilation;
1846+
var location = GetFirstLocation();
1847+
18461848
if (IsInterface)
18471849
{
18481850
CheckInterfaceMembers(this.GetMembersAndInitializers().NonTypeMembers, diagnostics);
18491851
}
18501852
else if (IsExtension)
18511853
{
18521854
CheckExtensionMembers(this.GetMembers(), diagnostics);
1855+
MessageID.IDS_FeatureExtensions.CheckFeatureAvailability(diagnostics, compilation, location);
18531856
}
18541857

18551858
CheckMemberNamesDistinctFromType(diagnostics);
@@ -1869,8 +1872,6 @@ protected void AfterMembersChecks(BindingDiagnosticBag diagnostics)
18691872
ReportRequiredMembers(diagnostics);
18701873
}
18711874

1872-
var location = GetFirstLocation();
1873-
18741875
if (this.IsRefLikeType)
18751876
{
18761877
compilation.EnsureIsByRefLikeAttributeExists(diagnostics, location, modifyCompilation: true);

0 commit comments

Comments
 (0)