Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8768,12 +8768,12 @@ static MethodGroupResolution resolveMethods(

bool inapplicable = false;
if (method.IsExtensionMethod
&& (object)method.ReduceExtensionMethod(receiverType, binder.Compilation) == null)
&& method.ReduceExtensionMethod(receiverType, binder.Compilation) is null)
{
inapplicable = true;
}
else if (method.GetIsNewExtensionMember()
&& SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(binder.Compilation, method, receiverType) == null)
&& SourceNamedTypeSymbol.ReduceExtensionMember(binder.Compilation, method, receiverType, wasExtensionFullyInferred: out _) is null)
{
inapplicable = true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1585,7 +1585,7 @@ private void CheckWhatCandidatesWeHave(
else
{
Debug.Assert(symbol.GetIsNewExtensionMember());
if (SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(this.Compilation, symbol, receiverType) is { } compatibleSubstitutedMember)
if (SourceNamedTypeSymbol.ReduceExtensionMember(this.Compilation, symbol, receiverType, wasExtensionFullyInferred: out _) is { } compatibleSubstitutedMember)
{
if (compatibleSubstitutedMember.IsStatic)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ private enum Dependency
Indirect = 0x12
}

private readonly CSharpCompilation _compilation;
#nullable enable
private readonly CSharpCompilation? _compilation;
#nullable disable
private readonly ConversionsBase _conversions;
private readonly ImmutableArray<TypeParameterSymbol> _methodTypeParameters;
private readonly NamedTypeSymbol _constructedContainingTypeOfMethod;
Expand Down Expand Up @@ -320,14 +322,14 @@ public static MethodTypeInferenceResult Infer(

#nullable enable
private MethodTypeInferrer(
CSharpCompilation compilation,
CSharpCompilation? compilation,
ConversionsBase conversions,
ImmutableArray<TypeParameterSymbol> methodTypeParameters,
NamedTypeSymbol constructedContainingTypeOfMethod,
ImmutableArray<TypeWithAnnotations> formalParameterTypes,
ImmutableArray<RefKind> formalParameterRefKinds,
ImmutableArray<BoundExpression> arguments,
Extensions extensions,
Extensions? extensions,
Dictionary<TypeParameterSymbol, int>? ordinals)
{
_compilation = compilation;
Expand Down Expand Up @@ -2856,7 +2858,7 @@ private bool Fix(int iParam, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo
}

private static (TypeWithAnnotations Type, bool FromFunctionType) Fix(
CSharpCompilation compilation,
CSharpCompilation? compilation,
ConversionsBase conversions,
TypeParameterSymbol typeParameter,
HashSet<TypeWithAnnotations>? exact,
Expand Down Expand Up @@ -2989,6 +2991,7 @@ private static (TypeWithAnnotations Type, bool FromFunctionType) Fix(
var resultType = functionType.GetInternalDelegateType();
if (hasExpressionTypeConstraint(typeParameter))
{
Debug.Assert(compilation is not null); // Tracked by https://github.com/dotnet/roslyn/issues/80658
var expressionOfTType = compilation.GetWellKnownType(WellKnownType.System_Linq_Expressions_Expression_T);
resultType = expressionOfTType.Construct(resultType);
}
Expand Down Expand Up @@ -3179,6 +3182,7 @@ private static NamedTypeSymbol GetInterfaceInferenceBound(ImmutableArray<NamedTy
// Helper methods
//

#nullable enable
/// <summary>
/// We apply type inference to an extension type, using the receiver as argument against the
/// extension parameter.
Expand All @@ -3187,7 +3191,7 @@ private static NamedTypeSymbol GetInterfaceInferenceBound(ImmutableArray<NamedTy
public static ImmutableArray<TypeWithAnnotations> InferTypeArgumentsFromReceiverType(
NamedTypeSymbol extension,
BoundExpression receiver,
CSharpCompilation compilation,
CSharpCompilation? compilation,
ConversionsBase conversions,
ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
Expand Down Expand Up @@ -3216,6 +3220,7 @@ public static ImmutableArray<TypeWithAnnotations> InferTypeArgumentsFromReceiver

return inferrer.GetInferredTypeArguments(out _);
}
#nullable disable

////////////////////////////////////////////////////////////////////////////////
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1681,7 +1681,7 @@ private ImmutableArray<ISymbol> LookupSymbolsInternal(
else
{
Debug.Assert(symbol.GetIsNewExtensionMember());
if (SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(binder.Compilation, symbol, receiverType) is { } compatibleSubstitutedMember)
if (SourceNamedTypeSymbol.ReduceExtensionMember(binder.Compilation, symbol, receiverType, wasExtensionFullyInferred: out _) is { } compatibleSubstitutedMember)
{
results.Add(compatibleSubstitutedMember.GetPublicSymbol());
}
Expand Down
2 changes: 0 additions & 2 deletions src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -717,8 +717,6 @@ public static bool CheckConstraintsForNamedType(

public static bool CheckConstraints(this NamedTypeSymbol type, in CheckConstraintsArgs args)
{
Debug.Assert(args.CurrentCompilation is object);

if (!RequiresChecking(type))
{
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,8 @@ internal static TMember ConstructIncludingExtension<TMember>(this TMember member
else
{
Debug.Assert(method.GetIsNewExtensionMember());
constructed = (MethodSymbol?)SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(compilation, constructed, receiverType);

if (checkFullyInferred && constructed?.IsGenericMethod == true && typeArguments.IsDefaultOrEmpty)
constructed = (MethodSymbol?)SourceNamedTypeSymbol.ReduceExtensionMember(compilation, constructed, receiverType, out bool wasExtensionFullyInferred);
if (checkFullyInferred && (!wasExtensionFullyInferred || (constructed?.IsGenericMethod == true && typeArguments.IsDefaultOrEmpty)))
{
return null;
}
Expand All @@ -297,7 +296,13 @@ internal static TMember ConstructIncludingExtension<TMember>(this TMember member
// infer type arguments based off the receiver type if needed, check applicability
Debug.Assert(receiverType is not null);
Debug.Assert(property.GetIsNewExtensionMember());
return (PropertySymbol?)SourceNamedTypeSymbol.GetCompatibleSubstitutedMember(compilation, property, receiverType);
var result = (PropertySymbol?)SourceNamedTypeSymbol.ReduceExtensionMember(compilation, property, receiverType, wasExtensionFullyInferred: out bool wasFullyInferred);
if (checkFullyInferred && !wasFullyInferred)
{
return null;
}

return result;
}

throw ExceptionUtilities.UnexpectedValue(member.Kind);
Expand Down
6 changes: 4 additions & 2 deletions src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,8 @@ public override TResult Accept<TResult>(CSharpSymbolVisitor<TResult> visitor)
return visitor.VisitMethod(this);
}

public MethodSymbol ReduceExtensionMethod(TypeSymbol receiverType, CSharpCompilation compilation)
#nullable enable
public MethodSymbol? ReduceExtensionMethod(TypeSymbol receiverType, CSharpCompilation? compilation)
{
return ReduceExtensionMethod(receiverType, compilation, wasFullyInferred: out _);
}
Expand All @@ -755,7 +756,7 @@ public MethodSymbol ReduceExtensionMethod(TypeSymbol receiverType, CSharpCompila
/// <param name="compilation">The compilation in which constraints should be checked.
/// Should not be null, but if it is null we treat constraints as we would in the latest
/// language version.</param>
public MethodSymbol ReduceExtensionMethod(TypeSymbol receiverType, CSharpCompilation compilation, out bool wasFullyInferred)
public MethodSymbol? ReduceExtensionMethod(TypeSymbol receiverType, CSharpCompilation? compilation, out bool wasFullyInferred)
{
if ((object)receiverType == null)
{
Expand All @@ -770,6 +771,7 @@ public MethodSymbol ReduceExtensionMethod(TypeSymbol receiverType, CSharpCompila

return ReducedExtensionMethodSymbol.Create(this, receiverType, compilation, out wasFullyInferred);
}
#nullable disable

/// <summary>
/// If this is an extension method, returns a reduced extension method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,26 @@ ITypeSymbol IMethodSymbol.GetTypeInferredDuringReduction(ITypeParameterSymbol re
GetPublicSymbol();
}

IMethodSymbol IMethodSymbol.ReduceExtensionMethod(ITypeSymbol receiverType)
#nullable enable
IMethodSymbol? IMethodSymbol.ReduceExtensionMethod(ITypeSymbol receiverType)
{
return _underlying.ReduceExtensionMethod(
receiverType.EnsureCSharpSymbolOrNull(nameof(receiverType)), compilation: null).
GetPublicSymbol();
}

IMethodSymbol? IMethodSymbol.ReduceExtensionMember(ITypeSymbol receiverType)
{
if (_underlying.GetIsNewExtensionMember() && SourceMemberContainerTypeSymbol.IsAllowedExtensionMember(_underlying))
{
var csharpReceiver = receiverType.EnsureCSharpSymbolOrNull(nameof(receiverType));
return (IMethodSymbol?)SourceNamedTypeSymbol.ReduceExtensionMember(compilation: null, _underlying, csharpReceiver, wasExtensionFullyInferred: out _).GetPublicSymbol();
}

return null;
}
#nullable disable

ImmutableArray<IMethodSymbol> IMethodSymbol.ExplicitInterfaceImplementations
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,17 @@ ImmutableArray<CustomModifier> IPropertySymbol.RefCustomModifiers
IPropertySymbol? IPropertySymbol.PartialImplementationPart => _underlying.PartialImplementationPart.GetPublicSymbol();

bool IPropertySymbol.IsPartialDefinition => (_underlying as SourcePropertySymbol)?.IsPartialDefinition ?? false;

IPropertySymbol? IPropertySymbol.ReduceExtensionMember(ITypeSymbol receiverType)
{
if (_underlying.GetIsNewExtensionMember() && SourceMemberContainerTypeSymbol.IsAllowedExtensionMember(_underlying))
{
var csharpReceiver = receiverType.EnsureCSharpSymbolOrNull(nameof(receiverType));
return (IPropertySymbol?)SourceNamedTypeSymbol.ReduceExtensionMember(compilation: null, _underlying, csharpReceiver, wasExtensionFullyInferred: out _).GetPublicSymbol();
}

return null;
}
#nullable disable

#region ISymbol Members
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1168,20 +1168,25 @@ private static string RawNameToHashString(string rawName)
return CodeAnalysis.CodeGen.PrivateImplementationDetails.HashToHex(hash);
}

internal static Symbol? GetCompatibleSubstitutedMember(CSharpCompilation compilation, Symbol extensionMember, TypeSymbol receiverType)
/// <summary>
/// Given a receiver type, check if we can infer type arguments for the extension block and check for compatibility.
/// If that is successful, return the substituted extension member and whether the extension block was fully inferred.
/// </summary>
internal static Symbol? ReduceExtensionMember(CSharpCompilation? compilation, Symbol extensionMember, TypeSymbol receiverType, out bool wasExtensionFullyInferred)
{
Debug.Assert(extensionMember.GetIsNewExtensionMember());

NamedTypeSymbol extension = extensionMember.ContainingType;
if (extension.ExtensionParameter is null)
{
wasExtensionFullyInferred = false;
return null;
}

Symbol result;
if (extensionMember.IsDefinition)
{
NamedTypeSymbol? constructedExtension = inferExtensionTypeArguments(extension, receiverType, compilation);
NamedTypeSymbol? constructedExtension = inferExtensionTypeArguments(extension, receiverType, compilation, out wasExtensionFullyInferred);
if (constructedExtension is null)
{
return null;
Expand All @@ -1191,23 +1196,27 @@ private static string RawNameToHashString(string rawName)
}
else
{
wasExtensionFullyInferred = true;
result = extensionMember;
}

ConversionsBase conversions = compilation?.Conversions ?? (ConversionsBase)extensionMember.ContainingAssembly.CorLibrary.TypeConversions;

Debug.Assert(result.ContainingType.ExtensionParameter is not null);
var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
Conversion conversion = compilation.Conversions.ConvertExtensionMethodThisArg(parameterType: result.ContainingType.ExtensionParameter.Type, receiverType, ref discardedUseSiteInfo, isMethodGroupConversion: false);
Conversion conversion = conversions.ConvertExtensionMethodThisArg(parameterType: result.ContainingType.ExtensionParameter.Type, receiverType, ref discardedUseSiteInfo, isMethodGroupConversion: false);
if (!conversion.Exists)
{
return null;
}

return result;

static NamedTypeSymbol? inferExtensionTypeArguments(NamedTypeSymbol extension, TypeSymbol receiverType, CSharpCompilation compilation)
static NamedTypeSymbol? inferExtensionTypeArguments(NamedTypeSymbol extension, TypeSymbol receiverType, CSharpCompilation? compilation, out bool wasExtensionFullyInferred)
{
if (extension.Arity == 0)
{
wasExtensionFullyInferred = true;
return extension;
}

Expand All @@ -1219,12 +1228,14 @@ private static string RawNameToHashString(string rawName)

var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
ImmutableArray<TypeWithAnnotations> typeArguments = MethodTypeInferrer.InferTypeArgumentsFromReceiverType(extension, receiverValue, compilation, conversions, ref discardedUseSiteInfo);
if (typeArguments.IsDefault || typeArguments.Any(t => !t.HasType))
if (typeArguments.IsDefault)
{
wasExtensionFullyInferred = false;
return null;
}

var result = extension.Construct(typeArguments);
ImmutableArray<TypeWithAnnotations> typeArgsForConstruct = fillNotInferredTypeArguments(extension, typeArguments, out wasExtensionFullyInferred);
var result = extension.Construct(typeArgsForConstruct);

var constraintArgs = new ConstraintsHelper.CheckConstraintsArgs(compilation, conversions, includeNullability: false,
NoLocation.Singleton, diagnostics: BindingDiagnosticBag.Discarded, template: CompoundUseSiteInfo<AssemblySymbol>.Discarded);
Expand All @@ -1237,6 +1248,20 @@ private static string RawNameToHashString(string rawName)

return result;
}

static ImmutableArray<TypeWithAnnotations> fillNotInferredTypeArguments(NamedTypeSymbol extension, ImmutableArray<TypeWithAnnotations> typeArgs, out bool wasFullyInferred)
{
// For the purpose of construction we use original type parameters in place of type arguments that we couldn't infer from the first argument.
wasFullyInferred = typeArgs.All(static t => t.HasType);
if (!wasFullyInferred)
{
return typeArgs.ZipAsArray(
extension.TypeParameters,
(t, tp) => t.HasType ? t : TypeWithAnnotations.Create(tp));
}

return typeArgs;
}
}
}
}
Loading