diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
index 74464c5b9805c..10438a88f7954 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
@@ -574,7 +574,7 @@ private BoundCollectionExpression BindArrayOrSpanCollectionExpression(
TypeSymbol elementType,
BindingDiagnosticBag diagnostics)
{
- var syntax = (CSharpSyntaxNode)node.Syntax;
+ var syntax = node.Syntax;
switch (collectionTypeKind)
{
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
index a880b0ded9dd2..685ffeb66fdef 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
@@ -4729,7 +4729,7 @@ private BoundExpression BindCollectionExpression(CollectionExpressionSyntax synt
{
builder.Add(bindElement(element, diagnostics));
}
- return new BoundUnconvertedCollectionExpression(syntax, builder.ToImmutableAndFree(), this);
+ return new BoundUnconvertedCollectionExpression(syntax, builder.ToImmutableAndFree());
BoundExpression bindElement(CollectionElementSyntax syntax, BindingDiagnosticBag diagnostics)
{
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
index da3ecdae85db3..a4b3d444936e8 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
@@ -1877,7 +1877,6 @@
-
diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
index d234b1d67673f..41ebcfef52aad 100644
--- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
@@ -1970,6 +1970,29 @@ internal MethodSymbol EnsureInlineArrayAsSpanExists(SyntaxNode syntaxNode, Named
diagnostics);
}
+ internal NamedTypeSymbol EnsureInlineArrayTypeExists(SyntaxNode syntaxNode, SyntheticBoundNodeFactory factory, int arrayLength, DiagnosticBag diagnostics)
+ {
+ Debug.Assert(Compilation.Assembly.RuntimeSupportsInlineArrayTypes);
+ Debug.Assert(arrayLength > 0);
+
+ string typeName = $"<>{(char)GeneratedNameKind.InlineArrayType}__InlineArray{arrayLength}";
+ var privateImplClass = GetPrivateImplClass(syntaxNode, diagnostics);
+ var typeAdapter = privateImplClass.GetSynthesizedType(typeName);
+
+ if (typeAdapter is null)
+ {
+ var attributeConstructor = (MethodSymbol)factory.SpecialMember(SpecialMember.System_Runtime_CompilerServices_InlineArrayAttribute__ctor);
+ Debug.Assert(attributeConstructor is { });
+
+ var typeSymbol = new SynthesizedInlineArrayTypeSymbol(SourceModule, typeName, arrayLength, attributeConstructor);
+ privateImplClass.TryAddSynthesizedType(typeSymbol.GetCciAdapter());
+ typeAdapter = privateImplClass.GetSynthesizedType(typeName)!;
+ }
+
+ Debug.Assert(typeAdapter.Name == typeName);
+ return (NamedTypeSymbol)typeAdapter.GetInternalSymbol()!;
+ }
+
internal MethodSymbol EnsureInlineArrayAsReadOnlySpanExists(SyntaxNode syntaxNode, NamedTypeSymbol spanType, NamedTypeSymbol intType, DiagnosticBag diagnostics)
{
Debug.Assert(intType.SpecialType == SpecialType.System_Int32);
diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
index cc08d6d698c51..cef843334e51e 100644
--- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
@@ -6282,29 +6282,26 @@ public BoundObjectCreationExpression Update(MethodSymbol constructor, ImmutableA
internal sealed partial class BoundUnconvertedCollectionExpression : BoundExpression
{
- public BoundUnconvertedCollectionExpression(SyntaxNode syntax, ImmutableArray elements, Binder binder, bool hasErrors = false)
+ public BoundUnconvertedCollectionExpression(SyntaxNode syntax, ImmutableArray elements, bool hasErrors = false)
: base(BoundKind.UnconvertedCollectionExpression, syntax, null, hasErrors || elements.HasErrors())
{
RoslynDebug.Assert(!elements.IsDefault, "Field 'elements' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
- RoslynDebug.Assert(binder is object, "Field 'binder' cannot be null (make the type nullable in BoundNodes.xml to remove this check)");
this.Elements = elements;
- this.Binder = binder;
}
public new TypeSymbol? Type => base.Type;
public ImmutableArray Elements { get; }
- public Binder Binder { get; }
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitUnconvertedCollectionExpression(this);
- public BoundUnconvertedCollectionExpression Update(ImmutableArray elements, Binder binder)
+ public BoundUnconvertedCollectionExpression Update(ImmutableArray elements)
{
- if (elements != this.Elements || binder != this.Binder)
+ if (elements != this.Elements)
{
- var result = new BoundUnconvertedCollectionExpression(this.Syntax, elements, binder, this.HasErrors);
+ var result = new BoundUnconvertedCollectionExpression(this.Syntax, elements, this.HasErrors);
result.CopyAttributes(this);
return result;
}
@@ -11569,7 +11566,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor
{
ImmutableArray elements = this.VisitList(node.Elements);
TypeSymbol? type = this.VisitType(node.Type);
- return node.Update(elements, node.Binder);
+ return node.Update(elements);
}
public override BoundNode? VisitCollectionExpression(BoundCollectionExpression node)
{
@@ -13782,12 +13779,12 @@ public NullabilityRewriter(ImmutableDictionary new TreeDumperNode("unconvertedCollectionExpression", null, new TreeDumperNode[]
{
new TreeDumperNode("elements", null, from x in node.Elements select Visit(x, null)),
- new TreeDumperNode("binder", node.Binder, null),
new TreeDumperNode("type", node.Type, null),
new TreeDumperNode("isSuppressed", node.IsSuppressed, null),
new TreeDumperNode("hasErrors", node.HasErrors, null)
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs
index d61e5fd565741..69e671205551a 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs
@@ -18,26 +18,35 @@ internal sealed partial class LocalRewriter
Debug.Assert(!_inExpressionLambda);
Debug.Assert(node.Type is { });
- var collectionTypeKind = ConversionsBase.GetCollectionExpressionTypeKind(_compilation, node.Type, out var elementType);
- switch (collectionTypeKind)
+ var previousSyntax = _factory.Syntax;
+ _factory.Syntax = node.Syntax;
+ try
{
- case CollectionExpressionTypeKind.CollectionInitializer:
- return VisitCollectionInitializerCollectionExpression(node, node.Type);
- case CollectionExpressionTypeKind.Array:
- case CollectionExpressionTypeKind.Span:
- case CollectionExpressionTypeKind.ReadOnlySpan:
- Debug.Assert(elementType is { });
- return VisitArrayOrSpanCollectionExpression(node, node.Type, elementType);
- case CollectionExpressionTypeKind.CollectionBuilder:
- return VisitCollectionBuilderCollectionExpression(node);
- case CollectionExpressionTypeKind.ListInterface:
- return VisitListInterfaceCollectionExpression(node);
- default:
- throw ExceptionUtilities.UnexpectedValue(collectionTypeKind);
+ var collectionTypeKind = ConversionsBase.GetCollectionExpressionTypeKind(_compilation, node.Type, out var elementType);
+ switch (collectionTypeKind)
+ {
+ case CollectionExpressionTypeKind.CollectionInitializer:
+ return VisitCollectionInitializerCollectionExpression(node, node.Type);
+ case CollectionExpressionTypeKind.Array:
+ case CollectionExpressionTypeKind.Span:
+ case CollectionExpressionTypeKind.ReadOnlySpan:
+ Debug.Assert(elementType is { });
+ return VisitArrayOrSpanCollectionExpression(node, node.Type, TypeWithAnnotations.Create(elementType));
+ case CollectionExpressionTypeKind.CollectionBuilder:
+ return VisitCollectionBuilderCollectionExpression(node);
+ case CollectionExpressionTypeKind.ListInterface:
+ return VisitListInterfaceCollectionExpression(node);
+ default:
+ throw ExceptionUtilities.UnexpectedValue(collectionTypeKind);
+ }
+ }
+ finally
+ {
+ _factory.Syntax = previousSyntax;
}
}
- private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpression node, TypeSymbol collectionType, TypeSymbol elementType)
+ private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpression node, TypeSymbol collectionType, TypeWithAnnotations elementType)
{
Debug.Assert(!_inExpressionLambda);
@@ -50,8 +59,8 @@ private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpr
Debug.Assert(collectionType.Name is "Span" or "ReadOnlySpan");
// We're constructing a Span or ReadOnlySpan rather than T[].
var spanType = (NamedTypeSymbol)collectionType;
- Debug.Assert(elementType.Equals(spanType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0].Type, TypeCompareKind.AllIgnoreOptions));
- arrayType = ArrayTypeSymbol.CreateSZArray(_compilation.Assembly, TypeWithAnnotations.Create(elementType));
+ Debug.Assert(elementType.Equals(spanType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0], TypeCompareKind.AllIgnoreOptions));
+ arrayType = ArrayTypeSymbol.CreateSZArray(_compilation.Assembly, elementType);
spanConstructor = ((MethodSymbol)_compilation.GetWellKnownTypeMember(
collectionType.Name == "Span" ? WellKnownMember.System_Span_T__ctor_Array : WellKnownMember.System_ReadOnlySpan_T__ctor_Array)!).AsMember(spanType);
}
@@ -64,7 +73,7 @@ private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpr
// The array initializer includes at least one spread element, so we'll create an intermediate List instance.
// https://github.com/dotnet/roslyn/issues/68785: Avoid intermediate List if all spread elements have Length property.
// https://github.com/dotnet/roslyn/issues/68785: Emit Enumerable.TryGetNonEnumeratedCount() and avoid intermediate List at runtime.
- var listType = _compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_List_T).Construct(elementType);
+ var listType = _compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_List_T).Construct(ImmutableArray.Create(elementType));
var listToArray = ((MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Generic_List_T__ToArray)!).AsMember(listType);
var list = VisitCollectionInitializerCollectionExpression(node, collectionType);
array = _factory.Call(list, listToArray);
@@ -159,16 +168,35 @@ private BoundExpression VisitCollectionBuilderCollectionExpression(BoundCollecti
Debug.Assert(!_inExpressionLambda);
Debug.Assert(node.Type is { });
+ var syntax = node.Syntax;
+ var elements = node.Elements;
var constructMethod = node.CollectionBuilderMethod;
+
Debug.Assert(constructMethod is { });
Debug.Assert(constructMethod.ReturnType.Equals(node.Type, TypeCompareKind.AllIgnoreOptions));
var spanType = (NamedTypeSymbol)constructMethod.Parameters[0].Type;
Debug.Assert(spanType.OriginalDefinition.Equals(_compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions));
- var span = VisitArrayOrSpanCollectionExpression(node, spanType, spanType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0].Type);
- return new BoundCall(
- node.Syntax,
+ var elementType = spanType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0];
+ var locals = ArrayBuilder.GetInstance();
+ var sideEffects = ArrayBuilder.GetInstance();
+ BoundExpression span;
+
+ if (elements.Length > 0
+ && !elements.Any(i => i is BoundCollectionExpressionSpreadElement)
+ && _compilation.Assembly.RuntimeSupportsInlineArrayTypes
+ && (!constructMethod.ReturnType.IsRefLikeType || constructMethod.Parameters[0].EffectiveScope == ScopedKind.ScopedValue))
+ {
+ span = CreateAndPopulateInlineArray(syntax, elementType, elements, locals, sideEffects);
+ }
+ else
+ {
+ span = VisitArrayOrSpanCollectionExpression(node, spanType, elementType);
+ }
+
+ var call = new BoundCall(
+ syntax,
receiverOpt: null,
method: constructMethod,
arguments: ImmutableArray.Create(span),
@@ -181,6 +209,64 @@ private BoundExpression VisitCollectionBuilderCollectionExpression(BoundCollecti
defaultArguments: default,
resultKind: LookupResultKind.Viable,
type: constructMethod.ReturnType);
+
+ return new BoundSequence(
+ syntax,
+ locals.ToImmutableAndFree(),
+ sideEffects.ToImmutableAndFree(),
+ call,
+ call.Type);
+ }
+
+ private BoundExpression CreateAndPopulateInlineArray(
+ SyntaxNode syntax,
+ TypeWithAnnotations elementType,
+ ImmutableArray elements,
+ ArrayBuilder locals,
+ ArrayBuilder sideEffects)
+ {
+ Debug.Assert(elements.Length > 0);
+ Debug.Assert(_factory.ModuleBuilderOpt is { });
+ Debug.Assert(_diagnostics.DiagnosticBag is { });
+ Debug.Assert(_compilation.Assembly.RuntimeSupportsInlineArrayTypes);
+
+ int arrayLength = elements.Length;
+ var inlineArrayType = _factory.ModuleBuilderOpt.EnsureInlineArrayTypeExists(syntax, _factory, arrayLength, _diagnostics.DiagnosticBag).Construct(ImmutableArray.Create(elementType));
+ Debug.Assert(inlineArrayType.HasInlineArrayAttribute(out int inlineArrayLength) && inlineArrayLength == arrayLength);
+
+ var intType = _factory.SpecialType(SpecialType.System_Int32);
+ MethodSymbol elementRef = _factory.ModuleBuilderOpt.EnsureInlineArrayElementRefExists(syntax, intType, _diagnostics.DiagnosticBag).
+ Construct(ImmutableArray.Create(TypeWithAnnotations.Create(inlineArrayType), elementType));
+
+ // Create an inline array and assign to a local.
+ // var tmp = new <>y__InlineArrayN();
+ BoundAssignmentOperator assignmentToTemp;
+ BoundLocal inlineArrayLocal = _factory.StoreToTemp(new BoundDefaultExpression(syntax, inlineArrayType), out assignmentToTemp, isKnownToReferToTempIfReferenceType: true);
+ sideEffects.Add(assignmentToTemp);
+ locals.Add(inlineArrayLocal.LocalSymbol);
+
+ // Populate the inline array.
+ // InlineArrayElementRef<<>y__InlineArrayN, ElementType>(ref tmp, 0) = element0;
+ // InlineArrayElementRef<<>y__InlineArrayN, ElementType>(ref tmp, 1) = element1;
+ // ...
+ for (int i = 0; i < arrayLength; i++)
+ {
+ var element = VisitExpression(elements[i]);
+ var call = _factory.Call(null, elementRef, inlineArrayLocal, _factory.Literal(i), useStrictArgumentRefKinds: true);
+ var assignment = new BoundAssignmentOperator(syntax, call, element, type: call.Type) { WasCompilerGenerated = true };
+ sideEffects.Add(assignment);
+ }
+
+ // Get a span to the inline array.
+ // ... InlineArrayAsReadOnlySpan<<>y__InlineArrayN, ElementType>(in tmp, N)
+ var inlineArrayAsReadOnlySpan = _factory.ModuleBuilderOpt.EnsureInlineArrayAsReadOnlySpanExists(syntax, _factory.WellKnownType(WellKnownType.System_ReadOnlySpan_T), intType, _diagnostics.DiagnosticBag).
+ Construct(ImmutableArray.Create(TypeWithAnnotations.Create(inlineArrayType), elementType));
+ return _factory.Call(
+ receiver: null,
+ inlineArrayAsReadOnlySpan,
+ inlineArrayLocal,
+ _factory.Literal(arrayLength),
+ useStrictArgumentRefKinds: true);
}
private BoundExpression MakeCollectionExpressionSpreadElement(BoundCollectionExpressionSpreadElement initializer)
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs
index 02e82a25f81a8..71a19beb2651b 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs
@@ -47,7 +47,8 @@ internal enum GeneratedNameKind
DynamicCallSiteField = 'p',
AsyncIteratorPromiseOfValueOrEndBackingField = 'v',
DisposeModeField = 'w',
- CombinedTokensField = 'x', // last
+ CombinedTokensField = 'x',
+ InlineArrayType = 'y', // last
// Deprecated - emitted by Dev12, but not by Roslyn.
// Don't reuse the values because the debugger might encounter them when consuming old binaries.
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs
new file mode 100644
index 0000000000000..fcbbce9b0ed9b
--- /dev/null
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInlineArrayTypeSymbol.cs
@@ -0,0 +1,245 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Microsoft.CodeAnalysis.CSharp.Emit;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.CSharp.Symbols
+{
+ ///
+ /// A synthesized type used during emit to allow temp locals of Span<T>
+ /// of a specific length where the span storage is on the stack.
+ ///
+ /// [InlineArray(N)] struct <>y__InlineArrayN<T> { private T _element0; }
+ ///
+ ///
+ internal sealed class SynthesizedInlineArrayTypeSymbol : NamedTypeSymbol
+ {
+ private readonly ModuleSymbol _containingModule;
+ private readonly int _arrayLength;
+ private readonly MethodSymbol _inlineArrayAttributeConstructor;
+ private readonly ImmutableArray _fields;
+
+ internal SynthesizedInlineArrayTypeSymbol(SourceModuleSymbol containingModule, string name, int arrayLength, MethodSymbol inlineArrayAttributeConstructor)
+ {
+ Debug.Assert(arrayLength > 0);
+
+ var typeParameter = new InlineArrayTypeParameterSymbol(this);
+ var field = new SynthesizedFieldSymbol(this, typeParameter, "_element0");
+
+ _containingModule = containingModule;
+ _arrayLength = arrayLength;
+ _inlineArrayAttributeConstructor = inlineArrayAttributeConstructor;
+ _fields = ImmutableArray.Create(field);
+ Name = name;
+ TypeParameters = ImmutableArray.Create(typeParameter);
+ }
+
+ public override int Arity => 1;
+
+ public override ImmutableArray TypeParameters { get; }
+
+ public override NamedTypeSymbol ConstructedFrom => this;
+
+ public override bool MightContainExtensionMethods => false;
+
+ public override string Name { get; }
+
+ public override IEnumerable MemberNames => GetMembers().SelectAsArray(m => m.Name);
+
+ public override Accessibility DeclaredAccessibility => Accessibility.Internal;
+
+ public override bool IsSerializable => false;
+
+ public override bool AreLocalsZeroed => true;
+
+ public override TypeKind TypeKind => TypeKind.Struct;
+
+ public override bool IsRefLikeType => false;
+
+ public override bool IsReadOnly => true;
+
+ public override Symbol? ContainingSymbol => _containingModule.GlobalNamespace;
+
+ internal override ModuleSymbol ContainingModule => _containingModule;
+
+ public override AssemblySymbol ContainingAssembly => _containingModule.ContainingAssembly;
+
+ public override ImmutableArray Locations => ImmutableArray.Empty;
+
+ public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty;
+
+ public override bool IsStatic => false;
+
+ public override bool IsAbstract => false;
+
+ public override bool IsSealed => true;
+
+ internal override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics => GetTypeParametersAsTypeArguments();
+
+ internal override bool IsFileLocal => false;
+
+ internal override FileIdentifier? AssociatedFileIdentifier => null;
+
+ internal override bool MangleName => false;
+
+ internal override bool HasDeclaredRequiredMembers => false;
+
+ internal override bool HasCodeAnalysisEmbeddedAttribute => false;
+
+ internal override bool IsInterpolatedStringHandlerType => false;
+
+ internal override bool HasSpecialName => false;
+
+ internal override bool IsComImport => false;
+
+ internal override bool IsWindowsRuntimeImport => false;
+
+ internal override bool ShouldAddWinRTMembers => false;
+
+ internal override TypeLayout Layout => default;
+
+ internal override CharSet MarshallingCharSet => DefaultMarshallingCharSet;
+
+ internal override bool HasDeclarativeSecurity => false;
+
+ internal override bool IsInterface => false;
+
+ internal override NamedTypeSymbol? NativeIntegerUnderlyingType => null;
+
+ internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => ContainingAssembly.GetSpecialType(SpecialType.System_ValueType);
+
+ internal override bool IsRecord => false;
+
+ internal override bool IsRecordStruct => false;
+
+ internal override ObsoleteAttributeData? ObsoleteAttributeData => null;
+
+ public override ImmutableArray GetMembers() => ImmutableArray.CastUp(_fields);
+
+ public override ImmutableArray GetMembers(string name) => GetMembers().WhereAsArray(m => m.Name == name);
+
+ public override ImmutableArray GetTypeMembers() => ImmutableArray.Empty;
+
+ public override ImmutableArray GetTypeMembers(ReadOnlyMemory name, int arity) => ImmutableArray.Empty;
+
+ public override ImmutableArray GetTypeMembers(ReadOnlyMemory name) => ImmutableArray.Empty;
+
+ protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable();
+
+ internal override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable();
+
+ internal override ImmutableArray GetAppliedConditionalSymbols() => ImmutableArray.Empty;
+
+ internal override AttributeUsageInfo GetAttributeUsageInfo() => default;
+
+ internal override NamedTypeSymbol GetDeclaredBaseType(ConsList basesBeingResolved) => BaseTypeNoUseSiteDiagnostics;
+
+ internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => ImmutableArray.Empty;
+
+ internal override ImmutableArray GetEarlyAttributeDecodingMembers() => GetMembersUnordered();
+
+ internal override ImmutableArray GetEarlyAttributeDecodingMembers(string name) => GetMembers(name);
+
+ internal override IEnumerable GetFieldsToEmit() => _fields;
+
+ internal override ImmutableArray GetInterfacesToEmit() => ImmutableArray.Empty;
+
+ internal override IEnumerable GetSecurityInformation() => SpecializedCollections.EmptyEnumerable();
+
+ internal override bool HasCollectionBuilderAttribute(out TypeSymbol? builderType, out string? methodName)
+ {
+ builderType = null;
+ methodName = null;
+ return false;
+ }
+
+ internal override bool HasInlineArrayAttribute(out int length)
+ {
+ length = _arrayLength;
+ return true;
+ }
+
+ internal override bool HasPossibleWellKnownCloneMethod() => false;
+
+ internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => ImmutableArray.Empty;
+
+ internal override IEnumerable<(MethodSymbol Body, MethodSymbol Implemented)> SynthesizedInterfaceMethodImpls() => SpecializedCollections.EmptyEnumerable<(MethodSymbol Body, MethodSymbol Implemented)>();
+
+ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes)
+ {
+ base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
+
+ var compilation = _containingModule.DeclaringCompilation;
+ Debug.Assert(compilation is { });
+
+ AddSynthesizedAttribute(
+ ref attributes,
+ new SynthesizedAttributeData(
+ _inlineArrayAttributeConstructor,
+ arguments: ImmutableArray.Create(new TypedConstant(compilation.GetSpecialType(SpecialType.System_Int32), TypedConstantKind.Primitive, _arrayLength)),
+ namedArguments: ImmutableArray>.Empty));
+ }
+
+ private sealed class InlineArrayTypeParameterSymbol : TypeParameterSymbol
+ {
+ private readonly SynthesizedInlineArrayTypeSymbol _container;
+
+ internal InlineArrayTypeParameterSymbol(SynthesizedInlineArrayTypeSymbol container)
+ {
+ _container = container;
+ }
+
+ public override string Name => "T";
+
+ public override int Ordinal => 0;
+
+ public override bool HasConstructorConstraint => false;
+
+ public override TypeParameterKind TypeParameterKind => TypeParameterKind.Type;
+
+ public override bool HasReferenceTypeConstraint => false;
+
+ public override bool IsReferenceTypeFromConstraintTypes => false;
+
+ public override bool HasNotNullConstraint => false;
+
+ public override bool HasValueTypeConstraint => false;
+
+ public override bool IsValueTypeFromConstraintTypes => false;
+
+ public override bool HasUnmanagedTypeConstraint => false;
+
+ public override VarianceKind Variance => VarianceKind.None;
+
+ public override Symbol ContainingSymbol => _container;
+
+ public override ImmutableArray Locations => ImmutableArray.Empty;
+
+ public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty;
+
+ internal override bool? IsNotNullable => null;
+
+ internal override bool? ReferenceTypeConstraintIsNullable => null;
+
+ internal override void EnsureAllConstraintsAreResolved()
+ {
+ }
+
+ internal override ImmutableArray GetConstraintTypes(ConsList inProgress) => ImmutableArray.Empty;
+
+ internal override TypeSymbol GetDeducedBaseType(ConsList inProgress) => ContainingAssembly.GetSpecialType(SpecialType.System_Object);
+
+ internal override NamedTypeSymbol GetEffectiveBaseClass(ConsList inProgress) => ContainingAssembly.GetSpecialType(SpecialType.System_Object);
+
+ internal override ImmutableArray GetInterfaces(ConsList inProgress) => ImmutableArray.Empty;
+ }
+ }
+}
diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs
index 4f450382a0f78..0657236b044dc 100644
--- a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs
+++ b/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs
@@ -4,6 +4,7 @@
#nullable disable
+using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting;
@@ -17,6 +18,8 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class CollectionExpressionTests : CSharpTestBase
{
+ private static string IncludeExpectedOutput(string expectedOutput) => ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null;
+
private const string s_collectionExtensions = """
using System;
using System.Collections;
@@ -1604,7 +1607,7 @@ static void Main()
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F2").WithArguments("Program.F2(T[][], T[][])").WithLocation(8, 17));
}
- [ConditionalFact(typeof(CoreClrOnly))]
+ [Fact]
public void TypeInference_24()
{
string source = """
@@ -1627,10 +1630,10 @@ static void Main()
new[] { source, s_collectionExtensionsWithSpan },
targetFramework: TargetFramework.Net70,
verify: Verification.Skipped,
- expectedOutput: "[0, 2], [null, 4], ");
+ expectedOutput: IncludeExpectedOutput("[0, 2], [null, 4], "));
}
- [ConditionalFact(typeof(CoreClrOnly))]
+ [Fact]
public void TypeInference_25()
{
string source = """
@@ -2663,7 +2666,7 @@ static void Main()
Diagnostic(ErrorCode.ERR_CollectionExpressionTargetTypeNotConstructible, "[[1, 2], [3, 4]]").WithArguments("int[*,*]").WithLocation(5, 20));
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[CombinatorialData]
public void Span_01(bool useReadOnlySpan)
{
@@ -2685,7 +2688,11 @@ static void Main()
}
}
""";
- var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, targetFramework: TargetFramework.Net70, verify: Verification.Skipped, expectedOutput: "[], [1, 2], [3, 4, 5], [null, 7], ");
+ var verifier = CompileAndVerify(
+ new[] { source, s_collectionExtensionsWithSpan },
+ targetFramework: TargetFramework.Net70,
+ verify: Verification.Skipped,
+ expectedOutput: IncludeExpectedOutput("[], [1, 2], [3, 4, 5], [null, 7], "));
verifier.VerifyIL("Program.Create1", $$"""
{
// Code size 12 (0xc)
@@ -2762,7 +2769,7 @@ .maxstack 4
""");
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[CombinatorialData]
public void Span_02(bool useReadOnlySpan)
{
@@ -2780,10 +2787,14 @@ static void Main()
}
}
""";
- CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, targetFramework: TargetFramework.Net70, verify: Verification.Skipped, expectedOutput: "[], [1, 2, 3], ");
+ CompileAndVerify(
+ new[] { source, s_collectionExtensionsWithSpan },
+ targetFramework: TargetFramework.Net70,
+ verify: Verification.Skipped,
+ expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], "));
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[CombinatorialData]
public void Span_03(bool useReadOnlySpan)
{
@@ -2801,10 +2812,14 @@ static void Main()
}
}
""";
- CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, targetFramework: TargetFramework.Net70, verify: Verification.Skipped, expectedOutput: "[], [1, 2, 3], ");
+ CompileAndVerify(
+ new[] { source, s_collectionExtensionsWithSpan },
+ targetFramework: TargetFramework.Net70,
+ verify: Verification.Skipped,
+ expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], "));
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[CombinatorialData]
public void Span_04(bool useReadOnlySpan)
{
@@ -2833,7 +2848,7 @@ class Program
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "[]").WithLocation(6, 28));
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[CombinatorialData]
public void Span_05(bool useReadOnlySpan)
{
@@ -2856,7 +2871,7 @@ class Program
comp.VerifyEmitDiagnostics();
}
- [ConditionalFact(typeof(CoreClrOnly))]
+ [Fact]
public void Span_MissingConstructor()
{
string source = """
@@ -4281,7 +4296,7 @@ static void Main()
Diagnostic(ErrorCode.ERR_SyntaxError, "4").WithArguments(",").WithLocation(9, 16));
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[CombinatorialData]
public void SpreadElement_01(
[CombinatorialValues("IEnumerable", "int[]", "List", "Span", "ReadOnlySpan")] string spreadType,
@@ -4306,7 +4321,7 @@ static void Main()
options: TestOptions.ReleaseExe,
targetFramework: TargetFramework.Net70,
verify: Verification.Skipped,
- expectedOutput: "[1, 2, 3], ");
+ expectedOutput: IncludeExpectedOutput("[1, 2, 3], "));
// Verify some of the cases.
string expectedIL = (spreadType, collectionType) switch
@@ -4467,7 +4482,7 @@ .locals init (System.Collections.Generic.List V_0,
}
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[InlineData("int[]")]
[InlineData("System.Collections.Generic.List")]
[InlineData("System.Span")]
@@ -4497,7 +4512,7 @@ static void Main()
options: TestOptions.ReleaseExe,
targetFramework: TargetFramework.Net70,
verify: Verification.Skipped,
- expectedOutput: "[1, 2], ");
+ expectedOutput: IncludeExpectedOutput("[1, 2], "));
if (collectionType == "System.ReadOnlySpan")
{
@@ -4957,7 +4972,7 @@ .locals init (System.Collections.Generic.List V_0,
""");
}
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
[InlineData("List")]
[InlineData("Span")]
[InlineData("ReadOnlySpan")]
@@ -4985,7 +5000,7 @@ static void Main()
new[] { source, s_collectionExtensionsWithSpan },
targetFramework: TargetFramework.Net70,
verify: Verification.Skipped,
- expectedOutput: "[1, 2, 3], [1, 2, 3], ");
+ expectedOutput: IncludeExpectedOutput("[1, 2, 3], [1, 2, 3], "));
}
[Fact]
@@ -5588,7 +5603,7 @@ .maxstack 5
""");
}
- [ConditionalFact(typeof(CoreClrOnly))]
+ [Fact]
public void SemanticModel()
{
string source = """
@@ -5658,7 +5673,7 @@ private static void VerifyTypes(SemanticModel model, ExpressionSyntax expr, stri
}
[CombinatorialData]
- [ConditionalTheory(typeof(CoreClrOnly))]
+ [Theory]
public void CollectionBuilder_01(bool useCompilationReference)
{
string sourceA = """
@@ -5682,7 +5697,7 @@ public static MyCollection Create(ReadOnlySpan items)
}
}
""";
- var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70);
+ var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80);
var refA = AsReference(comp, useCompilationReference);
string sourceB1 = """
@@ -5694,7 +5709,7 @@ static void Main()
x.Report();
MyCollection y = F1();
y.Report();
- MyCollection