-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Closed
Description
The feature was renamed to "collection expressions".
Championed issue: dotnet/csharplang#5354
Speclet: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md
Compiler
General Concerns
- Spec - In progress
- Language version (
LanguageVersionDiagnostics) - Documentation
- New BCL APIs for collection creation ([API Proposal]: BCL additions to support C# 12's "Collection Literals" feature. runtime#87569)
- Public APIs [API proposal] Collection literals #68687
- IOperation
- GetTypeInfo
- GetConversion
- Whole collection expression
- Elements (splat and expression)
- GetSymbolInfo (should return nothing)
- AnalyzeX(Data|Control)Flow should show appropriate reads
- Splats
- Expressions
- VB/F# - Nothing to do
- C++/CLI - Nothing to do
- Build VS
- Add to compiler test plan
- Syntax
- Implicit conversions
Parsing
- Ambiguity scenarios
-
a?[b](CollectionExpressionParsingTests.ConditionalAmbiguityX) - Attribute/collection literal confusion (
CollectionExpressionParsingTests.AttributeOnStartOfLambda,CollectionExpressionParsingTests.TopLevelDotAccess_AttributeAmbiguityX) - Cast vs parenthesized expression (
CollectionExpressionParsingTests.CastVsIndexAmbiguityX)-
(a)[b] -
(a?)[b] -
(a<b>)[c]
-
- Breaking change:
_ = x ? y?[0] : z; // syntax error
-
- As RValue
- Indexing expression (
CollectionExpressionParsingTests.AttemptToImmediatelyIndexInTopLevelStatement) - Direct invocation
- Input to switch expression
- Empty collection
- Operators
- Indexing expression (
Semantics
- Definite assignment
- Test in catch filter
- Particularly with something that might require multiple spill levels, such as interpolated string handler element type
- Usage in
asyncmethods- When builder type is a ref struct and there are no awaits in the elements
- When builder type is a ref struct and there are awaits in the elements
- With fallback ability (List)
- Without fallback ability
- Best common element type (
BestCommonType_03,_04) - Type Inference:
- Usage in generic arguments makes inferences from collection literal elements (
TypeInference_03,_04) - Usage in lambda returns makes inferences from collection literal elements
- Tuples of collection literals
- Collection literals of tuples (
TypeInference_37)
- Usage in generic arguments makes inferences from collection literal elements (
- Target types:
-
var,object,dynamic -
T[](Array_*) -
T[,](Array_04) -
Span<T>,ReadOnlySpan<T>(Span_*) -
IEnumerable,ICollection,IList(InterfaceType_01) -
IEnumerable<T>,ICollection<T>,IList<T>,IReadOnlyCollection<T>,IReadOnlyList<T>(InterfaceType_02) - collection initializer types: reference type, value type, type parameter (
CollectionInitializerType_01,_02,TypeParameter_*) - custom construct methods
-
inline arrays - Element type has conversion from expression, like interpolated string handlers
-
- Collection initializer types:
- 0, 1, >1
Add()method (CollectionInitializerType_03,CollectionInitializerType_12) - inaccessible .ctor (
CollectionInitializerType_05) - .ctor with/without
int capacity - .ctor with all optional parameters (
CollectionInitializerType_ConstructorOptionalParameters) - .ctor with single
paramsparameter (CollectionInitializerType_ConstructorParamsArray) - .ctor with ref parameters
- ref struct element type (
RefStruct_03) -
Obsoletemethods -
UnmanagedCallersOnlymethods -
CompilerFeatureRequiredmethods - Nullability mismatches
- Collection builder type is a PIA
- 0, 1, >1
- Spread collection type:
-
IEnumerableonly (SpreadElement_10) - pattern-based enumerator
- Without implementing IDisposable
- With implementing IDisposable
-
ref structiterator type -
ref structtype- Without Dispose
- With Dispose
- with
LengthorCountproperty - Above marked
Obsolete(SpreadElement_LengthObsolete) - Above marked
UnmanagedCallersOnly - Above marked
CompilerFeatureRequired - Embeds appropriate interop types when enumerator is an pia
-
-
Extension method invocation-
type inference
methods)
-
- cannot be used as constants
- Expression trees (
ExpressionTrees) - Optimizations:
- emit
Array.Empty<T>()forIEnumerable<T> e = [];(ArrayEmpty_01) -
avoid heap allocation when not observable:foreach (var b in [true, false]) { ... }
- emit
-
__arglistandArgIteratorusage -
refsafety in elements- Element should not escape by value
- Element should not escape by ref
-
stackallocelement - collection expressions targeting ref structs cannot be returned (
RefSafety_Return_01)
- Use as LValue
- Directly assigning
- Assigning into an indexer
- Pass by
ref (readonly) - Pass by
in- Implicit (
TypeInference_20) - Explicit (
TypeInference_21)
- Implicit (
-
ref (readonly)return -
refreassignment
- Anonymous type usage
- Assignment to property
- Top-level usage
- Direct slicing (1..2)
- Direct indexing (^1)
- Execution order of elements vs collection ctor
-
Direct method execution (MemberAccess_01,_02) -
fixedstatement immediately taking a pointer - Direct argument of a
usingblock - Collection element subjected to a checked user-defined implicit conversion during creation
-
ReadOnlySpan<byte[]> x = ["abc"u8];should behave likebyte[] x = "abc"u8; - Suppression with
!(should produce a diagnostic) - Nullability analysis
Productivity
- Completion
- Verify that completion for
[return: MyAttribute]and[return: expr]are both possible
- Verify that completion for
- Formatting:
List<int> list = [1, 2, 3];(no extra spaces) - Incomplete code typing experience
- Find all on builder types/methods
- F1 on the brackets
- Immediate window compilation
- DebuggerDisplay
- Assigning values in the watch window
- EE
- EnC
- Stepping through debugger with
[Method1(), Method2()]should behave like array creation and other similar existing constructs
Open Questions
- Syntax ambiguities:
-
(X)[i]cast collection literal or indexing? -
[a ? [b] : c]conditional[a ? ([b]) : c]or key-value pair[(a ? [b]) : c]? -
a ? b ? [c] : dnested indexera ? (b?[c]) : dor nested collection literala ? (b ? ([c]) : d)? -
Range[] ranges = [range1, ..e, range2];spread or range..e?
-
- Collection literals at the beginning of an expression statement?
[1].ToString(); // error CS7014: Attributes are not valid in this context.
- What are the requirements for a spread element type? Is a span spreadable for instance?
- Is evaluation of elements interleaved with
Add()calls? - Any type that implements
IEnumerableand has an accessible parameterless constructor is a valid target type for[]. Should the requirements for a collection initializer type be stronger than this? - Should multi-dimensional arrays be supported with nested collection literal syntax?
int[,] a = [[1, 2], [3, 4]];
- Should better function member prefer some constructible collection types over others?
F([1, 2, 3]); // ambiguous? static void F(IEnumerable<int> arg) { } static void F(int[] arg) { }
- When generating an intermediate List, should we use the well-known member
List<T>.Add(T)rather than relying on lookup? - Should spread elements support target type?
string[] a = [..b ? [null] : []];
- Infer from spread element iteration type? See LDM-2023-09-20
IEnumerable<int> e = [1, 2, 3]; F([..e]); // ok? F([..[4, 5]); // ok? static void F<T>(T[] arg) { }
- Infer from lambda return expression? From 11.6.3.7, a lower-bound inference is made from the return type of the lambda expression. (
TypeInference_40)F(() => [1]); F(() => { if (b) return []; return [2]; }); static void F<T>(Func<T[]> arg) { }
- Should
IAsyncEnumerable<int> ebe supported for[1, 2, await ..e]?
Reactions are currently unavailable