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

Create default arguments during binding #49186

Merged
merged 6 commits into from
Nov 14, 2020
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
69 changes: 60 additions & 9 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,61 @@ private static bool RequiresRefOrOut(BindValueKind kind)
return (kind & BindValueKind.RefOrOut) == BindValueKind.RefOrOut;
}

#nullable enable

private BoundIndexerAccess BindIndexerDefaultArguments(BoundIndexerAccess indexerAccess, BindValueKind valueKind, DiagnosticBag diagnostics)
{
var useSetAccessor = valueKind == BindValueKind.Assignable && !indexerAccess.Indexer.ReturnsByRef;
var accessorForDefaultArguments = useSetAccessor
? indexerAccess.Indexer.GetOwnOrInheritedSetMethod()
: indexerAccess.Indexer.GetOwnOrInheritedGetMethod();
if (accessorForDefaultArguments is not null)
{
var argumentsBuilder = ArrayBuilder<BoundExpression>.GetInstance(accessorForDefaultArguments.ParameterCount);
argumentsBuilder.AddRange(indexerAccess.Arguments);

ArrayBuilder<RefKind>? refKindsBuilderOpt;
if (!indexerAccess.ArgumentRefKindsOpt.IsDefaultOrEmpty)
{
refKindsBuilderOpt = ArrayBuilder<RefKind>.GetInstance(accessorForDefaultArguments.ParameterCount);
refKindsBuilderOpt.AddRange(indexerAccess.ArgumentRefKindsOpt);
}
else
{
refKindsBuilderOpt = null;
}
var argsToParams = indexerAccess.ArgsToParamsOpt;

// It is possible for the indexer 'value' parameter from metadata to have a default value, but the compiler will not use it.
// However, we may still use any default values from the preceding parameters.
var parameters = accessorForDefaultArguments.Parameters;
if (useSetAccessor)
{
parameters = parameters.RemoveAt(parameters.Length - 1);
}
Debug.Assert(parameters.Length == indexerAccess.Indexer.Parameters.Length);
BindDefaultArguments(indexerAccess.Syntax, parameters, argumentsBuilder, refKindsBuilderOpt, ref argsToParams, out var defaultArguments, indexerAccess.Expanded, enableCallerInfo: true, diagnostics);

indexerAccess = indexerAccess.Update(
indexerAccess.ReceiverOpt,
indexerAccess.Indexer,
argumentsBuilder.ToImmutableAndFree(),
indexerAccess.ArgumentNamesOpt,
refKindsBuilderOpt?.ToImmutableOrNull() ?? default,
indexerAccess.Expanded,
argsToParams,
defaultArguments,
indexerAccess.BinderOpt,
indexerAccess.Type);

refKindsBuilderOpt?.Free();
}

return indexerAccess;
}

#nullable disable

