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

Merge 'features/ParamsCollections' into 'main' #72511

Merged
merged 44 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2bedf28
Merge main to ParamsCollections (#71150)
AlekseyTs Dec 7, 2023
569dcb7
Make trivial Params Collections scenarios working end to end (#71136)
AlekseyTs Dec 11, 2023
60a4581
Params Collections: Implement language version check. (#71228)
AlekseyTs Dec 13, 2023
88c8859
Params Collections: Implement "Better function member" section of the…
AlekseyTs Dec 18, 2023
07fc1db
IOperation - drop synthesized conversion placed on top of params coll…
AlekseyTs Dec 20, 2023
0e16ec0
Add handling of params collections for natural delegate types (#71334)
AlekseyTs Jan 6, 2024
a91ef66
Params Collections - Adjust binding in presence of dynamic arguments …
AlekseyTs Jan 8, 2024
a9ffbe0
Params Collections: misc chanages (#71423)
AlekseyTs Jan 9, 2024
4fb7084
Merge 'dotnet/main' into ParamsCollections
AlekseyTs Jan 9, 2024
99ef47c
Temporarily skip some tests to unblock merge from `main`
AlekseyTs Jan 9, 2024
0be7dc3
Merge 'dotnet/main' into ParamsCollections (#71545)
AlekseyTs Jan 9, 2024
6bc0d9b
Enable some dynamic collection expression tests which were disabled d…
AlekseyTs Jan 10, 2024
7f00d15
Add a test for 'Params Collections.' (#71572)
AlekseyTs Jan 11, 2024
55b6a79
Params Collections: Add a bunch of PROTOTYPE comments and a couple of…
AlekseyTs Jan 12, 2024
ba5ee92
Use ParamCollectionAttribute to mark params collections in metadata (…
AlekseyTs Jan 26, 2024
399026e
Merge 'dotnet/main' into ParamsCollections
AlekseyTs Jan 26, 2024
882ccbc
Follow up on merge from 'main'
AlekseyTs Jan 26, 2024
897fd49
Merge 'dotnet/main' into ParamsCollections(#71824)
AlekseyTs Jan 26, 2024
1c5c7e2
Adjust public API based on API review feedback (#71940)
AlekseyTs Feb 5, 2024
6cd3f1e
Align `params` type validation with the the spec (#71918)
AlekseyTs Feb 7, 2024
6fcac7d
Params parameters are implicitly scoped when their type is a ref stru…
AlekseyTs Feb 9, 2024
18852b8
Merge remote-tracking branch 'dotnet/main' into ParamsCollections_20
AlekseyTs Feb 10, 2024
25414ee
Update test according to changes in ParamsCollections branch
AlekseyTs Feb 10, 2024
1dbe23e
Merge 'dotnet/main' into ParamsCollections (#72042)
AlekseyTs Feb 12, 2024
2b8a744
Break a cycle through attributes (#72041)
AlekseyTs Feb 12, 2024
7ddc662
Add more tests and address some of the PROTOTYPE comments (#72089)
AlekseyTs Feb 14, 2024
ba462cc
Address more PROTOTYPE comments (#72113)
AlekseyTs Feb 16, 2024
03fd758
Clone some IDE tests for params collections (#72228)
AlekseyTs Feb 22, 2024
05cf517
Add `ArgumentKind.ParamCollection` (#72221)
AlekseyTs Feb 22, 2024
8085621
Rename BoundNode flag for clarity (#72235)
AlekseyTs Feb 23, 2024
9180f98
Params parameter is implicitly scoped if and only if `params` is expl…
AlekseyTs Feb 27, 2024
835dd26
Address some PROTOTYPE comments (#72298)
AlekseyTs Feb 29, 2024
5b563bf
Merge 'main' into ParamsCollections
AlekseyTs Mar 5, 2024
637dec2
Regenerate ErrorFacts.Generated.cs
AlekseyTs Mar 5, 2024
811c275
Merge 'main' into ParamsCollections (#72390)
AlekseyTs Mar 5, 2024
b6f9fe5
Rename IDS_ParamsCollections to IDS_FeatureParamsCollections (#72399)
AlekseyTs Mar 5, 2024
91815cb
Misc. work for params collections (#72408)
AlekseyTs Mar 6, 2024
512187f
Ensure obsolete diagnostics about required constructor or Add method …
AlekseyTs Mar 8, 2024
84d12e1
Merge 'main' into ParamsCollections
AlekseyTs Mar 12, 2024
bf22912
Merge 'main' into ParamsCollections (#72497)
AlekseyTs Mar 12, 2024
99f3521
Adjust GetUnderlyingCollectionExpressionElement to handle params coll…
AlekseyTs Mar 12, 2024
bc9a7f0
Pack resource IDs and adjust Compiler Test Plan (#72499)
AlekseyTs Mar 12, 2024
3d0bcbb
Merge 'features/ParamsCollections' into 'main'
AlekseyTs Mar 12, 2024
d073ac9
Adjust test baselines
AlekseyTs Mar 12, 2024
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
2 changes: 1 addition & 1 deletion docs/contributing/Compiler Test Plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ This document provides guidance for thinking about language interactions and tes
- fields (required and not)
- properties (including get/set/init accessors, required and not)
- events (including add/remove accessors)
- Parameter modifiers (ref, out, in, ref readonly, params)
- Parameter modifiers: ref, out, in, ref readonly, params (for array, for non-array)
- Attributes (including generic attributes and security attributes)
- Generics (type arguments, variance, constraints including `class`, `struct`, `new()`, `unmanaged`, `notnull`, types and interfaces with nullability)
- Default and constant values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4532,6 +4532,11 @@ static bool Goo(int x, object y, object z)
{
return true;
}

static bool Goo(long x, object y, object z)
{
return true;
}
}
""";

Expand Down Expand Up @@ -4568,7 +4573,19 @@ class C<T>
{
}
}


int this[long x, object s, object d]
{
get
{
return 0;
}

set
{
}
}

void Goo(dynamic xx)
{
var y = this[x: xx, s: "", d: (object)""];
Expand Down Expand Up @@ -4681,6 +4698,11 @@ static bool Goo(object y, int x, object z)
{
return true;
}

static bool Goo(object y, long x, object z)
{
return true;
}
}
""";

Expand Down Expand Up @@ -5219,10 +5241,10 @@ class Program
{
public static void Main(string[] args)
{
TakesParams([|(string)|]null);
TakesParams([|(Program)|]null);
}

private static void TakesParams({|CS0225:params|} string wrongDefined)
private static void TakesParams({|CS0225:params|} Program wrongDefined)
{
}
}
Expand All @@ -5235,7 +5257,7 @@ public static void Main(string[] args)
TakesParams(null);
}

private static void TakesParams({|CS0225:params|} string wrongDefined)
private static void TakesParams({|CS0225:params|} Program wrongDefined)
{
}
}
Expand Down Expand Up @@ -5461,13 +5483,13 @@ await VerifyCS.VerifyCodeFixAsync(
using System;
sealed class MarkAttribute : Attribute
{
public MarkAttribute(bool otherArg, {|CS0225:params|} string wrongDefined)
public MarkAttribute(bool otherArg, {|CS0225:params|} object wrongDefined)
{
}
public int Prop { get; set; }
}

[Mark(true, [|(string)|]null, Prop = 1)]
[Mark(true, [|(object)|]null, Prop = 1)]
static class Program
{
}
Expand All @@ -5476,7 +5498,7 @@ static class Program
using System;
sealed class MarkAttribute : Attribute
{
public MarkAttribute(bool otherArg, {|CS0225:params|} string wrongDefined)
public MarkAttribute(bool otherArg, {|CS0225:params|} object wrongDefined)
{
}
public int Prop { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public override bool HasExplicitReturnType(out RefKind refKind, out TypeWithAnno
public override int ParameterCount { get { return _parameters.Length; } }
public override bool IsAsync { get { return false; } }
public override bool IsStatic => false;
public override bool HasParamsArray => false;
public override RefKind RefKind(int index) { return Microsoft.CodeAnalysis.RefKind.None; }
public override ScopedKind DeclaredScope(int index) => ScopedKind.None;
public override MessageID MessageID { get { return MessageID.IDS_FeatureQueryExpression; } } // TODO: what is the correct ID here?
Expand Down
16 changes: 9 additions & 7 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ private static bool RequiresRefOrOut(BindValueKind kind)

#nullable enable

private BoundIndexerAccess BindIndexerDefaultArgumentsAndParamsArray(BoundIndexerAccess indexerAccess, BindValueKind valueKind, BindingDiagnosticBag diagnostics)
private BoundIndexerAccess BindIndexerDefaultArgumentsAndParamsCollection(BoundIndexerAccess indexerAccess, BindValueKind valueKind, BindingDiagnosticBag diagnostics)
{
var useSetAccessor = valueKind == BindValueKind.Assignable && !indexerAccess.Indexer.ReturnsByRef;
var accessorForDefaultArguments = useSetAccessor
Expand Down Expand Up @@ -368,7 +368,7 @@ private BoundIndexerAccess BindIndexerDefaultArgumentsAndParamsArray(BoundIndexe
}
}

BindDefaultArgumentsAndParamsArray(indexerAccess.Syntax, parameters, argumentsBuilder, refKindsBuilderOpt, namesBuilder, ref argsToParams, out defaultArguments, indexerAccess.Expanded, enableCallerInfo: true, diagnostics);
BindDefaultArgumentsAndParamsCollection(indexerAccess.Syntax, parameters, argumentsBuilder, refKindsBuilderOpt, namesBuilder, ref argsToParams, out defaultArguments, indexerAccess.Expanded, enableCallerInfo: true, diagnostics);

if (namesBuilder is object)
{
Expand Down Expand Up @@ -412,7 +412,7 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
expr = BindIndexedPropertyAccess((BoundPropertyGroup)expr, mustHaveAllOptionalParameters: false, diagnostics: diagnostics);
if (expr is BoundIndexerAccess indexerAccess)
{
expr = BindIndexerDefaultArgumentsAndParamsArray(indexerAccess, valueKind, diagnostics);
expr = BindIndexerDefaultArgumentsAndParamsCollection(indexerAccess, valueKind, diagnostics);
}
break;

Expand All @@ -430,7 +430,7 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
return expr;

case BoundKind.IndexerAccess:
expr = BindIndexerDefaultArgumentsAndParamsArray((BoundIndexerAccess)expr, valueKind, diagnostics);
expr = BindIndexerDefaultArgumentsAndParamsCollection((BoundIndexerAccess)expr, valueKind, diagnostics);
break;

case BoundKind.UnconvertedObjectCreationExpression:
Expand Down Expand Up @@ -474,7 +474,7 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
{
var methodGroup = (BoundMethodGroup)expr;
CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
var resolution = this.ResolveMethodGroup(methodGroup, analyzedArguments: null, isMethodGroupConversion: false, useSiteInfo: ref useSiteInfo);
var resolution = this.ResolveMethodGroup(methodGroup, analyzedArguments: null, useSiteInfo: ref useSiteInfo, options: OverloadResolution.Options.None);
diagnostics.Add(expr.Syntax, useSiteInfo);
Symbol otherSymbol = null;
bool resolvedToMethodGroup = resolution.MethodGroup != null;
Expand Down Expand Up @@ -4794,7 +4794,8 @@ private SignatureOnlyMethodSymbol GetInlineArrayAccessEquivalentSignatureMethod(
ImmutableArray.Create<ParameterSymbol>(new SignatureOnlyParameterSymbol(
TypeWithAnnotations.Create(elementAccess.Expression.Type),
ImmutableArray<CustomModifier>.Empty,
isParams: false,
isParamsArray: false,
isParamsCollection: false,
parameterRefKind
)),
resultRefKind,
Expand Down Expand Up @@ -4833,7 +4834,8 @@ private SignatureOnlyMethodSymbol GetInlineArrayConversionEquivalentSignatureMet
ImmutableArray.Create<ParameterSymbol>(new SignatureOnlyParameterSymbol(
TypeWithAnnotations.Create(inlineArray.Type),
ImmutableArray<CustomModifier>.Empty,
isParams: false,
isParamsArray: false,
isParamsCollection: false,
parameterRefKind
)),
RefKind.None,
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ internal virtual LocalSymbol? LocalInProgress
}
}

internal virtual NamedTypeSymbol? ParamsCollectionTypeInProgress => null;

internal virtual BoundExpression? ConditionalReceiverExpression
{
get
Expand Down
20 changes: 15 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,15 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a
out var memberResolutionResult,
out var candidateConstructors,
allowProtectedConstructorsOfBaseType: true,
suppressUnsupportedRequiredMembersError: false);
out CompoundUseSiteInfo<AssemblySymbol> overloadResolutionUseSiteInfo);

ReportConstructorUseSiteDiagnostics(node.Location, diagnostics, suppressUnsupportedRequiredMembersError: false, in overloadResolutionUseSiteInfo);

if (memberResolutionResult.IsNotNull)
{
this.CheckAndCoerceArguments<MethodSymbol>(memberResolutionResult, analyzedArguments.ConstructorArguments, diagnostics, receiver: null, invokedAsExtensionMethod: false);
}

attributeConstructor = memberResolutionResult.Member;
expanded = memberResolutionResult.Resolution == MemberResolutionKind.ApplicableInExpandedForm;
argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt;
Expand All @@ -221,7 +229,7 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a
}
else
{
attributeArgumentBinder.BindDefaultArgumentsAndParamsArray(
attributeArgumentBinder.BindDefaultArgumentsAndParamsCollection(
node,
attributeConstructor.Parameters,
analyzedArguments.ConstructorArguments.Arguments,
Expand Down Expand Up @@ -340,7 +348,7 @@ ImmutableArray<int> makeSourceIndices()
return default;
}

Debug.Assert(arguments.Count(a => a.IsParamsArray) == (boundAttribute.ConstructorExpanded ? 1 : 0));
Debug.Assert(arguments.Count(a => a.IsParamsArrayOrCollection) == (boundAttribute.ConstructorExpanded ? 1 : 0));

// make source indices if we have anything that doesn't map 1:1 from arguments to parameters:
// 1. implicit default arguments
Expand Down Expand Up @@ -372,10 +380,12 @@ ImmutableArray<int> makeSourceIndices()
constructorArgumentSourceIndices.Count = lengthAfterRewriting;
for (int argIndex = 0; argIndex < lengthAfterRewriting; argIndex++)
{
Debug.Assert(!arguments[argIndex].IsParamsArrayOrCollection || arguments[argIndex] is BoundArrayCreation);

int paramIndex = argsToParamsOpt.IsDefault ? argIndex : argsToParamsOpt[argIndex];
constructorArgumentSourceIndices[paramIndex] =
defaultArguments[argIndex] ||
(arguments[argIndex].IsParamsArray && arguments[argIndex] is BoundArrayCreation { Bounds: [BoundLiteral { ConstantValueOpt.Value: 0 }] }) ?
(arguments[argIndex].IsParamsArrayOrCollection && arguments[argIndex] is BoundArrayCreation { Bounds: [BoundLiteral { ConstantValueOpt.Value: 0 }] }) ?
-1 : argIndex;
}
return constructorArgumentSourceIndices.ToImmutableAndFree();
Expand Down Expand Up @@ -901,7 +911,7 @@ private TypedConstant VisitConversion(BoundConversion node, BindingDiagnosticBag
var operandType = operand.Type;

if (node.Conversion.IsCollectionExpression
&& node.Conversion.GetCollectionExpressionTypeKind(out _) == CollectionExpressionTypeKind.Array)
&& node.Conversion.GetCollectionExpressionTypeKind(out _, out _, out _) == CollectionExpressionTypeKind.Array)
{
Debug.Assert(type.IsSZArray());
return VisitArrayCollectionExpression(type, (BoundCollectionExpression)operand, diagnostics, ref attrHasErrors, curArgumentHasErrors);
Expand Down
14 changes: 8 additions & 6 deletions src/Compilers/CSharp/Portable/Binder/Binder_Await.cs
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,10 @@ private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, Bi
return false;
}

var getAwaiterMethod = ((BoundCall)getAwaiterCall).Method;
var call = (BoundCall)getAwaiterCall;
var getAwaiterMethod = call.Method;
if (getAwaiterMethod is ErrorMethodSymbol ||
HasOptionalOrVariableParameters(getAwaiterMethod) || // We might have been able to resolve a GetAwaiter overload with optional parameters, so check for that here
call.Expanded || HasOptionalParameters(getAwaiterMethod) || // We might have been able to resolve a GetAwaiter overload with optional parameters, so check for that here
getAwaiterMethod.ReturnsVoid) // If GetAwaiter returns void, don't bother checking that it returns an Awaiter.
{
Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type);
Expand Down Expand Up @@ -451,7 +452,8 @@ private bool GetGetResultMethod(BoundExpression awaiterExpression, SyntaxNode no
return false;
}

getResultMethod = ((BoundCall)getAwaiterGetResultCall).Method;
var call = (BoundCall)getAwaiterGetResultCall;
getResultMethod = call.Method;
if (getResultMethod.IsExtensionMethod)
{
Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult);
Expand All @@ -460,7 +462,7 @@ private bool GetGetResultMethod(BoundExpression awaiterExpression, SyntaxNode no
return false;
}

if (HasOptionalOrVariableParameters(getResultMethod) || getResultMethod.IsConditional)
if (call.Expanded || HasOptionalParameters(getResultMethod) || getResultMethod.IsConditional)
{
Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType);
getResultMethod = null;
Expand All @@ -472,14 +474,14 @@ private bool GetGetResultMethod(BoundExpression awaiterExpression, SyntaxNode no
return true;
}

private static bool HasOptionalOrVariableParameters(MethodSymbol method)
private static bool HasOptionalParameters(MethodSymbol method)
{
RoslynDebug.Assert(method != null);

if (method.ParameterCount != 0)
{
var parameter = method.Parameters[method.ParameterCount - 1];
return parameter.IsOptional || parameter.IsParams;
return parameter.IsOptional;
}

return false;
Expand Down
Loading
Loading