Skip to content

Commit

Permalink
Params side of the design chnages around Add methods
Browse files Browse the repository at this point in the history
  • Loading branch information
AlekseyTs committed Mar 28, 2024
1 parent 4330e53 commit edaf605
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 244 deletions.
7 changes: 6 additions & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,7 @@ static bool bindMethodGroupInvocation(
out ImmutableArray<MethodSymbol> addMethods)
{
Debug.Assert(methodGroup.ReceiverOpt is not null);
Debug.Assert(methodGroup.ReceiverOpt.Type is not null);

bool result;
CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = addMethodBinder.GetNewCompoundUseSiteInfo(diagnostics);
Expand Down Expand Up @@ -1129,6 +1130,11 @@ static bool bindMethodGroupInvocation(

addMethods = filterOutBadGenericMethods(addMethodBinder, syntax, methodGroup, analyzedArguments, resolution, finalApplicableCandidates, ref useSiteInfo);
result = !addMethods.IsEmpty;

if (!result)
{
diagnostics.Add(ErrorCode.ERR_CollectionExpressionMissingAdd, syntax, methodGroup.ReceiverOpt.Type);
}
}
}
else
Expand Down Expand Up @@ -1550,7 +1556,6 @@ private void GenerateImplicitConversionErrorForCollectionExpression(
if (elements.Length > 0 &&
!HasCollectionExpressionApplicableAddMethod(node.Syntax, targetType, addMethods: out _, diagnostics))
{
Error(diagnostics, ErrorCode.ERR_CollectionExpressionMissingAdd, node.Syntax, targetType);
reportedErrors = true;
}
}
Expand Down
41 changes: 21 additions & 20 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3407,34 +3407,50 @@ private void CheckAndCoerceArguments<TMember>(
}
}

TypeWithAnnotations parameterTypeWithAnnotations;
int paramNum = result.ParameterFromArgument(arg);

if (paramNum == parameters.Length - 1 && result.Kind == MemberResolutionKind.ApplicableInExpandedForm)
{
Debug.Assert(result.ParamsElementTypeOpt.HasType);
Debug.Assert(result.ParamsElementTypeOpt.Type != (object)ErrorTypeSymbol.EmptyParamsCollectionElementTypeSentinel);

if (!parameters[paramNum].Type.IsSZArray())
{
// Conversions to elements of non-array param collections are applied in the process of collection construction
continue;
}

parameterTypeWithAnnotations = result.ParamsElementTypeOpt;
}
else
{
parameterTypeWithAnnotations = parameters[paramNum].TypeWithAnnotations;
}

