Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow by-ref Extension methods on value types #15535

Closed
wants to merge 15 commits into from
Closed
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
20 changes: 15 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5635,19 +5635,29 @@ private MethodGroupResolution BindExtensionMethod(
diagnostics.Free();
continue;
}

RefOmitMode refOmitMode = RefOmitMode.None;
if (actualArguments == null)
{
// Create a set of arguments for overload resolution of the
// extension methods that includes the "this" parameter.
actualArguments = AnalyzedArguments.GetInstance();
refOmitMode = RefOmitMode.ExtensionMethod;
CombineExtensionMethodArguments(left, analyzedArguments, actualArguments);
}

var overloadResolutionResult = OverloadResolutionResult<MethodSymbol>.GetInstance();
bool allowRefOmittedArguments = methodGroup.Receiver.IsExpressionOfComImportType();
var overloadResolutionResult = OverloadResolutionResult<MethodSymbol>.GetInstance() ;
if (methodGroup.Receiver.IsExpressionOfComImportType())
{
refOmitMode = RefOmitMode.All;
}
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
OverloadResolution.MethodInvocationOverloadResolution(methodGroup.Methods, methodGroup.TypeArguments, actualArguments, overloadResolutionResult, ref useSiteDiagnostics, isMethodGroupConversion, allowRefOmittedArguments);
OverloadResolution.MethodInvocationOverloadResolution(methodGroup.Methods,
methodGroup.TypeArguments,
actualArguments,
overloadResolutionResult,
ref useSiteDiagnostics,
isMethodGroupConversion,
refOmitMode);
diagnostics.Add(expression, useSiteDiagnostics);
var sealedDiagnostics = diagnostics.ToReadOnlyAndFree();
var result = new MethodGroupResolution(methodGroup, null, overloadResolutionResult, actualArguments, methodGroup.ResultKind, sealedDiagnostics);
Expand Down Expand Up @@ -6778,7 +6788,7 @@ private MethodGroupResolution ResolveDefaultMethodGroup(
bool allowRefOmittedArguments = methodGroup.Receiver.IsExpressionOfComImportType();
OverloadResolution.MethodInvocationOverloadResolution(
methodGroup.Methods, methodGroup.TypeArguments, analyzedArguments,
result, ref useSiteDiagnostics, isMethodGroupConversion, allowRefOmittedArguments,
result, ref useSiteDiagnostics, isMethodGroupConversion, allowRefOmittedArguments ? RefOmitMode.All : RefOmitMode.None,
inferWithDynamic: inferWithDynamic, allowUnexpandedForm: allowUnexpandedForm);
return new MethodGroupResolution(methodGroup, null, result, analyzedArguments, methodGroup.ResultKind, sealedDiagnostics);
}
Expand Down
8 changes: 8 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,14 @@ private BoundCall BindInvocationExpressionContinued(
args = analyzedArguments.Arguments.ToImmutable();
}

// Verify that receiver is accessible if by-ref extension method
if (invokedAsExtensionMethod &&
!method.ParameterRefKinds.IsDefaultOrEmpty &&
method.ParameterRefKinds[0] == RefKind.Ref)
{
CheckIsVariable(expression, args[0], BindValueKind.RefOrOut, false, diagnostics);
}

// This will be the receiver of the BoundCall node that we create.
// For extension methods, there is no receiver because the receiver in source was actually the first argument.
// For instance methods, we may have synthesized an implicit this node. We'll keep it for the emitter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal struct MemberAnalysisResult
/// Omit ref feature for COM interop: We can pass arguments by value for ref parameters if we are invoking a method/property on an instance of a COM imported type.
/// This property returns a flag indicating whether we had any ref omitted argument for the given call.
/// </summary>
public readonly bool HasAnyRefOmittedArgument;
public readonly bool HasAnyComRefOmittedArgument;

private MemberAnalysisResult(MemberResolutionKind kind)
: this(kind, default(ImmutableArray<int>), default(ImmutableArray<int>), default(ImmutableArray<Conversion>))
Expand All @@ -35,14 +35,14 @@ private MemberAnalysisResult(
ImmutableArray<int> argsToParamsOpt,
ImmutableArray<Conversion> conversionsOpt,
int missingParameter = -1,
bool hasAnyRefOmittedArgument = false)
bool hasAnyComRefOmittedArgument = false)
{
this.Kind = kind;
this.BadArgumentsOpt = badArgumentsOpt;
this.ArgsToParamsOpt = argsToParamsOpt;
this.ConversionsOpt = conversionsOpt;
this.BadParameter = missingParameter;
this.HasAnyRefOmittedArgument = hasAnyRefOmittedArgument;
this.HasAnyComRefOmittedArgument = hasAnyComRefOmittedArgument;
}

public override bool Equals(object obj)
Expand Down Expand Up @@ -246,14 +246,14 @@ public static MemberAnalysisResult LessDerived()
return new MemberAnalysisResult(MemberResolutionKind.LessDerived);
}

public static MemberAnalysisResult NormalForm(ImmutableArray<int> argsToParamsOpt, ImmutableArray<Conversion> conversions, bool hasAnyRefOmittedArgument)
public static MemberAnalysisResult NormalForm(ImmutableArray<int> argsToParamsOpt, ImmutableArray<Conversion> conversions, bool hasAnyComRefOmittedArgument)
{
return new MemberAnalysisResult(MemberResolutionKind.ApplicableInNormalForm, default(ImmutableArray<int>), argsToParamsOpt, conversions, hasAnyRefOmittedArgument: hasAnyRefOmittedArgument);
return new MemberAnalysisResult(MemberResolutionKind.ApplicableInNormalForm, default(ImmutableArray<int>), argsToParamsOpt, conversions, hasAnyComRefOmittedArgument: hasAnyComRefOmittedArgument);
}

public static MemberAnalysisResult ExpandedForm(ImmutableArray<int> argsToParamsOpt, ImmutableArray<Conversion> conversions, bool hasAnyRefOmittedArgument)
public static MemberAnalysisResult ExpandedForm(ImmutableArray<int> argsToParamsOpt, ImmutableArray<Conversion> conversions, bool hasAnyComRefOmittedArgument)
{
return new MemberAnalysisResult(MemberResolutionKind.ApplicableInExpandedForm, default(ImmutableArray<int>), argsToParamsOpt, conversions, hasAnyRefOmittedArgument: hasAnyRefOmittedArgument);
return new MemberAnalysisResult(MemberResolutionKind.ApplicableInExpandedForm, default(ImmutableArray<int>), argsToParamsOpt, conversions, hasAnyComRefOmittedArgument: hasAnyComRefOmittedArgument);
}

public static MemberAnalysisResult Worse()
Expand Down
Loading