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: 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