if (kind.IsInterpolatedStringHandler)
{
Debug.Assert(argument is BoundUnconvertedInterpolatedString or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true });
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
reportUnsafeIfNeeded(methodResult, diagnostics, argument, parameterTypeWithAnnotations);
arguments[arg] = BindInterpolatedStringHandlerInMemberCall(argument, parameterTypeWithAnnotations.Type, arguments, parameters, ref result, arg, receiver, diagnostics);
}
// https://github.com/dotnet/roslyn/issues/37119 : should we create an (Identity) conversion when the kind is Identity but the types differ?
else if (!kind.IsIdentity)
{
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
reportUnsafeIfNeeded(methodResult, diagnostics, argument, parameterTypeWithAnnotations);

arguments[arg] = CreateConversion(argument.Syntax, argument, kind, isCast: false, conversionGroupOpt: null, parameterTypeWithAnnotations.Type, diagnostics);
}
else if (argument.Kind == BoundKind.OutVariablePendingInference)
{
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
arguments[arg] = ((OutVariablePendingInference)argument).SetInferredTypeWithAnnotations(parameterTypeWithAnnotations, diagnostics);
}
else if (argument.Kind == BoundKind.OutDeconstructVarPendingInference)
{
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
arguments[arg] = ((OutDeconstructVarPendingInference)argument).SetInferredTypeWithAnnotations(parameterTypeWithAnnotations, success: true);
}
else if (argument.Kind == BoundKind.DiscardExpression && !argument.HasExpressionType())
{
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
Debug.Assert(parameterTypeWithAnnotations.HasType);
arguments[arg] = ((BoundDiscardExpression)argument).SetInferredTypeWithAnnotations(parameterTypeWithAnnotations);
}
Expand All @@ -3443,7 +3459,6 @@ private void CheckAndCoerceArguments<TMember>(
Debug.Assert(kind.IsIdentity);
if (argument is BoundTupleLiteral)
{
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
// CreateConversion reports tuple literal name mismatches, and constructs the expected pattern of bound nodes.
arguments[arg] = CreateConversion(argument.Syntax, argument, kind, isCast: false, conversionGroupOpt: null, parameterTypeWithAnnotations.Type, diagnostics);
}
Expand Down Expand Up @@ -3473,20 +3488,6 @@ private static ParameterSymbol GetCorrespondingParameter(ref MemberAnalysisResul
}
#nullable disable

private static TypeWithAnnotations GetCorrespondingParameterTypeWithAnnotations(ref MemberAnalysisResult result, ImmutableArray<ParameterSymbol> parameters, int arg)
{
int paramNum = result.ParameterFromArgument(arg);

if (paramNum == parameters.Length - 1 && result.Kind == MemberResolutionKind.ApplicableInExpandedForm)
{
Debug.Assert(result.ParamsElementTypeOpt.HasType);
Debug.Assert(result.ParamsElementTypeOpt.Type != (object)ErrorTypeSymbol.EmptyParamsCollectionElementTypeSentinel);
return result.ParamsElementTypeOpt;
}

return parameters[paramNum].TypeWithAnnotations;
}

private BoundExpression BindArrayCreationExpression(ArrayCreationExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
// SPEC begins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ internal void ReportDiagnostics<T>(
// Otherwise, if there is any such method that has a bad argument conversion or out/ref mismatch
// then the first such method found is the best bad method.

if (HadBadArguments(diagnostics, binder, name, arguments, symbols, location, binder.Flags, isMethodGroupConversion))
if (HadBadArguments(diagnostics, binder, name, receiver, arguments, symbols, location, binder.Flags, isMethodGroupConversion))
{
return;
}
Expand Down Expand Up @@ -505,14 +505,22 @@ internal void ReportDiagnostics<T>(
// but no argument was supplied for it then the first such method is
// the best bad method.
case MemberResolutionKind.RequiredParameterMissing:
if ((binder.Flags & BinderFlags.CollectionExpressionConversionValidation) != 0 && receiver is null)
if ((binder.Flags & BinderFlags.CollectionExpressionConversionValidation) != 0)
{
Debug.Assert(firstSupported.Member is MethodSymbol { MethodKind: MethodKind.Constructor });
diagnostics.Add(
isParamsModifierValidation ?
ErrorCode.ERR_ParamsCollectionMissingConstructor :
ErrorCode.ERR_CollectionExpressionMissingConstructor,
location);
if (receiver is null)
{
Debug.Assert(firstSupported.Member is MethodSymbol { MethodKind: MethodKind.Constructor });
diagnostics.Add(
isParamsModifierValidation ?
ErrorCode.ERR_ParamsCollectionMissingConstructor :
ErrorCode.ERR_CollectionExpressionMissingConstructor,
location);
}
else
{
Debug.Assert(firstSupported.Member is MethodSymbol { Name: "Add" });
diagnostics.Add(ErrorCode.ERR_CollectionExpressionMissingAdd, location, receiver.Type);
}
}
else
{
Expand Down Expand Up @@ -1072,6 +1080,7 @@ private bool HadBadArguments(
BindingDiagnosticBag diagnostics,
Binder binder,
string name,
BoundExpression receiver,
AnalyzedArguments arguments,
ImmutableArray<Symbol> symbols,
Location location,
Expand Down Expand Up @@ -1118,7 +1127,11 @@ private bool HadBadArguments(
}
}

if (!flags.Includes(BinderFlags.CollectionExpressionConversionValidation))
if (flags.Includes(BinderFlags.CollectionExpressionConversionValidation))
{
diagnostics.Add(ErrorCode.ERR_CollectionExpressionMissingAdd, location, receiver.Type);
}
else
{
// The best overloaded Add method '{0}' for the collection initializer has some invalid arguments
diagnostics.Add(ErrorCode.ERR_BadArgTypesForCollectionAdd, location, symbols, method);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1581,8 +1581,6 @@ void validateParamsType(BindingDiagnosticBag diagnostics)

if (!binder.HasCollectionExpressionApplicableAddMethod(syntax, Type, out ImmutableArray<MethodSymbol> addMethods, diagnostics))
{
// PROTOTYPE: Report ERR_CollectionExpressionMissingAdd or similar if there are no errors in the bag
// Probably shouldn't happen, but better safe than sorry.
return;
}

Expand Down
Loading

0 comments on commit edaf605

Please sign in to comment.