diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index b61abacd57cd1..b0e9658085aa5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -2989,11 +2989,21 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint { case BoundKind.DefaultLiteral: case BoundKind.DefaultExpression: - case BoundKind.Parameter: case BoundKind.ThisReference: // always returnable return true; + case BoundKind.Parameter: + var parameter = ((BoundParameter)expr).ParameterSymbol; + // params Span value cannot be returned since that would + // prevent sharing repeated allocations at the call-site. + if (parameter.IsParams && !parameter.Type.IsSZArray()) + { + Error(diagnostics, ErrorCode.ERR_EscapeParamsSpan, node, expr.Syntax); + return false; + } + return true; + case BoundKind.TupleLiteral: case BoundKind.ConvertedTupleLiteral: var tupleLiteral = (BoundTupleExpression)expr; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index a11f9e07bb228..02e74b5492ca4 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -3079,7 +3079,7 @@ private static TypeWithAnnotations GetCorrespondingParameterTypeWithAnnotations( if (paramNum == parameters.Length - 1 && result.Kind == MemberResolutionKind.ApplicableInExpandedForm) { - type = ((ArrayTypeSymbol)type.Type).ElementTypeWithAnnotations; + type = type.Type.GetParamsElementType(); } return type; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index 05a1304c219ee..08302d706f0ae 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -1106,6 +1106,16 @@ private BoundCall BindInvocationExpressionContinued( gotError = ReportUnsafeIfNotAllowed(node, diagnostics) || gotError; } + if (expanded) + { + var parameter = method.Parameters[^1]; + Debug.Assert(parameter.IsParams); + if (!parameter.Type.IsSZArray() && !CheckFeatureAvailability(node, MessageID.IDS_FeatureParamsSpan, diagnostics)) + { + gotError = true; + } + } + bool hasBaseReceiver = receiver != null && receiver.Kind == BoundKind.BaseReference; ReportDiagnosticsIfObsolete(diagnostics, method, node, hasBaseReceiver); diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index be0401ed762a0..7c70a52026145 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -1008,7 +1008,7 @@ private static bool PreferExpandedFormOverNormalForm(MemberAnalysisResult normal // We need to know if this is a valid formal parameter list with a parameter array // as the final formal parameter. We might be in an error recovery scenario // where the params array is not an array type. - public static bool IsValidParams(Symbol member) + public bool IsValidParams(Symbol member) { // A varargs method is never a valid params method. if (member.GetIsVararg()) @@ -1026,10 +1026,10 @@ public static bool IsValidParams(Symbol member) return IsValidParamsParameter(final); } - public static bool IsValidParamsParameter(ParameterSymbol final) + public bool IsValidParamsParameter(ParameterSymbol final) { Debug.Assert((object)final == final.ContainingSymbol.GetParameters().Last()); - return final.IsParams && ((ParameterSymbol)final.OriginalDefinition).Type.IsSZArray(); + return final.IsParams && final.Type.IsParamsType(Compilation); } /// @@ -1638,9 +1638,9 @@ private TypeSymbol GetParameterType(ParameterSymbol parameter, MemberAnalysisRes { var type = parameter.Type; if (result.Kind == MemberResolutionKind.ApplicableInExpandedForm && - parameter.IsParams && type.IsSZArray()) + parameter.IsParams && type.IsParamsType(Compilation)) { - return ((ArrayTypeSymbol)type).ElementType; + return type.GetParamsElementType().Type; } else { @@ -2036,11 +2036,29 @@ private BetterResult BetterFunctionMember( // NB: OriginalDefinition, not ConstructedFrom. Substitutions into containing symbols // must also be ignored for this tie-breaker. + var m1Original = m1.LeastOverriddenMember.OriginalDefinition.GetParameters(); + var m2Original = m2.LeastOverriddenMember.OriginalDefinition.GetParameters(); + + // Prefer params Span or ReadOnlySpan over params T[]. + if (m1.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm && m2.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm) + { + var parameter1 = m1Original.Last(); + var parameter2 = m2Original.Last(); + + Debug.Assert(parameter1.IsParams); + Debug.Assert(parameter2.IsParams); + + switch (parameter1.Type.IsSZArray(), parameter2.Type.IsSZArray()) + { + case (false, true): + return BetterResult.Left; + case (true, false): + return BetterResult.Right; + } + } var uninst1 = ArrayBuilder.GetInstance(); var uninst2 = ArrayBuilder.GetInstance(); - var m1Original = m1.LeastOverriddenMember.OriginalDefinition.GetParameters(); - var m2Original = m2.LeastOverriddenMember.OriginalDefinition.GetParameters(); for (i = 0; i < arguments.Count; ++i) { // If these are both applicable varargs methods and we're looking at the __arglist argument @@ -3236,7 +3254,7 @@ private static EffectiveParameters GetEffectiveParametersInExpandedForm var parameter = parameters[parm]; var type = parameter.TypeWithAnnotations; - types.Add(parm == parameters.Length - 1 ? ((ArrayTypeSymbol)type.Type).ElementTypeWithAnnotations : type); + types.Add(parm == parameters.Length - 1 ? type.Type.GetParamsElementType() : type); var argRefKind = hasAnyRefArg ? argumentRefKinds[arg] : RefKind.None; var paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, isMethodGroupConversion, allowRefOmittedArguments, binder, ref hasAnyRefOmittedArgument); diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs index 41ce9c824011c..70a1c4b41ab46 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs @@ -55,7 +55,7 @@ public ImmutableArray ToImmutableArray() } } - private static ArgumentAnalysisResult AnalyzeArguments( + private ArgumentAnalysisResult AnalyzeArguments( Symbol symbol, AnalyzedArguments arguments, bool isMethodGroupConversion, diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index df67fbc6c2a40..6002a5409fce4 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5107,6 +5107,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A result of a stackalloc expression of type '{0}' cannot be used in this context because it may be exposed outside of the containing method + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot initialize a by-value variable with a reference @@ -6642,6 +6645,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ variance safety for static interface members + + params Span<T> + params Span<T> is not localizable + Record equality contract property '{0}' must have a get accessor. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 677bc3adf374a..275fe9b8db753 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2027,6 +2027,8 @@ internal enum ErrorCode ERR_NullCheckingOnOutParameter = 8994, WRN_NullCheckingOnNullableType = 8995, + ERR_EscapeParamsSpan = 8999, + #endregion // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 73accd97ff336..3013e4cc2be5d 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -243,6 +243,7 @@ internal enum MessageID IDS_ParameterNullChecking = MessageBase + 12815, IDS_FeatureCacheStaticMethodGroupConversion = MessageBase + 12816, + IDS_FeatureParamsSpan = MessageBase + 12817, } // Message IDs may refer to strings that need to be localized. @@ -358,6 +359,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureListPattern: // semantic check case MessageID.IDS_FeatureCacheStaticMethodGroupConversion: // lowering check case MessageID.IDS_ParameterNullChecking: // syntax check + case MessageID.IDS_FeatureParamsSpan: // semantic check return LanguageVersion.Preview; // C# 10.0 features. diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs index e5c7af97c517c..38138725e29a0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs @@ -644,7 +644,7 @@ private ImmutableArray MakeArguments( // Step two: If we have a params array, build the array and fill in the argument. if (expanded) { - actualArguments[actualArguments.Length - 1] = BuildParamsArray(syntax, methodOrIndexer, argsToParamsOpt, rewrittenArguments, parameters, actualArguments[actualArguments.Length - 1]); + actualArguments[actualArguments.Length - 1] = BuildParamsArray(syntax, argsToParamsOpt, rewrittenArguments, parameters, actualArguments[actualArguments.Length - 1]); } if (isComReceiver) @@ -1027,7 +1027,6 @@ private static bool IsBeginningOfParamArray( private BoundExpression BuildParamsArray( SyntaxNode syntax, - Symbol methodOrIndexer, ImmutableArray argsToParamsOpt, ImmutableArray rewrittenArguments, ImmutableArray parameters, @@ -1092,7 +1091,12 @@ private BoundExpression BuildParamsArray( } } - return CreateParamArrayArgument(syntax, paramArrayType, arrayArgs, _compilation, this); + if (paramArrayType.IsSZArray()) + { + return CreateParamArrayArgument(syntax, paramArrayType, arrayArgs, _compilation, this); + } + + return CreateParamsSpan(syntax, paramArrayType, arrayArgs); } private static BoundExpression CreateParamArrayArgument(SyntaxNode syntax, @@ -1101,7 +1105,6 @@ private static BoundExpression CreateParamArrayArgument(SyntaxNode syntax, CSharpCompilation compilation, LocalRewriter? localRewriter) { - TypeSymbol int32Type = compilation.GetSpecialType(SpecialType.System_Int32); BoundExpression arraySize = MakeLiteral(syntax, ConstantValue.Create(arrayArgs.Length), int32Type, localRewriter); @@ -1113,6 +1116,92 @@ private static BoundExpression CreateParamArrayArgument(SyntaxNode syntax, { WasCompilerGenerated = true }; } + private BoundExpression CreateParamsSpan( + SyntaxNode syntax, + TypeSymbol paramArrayType, + ImmutableArray arrayArgs) + { + var elementType = paramArrayType.GetParamsElementType().Type; + int length = arrayArgs.Length; + + // PROTOTYPE: If we actually allocate from the stack, it may be necessary to + // clear the execution stack before allocation. (See corresponding requirement + // for 'stackalloc' in LocalRewriter.VisitStackAllocArrayCreationBase().) + + // For now, simply allocate the array on the heap: new Span(new T[length]) + var intType = _compilation.GetSpecialType(SpecialType.System_Int32); + var array = new BoundArrayCreation( + syntax, + ImmutableArray.Create(MakeLiteral(syntax, ConstantValue.Create(length), intType, this)), + initializerOpt: null, + ArrayTypeSymbol.CreateSZArray(_compilation.SourceAssembly, TypeWithAnnotations.Create(elementType))) + { WasCompilerGenerated = true }; + + MethodSymbol spanConstructor; + MethodSymbol spanGetItem; + MethodSymbol? spanToReadOnlySpanOperator = null; + if (!TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Span_T__ctorArray, out spanConstructor) || + !TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Span_T__get_Item, out spanGetItem) || + // PROTOTYPE: To convert from Span to ReadOnlySpan, we're currently looking for + // 'static implicit operator ReadOnlySpan(Span span)' explicitly. Instead, should + // we use ConversionsBase.ClassifyImplicitConversionFromType() to find the conversion? + (paramArrayType.OriginalDefinition.Equals(_compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions) && + !TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Span_T__op_Implicit_SpanReadOnlySpan, out spanToReadOnlySpanOperator))) + { + return BadExpression(syntax, paramArrayType, ImmutableArray.Empty); + } + + var spanType = spanConstructor.ContainingType.Construct(elementType); + spanConstructor = spanConstructor.AsMember(spanType); + spanGetItem = spanGetItem.AsMember(spanType); + spanToReadOnlySpanOperator = spanToReadOnlySpanOperator?.AsMember(spanType); + + var sideEffects = ArrayBuilder.GetInstance(); + var span = _factory.New(spanConstructor, array); + var temp = _factory.StoreToTemp(span, out var assignment); + sideEffects.Add(assignment); + + // temp[0] = arrayArgs[0]; + // ... + // temp[n - 1] = arrayArgs[n - 1]; + // temp + for (int i = 0; i < arrayArgs.Length; i++) + { + assignment = _factory.AssignmentExpression( + _factory.Call(temp, spanGetItem, MakeLiteral(syntax, ConstantValue.Create(i), intType, this)), + _factory.Convert(elementType, arrayArgs[i])); + sideEffects.Add(assignment); + } + + BoundExpression expr = temp; + if (spanToReadOnlySpanOperator is { }) + { + // Convert Span to ReadOnlySpan. + expr = new BoundCall( + syntax, + receiverOpt: null, + method: spanToReadOnlySpanOperator, + arguments: ImmutableArray.Create(expr), + argumentNamesOpt: default, + argumentRefKindsOpt: default, + isDelegateCall: false, + expanded: false, + invokedAsExtensionMethod: false, + argsToParamsOpt: default, + defaultArguments: default, + resultKind: LookupResultKind.Viable, + type: spanToReadOnlySpanOperator.ReturnType); + } + + Debug.Assert(expr.Type is { }); + return new BoundSequence( + syntax, + locals: ImmutableArray.Create(temp.LocalSymbol), + sideEffects.ToImmutableAndFree(), + expr, + expr.Type); + } + /// /// To create literal expression for IOperation, set localRewriter to null. /// diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs index bff709c7b4ed9..bfa0a8e82d7c9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs @@ -356,7 +356,7 @@ private BoundIndexerAccess TransformIndexerAccess(BoundIndexerAccess indexerAcce // Step two: If we have a params array, build the array and fill in the argument. if (expanded) { - BoundExpression array = BuildParamsArray(syntax, indexer, argsToParamsOpt, rewrittenArguments, parameters, actualArguments[actualArguments.Length - 1]); + BoundExpression array = BuildParamsArray(syntax, argsToParamsOpt, rewrittenArguments, parameters, actualArguments[actualArguments.Length - 1]); BoundAssignmentOperator storeToTemp; var boundTemp = _factory.StoreToTemp(array, out storeToTemp); stores.Add(storeToTemp); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index 910cd4273f970..c3db6186b6615 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -16,6 +16,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal static class ParameterHelpers { +#nullable enable public static ImmutableArray MakeParameters( Binder binder, Symbol owner, @@ -129,7 +130,7 @@ private static ImmutableArray MakeParameters.GetInstance(); - var mustBeLastParameter = (ParameterSyntax)null; + var mustBeLastParameter = (ParameterSyntax?)null; foreach (var parameterSyntax in parametersList) { @@ -219,7 +220,7 @@ private static ImmutableArray MakeParameters); @@ -233,7 +234,6 @@ private static ImmutableArray MakeParameters parameters) { EnsureIsReadOnlyAttributeExists(moduleBuilder.Compilation, parameters, diagnostics: null, modifyCompilation: false, moduleBuilder); @@ -343,7 +343,6 @@ private static void EnsureNullableAttributeExists(CSharpCompilation compilation, } private static Location GetParameterLocation(ParameterSymbol parameter) => parameter.GetNonNullSyntaxNode().Location; -#nullable disable private static void CheckParameterModifiers(BaseParameterSyntax parameter, BindingDiagnosticBag diagnostics, bool parsingFunctionPointerParams) { @@ -507,15 +506,23 @@ private static void ReportParameterErrors( // error CS1100: Method '{0}' has a parameter modifier 'this' which is not on the first parameter diagnostics.Add(ErrorCode.ERR_BadThisParam, thisKeyword.GetLocation(), owner.Name); } - else if (parameter.IsParams && owner.IsOperator()) + else if (parameter.IsParams) { - // error CS1670: params is not valid in this context - diagnostics.Add(ErrorCode.ERR_IllegalParams, paramsKeyword.GetLocation()); - } - else if (parameter.IsParams && !parameter.TypeWithAnnotations.IsSZArray()) - { - // error CS0225: The params parameter must be a single dimensional array - diagnostics.Add(ErrorCode.ERR_ParamsMustBeArray, paramsKeyword.GetLocation()); + if (owner.IsOperator()) + { + // error CS1670: params is not valid in this context + diagnostics.Add(ErrorCode.ERR_IllegalParams, paramsKeyword.GetLocation()); + } + else if (!parameter.Type.IsParamsType(parameter.DeclaringCompilation)) + { + // PROTOTYPE: Update error message to include 'Span' and 'ReadOnlySpan'. + // error CS0225: The params parameter must be a single dimensional array + diagnostics.Add(ErrorCode.ERR_ParamsMustBeArray, paramsKeyword.GetLocation()); + } + else if (!parameter.Type.IsSZArray()) + { + MessageID.IDS_FeatureParamsSpan.CheckFeatureAvailability(diagnostics, parameterSyntax, paramsKeyword.GetLocation()); + } } else if (parameter.TypeWithAnnotations.IsStatic) { @@ -539,6 +546,7 @@ private static void ReportParameterErrors( diagnostics.Add(ErrorCode.ERR_MethodArgCantBeRefAny, parameterSyntax.Location, parameter.Type); } } +#nullable disable internal static bool ReportDefaultParameterErrors( Binder binder, diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index a83da25243d79..53c8775b1ecea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1677,6 +1677,34 @@ private static bool HasNamespaceName(NamespaceSymbol @namespace, string namespac return (name.Length == length) && (string.Compare(name, 0, namespaceName, offset, length, comparison) == 0); } + internal static bool IsParamsType(this TypeSymbol type, CSharpCompilation compilation) + { + if (type.IsSZArray()) + { + return true; + } + if (type is NamedTypeSymbol { Arity: 1 } namedType) + { + var constructedFrom = namedType.ConstructedFrom; + return (object)constructedFrom == compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T) || + (object)constructedFrom == compilation.GetWellKnownType(WellKnownType.System_Span_T); + } + return false; + } + + internal static TypeWithAnnotations GetParamsElementType(this TypeSymbol type) + { + if (type is ArrayTypeSymbol arrayType) + { + return arrayType.ElementTypeWithAnnotations; + } + if (type is NamedTypeSymbol { Arity: 1 } namedType) + { + return namedType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]; + } + throw ExceptionUtilities.UnexpectedValue(type); + } + internal static bool IsNonGenericTaskType(this TypeSymbol type, CSharpCompilation compilation) { var namedType = type as NamedTypeSymbol; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index c3617ff947a0b..67a9a9f22e45c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -427,6 +427,11 @@ Vlastnost kontraktu rovnosti záznamu {0} musí mít přístupový objekt get. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static Explicitní implementace uživatelem definovaného operátoru {0} musí být deklarovaná jako statická. @@ -1372,6 +1377,11 @@ konstruktory struktury bez parametrů + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records pozice polí v záznamech diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 96921bc9ee6f7..3dd3dc50089dc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -427,6 +427,11 @@ Die EqualityContract-Eigenschaft "{0}" für Datensätze muss eine get-Zugriffsmethode aufweisen. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static Die explizite Implementierung eines benutzerdefinierten Operators "{0}" muss als statisch deklariert werden. @@ -1372,6 +1377,11 @@ Parameterlose Strukturkonstruktoren + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records Positionsfelder in Datensätzen diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 79bb01f3e14e3..413bf44d147b9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -427,6 +427,11 @@ La propiedad del contrato de igualdad de registros "{0}" debe tener un descriptor de acceso get. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static La implementación explícita de un operador definido por el usuario "{0}" se debe declarar como estático @@ -1372,6 +1377,11 @@ constructores de estructuras sin parámetros + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records campos posicionales en registros diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 0f5e8115e8eb9..83d390d6a4943 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -427,6 +427,11 @@ La propriété de contrat d'égalité d'enregistrement '{0}' doit avoir un accesseur get. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static L’implémentation explicite d’un opérateur « {0} » défini par l’utilisateur doit être déclarée comme static @@ -1372,6 +1377,11 @@ constructeurs de struct sans paramètre + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records champs positionnels dans les enregistrements diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index dada06ff62819..ad618f5b14d21 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -427,6 +427,11 @@ La proprietà '{0}' del contratto di uguaglianza record deve contenere una funzione di accesso get. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static L'implementazione esplicita di un operatore definito dall'utente '{0}' deve essere dichiarata come statica @@ -1372,6 +1377,11 @@ costruttori struct senza parametri + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records campi posizionali nei record diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 2914f864037da..1463330842805 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -427,6 +427,11 @@ レコードの等値コントラクト プロパティ '{0}' には get アクセサーが必要です。 + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static ユーザー定義演算子 '{0}' の明示的な実装は静的として宣言する必要があります @@ -1372,6 +1377,11 @@ パラメーターのない構造体コンストラクター + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records レコード内の位置指定フィールド diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 62f0dff70777a..5d3317cf8c0af 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -427,6 +427,11 @@ 레코드 같음 계약 속성 '{0}'에는 get 접근자가 있어야 합니다. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static 사용자 정의 연산자 '{0}'의 명시적 구현은 정적으로 선언되어야 합니다. @@ -1372,6 +1377,11 @@ 매개 변수 없는 구조체 생성자 + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records 레코드의 위치 필드 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 6de6a1de3c822..40c439ad6b668 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -427,6 +427,11 @@ Właściwość kontraktu równości rekordu „{0}” musi mieć metodę dostępu get. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static Jawna implementacja operatora zdefiniowanego przez użytkownika „{0}” musi być zadeklarowana jako statyczna @@ -1372,6 +1377,11 @@ Konstruktory struktury bez parametrów + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records pola pozycyjne w rekordach diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 4c55b10bba09f..744148bb88fa1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -427,6 +427,11 @@ A propriedade de contrato de igualdade do registro '{0}' precisa ter um acessador get. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static A implementação explícita de um operador definido pelo usuário '{0}' deve ser declarada estática @@ -1372,6 +1377,11 @@ construtores struct sem parâmetros + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records campos posicionais nos registros diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index dcc8f5926efbb..ac5346537e726 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -427,6 +427,11 @@ Свойство контракта на равенство записей "{0}" должно иметь метод доступа get. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static Явная реализация определяемого пользователем оператора "{0}" должна быть объявлена статической @@ -1372,6 +1377,11 @@ конструкторы структуры без параметров + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records позиционные поля в записях diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 27604919dce03..0117d47efbc43 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -427,6 +427,11 @@ '{0}' kayıt eşitlik anlaşması özelliğinin get erişimcisine sahip olması gerekir. + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static '{0}' kullanıcı tanımlı işlecinin açık uygulaması statik olarak bildirilmelidir @@ -1372,6 +1377,11 @@ parametresiz yapı oluşturucuları + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records kayıtlardaki konumsal alanlar diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 30524b3ae4a23..b242944dd8fd9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -427,6 +427,11 @@ 记录等同性合同属性“{0}”必须具有 get 访问器。 + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static 用户定义的运算符“{0}”的显式实现必须声明为静态 @@ -1372,6 +1377,11 @@ 参数结构构造函数 + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records 记录中的位置字段 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 07fd8e9d87a2e..29759007c80da 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -427,6 +427,11 @@ 記錄相等 contract 屬性 '{0}' 必須要有 get 存取子。 + + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + Cannot use params '{0}' in this context because it may prevent reuse at the call-site + + Explicit implementation of a user-defined operator '{0}' must be declared static 使用者定義的運算子 '{0}' 的明確實作必須宣告為靜態 @@ -1372,6 +1377,11 @@ 無參數結構建構函式 + + params Span<T> + params Span<T> + params Span<T> is not localizable + positional fields in records 記錄中的位置欄位 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ParamsSpanTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ParamsSpanTests.cs new file mode 100644 index 0000000000000..a3e0a2e20f463 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ParamsSpanTests.cs @@ -0,0 +1,1122 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class ParamsSpanTests : CSharpTestBase + { + [ConditionalFact(typeof(CoreClrOnly))] + public void ParamsSpan_01() + { + var sourceA = +@"using System; +public class A +{ + public static void F1(params Span args) + { + foreach (var arg in args) Console.WriteLine(arg); + } + public static void F2(params ReadOnlySpan args) + { + foreach (var arg in args) Console.WriteLine(arg); + } +}"; + + var compA = CreateCompilation(sourceA, targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular10); + compA.VerifyDiagnostics( + // (4,27): error CS8652: The feature 'params Span' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static void F1(params Span args) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "params").WithArguments("params Span").WithLocation(4, 27), + // (8,27): error CS8652: The feature 'params Span' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static void F2(params ReadOnlySpan args) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "params").WithArguments("params Span").WithLocation(8, 27)); + + compA = CreateCompilation(sourceA, targetFramework: TargetFramework.NetCoreApp); + compA.VerifyDiagnostics(); + var refA = compA.EmitToImageReference(); + + var sourceB = +@"class B +{ + static void Main() + { + A.F1(); + A.F1(1, 2, ""hello""); + A.F2(); + A.F2(""span"", 3); + } +}"; + + var compB = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular10, options: TestOptions.ReleaseExe); + compB.VerifyDiagnostics( + // (5,9): error CS8652: The feature 'params Span' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // A.F1(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "A.F1()").WithArguments("params Span").WithLocation(5, 9), + // (6,9): error CS8652: The feature 'params Span' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // A.F1(1, 2, "hello"); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"A.F1(1, 2, ""hello"")").WithArguments("params Span").WithLocation(6, 9), + // (7,9): error CS8652: The feature 'params Span' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // A.F2(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "A.F2()").WithArguments("params Span").WithLocation(7, 9), + // (8,9): error CS8652: The feature 'params Span' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // A.F2("span", 3); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"A.F2(""span"", 3)").WithArguments("params Span").WithLocation(8, 9)); + + compB = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); + compB.VerifyDiagnostics(); + var verifier = CompileAndVerify(compB, verify: Verification.Skipped, expectedOutput: +@"1 +2 +hello +span +3 +"); + verifier.VerifyIL("B.Main", +@"{ + // Code size 154 (0x9a) + .maxstack 2 + .locals init (System.Span V_0) + IL_0000: ldc.i4.0 + IL_0001: newarr ""object"" + IL_0006: newobj ""System.Span..ctor(object[])"" + IL_000b: call ""void A.F1(params System.Span)"" + IL_0010: ldloca.s V_0 + IL_0012: ldc.i4.3 + IL_0013: newarr ""object"" + IL_0018: call ""System.Span..ctor(object[])"" + IL_001d: ldloca.s V_0 + IL_001f: ldc.i4.0 + IL_0020: call ""ref object System.Span.this[int].get"" + IL_0025: ldc.i4.1 + IL_0026: box ""int"" + IL_002b: stind.ref + IL_002c: ldloca.s V_0 + IL_002e: ldc.i4.1 + IL_002f: call ""ref object System.Span.this[int].get"" + IL_0034: ldc.i4.2 + IL_0035: box ""int"" + IL_003a: stind.ref + IL_003b: ldloca.s V_0 + IL_003d: ldc.i4.2 + IL_003e: call ""ref object System.Span.this[int].get"" + IL_0043: ldstr ""hello"" + IL_0048: stind.ref + IL_0049: ldloc.0 + IL_004a: call ""void A.F1(params System.Span)"" + IL_004f: ldc.i4.0 + IL_0050: newarr ""object"" + IL_0055: newobj ""System.Span..ctor(object[])"" + IL_005a: call ""System.ReadOnlySpan System.Span.op_Implicit(System.Span)"" + IL_005f: call ""void A.F2(params System.ReadOnlySpan)"" + IL_0064: ldloca.s V_0 + IL_0066: ldc.i4.2 + IL_0067: newarr ""object"" + IL_006c: call ""System.Span..ctor(object[])"" + IL_0071: ldloca.s V_0 + IL_0073: ldc.i4.0 + IL_0074: call ""ref object System.Span.this[int].get"" + IL_0079: ldstr ""span"" + IL_007e: stind.ref + IL_007f: ldloca.s V_0 + IL_0081: ldc.i4.1 + IL_0082: call ""ref object System.Span.this[int].get"" + IL_0087: ldc.i4.3 + IL_0088: box ""int"" + IL_008d: stind.ref + IL_008e: ldloc.0 + IL_008f: call ""System.ReadOnlySpan System.Span.op_Implicit(System.Span)"" + IL_0094: call ""void A.F2(params System.ReadOnlySpan)"" + IL_0099: ret +}"); + } + + [ConditionalTheory(typeof(CoreClrOnly))] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.Preview)] + public void ParamsSpan_02(LanguageVersion languageVersion) + { + var sourceA = +@"using System; +public class A +{ + public static void F1(params Span args) + { + foreach (var arg in args) Console.WriteLine(arg); + } + public static void F2(params ReadOnlySpan args) + { + foreach (var arg in args) Console.WriteLine(arg); + } +}"; + + var compA = CreateCompilation(sourceA, targetFramework: TargetFramework.NetCoreApp); + compA.VerifyDiagnostics(); + var refA = compA.EmitToImageReference(); + + var sourceB = +@"using System; +class B +{ + static void Main() + { + A.F1(new object[0]); + A.F1(new object[] { 1 }); + A.F1(new Span(new object[] { 2, ""hello"" })); + A.F2(new object[0]); + A.F2(new object[] { ""span"" }); + A.F2(new ReadOnlySpan(new object[] { 3 })); + } +}"; + + var compB = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); + compB.VerifyDiagnostics(); + var verifier = CompileAndVerify(compB, verify: Verification.Skipped, expectedOutput: +@"1 +2 +hello +span +3 +"); + verifier.VerifyIL("B.Main", +@"{ + // Code size 140 (0x8c) + .maxstack 4 + IL_0000: ldc.i4.0 + IL_0001: newarr ""object"" + IL_0006: call ""System.Span System.Span.op_Implicit(object[])"" + IL_000b: call ""void A.F1(params System.Span)"" + IL_0010: ldc.i4.1 + IL_0011: newarr ""object"" + IL_0016: dup + IL_0017: ldc.i4.0 + IL_0018: ldc.i4.1 + IL_0019: box ""int"" + IL_001e: stelem.ref + IL_001f: call ""System.Span System.Span.op_Implicit(object[])"" + IL_0024: call ""void A.F1(params System.Span)"" + IL_0029: ldc.i4.2 + IL_002a: newarr ""object"" + IL_002f: dup + IL_0030: ldc.i4.0 + IL_0031: ldc.i4.2 + IL_0032: box ""int"" + IL_0037: stelem.ref + IL_0038: dup + IL_0039: ldc.i4.1 + IL_003a: ldstr ""hello"" + IL_003f: stelem.ref + IL_0040: newobj ""System.Span..ctor(object[])"" + IL_0045: call ""void A.F1(params System.Span)"" + IL_004a: ldc.i4.0 + IL_004b: newarr ""object"" + IL_0050: call ""System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(object[])"" + IL_0055: call ""void A.F2(params System.ReadOnlySpan)"" + IL_005a: ldc.i4.1 + IL_005b: newarr ""object"" + IL_0060: dup + IL_0061: ldc.i4.0 + IL_0062: ldstr ""span"" + IL_0067: stelem.ref + IL_0068: call ""System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(object[])"" + IL_006d: call ""void A.F2(params System.ReadOnlySpan)"" + IL_0072: ldc.i4.1 + IL_0073: newarr ""object"" + IL_0078: dup + IL_0079: ldc.i4.0 + IL_007a: ldc.i4.3 + IL_007b: box ""int"" + IL_0080: stelem.ref + IL_0081: newobj ""System.ReadOnlySpan..ctor(object[])"" + IL_0086: call ""void A.F2(params System.ReadOnlySpan)"" + IL_008b: ret +}"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void ParamsSpan_03() + { + var source = +@"using System; +class Program +{ + static void F(params Span args) + { + foreach (var arg in args) Console.WriteLine(arg); + } + static void Main() + { + F(1, 2, 3); + F(""4"", ""5"", ""6""); + } +}"; + // PROTOTYPE: Should use to initialize + // the new[] { 1, 2, 3 } case, to match the behavior for 'params T[]' + // from CodeGenerator.EmitArrayInitializers(). + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"1 +2 +3 +4 +5 +6 +"); + verifier.VerifyIL("Program.Main", +@"{ + // Code size 111 (0x6f) + .maxstack 2 + .locals init (System.Span V_0, + System.Span V_1) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.3 + IL_0003: newarr ""int"" + IL_0008: call ""System.Span..ctor(int[])"" + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.0 + IL_0010: call ""ref int System.Span.this[int].get"" + IL_0015: ldc.i4.1 + IL_0016: stind.i4 + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.1 + IL_001a: call ""ref int System.Span.this[int].get"" + IL_001f: ldc.i4.2 + IL_0020: stind.i4 + IL_0021: ldloca.s V_0 + IL_0023: ldc.i4.2 + IL_0024: call ""ref int System.Span.this[int].get"" + IL_0029: ldc.i4.3 + IL_002a: stind.i4 + IL_002b: ldloc.0 + IL_002c: call ""void Program.F(params System.Span)"" + IL_0031: ldloca.s V_1 + IL_0033: ldc.i4.3 + IL_0034: newarr ""string"" + IL_0039: call ""System.Span..ctor(string[])"" + IL_003e: ldloca.s V_1 + IL_0040: ldc.i4.0 + IL_0041: call ""ref string System.Span.this[int].get"" + IL_0046: ldstr ""4"" + IL_004b: stind.ref + IL_004c: ldloca.s V_1 + IL_004e: ldc.i4.1 + IL_004f: call ""ref string System.Span.this[int].get"" + IL_0054: ldstr ""5"" + IL_0059: stind.ref + IL_005a: ldloca.s V_1 + IL_005c: ldc.i4.2 + IL_005d: call ""ref string System.Span.this[int].get"" + IL_0062: ldstr ""6"" + IL_0067: stind.ref + IL_0068: ldloc.1 + IL_0069: call ""void Program.F(params System.Span)"" + IL_006e: ret +}"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void ParamsSpan_04() + { + var source = +@"using System; +class Program +{ + static void F(params ReadOnlySpan args) + { + foreach (var arg in args) Console.WriteLine(arg); + } + static void Main() + { + F(1, 2, 3); + F(""4"", ""5"", ""6""); + } +}"; + // PROTOTYPE: Should use to initialize + // the new[] { 1, 2, 3 } case, to match the behavior for 'params T[]' + // from CodeGenerator.EmitArrayInitializers(). + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"1 +2 +3 +4 +5 +6 +"); + verifier.VerifyIL("Program.Main", +@"{ + // Code size 121 (0x79) + .maxstack 2 + .locals init (System.Span V_0, + System.Span V_1) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.3 + IL_0003: newarr ""int"" + IL_0008: call ""System.Span..ctor(int[])"" + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.0 + IL_0010: call ""ref int System.Span.this[int].get"" + IL_0015: ldc.i4.1 + IL_0016: stind.i4 + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.1 + IL_001a: call ""ref int System.Span.this[int].get"" + IL_001f: ldc.i4.2 + IL_0020: stind.i4 + IL_0021: ldloca.s V_0 + IL_0023: ldc.i4.2 + IL_0024: call ""ref int System.Span.this[int].get"" + IL_0029: ldc.i4.3 + IL_002a: stind.i4 + IL_002b: ldloc.0 + IL_002c: call ""System.ReadOnlySpan System.Span.op_Implicit(System.Span)"" + IL_0031: call ""void Program.F(params System.ReadOnlySpan)"" + IL_0036: ldloca.s V_1 + IL_0038: ldc.i4.3 + IL_0039: newarr ""string"" + IL_003e: call ""System.Span..ctor(string[])"" + IL_0043: ldloca.s V_1 + IL_0045: ldc.i4.0 + IL_0046: call ""ref string System.Span.this[int].get"" + IL_004b: ldstr ""4"" + IL_0050: stind.ref + IL_0051: ldloca.s V_1 + IL_0053: ldc.i4.1 + IL_0054: call ""ref string System.Span.this[int].get"" + IL_0059: ldstr ""5"" + IL_005e: stind.ref + IL_005f: ldloca.s V_1 + IL_0061: ldc.i4.2 + IL_0062: call ""ref string System.Span.this[int].get"" + IL_0067: ldstr ""6"" + IL_006c: stind.ref + IL_006d: ldloc.1 + IL_006e: call ""System.ReadOnlySpan System.Span.op_Implicit(System.Span)"" + IL_0073: call ""void Program.F(params System.ReadOnlySpan)"" + IL_0078: ret +}"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Operator() + { + var source = +@"using System; +class A +{ + public static A operator+(A a, params Span args) + { + return a; + } + public static implicit operator B(A a, params ReadOnlySpan args) + { + return default; + } +} +class B +{ +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (4,36): error CS1670: params is not valid in this context + // public static A operator+(A a, params Span args) + Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(4, 36), + // (8,38): error CS1019: Overloadable unary operator expected + // public static implicit operator B(A a, params ReadOnlySpan args) + Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "(A a, params ReadOnlySpan args)").WithLocation(8, 38), + // (8,44): error CS1670: params is not valid in this context + // public static implicit operator B(A a, params ReadOnlySpan args) + Diagnostic(ErrorCode.ERR_IllegalParams, "params").WithLocation(8, 44)); + } + + /// + /// Optional parameters are allowed before 'params'. + /// + [ConditionalFact(typeof(CoreClrOnly))] + public void OptionalParameters() + { + var sourceA = +@"using System; +public class A +{ + public static void F1(int x, int y = 2, params Span args) + { + Console.WriteLine((x, y)); + foreach (var arg in args) Console.WriteLine(arg); + } + public static void F2(T x = default, params ReadOnlySpan args) + { + Console.WriteLine(x); + foreach (var arg in args) Console.WriteLine(arg); + } +}"; + var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + var refA = comp.EmitToImageReference(); + + var sourceB = +@"class B +{ + static void Main() + { + A.F1(1); + A.F1(2, 3); + A.F1(3, 4, 5); + A.F2(); + A.F2(1); + A.F2(2, 3, 4); + } +}"; + CompileAndVerify(sourceB, references: new[] { refA }, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"(1, 2) +(2, 3) +(3, 4) +5 +0 +1 +2 +3 +4 +"); + } + [ConditionalFact(typeof(CoreClrOnly))] + public void MissingSpanConstructor() + { + var source = +@"using System; +class Program +{ + static void F1(params Span args) { } + static void F2(params ReadOnlySpan args) { } + static void Main() + { + F1(); + F2(); + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Span_T__ctorArray); + comp.VerifyEmitDiagnostics( + // (8,9): error CS0656: Missing compiler required member 'System.Span`1..ctor' + // F1(); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "F1()").WithArguments("System.Span`1", ".ctor").WithLocation(8, 9), + // (9,9): error CS0656: Missing compiler required member 'System.Span`1..ctor' + // F2(); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "F2()").WithArguments("System.Span`1", ".ctor").WithLocation(9, 9)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void MissingSpanGetItem() + { + var source = +@"using System; +class Program +{ + static void F1(params Span args) { } + static void F2(params ReadOnlySpan args) { } + static void Main() + { + F1(); + F2(); + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Span_T__get_Item); + comp.VerifyEmitDiagnostics( + // (8,9): error CS0656: Missing compiler required member 'System.Span`1.get_Item' + // F1(); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "F1()").WithArguments("System.Span`1", "get_Item").WithLocation(8, 9), + // (9,9): error CS0656: Missing compiler required member 'System.Span`1.get_Item' + // F2(); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "F2()").WithArguments("System.Span`1", "get_Item").WithLocation(9, 9)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void MissingSpanImplicitOperator() + { + var source = +@"using System; +class Program +{ + static void F1(params Span args) { } + static void F2(params ReadOnlySpan args) { } + static void Main() + { + F1(); + F2(); + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Span_T__op_Implicit_SpanReadOnlySpan); + comp.VerifyEmitDiagnostics( + // (9,9): error CS0656: Missing compiler required member 'System.Span`1.op_Implicit' + // F2(); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "F2()").WithArguments("System.Span`1", "op_Implicit").WithLocation(9, 9)); + } + + /// + /// params value cannot be returned from the method since that + /// would prevent sharing repeated allocations at the call-site. + /// + [ConditionalFact(typeof(CoreClrOnly))] + public void CannotReturnSpan_01() + { + var source = +@"using System; +class Program +{ + static T[] F0(params T[] x0) + { + return x0; + } + static Span F1(params Span x1) + { + return x1; + } + static Span F2(Span x2, params Span y2) + { + return x2; + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (10,16): error CS8999: Cannot use params 'x1' in this context because it may prevent reuse at the call-site + // return x1; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "x1").WithArguments("x1").WithLocation(10, 16)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void CannotReturnSpan_02() + { + var source = +@"using System; +class Program +{ + static void F0(out T[] x0, params T[] y0) + { + x0 = y0; + } + static void F1(out ReadOnlySpan x1, params ReadOnlySpan y1) + { + x1 = y1; + } + static void F2(out ReadOnlySpan x2, ReadOnlySpan y2, params ReadOnlySpan z2) + { + x2 = y2; + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (10,14): error CS8999: Cannot use params 'y1' in this context because it may prevent reuse at the call-site + // x1 = y1; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "y1").WithArguments("y1").WithLocation(10, 14)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void CannotReturnSpan_03() + { + var source = +@"using System; +class Program +{ + static Span F1(params Span x1) + { + x1 = default; + return x1; + } + static void F2(out ReadOnlySpan x2, params ReadOnlySpan y2) + { + y2 = default; + x2 = y2; + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (7,16): error CS8999: Cannot use params 'x1' in this context because it may prevent reuse at the call-site + // return x1; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "x1").WithArguments("x1").WithLocation(7, 16), + // (12,14): error CS8999: Cannot use params 'y2' in this context because it may prevent reuse at the call-site + // x2 = y2; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "y2").WithArguments("y2").WithLocation(12, 14)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void CannotReturnSpan_04() + { + var source = +@"using System; +class Program +{ + static Span F1(Span x1, params Span y1) + { + x1 = y1; + return x1; + } + static Span F2(Span x2, params Span y2) + { + x2 = y2; + x2 = default; + return x2; + } + static void F3(out ReadOnlySpan x3, ReadOnlySpan y3, params ReadOnlySpan z3) + { + y3 = z3; + x3 = y3; + } + static void F4(out ReadOnlySpan x4, ReadOnlySpan y4, params ReadOnlySpan z4) + { + y4 = z4; + y4 = default; + x4 = y4; + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (6,14): error CS8999: Cannot use params 'y1' in this context because it may prevent reuse at the call-site + // x1 = y1; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "y1").WithArguments("y1").WithLocation(6, 14), + // (11,14): error CS8999: Cannot use params 'y2' in this context because it may prevent reuse at the call-site + // x2 = y2; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "y2").WithArguments("y2").WithLocation(11, 14), + // (17,14): error CS8999: Cannot use params 'z3' in this context because it may prevent reuse at the call-site + // y3 = z3; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "z3").WithArguments("z3").WithLocation(17, 14), + // (22,14): error CS8999: Cannot use params 'z4' in this context because it may prevent reuse at the call-site + // y4 = z4; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "z4").WithArguments("z4").WithLocation(22, 14)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void CannotReturnSpan_05() + { + var source = +@"using System; +abstract class A +{ + public abstract Span F(params Span args); +} +class B : A +{ + public override Span F(params Span args) => args; +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (8,58): error CS8999: Cannot use params 'args' in this context because it may prevent reuse at the call-site + // public override Span F(params Span args) => args; + Diagnostic(ErrorCode.ERR_EscapeParamsSpan, "args").WithArguments("args").WithLocation(8, 58)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void CannotReturnSpan_06() + { + var source = +@"using System; +interface I +{ + Span F(params Span args); +} +class C : I +{ + public Span F(Span args) => args; +}"; + // PROTOTYPE: Should report: error CS8999: Cannot use params 'args' in this context because it may prevent reuse at the call-site + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void CannotReturnSpan_07() + { + var source = +@"using System; +interface I +{ + Span F(params Span args); +} +class C : I +{ + Span I.F(Span args) => args; +}"; + // PROTOTYPE: Should report: error CS8999: Cannot use params 'args' in this context because it may prevent reuse at the call-site + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + /// + /// Prefer params Span or ReadOnlySpan over params T[]. + /// + [ConditionalFact(typeof(CoreClrOnly))] + public void OverloadResolution_01() + { + var sourceA = +@"using System; +public class A +{ + public static void F1(params object[] args) { throw new Exception(); } + public static void F1(params Span args) { foreach (var arg in args) Console.WriteLine(arg); } + public static void F2(params object[] args) { throw new Exception(); } + public static void F2(params ReadOnlySpan args) { foreach (var arg in args) Console.WriteLine(arg); } +}"; + var comp = CreateCompilation(sourceA, targetFramework: TargetFramework.NetCoreApp); + var refA = comp.EmitToImageReference(); + + var sourceB = +@"using System; +class B : A +{ + static void Main() + { + F1(1, 2, 3); + F2(""hello"", ""world""); + } +}"; + CompileAndVerify(sourceB, references: new[] { refA }, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"1 +2 +3 +hello +world +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void OverloadResolution_02() + { + var source = +@"using System; +class Program +{ + static void F1(params T[] args) { Console.WriteLine(""F1(params T[] args)""); } + static void F1(params Span args) { Console.WriteLine(""F1(params Span args)""); } + static void F2(params object[] args) { Console.WriteLine(""F2(params object[] args)""); } + static void F2(params Span args) { Console.WriteLine(""F2(params Span args)""); } + static void Main() + { + F1(1, 2, 3); + F2(4, 5); + } +}"; + CompileAndVerify(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"F1(params T[] args) +F2(params Span args) +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void OverloadResolution_03() + { + var source = +@"using System; +class Program +{ + static void F1(params ReadOnlySpan args) { } + static void F1(params Span args) { } + static void F2(params ReadOnlySpan args) { } + static void F2(params Span args) { } + static void Main() + { + F1(1, 2, 3); + F2(""hello"", ""span""); + } +}"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (10,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(params ReadOnlySpan)' and 'Program.F1(params Span)' + // F1(1, 2, 3); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments("Program.F1(params System.ReadOnlySpan)", "Program.F1(params System.Span)").WithLocation(10, 9), + // (11,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(params ReadOnlySpan)' and 'Program.F2(params Span)' + // F2("hello", "span"); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(params System.ReadOnlySpan)", "Program.F2(params System.Span)").WithLocation(11, 9)); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void OverloadResolution_04() + { + var source = +@"using System; +class Program +{ + static void F1(params ReadOnlySpan args) { Console.WriteLine(""F1(params ReadOnlySpan args)""); } + static void F1(params Span args) { Console.WriteLine(""F1(params Span args)""); } + static void F2(params ReadOnlySpan args) { Console.WriteLine(""F2(params ReadOnlySpan args)""); } + static void F2(params Span args) { Console.WriteLine(""F2(params Span args)""); } + static void Main() + { + F1(1, 2, 3); + F2(""hello"", ""world""); + } +}"; + CompileAndVerify(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"F1(params ReadOnlySpan args) +F2(params Span args) +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void RepeatedCalls_01() + { + var source = +@"using System; +class Program +{ + static void F(params Span args) + { + foreach (var arg in args) Console.WriteLine(arg); + } + static void Main() + { + F(1, 2); + int offset = 2; + while (offset < 15) + { + F(offset + 1, offset + 2); + F(offset + 3, offset + 4, offset + 5); + offset += 5; + } + F(offset + 1, offset + 2, offset + 3); + } +}"; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +"); + // PROTOTYPE: If the same buffer is re-used across multiple calls, we + // need to clear the buffer when leaving the scope of any particular + // use to match users' expectations around GC for the elements. + verifier.VerifyIL("Program.Main", +@"{ + // Code size 206 (0xce) + .maxstack 3 + .locals init (int V_0, //offset + System.Span V_1) + IL_0000: ldloca.s V_1 + IL_0002: ldc.i4.2 + IL_0003: newarr ""int"" + IL_0008: call ""System.Span..ctor(int[])"" + IL_000d: ldloca.s V_1 + IL_000f: ldc.i4.0 + IL_0010: call ""ref int System.Span.this[int].get"" + IL_0015: ldc.i4.1 + IL_0016: stind.i4 + IL_0017: ldloca.s V_1 + IL_0019: ldc.i4.1 + IL_001a: call ""ref int System.Span.this[int].get"" + IL_001f: ldc.i4.2 + IL_0020: stind.i4 + IL_0021: ldloc.1 + IL_0022: call ""void Program.F(params System.Span)"" + IL_0027: ldc.i4.2 + IL_0028: stloc.0 + IL_0029: br.s IL_0091 + IL_002b: ldloca.s V_1 + IL_002d: ldc.i4.2 + IL_002e: newarr ""int"" + IL_0033: call ""System.Span..ctor(int[])"" + IL_0038: ldloca.s V_1 + IL_003a: ldc.i4.0 + IL_003b: call ""ref int System.Span.this[int].get"" + IL_0040: ldloc.0 + IL_0041: ldc.i4.1 + IL_0042: add + IL_0043: stind.i4 + IL_0044: ldloca.s V_1 + IL_0046: ldc.i4.1 + IL_0047: call ""ref int System.Span.this[int].get"" + IL_004c: ldloc.0 + IL_004d: ldc.i4.2 + IL_004e: add + IL_004f: stind.i4 + IL_0050: ldloc.1 + IL_0051: call ""void Program.F(params System.Span)"" + IL_0056: ldloca.s V_1 + IL_0058: ldc.i4.3 + IL_0059: newarr ""int"" + IL_005e: call ""System.Span..ctor(int[])"" + IL_0063: ldloca.s V_1 + IL_0065: ldc.i4.0 + IL_0066: call ""ref int System.Span.this[int].get"" + IL_006b: ldloc.0 + IL_006c: ldc.i4.3 + IL_006d: add + IL_006e: stind.i4 + IL_006f: ldloca.s V_1 + IL_0071: ldc.i4.1 + IL_0072: call ""ref int System.Span.this[int].get"" + IL_0077: ldloc.0 + IL_0078: ldc.i4.4 + IL_0079: add + IL_007a: stind.i4 + IL_007b: ldloca.s V_1 + IL_007d: ldc.i4.2 + IL_007e: call ""ref int System.Span.this[int].get"" + IL_0083: ldloc.0 + IL_0084: ldc.i4.5 + IL_0085: add + IL_0086: stind.i4 + IL_0087: ldloc.1 + IL_0088: call ""void Program.F(params System.Span)"" + IL_008d: ldloc.0 + IL_008e: ldc.i4.5 + IL_008f: add + IL_0090: stloc.0 + IL_0091: ldloc.0 + IL_0092: ldc.i4.s 15 + IL_0094: blt.s IL_002b + IL_0096: ldloca.s V_1 + IL_0098: ldc.i4.3 + IL_0099: newarr ""int"" + IL_009e: call ""System.Span..ctor(int[])"" + IL_00a3: ldloca.s V_1 + IL_00a5: ldc.i4.0 + IL_00a6: call ""ref int System.Span.this[int].get"" + IL_00ab: ldloc.0 + IL_00ac: ldc.i4.1 + IL_00ad: add + IL_00ae: stind.i4 + IL_00af: ldloca.s V_1 + IL_00b1: ldc.i4.1 + IL_00b2: call ""ref int System.Span.this[int].get"" + IL_00b7: ldloc.0 + IL_00b8: ldc.i4.2 + IL_00b9: add + IL_00ba: stind.i4 + IL_00bb: ldloca.s V_1 + IL_00bd: ldc.i4.2 + IL_00be: call ""ref int System.Span.this[int].get"" + IL_00c3: ldloc.0 + IL_00c4: ldc.i4.3 + IL_00c5: add + IL_00c6: stind.i4 + IL_00c7: ldloc.1 + IL_00c8: call ""void Program.F(params System.Span)"" + IL_00cd: ret +}"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void RepeatedCalls_02() + { + var source = +@"using System; +class Program +{ + static T ElementAt(int index, params Span args) + { + var value = args[index]; + Console.WriteLine(""ElementAt<{0}>({1}): {2}"", typeof(T), index, value); + return value; + } + static void Main() + { + var value = ElementAt( + 0, + ElementAt(1, 'a', 'b', 'c'), + ElementAt(2, 'e', 'f', 'g'), + 'h'); + Console.WriteLine(value); + } +}"; + // No buffer re-use. + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: +@"ElementAt(1): b +ElementAt(2): g +ElementAt(0): b +b +"); + verifier.VerifyIL("Program.Main", +@"{ + // Code size 161 (0xa1) + .maxstack 5 + .locals init (System.Span V_0, + System.Span V_1) + IL_0000: ldc.i4.0 + IL_0001: ldloca.s V_0 + IL_0003: ldc.i4.3 + IL_0004: newarr ""char"" + IL_0009: call ""System.Span..ctor(char[])"" + IL_000e: ldloca.s V_0 + IL_0010: ldc.i4.0 + IL_0011: call ""ref char System.Span.this[int].get"" + IL_0016: ldc.i4.1 + IL_0017: ldloca.s V_1 + IL_0019: ldc.i4.3 + IL_001a: newarr ""char"" + IL_001f: call ""System.Span..ctor(char[])"" + IL_0024: ldloca.s V_1 + IL_0026: ldc.i4.0 + IL_0027: call ""ref char System.Span.this[int].get"" + IL_002c: ldc.i4.s 97 + IL_002e: stind.i2 + IL_002f: ldloca.s V_1 + IL_0031: ldc.i4.1 + IL_0032: call ""ref char System.Span.this[int].get"" + IL_0037: ldc.i4.s 98 + IL_0039: stind.i2 + IL_003a: ldloca.s V_1 + IL_003c: ldc.i4.2 + IL_003d: call ""ref char System.Span.this[int].get"" + IL_0042: ldc.i4.s 99 + IL_0044: stind.i2 + IL_0045: ldloc.1 + IL_0046: call ""char Program.ElementAt(int, params System.Span)"" + IL_004b: stind.i2 + IL_004c: ldloca.s V_0 + IL_004e: ldc.i4.1 + IL_004f: call ""ref char System.Span.this[int].get"" + IL_0054: ldc.i4.2 + IL_0055: ldloca.s V_1 + IL_0057: ldc.i4.3 + IL_0058: newarr ""char"" + IL_005d: call ""System.Span..ctor(char[])"" + IL_0062: ldloca.s V_1 + IL_0064: ldc.i4.0 + IL_0065: call ""ref char System.Span.this[int].get"" + IL_006a: ldc.i4.s 101 + IL_006c: stind.i2 + IL_006d: ldloca.s V_1 + IL_006f: ldc.i4.1 + IL_0070: call ""ref char System.Span.this[int].get"" + IL_0075: ldc.i4.s 102 + IL_0077: stind.i2 + IL_0078: ldloca.s V_1 + IL_007a: ldc.i4.2 + IL_007b: call ""ref char System.Span.this[int].get"" + IL_0080: ldc.i4.s 103 + IL_0082: stind.i2 + IL_0083: ldloc.1 + IL_0084: call ""char Program.ElementAt(int, params System.Span)"" + IL_0089: stind.i2 + IL_008a: ldloca.s V_0 + IL_008c: ldc.i4.2 + IL_008d: call ""ref char System.Span.this[int].get"" + IL_0092: ldc.i4.s 104 + IL_0094: stind.i2 + IL_0095: ldloc.0 + IL_0096: call ""char Program.ElementAt(int, params System.Span)"" + IL_009b: call ""void System.Console.WriteLine(char)"" + IL_00a0: ret +}"); + } + } +} diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index b8ce5205655ec..bda0f8b371d31 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -436,8 +436,10 @@ internal enum WellKnownMember System_ObsoleteAttribute__ctor, System_Span_T__ctor, + System_Span_T__ctorArray, System_Span_T__get_Item, System_Span_T__get_Length, + System_Span_T__op_Implicit_SpanReadOnlySpan, System_ReadOnlySpan_T__ctor, System_ReadOnlySpan_T__get_Item, diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 00f6ae1bcf8a4..223702ee9ebdb 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -2999,7 +2999,7 @@ static WellKnownMembers() (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean, - // System_Span__ctor + // System_Span_T__ctor (byte)(MemberFlags.Constructor), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Span_T - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity @@ -3008,7 +3008,15 @@ static WellKnownMembers() (byte)SignatureTypeCode.Pointer, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, - // System_Span__get_Item + // System_Span_T__ctorArray + (byte)(MemberFlags.Constructor), // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Span_T - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.GenericTypeParameter, 0, + + // System_Span_T__get_Item (byte)(MemberFlags.PropertyGet), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Span_T - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity @@ -3016,14 +3024,28 @@ static WellKnownMembers() (byte)SignatureTypeCode.ByReference, (byte)SignatureTypeCode.GenericTypeParameter, 0, // Return Type (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, - // System_Span__get_Length + // System_Span_T__get_Length (byte)(MemberFlags.PropertyGet), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Span_T - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, // Return Type - // System_ReadOnlySpan__ctor + // System_Span_T__op_Implicit_SpanReadOnlySpan + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Span_T - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.GenericTypeInstance, // Return Type + (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ReadOnlySpan_T - WellKnownType.ExtSentinel), + 1, + (byte)SignatureTypeCode.GenericTypeParameter, 0, + (byte)SignatureTypeCode.GenericTypeInstance, + (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Span_T - WellKnownType.ExtSentinel), + 1, + (byte)SignatureTypeCode.GenericTypeParameter, 0, + + // System_ReadOnlySpan_T__ctor (byte)(MemberFlags.Constructor), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ReadOnlySpan_T - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity @@ -3032,7 +3054,7 @@ static WellKnownMembers() (byte)SignatureTypeCode.Pointer, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, - // System_ReadOnlySpan__get_Item + // System_ReadOnlySpan_T__get_Item (byte)(MemberFlags.PropertyGet), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ReadOnlySpan_T - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity @@ -3040,7 +3062,7 @@ static WellKnownMembers() (byte)SignatureTypeCode.ByReference, (byte)SignatureTypeCode.GenericTypeParameter, 0, // Return Type (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, - // System_ReadOnlySpan__get_Length + // System_ReadOnlySpan_T__get_Length (byte)(MemberFlags.PropertyGet), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ReadOnlySpan_T - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity @@ -3909,12 +3931,14 @@ static WellKnownMembers() ".ctor", // System_Runtime_CompilerServices_IsReadOnlyAttribute__ctor ".ctor", // System_Runtime_CompilerServices_IsByRefLikeAttribute__ctor ".ctor", // System_Runtime_CompilerServices_ObsoleteAttribute__ctor - ".ctor", // System_Span__ctor - "get_Item", // System_Span__get_Item - "get_Length", // System_Span__get_Length - ".ctor", // System_ReadOnlySpan__ctor - "get_Item", // System_ReadOnlySpan__get_Item - "get_Length", // System_ReadOnlySpan__get_Length + ".ctor", // System_Span_T__ctor + ".ctor", // System_Span_T__ctorArray + "get_Item", // System_Span_T__get_Item + "get_Length", // System_Span_T__get_Length + "op_Implicit", // System_Span_T__op_Implicit_SpanReadOnlySpan + ".ctor", // System_ReadOnlySpan_T__ctor + "get_Item", // System_ReadOnlySpan_T__get_Item + "get_Length", // System_ReadOnlySpan_T__get_Length ".ctor", // System_Runtime_CompilerServices_IsUnmanagedAttribute__ctor "Fix", // Microsoft_VisualBasic_Conversion__FixSingle