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/CollectionLiterals into main #68831

Merged
merged 46 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c3d7fd2
Initial syntax types for collection literals
CyrusNajmabadi Jan 13, 2023
d5982b0
change name for consistency
CyrusNajmabadi Jan 13, 2023
9a3bc92
Update publicapi
CyrusNajmabadi Jan 13, 2023
75c3063
Update tests
CyrusNajmabadi Jan 15, 2023
0e9dc16
UPdate generated code.
CyrusNajmabadi Jan 15, 2023
465f927
Merge pull request #66412 from CyrusNajmabadi/collectionLiteralSyntax
CyrusNajmabadi Jan 17, 2023
2b44cb2
Merge remote-tracking branch 'upstream/main' into mainToCollections
CyrusNajmabadi Jan 28, 2023
42b4ddd
API
CyrusNajmabadi Jan 28, 2023
ffa3a66
Merge pull request #66586 from CyrusNajmabadi/mainToCollections
CyrusNajmabadi Jan 29, 2023
a4ce86a
Merge branch 'main' into mainToCollections
CyrusNajmabadi Jan 31, 2023
fe8abdb
Merge pull request #66625 from CyrusNajmabadi/mainToCollections
CyrusNajmabadi Jan 31, 2023
598cbe4
Initial support for collection literal parsing. (#66417)
CyrusNajmabadi Jan 31, 2023
44dd7b2
Merge remote-tracking branch 'upstream/main' into collections-update
cston Mar 13, 2023
f30aa87
Ignore primary constructor parameters in collection literals
cston Mar 13, 2023
07daeef
Merge pull request #67280 from cston/collections-update
cston Mar 13, 2023
02f55f6
Initial binding and lowering of collection literals with single-value…
cston Mar 14, 2023
1fbd1fb
Merge remote-tracking branch 'upstream/main' into collections-merge-main
cston Apr 21, 2023
372107b
Merge pull request #67917 from cston/collections-merge-main
cston Apr 21, 2023
02bf874
Initial support for collection literal spread elements (#67942)
cston May 12, 2023
4f05970
Merge remote-tracking branch 'upstream/main' into collections-merge
cston May 17, 2023
fe79cfc
Merge pull request #68227 from cston/collections-merge
cston May 17, 2023
547e0f7
Fix collection literal format spacing
CyrusNajmabadi May 22, 2023
5c5b672
Merge pull request #68284 from CyrusNajmabadi/collectionFormatting
CyrusNajmabadi May 22, 2023
54200de
Merge remote-tracking branch 'upstream/main' into collections-merge
cston Jun 8, 2023
0fbcee5
Merge pull request #68482 from cston/collections-merge
cston Jun 8, 2023
2955139
Refine parsing of potentially ambiguous casts/index expressions with …
CyrusNajmabadi Jun 12, 2023
6bd8524
Improve collection literal parsing (#68561)
CyrusNajmabadi Jun 14, 2023
d11bf96
Update handling of collection literals with no target type (#68598)
cston Jun 22, 2023
0d9509c
Fix issue parsing collection literal containing lambdas (#68734)
CyrusNajmabadi Jun 22, 2023
4feb306
Collection literals: type inference (#68703)
cston Jun 23, 2023
de4f0b7
Fix collection literal parsing at the state of a statement expression…
CyrusNajmabadi Jun 23, 2023
d2d0d3c
Rename CollectionCreationExpression to CollectionExpression (#68747)
cston Jun 23, 2023
3720edc
Collection literals: remove DictionaryElementSyntax (#68752)
cston Jun 26, 2023
c6c3595
Fix parsing certain postfix expressions with top level collection lit…
CyrusNajmabadi Jun 26, 2023
45afaea
Fix ambiguity parsing collection expressions vs conditional access ex…
CyrusNajmabadi Jun 27, 2023
f4f5b39
Merge remote-tracking branch 'upstream/main' into collections-merge
cston Jun 28, 2023
1f2bdd6
Merge pull request #68821 from dotnet/merges/main-to-release/dev17.7
RikkiGibson Jun 28, 2023
c53203e
Localized file check-in by OneLocBuild Task: Build definition ID 327:…
dotnet-bot Jun 28, 2023
1b93dd2
Localized file check-in by OneLocBuild Task: Build definition ID 327:…
dotnet-bot Jun 28, 2023
d768e46
Localized file check-in by OneLocBuild Task: Build definition ID 327:…
dotnet-bot Jun 28, 2023
2122c82
Regenerate bound nodes
RikkiGibson Jun 28, 2023
c0a307a
Collection literals: use NoneOperation (#68795)
cston Jun 28, 2023
44ee200
Merge pull request #68824 from dotnet/locfiles/610afbb3-1edc-4329-87b…
Cosifne Jun 28, 2023
308b868
Merge pull request #68812 from cston/collections-merge
cston Jun 28, 2023
77d3192
Collection literals: address comments (#68793)
cston Jun 29, 2023
b865d5c
Merge remote-tracking branch 'upstream/features/CollectionLiterals' i…
cston Jun 29, 2023
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
13 changes: 13 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,13 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
}
break;

case BoundKind.UnconvertedCollectionLiteralExpression:
if (valueKind == BindValueKind.RValue)
{
return expr;
}
break;

case BoundKind.PointerIndirectionOperator:
if ((valueKind & BindValueKind.RefersToLocation) == BindValueKind.RefersToLocation)
{
Expand Down Expand Up @@ -3952,6 +3959,9 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres
var switchExpr = (BoundSwitchExpression)expr;
return GetValEscape(switchExpr.SwitchArms.SelectAsArray(a => a.Value), scopeOfTheContainingExpression);

case BoundKind.CollectionLiteralExpression:
return CallingMethodScope;

default:
// in error situations some unexpected nodes could make here
// returning "scopeOfTheContainingExpression" seems safer than throwing.
Expand Down Expand Up @@ -4478,6 +4488,9 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF

return true;

case BoundKind.CollectionLiteralExpression:
return true;

default:
// in error situations some unexpected nodes could make here
// returning "false" seems safer than throwing.
Expand Down
217 changes: 217 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static bool filterConversion(Conversion conversion)
return !conversion.IsInterpolatedString &&
!conversion.IsInterpolatedStringHandler &&
!conversion.IsSwitchExpression &&
!conversion.IsCollectionLiteral &&
!(conversion.IsTupleLiteralConversion || (conversion.IsNullable && conversion.UnderlyingConversions[0].IsTupleLiteralConversion)) &&
(!conversion.IsUserDefined || filterConversion(conversion.UserDefinedFromConversion));
}
Expand Down Expand Up @@ -230,6 +231,16 @@ BoundExpression createConversion(
return ConvertObjectCreationExpression(syntax, (BoundUnconvertedObjectCreationExpression)source, conversion, isCast, destination, conversionGroupOpt, wasCompilerGenerated, diagnostics);
}

if (source.Kind == BoundKind.UnconvertedCollectionLiteralExpression)
{
Debug.Assert(conversion.IsCollectionLiteral || !conversion.Exists);
source = ConvertCollectionLiteralExpression(
(BoundUnconvertedCollectionLiteralExpression)source,
destination,
wasCompilerGenerated,
diagnostics);
}

if (source.Kind == BoundKind.UnconvertedConditionalOperator)
{
Debug.Assert(source.Type is null);
Expand Down Expand Up @@ -515,6 +526,212 @@ static BoundExpression bindObjectCreationExpression(
}
}

private BoundExpression ConvertCollectionLiteralExpression(
BoundUnconvertedCollectionLiteralExpression node,
TypeSymbol targetType,
bool wasCompilerGenerated,
BindingDiagnosticBag diagnostics)
{
TypeSymbol? elementType;
var collectionTypeKind = ConversionsBase.GetCollectionLiteralTypeKind(Compilation, targetType, out elementType);
switch (collectionTypeKind)
{
case CollectionLiteralTypeKind.CollectionInitializer:
return BindCollectionInitializerCollectionLiteral(node, collectionTypeKind, targetType, wasCompilerGenerated: wasCompilerGenerated, diagnostics);
case CollectionLiteralTypeKind.Array:
case CollectionLiteralTypeKind.Span:
case CollectionLiteralTypeKind.ReadOnlySpan:
return BindArrayOrSpanCollectionLiteral(node, targetType, wasCompilerGenerated: wasCompilerGenerated, collectionTypeKind, elementType!, diagnostics);
case CollectionLiteralTypeKind.ListInterface:
return BindListInterfaceCollectionLiteral(node, targetType, wasCompilerGenerated: wasCompilerGenerated, elementType!, diagnostics);
case CollectionLiteralTypeKind.None:
return BindCollectionLiteralForErrorRecovery(node, targetType, diagnostics);
default:
throw ExceptionUtilities.UnexpectedValue(collectionTypeKind);
}
}

private BoundCollectionLiteralExpression BindArrayOrSpanCollectionLiteral(
BoundUnconvertedCollectionLiteralExpression node,
TypeSymbol targetType,
bool wasCompilerGenerated,
CollectionLiteralTypeKind collectionTypeKind,
TypeSymbol elementType,
BindingDiagnosticBag diagnostics)
{
var syntax = (CSharpSyntaxNode)node.Syntax;

switch (collectionTypeKind)
{
case CollectionLiteralTypeKind.Span:
_ = GetWellKnownTypeMember(WellKnownMember.System_Span_T__ctor_Array, diagnostics, syntax: syntax);
break;
case CollectionLiteralTypeKind.ReadOnlySpan:
_ = GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__ctor_Array, diagnostics, syntax: syntax);
break;
}

var elements = node.Elements;
if (elements.Any(e => e is BoundCollectionLiteralSpreadElement))
{
// The array initializer includes at least one spread element, so we'll create an intermediate List<T> instance.
// https://github.com/dotnet/roslyn/issues/68785: Avoid intermediate List<T> if all spread elements have Length property.
_ = GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_List_T__ToArray, diagnostics, syntax: syntax);
var result = BindCollectionInitializerCollectionLiteral(
node,
collectionTypeKind,
GetWellKnownType(WellKnownType.System_Collections_Generic_List_T, diagnostics, syntax).Construct(elementType),
wasCompilerGenerated: wasCompilerGenerated,
diagnostics);
return result.Update(result.CollectionTypeKind, result.Placeholder, result.CollectionCreation, result.Elements, targetType);
}

var implicitReceiver = new BoundObjectOrCollectionValuePlaceholder(syntax, isNewInstance: true, targetType) { WasCompilerGenerated = true };
var builder = ArrayBuilder<BoundExpression>.GetInstance(elements.Length);
foreach (var element in elements)
{
builder.Add(convertArrayElement(element, elementType, diagnostics));
}
return new BoundCollectionLiteralExpression(
syntax,
collectionTypeKind,
implicitReceiver,
collectionCreation: null,
builder.ToImmutableAndFree(),
targetType)
{ WasCompilerGenerated = wasCompilerGenerated };

BoundExpression convertArrayElement(BoundExpression element, TypeSymbol elementType, BindingDiagnosticBag diagnostics)
{
var useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
var conversion = Conversions.ClassifyImplicitConversionFromExpression(element, elementType, ref useSiteInfo);
diagnostics.Add(element.Syntax, useSiteInfo);
bool hasErrors = !conversion.IsValid;
if (hasErrors)
{
GenerateImplicitConversionError(diagnostics, element.Syntax, conversion, element, elementType);
// Suppress any additional diagnostics
diagnostics = BindingDiagnosticBag.Discarded;
}
var result = CreateConversion(
element.Syntax,
element,
conversion,
isCast: false,
conversionGroupOpt: null,
wasCompilerGenerated: true,
destination: elementType,
diagnostics,
hasErrors: hasErrors);
result.WasCompilerGenerated = true;
return result;
}
}

private BoundCollectionLiteralExpression BindCollectionInitializerCollectionLiteral(
BoundUnconvertedCollectionLiteralExpression node,
CollectionLiteralTypeKind collectionTypeKind,
TypeSymbol targetType,
bool wasCompilerGenerated,
BindingDiagnosticBag diagnostics,
bool hasErrors = false)
{
var syntax = node.Syntax;

BoundExpression collectionCreation;
if (targetType is NamedTypeSymbol namedType)
{
var analyzedArguments = AnalyzedArguments.GetInstance();
// https://github.com/dotnet/roslyn/issues/68785: Use ctor with `int capacity` when the size is known.
collectionCreation = BindClassCreationExpression(syntax, namedType.Name, syntax, namedType, analyzedArguments, diagnostics);
collectionCreation.WasCompilerGenerated = true;
analyzedArguments.Free();
}
else if (targetType is TypeParameterSymbol typeParameter)
{
var arguments = AnalyzedArguments.GetInstance();
collectionCreation = BindTypeParameterCreationExpression(syntax, typeParameter, arguments, initializerOpt: null, typeSyntax: syntax, wasTargetTyped: true, diagnostics);
arguments.Free();
}
else
{
collectionCreation = new BoundBadExpression(syntax, LookupResultKind.NotCreatable, ImmutableArray<Symbol?>.Empty, ImmutableArray<BoundExpression>.Empty, targetType);
}

var implicitReceiver = new BoundObjectOrCollectionValuePlaceholder(syntax, isNewInstance: true, targetType) { WasCompilerGenerated = true };
var collectionInitializerAddMethodBinder = this.WithAdditionalFlags(BinderFlags.CollectionInitializerAddMethod);
var builder = ArrayBuilder<BoundExpression>.GetInstance(node.Elements.Length);
foreach (var element in node.Elements)
{
var result = element switch
{
BoundBadExpression => element,
BoundCollectionLiteralSpreadElement spreadElement => BindCollectionInitializerSpreadElementAddMethod(
(SpreadElementSyntax)spreadElement.Syntax,
spreadElement,
collectionInitializerAddMethodBinder,
implicitReceiver,
diagnostics),
_ => BindCollectionInitializerElementAddMethod(
(ExpressionSyntax)element.Syntax,
ImmutableArray.Create(element),
hasEnumerableInitializerType: true,
collectionInitializerAddMethodBinder,
diagnostics,
implicitReceiver),
};
result.WasCompilerGenerated = true;
builder.Add(result);
}
return new BoundCollectionLiteralExpression(
syntax,
collectionTypeKind,
implicitReceiver,
collectionCreation,
builder.ToImmutableAndFree(),
targetType,
hasErrors)
{ WasCompilerGenerated = wasCompilerGenerated };
}

private BoundCollectionLiteralExpression BindListInterfaceCollectionLiteral(
BoundUnconvertedCollectionLiteralExpression node,
TypeSymbol targetType,
bool wasCompilerGenerated,
TypeSymbol elementType,
BindingDiagnosticBag diagnostics)
{
// https://github.com/dotnet/roslyn/issues/68785: Emit [] as Array.Empty<T>() rather than a List<T>.
var result = BindCollectionInitializerCollectionLiteral(
node,
CollectionLiteralTypeKind.ListInterface,
GetWellKnownType(WellKnownType.System_Collections_Generic_List_T, diagnostics, node.Syntax).Construct(elementType),
wasCompilerGenerated: wasCompilerGenerated,
diagnostics);
return result.Update(result.CollectionTypeKind, result.Placeholder, result.CollectionCreation, result.Elements, targetType);
}

private BoundCollectionLiteralExpression BindCollectionLiteralForErrorRecovery(
BoundUnconvertedCollectionLiteralExpression node,
TypeSymbol targetType,
BindingDiagnosticBag diagnostics)
{
var syntax = node.Syntax;
var builder = ArrayBuilder<BoundExpression>.GetInstance(node.Elements.Length);
foreach (var element in node.Elements)
{
builder.Add(BindToNaturalType(element, diagnostics, reportNoTargetType: !targetType.IsErrorType()));
}
return new BoundCollectionLiteralExpression(
syntax,
collectionTypeKind: CollectionLiteralTypeKind.None,
placeholder: null,
collectionCreation: null,
elements: builder.ToImmutableAndFree(),
targetType,
hasErrors: true);
}

/// <summary>
/// Rewrite the subexpressions in a conditional expression to convert the whole thing to the destination type.
/// </summary>
Expand Down
Loading