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 z = F2(4, 5); + MyCollection z = F2(3, 4); z.Report(); } static MyCollection F0() @@ -5703,7 +5718,7 @@ static MyCollection F0() } static MyCollection F1() { - return [1, 2, 3]; + return [0, 1, 2]; } static MyCollection F2(int x, object y) { @@ -5712,7 +5727,12 @@ static MyCollection F2(int x, object y) } """; - var verifier = CompileAndVerify(new[] { sourceB1, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], [4, 5, null], "); + var verifier = CompileAndVerify( + new[] { sourceB1, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [0, 1, 2], [3, 4, null], ")); verifier.VerifyIL("Program.F0", """ { @@ -5728,33 +5748,62 @@ .maxstack 1 verifier.VerifyIL("Program.F1", """ { - // Code size 16 (0x10) - .maxstack 1 - IL_0000: ldtoken ".__StaticArrayInitTypeSize=12_Align=4 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D4" - IL_0005: call "System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)" - IL_000a: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" - IL_000f: ret + // Code size 52 (0x34) + .maxstack 2 + .locals init (<>y__InlineArray3 V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "<>y__InlineArray3" + IL_0008: ldloca.s V_0 + IL_000a: ldc.i4.0 + IL_000b: call "InlineArrayElementRef<<>y__InlineArray3, int>(ref <>y__InlineArray3, int)" + IL_0010: ldc.i4.0 + IL_0011: stind.i4 + IL_0012: ldloca.s V_0 + IL_0014: ldc.i4.1 + IL_0015: call "InlineArrayElementRef<<>y__InlineArray3, int>(ref <>y__InlineArray3, int)" + IL_001a: ldc.i4.1 + IL_001b: stind.i4 + IL_001c: ldloca.s V_0 + IL_001e: ldc.i4.2 + IL_001f: call "InlineArrayElementRef<<>y__InlineArray3, int>(ref <>y__InlineArray3, int)" + IL_0024: ldc.i4.2 + IL_0025: stind.i4 + IL_0026: ldloca.s V_0 + IL_0028: ldc.i4.3 + IL_0029: call "InlineArrayAsReadOnlySpan<<>y__InlineArray3, int>(in <>y__InlineArray3, int)" + IL_002e: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" + IL_0033: ret } """); verifier.VerifyIL("Program.F2", """ { - // Code size 30 (0x1e) - .maxstack 4 - IL_0000: ldc.i4.3 - IL_0001: newarr "object" - IL_0006: dup - IL_0007: ldc.i4.0 - IL_0008: ldarg.0 - IL_0009: box "int" - IL_000e: stelem.ref - IL_000f: dup - IL_0010: ldc.i4.1 - IL_0011: ldarg.1 - IL_0012: stelem.ref - IL_0013: newobj "System.ReadOnlySpan..ctor(object[])" - IL_0018: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" - IL_001d: ret + // Code size 57 (0x39) + .maxstack 2 + .locals init (<>y__InlineArray3 V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "<>y__InlineArray3" + IL_0008: ldloca.s V_0 + IL_000a: ldc.i4.0 + IL_000b: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_0010: ldarg.0 + IL_0011: box "int" + IL_0016: stind.ref + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.1 + IL_001a: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_001f: ldarg.1 + IL_0020: stind.ref + IL_0021: ldloca.s V_0 + IL_0023: ldc.i4.2 + IL_0024: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_0029: ldnull + IL_002a: stind.ref + IL_002b: ldloca.s V_0 + IL_002d: ldc.i4.3 + IL_002e: call "InlineArrayAsReadOnlySpan<<>y__InlineArray3, object>(in <>y__InlineArray3, int)" + IL_0033: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" + IL_0038: ret } """); @@ -5773,7 +5822,12 @@ static MyCollection F2(MyCollection c) } """; - verifier = CompileAndVerify(new[] { sourceB2, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[1, 2, 3], "); + verifier = CompileAndVerify( + new[] { sourceB2, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); verifier.VerifyIL("Program.F2", """ { @@ -5823,7 +5877,316 @@ .locals init (System.Collections.Generic.List V_0, } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] + public void CollectionBuilder_02A( + [CombinatorialValues(TargetFramework.Net70, TargetFramework.Net80)] TargetFramework targetFramework, + bool useCompilationReference) + { + string sourceA = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + [CollectionBuilder(typeof(MyCollectionBuilder), nameof(MyCollectionBuilder.Create))] + public struct MyCollection : IEnumerable + { + private readonly List _list; + public MyCollection(List list) { _list = list; } + public IEnumerator GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + public class MyCollectionBuilder + { + public static MyCollection Create(ReadOnlySpan items) + { + return new MyCollection(new List(items.ToArray())); + } + } + """; + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: targetFramework); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = """ + class Program + { + static void Main() + { + var x = F(); + x.Report(); + } + static MyCollection F() + { + return [1, 2, null]; + } + } + """; + comp = CreateCompilation(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: targetFramework, options: TestOptions.ReleaseExe); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify( + comp, + symbolValidator: module => + { + var type = module.GlobalNamespace.GetTypeMembers("<>y__InlineArray3").SingleOrDefault(); + if (targetFramework == TargetFramework.Net80) + { + Assert.NotNull(type); + } + else + { + Assert.Null(type); + } + }, + verify: targetFramework == TargetFramework.Net80 ? Verification.Fails : Verification.FailsPEVerify, + expectedOutput: IncludeExpectedOutput("[1, 2, null], ")); + if (targetFramework == TargetFramework.Net80) + { + verifier.VerifyIL("Program.F", + """ + { + // Code size 74 (0x4a) + .maxstack 2 + .locals init (<>y__InlineArray3 V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "<>y__InlineArray3" + IL_0008: ldloca.s V_0 + IL_000a: ldc.i4.0 + IL_000b: call "InlineArrayElementRef<<>y__InlineArray3, int?>(ref <>y__InlineArray3, int)" + IL_0010: ldc.i4.1 + IL_0011: newobj "int?..ctor(int)" + IL_0016: stobj "int?" + IL_001b: ldloca.s V_0 + IL_001d: ldc.i4.1 + IL_001e: call "InlineArrayElementRef<<>y__InlineArray3, int?>(ref <>y__InlineArray3, int)" + IL_0023: ldc.i4.2 + IL_0024: newobj "int?..ctor(int)" + IL_0029: stobj "int?" + IL_002e: ldloca.s V_0 + IL_0030: ldc.i4.2 + IL_0031: call "InlineArrayElementRef<<>y__InlineArray3, int?>(ref <>y__InlineArray3, int)" + IL_0036: initobj "int?" + IL_003c: ldloca.s V_0 + IL_003e: ldc.i4.3 + IL_003f: call "InlineArrayAsReadOnlySpan<<>y__InlineArray3, int?>(in <>y__InlineArray3, int)" + IL_0044: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" + IL_0049: ret + } + """); + } + else + { + verifier.VerifyIL("Program.F", + """ + { + // Code size 43 (0x2b) + .maxstack 4 + IL_0000: ldc.i4.3 + IL_0001: newarr "int?" + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldc.i4.1 + IL_0009: newobj "int?..ctor(int)" + IL_000e: stelem "int?" + IL_0013: dup + IL_0014: ldc.i4.1 + IL_0015: ldc.i4.2 + IL_0016: newobj "int?..ctor(int)" + IL_001b: stelem "int?" + IL_0020: newobj "System.ReadOnlySpan..ctor(int?[])" + IL_0025: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" + IL_002a: ret + } + """); + } + } + + // As above, but with TargetFramework.NetFramework. + [ConditionalFact(typeof(DesktopOnly))] + public void CollectionBuilder_02B() + { + string sourceA = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + [CollectionBuilder(typeof(MyCollectionBuilder), nameof(MyCollectionBuilder.Create))] + public struct MyCollection : IEnumerable + { + private readonly List _list; + public MyCollection(List list) { _list = list; } + public IEnumerator GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + public class MyCollectionBuilder + { + public static MyCollection Create(ReadOnlySpan items) + { + var list = new List(); + foreach (var i in items) list.Add(i); + return new MyCollection(list); + } + } + """; + string sourceB = """ + class Program + { + static void Main() + { + var x = F(); + x.Report(); + } + static MyCollection F() + { + return [1, 2, null]; + } + } + """; + var comp = CreateCompilationWithSpanAndMemoryExtensions( + new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition, s_collectionExtensions }, + targetFramework: TargetFramework.NetFramework, + options: TestOptions.ReleaseExe); + comp.VerifyEmitDiagnostics(); + + var verifier = CompileAndVerify( + comp, + symbolValidator: module => + { + var type = module.GlobalNamespace.GetTypeMembers("<>y__InlineArray3").SingleOrDefault(); + Assert.Null(type); + }, + expectedOutput: "[1, 2, null], "); + verifier.VerifyIL("Program.F", + """ + { + // Code size 43 (0x2b) + .maxstack 4 + IL_0000: ldc.i4.3 + IL_0001: newarr "int?" + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldc.i4.1 + IL_0009: newobj "int?..ctor(int)" + IL_000e: stelem "int?" + IL_0013: dup + IL_0014: ldc.i4.1 + IL_0015: ldc.i4.2 + IL_0016: newobj "int?..ctor(int)" + IL_001b: stelem "int?" + IL_0020: newobj "System.ReadOnlySpan..ctor(int?[])" + IL_0025: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" + IL_002a: ret + } + """); + } + + [Fact] + public void CollectionBuilder_InlineArrayTypes() + { + string sourceA = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + [CollectionBuilder(typeof(MyCollectionBuilder), nameof(MyCollectionBuilder.Create))] + public struct MyCollection : IEnumerable + { + private readonly List _list; + public MyCollection(List list) { _list = list; } + public IEnumerator GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + public class MyCollectionBuilder + { + public static MyCollection Create(ReadOnlySpan items) + { + return new MyCollection(new List(items.ToArray())); + } + } + class A + { + static void M() + { + MyCollection x; + x = []; + x = [null, null]; + x = [1, 2, 3]; + } + } + """; + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); + CompileAndVerify( + comp, + symbolValidator: module => + { + AssertEx.Equal(new[] { "<>y__InlineArray2", "<>y__InlineArray3" }, getInlineArrayTypeNames(module)); + }, + verify: Verification.Skipped); + var refA = comp.EmitToImageReference(); + + string sourceB = """ + class B + { + static void M(MyCollection c) + { + } + static void M1() + { + M([1]); + } + static void M2() + { + M([4, 5, 6]); + M(["a"]); + M(["b"]); + } + } + """; + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); + CompileAndVerify( + comp, + symbolValidator: module => + { + AssertEx.Equal(new[] { "<>y__InlineArray1", "<>y__InlineArray3" }, getInlineArrayTypeNames(module)); + }, + verify: Verification.Skipped); + + const int n = 1025; + var builder = new System.Text.StringBuilder(); + for (int i = 0; i < n; i++) + { + if (i > 0) builder.Append(", "); + builder.Append(i); + } + string sourceC = $$""" + using System; + using System.Linq; + class Program + { + static void Main() + { + MyCollection c = [{{builder.ToString()}}]; + Console.WriteLine(c.Count()); + } + } + """; + comp = CreateCompilation(sourceC, references: new[] { refA }, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + CompileAndVerify( + comp, + symbolValidator: module => + { + AssertEx.Equal(new[] { $"<>y__InlineArray{n}" }, getInlineArrayTypeNames(module)); + }, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput($"{n}")); + + static ImmutableArray getInlineArrayTypeNames(ModuleSymbol module) + { + return module.GlobalNamespace.GetTypeMembers().WhereAsArray(t => t.Name.StartsWith("<>y__InlineArray")).SelectAsArray(t => t.Name); + } + } + + [CombinatorialData] + [Theory] public void CollectionBuilder_RefStructCollection(bool useCompilationReference, bool useScoped) { string qualifier = useScoped ? "scoped " : ""; @@ -5847,7 +6210,7 @@ public static MyCollection Create({{qualifier}}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 sourceB = """ @@ -5868,39 +6231,77 @@ static MyCollection F() } """; - var verifier = CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, verify: Verification.Fails, expectedOutput: "1, 2, 3, "); - // https://github.com/dotnet/roslyn/issues/68785: Avoid heap allocation for 'scoped' case. - verifier.VerifyIL("Program.F", - $$""" - { - // Code size 44 (0x2c) - .maxstack 4 - IL_0000: ldc.i4.3 - IL_0001: newarr "object" - IL_0006: dup - IL_0007: ldc.i4.0 - IL_0008: ldc.i4.1 - IL_0009: box "int" - IL_000e: stelem.ref - IL_000f: dup - IL_0010: ldc.i4.1 - IL_0011: ldc.i4.2 - IL_0012: box "int" - IL_0017: stelem.ref - IL_0018: dup - IL_0019: ldc.i4.2 - IL_001a: ldc.i4.3 - IL_001b: box "int" - IL_0020: stelem.ref - IL_0021: newobj "System.ReadOnlySpan..ctor(object[])" - IL_0026: call "MyCollection MyCollectionBuilder.Create({{qualifier}}System.ReadOnlySpan)" - IL_002b: ret - } - """); + var verifier = CompileAndVerify(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80, verify: Verification.Fails, expectedOutput: IncludeExpectedOutput("1, 2, 3, ")); + if (useScoped) + { + verifier.VerifyIL("Program.F", + $$""" + { + // Code size 67 (0x43) + .maxstack 2 + .locals init (<>y__InlineArray3 V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "<>y__InlineArray3" + IL_0008: ldloca.s V_0 + IL_000a: ldc.i4.0 + IL_000b: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_0010: ldc.i4.1 + IL_0011: box "int" + IL_0016: stind.ref + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.1 + IL_001a: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_001f: ldc.i4.2 + IL_0020: box "int" + IL_0025: stind.ref + IL_0026: ldloca.s V_0 + IL_0028: ldc.i4.2 + IL_0029: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_002e: ldc.i4.3 + IL_002f: box "int" + IL_0034: stind.ref + IL_0035: ldloca.s V_0 + IL_0037: ldc.i4.3 + IL_0038: call "InlineArrayAsReadOnlySpan<<>y__InlineArray3, object>(in <>y__InlineArray3, int)" + IL_003d: call "MyCollection MyCollectionBuilder.Create(scoped System.ReadOnlySpan)" + IL_0042: ret + } + """); + } + else + { + verifier.VerifyIL("Program.F", + $$""" + { + // Code size 44 (0x2c) + .maxstack 4 + IL_0000: ldc.i4.3 + IL_0001: newarr "object" + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldc.i4.1 + IL_0009: box "int" + IL_000e: stelem.ref + IL_000f: dup + IL_0010: ldc.i4.1 + IL_0011: ldc.i4.2 + IL_0012: box "int" + IL_0017: stelem.ref + IL_0018: dup + IL_0019: ldc.i4.2 + IL_001a: ldc.i4.3 + IL_001b: box "int" + IL_0020: stelem.ref + IL_0021: newobj "System.ReadOnlySpan..ctor(object[])" + IL_0026: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" + IL_002b: ret + } + """); + } } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_NonGenericCollection(bool useCompilationReference) { string sourceA = """ @@ -5922,7 +6323,7 @@ public static MyCollection Create(ReadOnlySpan items) => new MyCollection(new List(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -5937,11 +6338,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InterfaceCollection_ReturnInterface(bool useCompilationReference) { string sourceA = """ @@ -5966,7 +6372,7 @@ public sealed class MyCollection : IMyCollection } } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -5981,11 +6387,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(MyCollectionBuilder.MyCollection) [], (MyCollectionBuilder.MyCollection) [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(MyCollectionBuilder.MyCollection) [], (MyCollectionBuilder.MyCollection) [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InterfaceCollection_ReturnImplementation(bool useCompilationReference) { string sourceA = """ @@ -6010,7 +6421,7 @@ public sealed class MyCollection : IMyCollection } } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6023,7 +6434,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,35): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'IMyCollection'. // IMyCollection x = []; @@ -6034,7 +6445,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_NestedCollectionAndBuilder(bool useCompilationReference) { string sourceA = """ @@ -6059,7 +6470,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 sourceB = """ @@ -6074,11 +6485,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_NoElementType(bool useCompilationReference) { string sourceA = """ @@ -6094,7 +6510,7 @@ public class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6109,7 +6525,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,34): error CS9188: 'MyCollection' has a CollectionBuilderAttribute but no element type. // MyCollection x = []; @@ -6120,7 +6536,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ElementTypeFromPattern_01(bool useCompilationReference) { string sourceA = """ @@ -6156,7 +6572,7 @@ public static MyCollection Create(ReadOnlySpan items) => new MyCollection(items.ToArray()); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6176,11 +6592,16 @@ static IEnumerable GetElements(MyCollection c) } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ElementTypeFromPattern_02(bool useCompilationReference) { string sourceA = """ @@ -6216,7 +6637,7 @@ public static MyCollection Create(ReadOnlySpan items) => new MyCollection(items.ToArray()); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6236,11 +6657,16 @@ static IEnumerable GetElements(MyCollection c) } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ObjectElementType_01(bool useCompilationReference) { string sourceA = """ @@ -6260,7 +6686,7 @@ public static MyCollection Create(ReadOnlySpan items) => new MyCollection(items.ToArray()); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6275,11 +6701,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ObjectElementType_02(bool useCompilationReference) { string sourceA = """ @@ -6297,7 +6728,7 @@ public class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6312,7 +6743,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,34): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -6323,7 +6754,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ConstructedElementType(bool useCompilationReference) { string sourceA = """ @@ -6351,7 +6782,7 @@ public static C Create(ReadOnlySpan> items) => new C(new List>(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6366,11 +6797,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(C) [null], (C) [E(1), null], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(C) [null], (C) [E(1), null], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_Dictionary(bool useCompilationReference) { string sourceA = """ @@ -6396,7 +6832,7 @@ public static MyImmutableDictionary Create(ReadOnlySpan new MyImmutableDictionary(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 sourceB = """ @@ -6412,10 +6848,15 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [[one, 1], [two, 2]], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [[one, 1], [two, 2]], ")); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_MissingBuilderType() { string sourceA = """ @@ -6423,7 +6864,7 @@ public class MyCollectionBuilder { } """; - var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.Net80); var refA = comp.EmitToImageReference(); string sourceB = """ @@ -6437,7 +6878,7 @@ public struct MyCollection : IEnumerable IEnumerator IEnumerable.GetEnumerator() => default; } """; - comp = CreateCompilation(new[] { sourceB, CollectionBuilderAttributeDefinition }, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(new[] { sourceB, CollectionBuilderAttributeDefinition }, references: new[] { refA }, targetFramework: TargetFramework.Net80); var refB = comp.EmitToImageReference(); string sourceC = """ @@ -6452,7 +6893,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceC, references: new[] { refB }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceC, references: new[] { refB }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,31): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -6463,7 +6904,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_MissingBuilderMethod(bool useCompilationReference) { string sourceA = """ @@ -6480,7 +6921,7 @@ public class MyCollectionBuilder { } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6495,7 +6936,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,31): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -6505,7 +6946,7 @@ static void Main() Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[null]").WithArguments("Create", "T", "MyCollection").WithLocation(7, 34)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_NullBuilderType() { string sourceA = """ @@ -6531,7 +6972,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(4,2): error CS9185: The CollectionBuilderAttribute builder type must be a non-generic class or struct. // [CollectionBuilder(null, "Create")] @@ -6584,7 +7025,7 @@ static void Main() Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[null]").WithArguments("Create", "T", "MyCollection").WithLocation(7, 34)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_InvalidBuilderType_Interface() { string sourceA = """ @@ -6615,7 +7056,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(5,2): error CS9185: The CollectionBuilderAttribute builder type must be a non-generic class or struct. // [CollectionBuilder(typeof(MyCollectionBuilder), "Create")] @@ -6678,7 +7119,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InvalidBuilderType_03( [CombinatorialValues("public delegate void MyCollectionBuilder();", "public enum MyCollectionBuilder { }")] string builderTypeDefinition) { @@ -6707,7 +7148,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(5,2): error CS9185: The CollectionBuilderAttribute builder type must be a non-generic class or struct. // [CollectionBuilder(typeof(MyCollectionBuilder), "ToString")] @@ -6721,7 +7162,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InvalidBuilderType_04( [CombinatorialValues("int[]", "int*", "(object, object)")] string builderTypeName) { @@ -6748,7 +7189,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(4,2): error CS9185: The CollectionBuilderAttribute builder type must be a non-generic class or struct. // [CollectionBuilder(typeof(int*), "ToString")] @@ -6761,7 +7202,7 @@ static void Main() Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[null]").WithArguments("ToString", "T", "MyCollection").WithLocation(7, 34)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_InvalidBuilderType_TypeParameter() { string source = """ @@ -6788,7 +7229,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(6,24): error CS0416: 'T': an attribute argument cannot use type parameters // [CollectionBuilder(typeof(T), "ToString")] @@ -6799,7 +7240,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_NullOrEmptyMethodName([CombinatorialValues("null", "\"\"")] string methodName) { string sourceA = $$""" @@ -6828,7 +7269,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(4,2): error CS9186: The CollectionBuilderAttribute method name is invalid. // [CollectionBuilder(typeof(MyCollectionBuilder), "")] @@ -6891,7 +7332,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InstanceMethod(bool useCompilationReference) { string sourceA = """ @@ -6910,7 +7351,7 @@ public class MyCollectionBuilder public MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6925,7 +7366,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,31): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -6936,7 +7377,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_OtherMember_01( [CombinatorialValues( "public MyCollection Create = null;", @@ -6959,7 +7400,7 @@ public class MyCollectionBuilder {{createMember}} } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -6974,7 +7415,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,26): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -6985,14 +7426,14 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_TypeDifferences_Dynamic_01(bool useCompilationReference) { CollectionBuilder_TypeDifferences("object", "dynamic", "1, 2, 3", "[1, 2, 3]", useCompilationReference); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_TypeDifferences_Dynamic_02(bool useCompilationReference) { string sourceA = $$""" @@ -7013,7 +7454,7 @@ public static MyCollection Create(ReadOnlySpan items) => new MyCollection(new List(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = $$""" @@ -7034,11 +7475,16 @@ static IEnumerable GetElements(MyCollection c) } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: $"[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput($"[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_TypeDifferences_TupleElementNames(bool useCompilationReference) { CollectionBuilder_TypeDifferences("(int, int)", "(int A, int B)", "(1, 2), default", "[(1, 2), (0, 0)]", useCompilationReference); @@ -7046,7 +7492,7 @@ public void CollectionBuilder_TypeDifferences_TupleElementNames(bool useCompilat } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_TypeDifferences_Nullability(bool useCompilationReference) { CollectionBuilder_TypeDifferences("object", "object?", "1, 2, 3", "[1, 2, 3]", useCompilationReference); @@ -7075,7 +7521,7 @@ public static MyCollection Create(ReadOnlySpan<{{builderElementType}}> items) => new MyCollection(new List<{{collectionElementType}}>(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = $$""" @@ -7092,12 +7538,17 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: $"[], {expectedOutput}, "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput($"[], {expectedOutput}, ")); } // If there are multiple attributes, the first is used. [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_MultipleAttributes(bool useCompilationReference) { string sourceAttribute = """ @@ -7135,7 +7586,7 @@ public static MyCollection Create2(ReadOnlySpan items) => throw null; } """; - var comp = CreateCompilation(new[] { sourceAttribute, sourceA }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceAttribute, sourceA }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7148,7 +7599,12 @@ static void Main() } } """; - var verifier = CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[1, 2, 3], "); + var verifier = CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); comp = (CSharpCompilation)verifier.Compilation; var collectionType = (NamedTypeSymbol)comp.GetMember("Program.F").ReturnType; @@ -7160,7 +7616,7 @@ static void Main() Assert.Equal("Create1", methodName); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_GenericBuilderType_01() { string sourceA = """ @@ -7191,7 +7647,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(5,2): error CS9185: The CollectionBuilderAttribute builder type must be a non-generic class or struct. // [CollectionBuilder(typeof(MyCollectionBuilder<>), "Create")] @@ -7204,7 +7660,7 @@ static void Main() Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[null]").WithArguments("Create", "T", "MyCollection").WithLocation(7, 34)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_GenericBuilderType_02() { string sourceA = """ @@ -7235,7 +7691,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(5,2): error CS9185: The CollectionBuilderAttribute builder type must be a non-generic class or struct. // [CollectionBuilder(typeof(MyCollectionBuilder), "Create")] @@ -7248,7 +7704,7 @@ static void Main() Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[null]").WithArguments("Create", "T", "MyCollection").WithLocation(7, 34)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_GenericBuilderType_03() { string source = """ @@ -7283,7 +7739,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(7,24): error CS0416: 'Container.MyCollectionBuilder': an attribute argument cannot use type parameters // [CollectionBuilder(typeof(MyCollectionBuilder), "Create")] @@ -7294,7 +7750,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_GenericCollectionContainerType_01(bool useCompilationReference) { string sourceA = """ @@ -7319,7 +7775,7 @@ public static Container.MyCollection Create(ReadOnlySpan items) => new Container.MyCollection(new List(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7334,11 +7790,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_GenericCollectionContainerType_02(bool useCompilationReference) { string sourceA = """ @@ -7363,7 +7824,7 @@ public static Container.MyCollection Create(ReadOnlySpan items) => new Container.MyCollection(new List(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7378,11 +7839,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_GenericCollectionContainerType_03(bool useCompilationReference) { string sourceA = """ @@ -7407,7 +7873,7 @@ public static Container.MyCollection Create(ReadOnlySpan items) => new Container.MyCollection(new List(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7422,11 +7888,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(Container.MyCollection) [], (Container.MyCollection) [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_GenericType_ElementTypeFirstOfTwo(bool useCompilationReference) { string sourceA = """ @@ -7448,7 +7919,7 @@ public static MyCollection Create(ReadOnlySpan items) => new MyCollection(new List(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7463,11 +7934,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(MyCollection) [], (MyCollection) [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(MyCollection) [], (MyCollection) [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_GenericType_ElementTypeSecondOfTwo(bool useCompilationReference) { string sourceA = """ @@ -7489,7 +7965,7 @@ public static MyCollection Create(ReadOnlySpan items) => new MyCollection(new List(items.ToArray())); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7504,11 +7980,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "(MyCollection) [], (MyCollection) [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("(MyCollection) [], (MyCollection) [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InaccessibleBuilderType_01(bool useCompilationReference) { string sourceA = """ @@ -7527,7 +8008,7 @@ internal class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7542,7 +8023,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,31): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -7553,7 +8034,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_NestedBuilderType(bool useCompilationReference) { string sourceA = """ @@ -7575,7 +8056,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 sourceB = """ @@ -7591,11 +8072,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InaccessibleBuilderType_02(bool useCompilationReference) { string sourceA = """ @@ -7615,7 +8101,7 @@ protected class MyCollectionBuilder static readonly MyCollection _instance = [1, 2, 3]; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7630,7 +8116,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,26): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -7641,7 +8127,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InaccessibleMethod(bool useCompilationReference) { string sourceA = """ @@ -7661,7 +8147,7 @@ public class MyCollectionBuilder internal static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7676,7 +8162,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,31): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -7687,7 +8173,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_Overloads_01(bool useCompilationReference) { string sourceA = """ @@ -7723,7 +8209,7 @@ public static MyCollection Create(ReadOnlySpan items, int index = 0) } } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7738,11 +8224,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_Overloads_02(bool useCompilationReference) { string sourceA = """ @@ -7770,7 +8261,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 sourceB = """ @@ -7785,11 +8276,16 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_UnexpectedSignature_01( [CombinatorialValues( "public static MyCollection Create(ReadOnlySpan items) => default;", // constructed parameter and return types @@ -7825,7 +8321,7 @@ public class MyCollectionBuilder {{methodDeclaration}} } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7840,7 +8336,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,34): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -7851,7 +8347,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_UnexpectedSignature_MoreTypeParameters(bool useCompilationReference) { string sourceA = """ @@ -7870,7 +8366,7 @@ public class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7885,7 +8381,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,26): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -7896,7 +8392,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_UnexpectedSignature_FewerTypeParameters(bool useCompilationReference) { string sourceA = """ @@ -7915,7 +8411,7 @@ public sealed class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7930,7 +8426,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,39): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -7941,7 +8437,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_InheritedAttributeOnBaseCollection(bool useCompilationReference) { string sourceAttribute = """ @@ -7973,7 +8469,7 @@ public sealed class MyCollectionBuilder public static MyCollectionBase Create(ReadOnlySpan items) => new MyCollection(); } """; - var comp = CreateCompilation(new[] { sourceA, sourceAttribute }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceAttribute }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -7987,7 +8483,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,27): error CS1061: 'MyCollection' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'MyCollection' could be found (are you missing a using directive or an assembly reference?) // MyCollection y = [2]; @@ -7995,7 +8491,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_CreateMethodOnBase(bool useCompilationReference) { string sourceA = """ @@ -8017,7 +8513,7 @@ public sealed class MyCollectionBuilder : MyCollectionBuilderBase { } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -8031,7 +8527,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,26): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // MyCollection x = []; @@ -8042,7 +8538,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ObsoleteBuilderType_01(bool useCompilationReference) { string sourceA = """ @@ -8062,7 +8558,7 @@ public class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -8077,7 +8573,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,34): warning CS0612: 'MyCollectionBuilder' is obsolete // MyCollection x = []; @@ -8087,7 +8583,7 @@ static void Main() Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "[1, 2, 3]").WithArguments("MyCollectionBuilder").WithLocation(7, 31)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_ObsoleteBuilderType_02() { string sourceA = """ @@ -8119,7 +8615,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(5,27): error CS0619: 'MyCollectionBuilder' is obsolete: 'message 2' // [CollectionBuilder(typeof(MyCollectionBuilder), "Create")] @@ -8133,7 +8629,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ObsoleteBuilderMethod_01(bool useCompilationReference) { string sourceA = """ @@ -8153,7 +8649,7 @@ public class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -8168,7 +8664,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,34): warning CS0612: 'MyCollectionBuilder.Create(ReadOnlySpan)' is obsolete // MyCollection x = []; @@ -8179,7 +8675,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_ObsoleteBuilderMethod_02(bool useCompilationReference) { string sourceA = """ @@ -8199,7 +8695,7 @@ public class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -8214,7 +8710,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,34): error CS0619: 'MyCollectionBuilder.Create(ReadOnlySpan)' is obsolete: 'message 4' // MyCollection x = []; @@ -8224,7 +8720,7 @@ static void Main() Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "[1, 2, 3]").WithArguments("MyCollectionBuilder.Create(System.ReadOnlySpan)", "message 4").WithLocation(7, 31)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_UnmanagedCallersOnly() { string sourceA = """ @@ -8257,7 +8753,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 1.cs(6,34): error CS8901: 'MyCollectionBuilder.Create(ReadOnlySpan)' is attributed with 'UnmanagedCallersOnly' and cannot be called directly. Obtain a function pointer to this method. // MyCollection x = []; @@ -8274,7 +8770,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_Constraints_CollectionAndBuilder(bool useCompilationReference) { string sourceA = """ @@ -8296,7 +8792,7 @@ public static MyCollection Create(ReadOnlySpan items) where T : struct => new MyCollection(new List(items.ToArray())); } """; - 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 = """ @@ -8311,7 +8807,12 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB1, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB1, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); string sourceB2 = """ #pragma warning disable 219 @@ -8324,7 +8825,7 @@ static void Main() } } """; - comp = CreateCompilation(sourceB2, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB2, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,32): error CS0453: The type 'int?' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyCollectionBuilder.Create(ReadOnlySpan)' // MyCollection x = [4, null]; @@ -8332,7 +8833,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_Constraints_BuilderOnly(bool useCompilationReference) { string sourceA = """ @@ -8354,7 +8855,7 @@ public static MyCollection Create(ReadOnlySpan items) where T : struct => new MyCollection(new List(items.ToArray())); } """; - 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 = """ @@ -8369,7 +8870,12 @@ static void Main() } } """; - CompileAndVerify(new[] { sourceB1, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB1, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); string sourceB2 = """ #pragma warning disable 219 @@ -8382,14 +8888,14 @@ static void Main() } } """; - comp = CreateCompilation(sourceB2, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB2, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,32): error CS0453: The type 'int?' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyCollectionBuilder.Create(ReadOnlySpan)' // MyCollection x = [4, null]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "[4, null]").WithArguments("MyCollectionBuilder.Create(System.ReadOnlySpan)", "T", "int?").WithLocation(6, 32)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_Constraints_CollectionOnly() { string sourceA = """ @@ -8423,7 +8929,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 1.cs(7,22): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyCollection' // MyCollection y = [1, 2, 3]; @@ -8434,7 +8940,7 @@ static void Main() } [CombinatorialData] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_Substituted_01(bool useCompilationReference) { string sourceA = """ @@ -8453,7 +8959,7 @@ public class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => default; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); var refA = AsReference(comp, useCompilationReference); string sourceB = """ @@ -8470,7 +8976,7 @@ static void F(MyCollection c) } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics(); var collectionType = (NamedTypeSymbol)comp.GetMember("Program.F").Parameters[0].Type; @@ -8488,7 +8994,7 @@ static void F(MyCollection c) Assert.Equal("Create", methodName); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_Substituted_02() { string sourceA = """ @@ -8524,7 +9030,7 @@ static void F(MyCollection c) } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(5,2): error CS9185: The CollectionBuilderAttribute builder type must be a non-generic class or struct. // [CollectionBuilder(typeof(Container.MyCollectionBuilder), "Create")] @@ -8548,7 +9054,7 @@ static void F(MyCollection c) Assert.Equal("Create", methodName); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_Substituted_03() { string source = """ @@ -8582,7 +9088,7 @@ static void F(Container.MyCollection c) } } """; - var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(7,24): error CS0416: 'Container.MyCollectionBuilder': an attribute argument cannot use type parameters // [CollectionBuilder(typeof(MyCollectionBuilder), "Create")] @@ -8655,7 +9161,7 @@ static void F(MyCollection c) Assert.Equal("Create", methodName); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_ExtensionMethodGetEnumerator_01() { string source = """ @@ -8686,14 +9192,14 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(24,31): error CS9188: 'MyCollection' has a CollectionBuilderAttribute but no element type. // MyCollection c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderNoElementType, "[]").WithArguments("MyCollection").WithLocation(24, 31)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_ExtensionMethodGetEnumerator_02() { string sourceA = """ @@ -8714,7 +9220,7 @@ static class Extensions static MyCollection F() => []; } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics(); var refA = comp.EmitToImageReference(); @@ -8728,14 +9234,14 @@ static void Main() } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net70); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,31): error CS9188: 'MyCollection' has a CollectionBuilderAttribute but no element type. // MyCollection c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderNoElementType, "[]").WithArguments("MyCollection").WithLocation(6, 31)); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_InaccessibleGetEnumerator() { string source = """ @@ -8760,7 +9266,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(8,42): error CS9188: 'MyCollection' has a CollectionBuilderAttribute but no element type. // public static MyCollection F() => []; @@ -8776,7 +9282,7 @@ static void Main() [InlineData("scoped", "", true)] [InlineData("scoped", "scoped", false)] [InlineData("scoped", "scoped", true)] - [ConditionalTheory(typeof(CoreClrOnly))] + [Theory] public void CollectionBuilder_Scoped(string constructorParameterModifier, string builderParameterModifier, bool useCompilationReference) { string sourceA = $$""" @@ -8798,7 +9304,7 @@ public class MyCollectionBuilder public static MyCollection Create({{builderParameterModifier}} ReadOnlySpan items) => new(items); } """; - var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics(); var refA = AsReference(comp, useCompilationReference); @@ -8821,10 +9327,15 @@ static List GetItems(MyCollection c) } } """; - CompileAndVerify(new[] { sourceB, s_collectionExtensions }, references: new[] { refA }, targetFramework: TargetFramework.Net70, expectedOutput: "[], [1, 2, 3], "); + CompileAndVerify( + new[] { sourceB, s_collectionExtensions }, + references: new[] { refA }, + targetFramework: TargetFramework.Net80, + verify: builderParameterModifier == "scoped" ? Verification.Fails : Verification.FailsPEVerify, + expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], ")); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_ScopedBuilderParameterOnly() { string sourceA = $$""" @@ -8858,7 +9369,7 @@ static void Main() } } """; - var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(16,78): error CS8347: Cannot use a result of 'MyCollection.MyCollection(ReadOnlySpan)' in this context because it may expose variables referenced by parameter 'items' outside of their declaration scope // public static MyCollection Create(scoped ReadOnlySpan items) => new(items); @@ -8868,7 +9379,54 @@ static void Main() Diagnostic(ErrorCode.ERR_EscapeVariable, "items").WithArguments("scoped System.ReadOnlySpan items").WithLocation(16, 82)); } - [ConditionalFact(typeof(CoreClrOnly))] + [CombinatorialData] + [Theory] + public void CollectionBuilder_MissingInt32(bool useCompilationReference) + { + string sourceA = """ + using System; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + [CollectionBuilder(typeof(MyCollectionBuilder), nameof(MyCollectionBuilder.Create))] + public struct MyCollection + { + public IEnumerator GetEnumerator() => default; + } + public class MyCollectionBuilder + { + public static MyCollection Create(ReadOnlySpan items) => default; + } + """; + var comp = CreateCompilation(new[] { sourceA, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = """ + #pragma warning disable 219 + class Program + { + static void Main() + { + MyCollection x = []; + MyCollection y = ["2"]; + MyCollection z = new(); + } + } + """; + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); + comp.MakeTypeMissing(SpecialType.System_Int32); + comp.VerifyEmitDiagnostics( + // (7,34): error CS0518: Predefined type 'System.Int32' is not defined or imported + // MyCollection y = ["2"]; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"[""2""]").WithArguments("System.Int32").WithLocation(7, 34), + // (7,34): error CS0518: Predefined type 'System.Int32' is not defined or imported + // MyCollection y = ["2"]; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"[""2""]").WithArguments("System.Int32").WithLocation(7, 34), + // (7,34): error CS0518: Predefined type 'System.Int32' is not defined or imported + // MyCollection y = ["2"]; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"[""2""]").WithArguments("System.Int32").WithLocation(7, 34)); + } + + [Fact] public void CollectionBuilder_Async() { string sourceA = """ @@ -8912,143 +9470,156 @@ static async Task F(int i) } } """; - var verifier = CompileAndVerify(new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition, s_collectionExtensions }, targetFramework: TargetFramework.Net70, expectedOutput: "[1, 2, 3], "); + var verifier = CompileAndVerify( + new[] { sourceA, sourceB, CollectionBuilderAttributeDefinition, s_collectionExtensions }, + targetFramework: TargetFramework.Net80, + verify: Verification.Fails, + expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); verifier.VerifyIL("Program.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", """ { - // Code size 285 (0x11d) - .maxstack 4 + // Code size 324 (0x144) + .maxstack 3 .locals init (int V_0, MyCollection V_1, int V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) + int V_3, + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld "int Program.d__1.<>1__state" IL_0006: stloc.0 .try { IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0049 + IL_0008: brfalse.s IL_0057 IL_000a: ldloc.0 IL_000b: ldc.i4.1 - IL_000c: beq IL_00a7 - IL_0011: ldc.i4.1 - IL_0012: call "System.Threading.Tasks.Task Program.F(int)" - IL_0017: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" - IL_001c: stloc.3 - IL_001d: ldloca.s V_3 - IL_001f: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" - IL_0024: brtrue.s IL_0065 - IL_0026: ldarg.0 - IL_0027: ldc.i4.0 - IL_0028: dup - IL_0029: stloc.0 - IL_002a: stfld "int Program.d__1.<>1__state" - IL_002f: ldarg.0 - IL_0030: ldloc.3 - IL_0031: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" - IL_0036: ldarg.0 - IL_0037: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" - IL_003c: ldloca.s V_3 - IL_003e: ldarg.0 - IL_003f: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.AwaitUnsafeOnCompleted, Program.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__1)" - IL_0044: leave IL_011c - IL_0049: ldarg.0 - IL_004a: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" - IL_004f: stloc.3 - IL_0050: ldarg.0 - IL_0051: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" - IL_0056: initobj "System.Runtime.CompilerServices.TaskAwaiter" - IL_005c: ldarg.0 - IL_005d: ldc.i4.m1 - IL_005e: dup - IL_005f: stloc.0 - IL_0060: stfld "int Program.d__1.<>1__state" - IL_0065: ldarg.0 - IL_0066: ldloca.s V_3 - IL_0068: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" - IL_006d: stfld "int Program.d__1.<>7__wrap1" - IL_0072: ldc.i4.3 - IL_0073: call "System.Threading.Tasks.Task Program.F(int)" - IL_0078: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" - IL_007d: stloc.3 - IL_007e: ldloca.s V_3 - IL_0080: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" - IL_0085: brtrue.s IL_00c3 - IL_0087: ldarg.0 - IL_0088: ldc.i4.1 - IL_0089: dup - IL_008a: stloc.0 - IL_008b: stfld "int Program.d__1.<>1__state" - IL_0090: ldarg.0 - IL_0091: ldloc.3 - IL_0092: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" - IL_0097: ldarg.0 - IL_0098: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" - IL_009d: ldloca.s V_3 - IL_009f: ldarg.0 - IL_00a0: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.AwaitUnsafeOnCompleted, Program.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__1)" - IL_00a5: leave.s IL_011c - IL_00a7: ldarg.0 - IL_00a8: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" - IL_00ad: stloc.3 + IL_000c: beq IL_00cf + IL_0011: ldarg.0 + IL_0012: ldflda "<>y__InlineArray3 Program.d__1.<>7__wrap1" + IL_0017: initobj "<>y__InlineArray3" + IL_001d: ldc.i4.1 + IL_001e: call "System.Threading.Tasks.Task Program.F(int)" + IL_0023: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0028: stloc.s V_4 + IL_002a: ldloca.s V_4 + IL_002c: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_0031: brtrue.s IL_0074 + IL_0033: ldarg.0 + IL_0034: ldc.i4.0 + IL_0035: dup + IL_0036: stloc.0 + IL_0037: stfld "int Program.d__1.<>1__state" + IL_003c: ldarg.0 + IL_003d: ldloc.s V_4 + IL_003f: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" + IL_0044: ldarg.0 + IL_0045: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" + IL_004a: ldloca.s V_4 + IL_004c: ldarg.0 + IL_004d: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.AwaitUnsafeOnCompleted, Program.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__1)" + IL_0052: leave IL_0143 + IL_0057: ldarg.0 + IL_0058: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" + IL_005d: stloc.s V_4 + IL_005f: ldarg.0 + IL_0060: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" + IL_0065: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_006b: ldarg.0 + IL_006c: ldc.i4.m1 + IL_006d: dup + IL_006e: stloc.0 + IL_006f: stfld "int Program.d__1.<>1__state" + IL_0074: ldloca.s V_4 + IL_0076: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_007b: stloc.2 + IL_007c: ldarg.0 + IL_007d: ldflda "<>y__InlineArray3 Program.d__1.<>7__wrap1" + IL_0082: ldc.i4.0 + IL_0083: call "InlineArrayElementRef<<>y__InlineArray3, int>(ref <>y__InlineArray3, int)" + IL_0088: ldloc.2 + IL_0089: stind.i4 + IL_008a: ldarg.0 + IL_008b: ldflda "<>y__InlineArray3 Program.d__1.<>7__wrap1" + IL_0090: ldc.i4.1 + IL_0091: call "InlineArrayElementRef<<>y__InlineArray3, int>(ref <>y__InlineArray3, int)" + IL_0096: ldc.i4.2 + IL_0097: stind.i4 + IL_0098: ldc.i4.3 + IL_0099: call "System.Threading.Tasks.Task Program.F(int)" + IL_009e: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_00a3: stloc.s V_4 + IL_00a5: ldloca.s V_4 + IL_00a7: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_00ac: brtrue.s IL_00ec IL_00ae: ldarg.0 - IL_00af: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" - IL_00b4: initobj "System.Runtime.CompilerServices.TaskAwaiter" - IL_00ba: ldarg.0 - IL_00bb: ldc.i4.m1 - IL_00bc: dup - IL_00bd: stloc.0 - IL_00be: stfld "int Program.d__1.<>1__state" - IL_00c3: ldloca.s V_3 - IL_00c5: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" - IL_00ca: stloc.2 - IL_00cb: ldc.i4.3 - IL_00cc: newarr "int" - IL_00d1: dup - IL_00d2: ldc.i4.0 - IL_00d3: ldarg.0 - IL_00d4: ldfld "int Program.d__1.<>7__wrap1" - IL_00d9: stelem.i4 - IL_00da: dup - IL_00db: ldc.i4.1 - IL_00dc: ldc.i4.2 - IL_00dd: stelem.i4 - IL_00de: dup - IL_00df: ldc.i4.2 - IL_00e0: ldloc.2 - IL_00e1: stelem.i4 - IL_00e2: newobj "System.ReadOnlySpan..ctor(int[])" - IL_00e7: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" - IL_00ec: stloc.1 - IL_00ed: leave.s IL_0108 + IL_00af: ldc.i4.1 + IL_00b0: dup + IL_00b1: stloc.0 + IL_00b2: stfld "int Program.d__1.<>1__state" + IL_00b7: ldarg.0 + IL_00b8: ldloc.s V_4 + IL_00ba: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" + IL_00bf: ldarg.0 + IL_00c0: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" + IL_00c5: ldloca.s V_4 + IL_00c7: ldarg.0 + IL_00c8: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.AwaitUnsafeOnCompleted, Program.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.d__1)" + IL_00cd: leave.s IL_0143 + IL_00cf: ldarg.0 + IL_00d0: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" + IL_00d5: stloc.s V_4 + IL_00d7: ldarg.0 + IL_00d8: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.d__1.<>u__1" + IL_00dd: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_00e3: ldarg.0 + IL_00e4: ldc.i4.m1 + IL_00e5: dup + IL_00e6: stloc.0 + IL_00e7: stfld "int Program.d__1.<>1__state" + IL_00ec: ldloca.s V_4 + IL_00ee: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_00f3: stloc.3 + IL_00f4: ldarg.0 + IL_00f5: ldflda "<>y__InlineArray3 Program.d__1.<>7__wrap1" + IL_00fa: ldc.i4.2 + IL_00fb: call "InlineArrayElementRef<<>y__InlineArray3, int>(ref <>y__InlineArray3, int)" + IL_0100: ldloc.3 + IL_0101: stind.i4 + IL_0102: ldarg.0 + IL_0103: ldflda "<>y__InlineArray3 Program.d__1.<>7__wrap1" + IL_0108: ldc.i4.3 + IL_0109: call "InlineArrayAsReadOnlySpan<<>y__InlineArray3, int>(in <>y__InlineArray3, int)" + IL_010e: call "MyCollection MyCollectionBuilder.Create(System.ReadOnlySpan)" + IL_0113: stloc.1 + IL_0114: leave.s IL_012f } catch System.Exception { - IL_00ef: stloc.s V_4 - IL_00f1: ldarg.0 - IL_00f2: ldc.i4.s -2 - IL_00f4: stfld "int Program.d__1.<>1__state" - IL_00f9: ldarg.0 - IL_00fa: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" - IL_00ff: ldloc.s V_4 - IL_0101: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.SetException(System.Exception)" - IL_0106: leave.s IL_011c + IL_0116: stloc.s V_5 + IL_0118: ldarg.0 + IL_0119: ldc.i4.s -2 + IL_011b: stfld "int Program.d__1.<>1__state" + IL_0120: ldarg.0 + IL_0121: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" + IL_0126: ldloc.s V_5 + IL_0128: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.SetException(System.Exception)" + IL_012d: leave.s IL_0143 } - IL_0108: ldarg.0 - IL_0109: ldc.i4.s -2 - IL_010b: stfld "int Program.d__1.<>1__state" - IL_0110: ldarg.0 - IL_0111: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" - IL_0116: ldloc.1 - IL_0117: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.SetResult(MyCollection)" - IL_011c: ret + IL_012f: ldarg.0 + IL_0130: ldc.i4.s -2 + IL_0132: stfld "int Program.d__1.<>1__state" + IL_0137: ldarg.0 + IL_0138: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder> Program.d__1.<>t__builder" + IL_013d: ldloc.1 + IL_013e: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.SetResult(MyCollection)" + IL_0143: ret } """); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CollectionBuilder_AttributeCycle() { string source = """ @@ -9071,7 +9642,7 @@ static class MyCollectionBuilder public static MyCollection Create(ReadOnlySpan items) => null; } """; - var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net70); + var comp = CreateCompilation(new[] { source, CollectionBuilderAttributeDefinition }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // 0.cs(6,49): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [CollectionBuilder(typeof(MyCollectionBuilder), MyCollectionBuilder.GetName([1, 2, 3]))] @@ -9278,7 +9849,7 @@ static T[] Create(T a, T b) """); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void IOperation_Span() { string source = """ diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 2150191642108..0da329ec67684 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection.Metadata; using System.Runtime.InteropServices; @@ -82,6 +81,10 @@ internal sealed class PrivateImplementationDetails : DefaultTypeDef, Cci.INamesp private readonly ConcurrentDictionary _synthesizedMethods = new ConcurrentDictionary(); + // synthesized top-level types (for inline arrays currently) + private ImmutableArray _orderedTopLevelTypes; + private readonly ConcurrentDictionary _synthesizedTopLevelTypes = new ConcurrentDictionary(); + // field types for different block sizes. private ImmutableArray _orderedProxyTypes; private readonly ConcurrentDictionary<(uint Size, ushort Alignment), Cci.ITypeReference> _proxyTypes = new ConcurrentDictionary<(uint Size, ushort Alignment), Cci.ITypeReference>(); @@ -155,6 +158,9 @@ internal void Freeze() // Sort methods. _orderedSynthesizedMethods = _synthesizedMethods.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).AsImmutable(); + // Sort top-level types. + _orderedTopLevelTypes = _synthesizedTopLevelTypes.OrderBy(kvp => kvp.Key).Select(kvp => (Cci.INamespaceTypeDefinition)kvp.Value).AsImmutable(); + // Sort proxy types. _orderedProxyTypes = _proxyTypes.OrderBy(kvp => kvp.Key.Size).ThenBy(kvp => kvp.Key.Alignment).Select(kvp => kvp.Value).AsImmutable(); } @@ -320,6 +326,25 @@ internal bool TryAddSynthesizedMethod(Cci.IMethodDefinition method) return method; } + internal bool TryAddSynthesizedType(Cci.INamespaceTypeDefinition type) + { + Debug.Assert(!IsFrozen); + Debug.Assert(type.Name is { }); + return _synthesizedTopLevelTypes.TryAdd(type.Name, type); + } + + internal Cci.INamespaceTypeDefinition? GetSynthesizedType(string name) + { + _synthesizedTopLevelTypes.TryGetValue(name, out var type); + return type; + } + + internal IEnumerable GetAdditionalTopLevelTypes() + { + Debug.Assert(IsFrozen); + return _orderedTopLevelTypes; + } + public override IEnumerable GetNestedTypes(EmitContext context) { Debug.Assert(IsFrozen); diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 651e9cfdacb18..1762c723de65d 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -664,6 +664,13 @@ protected bool ContainsTopLevelType(string fullEmittedName) AddTopLevelType(names, privateImpl); VisitTopLevelType(typeReferenceIndexer, privateImpl); yield return privateImpl; + + foreach (var typeDef in privateImpl.GetAdditionalTopLevelTypes()) + { + AddTopLevelType(names, typeDef); + VisitTopLevelType(typeReferenceIndexer, typeDef); + yield return typeDef; + } } if (EmbeddedTypesManagerOpt != null)