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

Params side of the design changes around Add methods #72771

Merged
merged 7 commits into from
Mar 29, 2024

Conversation

AlekseyTs
Copy link
Contributor

@AlekseyTs AlekseyTs commented Mar 28, 2024

The main observable change - the original (unconverted) params arguments are used in the process of populating target collection.

Spec changes: dotnet/csharplang#8022

Fixes #72098

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Mar 28, 2024
}

return parameters[paramNum].TypeWithAnnotations;
BoundExpression bindInterpolatedStringHandlerInMemberCall(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bindInterpolatedStringHandlerInMemberCall

This used to be BindInterpolatedStringHandlerInMemberCall at the end of the Binder_InterpolatedString.cs. No meaningful changes during the move.

@@ -873,227 +873,5 @@ private ImmutableArray<BoundExpression> BindInterpolatedStringParts(BoundUnconve
positionInfo.Free();
return (builderAppendCallsArray.ToImmutableAndFree(), builderPatternExpectsBool ?? false, positionInfoArray.ToImmutableAndFree(), baseStringLength, numFormatHoles);
}

private BoundExpression BindInterpolatedStringHandlerInMemberCall(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BindInterpolatedStringHandlerInMemberCall

Moved as a local function bindInterpolatedStringHandlerInMemberCall to Binder_Expressions.cs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have a slight leaning towards keeping this where it is. I won't block on it, but I did put this here intentionally, rather than making it a local function in CoerceArguments, because I wanted to keep all the interpolation logic together.

Copy link
Contributor Author

@AlekseyTs AlekseyTs Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have a slight leaning towards keeping this where it is. I won't block on it, but I did put this here intentionally, rather than making it a local function in CoerceArguments, because I wanted to keep all the interpolation logic together.

The primary reason for the move is to constrain access to MemberAnalysisResult,.ArgsToParamsOpt to as few helpers that anyone can call in the future as possible. I was able make other helper(s) local functions, I wouldn't be able otherwise. I find that more important than a desire to keep interpolation logic in a separate file.

BoundExpression bindInterpolatedStringHandlerInMemberCall(
BoundExpression unconvertedString,
TypeSymbol handlerType,
ArrayBuilder<BoundExpression>? arguments,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArrayBuilder? arguments,

Made this parameter nullable.

diagnostics);
}

Debug.Assert(arguments is not null);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug.Assert(arguments is not null);

Added this assert.

Debug.Assert(paramsArgsBuilder.Count == 0);

firstParamsArgument = i;
paramsArgsBuilder.Add(argumentsBuilder[i]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paramsArgsBuilder.Add(argumentsBuilder[i]);

Logic for this and the next statement (the for) was moved to local function CheckAndCoerceArguments.collectParamsArgs

return coercedArgument;
}

ArrayBuilder<BoundExpression> collectParamsArgs(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collectParamsArgs

This is essentially the logic that used to be in a loop at the beginning of BindDefaultArgumentsAndParamsCollection

ImmutableArray<BoundExpression> collectionArgs = paramsArgsBuilder.ToImmutableAndFree();
int collectionArgsLength = collectionArgs.Length;

TypeSymbol collectionType = parameters[paramsIndex].Type;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeSymbol collectionType = parameters[paramsIndex].Type;

Code starting from here through Debug.Assert(collection.IsParamsArrayOrCollection); is extracted to CreateParamsCollection helper. No chnages to the code other than making parameters[paramsIndex] a parameter named "paramsParameter".

@@ -1900,6 +1741,116 @@ static int getArgumentIndex(int parameterIndex, ImmutableArray<int> argsToParams

}

private BoundExpression CreateParamsCollection(SyntaxNode node, ParameterSymbol paramsParameter, ImmutableArray<BoundExpression> collectionArgs, BindingDiagnosticBag diagnostics)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateParamsCollection

This is a helper extracted from BindDefaultArgumentsAndParamsCollection. See a comment at the original location

Debug.Assert(!haveDefaultArguments || collectionArgsLength == 1);
Debug.Assert(collectionArgsLength == 1 || firstParamsArgument + collectionArgsLength == argumentsBuilder.Count);

for (var i = firstParamsArgument + collectionArgsLength - 1; i != firstParamsArgument; i--)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (var i = firstParamsArgument + collectionArgsLength - 1; i != firstParamsArgument; i--)

Logic in this loop is moved to a loop at the end of the CheckAndCoerceArguments.createParamsCollection local function

argsToParamsBuilder.AddRange(argsToParamsOpt);
}

for (var i = firstParamsArgument + collectionArgs.Length - 1; i != firstParamsArgument; i--)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (var i = firstParamsArgument + collectionArgs.Length - 1; i != firstParamsArgument; i--)

Logic in this loop used to be in BindDefaultArgumentsAndParamsCollection. See a comment at the original location.

@AlekseyTs AlekseyTs changed the title Params side of the design chnages around Add methods Params side of the design changes around Add methods Mar 28, 2024
@AlekseyTs AlekseyTs marked this pull request as ready for review March 28, 2024 22:03
@AlekseyTs AlekseyTs requested a review from a team as a code owner March 28, 2024 22:03
@AlekseyTs
Copy link
Contributor Author

@cston, @RikkiGibson, @333fred Please review

@RikkiGibson RikkiGibson self-assigned this Mar 28, 2024
return coercedArgument;
}

