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
13 changes: 13 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,19 @@ internal static void ReportDiagnosticsIfObsoleteInternal(BindingDiagnosticBag di
}
}

internal static bool IsDisallowedExtensionInOlderLangVer(MethodSymbol symbol)
{
return symbol.GetIsNewExtensionMember() && (symbol.IsStatic || symbol.MethodKind != MethodKind.Ordinary);
}

internal static void ReportDiagnosticsIfDisallowedExtension(BindingDiagnosticBag diagnostics, MethodSymbol method, SyntaxNode syntax)
{
if (IsDisallowedExtensionInOlderLangVer(method))
{
MessageID.IDS_FeatureExtensions.CheckFeatureAvailability(diagnostics, syntax);
}
}

internal static void ReportDiagnosticsIfUnmanagedCallersOnly(BindingDiagnosticBag diagnostics, MethodSymbol symbol, SyntaxNodeOrToken syntax, bool isDelegateConversion)
{
var unmanagedCallersOnlyAttributeData = symbol.GetUnmanagedCallersOnlyAttributeData(forceComplete: false);
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,7 @@ private bool HasCollectionInitializerTypeInProgress(SyntaxNode syntax, TypeSymbo
ReportDiagnosticsIfObsolete(diagnostics, collectionBuilderMethod.ContainingType, syntax, hasBaseReceiver: false);
ReportDiagnosticsIfObsolete(diagnostics, collectionBuilderMethod, syntax, hasBaseReceiver: false);
ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, collectionBuilderMethod, syntax, isDelegateConversion: false);
Debug.Assert(!collectionBuilderMethod.GetIsNewExtensionMember());

return collectionBuilderMethod;
}
Expand Down Expand Up @@ -1430,11 +1431,14 @@ static bool bindMethodGroupInvocation(
{
addMethodBinder.ReportDiagnosticsIfObsolete(diagnostics, addMethods[0], syntax, hasBaseReceiver: false);
ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, addMethods[0], syntax, isDelegateConversion: false);
Debug.Assert(!IsDisallowedExtensionInOlderLangVer(addMethods[0]));
}
}
}
else
{
Debug.Assert(!resolution.OverloadResolutionResult.Succeeded);

result = bindInvocationExpressionContinued(
addMethodBinder, syntax, expression, resolution.OverloadResolutionResult, resolution.AnalyzedArguments,
resolution.MethodGroup, diagnostics: diagnostics, out var addMethod);
Expand Down Expand Up @@ -1622,6 +1626,7 @@ static bool bindInvocationExpressionContinued(

addMethodBinder.ReportDiagnosticsIfObsolete(diagnostics, method, node, hasBaseReceiver: false);
ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, method, node, isDelegateConversion: false);
ReportDiagnosticsIfDisallowedExtension(diagnostics, method, node);

// No use site errors, but there could be use site warnings.
// If there are any use site warnings, they have already been reported by overload resolution.
Expand Down Expand Up @@ -3051,6 +3056,7 @@ private bool MethodGroupConversionHasErrors(
ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, selectedMethod, syntax, isDelegateConversion: true);
}
ReportDiagnosticsIfObsolete(diagnostics, selectedMethod, syntax, hasBaseReceiver: false);
ReportDiagnosticsIfDisallowedExtension(diagnostics, selectedMethod, syntax);

