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
4 changes: 3 additions & 1 deletion src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3241,7 +3241,9 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind

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

// if the modifiers do not contain async or replace and the type is the identifier "async" or "replace", then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,16 @@ private SourceConstructorSymbol(

if (syntax.Identifier.ValueText != containingType.Name)
{
// This is probably a method declaration with the type missing.
diagnostics.Add(ErrorCode.ERR_MemberNeedsType, location);
if (syntax.Identifier.Text == "extension")
{
bool reported = !MessageID.IDS_FeatureExtensions.CheckFeatureAvailability(diagnostics, syntax);
Copy link
Member Author

Choose a reason for hiding this comment

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

📝 I intentionally didn't introduce a dedicated error message for this niche scenario, where the user intends to write a constructor but accidentally named it "extension" or should have named the type "extension". I think it's safe to assume the user wants an extension block

Debug.Assert(reported);
}
else
{
// This is probably a method declaration with the type missing.
diagnostics.Add(ErrorCode.ERR_MemberNeedsType, location);
}
}

bool hasAnyBody = syntax.HasAnyBody();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1843,13 +1843,16 @@ internal override IEnumerable<Symbol> GetInstanceFieldsAndEvents()
protected void AfterMembersChecks(BindingDiagnosticBag diagnostics)
{
var compilation = DeclaringCompilation;
var location = GetFirstLocation();

if (IsInterface)
{
CheckInterfaceMembers(this.GetMembersAndInitializers().NonTypeMembers, diagnostics);
}
else if (IsExtension)
{
CheckExtensionMembers(this.GetMembers(), diagnostics);
MessageID.IDS_FeatureExtensions.CheckFeatureAvailability(diagnostics, compilation, location);
}

CheckMemberNamesDistinctFromType(diagnostics);
Expand All @@ -1869,8 +1872,6 @@ protected void AfterMembersChecks(BindingDiagnosticBag diagnostics)
ReportRequiredMembers(diagnostics);
}

var location = GetFirstLocation();

if (this.IsRefLikeType)
{
compilation.EnsureIsByRefLikeAttributeExists(diagnostics, location, modifyCompilation: true);
Expand Down
Loading