/// <summary>
/// Check the expression is of the required lvalue and rvalue specified by valueKind.
/// The method returns the original expression if the expression is of the required
Expand All @@ -182,6 +237,10 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
{
case BoundKind.PropertyGroup:
expr = BindIndexedPropertyAccess((BoundPropertyGroup)expr, mustHaveAllOptionalParameters: false, diagnostics: diagnostics);
if (expr is BoundIndexerAccess indexerAccess)
{
expr = BindIndexerDefaultArguments(indexerAccess, valueKind, diagnostics);
}
break;

case BoundKind.Local:
Expand All @@ -198,15 +257,7 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
return expr;

case BoundKind.IndexerAccess:
{
// Assigning to a non ref return indexer needs to set 'useSetterForDefaultArgumentGeneration' to true.
// This is for IOperation purpose.
var indexerAccess = (BoundIndexerAccess)expr;
if (valueKind == BindValueKind.Assignable && !indexerAccess.Indexer.ReturnsByRef)
{
expr = indexerAccess.Update(useSetterForDefaultArgumentGeneration: true);
}
}
expr = BindIndexerDefaultArguments((BoundIndexerAccess)expr, valueKind, diagnostics);
break;

case BoundKind.UnconvertedObjectCreationExpression:
Expand Down
41 changes: 27 additions & 14 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1933,13 +1933,7 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Diagn

internal Symbol ContainingMember()
{
// We skip intervening lambdas and local functions to find the actual member.
var containingMember = this.ContainingMemberOrLambda;
while (containingMember.Kind != SymbolKind.NamedType && (object)containingMember.ContainingSymbol != null && containingMember.ContainingSymbol.Kind != SymbolKind.NamedType)
{
containingMember = containingMember.ContainingSymbol;
}
return containingMember;
return this.ContainingMemberOrLambda.ContainingNonLambdaMember();
333fred marked this conversation as resolved.
Show resolved Hide resolved
}

private BoundExpression TryBindInteractiveReceiver(SyntaxNode syntax, NamedTypeSymbol memberDeclaringType)
Expand Down Expand Up @@ -3959,23 +3953,27 @@ private BoundExpression BindConstructorInitializerCore(

CSharpSyntaxNode nonNullSyntax;
Location errorLocation;
bool enableCallerInfo;

switch (initializerArgumentListOpt?.Parent)
{
case ConstructorInitializerSyntax initializerSyntax:
nonNullSyntax = initializerSyntax;
errorLocation = initializerSyntax.ThisOrBaseKeyword.GetLocation();
enableCallerInfo = true;
break;

case PrimaryConstructorBaseTypeSyntax baseWithArguments:
nonNullSyntax = baseWithArguments;
errorLocation = initializerArgumentListOpt.GetLocation();
enableCallerInfo = true;
break;

default:
// Note: use syntax node of constructor with initializer, not constructor invoked by initializer (i.e. methodResolutionResult).
nonNullSyntax = constructor.GetNonNullSyntaxNode();
errorLocation = constructor.Locations[0];
enableCallerInfo = false;
break;
}

Expand Down Expand Up @@ -4037,9 +4035,12 @@ private BoundExpression BindConstructorInitializerCore(

ReportDiagnosticsIfObsolete(diagnostics, resultMember, nonNullSyntax, hasBaseReceiver: isBaseConstructorInitializer);

var expanded = memberResolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm;
var argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt;
BindDefaultArguments(nonNullSyntax, resultMember.Parameters, analyzedArguments.Arguments, analyzedArguments.RefKinds, ref argsToParamsOpt, out var defaultArguments, expanded, enableCallerInfo, diagnostics);

var arguments = analyzedArguments.Arguments.ToImmutable();
var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
var argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt;
if (!hasErrors)
{
hasErrors = !CheckInvocationArgMixing(
Expand All @@ -4061,9 +4062,10 @@ private BoundExpression BindConstructorInitializerCore(
analyzedArguments.GetNames(),
refKinds,
isDelegateCall: false,
expanded: memberResolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm,
expanded,
invokedAsExtensionMethod: false,
argsToParamsOpt: argsToParamsOpt,
defaultArguments: defaultArguments,
resultKind: LookupResultKind.Viable,
binderOpt: this,
type: constructorReturnType,
Expand Down Expand Up @@ -4653,6 +4655,7 @@ private BoundExpression BindObjectInitializerMember(
ImmutableArray<string> argumentNamesOpt = default(ImmutableArray<string>);
ImmutableArray<int> argsToParamsOpt = default(ImmutableArray<int>);
ImmutableArray<RefKind> argumentRefKindsOpt = default(ImmutableArray<RefKind>);
BitVector defaultArguments = default(BitVector);
bool expanded = false;

switch (boundMemberKind)
Expand Down Expand Up @@ -4683,12 +4686,14 @@ private BoundExpression BindObjectInitializerMember(

case BoundKind.IndexerAccess:
{
var indexer = (BoundIndexerAccess)boundMember;
var indexer = BindIndexerDefaultArguments((BoundIndexerAccess)boundMember, valueKind, diagnostics);
boundMember = indexer;
hasErrors |= isRhsNestedInitializer && !CheckNestedObjectInitializerPropertySymbol(indexer.Indexer, namedAssignment.Left, diagnostics, hasErrors, ref resultKind);
arguments = indexer.Arguments;
argumentNamesOpt = indexer.ArgumentNamesOpt;
argsToParamsOpt = indexer.ArgsToParamsOpt;
argumentRefKindsOpt = indexer.ArgumentRefKindsOpt;
defaultArguments = indexer.DefaultArguments;
expanded = indexer.Expanded;

break;
Expand Down Expand Up @@ -4732,6 +4737,7 @@ private BoundExpression BindObjectInitializerMember(
argumentRefKindsOpt,
expanded,
argsToParamsOpt,
defaultArguments,
resultKind,
implicitReceiver.Type,
binder: this,
Expand Down Expand Up @@ -5081,6 +5087,7 @@ private BoundExpression BindCollectionInitializerElementAddMethod(
boundCall.ReceiverOpt,
boundCall.Expanded,
boundCall.ArgsToParamsOpt,
boundCall.DefaultArguments,
boundCall.InvokedAsExtensionMethod,
boundCall.ResultKind,
binderOpt: boundCall.BinderOpt,
Expand Down Expand Up @@ -5254,9 +5261,12 @@ protected BoundExpression BindClassCreationExpression(
FoldParameterlessValueTypeConstructor(type) :
null;

var expanded = memberResolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm;
var argToParams = memberResolutionResult.Result.ArgsToParamsOpt;
BindDefaultArguments(node, method.Parameters, analyzedArguments.Arguments, analyzedArguments.RefKinds, ref argToParams, out var defaultArguments, expanded, enableCallerInfo: true, diagnostics);

var arguments = analyzedArguments.Arguments.ToImmutable();
var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
var argToParams = memberResolutionResult.Result.ArgsToParamsOpt;

if (!hasError)
{
Expand All @@ -5279,8 +5289,9 @@ protected BoundExpression BindClassCreationExpression(
arguments,
analyzedArguments.GetNames(),
refKinds,
memberResolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm,
expanded,
argToParams,
defaultArguments,
constantValueOpt,
boundInitializerOpt,
wasTargetTyped,
Expand Down Expand Up @@ -5442,7 +5453,7 @@ private BoundExpression BindComImportCoClassCreationExpression(SyntaxNode node,
case BoundKind.ObjectCreationExpression:
var creation = (BoundObjectCreationExpression)classCreation;
return creation.Update(creation.Constructor, creation.ConstructorsGroup, creation.Arguments, creation.ArgumentNamesOpt,
creation.ArgumentRefKindsOpt, creation.Expanded, creation.ArgsToParamsOpt, creation.ConstantValueOpt,
creation.ArgumentRefKindsOpt, creation.Expanded, creation.ArgsToParamsOpt, creation.DefaultArguments, creation.ConstantValueOpt,
creation.InitializerExpressionOpt, creation.BinderOpt, interfaceType);

case BoundKind.BadExpression:
Expand Down Expand Up @@ -7786,6 +7797,8 @@ private BoundExpression BindIndexerOrIndexedPropertyAccess(
diagnostics);
}

// Note that we do not bind default arguments here, because at this point we do not know whether
// the indexer is being used in a 'get', or 'set', or 'get+set' (compound assignment) context.
propertyAccess = new BoundIndexerAccess(
syntax,
receiver,
Expand All @@ -7795,8 +7808,8 @@ private BoundExpression BindIndexerOrIndexedPropertyAccess(
argumentRefKinds,
isExpanded,
argsToParams,
defaultArguments: default,
this,
false,
property.Type,
gotError);
}
Expand Down
Loading