ArrayBuilder<BoundExpression> collectParamsArgs(
Copy link
Member

@cston cston Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collectParamsArgs

Can this local function be static? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this local function be static?

Yes, changing.

(BoundKind.OutVariablePendingInference or BoundKind.OutDeconstructVarPendingInference or BoundKind.DiscardExpression or BoundKind.ArgListOperator));

// Conversions to elements of collection are applied in the process of collection construction
paramsArgsBuilder.Add(arguments[arg]);
Copy link
Member

@cston cston Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extracting a local function for use here and inside the while loop. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extracting a local function for use here and inside the while loop.

Are you referring to paramsArgsBuilder.Add(arguments[arg]);? If so, I do not believe it is worth the trouble. There isn't enough "critical mass" in combined complexity and volume to gain much from sharing. A call would look as complicated as the current code, in my opinion.

Copy link
Contributor Author

@AlekseyTs AlekseyTs Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a closer look, I ended up refactoring the loop and avoiding the duplication.

}

// Note, this function is going to free paramsArgsBuilder
void createParamsCollection(
Copy link
Member

@cston cston Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

void

static? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coerceArgument cannot be static, this disallows createParamsCollection to be static.

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking, so I'm signing off.

}

/// <summary>
/// A bit vector representing whose true bits indicate indices of bad arguments
Copy link
Member

@333fred 333fred Mar 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// A bit vector representing whose true bits indicate indices of bad arguments
/// A bit vector whose true bits indicate indices of bad arguments
``` #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment was copied from below. I have no intent fixing it in this PR. Feel free to fix both comments after the PR is merged.

@@ -9435,7 +9816,7 @@ private BoundExpression BindIndexedPropertyAccess(SyntaxNode syntax, BoundExpres
PropertySymbol property = resolutionResult.Member;

var isExpanded = resolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm;
var argsToParams = resolutionResult.Result.ArgsToParamsOpt;
ImmutableArray<int> argsToParams;
Copy link
Member

@333fred 333fred Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: consider moving this declaration closer to the usage, or inline. #Resolved

@@ -873,227 +873,5 @@ private ImmutableArray<BoundExpression> BindInterpolatedStringParts(BoundUnconve
positionInfo.Free();
return (builderAppendCallsArray.ToImmutableAndFree(), builderPatternExpectsBool ?? false, positionInfoArray.ToImmutableAndFree(), baseStringLength, numFormatHoles);
}

private BoundExpression BindInterpolatedStringHandlerInMemberCall(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have a slight leaning towards keeping this where it is. I won't block on it, but I did put this here intentionally, rather than making it a local function in CoerceArguments, because I wanted to keep all the interpolation logic together.

@AlekseyTs AlekseyTs requested a review from cston March 29, 2024 02:51
@@ -651,7 +651,8 @@ class Program
Assert.True(attributeData.HasErrors);
Assert.Equal("AAttribute..ctor(params System.Int32[] args)", attributeData.AttributeConstructor.ToTestDisplayString());
Assert.Equal(1, attributeData.AttributeConstructor.ParameterCount);
Assert.Equal(new object[] { 1, 2, 3 }, attributeData.ConstructorArguments.Select(arg => arg.Value));
Assert.Equal(TypedConstantKind.Array, attributeData.ConstructorArguments.Single().Kind);
Copy link
Member

@cston cston Mar 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attributeData.ConstructorArguments.Single()

Is this a meaningful change to the public API behavior for AttributeData.ConstructorArguments? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a meaningful change to the public API behavior for AttributeData.ConstructorArguments?

Yes. In some error conditions we are actually manage to create an array. The behavior is close to the success case now, see the other test I modified in this file

@AlekseyTs AlekseyTs enabled auto-merge (squash) March 29, 2024 03:27
@AlekseyTs AlekseyTs merged commit eadc0cc into dotnet:features/CollectionAdd Mar 29, 2024
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants