diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 1940090525932..e8aaa6f0ba0ae 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -4069,7 +4069,6 @@ private bool HasLocalScope(BoundCollectionExpression expr) } return true; case CollectionExpressionTypeKind.ImplementsIEnumerable: - case CollectionExpressionTypeKind.ImplementsIEnumerableT: // Error cases. Restrict the collection to local scope. return true; default: diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index a16ad20e31475..b4cbc60d6f806 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -636,7 +636,6 @@ private BoundCollectionExpression ConvertCollectionExpression( } break; - case CollectionExpressionTypeKind.ImplementsIEnumerableT: case CollectionExpressionTypeKind.ImplementsIEnumerable: if (targetType.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Collections_Immutable_ImmutableArray_T), TypeCompareKind.ConsiderEverything)) { @@ -651,7 +650,7 @@ private BoundCollectionExpression ConvertCollectionExpression( BoundExpression? collectionCreation = null; BoundObjectOrCollectionValuePlaceholder? implicitReceiver = null; - if (collectionTypeKind is CollectionExpressionTypeKind.ImplementsIEnumerableT or CollectionExpressionTypeKind.ImplementsIEnumerable) + if (collectionTypeKind is CollectionExpressionTypeKind.ImplementsIEnumerable) { implicitReceiver = new BoundObjectOrCollectionValuePlaceholder(syntax, isNewInstance: true, targetType) { WasCompilerGenerated = true }; if (targetType is NamedTypeSymbol namedType) @@ -772,7 +771,7 @@ BoundNode bindSpreadElement(BoundCollectionExpressionSpreadElement element, Type /// internal static BoundExpression? GetUnderlyingCollectionExpressionElement(BoundCollectionExpression expr, BoundExpression? element) { - if (expr.CollectionTypeKind is CollectionExpressionTypeKind.ImplementsIEnumerable or CollectionExpressionTypeKind.ImplementsIEnumerableT) + if (expr.CollectionTypeKind is CollectionExpressionTypeKind.ImplementsIEnumerable) { return element switch { @@ -831,30 +830,33 @@ private void GenerateImplicitConversionErrorForCollectionExpression( BindingDiagnosticBag diagnostics) { var collectionTypeKind = ConversionsBase.GetCollectionExpressionTypeKind(Compilation, targetType, out TypeWithAnnotations elementTypeWithAnnotations); - if (collectionTypeKind == CollectionExpressionTypeKind.CollectionBuilder) - { - Debug.Assert(elementTypeWithAnnotations.Type is null); // GetCollectionExpressionTypeKind() does not set elementType for CollectionBuilder cases. - if (!TryGetCollectionIterationType((ExpressionSyntax)node.Syntax, targetType, out elementTypeWithAnnotations)) - { - Error(diagnostics, ErrorCode.ERR_CollectionBuilderNoElementType, node.Syntax, targetType); - return; - } - Debug.Assert(elementTypeWithAnnotations.HasType); - } - - var elementType = elementTypeWithAnnotations.Type; - if (collectionTypeKind == CollectionExpressionTypeKind.ImplementsIEnumerableT - && findSingleIEnumerableTImplementation(targetType, Compilation) is { } implementation) + switch (collectionTypeKind) { - // If we have a single IEnumerable implementation, we can report conversion errors against that element type below - elementType = implementation.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0].Type; + case CollectionExpressionTypeKind.ImplementsIEnumerable: + case CollectionExpressionTypeKind.CollectionBuilder: + Debug.Assert(elementTypeWithAnnotations.Type is null); // GetCollectionExpressionTypeKind() does not set elementType for these cases. + if (!TryGetCollectionIterationType((ExpressionSyntax)node.Syntax, targetType, out elementTypeWithAnnotations)) + { + Error( + diagnostics, + collectionTypeKind == CollectionExpressionTypeKind.CollectionBuilder ? + ErrorCode.ERR_CollectionBuilderNoElementType : + ErrorCode.ERR_CollectionExpressionTargetNoElementType, + node.Syntax, + targetType); + return; + } + Debug.Assert(elementTypeWithAnnotations.HasType); + break; } bool reportedErrors = false; - if (collectionTypeKind != CollectionExpressionTypeKind.None && - elementType is { }) + if (collectionTypeKind != CollectionExpressionTypeKind.None) { + var elementType = elementTypeWithAnnotations.Type; + Debug.Assert(elementType is { }); + var elements = node.Elements; var useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); foreach (var element in elements) @@ -896,27 +898,6 @@ private void GenerateImplicitConversionErrorForCollectionExpression( } return; - - static NamedTypeSymbol? findSingleIEnumerableTImplementation(TypeSymbol targetType, CSharpCompilation compilation) - { - var allInterfaces = targetType.GetAllInterfacesOrEffectiveInterfaces(); - var ienumerableType = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T); - NamedTypeSymbol? singleIEnumerableImplementation = null; - foreach (var @interface in allInterfaces) - { - if (ReferenceEquals(@interface.OriginalDefinition, ienumerableType)) - { - if (singleIEnumerableImplementation is not null) - { - return null; - } - - singleIEnumerableImplementation = @interface; - } - } - - return singleIEnumerableImplementation; - } } private MethodSymbol? GetCollectionBuilderMethod( diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/CollectionExpressionTypeKind.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/CollectionExpressionTypeKind.cs index ee9b8e7283ac3..40d70499e1f38 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/CollectionExpressionTypeKind.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/CollectionExpressionTypeKind.cs @@ -11,7 +11,6 @@ internal enum CollectionExpressionTypeKind Span, ReadOnlySpan, CollectionBuilder, - ImplementsIEnumerableT, ImplementsIEnumerable, ArrayInterface, } diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs index 8ffd7b169c75f..cbae2e9f7df79 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs @@ -106,18 +106,20 @@ internal DeconstructionUncommonData(DeconstructMethodInfo deconstructMethodInfoO private sealed class CollectionExpressionUncommonData : NestedUncommonData { - internal CollectionExpressionUncommonData(CollectionExpressionTypeKind collectionExpressionTypeKind, TypeSymbol? elementType, ImmutableArray elementConversions) : + internal CollectionExpressionUncommonData(CollectionExpressionTypeKind collectionExpressionTypeKind, TypeSymbol elementType, ImmutableArray elementConversions) : base(elementConversions) { + Debug.Assert(collectionExpressionTypeKind != CollectionExpressionTypeKind.None); + Debug.Assert(elementType is { }); CollectionExpressionTypeKind = collectionExpressionTypeKind; ElementType = elementType; } internal readonly CollectionExpressionTypeKind CollectionExpressionTypeKind; - internal readonly TypeSymbol? ElementType; + internal readonly TypeSymbol ElementType; } - internal static Conversion CreateCollectionExpressionConversion(CollectionExpressionTypeKind collectionExpressionTypeKind, TypeSymbol? elementType, ImmutableArray elementConversions) + internal static Conversion CreateCollectionExpressionConversion(CollectionExpressionTypeKind collectionExpressionTypeKind, TypeSymbol elementType, ImmutableArray elementConversions) { return new Conversion( ConversionKind.CollectionExpression, diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs index 9a78f04f0200c..2e0286cc994a5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs @@ -168,6 +168,7 @@ protected override Conversion GetCollectionExpressionConversion( case CollectionExpressionTypeKind.None: return Conversion.NoConversion; + case CollectionExpressionTypeKind.ImplementsIEnumerable: case CollectionExpressionTypeKind.CollectionBuilder: { _binder.TryGetCollectionIterationType((Syntax.ExpressionSyntax)syntax, targetType, out elementTypeWithAnnotations); @@ -180,31 +181,9 @@ protected override Conversion GetCollectionExpressionConversion( break; } - var elements = node.Elements; - if (collectionTypeKind == CollectionExpressionTypeKind.ImplementsIEnumerable) - { - return Conversion.CreateCollectionExpressionConversion(collectionTypeKind, elementType: null, default); - } - else if (collectionTypeKind == CollectionExpressionTypeKind.ImplementsIEnumerableT) - { - var allInterfaces = targetType.GetAllInterfacesOrEffectiveInterfaces(); - var ienumerableType = this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T); - bool isCompatible = false; - foreach (var @interface in allInterfaces) - { - if (isCompatibleIEnumerableT(@interface, ienumerableType, elements, ref useSiteInfo)) - { - isCompatible = true; - // Don't break so we collect all remaining use-site information - } - } - - return isCompatible - ? Conversion.CreateCollectionExpressionConversion(collectionTypeKind, elementType: null, default) - : Conversion.NoConversion; - } - Debug.Assert(elementType is { }); + + var elements = node.Elements; var builder = ArrayBuilder.GetInstance(elements.Length); foreach (var element in elements) { @@ -220,33 +199,6 @@ protected override Conversion GetCollectionExpressionConversion( return Conversion.CreateCollectionExpressionConversion(collectionTypeKind, elementType, builder.ToImmutableAndFree()); - bool isCompatibleIEnumerableT(NamedTypeSymbol targetInterface, NamedTypeSymbol ienumerableType, - ImmutableArray elements, ref CompoundUseSiteInfo useSiteInfo) - { - Debug.Assert(ienumerableType.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T); - if (!ReferenceEquals(targetInterface.OriginalDefinition, ienumerableType)) - { - return false; - } - - var targetElementType = targetInterface.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; - return elementsCanAllConvert(elements, targetElementType.Type, ref useSiteInfo); - } - - bool elementsCanAllConvert(ImmutableArray elements, TypeSymbol elementType, ref CompoundUseSiteInfo useSiteInfo) - { - foreach (var element in elements) - { - Conversion elementConversion = convertElement(element, elementType, ref useSiteInfo); - if (!elementConversion.Exists) - { - return false; - } - } - - return true; - } - Conversion convertElement(BoundNode element, TypeSymbol elementType, ref CompoundUseSiteInfo useSiteInfo) { return element switch diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 76cb56ae935a2..bc642f9dbed35 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -1650,11 +1650,6 @@ internal static CollectionExpressionTypeKind GetCollectionExpressionTypeKind(CSh { return CollectionExpressionTypeKind.CollectionBuilder; } - else if (implementsSpecialInterface(compilation, destination, SpecialType.System_Collections_Generic_IEnumerable_T)) - { - elementType = default; - return CollectionExpressionTypeKind.ImplementsIEnumerableT; - } else if (implementsSpecialInterface(compilation, destination, SpecialType.System_Collections_IEnumerable)) { // ^ This implementation differs from Binder.CollectionInitializerTypeImplementsIEnumerable(). diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 18e1aed8fc22c..93093f92a9b20 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6856,6 +6856,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' has a CollectionBuilderAttribute but no element type. + + Collection expression target '{0}' has no element type. + The CollectionBuilderAttribute builder type must be a non-generic class or struct. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 94377e47d7af2..e3e945e05b48e 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2281,6 +2281,7 @@ internal enum ErrorCode ERR_InvalidExperimentalDiagID = 9211, ERR_SpreadMissingMember = 9212, + ERR_CollectionExpressionTargetNoElementType = 9213, #endregion diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 628c1fbb22ed8..a40daa23293fa 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2410,6 +2410,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code) case ErrorCode.ERR_CollectionExpressionImmutableArray: case ErrorCode.ERR_InvalidExperimentalDiagID: case ErrorCode.ERR_SpreadMissingMember: + case ErrorCode.ERR_CollectionExpressionTargetNoElementType: return false; default: // NOTE: All error codes must be explicitly handled in this switch statement diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs index 48ffb8ec50e7d..1bc4a5f770fd1 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs @@ -38,8 +38,6 @@ private BoundExpression RewriteCollectionExpressionConversion(Conversion convers switch (collectionTypeKind) { case CollectionExpressionTypeKind.ImplementsIEnumerable: - return VisitCollectionInitializerCollectionExpression(node, node.Type); - case CollectionExpressionTypeKind.ImplementsIEnumerableT: if (useListOptimization(_compilation, node, out var listElementType)) { return CreateAndPopulateList(node, listElementType, node.Elements.SelectAsArray(static (element, node) => unwrapListElement(node, element), node)); @@ -1082,8 +1080,6 @@ private BoundExpression GetKnownLengthExpression(ImmutableArray eleme for (int i = 0; i < numberIncludingLastSpread; i++) { var element = elements[i]; - var rewrittenExpression = rewrittenExpressions[i]; - if (element is BoundCollectionExpressionSpreadElement spreadElement) { var collectionPlaceholder = spreadElement.ExpressionPlaceholder; diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 16c5e20b49980..beb9c8077076f 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -1246,7 +1246,6 @@ private ICollectionExpressionOperation CreateBoundCollectionExpression(BoundColl case CollectionExpressionTypeKind.Span: return null; case CollectionExpressionTypeKind.ImplementsIEnumerable: - case CollectionExpressionTypeKind.ImplementsIEnumerableT: return (expr.CollectionCreation as BoundObjectCreationExpression)?.Constructor; case CollectionExpressionTypeKind.CollectionBuilder: return expr.CollectionBuilderMethod; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index c3f554f0bded6..240fe2b351e65 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index fdb74b60acfc9..d0817c17f3183 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 59ed9fd0bbe41..0d4ff8080e772 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 6751262cf343f..b10c7f7c26029 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 79ba0e07f9afe..98b232aabc958 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 6db000ac34445..822c0095ea75a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 2e5ea831e66b5..a9e2b312efb71 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 0ae45f0139585..386d274db47af 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 77c3a0ef278e4..6b0fc279fd701 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 7ef5812cc6ba2..9ca32982c8ac4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -437,6 +437,11 @@ Отсутствует целевой тип для выражения коллекции. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Не удается инициализировать '{0}' с выражением коллекции, так как тип не является конструкторируемым. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index ef4e8f312bed7..d66953dd93cef 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index c15c75a1075a9..12b13ef6c50e3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index f283996903380..cd2428ed9b358 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -437,6 +437,11 @@ There is no target type for the collection expression. + + Collection expression target '{0}' has no element type. + Collection expression target '{0}' has no element type. + + Cannot initialize type '{0}' with a collection expression because the type is not constructible. Cannot initialize type '{0}' with a collection expression because the type is not constructible. diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs index 7e7cb9deb95b4..41b09756e3b9c 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs @@ -4818,7 +4818,7 @@ unsafe static void Main() } [Fact] - public void PointerType_05() + public void PointerType_05A() { string source = """ using System.Collections; @@ -4839,6 +4839,52 @@ unsafe static void Main() } } """; + var comp = CreateCompilation(new[] { source, s_collectionExtensions }, options: TestOptions.UnsafeReleaseExe, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // 0.cs(14,22): error CS0029: Cannot implicitly convert type 'void*' to 'object' + // C c = [null, p]; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "p").WithArguments("void*", "object").WithLocation(14, 22)); + } + + [Fact] + public void PointerType_05B() + { + string source = """ + using System.Collections; + using System.Collections.Generic; + class C : IEnumerable + { + private List _list = new List(); + unsafe public void Add(void* p) { _list.Add((nint)p); } + public Enumerator GetEnumerator() => new Enumerator(_list); + IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); + } + class Enumerator + { + private readonly List _list; + private int _index; + public Enumerator(List list) + { + _list = list; + _index = -1; + } + public bool MoveNext() + { + if (_index < _list.Count) _index++; + return _index < _list.Count; + } + public unsafe void* Current => (void*)_list[_index]; + } + class Program + { + unsafe static void Main() + { + void* p = (void*)2; + C c = [null, p]; + c.Report(); + } + } + """; CompileAndVerify(new[] { source, s_collectionExtensions }, options: TestOptions.UnsafeReleaseExe, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[0, 2], ")); } @@ -5744,7 +5790,7 @@ static void Main() [Fact] public void CollectionInitializerType_17() { - string source = """ + string sourceA = """ using System.Collections; using System.Collections.Generic; class C : IEnumerable @@ -5753,50 +5799,57 @@ class C : IEnumerable public void Add(params T[] args) { _list.AddRange(args); } IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } + """; + + string sourceB1 = """ + class Program + { + static void Main() + { + C c = [[], [1, 2]]; + c.Report(); + } + } + """; + var comp = CreateCompilation(new[] { sourceA, sourceB1, s_collectionExtensions }); + comp.VerifyEmitDiagnostics( + // 1.cs(5,21): error CS9174: Cannot initialize type 'object' with a collection expression because the type is not constructible. + // C c = [[], [1, 2]]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetTypeNotConstructible, "[]").WithArguments("object").WithLocation(5, 21), + // 1.cs(5,25): error CS9174: Cannot initialize type 'object' with a collection expression because the type is not constructible. + // C c = [[], [1, 2]]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetTypeNotConstructible, "[1, 2]").WithArguments("object").WithLocation(5, 25)); + + string sourceB2 = """ class Program { static void Main() { - C c = [[], [1, 2], 3]; + C c = [3]; c.Report(); } } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: "[1, 2, 3], "); + var verifier = CompileAndVerify(new[] { sourceA, sourceB2, s_collectionExtensions }, expectedOutput: "[3], "); verifier.VerifyIL("Program.Main", """ { - // Code size 61 (0x3d) + // Code size 30 (0x1e) .maxstack 5 .locals init (C V_0) IL_0000: newobj "C..ctor()" IL_0005: stloc.0 IL_0006: ldloc.0 - IL_0007: call "int[] System.Array.Empty()" - IL_000c: callvirt "void C.Add(params int[])" - IL_0011: ldloc.0 - IL_0012: ldc.i4.2 - IL_0013: newarr "int" - IL_0018: dup - IL_0019: ldc.i4.0 - IL_001a: ldc.i4.1 - IL_001b: stelem.i4 - IL_001c: dup - IL_001d: ldc.i4.1 - IL_001e: ldc.i4.2 - IL_001f: stelem.i4 - IL_0020: callvirt "void C.Add(params int[])" - IL_0025: ldloc.0 - IL_0026: ldc.i4.1 - IL_0027: newarr "int" - IL_002c: dup - IL_002d: ldc.i4.0 - IL_002e: ldc.i4.3 - IL_002f: stelem.i4 - IL_0030: callvirt "void C.Add(params int[])" - IL_0035: ldloc.0 - IL_0036: ldc.i4.0 - IL_0037: call "void CollectionExtensions.Report(object, bool)" - IL_003c: ret + IL_0007: ldc.i4.1 + IL_0008: newarr "int" + IL_000d: dup + IL_000e: ldc.i4.0 + IL_000f: ldc.i4.3 + IL_0010: stelem.i4 + IL_0011: callvirt "void C.Add(params int[])" + IL_0016: ldloc.0 + IL_0017: ldc.i4.0 + IL_0018: call "void CollectionExtensions.Report(object, bool)" + IL_001d: ret } """); } @@ -6254,6 +6307,416 @@ static MyCollection Create(int x, int[] y) """); } + [Fact] + public void CollectionInitializerType_GetEnumeratorPattern_Generic() + { + string sourceA = """ + using System.Collections; + using System.Collections.Generic; + class MyCollection : IEnumerable + { + private List _list = new(); + public void Add(string s) { _list.Add(s); } + public void Add(int i) { throw null; } + public IEnumerator GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + """; + + string sourceB1 = """ + using System; + class Program + { + static void Main() + { + MyCollection x = ["1", null]; + MyCollection y = [..x, "3"]; + foreach (var i in y) + Console.Write("{0}, ", i ?? "null"); + } + } + """; + CompileAndVerify(new[] { sourceA, sourceB1 }, expectedOutput: "1, null, 3, "); + + string sourceB2 = """ + class Program + { + static void Main() + { + MyCollection x = [1, default]; + MyCollection y = [..x, 3]; + } + } + """; + var comp = CreateCompilation(new[] { sourceA, sourceB2 }); + comp.VerifyEmitDiagnostics( + // 1.cs(5,27): error CS0029: Cannot implicitly convert type 'int' to 'string' + // MyCollection x = [1, default]; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(5, 27), + // 1.cs(6,32): error CS0029: Cannot implicitly convert type 'int' to 'string' + // MyCollection y = [..x, 3]; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "3").WithArguments("int", "string").WithLocation(6, 32)); + } + + [Fact] + public void CollectionInitializerType_GetEnumeratorPattern_NonGeneric() + { + string sourceA = """ + using System.Collections; + using System.Collections.Generic; + class MyCollection : IEnumerable + { + private List _list = new(); + public void Add(string s) { _list.Add(s); } + public void Add(int i) { throw null; } + public IEnumerator GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + """; + + string sourceB1 = """ + using System; + class Program + { + static void Main() + { + MyCollection x = ["1", null]; + MyCollection y = [..x, "3"]; + foreach (var i in y) + Console.Write("{0}, ", i ?? "null"); + } + } + """; + CompileAndVerify(new[] { sourceA, sourceB1 }, expectedOutput: "1, null, 3, "); + + string sourceB2 = """ + class Program + { + static void Main() + { + MyCollection x = [1, default]; + MyCollection y = [..x, 3]; + } + } + """; + var comp = CreateCompilation(new[] { sourceA, sourceB2 }); + comp.VerifyEmitDiagnostics( + // 1.cs(5,27): error CS0029: Cannot implicitly convert type 'int' to 'string' + // MyCollection x = [1, default]; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(5, 27), + // 1.cs(6,32): error CS0029: Cannot implicitly convert type 'int' to 'string' + // MyCollection y = [..x, 3]; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "3").WithArguments("int", "string").WithLocation(6, 32)); + } + + [Fact] + public void CollectionInitializerType_GetEnumeratorPattern_NoImplementations() + { + string sourceA = """ + using System.Collections; + using System.Collections.Generic; + class MyCollection + { + private List _list = new(); + public void Add(string s) { _list.Add(s); } + public IEnumerator GetEnumerator() => _list.GetEnumerator(); + } + """; + + string sourceB1 = """ + using System; + class Program + { + static void Main() + { + MyCollection c = new(); + c.Add("1"); + c.Add(default); + foreach (var i in c) + Console.Write("{0}, ", i ?? "null"); + } + } + """; + CompileAndVerify(new[] { sourceA, sourceB1 }, expectedOutput: "1, null, "); + + string sourceB2 = """ + class Program + { + static void Main() + { + MyCollection x = ["1", default]; + MyCollection y = [..x]; + } + } + """; + var comp = CreateCompilation(new[] { sourceA, sourceB2 }); + comp.VerifyEmitDiagnostics( + // 1.cs(5,26): error CS9174: Cannot initialize type 'MyCollection' with a collection expression because the type is not constructible. + // MyCollection x = ["1", default]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetTypeNotConstructible, @"[""1"", default]").WithArguments("MyCollection").WithLocation(5, 26), + // 1.cs(6,26): error CS9174: Cannot initialize type 'MyCollection' with a collection expression because the type is not constructible. + // MyCollection y = [..x]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetTypeNotConstructible, "[..x]").WithArguments("MyCollection").WithLocation(6, 26)); + } + + [Fact] + public void CollectionInitializerType_GetEnumeratorPattern_RefStruct_Generic() + { + string sourceA = """ + using System.Collections; + using System.Collections.Generic; + ref struct R + { + public R(object value) { Value = value; } + public readonly object Value; + } + class MyCollection : IEnumerable + { + private List _list = new(); + public void Add(R r) { _list.Add(r.Value); } + public MyEnumerator GetEnumerator() => new MyEnumerator(_list); + IEnumerator IEnumerable.GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + class MyEnumerator + { + private List _list; + private int _index = -1; + public MyEnumerator(List list) { _list = list; } + public bool MoveNext() + { + if (_index < _list.Count) _index++; + return _index < _list.Count; + } + public R Current => new R(_list[_index]); + } + """; + + string sourceB = """ + using System; + class Program + { + static void Main() + { + MyCollection x = [new R(1)]; + MyCollection y = [..x, new R(2)]; + foreach (var i in y) + Console.Write("{0}, ", i.Value); + } + } + """; + CompileAndVerify(new[] { sourceA, sourceB }, verify: Verification.FailsILVerify, expectedOutput: "1, 2, "); + } + + [Fact] + public void CollectionInitializerType_GetEnumeratorPattern_RefStruct_NonGeneric() + { + string sourceA = """ + using System.Collections; + using System.Collections.Generic; + ref struct R + { + public R(object value) { Value = value; } + public readonly object Value; + } + class MyCollection : IEnumerable + { + private List _list = new(); + public void Add(R r) { _list.Add(r.Value); } + public MyEnumerator GetEnumerator() => new MyEnumerator(_list); + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + class MyEnumerator + { + private List _list; + private int _index = -1; + public MyEnumerator(List list) { _list = list; } + public bool MoveNext() + { + if (_index < _list.Count) _index++; + return _index < _list.Count; + } + public R Current => new R(_list[_index]); + } + """; + + string sourceB = """ + using System; + class Program + { + static void Main() + { + MyCollection x = [new R(1)]; + MyCollection y = [..x, new R(2)]; + foreach (var i in y) + Console.Write("{0}, ", i.Value); + } + } + """; + CompileAndVerify(new[] { sourceA, sourceB }, verify: Verification.FailsILVerify, expectedOutput: "1, 2, "); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/71387")] + [Fact] + public void CollectionInitializerType_MultipleIEnumerableTImplementations_01() + { + string sourceA = """ + using System.Collections; + using System.Collections.Generic; + class MyCollection : IEnumerable, IEnumerable + { + private List _list = new(); + public void Add(string s) { _list.Add(s); } + IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); + } + """; + + string sourceB1 = """ + class Program + { + static void Main() + { + foreach (var i in new MyCollection()) { } + } + } + """; + var comp = CreateCompilation(new[] { sourceA, sourceB1 }); + comp.VerifyEmitDiagnostics( + // 1.cs(5,27): error CS1640: foreach statement cannot operate on variables of type 'MyCollection' because it implements multiple instantiations of 'IEnumerable'; try casting to a specific interface instantiation + // foreach (var i in new MyCollection()) { } + Diagnostic(ErrorCode.ERR_MultipleIEnumOfT, "new MyCollection()").WithArguments("MyCollection", "System.Collections.Generic.IEnumerable").WithLocation(5, 27)); + + string sourceB2 = """ + class Program + { + static void Main() + { + MyCollection c; + c = []; + c = ["1"]; + c = [2]; + } + } + """; + comp = CreateCompilation(new[] { sourceA, sourceB2 }); + comp.VerifyEmitDiagnostics( + // 1.cs(6,13): error CS9213: Collection expression target 'MyCollection' has no element type. + // c = []; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, "[]").WithArguments("MyCollection").WithLocation(6, 13), + // 1.cs(7,13): error CS9213: Collection expression target 'MyCollection' has no element type. + // c = ["1"]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, @"[""1""]").WithArguments("MyCollection").WithLocation(7, 13), + // 1.cs(8,13): error CS9213: Collection expression target 'MyCollection' has no element type. + // c = [2]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, "[2]").WithArguments("MyCollection").WithLocation(8, 13)); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/71387")] + [Fact] + public void CollectionInitializerType_MultipleIEnumerableTImplementations_02() + { + string sourceA = """ + using System.Collections; + using System.Collections.Generic; + abstract class MyCollectionBase : IEnumerable + { + public List _list = new(); + public void Add(T t) { _list.Add(t); } + IEnumerator IEnumerable.GetEnumerator() + { + foreach (var i in _list) yield return (T)i; + } + IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); + } + class MyCollection : MyCollectionBase, IEnumerable + { + public void Add(U u) { _list.Add(u); } + IEnumerator IEnumerable.GetEnumerator() + { + foreach (var i in _list) yield return (U)i; + } + } + """; + + string sourceB1 = """ + class Program + { + static void Main() + { + foreach (var i in new MyCollection()) { } + foreach (var i in new MyCollection()) { } + } + static void F() + { + foreach (var i in new MyCollection()) { } + } + } + """; + var comp = CreateCompilation(new[] { sourceA, sourceB1 }); + comp.VerifyEmitDiagnostics( + // 1.cs(5,27): error CS1640: foreach statement cannot operate on variables of type 'MyCollection' because it implements multiple instantiations of 'IEnumerable'; try casting to a specific interface instantiation + // foreach (var i in new MyCollection()) { } + Diagnostic(ErrorCode.ERR_MultipleIEnumOfT, "new MyCollection()").WithArguments("MyCollection", "System.Collections.Generic.IEnumerable").WithLocation(5, 27), + // 1.cs(6,27): error CS1640: foreach statement cannot operate on variables of type 'MyCollection' because it implements multiple instantiations of 'IEnumerable'; try casting to a specific interface instantiation + // foreach (var i in new MyCollection()) { } + Diagnostic(ErrorCode.ERR_MultipleIEnumOfT, "new MyCollection()").WithArguments("MyCollection", "System.Collections.Generic.IEnumerable").WithLocation(6, 27), + // 1.cs(10,27): error CS1640: foreach statement cannot operate on variables of type 'MyCollection' because it implements multiple instantiations of 'IEnumerable'; try casting to a specific interface instantiation + // foreach (var i in new MyCollection()) { } + Diagnostic(ErrorCode.ERR_MultipleIEnumOfT, "new MyCollection()").WithArguments("MyCollection", "System.Collections.Generic.IEnumerable").WithLocation(10, 27)); + + string sourceB2 = """ + class Program + { + static void Main() + { + Create([]); + Create([2]); + } + static void F(T t) + { + Create([t]); + } + static void Create(MyCollection c) + { + } + } + """; + comp = CreateCompilation(new[] { sourceA, sourceB2 }); + comp.VerifyEmitDiagnostics( + // 1.cs(5,32): error CS1503: Argument 1: cannot convert from 'collection expressions' to 'MyCollection' + // Create([]); + Diagnostic(ErrorCode.ERR_BadArgType, "[]").WithArguments("1", "collection expressions", "MyCollection").WithLocation(5, 32), + // 1.cs(6,29): error CS1503: Argument 1: cannot convert from 'collection expressions' to 'MyCollection' + // Create([2]); + Diagnostic(ErrorCode.ERR_BadArgType, "[2]").WithArguments("1", "collection expressions", "MyCollection").WithLocation(6, 29), + // 1.cs(10,22): error CS1503: Argument 1: cannot convert from 'collection expressions' to 'MyCollection' + // Create([t]); + Diagnostic(ErrorCode.ERR_BadArgType, "[t]").WithArguments("1", "collection expressions", "MyCollection").WithLocation(10, 22)); + + string sourceB3 = """ + class Program + { + static void Main() + { + Create([3]); + F(4); + } + static void F(T t) + { + Create([t]); + } + static void Create(MyCollection c) + { + c.Report(); + } + } + """; + CompileAndVerify(new[] { sourceA, sourceB3, s_collectionExtensions }, expectedOutput: "[3], [4], "); + } + [Theory] [InlineData("class")] [InlineData("struct")] @@ -11425,7 +11888,7 @@ public void OrderOfEvaluation() using System; using System.Collections; using System.Collections.Generic; - class C : IEnumerable + class C : IEnumerable { private List _list = new List(); public void Add(T t) @@ -11433,7 +11896,8 @@ public void Add(T t) Console.WriteLine("Add {0}", t); _list.Add(t); } - IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => throw null; } class Program { @@ -18370,11 +18834,29 @@ class C : IEnumerable { private List _list = new List(); public void Add(R r) { _list.Add(r._i); } + public Enumerator GetEnumerator() => new Enumerator(_list); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } + class Enumerator + { + private readonly List _list; + private int _index; + public Enumerator(List list) + { + _list = list; + _index = -1; + } + public bool MoveNext() + { + if (_index < _list.Count) _index++; + return _index < _list.Count; + } + public R Current => new R(_list[_index]); + } ref struct R { public int _i; + public R(int i) { _i = i; } public R(ref int i) { _i = i; } } class Program @@ -18387,7 +18869,7 @@ static void Main() } } """; - CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: "[0, 1], "); + CompileAndVerify(new[] { source, s_collectionExtensions }, verify: Verification.Skipped, expectedOutput: "[0, 1], "); } [CombinatorialData] @@ -23560,7 +24042,7 @@ public XAttribute(int[] values) { } } """; - var comp = CreateCompilation(source).VerifyEmitDiagnostics( + CreateCompilation(source).VerifyEmitDiagnostics( // (1,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [X([1, 2, C.M()])] Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M()").WithLocation(1, 11) @@ -24473,7 +24955,7 @@ static void Main() } """; - var comp = CreateCompilation(source).VerifyEmitDiagnostics( + CreateCompilation(source).VerifyEmitDiagnostics( // (27,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(AbstractCollection)' and 'Program.F(NoConstructorCollection)' // F([]); Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(AbstractCollection)", "Program.F(NoConstructorCollection)").WithLocation(27, 9) @@ -24822,8 +25304,10 @@ class Collection : {{interfaces}} } """; - var comp = CreateCompilation(source).VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "RAN"); + CreateCompilation(source).VerifyEmitDiagnostics( + // (4,16): error CS9213: Collection expression target 'Collection' has no element type. + // Collection c = [1]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, "[1]").WithArguments("Collection").WithLocation(4, 16)); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69521")] @@ -24853,8 +25337,10 @@ class Collection : {{interfaces}} } """; - var comp = CreateCompilation(source).VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "RAN"); + CreateCompilation(source).VerifyEmitDiagnostics( + // (4,16): error CS9213: Collection expression target 'Collection' has no element type. + // Collection c = [1]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, "[1]").WithArguments("Collection").WithLocation(4, 16)); } [Theory] @@ -24880,9 +25366,9 @@ public void GenericIEnumerable_MultipleInvalid(string typeKind) """; CreateCompilation(source).VerifyEmitDiagnostics( - // (4,16): error CS9174: Cannot initialize type 'Collection' with a collection expression because the type is not constructible. + // (4,16): error CS9213: Collection expression target 'Collection' has no element type. // Collection c = ["hi"]; - Diagnostic(ErrorCode.ERR_CollectionExpressionTargetTypeNotConstructible, @"[""hi""]").WithArguments("Collection").WithLocation(4, 16) + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, @"[""hi""]").WithArguments("Collection").WithLocation(4, 16) ); } @@ -24972,6 +25458,34 @@ class Collection : IEnumerable, IEnumerable } """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (4,16): error CS9213: Collection expression target 'Collection' has no element type. + // Collection c = [new C()]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, "[new C()]").WithArguments("Collection").WithLocation(4, 16)); + } + + [Fact] + public void NonGenericIEnumerable_TwoCompatibleInterfaces() + { + string source = """ + using System.Collections; + using System.Collections.Generic; + + Collection c = [new C()]; + + interface I1 { } + interface I2 { } + + class C : I1, I2 { } + + class Collection : IEnumerable + { + IEnumerator IEnumerable.GetEnumerator() => null; + public void Add(I1 i) => throw null; + public void Add(I2 i) => throw null; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( // (4,17): error CS0121: The call is ambiguous between the following methods or properties: 'Collection.Add(I1)' and 'Collection.Add(I2)' // Collection c = [new C()]; @@ -25005,8 +25519,10 @@ class Collection : IEnumerable, IEnumerable } """; - var comp = CreateCompilation(source).VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: IncludeExpectedOutput("RAN")); + CreateCompilation(source).VerifyEmitDiagnostics( + // (4,16): error CS9213: Collection expression target 'Collection' has no element type. + // Collection c = [new C()]; + Diagnostic(ErrorCode.ERR_CollectionExpressionTargetNoElementType, "[new C()]").WithArguments("Collection").WithLocation(4, 16)); } [Fact] @@ -25451,7 +25967,7 @@ static void Main() Diagnostic(ErrorCode.ERR_CollectionExpressionImmutableArray, "[1, 2, 3]").WithArguments("System.Collections.Immutable.ImmutableArray").WithLocation(7, 35)); var collectionType = comp.GetWellKnownType(WellKnownType.System_Collections_Immutable_ImmutableArray_T).Construct(comp.GetSpecialType(SpecialType.System_Int32)); - Assert.Equal(CollectionExpressionTypeKind.ImplementsIEnumerableT, ConversionsBase.GetCollectionExpressionTypeKind(comp, collectionType, out _)); + Assert.Equal(CollectionExpressionTypeKind.ImplementsIEnumerable, ConversionsBase.GetCollectionExpressionTypeKind(comp, collectionType, out _)); // ImmutableCollectionsMarshal.AsImmutableArray is not sufficient to optimize collection expressions // targeting ImmutableArray. ImmutableArray must also have a [CollectionBuilder] attribute. @@ -25475,7 +25991,7 @@ public static class ImmutableCollectionsMarshal Diagnostic(ErrorCode.ERR_CollectionExpressionImmutableArray, "[1, 2, 3]").WithArguments("System.Collections.Immutable.ImmutableArray").WithLocation(7, 35)); collectionType = comp.GetWellKnownType(WellKnownType.System_Collections_Immutable_ImmutableArray_T).Construct(comp.GetSpecialType(SpecialType.System_Int32)); - Assert.Equal(CollectionExpressionTypeKind.ImplementsIEnumerableT, ConversionsBase.GetCollectionExpressionTypeKind(comp, collectionType, out _)); + Assert.Equal(CollectionExpressionTypeKind.ImplementsIEnumerable, ConversionsBase.GetCollectionExpressionTypeKind(comp, collectionType, out _)); } [Fact] @@ -25850,7 +26366,13 @@ public void RefStruct_ImplementsIEnumerable() ref struct S : IEnumerable { public void Add(params S[] x) => throw null; - public IEnumerator GetEnumerator() => throw null; + public Enumerator GetEnumerator() => new Enumerator(); + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + class Enumerator + { + public bool MoveNext() => false; + public S Current => default; } class Program { @@ -25865,9 +26387,9 @@ class Program // (4,28): error CS0611: Array elements cannot be of type 'S' // public void Add(params S[] x) => throw null; Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "S").WithArguments("S").WithLocation(4, 28), - // (9,21): error CS9203: A collection expression of type 'S' cannot be used in this context because it may be exposed outside of the current scope. + // (15,21): error CS9203: A collection expression of type 'S' cannot be used in this context because it may be exposed outside of the current scope. // static S F() => [[]]; - Diagnostic(ErrorCode.ERR_CollectionExpressionEscape, "[[]]").WithArguments("S").WithLocation(9, 21)); + Diagnostic(ErrorCode.ERR_CollectionExpressionEscape, "[[]]").WithArguments("S").WithLocation(15, 21)); } [WorkItem("https://github.com/dotnet/roslyn/issues/70638")] @@ -26884,7 +27406,7 @@ public void Add(MyCollection c) } - public IEnumerator GetEnumerator() => throw new NotImplementedException(); + public IEnumerator GetEnumerator() => throw new NotImplementedException(); IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); } @@ -26921,7 +27443,7 @@ public void Add(MyCollection c) } - public IEnumerator GetEnumerator() => throw new NotImplementedException(); + public IEnumerator GetEnumerator() => throw new NotImplementedException(); IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); }