// No use site errors, but there could be use site warnings.
// If there are use site warnings, they were reported during the overload resolution process
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8030,6 +8030,7 @@ private BoundExpression MakeMemberAccessValue(BoundExpression expr, BindingDiagn

private BoundExpression GetExtensionMemberAccess(SyntaxNode syntax, BoundExpression? receiver, Symbol extensionMember, BindingDiagnosticBag diagnostics)
{
MessageID.IDS_FeatureExtensions.CheckFeatureAvailability(diagnostics, syntax);
receiver = ReplaceTypeOrValueReceiver(receiver, useType: extensionMember.IsStatic, diagnostics);

switch (extensionMember)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1325,6 +1325,7 @@ private BoundCall BindInvocationExpressionContinued(

ReportDiagnosticsIfObsolete(diagnostics, method, node, hasBaseReceiver);
ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, method, node, isDelegateConversion: false);
ReportDiagnosticsIfDisallowedExtension(diagnostics, method, node);

// No use site errors, but there could be use site warnings.
// If there are any use site warnings, they have already been reported by overload resolution.
Expand Down
41 changes: 19 additions & 22 deletions src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,37 +202,34 @@ internal void EnumerateAllExtensionMembersInSingleBinder(ArrayBuilder<SingleLook
PooledHashSet<MethodSymbol>? implementationsToShadow = null;

// 1. Collect new extension members
if (this.Compilation.LanguageVersion.AllowNewExtensions())
{
var extensionDeclarations = ArrayBuilder<NamedTypeSymbol>.GetInstance();
this.GetExtensionDeclarations(extensionDeclarations, originalBinder);
var extensionDeclarations = ArrayBuilder<NamedTypeSymbol>.GetInstance();
this.GetExtensionDeclarations(extensionDeclarations, originalBinder);

foreach (NamedTypeSymbol extensionDeclaration in extensionDeclarations)
foreach (NamedTypeSymbol extensionDeclaration in extensionDeclarations)
{
if (extensionDeclaration.ExtensionParameter is null)
{
if (extensionDeclaration.ExtensionParameter is null)
{
continue;
}
continue;
}

var candidates = name is null ? extensionDeclaration.GetMembers() : extensionDeclaration.GetMembers(name);
var candidates = name is null ? extensionDeclaration.GetMembers() : extensionDeclaration.GetMembers(name);

foreach (var candidate in candidates)
{
SingleLookupResult resultOfThisMember = originalBinder.CheckViability(candidate, arity, options, null, diagnose: true, useSiteInfo: ref useSiteInfo);
result.Add(resultOfThisMember);
foreach (var candidate in candidates)
{
SingleLookupResult resultOfThisMember = originalBinder.CheckViability(candidate, arity, options, null, diagnose: true, useSiteInfo: ref useSiteInfo);
result.Add(resultOfThisMember);

if (candidate is MethodSymbol { IsStatic: false } shadows &&
shadows.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() is { } toShadow)
{
implementationsToShadow ??= PooledHashSet<MethodSymbol>.GetInstance();
implementationsToShadow.Add(toShadow);
}
if (candidate is MethodSymbol { IsStatic: false } shadows &&
shadows.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() is { } toShadow)
{
implementationsToShadow ??= PooledHashSet<MethodSymbol>.GetInstance();
implementationsToShadow.Add(toShadow);
}
}

extensionDeclarations.Free();
}

extensionDeclarations.Free();

// 2. Collect classic extension methods
var extensionMethods = ArrayBuilder<MethodSymbol>.GetInstance();
this.GetCandidateExtensionMethods(extensionMethods, name, arity, options, originalBinder: originalBinder);
Expand Down
4 changes: 4 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -465,12 +465,16 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno
var foreachKeyword = _syntax.ForEachKeyword;
ReportDiagnosticsIfObsolete(diagnostics, getEnumeratorMethod, foreachKeyword, hasBaseReceiver: false);
ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, getEnumeratorMethod, foreachKeyword, isDelegateConversion: false);
Debug.Assert(!IsDisallowedExtensionInOlderLangVer(getEnumeratorMethod));

// MoveNext is an instance method, so it does not need to have unmanaged callers only diagnostics reported.
// Either a diagnostic was reported at the declaration of the method (for the invalid attribute), or MoveNext
// is marked as not supported and we won't get here in the first place (for metadata import).
ReportDiagnosticsIfObsolete(diagnostics, builder.MoveNextInfo.Method, foreachKeyword, hasBaseReceiver: false);
ReportDiagnosticsIfObsolete(diagnostics, builder.CurrentPropertyGetter, foreachKeyword, hasBaseReceiver: false);
ReportDiagnosticsIfObsolete(diagnostics, builder.CurrentPropertyGetter.AssociatedSymbol, foreachKeyword, hasBaseReceiver: false);
Debug.Assert(!IsDisallowedExtensionInOlderLangVer(builder.MoveNextInfo.Method));
Debug.Assert(!IsDisallowedExtensionInOlderLangVer(builder.CurrentPropertyGetter));

// We want to convert from inferredType in the array/string case and builder.ElementType in the enumerator case,
// but it turns out that these are equivalent (when both are available).
Expand Down
5 changes: 0 additions & 5 deletions src/Compilers/CSharp/Portable/LanguageVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -572,10 +572,5 @@ internal static bool AllowImprovedOverloadCandidates(this LanguageVersion self)
{
return self >= MessageID.IDS_FeatureImprovedOverloadCandidates.RequiredVersion();
}

internal static bool AllowNewExtensions(this LanguageVersion self)
{
return self >= MessageID.IDS_FeatureExtensions.RequiredVersion();
}
}
}
Loading