diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 90de29e0cf461..329de22ae1a7f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -5422,7 +5422,7 @@ static BoundNode bindSpreadElement(SpreadElementSyntax syntax, BindingDiagnostic Debug.Assert(length > 0); lengthOrCount = new BoundLiteral(expression.Syntax, ConstantValue.Create(length), @this.GetSpecialType(SpecialType.System_Int32, diagnostics, expression.Syntax)) { WasCompilerGenerated = true }; } - else if (!@this.TryBindNonExtensionLengthOrCount(syntax.Expression, expressionPlaceholder, out lengthOrCount, ref useSiteInfo, diagnostics)) // PROTOTYPE should extension Length/Count count? + else if (!@this.TryBindNonExtensionLengthOrCount(syntax.Expression, expressionPlaceholder, out lengthOrCount, ref useSiteInfo, diagnostics)) { lengthOrCount = null; } @@ -9268,17 +9268,15 @@ private bool TryBindImplicitIndexerInAnyScope(SyntaxNode syntax, BoundExpression AnalyzedArguments? analyzedIntIndexerOrSliceArguments = null; ImmutableArray intIndexerOrSliceArgumentPlaceholders = default; - AnalyzedArguments? actualExtensionLengthOrCountArguments = null; AnalyzedArguments? actualExtensionIntIndexerOrSliceArguments = null; bool result = tryBindImplicitIndexerInAnyScope( syntax, left, analyzedArguments, binder: this, ref useSiteInfo, diagnostics, ref analyzedIntIndexerOrSliceArguments, ref intIndexerOrSliceArgumentPlaceholders, - ref actualExtensionLengthOrCountArguments, ref actualExtensionIntIndexerOrSliceArguments, + ref actualExtensionIntIndexerOrSliceArguments, out extensionIndexerAccess); analyzedIntIndexerOrSliceArguments?.Free(); - actualExtensionLengthOrCountArguments?.Free(); actualExtensionIntIndexerOrSliceArguments?.Free(); return result; @@ -9293,14 +9291,13 @@ static bool tryBindImplicitIndexerInAnyScope( BindingDiagnosticBag diagnostics, ref AnalyzedArguments? analyzedIntIndexerOrSliceArguments, ref ImmutableArray argumentPlaceholders, - ref AnalyzedArguments? actualExtensionLengthOrCountArguments, ref AnalyzedArguments? actualExtensionIntIndexerOrSliceArguments, out BoundExpression? indexerAccess) { + indexerAccess = null; IndexOrRangeArgKind argKind = GetIndexOrRangeArgKind(arguments, binder.Compilation); if (argKind == IndexOrRangeArgKind.None) { - indexerAccess = null; return false; } @@ -9312,33 +9309,9 @@ static bool tryBindImplicitIndexerInAnyScope( BoundExpression? indexerOrSliceAccess = null; BoundExpression? lengthOrCountAccess = null; - bool foundApplicableLengthOrCount = false; - if (binder.TryBindNonExtensionLengthOrCount(syntax, receiverPlaceholder, out var instanceLengthOrCountAccess, ref useSiteInfo, implicitIndexerDiagnostics)) - { - foundApplicableLengthOrCount = true; - lengthOrCountAccess = instanceLengthOrCountAccess; - } - - if (!foundApplicableLengthOrCount) - { - foreach (var scope in new ExtensionScopes(binder)) - { - if (tryLookupExtensionLengthOrCount(syntax, receiverPlaceholder, binder, scope, - ref actualExtensionLengthOrCountArguments, out PropertySymbol? extensionLengthOrCountProperty, ref useSiteInfo, implicitIndexerDiagnostics)) - { - foundApplicableLengthOrCount = true; - if (extensionLengthOrCountProperty is not null) - { - Debug.Assert(extensionLengthOrCountProperty.ContainingType.ExtensionParameter is not null); - diagnostics.ReportUseSite(extensionLengthOrCountProperty, syntax); - lengthOrCountAccess = binder.GetExtensionMemberAccess(syntax, receiver, extensionLengthOrCountProperty, implicitIndexerDiagnostics).MakeCompilerGenerated(); - lengthOrCountAccess = binder.CheckValue(lengthOrCountAccess, BindValueKind.RValue, implicitIndexerDiagnostics); - } - - break; - } - } - } + // Check for Length/Count property in both instance and extension scopes + bool foundApplicableLengthOrCount = binder.TryBindLengthOrCountInAnyScope( + syntax, receiverPlaceholder, ref useSiteInfo, implicitIndexerDiagnostics, out lengthOrCountAccess); bool foundApplicableIndexerOrSlice = false; if (foundApplicableLengthOrCount) @@ -9363,17 +9336,13 @@ static bool tryBindImplicitIndexerInAnyScope( } } } - } - if (lengthOrCountAccess is not null && indexerOrSliceAccess is not null) - { - Debug.Assert(!argumentPlaceholders.IsDefault); - indexerAccess = binder.MakeImplicitIndexerAccess(syntax, receiver, arguments, receiverPlaceholder, - lengthOrCountAccess, indexerOrSliceAccess, argumentPlaceholders, argKind, implicitIndexerDiagnostics); - } - else - { - indexerAccess = null; + if (lengthOrCountAccess is not null && indexerOrSliceAccess is not null) + { + Debug.Assert(!argumentPlaceholders.IsDefault); + indexerAccess = binder.MakeImplicitIndexerAccess(syntax, receiver, arguments, receiverPlaceholder, + lengthOrCountAccess, indexerOrSliceAccess, argumentPlaceholders, argKind, implicitIndexerDiagnostics); + } } if (foundApplicableLengthOrCount && foundApplicableIndexerOrSlice) @@ -9387,12 +9356,40 @@ static bool tryBindImplicitIndexerInAnyScope( // (the Length/Count and the this[int]/Slice) when each part is searched independently across extension scopes. return foundApplicableLengthOrCount && foundApplicableIndexerOrSlice; } + } + + // Returns true if any applicable candidates + // The caller is responsible to free actualExtensionLengthOrCountArguments + static bool TryBindExtensionLengthOrCountInScope( + SyntaxNode syntax, + BoundValuePlaceholderBase receiver, + Binder binder, + ExtensionScope scope, + ref AnalyzedArguments? actualExtensionLengthOrCountArguments, + out BoundExpression? lengthOrCountAccess, + ref CompoundUseSiteInfo useSiteInfo, + BindingDiagnosticBag diagnostics) + { + lengthOrCountAccess = null; + bool foundApplicable = tryLookupExtensionLengthOrCount(syntax, receiver, binder, scope, ref actualExtensionLengthOrCountArguments, out var lengthOrCountProperty, ref useSiteInfo, diagnostics); + if (foundApplicable) + { + if (lengthOrCountProperty is not null) + { + lengthOrCountProperty.AddUseSiteInfo(ref useSiteInfo); + Debug.Assert(lengthOrCountProperty.ContainingType.ExtensionParameter is not null); + lengthOrCountAccess = binder.GetExtensionMemberAccess(syntax, receiver, lengthOrCountProperty, diagnostics).MakeCompilerGenerated(); + lengthOrCountAccess = binder.CheckValue(lengthOrCountAccess, BindValueKind.RValue, diagnostics); + } + + return true; + } + + return false; - // Returns true if any applicable candidates - // The caller is responsible to free actualExtensionLengthOrCountArguments static bool tryLookupExtensionLengthOrCount( SyntaxNode syntax, - BoundImplicitIndexerReceiverPlaceholder receiver, + BoundValuePlaceholderBase receiver, Binder binder, ExtensionScope scope, ref AnalyzedArguments? actualExtensionLengthOrCountArguments, @@ -9464,7 +9461,46 @@ static bool tryResolveLengthOrCount(BoundExpression receiver, ArrayBuilder useSiteInfo, + BindingDiagnosticBag diagnostics, + out BoundExpression? lengthAccess) + { + var instanceDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics); + bool foundApplicable = TryBindNonExtensionLengthOrCount(node, receiverPlaceholder, out lengthAccess, ref useSiteInfo, instanceDiagnostics); + + if (foundApplicable) + { + diagnostics.AddRangeAndFree(instanceDiagnostics); + return true; + } + + AnalyzedArguments? actualExtensionLengthOrCountArguments = null; + foreach (var scope in new ExtensionScopes(this)) + { + foundApplicable = TryBindExtensionLengthOrCountInScope(node, receiverPlaceholder, binder: this, scope, + ref actualExtensionLengthOrCountArguments, out lengthAccess, ref useSiteInfo, diagnostics); + + if (foundApplicable) + { + if (lengthAccess is null) + { + break; + } + + actualExtensionLengthOrCountArguments?.Free(); + instanceDiagnostics.Free(); + return true; + } + } + actualExtensionLengthOrCountArguments?.Free(); + diagnostics.AddRangeAndFree(instanceDiagnostics); + return false; } // Returns true if any applicable candidates @@ -11309,6 +11345,8 @@ private bool TryBindNonExtensionImplicitIndexerParts( actualExtensionIntIndexerOrSliceArguments?.Free(); } + // We consider this scope to have an applicable implicit indexer if we found applicable candidates for both parts (the Length/Count and the this[int]/Slice). + // If only one parts or no parts are applicable, we'll continue searching further scopes. return lengthOrCountAccess?.HasErrors == false && indexerOrSliceAccess?.HasErrors == false; } @@ -11408,6 +11446,7 @@ private static bool IsValidImplicitIndexIndexer(PropertySymbol property) original.Parameters[0] is { Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.None }; } + // Returns true if any applicable candidates private bool TryBindNonExtensionLengthOrCount( SyntaxNode syntax, BoundValuePlaceholderBase receiverPlaceholder, @@ -11415,6 +11454,23 @@ private bool TryBindNonExtensionLengthOrCount( ref CompoundUseSiteInfo useSiteInfo, BindingDiagnosticBag diagnostics) { + Debug.Assert(receiverPlaceholder.Type is not null); + if (receiverPlaceholder.Type.IsSZArray()) + { + bool foundApplicable = TryGetSpecialTypeMember(Compilation, SpecialMember.System_Array__Length, syntax, diagnostics, out PropertySymbol lengthProperty); + Debug.Assert(foundApplicable == lengthProperty is not null); + if (lengthProperty is not null) + { + lengthOrCountAccess = new BoundPropertyAccess(syntax, receiverPlaceholder, initialBindingReceiverIsSubjectToCloning: ThreeState.False, lengthProperty, autoPropertyAccessorKind: AccessorKind.Unknown, LookupResultKind.Viable, lengthProperty.Type) { WasCompilerGenerated = true }; + } + else + { + lengthOrCountAccess = new BoundBadExpression(syntax, LookupResultKind.Empty, ImmutableArray.Empty, ImmutableArray.Empty, CreateErrorType(), hasErrors: true) { WasCompilerGenerated = true }; + } + + return foundApplicable; + } + var lookupResult = LookupResult.GetInstance(); Debug.Assert(receiverPlaceholder.Type is not null); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs index 32edab2396ea1..2c478ed10772d 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs @@ -573,53 +573,48 @@ private bool IsCountableAndIndexable(SyntaxNode node, TypeSymbol inputType, out } private bool BindLengthAndIndexerForListPattern(SyntaxNode node, TypeSymbol inputType, BindingDiagnosticBag diagnostics, - out BoundExpression indexerAccess, out BoundExpression lengthAccess, out BoundListPatternReceiverPlaceholder? receiverPlaceholder, out BoundListPatternIndexPlaceholder argumentPlaceholder) + out BoundExpression indexerAccess, [NotNull] out BoundExpression? lengthAccess, out BoundListPatternReceiverPlaceholder? receiverPlaceholder, out BoundListPatternIndexPlaceholder argumentPlaceholder) { Debug.Assert(!inputType.IsDynamic()); bool hasErrors = false; receiverPlaceholder = new BoundListPatternReceiverPlaceholder(node, inputType) { WasCompilerGenerated = true }; - if (inputType.IsSZArray()) + var useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); + hasErrors = !TryBindLengthOrCountInAnyScope(node, receiverPlaceholder, ref useSiteInfo, diagnostics, out lengthAccess); + if (lengthAccess is null) { - hasErrors |= !TryGetSpecialTypeMember(Compilation, SpecialMember.System_Array__Length, node, diagnostics, out PropertySymbol lengthProperty); - if (lengthProperty is not null) - { - lengthAccess = new BoundPropertyAccess(node, receiverPlaceholder, initialBindingReceiverIsSubjectToCloning: ThreeState.False, lengthProperty, autoPropertyAccessorKind: AccessorKind.Unknown, LookupResultKind.Viable, lengthProperty.Type) { WasCompilerGenerated = true }; - } - else - { - lengthAccess = new BoundBadExpression(node, LookupResultKind.Empty, ImmutableArray.Empty, ImmutableArray.Empty, CreateErrorType(), hasErrors: true) { WasCompilerGenerated = true }; - } - } - else - { - var useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); - if (!TryBindNonExtensionLengthOrCount(node, receiverPlaceholder, out lengthAccess, ref useSiteInfo, diagnostics)) // PROTOTYPE should extension Length/Count count? - { - hasErrors = true; - Error(diagnostics, ErrorCode.ERR_ListPatternRequiresLength, node, inputType); - } - - diagnostics.Add(node, useSiteInfo); + hasErrors = true; + Error(diagnostics, ErrorCode.ERR_ListPatternRequiresLength, node, inputType); + lengthAccess = new BoundBadExpression(node, LookupResultKind.Empty, symbols: [], childBoundNodes: [], CreateErrorType(), hasErrors: true) { WasCompilerGenerated = true }; } - var analyzedArguments = AnalyzedArguments.GetInstance(); - var systemIndexType = GetWellKnownType(WellKnownType.System_Index, diagnostics, node); - argumentPlaceholder = new BoundListPatternIndexPlaceholder(node, systemIndexType) { WasCompilerGenerated = true }; - analyzedArguments.Arguments.Add(argumentPlaceholder); + diagnostics.Add(node, useSiteInfo); - indexerAccess = BindElementAccessCore(node, receiverPlaceholder, analyzedArguments, diagnostics).MakeCompilerGenerated(); - indexerAccess = CheckValue(indexerAccess, BindValueKind.RValue, diagnostics); - Debug.Assert(indexerAccess is BoundIndexerAccess or BoundImplicitIndexerAccess or BoundArrayAccess or BoundBadExpression or BoundDynamicIndexerAccess or BoundPointerElementAccess); - analyzedArguments.Free(); + hasErrors |= !tryBindIndexIndexer(receiverPlaceholder, out indexerAccess, out argumentPlaceholder, diagnostics, node); + return !hasErrors && !lengthAccess.HasErrors; - if (!systemIndexType.HasUseSiteError) + bool tryBindIndexIndexer(BoundListPatternReceiverPlaceholder receiverPlaceholder, out BoundExpression indexerAccess, + out BoundListPatternIndexPlaceholder argumentPlaceholder, BindingDiagnosticBag diagnostics, + SyntaxNode node) { - // Check required well-known member. - _ = GetWellKnownTypeMember(WellKnownMember.System_Index__ctor, diagnostics, syntax: node); - } + var analyzedArguments = AnalyzedArguments.GetInstance(); + var systemIndexType = GetWellKnownType(WellKnownType.System_Index, diagnostics, node); + argumentPlaceholder = new BoundListPatternIndexPlaceholder(node, systemIndexType) { WasCompilerGenerated = true }; + analyzedArguments.Arguments.Add(argumentPlaceholder); - return !hasErrors && !lengthAccess.HasErrors && !indexerAccess.HasErrors; + indexerAccess = BindElementAccessCore(node, receiverPlaceholder, analyzedArguments, diagnostics).MakeCompilerGenerated(); + indexerAccess = CheckValue(indexerAccess, BindValueKind.RValue, diagnostics); + Debug.Assert(indexerAccess is BoundIndexerAccess or BoundImplicitIndexerAccess or BoundArrayAccess or BoundBadExpression or BoundDynamicIndexerAccess or BoundPointerElementAccess); + analyzedArguments.Free(); + + if (!systemIndexType.HasUseSiteError) + { + // Check required well-known member. + _ = GetWellKnownTypeMember(WellKnownMember.System_Index__ctor, diagnostics, syntax: node); + } + + return !indexerAccess.HasErrors; + } } private static BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSymbol inputType, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs index 8f15b68202513..ded1ad35a6a20 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Roslyn.Utilities; @@ -365,17 +366,42 @@ private void VisitBinaryOperatorChildren(BoundBinaryOperatorBase node) { VisitList(node.Subpatterns); Visit(node.VariableAccess); - // Ignore indexer access (just a node to hold onto some symbols) + if (!node.HasErrors && + node.Subpatterns.Any(static (BoundPattern p) => p.Kind != BoundKind.SlicePattern)) + { + VisitExtensionIndexerArguments(node.IndexerAccess); + } return null; } public override BoundNode? VisitSlicePattern(BoundSlicePattern node) { this.Visit(node.Pattern); - // Ignore indexer access (just a node to hold onto some symbols) + VisitExtensionIndexerArguments(node.IndexerAccess); return null; } + private void VisitExtensionIndexerArguments(BoundExpression? indexerAccess) + { + if (indexerAccess is BoundImplicitIndexerAccess implicitAccess) + { + indexerAccess = implicitAccess.IndexerOrSliceAccess; + } + + // We only need to visit arguments for extension block members because + // the nullability analysis for list and slice patterns only visits arguments + // for extension indexers. + switch (indexerAccess) + { + case BoundIndexerAccess { Indexer: { } indexer } ia when indexer.IsExtensionBlockMember(): + VisitList(ia.Arguments); + break; + case BoundCall { Method: { } method } call when method.IsExtensionBlockMember(): + VisitList(call.Arguments); + break; + } + } + public override BoundNode? VisitSwitchExpressionArm(BoundSwitchExpressionArm node) { this.Visit(node.Pattern); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 52260909fea90..52705d44d598a 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -7454,6 +7454,12 @@ or BoundDagPropertyEvaluation return true; } + if (node is BoundCall && node.Syntax is SlicePatternSyntax) + { + // A Slice call + return true; + } + var syntax = node.Syntax; if (syntax.Kind() != SyntaxKind.InvocationExpression) { diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs index d0ff4bfbaa426..8ec25b209999c 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs @@ -511,7 +511,7 @@ public PossiblyConditionalState Clone() var output = e.MakeResultTemp(); var outputSlot = getOrMakeAndRegisterDagTempSlot(output); Debug.Assert(outputSlot > 0); - SetState(ref this.State, outputSlot, NullableFlowState.NotNull); // Slice value is assumed to be never null + TrackNullableStateForAssignment(valueOpt: null, type, outputSlot, type.ToTypeWithState()); break; } case BoundDagAssignmentEvaluation e: @@ -976,8 +976,29 @@ TypeWithAnnotations getIndexerOutputType(TypeSymbol inputType, BoundExpression e return property.GetTypeOrReturnType(); case BoundCall call: - Debug.Assert(!call.Method.IsExtensionBlockMember()); - return AsMemberOfType(inputType, call.Method).GetTypeOrReturnType(); + MethodSymbol method; + if (call.Method.IsExtensionBlockMember()) + { + var reinferenceResult = ReInferMethodAndVisitArguments( + e, + receiverOpt: new BoundExpressionWithNullability(e.Syntax, expression, NullableAnnotation.NotAnnotated, inputType), + receiverType: TypeWithState.Create(inputType, NullableFlowState.NotNull), + call.Method, + call.Arguments, + call.ArgumentRefKindsOpt, + call.ArgsToParamsOpt, + call.DefaultArguments, + call.Expanded, + call.InvokedAsExtensionMethod); + + method = reinferenceResult.Member; + } + else + { + method = (MethodSymbol)AsMemberOfType(inputType, call.Method); + } + + return method.GetTypeOrReturnType(); case BoundArrayAccess arrayAccess: return isSlice diff --git a/src/Compilers/CSharp/Test/CSharp15/ExtensionIndexersTests.cs b/src/Compilers/CSharp/Test/CSharp15/ExtensionIndexersTests.cs index f6f9451fa4934..b827225b6ef6e 100644 --- a/src/Compilers/CSharp/Test/CSharp15/ExtensionIndexersTests.cs +++ b/src/Compilers/CSharp/Test/CSharp15/ExtensionIndexersTests.cs @@ -6326,6 +6326,7 @@ class C { } // _ = c[1..^1]; Diagnostic(ErrorCode.ERR_BadIndexLHS, "c[1..^1]").WithArguments("C").WithLocation(2, 5)); } + [Fact] public void ImplicitRangeIndexer_32() { @@ -6782,6 +6783,163 @@ class C CompileAndVerify(comp, expectedOutput: ExpectedOutput("instLength slice(0, 4) ok"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82756")] + public void ImplicitRangeIndexer_42() + { + // array type, extension this[Index] + extension this[Range] + var src = """ +public static class E +{ + public static void Main() + { + int[] i = [1, 2, 3]; + M1(i); + M2(i); + } + + public static void M1(int[] i) + { + System.Console.Write(i[^1]); + } + + public static void M2(int[] i) + { + System.Console.Write(i[1..^1][0]); + } + + extension(int[] a) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get => throw null; } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("32"), verify: Verification.Skipped).VerifyDiagnostics(); + verifier.VerifyIL("E.M1", """ +{ + // Code size 15 (0xf) + .maxstack 3 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: dup + IL_0003: ldlen + IL_0004: conv.i4 + IL_0005: ldc.i4.1 + IL_0006: sub + IL_0007: ldelem.i4 + IL_0008: call "void System.Console.Write(int)" + IL_000d: nop + IL_000e: ret +} +"""); + verifier.VerifyIL("E.M2", """ +{ + // Code size 34 (0x22) + .maxstack 4 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.1 + IL_0003: call "System.Index System.Index.op_Implicit(int)" + IL_0008: ldc.i4.1 + IL_0009: ldc.i4.1 + IL_000a: newobj "System.Index..ctor(int, bool)" + IL_000f: newobj "System.Range..ctor(System.Index, System.Index)" + IL_0014: call "int[] System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray(int[], System.Range)" + IL_0019: ldc.i4.0 + IL_001a: ldelem.i4 + IL_001b: call "void System.Console.Write(int)" + IL_0020: nop + IL_0021: ret +} +"""); + + // Tracked by https://github.com/dotnet/roslyn/issues/82756 + // Missing diagnostic for missing Array.Length member + comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.MakeMemberMissing(SpecialMember.System_Array__Length); + comp.VerifyEmitDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82756")] + public void ImplicitRangeIndexer_43() + { + // array type, extension Length + extension this[Index] + extension this[Range] + var src = """ +public static class E +{ + public static void Main() + { + int[] i = [1, 2, 3]; + M1(i); + M2(i); + } + + public static void M1(int[] i) + { + System.Console.Write(i[^1]); + } + + public static void M2(int[] i) + { + System.Console.Write(i[1..^1][0]); + } + + extension(int[] a) + { + public int Length => throw null; + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get => throw null; } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("32"), verify: Verification.Skipped).VerifyDiagnostics(); + + comp = CreateCompilation(src, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + comp.MakeMemberMissing(SpecialMember.System_Array__Length); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("32"), verify: Verification.Skipped).VerifyDiagnostics(); + verifier.VerifyIL("E.M1", """ +{ + // Code size 15 (0xf) + .maxstack 3 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: dup + IL_0003: ldlen + IL_0004: conv.i4 + IL_0005: ldc.i4.1 + IL_0006: sub + IL_0007: ldelem.i4 + IL_0008: call "void System.Console.Write(int)" + IL_000d: nop + IL_000e: ret +} +"""); + verifier.VerifyIL("E.M2", """ +{ + // Code size 34 (0x22) + .maxstack 4 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.1 + IL_0003: call "System.Index System.Index.op_Implicit(int)" + IL_0008: ldc.i4.1 + IL_0009: ldc.i4.1 + IL_000a: newobj "System.Index..ctor(int, bool)" + IL_000f: newobj "System.Range..ctor(System.Index, System.Index)" + IL_0014: call "int[] System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray(int[], System.Range)" + IL_0019: ldc.i4.0 + IL_001a: ldelem.i4 + IL_001b: call "void System.Console.Write(int)" + IL_0020: nop + IL_0021: ret +} +"""); + } + [Fact] public void ObjectInitializer_01() { @@ -6912,28 +7070,15 @@ public static class E var comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [.., 1]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.., 1]").WithArguments("C").WithLocation(1, 16), // (1,16): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // _ = new C() is [.., 1]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "[.., 1]").WithArguments("extension indexers").WithLocation(1, 16)); - // PROTOTYPE where should extension Length/Count count? comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [.., 1]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.., 1]").WithArguments("C").WithLocation(1, 16)); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); - comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); - comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [.., 1]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.., 1]").WithArguments("C").WithLocation(1, 16), - // (8,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(8, 20)); + comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] @@ -7070,67 +7215,12 @@ public static class E CompileAndVerify(comp, expectedOutput: ExpectedOutput("(^1, 42)"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } - [Theory, CombinatorialData] - public void SpreadPattern_01(bool useCompilationReference) - { - var libSrc = """ -public class C { } - -public static class E -{ - extension(C c) - { - public int Length => 3; - public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } - public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } - } -} -"""; - var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net70); - var libRef = AsReference(libComp, useCompilationReference); - - var src = """ -_ = new C() is [_, .. var x]; -"""; - - var comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); - comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [_, .. var x]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[_, .. var x]").WithArguments("C").WithLocation(1, 16), - // (1,16): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = new C() is [_, .. var x]; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "[_, .. var x]").WithArguments("extension indexers").WithLocation(1, 16), - // (1,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = new C() is [_, .. var x]; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ".. var x").WithArguments("extension indexers").WithLocation(1, 20)); - - // PROTOTYPE where should extension Length/Count count? - comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [_, .. var x]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[_, .. var x]").WithArguments("C").WithLocation(1, 16)); - - comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); - comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [_, .. var x]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[_, .. var x]").WithArguments("C").WithLocation(1, 16), - // (8,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(8, 20), - // (9,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(9, 20)); - } - [Fact] - public void SpreadPattern_02() + public void ListPattern_05() { - // boxed receiver + // instance Length, extension Length + extension this[int] var src = """ -_ = new S() is [_, .. var x]; +_ = new S() is [.., 1]; public struct S { @@ -7141,808 +7231,2670 @@ public static class E { extension(object o) { - public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } - public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } + public int Length => throw null; // only used to fulfill the requirement for implicit indexer + public int this[int i] { get { System.Console.WriteLine(i); return 0; } } } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("2"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("", """ { - // Code size 55 (0x37) - .maxstack 4 - .locals init (S V_0) + // Code size 42 (0x2a) + .maxstack 3 + .locals init (S V_0, + int V_1) IL_0000: ldloca.s V_0 IL_0002: initobj "S" IL_0008: ldloca.s V_0 IL_000a: call "int S.Length.get" - IL_000f: ldc.i4.1 - IL_0010: blt.s IL_0034 - IL_0012: ldloc.0 - IL_0013: box "S" - IL_0018: ldc.i4.1 - IL_0019: ldc.i4.0 - IL_001a: newobj "System.Index..ctor(int, bool)" - IL_001f: ldc.i4.0 - IL_0020: ldc.i4.1 - IL_0021: newobj "System.Index..ctor(int, bool)" - IL_0026: newobj "System.Range..ctor(System.Index, System.Index)" - IL_002b: call "int E.get_Item(object, System.Range)" - IL_0030: pop - IL_0031: ldc.i4.1 - IL_0032: br.s IL_0035 - IL_0034: ldc.i4.0 - IL_0035: pop - IL_0036: ret + IL_000f: stloc.1 + IL_0010: ldloc.1 + IL_0011: ldc.i4.1 + IL_0012: blt.s IL_0027 + IL_0014: ldloc.0 + IL_0015: box "S" + IL_001a: ldloc.1 + IL_001b: ldc.i4.1 + IL_001c: sub + IL_001d: call "int E.get_Item(object, int)" + IL_0022: ldc.i4.1 + IL_0023: ceq + IL_0025: br.s IL_0028 + IL_0027: ldc.i4.0 + IL_0028: pop + IL_0029: ret } """); } - [Theory, CombinatorialData] - public void ConditionalAssignment_01(bool useCompilationReference) + [Fact] + public void ListPattern_06() { - var libSrc = """ -public class C { } + // instance Length, extension this[int] + var src = """ +_ = new S() is [.., 1]; + +public struct S +{ + public int Length => 3; +} public static class E { - extension(C c) + extension(object o) { - public int this[int i] - { - set { System.Console.WriteLine($"set_Item({i} {value})"); } - } + public int this[int i] { get { System.Console.WriteLine(i); return 1; } } } } """; - var libComp = CreateCompilation(libSrc); - var libRef = AsReference(libComp, useCompilationReference); - - var src = """ -C c = null; -c?[42] = 0; - -c = new C(); -c?[43] = 100; -"""; - - var comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); - comp.VerifyEmitDiagnostics( - // (2,3): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // c?[42] = 0; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "[42]").WithArguments("extension indexers").WithLocation(2, 3), - // (5,3): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // c?[43] = 100; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "[43]").WithArguments("extension indexers").WithLocation(5, 3)); - - comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.RegularNext); - comp.VerifyEmitDiagnostics(); - - comp = CreateCompilation(src, references: [libRef]); - CompileAndVerify(comp, expectedOutput: "set_Item(43 100)").VerifyDiagnostics(); - comp = CreateCompilation([src, libSrc], parseOptions: TestOptions.Regular14); - comp.VerifyEmitDiagnostics( - // (7,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public int this[int i] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(7, 20)); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("2"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] - public void ConditionalAssignment_02() + public void ListPattern_07() { - // nullable value type receiver + // ambiguous extension Length + extension this[int] var src = """ -E.Test(null, 42, 0); -E.Test(new S(), 43, 100); +_ = new S() is [.., 1]; public struct S { } -public static class E +public static class E1 { - public static void Test(S? s, int index, int value) + extension(object o) { - s?[index] = value; + public int Length => 3; + public int this[int i] { get => throw null; } } +} - extension(S s) +public static class E2 +{ + extension(object o) { - public int this[int i] - { - set { System.Console.WriteLine($"set_Item({i} {value})"); } - } + public int Length => 3; } } """; - // Tracked by https://github.com/dotnet/roslyn/issues/79451 : consider adjusting receiver requirements for extension members - var comp = CreateCompilation(src); + // PROTOTYPE diagnostic quality, consider improving the second diagnostic to mention System.Index + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (10,11): error CS0131: The left-hand side of an assignment must be a variable, property or indexer - // s?[index] = value; - Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "[index]").WithLocation(10, 11)); - - //var verifier = CompileAndVerify(comp, expectedOutput: "set_Item(43 100)").VerifyDiagnostics(); - //verifier.VerifyIL("E.Test", ""); + // (1,16): error CS8985: List patterns may not be used for a value of type 'S'. No suitable 'Length' or 'Count' property was found. + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.., 1]").WithArguments("S").WithLocation(1, 16), + // (1,16): error CS0021: Cannot apply indexing with [] to an expression of type 'S' + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[.., 1]").WithArguments("S").WithLocation(1, 16)); } - [Theory, CombinatorialData] - public void ConditionalAccess_01(bool useCompilationReference) + [Fact] + public void ListPattern_08() { - var libSrc = """ -public class C { } + // extension Length + ambiguous extension this[int] + var src = """ +_ = new S() is [.., 1]; -public static class E +public struct S { } + +public static class E1 { - extension(C c) + extension(object o) { - public int this[int i] - { - get { System.Console.Write($" get_Item({i}) "); return 100; } - } + public int Length => 3; + public int this[int i] { get => throw null; } } } -"""; - - var libComp = CreateCompilation(libSrc); - var libRef = AsReference(libComp, useCompilationReference); - - var src = """ -C c = null; -System.Console.Write(c?[42] is null); -c = new C(); -System.Console.Write(c?[43] is 100); +public static class E2 +{ + extension(object o) + { + public int this[int i] { get => throw null; } + } +} """; - var comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); - comp.VerifyEmitDiagnostics( - // (2,24): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // System.Console.Write(c?[42] is null); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "[42]").WithArguments("extension indexers").WithLocation(2, 24), - // (5,24): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // System.Console.Write(c?[43] is 100); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "[43]").WithArguments("extension indexers").WithLocation(5, 24)); - - comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.RegularNext); - comp.VerifyEmitDiagnostics(); - - comp = CreateCompilation(src, references: [libRef]); - CompileAndVerify(comp, expectedOutput: "True get_Item(43) True").VerifyDiagnostics(); - - comp = CreateCompilation([src, libSrc], parseOptions: TestOptions.Regular14); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (7,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public int this[int i] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(7, 20)); + // (1,16): error CS0021: Cannot apply indexing with [] to an expression of type 'S' + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[.., 1]").WithArguments("S").WithLocation(1, 16)); } [Fact] - public void ConditionalAccess_02() + public void ListPattern_09() { - // nullable value type receiver + // instance Length + ambiguous extension this[Index] var src = """ -System.Console.Write(E.Test(null, 42) is null); - -System.Console.Write(E.Test(new S(), 43) is 100); +_ = new S() is [.., 1]; -public struct S { } +public struct S +{ + public int Length => 3; +} -public static class E +public static class E1 { - public static int? Test(S? s, int index) + extension(object o) { - return s?[index]; + public int this[System.Index i] { get => throw null; } } +} - extension(S s) +public static class E2 +{ + extension(object o) { - public int this[int i] - { - get { System.Console.Write($" get_Item({i}) "); return 100; } - } + public int this[System.Index i] { get => throw null; } } } """; - var comp = CreateCompilation(src); - var verifier = CompileAndVerify(comp, expectedOutput: "True get_Item(43) True").VerifyDiagnostics(); - verifier.VerifyIL("E.Test", """ -{ - // Code size 38 (0x26) - .maxstack 2 - .locals init (int? V_0) - IL_0000: ldarga.s V_0 - IL_0002: call "bool S?.HasValue.get" - IL_0007: brtrue.s IL_0013 - IL_0009: ldloca.s V_0 - IL_000b: initobj "int?" - IL_0011: ldloc.0 - IL_0012: ret - IL_0013: ldarga.s V_0 - IL_0015: call "S S?.GetValueOrDefault()" - IL_001a: ldarg.1 - IL_001b: call "int E.get_Item(S, int)" - IL_0020: newobj "int?..ctor(int)" - IL_0025: ret -} -"""); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,16): error CS0021: Cannot apply indexing with [] to an expression of type 'S' + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[.., 1]").WithArguments("S").WithLocation(1, 16)); } [Fact] - public void Nameof_01() + public void ListPattern_10() { + // extension Length + instance this[Index] var src = """ -object o = new object(); -_ = nameof(o[0]); +_ = new S() is [.., 1]; + +public struct S +{ + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } +} public static class E { extension(object o) { - public int this[int i] => 0; + public int Length => 3; } } """; - CreateCompilation(src).VerifyEmitDiagnostics( - // (2,12): error CS8081: Expression does not have a name. - // _ = nameof(o[0]); - Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "o[0]").WithLocation(2, 12)); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] - public void Nameof_02() + public void ListPattern_11() { - // setter-only indexer + // ambiguous extension Length + ambiguous extension this[int] var src = """ -object o = new object(); -_ = nameof(o[0]); +_ = new S() is [.., 1]; -public static class E +public struct S { } + +public static class E1 { extension(object o) { - public int this[int i] { set { } } + public int Length => 3; + public int this[int i] { get => throw null; } + } +} + +public static class E2 +{ + extension(object o) + { + public int Length => 3; + public int this[int i] { get => throw null; } } } """; - CreateCompilation(src).VerifyEmitDiagnostics( - // (2,12): error CS8081: Expression does not have a name. - // _ = nameof(o[0]); - Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "o[0]").WithLocation(2, 12), - // (2,12): error CS0154: The property or indexer 'E.extension(object).this[int]' cannot be used in this context because it lacks the get accessor - // _ = nameof(o[0]); - Diagnostic(ErrorCode.ERR_PropertyLacksGet, "o[0]").WithArguments("E.extension(object).this[int]").WithLocation(2, 12)); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,16): error CS8985: List patterns may not be used for a value of type 'S'. No suitable 'Length' or 'Count' property was found. + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.., 1]").WithArguments("S").WithLocation(1, 16), + // (1,16): error CS0021: Cannot apply indexing with [] to an expression of type 'S' + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[.., 1]").WithArguments("S").WithLocation(1, 16)); } [Fact] - public void ORPA_01() + public void ListPattern_12() { - var source = """ -_ = 42[43]; + // ambiguous extension Length + ambiguous extension this[Index] + var src = """ +_ = new S() is [.., 1]; -static class E +public struct S { } + +public static class E1 { - extension(int i) + extension(object o) { - public int this[int j] => throw null; + public int Length => 3; + public int this[System.Index i] { get => throw null; } + } +} - [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - public int this[long l] { get { System.Console.Write("ran"); return 0; } } +public static class E2 +{ + extension(object o) + { + public int Length => 3; + public int this[System.Index i] { get => throw null; } } } """; - var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); - CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,16): error CS8985: List patterns may not be used for a value of type 'S'. No suitable 'Length' or 'Count' property was found. + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.., 1]").WithArguments("S").WithLocation(1, 16), + // (1,16): error CS0021: Cannot apply indexing with [] to an expression of type 'S' + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[.., 1]").WithArguments("S").WithLocation(1, 16)); } [Fact] - public void ORPA_02() + public void ListPattern_13() { - var source = """ -_ = 42[43]; + // generic extension Length + generic extension this[Index] + var src = """ +_ = new S() is [.., 1]; -static class E +public struct S { } + +public static class E { - extension(int i) + extension(T t) { - [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - public int this[int j] { get { System.Console.Write("ran"); return 0; } } - - public int this[long l] => throw null; + public int Length => 3; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } """; - var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); - CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] - public void ORPA_03() + public void ListPattern_14() { - var source = """ -_ = 42[43]; + // separate generic extension Length + generic extension this[Index] + var src = """ +_ = new S() is [.., 1]; -static class E1 +public struct S { } + +public static class E1 { - extension(int i) + extension(T t) { - public int this[int j] { get { System.Console.Write("ran"); return 0; } } + public int Length => 3; } } -static class E2 +public static class E2 { - extension(int i) + extension(T t) { - [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] - public int this[long l] => throw null; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } """; - var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); - CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] - public void Metadata_01() + public void ListPattern_15() { - var source = """ + // extension Length + var src = """ +_ = new S() is [.., 1]; + +public struct S { } + public static class E { - extension(int i) + extension(object o) { - public int this[int j] { get { return 42; } } + public int Length => 3; } } """; - var comp = CreateCompilation(source); - var verifier = CompileAndVerify(comp).VerifyDiagnostics(); - verifier.VerifyTypeIL("E", """ -.class public auto ansi abstract sealed beforefieldinit E - extends [netstandard]System.Object + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,16): error CS0021: Cannot apply indexing with [] to an expression of type 'S' + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[.., 1]").WithArguments("S").WithLocation(1, 16)); + } + + [Fact] + public void ListPattern_16() + { + // instance Length, inner extension Length, outer extension this[int] + var src = """ +using Outer; + +namespace Inner { - .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( - 01 00 00 00 - ) - // Nested Types - .class nested public auto ansi sealed specialname '$BA41CFE2B5EDAEB8C1B9062F59ED4D69' - extends [netstandard]System.Object + public class C { - .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( - 01 00 00 00 - ) - .custom instance void [netstandard]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( - 01 00 04 49 74 65 6d 00 00 - ) - // Nested Types - .class nested public auto ansi abstract sealed specialname '$F4B4FFE41AB49E80A4ECF390CF6EB372' - extends [netstandard]System.Object + public static void Main() { - // Methods - .method public hidebysig specialname static - void '$' ( - int32 i - ) cil managed - { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Method begins at RVA 0x2089 - // Code size 1 (0x1) - .maxstack 8 - IL_0000: ret - } // end of method '$F4B4FFE41AB49E80A4ECF390CF6EB372'::'$' - } // end of class $F4B4FFE41AB49E80A4ECF390CF6EB372 - // Methods - .method public hidebysig specialname - instance int32 get_Item ( - int32 j - ) cil managed + _ = new S() is [.., 1]; + } + } + + public static class E1 + { + extension(object o) { - .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( - 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 - 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 - 46 36 45 42 33 37 32 00 00 - ) - // Method begins at RVA 0x2082 - // Code size 6 (0x6) - .maxstack 8 - IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() - IL_0005: throw - } // end of method '$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_Item - // Properties - .property instance int32 Item( - int32 j - ) + public int Length => throw null; + } + } +} + +public struct S +{ + public int Length => 3; +} + + +namespace Outer +{ + public static class E2 + { + extension(object o) { - .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( - 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 - 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 - 46 36 45 42 33 37 32 00 00 - ) - .get instance int32 E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_Item(int32) + public int this[int i] { get { System.Console.WriteLine(i); return 1; } } } - } // end of class $BA41CFE2B5EDAEB8C1B9062F59ED4D69 - // Methods - .method public hidebysig static - int32 get_Item ( - int32 i, - int32 j - ) cil managed + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("2"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void ListPattern_17() { - // Method begins at RVA 0x207e - // Code size 3 (0x3) - .maxstack 8 - IL_0000: ldc.i4.s 42 - IL_0002: ret - } // end of method E::get_Item -} // end of class E -""".Replace("[netstandard]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + // instance Length, inner extension Length, extension this[Index] + var src = """ +using Outer; + +public struct S +{ + public int Length => 3; +} + +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.., 1]; + } } - [Theory, CombinatorialData] - public void Metadata_02(bool useCompilationReference) + public static class E1 { - var libSrc = """ -public static class E + extension(object o) + { + public int Length => throw null; + } + } +} + +namespace Outer { - extension(int i) + public static class E2 { - public int this[int j] + extension(object o) { - get { System.Console.Write($"get({j}) "); return 42; } - set { System.Console.Write($"set({j}, {value}) "); } + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } } """; - var libComp = CreateCompilation(libSrc); - var libRef = AsReference(libComp, useCompilationReference); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void ListPattern_18() + { + // instance Length, inner ambiguous extension Length, outer extension this[Index] var src = """ -int i = 0; -_ = i[43]; -i[101] = 102; -"""; - var comp = CreateCompilation(src, [libRef]); - CompileAndVerify(comp, expectedOutput: "get(43) set(101, 102)").VerifyDiagnostics(); +using Outer; - var indexer = comp.GlobalNamespace.GetTypeMember("E").GetTypeMember("").GetMembers().OfType().Single(); - AssertEx.Equal("E.extension(int).this[int]", indexer.ToDisplayString()); - Assert.True(indexer.IsIndexer); - AssertEx.Equal("E.extension(int).this[int].get", indexer.GetMethod.ToDisplayString()); - AssertEx.Equal("E.extension(int).this[int].set", indexer.SetMethod.ToDisplayString()); +public struct S +{ + public int Length => 3; +} - comp = CreateCompilation(src, [libRef], parseOptions: TestOptions.Regular14); - comp.VerifyEmitDiagnostics( - // (2,5): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // _ = i[43]; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "i[43]").WithArguments("extension indexers").WithLocation(2, 5), - // (3,1): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // i[101] = 102; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "i[101]").WithArguments("extension indexers").WithLocation(3, 1)); +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.., 1]; + } } - [Theory, CombinatorialData] - public void Metadata_03(bool useCompilationReference) + public static class E1 { - // IndexerName attribute on single indexer - var libSrc = """ -public static class E + extension(object o) + { + public int Length => throw null; + } + } + + public static class E2 + { + extension(object o) + { + public int Length => throw null; + } + } +} + +namespace Outer { - extension(int i) + public static class E3 { - [System.Runtime.CompilerServices.IndexerName("MyIndexer")] - public int this[int j] + extension(object o) { - get { System.Console.Write($"get({j}) "); return 42; } - set { System.Console.Write($"set({j}, {value}) "); } + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } } """; - var libComp = CreateCompilation(libSrc); - var verifier = CompileAndVerify(libComp).VerifyDiagnostics(); - verifier.VerifyTypeIL("E", """ -.class public auto ansi abstract sealed beforefieldinit E - extends [netstandard]System.Object + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void ListPattern_19() + { + // instance Length, inner ambiguous extension Length + extension this[int], outer extension this[Index] + var src = """ +using Outer; + +public struct S { - .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( - 01 00 00 00 - ) - // Nested Types - .class nested public auto ansi sealed specialname '$BA41CFE2B5EDAEB8C1B9062F59ED4D69' - extends [netstandard]System.Object + public int Length => 3; +} + +namespace Inner +{ + public class C { - .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( - 01 00 00 00 - ) - .custom instance void [netstandard]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( - 01 00 09 4d 79 49 6e 64 65 78 65 72 00 00 - ) - // Nested Types - .class nested public auto ansi abstract sealed specialname '$F4B4FFE41AB49E80A4ECF390CF6EB372' - extends [netstandard]System.Object + public static void Main() { - // Methods - .method public hidebysig specialname static - void '$' ( - int32 i - ) cil managed - { - .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Method begins at RVA 0x20bb - // Code size 1 (0x1) - .maxstack 8 - IL_0000: ret - } // end of method '$F4B4FFE41AB49E80A4ECF390CF6EB372'::'$' - } // end of class $F4B4FFE41AB49E80A4ECF390CF6EB372 - // Methods - .method public hidebysig specialname - instance int32 get_MyIndexer ( - int32 j - ) cil managed + _ = new S() is [.., 1]; + } + } + + public static class E1 + { + extension(object o) { - .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( - 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 - 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 - 46 36 45 42 33 37 32 00 00 - ) - // Method begins at RVA 0x20b4 - // Code size 6 (0x6) - .maxstack 8 - IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() - IL_0005: throw - } // end of method '$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_MyIndexer - .method public hidebysig specialname - instance void set_MyIndexer ( - int32 j, - int32 'value' - ) cil managed - { - .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( - 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 - 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 - 46 36 45 42 33 37 32 00 00 - ) - // Method begins at RVA 0x20b4 - // Code size 6 (0x6) - .maxstack 8 - IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() - IL_0005: throw - } // end of method '$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_MyIndexer - // Properties - .property instance int32 MyIndexer( - int32 j - ) - { - .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( - 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 - 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 - 46 36 45 42 33 37 32 00 00 - ) - .get instance int32 E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_MyIndexer(int32) - .set instance void E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_MyIndexer(int32, int32) + public int Length => throw null; } - } // end of class $BA41CFE2B5EDAEB8C1B9062F59ED4D69 - // Methods - .method public hidebysig static - int32 get_MyIndexer ( - int32 i, - int32 j - ) cil managed - { - // Method begins at RVA 0x207e - // Code size 24 (0x18) - .maxstack 8 - IL_0000: ldstr "get({0}) " - IL_0005: ldarg.1 - IL_0006: box [netstandard]System.Int32 - IL_000b: call string [netstandard]System.String::Format(string, object) - IL_0010: call void [netstandard]System.Console::Write(string) - IL_0015: ldc.i4.s 42 - IL_0017: ret - } // end of method E::get_MyIndexer - .method public hidebysig static - void set_MyIndexer ( - int32 i, - int32 j, - int32 'value' - ) cil managed - { - // Method begins at RVA 0x2097 - // Code size 28 (0x1c) - .maxstack 8 - IL_0000: ldstr "set({0}, {1}) " - IL_0005: ldarg.1 - IL_0006: box [netstandard]System.Int32 - IL_000b: ldarg.2 - IL_000c: box [netstandard]System.Int32 - IL_0011: call string [netstandard]System.String::Format(string, object, object) - IL_0016: call void [netstandard]System.Console::Write(string) - IL_001b: ret - } // end of method E::set_MyIndexer -} // end of class E -""".Replace("[netstandard]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); - - var src = """ -int i = 0; -_ = i[43]; -i[101] = 102; - -E.get_MyIndexer(i, 43); -E.set_MyIndexer(i, 101, 102); -"""; - var comp = CreateCompilation(src, [AsReference(libComp, useCompilationReference)]); - CompileAndVerify(comp, expectedOutput: "get(43) set(101, 102) get(43) set(101, 102)").VerifyDiagnostics(); - - var indexer = comp.GlobalNamespace.GetTypeMember("E").GetTypeMember("").GetMembers().OfType().Single(); - AssertEx.Equal("E.extension(int).this[int]", indexer.ToDisplayString()); - Assert.True(indexer.IsIndexer); - AssertEx.Equal("E.extension(int).this[int].get", indexer.GetMethod.ToDisplayString()); - AssertEx.Equal("E.extension(int).this[int].set", indexer.SetMethod.ToDisplayString()); } - [Theory, CombinatorialData] - public void Metadata_04(bool useCompilationReference) - { - // Matching IndexerName attributes on both indexers - var libSrc = """ -public static class E -{ - extension(int i) + public static class E2 { - [System.Runtime.CompilerServices.IndexerName("MyIndexer")] - public int this[int j] + extension(object o) { - get { System.Console.Write($"get({j}) "); return 42; } - set { System.Console.Write($"set({j}, {value}) "); } + public int Length => throw null; + public int this[int i] { get { System.Console.WriteLine(i); return 0; } } } + } +} - [System.Runtime.CompilerServices.IndexerName("MyIndexer")] - public int this[string s] +namespace Outer +{ + public static class E3 + { + extension(object o) { - get { System.Console.Write($"get2({s}) "); return 42; } - set { System.Console.Write($"set2({s}, {value}) "); } + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } } """; - var libComp = CreateCompilation(libSrc); - var verifier = CompileAndVerify(libComp).VerifyDiagnostics(); - - var src = """ -int i = 0; -_ = i[43]; -i[101] = 102; - -E.get_MyIndexer(i, 43); -E.set_MyIndexer(i, 101, 102); -_ = i["A"]; -i["B"] = 102; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } -E.get_MyIndexer(i, "A"); -E.set_MyIndexer(i, "B", 102); -"""; - var comp = CreateCompilation(src, [AsReference(libComp, useCompilationReference)]); - CompileAndVerify(comp, expectedOutput: "get(43) set(101, 102) get(43) set(101, 102) get2(A) set2(B, 102) get2(A) set2(B, 102)").VerifyDiagnostics(); + [Fact] + public void ListPattern_20() + { + // instance Length, inner extension Length + ambiguous extension this[int], outer extension this[Index] + var src = """ +using Outer; - var indexers = comp.GlobalNamespace.GetTypeMember("E").GetTypeMember("").GetMembers().OfType().ToArray(); - AssertEx.Equal("E.extension(int).this[int]", indexers[0].ToDisplayString()); - Assert.True(indexers[0].IsIndexer); +public struct S +{ + public int Length => 3; +} - AssertEx.Equal("E.extension(int).this[string]", indexers[1].ToDisplayString()); - Assert.True(indexers[1].IsIndexer); +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.., 1]; + } } - [Fact] - public void IndexerName_01() + public static class E1 { - // IndexerName attribute on one of the indexers - var source = """ -public static class E -{ - extension((int a, int b) t) + extension(object o) + { + public int Length => throw null; + public int this[int i] { get => throw null; } + } + } + + public static class E2 { - public int this[string s] + extension(object o) { - get => throw null; - set => throw null; + public int this[int i] { get => throw null; } } } +} - extension((int c, int d) t) +namespace Outer +{ + public static class E3 { - [System.Runtime.CompilerServices.IndexerName("MyIndexer")] - public int this[int j] + extension(object o) { - get => throw null; - set => throw null; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } } """; - CreateCompilation(source).VerifyEmitDiagnostics( - // (15,20): error CS0668: Two indexers have different names; the IndexerName attribute must be used with the same name on every indexer within a type - // public int this[int j] - Diagnostic(ErrorCode.ERR_InconsistentIndexerNames, "this").WithLocation(15, 20)); + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] - public void IndexerName_02() + public void ListPattern_21() { - // IndexerName attribute uses same name as extension parameter - var source = """ -public static class E + // instance Length, outer extension this[Index] + var src = """ +using Outer; + +public struct S { - extension(int parameter) + public int Length => 3; +} + +namespace Inner +{ + public class C { - [System.Runtime.CompilerServices.IndexerName("parameter")] - public int this[int i] + public static void Main() { - get => throw null; - set => throw null; + _ = new S() is [.., 1]; } } } -"""; - CreateCompilation(source).VerifyEmitDiagnostics(); - } - [Fact] - public void IndexerName_03() - { - // IndexerName attribute uses same name as static enclosing class - var source = """ -public static class E +namespace Outer { - extension(int i) + public static class E { - [System.Runtime.CompilerServices.IndexerName("E")] - public int this[int j] + extension(object o) { - get => throw null; - set => throw null; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } } } } """; - CreateCompilation(source).VerifyEmitDiagnostics(); + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] - public void Extern_03() + public void ListPattern_22() { - var source = """ -using System.Runtime.InteropServices; -static class E + // inner ambiguous extension Length, outer extension Length + extension this[Index] + var src = """ +using Outer; + +public struct S { } + +namespace Inner { - extension(int i) + public class C { - extern int this[int j] + public static void Main() { - [DllImport("something.dll")] - get; - [DllImport("something.dll")] - set; + _ = new S() is [.., 1]; } } -} -"""; - var verifier = CompileAndVerify(source).VerifyDiagnostics(); - // Note: skeleton methods have "throw" bodies and lack pinvokeimpl/preservesig. Implementation methods have pinvokeimpl/preservesig and no body. - verifier.VerifyTypeIL("E", """ -.class private auto ansi abstract sealed beforefieldinit E + + public static class E1 + { + extension(object o) + { + public int Length => throw null; + } + } + + public static class E2 + { + extension(object o) + { + public int Length => throw null; + } + } +} + +namespace Outer +{ + public static class E3 + { + extension(object o) + { + public int Length => throw null; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (11,28): error CS8985: List patterns may not be used for a value of type 'S'. No suitable 'Length' or 'Count' property was found. + // _ = new S() is [.., 1]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.., 1]").WithArguments("S").WithLocation(11, 28)); + } + + [Fact] + public void ListPattern_23() + { + // inner inapplicable extension Length, outer extension Length + extension this[Index] + var src = """ +using Outer; + +public struct S { } + +public class D { } + +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.., 1]; + } + } + + public static class E1 + { + extension(D d) + { + public int Length => throw null; + } + } +} + +namespace Outer +{ + public static class E3 + { + extension(object o) + { + public int Length => 3; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void ListPattern_24() + { + // inner inapplicable extension this[Index], outer extension Length + extension this[Index] + var src = """ +using Outer; + +public struct S { } + +public class D { } + +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.., 1]; + } + } + + public static class E1 + { + extension(D d) + { + public int this[System.Index i] { get => throw null; } + } + } +} + +namespace Outer +{ + public static class E3 + { + extension(object o) + { + public int Length => 3; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void SpreadPattern_01(bool useCompilationReference) + { + // extension Length + extension this[Index] + extension this[Range] + var libSrc = """ +public class C { } + +public static class E +{ + extension(C c) + { + public int Length => 3; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } + } +} +"""; + var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net70); + var libRef = AsReference(libComp, useCompilationReference); + + var src = """ +_ = new C() is [_, .. var x]; +"""; + + var comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (1,16): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[_, .. var x]").WithArguments("extension indexers").WithLocation(1, 16), + // (1,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureInPreview, ".. var x").WithArguments("extension indexers").WithLocation(1, 20)); + + comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (8,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(8, 20), + // (9,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(9, 20)); + } + + [Fact] + public void SpreadPattern_02() + { + // boxed receiver + var src = """ +_ = new S() is [_, .. var x]; + +public struct S +{ + public int Length => 3; +} + +public static class E +{ + extension(object o) + { + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + public int this[System.Range r] { get { System.Console.WriteLine(r); return 0; } } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + verifier.VerifyIL("", """ +{ + // Code size 55 (0x37) + .maxstack 4 + .locals init (S V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "S" + IL_0008: ldloca.s V_0 + IL_000a: call "int S.Length.get" + IL_000f: ldc.i4.1 + IL_0010: blt.s IL_0034 + IL_0012: ldloc.0 + IL_0013: box "S" + IL_0018: ldc.i4.1 + IL_0019: ldc.i4.0 + IL_001a: newobj "System.Index..ctor(int, bool)" + IL_001f: ldc.i4.0 + IL_0020: ldc.i4.1 + IL_0021: newobj "System.Index..ctor(int, bool)" + IL_0026: newobj "System.Range..ctor(System.Index, System.Index)" + IL_002b: call "int E.get_Item(object, System.Range)" + IL_0030: pop + IL_0031: ldc.i4.1 + IL_0032: br.s IL_0035 + IL_0034: ldc.i4.0 + IL_0035: pop + IL_0036: ret +} +"""); + } + + [Theory, CombinatorialData] + public void SpreadPattern_03(bool useCompilationReference) + { + // extension Length + extension this[int] + extension Slice(int, int) + var libSrc = """ +public class C { } + +public static class E +{ + extension(C c) + { + public int Length => 3; + public int this[int i] { get { System.Console.Write(i); return 0; } } + public int Slice(int i, int j) { System.Console.Write((i, j)); return 0; } + } +} +"""; + var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net70); + var libRef = AsReference(libComp, useCompilationReference); + + var src = """ +_ = new C() is [_, .. var x]; +"""; + + var comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular13); + comp.VerifyEmitDiagnostics( + // (1,16): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "[_, .. var x]").WithArguments("extensions", "14.0").WithLocation(1, 16), + // (1,16): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, "[_, .. var x]").WithArguments("extensions", "14.0").WithLocation(1, 16), + // (1,16): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[_, .. var x]").WithArguments("extension indexers").WithLocation(1, 16), + // (1,20): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, ".. var x").WithArguments("extensions", "14.0").WithLocation(1, 20), + // (1,20): error CS9260: Feature 'extensions' is not available in C# 13.0. Please use language version 14.0 or greater. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion13, ".. var x").WithArguments("extensions", "14.0").WithLocation(1, 20)); + + comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (1,16): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[_, .. var x]").WithArguments("extension indexers").WithLocation(1, 16)); + + comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("(1, 2)"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + comp = CreateCompilation(src, references: [libRef], targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("(1, 2)"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_04() + { + // instance Length, inner extension this[int] + extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ + public int Length => 3; +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(C c) + { + public int this[int i] { get => throw null; } + public int Slice(int i, int j) => throw null; + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get { System.Console.Write(i); return 0; } } + public int this[System.Range r] { get { System.Console.Write(r); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_05() + { + // inner extension Length + extension this[int] + extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(C c) + { + public int Length => 3; + public int this[int i] { get => throw null; } + public int Slice(int i, int j) => throw null; + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get { System.Console.Write(r); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_06() + { + // inner ambiguous extension Length + extension this[int] + extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(C c) + { + public int Length => 3; + public int this[int i] { get => throw null; } + public int Slice(int i, int j) => throw null; + } + } + + public static class E2 + { + extension(C c) + { + public int Length => 3; + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get => throw null; } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (13,28): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[_, .. var x]").WithArguments("C").WithLocation(13, 28)); + } + + [Fact] + public void SpreadPattern_07() + { + // inner extension Length + extension Count + extension this[int] + extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(C c) + { + public int Length => 3; + public int Count => throw null; + public int this[int i] { get => throw null; } + public int Slice(int i, int j) => throw null; + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get { System.Console.Write(r); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_08() + { + // inner extension Length + ambiguous extension this[int] + extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(C c) + { + public int Length => 3; + public int this[int i] { get => throw null; } + public int Slice(int i, int j) => throw null; + } + } + + public static class E2 + { + extension(C c) + { + public int this[int i] { get => throw null; } + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get { System.Console.Write(r); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_09() + { + // inner extension Length + extension this[int] + ambiguous extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(C c) + { + public int Length => 3; + public int this[int i] { get => throw null; } + public int Slice(int i, int j) => throw null; + } + } + + public static class E2 + { + extension(C c) + { + public int Slice(int i, int j) => throw null; + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get { System.Console.Write(r); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_10() + { + // inner inapplicable extension Length + extension this[int] + extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(D d) + { + public int Length => 3; + } + extension(C c) + { + public int this[int i] { get => throw null; } + public int Slice(int i, int j) => throw null; + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get => throw null; } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics( + // (13,28): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. + // _ = new C() is [_, .. var x]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[_, .. var x]").WithArguments("C").WithLocation(13, 28)); + } + + [Fact] + public void SpreadPattern_11() + { + // inner extension Length + inapplicable extension this[int] + extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(D d) + { + public int this[int i] { get => throw null; } + } + extension(C c) + { + public int Length => 3; + public int Slice(int i, int j) { System.Console.Write($"{i}..{j}"); return 0; } + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get { System.Console.Write(r); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_12() + { + // inner extension Length + extension this[int] + inapplicable extension Slice(int, int), outer extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public class C +{ +} + +namespace Inner +{ + public class D + { + public static void Main() + { + _ = new C() is [_, .. var x]; + } + } + + public static class E1 + { + extension(D d) + { + public int Slice(int i, int j) => throw null; + } + extension(C c) + { + public int Length => 3; + public int this[int i] { get => throw null; } + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(C c) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get { System.Console.Write(r); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("1..^0"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_13() + { + // inner inapplicable extension this[Range], outer extension Length + extension this[Index] + extension this[Range] + var src = """ +using Outer; + +public struct S { } + +public class D { } + +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.. var x, 1]; + } + } + + public static class E1 + { + extension(D d) + { + public int this[System.Range r] { get => throw null; } + } + } +} + +namespace Outer +{ + public static class E3 + { + extension(object o) + { + public int Length => 3; + public int this[System.Index i] { get { System.Console.Write(i); return 0; } } + public int this[System.Range r] { get { System.Console.Write($"{r}, "); return 0; } } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("0..^1, ^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_14() + { + // generic extension Length + generic extension this[Index] + generic extension Slice(int, int) + var src = """ +_ = new S() is [.. var x, 1]; + +public struct S { } + +public static class E +{ + extension(T t) + { + public int Length => 3; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + public int Slice(int i, int j) { System.Console.Write($"Slice({i},{j}), "); return 0; } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("Slice(0,2), ^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_15() + { + // generic extension Length + generic extension this[Index] + generic extension this[Range] + var src = """ +_ = new S() is [.. var x, 1]; + +public struct S { } + +public static class E +{ + extension(T t) + { + public int Length => 3; + public int this[System.Index i] { get { System.Console.WriteLine(i); return 0; } } + public int this[System.Range r] { get { System.Console.Write($"{r}, "); return 0; } } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("0..^1, ^1"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void SpreadPattern_16() + { + // extension Length + extension this[Index] + extension Slice(T, T) + var src = """ +_ = new S() is [.. var x, 1]; + +public struct S { } + +public static class E +{ + extension(object o) + { + public int Length => 3; + public int this[System.Index i] { get => throw null; } + public int Slice(T i, T j) => throw null; + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (1,17): error CS0021: Cannot apply indexing with [] to an expression of type 'S' + // _ = new S() is [.. var x, 1]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, ".. var x").WithArguments("S").WithLocation(1, 17)); + } + + [Fact] + public void SpreadPattern_17() + { + // array type, extension this[Index] + extension this[Range] + var src = """ +public static class E +{ + public static void Main() + { + int[] i = [1, 2, 3]; + System.Console.Write(M(i)); + } + + public static bool M(int[] i) + { + return i is [.. var x, 3]; + } + + extension(int[] a) + { + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get => throw null; } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("True"), verify: Verification.Skipped).VerifyDiagnostics(); + verifier.VerifyIL("E.M", """ +{ + // Code size 54 (0x36) + .maxstack 4 + .locals init (int[] V_0, //x + int V_1, + bool V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brfalse.s IL_0030 + IL_0004: ldarg.0 + IL_0005: ldlen + IL_0006: conv.i4 + IL_0007: stloc.1 + IL_0008: ldloc.1 + IL_0009: ldc.i4.1 + IL_000a: blt.s IL_0030 + IL_000c: ldarg.0 + IL_000d: ldc.i4.0 + IL_000e: ldc.i4.0 + IL_000f: newobj "System.Index..ctor(int, bool)" + IL_0014: ldc.i4.1 + IL_0015: ldc.i4.1 + IL_0016: newobj "System.Index..ctor(int, bool)" + IL_001b: newobj "System.Range..ctor(System.Index, System.Index)" + IL_0020: call "int[] System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray(int[], System.Range)" + IL_0025: stloc.0 + IL_0026: ldarg.0 + IL_0027: ldloc.1 + IL_0028: ldc.i4.1 + IL_0029: sub + IL_002a: ldelem.i4 + IL_002b: ldc.i4.3 + IL_002c: ceq + IL_002e: br.s IL_0031 + IL_0030: ldc.i4.0 + IL_0031: stloc.2 + IL_0032: br.s IL_0034 + IL_0034: ldloc.2 + IL_0035: ret +} +"""); + + comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.MakeMemberMissing(SpecialMember.System_Array__Length); + comp.VerifyEmitDiagnostics( + // (11,21): error CS0656: Missing compiler required member 'System.Array.Length' + // return i is [.. var x, 3]; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[.. var x, 3]").WithArguments("System.Array", "Length").WithLocation(11, 21), + // (11,21): error CS8985: List patterns may not be used for a value of type 'int[]'. No suitable 'Length' or 'Count' property was found. + // return i is [.. var x, 3]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.. var x, 3]").WithArguments("int[]").WithLocation(11, 21)); + } + + [Fact] + public void SpreadPattern_17_WithExtensionLength() + { + // array type (with and without Length), extension Length + extension this[Index] + extension this[Range] + var src = """ +public static class E +{ + public static void Main() + { + int[] i = [1, 2, 3]; + System.Console.Write(M(i)); + } + + public static bool M(int[] i) + { + return i is [.. var x, 3]; + } + + extension(int[] a) + { + public int Length => throw null; + public int this[System.Index i] { get => throw null; } + public int this[System.Range r] { get => throw null; } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("True"), verify: Verification.Skipped).VerifyDiagnostics(); + + // Note: the presence of extension Length allows binding to succeed, but we still lower with specialized IL + comp = CreateCompilation(src, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("True"), verify: Verification.Skipped).VerifyDiagnostics(); + verifier.VerifyIL("E.M", """ +{ + // Code size 54 (0x36) + .maxstack 4 + .locals init (int[] V_0, //x + int V_1, + bool V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: brfalse.s IL_0030 + IL_0004: ldarg.0 + IL_0005: ldlen + IL_0006: conv.i4 + IL_0007: stloc.1 + IL_0008: ldloc.1 + IL_0009: ldc.i4.1 + IL_000a: blt.s IL_0030 + IL_000c: ldarg.0 + IL_000d: ldc.i4.0 + IL_000e: ldc.i4.0 + IL_000f: newobj "System.Index..ctor(int, bool)" + IL_0014: ldc.i4.1 + IL_0015: ldc.i4.1 + IL_0016: newobj "System.Index..ctor(int, bool)" + IL_001b: newobj "System.Range..ctor(System.Index, System.Index)" + IL_0020: call "int[] System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray(int[], System.Range)" + IL_0025: stloc.0 + IL_0026: ldarg.0 + IL_0027: ldloc.1 + IL_0028: ldc.i4.1 + IL_0029: sub + IL_002a: ldelem.i4 + IL_002b: ldc.i4.3 + IL_002c: ceq + IL_002e: br.s IL_0031 + IL_0030: ldc.i4.0 + IL_0031: stloc.2 + IL_0032: br.s IL_0034 + IL_0034: ldloc.2 + IL_0035: ret +} +"""); + } + + [Fact] + public void SpreadPattern_18() + { + // instance Length, inner extension Length + extension this[int], outer extension Length + extension Slice(int, int) + var src = """ +using Outer; + +public struct S +{ + public int Length => 3; +} + +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.. var x, 1]; + } + } + + public static class E1 + { + extension(S s) + { + public int Length => 3; + public int this[int i] { get { System.Console.WriteLine(i); return 0; } } + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(object o) + { + public int Length => throw null; + public object Slice(int i, int j) { System.Console.Write($"{i},{j}, "); return o; } + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0,2, 2"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + verifier.VerifyIL("Inner.C.Main", """ +{ + // Code size 62 (0x3e) + .maxstack 4 + .locals init (object V_0, //x + S V_1, + int V_2, + int V_3) + IL_0000: nop + IL_0001: ldloca.s V_1 + IL_0003: initobj "S" + IL_0009: ldloca.s V_1 + IL_000b: call "int S.Length.get" + IL_0010: stloc.2 + IL_0011: ldloc.2 + IL_0012: ldc.i4.1 + IL_0013: blt.s IL_003b + IL_0015: ldloc.1 + IL_0016: box "S" + IL_001b: ldc.i4.0 + IL_001c: ldloc.2 + IL_001d: ldc.i4.1 + IL_001e: sub + IL_001f: call "object Outer.E2.Slice(object, int, int)" + IL_0024: stloc.0 + IL_0025: ldloca.s V_1 + IL_0027: ldloc.2 + IL_0028: ldc.i4.1 + IL_0029: sub + IL_002a: stloc.3 + IL_002b: ldobj "S" + IL_0030: ldloc.3 + IL_0031: call "int Inner.E1.get_Item(S, int)" + IL_0036: ldc.i4.1 + IL_0037: ceq + IL_0039: br.s IL_003c + IL_003b: ldc.i4.0 + IL_003c: pop + IL_003d: ret +} +"""); + } + + [Fact] + public void SpreadPattern_19() + { + // instance Length + this[int], inner extension Length + inner Slice(int, int), outer extension Length + var src = """ +using Outer; + +public struct S +{ + public int Length => 3; + public int this[int i] { get { System.Console.WriteLine(i); return 0; } } +} + +namespace Inner +{ + public class C + { + public static void Main() + { + _ = new S() is [.. var x, 1]; + } + } + + public static class E1 + { + extension(S s) + { + public int Length => throw null; + public S Slice(int i, int j) { System.Console.Write($"{i},{j}, "); return s; } + } + } +} + +namespace Outer +{ + public static class E2 + { + extension(S s) + { + public int Length => throw null; + } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("0,2, 2"), verify: Verification.FailsPEVerify).VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // using Outer; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using Outer;").WithLocation(1, 1)); + verifier.VerifyIL("Inner.C.Main", """ +{ + // Code size 50 (0x32) + .maxstack 4 + .locals init (S V_0, //x + S V_1, + int V_2) + IL_0000: nop + IL_0001: ldloca.s V_1 + IL_0003: initobj "S" + IL_0009: ldloca.s V_1 + IL_000b: call "int S.Length.get" + IL_0010: stloc.2 + IL_0011: ldloc.2 + IL_0012: ldc.i4.1 + IL_0013: blt.s IL_002f + IL_0015: ldloc.1 + IL_0016: ldc.i4.0 + IL_0017: ldloc.2 + IL_0018: ldc.i4.1 + IL_0019: sub + IL_001a: call "S Inner.E1.Slice(S, int, int)" + IL_001f: stloc.0 + IL_0020: ldloca.s V_1 + IL_0022: ldloc.2 + IL_0023: ldc.i4.1 + IL_0024: sub + IL_0025: call "int S.this[int].get" + IL_002a: ldc.i4.1 + IL_002b: ceq + IL_002d: br.s IL_0030 + IL_002f: ldc.i4.0 + IL_0030: pop + IL_0031: ret +} +"""); + } + + [Theory, CombinatorialData] + public void ConditionalAssignment_01(bool useCompilationReference) + { + var libSrc = """ +public class C { } + +public static class E +{ + extension(C c) + { + public int this[int i] + { + set { System.Console.WriteLine($"set_Item({i} {value})"); } + } + } +} +"""; + var libComp = CreateCompilation(libSrc); + var libRef = AsReference(libComp, useCompilationReference); + + var src = """ +C c = null; +c?[42] = 0; + +c = new C(); +c?[43] = 100; +"""; + + var comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (2,3): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // c?[42] = 0; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[42]").WithArguments("extension indexers").WithLocation(2, 3), + // (5,3): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // c?[43] = 100; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[43]").WithArguments("extension indexers").WithLocation(5, 3)); + + comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, references: [libRef]); + CompileAndVerify(comp, expectedOutput: "set_Item(43 100)").VerifyDiagnostics(); + + comp = CreateCompilation([src, libSrc], parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int this[int i] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(7, 20)); + } + + [Fact] + public void ConditionalAssignment_02() + { + // nullable value type receiver + var src = """ +E.Test(null, 42, 0); +E.Test(new S(), 43, 100); + +public struct S { } + +public static class E +{ + public static void Test(S? s, int index, int value) + { + s?[index] = value; + } + + extension(S s) + { + public int this[int i] + { + set { System.Console.WriteLine($"set_Item({i} {value})"); } + } + } +} +"""; + + // Tracked by https://github.com/dotnet/roslyn/issues/79451 : consider adjusting receiver requirements for extension members + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (10,11): error CS0131: The left-hand side of an assignment must be a variable, property or indexer + // s?[index] = value; + Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "[index]").WithLocation(10, 11)); + + //var verifier = CompileAndVerify(comp, expectedOutput: "set_Item(43 100)").VerifyDiagnostics(); + //verifier.VerifyIL("E.Test", ""); + } + + [Theory, CombinatorialData] + public void ConditionalAccess_01(bool useCompilationReference) + { + var libSrc = """ +public class C { } + +public static class E +{ + extension(C c) + { + public int this[int i] + { + get { System.Console.Write($" get_Item({i}) "); return 100; } + } + } +} +"""; + + var libComp = CreateCompilation(libSrc); + var libRef = AsReference(libComp, useCompilationReference); + + var src = """ +C c = null; +System.Console.Write(c?[42] is null); + +c = new C(); +System.Console.Write(c?[43] is 100); +"""; + + var comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (2,24): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // System.Console.Write(c?[42] is null); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[42]").WithArguments("extension indexers").WithLocation(2, 24), + // (5,24): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // System.Console.Write(c?[43] is 100); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "[43]").WithArguments("extension indexers").WithLocation(5, 24)); + + comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, references: [libRef]); + CompileAndVerify(comp, expectedOutput: "True get_Item(43) True").VerifyDiagnostics(); + + comp = CreateCompilation([src, libSrc], parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int this[int i] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "this").WithArguments("extension indexers").WithLocation(7, 20)); + } + + [Fact] + public void ConditionalAccess_02() + { + // nullable value type receiver + var src = """ +System.Console.Write(E.Test(null, 42) is null); + +System.Console.Write(E.Test(new S(), 43) is 100); + +public struct S { } + +public static class E +{ + public static int? Test(S? s, int index) + { + return s?[index]; + } + + extension(S s) + { + public int this[int i] + { + get { System.Console.Write($" get_Item({i}) "); return 100; } + } + } +} +"""; + + var comp = CreateCompilation(src); + var verifier = CompileAndVerify(comp, expectedOutput: "True get_Item(43) True").VerifyDiagnostics(); + verifier.VerifyIL("E.Test", """ +{ + // Code size 38 (0x26) + .maxstack 2 + .locals init (int? V_0) + IL_0000: ldarga.s V_0 + IL_0002: call "bool S?.HasValue.get" + IL_0007: brtrue.s IL_0013 + IL_0009: ldloca.s V_0 + IL_000b: initobj "int?" + IL_0011: ldloc.0 + IL_0012: ret + IL_0013: ldarga.s V_0 + IL_0015: call "S S?.GetValueOrDefault()" + IL_001a: ldarg.1 + IL_001b: call "int E.get_Item(S, int)" + IL_0020: newobj "int?..ctor(int)" + IL_0025: ret +} +"""); + } + + [Fact] + public void Nameof_01() + { + var src = """ +object o = new object(); +_ = nameof(o[0]); + +public static class E +{ + extension(object o) + { + public int this[int i] => 0; + } +} +"""; + + CreateCompilation(src).VerifyEmitDiagnostics( + // (2,12): error CS8081: Expression does not have a name. + // _ = nameof(o[0]); + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "o[0]").WithLocation(2, 12)); + } + + [Fact] + public void Nameof_02() + { + // setter-only indexer + var src = """ +object o = new object(); +_ = nameof(o[0]); + +public static class E +{ + extension(object o) + { + public int this[int i] { set { } } + } +} +"""; + + CreateCompilation(src).VerifyEmitDiagnostics( + // (2,12): error CS8081: Expression does not have a name. + // _ = nameof(o[0]); + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "o[0]").WithLocation(2, 12), + // (2,12): error CS0154: The property or indexer 'E.extension(object).this[int]' cannot be used in this context because it lacks the get accessor + // _ = nameof(o[0]); + Diagnostic(ErrorCode.ERR_PropertyLacksGet, "o[0]").WithArguments("E.extension(object).this[int]").WithLocation(2, 12)); + } + + [Fact] + public void ORPA_01() + { + var source = """ +_ = 42[43]; + +static class E +{ + extension(int i) + { + public int this[int j] => throw null; + + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public int this[long l] { get { System.Console.Write("ran"); return 0; } } + } +} +"""; + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void ORPA_02() + { + var source = """ +_ = 42[43]; + +static class E +{ + extension(int i) + { + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public int this[int j] { get { System.Console.Write("ran"); return 0; } } + + public int this[long l] => throw null; + } +} +"""; + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void ORPA_03() + { + var source = """ +_ = 42[43]; + +static class E1 +{ + extension(int i) + { + public int this[int j] { get { System.Console.Write("ran"); return 0; } } + } +} + +static class E2 +{ + extension(int i) + { + [System.Runtime.CompilerServices.OverloadResolutionPriority(1)] + public int this[long l] => throw null; + } +} +"""; + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]); + CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics(); + } + + [Fact] + public void Metadata_01() + { + var source = """ +public static class E +{ + extension(int i) + { + public int this[int j] { get { return 42; } } + } +} +"""; + var comp = CreateCompilation(source); + var verifier = CompileAndVerify(comp).VerifyDiagnostics(); + + verifier.VerifyTypeIL("E", """ +.class public auto ansi abstract sealed beforefieldinit E + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed specialname '$BA41CFE2B5EDAEB8C1B9062F59ED4D69' + extends [netstandard]System.Object + { + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [netstandard]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 04 49 74 65 6d 00 00 + ) + // Nested Types + .class nested public auto ansi abstract sealed specialname '$F4B4FFE41AB49E80A4ECF390CF6EB372' + extends [netstandard]System.Object + { + // Methods + .method public hidebysig specialname static + void '$' ( + int32 i + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2089 + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '$F4B4FFE41AB49E80A4ECF390CF6EB372'::'$' + } // end of class $F4B4FFE41AB49E80A4ECF390CF6EB372 + // Methods + .method public hidebysig specialname + instance int32 get_Item ( + int32 j + ) cil managed + { + .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( + 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 + 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 + 46 36 45 42 33 37 32 00 00 + ) + // Method begins at RVA 0x2082 + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method '$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_Item + // Properties + .property instance int32 Item( + int32 j + ) + { + .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( + 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 + 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 + 46 36 45 42 33 37 32 00 00 + ) + .get instance int32 E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_Item(int32) + } + } // end of class $BA41CFE2B5EDAEB8C1B9062F59ED4D69 + // Methods + .method public hidebysig static + int32 get_Item ( + int32 i, + int32 j + ) cil managed + { + // Method begins at RVA 0x207e + // Code size 3 (0x3) + .maxstack 8 + IL_0000: ldc.i4.s 42 + IL_0002: ret + } // end of method E::get_Item +} // end of class E +""".Replace("[netstandard]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + } + + [Theory, CombinatorialData] + public void Metadata_02(bool useCompilationReference) + { + var libSrc = """ +public static class E +{ + extension(int i) + { + public int this[int j] + { + get { System.Console.Write($"get({j}) "); return 42; } + set { System.Console.Write($"set({j}, {value}) "); } + } + } +} +"""; + var libComp = CreateCompilation(libSrc); + var libRef = AsReference(libComp, useCompilationReference); + + var src = """ +int i = 0; +_ = i[43]; +i[101] = 102; +"""; + var comp = CreateCompilation(src, [libRef]); + CompileAndVerify(comp, expectedOutput: "get(43) set(101, 102)").VerifyDiagnostics(); + + var indexer = comp.GlobalNamespace.GetTypeMember("E").GetTypeMember("").GetMembers().OfType().Single(); + AssertEx.Equal("E.extension(int).this[int]", indexer.ToDisplayString()); + Assert.True(indexer.IsIndexer); + AssertEx.Equal("E.extension(int).this[int].get", indexer.GetMethod.ToDisplayString()); + AssertEx.Equal("E.extension(int).this[int].set", indexer.SetMethod.ToDisplayString()); + + comp = CreateCompilation(src, [libRef], parseOptions: TestOptions.Regular14); + comp.VerifyEmitDiagnostics( + // (2,5): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = i[43]; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "i[43]").WithArguments("extension indexers").WithLocation(2, 5), + // (3,1): error CS8652: The feature 'extension indexers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // i[101] = 102; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "i[101]").WithArguments("extension indexers").WithLocation(3, 1)); + } + + [Theory, CombinatorialData] + public void Metadata_03(bool useCompilationReference) + { + // IndexerName attribute on single indexer + var libSrc = """ +public static class E +{ + extension(int i) + { + [System.Runtime.CompilerServices.IndexerName("MyIndexer")] + public int this[int j] + { + get { System.Console.Write($"get({j}) "); return 42; } + set { System.Console.Write($"set({j}, {value}) "); } + } + } +} +"""; + var libComp = CreateCompilation(libSrc); + var verifier = CompileAndVerify(libComp).VerifyDiagnostics(); + + verifier.VerifyTypeIL("E", """ +.class public auto ansi abstract sealed beforefieldinit E + extends [netstandard]System.Object +{ + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested public auto ansi sealed specialname '$BA41CFE2B5EDAEB8C1B9062F59ED4D69' + extends [netstandard]System.Object + { + .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [netstandard]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 09 4d 79 49 6e 64 65 78 65 72 00 00 + ) + // Nested Types + .class nested public auto ansi abstract sealed specialname '$F4B4FFE41AB49E80A4ECF390CF6EB372' + extends [netstandard]System.Object + { + // Methods + .method public hidebysig specialname static + void '$' ( + int32 i + ) cil managed + { + .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x20bb + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method '$F4B4FFE41AB49E80A4ECF390CF6EB372'::'$' + } // end of class $F4B4FFE41AB49E80A4ECF390CF6EB372 + // Methods + .method public hidebysig specialname + instance int32 get_MyIndexer ( + int32 j + ) cil managed + { + .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( + 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 + 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 + 46 36 45 42 33 37 32 00 00 + ) + // Method begins at RVA 0x20b4 + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method '$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_MyIndexer + .method public hidebysig specialname + instance void set_MyIndexer ( + int32 j, + int32 'value' + ) cil managed + { + .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( + 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 + 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 + 46 36 45 42 33 37 32 00 00 + ) + // Method begins at RVA 0x20b4 + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj instance void [netstandard]System.NotSupportedException::.ctor() + IL_0005: throw + } // end of method '$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_MyIndexer + // Properties + .property instance int32 MyIndexer( + int32 j + ) + { + .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( + 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 + 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 + 46 36 45 42 33 37 32 00 00 + ) + .get instance int32 E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_MyIndexer(int32) + .set instance void E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::set_MyIndexer(int32, int32) + } + } // end of class $BA41CFE2B5EDAEB8C1B9062F59ED4D69 + // Methods + .method public hidebysig static + int32 get_MyIndexer ( + int32 i, + int32 j + ) cil managed + { + // Method begins at RVA 0x207e + // Code size 24 (0x18) + .maxstack 8 + IL_0000: ldstr "get({0}) " + IL_0005: ldarg.1 + IL_0006: box [netstandard]System.Int32 + IL_000b: call string [netstandard]System.String::Format(string, object) + IL_0010: call void [netstandard]System.Console::Write(string) + IL_0015: ldc.i4.s 42 + IL_0017: ret + } // end of method E::get_MyIndexer + .method public hidebysig static + void set_MyIndexer ( + int32 i, + int32 j, + int32 'value' + ) cil managed + { + // Method begins at RVA 0x2097 + // Code size 28 (0x1c) + .maxstack 8 + IL_0000: ldstr "set({0}, {1}) " + IL_0005: ldarg.1 + IL_0006: box [netstandard]System.Int32 + IL_000b: ldarg.2 + IL_000c: box [netstandard]System.Int32 + IL_0011: call string [netstandard]System.String::Format(string, object, object) + IL_0016: call void [netstandard]System.Console::Write(string) + IL_001b: ret + } // end of method E::set_MyIndexer +} // end of class E +""".Replace("[netstandard]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); + + var src = """ +int i = 0; +_ = i[43]; +i[101] = 102; + +E.get_MyIndexer(i, 43); +E.set_MyIndexer(i, 101, 102); +"""; + var comp = CreateCompilation(src, [AsReference(libComp, useCompilationReference)]); + CompileAndVerify(comp, expectedOutput: "get(43) set(101, 102) get(43) set(101, 102)").VerifyDiagnostics(); + + var indexer = comp.GlobalNamespace.GetTypeMember("E").GetTypeMember("").GetMembers().OfType().Single(); + AssertEx.Equal("E.extension(int).this[int]", indexer.ToDisplayString()); + Assert.True(indexer.IsIndexer); + AssertEx.Equal("E.extension(int).this[int].get", indexer.GetMethod.ToDisplayString()); + AssertEx.Equal("E.extension(int).this[int].set", indexer.SetMethod.ToDisplayString()); + } + + [Theory, CombinatorialData] + public void Metadata_04(bool useCompilationReference) + { + // Matching IndexerName attributes on both indexers + var libSrc = """ +public static class E +{ + extension(int i) + { + [System.Runtime.CompilerServices.IndexerName("MyIndexer")] + public int this[int j] + { + get { System.Console.Write($"get({j}) "); return 42; } + set { System.Console.Write($"set({j}, {value}) "); } + } + + [System.Runtime.CompilerServices.IndexerName("MyIndexer")] + public int this[string s] + { + get { System.Console.Write($"get2({s}) "); return 42; } + set { System.Console.Write($"set2({s}, {value}) "); } + } + } +} +"""; + var libComp = CreateCompilation(libSrc); + var verifier = CompileAndVerify(libComp).VerifyDiagnostics(); + + var src = """ +int i = 0; +_ = i[43]; +i[101] = 102; + +E.get_MyIndexer(i, 43); +E.set_MyIndexer(i, 101, 102); + +_ = i["A"]; +i["B"] = 102; + +E.get_MyIndexer(i, "A"); +E.set_MyIndexer(i, "B", 102); +"""; + var comp = CreateCompilation(src, [AsReference(libComp, useCompilationReference)]); + CompileAndVerify(comp, expectedOutput: "get(43) set(101, 102) get(43) set(101, 102) get2(A) set2(B, 102) get2(A) set2(B, 102)").VerifyDiagnostics(); + + var indexers = comp.GlobalNamespace.GetTypeMember("E").GetTypeMember("").GetMembers().OfType().ToArray(); + AssertEx.Equal("E.extension(int).this[int]", indexers[0].ToDisplayString()); + Assert.True(indexers[0].IsIndexer); + + AssertEx.Equal("E.extension(int).this[string]", indexers[1].ToDisplayString()); + Assert.True(indexers[1].IsIndexer); + } + + [Fact] + public void IndexerName_01() + { + // IndexerName attribute on one of the indexers + var source = """ +public static class E +{ + extension((int a, int b) t) + { + public int this[string s] + { + get => throw null; + set => throw null; + } + } + + extension((int c, int d) t) + { + [System.Runtime.CompilerServices.IndexerName("MyIndexer")] + public int this[int j] + { + get => throw null; + set => throw null; + } + } +} +"""; + CreateCompilation(source).VerifyEmitDiagnostics( + // (15,20): error CS0668: Two indexers have different names; the IndexerName attribute must be used with the same name on every indexer within a type + // public int this[int j] + Diagnostic(ErrorCode.ERR_InconsistentIndexerNames, "this").WithLocation(15, 20)); + } + + [Fact] + public void IndexerName_02() + { + // IndexerName attribute uses same name as extension parameter + var source = """ +public static class E +{ + extension(int parameter) + { + [System.Runtime.CompilerServices.IndexerName("parameter")] + public int this[int i] + { + get => throw null; + set => throw null; + } + } +} +"""; + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void IndexerName_03() + { + // IndexerName attribute uses same name as static enclosing class + var source = """ +public static class E +{ + extension(int i) + { + [System.Runtime.CompilerServices.IndexerName("E")] + public int this[int j] + { + get => throw null; + set => throw null; + } + } +} +"""; + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void Extern_03() + { + var source = """ +using System.Runtime.InteropServices; +static class E +{ + extension(int i) + { + extern int this[int j] + { + [DllImport("something.dll")] + get; + [DllImport("something.dll")] + set; + } + } +} +"""; + var verifier = CompileAndVerify(source).VerifyDiagnostics(); + // Note: skeleton methods have "throw" bodies and lack pinvokeimpl/preservesig. Implementation methods have pinvokeimpl/preservesig and no body. + verifier.VerifyTypeIL("E", """ +.class private auto ansi abstract sealed beforefieldinit E extends [netstandard]System.Object { .custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( @@ -10830,7 +12782,7 @@ public C this[int i] CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyEmitDiagnostics(); } - [Fact(Skip = "PROTOTYPE assertion in NullableWalker.DebugVerifier")] + [Fact] public void Nullability_ListPattern_01() { string source = """ @@ -12884,7 +14836,7 @@ public class C [Fact] public void IOperation_03() { - // list pattern, extension Length + // list pattern, extension Length, instance this[Index] var src = """ C c = new C(); @@ -12906,15 +14858,25 @@ public class C } """; - // PROTOTYPE where should extension Length/Count count? var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); - comp.VerifyEmitDiagnostics( - // (4,10): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = c is [42]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[42]").WithArguments("C").WithLocation(4, 10)); + comp.VerifyEmitDiagnostics(); - //string expectedOperationTree = ""; - //VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, [], targetFramework: TargetFramework.Net100); + string expectedOperationTree = """ +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: '_ = c is [42]') + Left: + IDiscardOperation (Symbol: System.Boolean _) (OperationKind.Discard, Type: System.Boolean) (Syntax: '_') + Right: + IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'c is [42]') + Value: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + Pattern: + IListPatternOperation (OperationKind.ListPattern, Type: null) (Syntax: '[42]') (InputType: C, NarrowedType: C, DeclaredSymbol: null, LengthSymbol: System.Int32 E.$9794DAFCCB9E752B29BFD6350ADA77F2.Length { get; }, IndexerSymbol: System.Int32 C.this[System.Index i] { get; }) + Patterns (1): + IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: '42') (InputType: System.Int32, NarrowedType: System.Int32) + Value: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') +"""; + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, [], targetFramework: TargetFramework.Net100); } [Fact] @@ -13169,7 +15131,102 @@ public class D { } ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 100) (Syntax: '100') """; - VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, [], targetFramework: TargetFramework.Net100); + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, [], targetFramework: TargetFramework.Net100); + } + + [Fact] + public void IOperation_09() + { + // implicit indexer with extension Length paired with instance this[int] + var src = """ +var c = new C(); +/**/ +c[^2] = 10; +/**/ + +static class E +{ + extension(C c) + { + public int Length => 3; + } +} + +class C +{ + public int this[int i] + { + get { System.Console.Write($"instance.get({i}) "); return 42; } + set { System.Console.Write($"instance.set({i}, {value}) "); } + } +} +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("instance.set(1, 10) "), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + string expectedOperationTree = """ +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'c[^2] = 10') +Left: + IImplicitIndexerReferenceOperation (OperationKind.ImplicitIndexerReference, Type: System.Int32) (Syntax: 'c[^2]') + Instance: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + Argument: + IUnaryOperation (UnaryOperatorKind.Hat) (OperationKind.Unary, Type: System.Index) (Syntax: '^2') + Operand: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') + LengthSymbol: System.Int32 E.$9794DAFCCB9E752B29BFD6350ADA77F2.Length { get; } + IndexerSymbol: System.Int32 C.this[System.Int32 i] { get; set; } +Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') +"""; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, [], targetFramework: TargetFramework.Net100); + } + + [Fact] + public void IOperation_10() + { + // implicit indexer with extension Length but no this[int] + var src = """ +var c = new C(); +/**/ +c[^2] = 10; +/**/ + +static class E +{ + extension(C c) + { + public int Length => 3; + } +} + +class C { } +"""; + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + string expectedOperationTree = """ +ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: ?, IsInvalid) (Syntax: 'c[^2] = 10') +Left: + IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'c[^2]') + Children(2): + IUnaryOperation (UnaryOperatorKind.Hat) (OperationKind.Unary, Type: System.Index, IsInvalid) (Syntax: '^2') + Operand: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2, IsInvalid) (Syntax: '2') + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') +Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') +"""; + + DiagnosticDescription[] expected = [ + // (3,1): error CS0021: Cannot apply indexing with [] to an expression of type 'C' + // c[^2] = 10; + Diagnostic(ErrorCode.ERR_BadIndexLHS, "c[^2]").WithArguments("C").WithLocation(3, 1) + ]; + + VerifyOperationTreeAndDiagnosticsForTest(src, expectedOperationTree, expected, targetFramework: TargetFramework.Net100); } [Fact] @@ -13363,26 +15420,27 @@ public void Nullability_ReceiverConversion_07() #nullable enable (object, object)? o = (new object(), new object()); -_ = o is [var x]; +if (o is [var x]) +{ + System.Console.Write(x); +} static class E { extension((object?, object?) o) { - public int this[System.Index i] { get => throw null!; } + public int this[System.Index i] { get { System.Console.Write($"{i} "); return 42; } } } extension((object, object) o) { - public int Length { get => throw null!; } + public int Length { get { System.Console.Write("Length "); return 1; } } } } """; - // PROTOTYPE where should extension Length/Count count? - CreateCompilation(src, targetFramework: TargetFramework.Net100).VerifyEmitDiagnostics( - // (4,10): error CS8985: List patterns may not be used for a value of type '(object, object)'. No suitable 'Length' or 'Count' property was found. - // _ = o is [var x]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[var x]").WithArguments("(object, object)").WithLocation(4, 10)); + + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("Length 0 42"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81851")] @@ -15296,83 +17354,313 @@ static void Test1() _ = 1[$""]; } - static void Test2() + static void Test2() + { + E.get_Item(3, $""); + } +} +"""; + + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "1234" : null; + var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + verifier.VerifyIL("Program.Test1", $$$""" +{ + // Code size 20 (0x14) + .maxstack 4 + .locals init (int V_0) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.0 + IL_0006: ldloca.s V_0 + IL_0008: newobj "InterpolationHandler..ctor(int, int, {{{refkind}}} int)" + IL_000d: call "int E.get_Item({{{refkind}}} int, InterpolationHandler)" + IL_0012: pop + IL_0013: ret +} +"""); + + verifier.VerifyIL("Program.Test2", $$$""" +{ + // Code size 20 (0x14) + .maxstack 4 + .locals init (int V_0) + IL_0000: ldc.i4.3 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.0 + IL_0006: ldloca.s V_0 + IL_0008: newobj "InterpolationHandler..ctor(int, int, {{{refkind}}} int)" + IL_000d: call "int E.get_Item({{{refkind}}} int, InterpolationHandler)" + IL_0012: pop + IL_0013: ret +} +"""); + + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify); + } + + [Theory, CombinatorialData] + public void InterpolationHandler_ReceiverParameter_ByIn_WithLocalReceiver(bool useMetadataRef) + { + var src = """ +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount, in int i) + { + System.Console.Write(i); + System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; + } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} + +public static class E +{ + extension(in int i) + { + public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] + { + get + { + System.Console.Write(i); + System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; + return 0; + } + } + } +} +"""; + + var exeSource = """ +int i = 1; +_ = i[$""]; +System.Console.Write(i); +E.get_Item(i, $""); +System.Console.Write(i); +"""; + + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123345" : null; + var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + verifier.VerifyIL("", """ +{ + // Code size 51 (0x33) + .maxstack 4 + .locals init (int V_0, //i + int& V_1) + IL_0000: ldc.i4.1 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: stloc.1 + IL_0005: ldloc.1 + IL_0006: ldc.i4.0 + IL_0007: ldc.i4.0 + IL_0008: ldloc.1 + IL_0009: newobj "InterpolationHandler..ctor(int, int, in int)" + IL_000e: call "int E.get_Item(in int, InterpolationHandler)" + IL_0013: pop + IL_0014: ldloc.0 + IL_0015: call "void System.Console.Write(int)" + IL_001a: ldloca.s V_0 + IL_001c: stloc.1 + IL_001d: ldloc.1 + IL_001e: ldc.i4.0 + IL_001f: ldc.i4.0 + IL_0020: ldloc.1 + IL_0021: newobj "InterpolationHandler..ctor(int, int, in int)" + IL_0026: call "int E.get_Item(in int, InterpolationHandler)" + IL_002b: pop + IL_002c: ldloc.0 + IL_002d: call "void System.Console.Write(int)" + IL_0032: ret +} +"""); + + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) + .VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void InterpolationHandler_ReceiverParameter_ByRefMismatch_01(bool useMetadataRef, [CombinatorialValues("ref readonly", "in", "")] string refkind) + { + var src = $$""" +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount, ref int i) + { + System.Console.Write(i); + } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} + +public static class E +{ + extension({{refkind}} int i) + { + public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] { get => 0; } + } +} +"""; + + var exeSource = $$""" +int i = 1; +_ = i[$""]; +E.get_Item({{(refkind == "" ? "" : "in ")}}i, $""); +"""; + + var expectedDiagnostic = new[] { + // (2,5): error CS1620: Argument 3 must be passed with the 'ref' keyword + // _ = i[$""]; + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(2, 5), + // (3,12): error CS1620: Argument 3 must be passed with the 'ref' keyword + // E.get_Item(i, $""); + Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref") + }; + + CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostic); + + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + CreateCompilation(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostic); + } + + [Theory, CombinatorialData] + public void InterpolationHandler_ReceiverParameter_ByRefMismatch_02(bool useMetadataRef, [CombinatorialValues("ref readonly", "in")] string refkind) + { + var src = $$""" +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount, {{refkind}} int i) + { + System.Console.Write(i); + System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; + } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} + +public static class E +{ + extension(ref int i) + { + public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] + { + get + { + System.Console.Write(i); + i++; + return 0; + } + } + } +} +"""; + + var exeSource = """ +int i = 1; +_ = i[$""]; +System.Console.Write(i); +E.get_Item(ref i, $""); +System.Console.Write(i); +"""; + + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123345" : null; + CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) + .VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void InterpolationHandler_ReceiverParameter_ByRefMismatch_03(bool useMetadataRef) + { + var src = $$""" +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount, int i) + { + System.Console.WriteLine(i); + } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} + +public static class E +{ + extension(ref int i) { - E.get_Item(3, $""); + public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] { get => 0; } } } """; - var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "1234" : null; - var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + var exeSource = """ +int i = 1; +_ = i[$""]; +E.get_Item(ref i, $""); +"""; - verifier.VerifyIL("Program.Test1", $$$""" -{ - // Code size 20 (0x14) - .maxstack 4 - .locals init (int V_0) - IL_0000: ldc.i4.1 - IL_0001: stloc.0 - IL_0002: ldloca.s V_0 - IL_0004: ldc.i4.0 - IL_0005: ldc.i4.0 - IL_0006: ldloca.s V_0 - IL_0008: newobj "InterpolationHandler..ctor(int, int, {{{refkind}}} int)" - IL_000d: call "int E.get_Item({{{refkind}}} int, InterpolationHandler)" - IL_0012: pop - IL_0013: ret -} -"""); + var expectedDiagnostics = new[] { + // (2,5): error CS1615: Argument 3 may not be passed with the 'ref' keyword + // _ = i[$""]; + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(2, 5), + // (3,16): error CS1615: Argument 3 may not be passed with the 'ref' keyword + // E.get_Item(ref i, $""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(3, 16) + }; - verifier.VerifyIL("Program.Test2", $$$""" -{ - // Code size 20 (0x14) - .maxstack 4 - .locals init (int V_0) - IL_0000: ldc.i4.3 - IL_0001: stloc.0 - IL_0002: ldloca.s V_0 - IL_0004: ldc.i4.0 - IL_0005: ldc.i4.0 - IL_0006: ldloca.s V_0 - IL_0008: newobj "InterpolationHandler..ctor(int, int, {{{refkind}}} int)" - IL_000d: call "int E.get_Item({{{refkind}}} int, InterpolationHandler)" - IL_0012: pop - IL_0013: ret -} -"""); + CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify); + CreateCompilation(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] - public void InterpolationHandler_ReceiverParameter_ByIn_WithLocalReceiver(bool useMetadataRef) + public void InterpolationHandler_StructReceiverParameter_ByValue(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, in int i) + public InterpolationHandler(int literalLength, int formattedCount, MyStruct s) { - System.Console.Write(i); - System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; + System.Console.Write(s.i); + s.i++; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } +public struct MyStruct +{ + public int i; +} + public static class E { - extension(in int i) + extension(MyStruct s) { - public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] + public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] { get { - System.Console.Write(i); - System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; + System.Console.Write(s.i); + s.i++; return 0; } } @@ -15381,46 +17669,38 @@ public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgume """; var exeSource = """ -int i = 1; -_ = i[$""]; -System.Console.Write(i); -E.get_Item(i, $""); -System.Console.Write(i); +_ = new MyStruct()[$""]; +E.get_Item(new MyStruct(), $""); """; - var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123345" : null; - var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "0000" : null; + var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) + .VerifyDiagnostics(); + verifier.VerifyIL("", """ { - // Code size 51 (0x33) + // Code size 47 (0x2f) .maxstack 4 - .locals init (int V_0, //i - int& V_1) - IL_0000: ldc.i4.1 - IL_0001: stloc.0 - IL_0002: ldloca.s V_0 - IL_0004: stloc.1 - IL_0005: ldloc.1 - IL_0006: ldc.i4.0 - IL_0007: ldc.i4.0 - IL_0008: ldloc.1 - IL_0009: newobj "InterpolationHandler..ctor(int, int, in int)" - IL_000e: call "int E.get_Item(in int, InterpolationHandler)" - IL_0013: pop - IL_0014: ldloc.0 - IL_0015: call "void System.Console.Write(int)" - IL_001a: ldloca.s V_0 - IL_001c: stloc.1 - IL_001d: ldloc.1 - IL_001e: ldc.i4.0 - IL_001f: ldc.i4.0 - IL_0020: ldloc.1 - IL_0021: newobj "InterpolationHandler..ctor(int, int, in int)" - IL_0026: call "int E.get_Item(in int, InterpolationHandler)" - IL_002b: pop - IL_002c: ldloc.0 - IL_002d: call "void System.Console.Write(int)" - IL_0032: ret + .locals init (MyStruct V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "MyStruct" + IL_0008: ldloc.0 + IL_0009: ldc.i4.0 + IL_000a: ldc.i4.0 + IL_000b: ldloc.0 + IL_000c: newobj "InterpolationHandler..ctor(int, int, MyStruct)" + IL_0011: call "int E.get_Item(MyStruct, InterpolationHandler)" + IL_0016: pop + IL_0017: ldloca.s V_0 + IL_0019: initobj "MyStruct" + IL_001f: ldloc.0 + IL_0020: ldc.i4.0 + IL_0021: ldc.i4.0 + IL_0022: ldloc.0 + IL_0023: newobj "InterpolationHandler..ctor(int, int, MyStruct)" + IL_0028: call "int E.get_Item(MyStruct, InterpolationHandler)" + IL_002d: pop + IL_002e: ret } """); @@ -15431,158 +17711,292 @@ .locals init (int V_0, //i } [Theory, CombinatorialData] - public void InterpolationHandler_ReceiverParameter_ByRefMismatch_01(bool useMetadataRef, [CombinatorialValues("ref readonly", "in", "")] string refkind) + public void InterpolationHandler_StructReceiverParameter_ByValueThroughField(bool useMetadataRef) { - var src = $$""" + var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] public struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, ref int i) + public InterpolationHandler(int literalLength, int formattedCount, MyStruct s) { - System.Console.Write(i); + System.Console.Write(s.i); + E.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } +public struct MyStruct +{ + public int i; +} + public static class E { - extension({{refkind}} int i) + extension(MyStruct s) { - public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] { get => 0; } + public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] + { + get + { + System.Console.Write(s.i); + E.field.i++; + return 0; + } + } } + + public static MyStruct field; } """; - var exeSource = $$""" -int i = 1; -_ = i[$""]; -E.get_Item({{(refkind == "" ? "" : "in ")}}i, $""); + var exeSource = """ +_ = E.field[Increment(), $""]; +E.get_Item(E.field, Increment(), $""); + +int Increment() => E.field.i++; """; - var expectedDiagnostic = new[] { - // (2,5): error CS1620: Argument 3 must be passed with the 'ref' keyword - // _ = i[$""]; - Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(2, 5), - // (3,12): error CS1620: Argument 3 must be passed with the 'ref' keyword - // E.get_Item(i, $""); - Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref") - }; + // See GetExtensionBlockMemberReceiverCaptureRefKind + var expectedOutput = "1233"; + var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) + .VerifyDiagnostics(); - CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostic); + verifier.VerifyIL("", """ +{ + // Code size 67 (0x43) + .maxstack 5 + .locals init (MyStruct& V_0, + int V_1, + InterpolationHandler V_2, + MyStruct V_3) + IL_0000: ldsflda "MyStruct E.field" + IL_0005: stloc.0 + IL_0006: call "int Program.<
$>g__Increment|0_0()" + IL_000b: stloc.1 + IL_000c: ldc.i4.0 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: ldobj "MyStruct" + IL_0014: newobj "InterpolationHandler..ctor(int, int, MyStruct)" + IL_0019: stloc.2 + IL_001a: ldloc.0 + IL_001b: ldobj "MyStruct" + IL_0020: ldloc.1 + IL_0021: ldloc.2 + IL_0022: call "int E.get_Item(MyStruct, int, InterpolationHandler)" + IL_0027: pop + IL_0028: ldsfld "MyStruct E.field" + IL_002d: stloc.3 + IL_002e: ldloc.3 + IL_002f: call "int Program.<
$>g__Increment|0_0()" + IL_0034: ldc.i4.0 + IL_0035: ldc.i4.0 + IL_0036: ldloc.3 + IL_0037: newobj "InterpolationHandler..ctor(int, int, MyStruct)" + IL_003c: call "int E.get_Item(MyStruct, int, InterpolationHandler)" + IL_0041: pop + IL_0042: ret +} +"""); - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); - CreateCompilation(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostic); + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) + .VerifyDiagnostics(); } [Theory, CombinatorialData] - public void InterpolationHandler_ReceiverParameter_ByRefMismatch_02(bool useMetadataRef, [CombinatorialValues("ref readonly", "in")] string refkind) + public void InterpolationHandler_StructReceiverParameter_Generic_ByValueThroughField(bool useMetadataRef) { - var src = $$""" + var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +public struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, {{refkind}} int i) + public InterpolationHandler(int literalLength, int formattedCount, TR s) { - System.Console.Write(i); - System.Runtime.CompilerServices.Unsafe.AsRef(in i)++; + System.Console.Write(((MyStruct)(object)s).i); + E.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } +public struct MyStruct +{ + public int i; +} + public static class E { - extension(ref int i) + extension(T s) { - public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] + public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] { get { - System.Console.Write(i); - i++; + System.Console.Write(((MyStruct)(object)s).i); + E.field.i++; return 0; } } } } -"""; - var exeSource = """ -int i = 1; -_ = i[$""]; -System.Console.Write(i); -E.get_Item(ref i, $""); -System.Console.Write(i); +public static class E +{ + public static T field; +} """; - var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123345" : null; - CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify).VerifyDiagnostics(); - - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + var exeSource = """ +class Program +{ + static void Main() + { + Test1(); + Test2(); + Test3(); + Test4(); + } - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) - .VerifyDiagnostics(); + static void Test1() + { + _ = E.field[Increment(), $""]; } - [Theory, CombinatorialData] - public void InterpolationHandler_ReceiverParameter_ByRefMismatch_03(bool useMetadataRef) + static void Test2() { - var src = $$""" -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler -{ - public InterpolationHandler(int literalLength, int formattedCount, int i) + E.get_Item(E.field, Increment(), $""); + } + + static void Test3() where T : struct { - System.Console.WriteLine(i); + _ = E.field[Increment(), $""]; } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; -} -public static class E -{ - extension(ref int i) + static void Test4() where T : struct { - public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] { get => 0; } + E.get_Item(E.field, Increment(), $""); } + + static int Increment() => E.field.i++; } """; - var exeSource = """ -int i = 1; -_ = i[$""]; -E.get_Item(ref i, $""); + // See GetExtensionBlockMemberReceiverCaptureRefKind + var expectedOutput = "12337899"; + var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) + .VerifyDiagnostics(); + + verifier.VerifyIL("Program.Test1", """ +{ + // Code size 73 (0x49) + .maxstack 3 + .locals init (T& V_0, + T V_1, + T& V_2, + int V_3, + InterpolationHandler V_4, + T V_5) + IL_0000: ldsflda "T E.field" + IL_0005: stloc.2 + IL_0006: ldloca.s V_5 + IL_0008: initobj "T" + IL_000e: ldloc.s V_5 + IL_0010: box "T" + IL_0015: brtrue.s IL_0022 + IL_0017: ldloc.2 + IL_0018: ldobj "T" + IL_001d: stloc.1 + IL_001e: ldloca.s V_1 + IL_0020: br.s IL_0023 + IL_0022: ldloc.2 + IL_0023: stloc.0 + IL_0024: call "int Program.Increment()" + IL_0029: stloc.3 + IL_002a: ldc.i4.0 + IL_002b: ldc.i4.0 + IL_002c: ldloc.0 + IL_002d: ldobj "T" + IL_0032: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0037: stloc.s V_4 + IL_0039: ldloc.0 + IL_003a: ldobj "T" + IL_003f: ldloc.3 + IL_0040: ldloc.s V_4 + IL_0042: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0047: pop + IL_0048: ret +} +"""); + + var expectedIL = """ +{ + // Code size 27 (0x1b) + .maxstack 5 + .locals init (T V_0) + IL_0000: ldsfld "T E.field" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call "int Program.Increment()" + IL_000c: ldc.i4.0 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0019: pop + IL_001a: ret +} """; + verifier.VerifyIL("Program.Test2", expectedIL); - var expectedDiagnostics = new[] { - // (2,5): error CS1615: Argument 3 may not be passed with the 'ref' keyword - // _ = i[$""]; - Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(2, 5), - // (3,16): error CS1615: Argument 3 may not be passed with the 'ref' keyword - // E.get_Item(ref i, $""); - Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(3, 16) - }; + verifier.VerifyIL("Program.Test3", """ +{ + // Code size 41 (0x29) + .maxstack 3 + .locals init (T& V_0, + int V_1, + InterpolationHandler V_2) + IL_0000: ldsflda "T E.field" + IL_0005: stloc.0 + IL_0006: call "int Program.Increment()" + IL_000b: stloc.1 + IL_000c: ldc.i4.0 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: ldobj "T" + IL_0014: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0019: stloc.2 + IL_001a: ldloc.0 + IL_001b: ldobj "T" + IL_0020: ldloc.1 + IL_0021: ldloc.2 + IL_0022: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0027: pop + IL_0028: ret +} +"""); - CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); + verifier.VerifyIL("Program.Test4", expectedIL); - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); - CreateCompilation(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) + .VerifyDiagnostics(); } [Theory, CombinatorialData] - public void InterpolationHandler_StructReceiverParameter_ByValue(bool useMetadataRef) + public void InterpolationHandler_StructReceiverParameter_Generic_ByValueThroughField_CompoundAssignment(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +public struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, MyStruct s) + public InterpolationHandler(int literalLength, int formattedCount, TR s) { - System.Console.Write(s.i); - s.i++; + System.Console.Write(((MyStruct)(object)s).i); + E.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; @@ -15595,74 +18009,76 @@ public struct MyStruct public static class E { - extension(MyStruct s) + extension(T s) { - public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] + public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] { get { - System.Console.Write(s.i); - s.i++; + System.Console.Write(((MyStruct)(object)s).i); + E.field.i++; return 0; } + set + { + System.Console.Write(((MyStruct)(object)s).i); + System.Console.Write(" "); + E.field.i++; + } } } } + +public static class E +{ + public static T field; +} """; var exeSource = """ -_ = new MyStruct()[$""]; -E.get_Item(new MyStruct(), $""); -"""; +class Program +{ + static void Main() + { + Test1(); + Test3(); + } - var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "0000" : null; - var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) - .VerifyDiagnostics(); + static void Test1() + { + E.field[Increment(), $""] += 0; + } - verifier.VerifyIL("", """ -{ - // Code size 47 (0x2f) - .maxstack 4 - .locals init (MyStruct V_0) - IL_0000: ldloca.s V_0 - IL_0002: initobj "MyStruct" - IL_0008: ldloc.0 - IL_0009: ldc.i4.0 - IL_000a: ldc.i4.0 - IL_000b: ldloc.0 - IL_000c: newobj "InterpolationHandler..ctor(int, int, MyStruct)" - IL_0011: call "int E.get_Item(MyStruct, InterpolationHandler)" - IL_0016: pop - IL_0017: ldloca.s V_0 - IL_0019: initobj "MyStruct" - IL_001f: ldloc.0 - IL_0020: ldc.i4.0 - IL_0021: ldc.i4.0 - IL_0022: ldloc.0 - IL_0023: newobj "InterpolationHandler..ctor(int, int, MyStruct)" - IL_0028: call "int E.get_Item(MyStruct, InterpolationHandler)" - IL_002d: pop - IL_002e: ret + static void Test3() where T : struct + { + E.field[Increment(), $""] += 0; + } + + static int Increment() => E.field.i++; } -"""); +"""; - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + var expectedOutput = "123 567"; + var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) + .VerifyDiagnostics(); - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, expectedOutput: expectedOutput, verify: Verification.FailsPEVerify) + var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); + + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) .VerifyDiagnostics(); } [Theory, CombinatorialData] - public void InterpolationHandler_StructReceiverParameter_ByValueThroughField(bool useMetadataRef) + public void InterpolationHandler_StructReceiverParameter_GenericStruct_ByValueThroughField(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +public struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, MyStruct s) + public InterpolationHandler(int literalLength, int formattedCount, TR s) { - System.Console.Write(s.i); - E.field.i++; + System.Console.Write(((MyStruct)(object)s).i); + E.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; @@ -15675,70 +18091,96 @@ public struct MyStruct public static class E { - extension(MyStruct s) + extension(T s) where T : struct { - public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] + public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] { get { - System.Console.Write(s.i); - E.field.i++; + System.Console.Write(((MyStruct)(object)s).i); + E.field.i++; return 0; } } } +} - public static MyStruct field; +public static class E +{ + public static T field; } """; var exeSource = """ -_ = E.field[Increment(), $""]; -E.get_Item(E.field, Increment(), $""); +class Program +{ + static void Main() + { + Test3(); + Test4(); + } -int Increment() => E.field.i++; + static void Test3() where T : struct + { + _ = E.field[Increment(), $""]; + } + + static void Test4() where T : struct + { + E.get_Item(E.field, Increment(), $""); + } + + static int Increment() => E.field.i++; +} """; - // See GetExtensionBlockMemberReceiverCaptureRefKind var expectedOutput = "1233"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) .VerifyDiagnostics(); - verifier.VerifyIL("", """ + verifier.VerifyIL("Program.Test3", """ { - // Code size 67 (0x43) - .maxstack 5 - .locals init (MyStruct& V_0, + // Code size 41 (0x29) + .maxstack 3 + .locals init (T& V_0, int V_1, - InterpolationHandler V_2, - MyStruct V_3) - IL_0000: ldsflda "MyStruct E.field" + InterpolationHandler V_2) + IL_0000: ldsflda "T E.field" IL_0005: stloc.0 - IL_0006: call "int Program.<
$>g__Increment|0_0()" + IL_0006: call "int Program.Increment()" IL_000b: stloc.1 IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 - IL_000f: ldobj "MyStruct" - IL_0014: newobj "InterpolationHandler..ctor(int, int, MyStruct)" + IL_000f: ldobj "T" + IL_0014: newobj "InterpolationHandler..ctor(int, int, T)" IL_0019: stloc.2 IL_001a: ldloc.0 - IL_001b: ldobj "MyStruct" + IL_001b: ldobj "T" IL_0020: ldloc.1 IL_0021: ldloc.2 - IL_0022: call "int E.get_Item(MyStruct, int, InterpolationHandler)" + IL_0022: call "int E.get_Item(T, int, InterpolationHandler)" IL_0027: pop - IL_0028: ldsfld "MyStruct E.field" - IL_002d: stloc.3 - IL_002e: ldloc.3 - IL_002f: call "int Program.<
$>g__Increment|0_0()" - IL_0034: ldc.i4.0 - IL_0035: ldc.i4.0 - IL_0036: ldloc.3 - IL_0037: newobj "InterpolationHandler..ctor(int, int, MyStruct)" - IL_003c: call "int E.get_Item(MyStruct, int, InterpolationHandler)" - IL_0041: pop - IL_0042: ret + IL_0028: ret +} +"""); + + verifier.VerifyIL("Program.Test4", """ +{ + // Code size 27 (0x1b) + .maxstack 5 + .locals init (T V_0) + IL_0000: ldsfld "T E.field" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call "int Program.Increment()" + IL_000c: ldc.i4.0 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0019: pop + IL_001a: ret } """); @@ -15749,7 +18191,7 @@ .locals init (MyStruct& V_0, } [Theory, CombinatorialData] - public void InterpolationHandler_StructReceiverParameter_Generic_ByValueThroughField(bool useMetadataRef) + public void InterpolationHandler_ClassReceiverParameter_GenericClass_ByValueThroughField(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] @@ -15757,14 +18199,14 @@ public struct InterpolationHandler { public InterpolationHandler(int literalLength, int formattedCount, TR s) { - System.Console.Write(((MyStruct)(object)s).i); - E.field.i++; + System.Console.Write(((MyClass)(object)s).i); + E.field = new MyClass() { i = E.field.i + 1 }; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -public struct MyStruct +public class MyClass { public int i; } @@ -15777,8 +18219,8 @@ public static class E { get { - System.Console.Write(((MyStruct)(object)s).i); - E.field.i++; + System.Console.Write(((MyClass)(object)s).i); + E.field = new MyClass() { i = E.field.i + 1 }; return 0; } } @@ -15796,10 +18238,11 @@ class Program { static void Main() { - Test1(); - Test2(); - Test3(); - Test4(); + E.field = new MyClass(); + Test1(); + Test2(); + Test3(); + Test4(); } static void Test1() @@ -15812,22 +18255,21 @@ static void Test2() E.get_Item(E.field, Increment(), $""); } - static void Test3() where T : struct + static void Test3() where T : class { _ = E.field[Increment(), $""]; } - static void Test4() where T : struct + static void Test4() where T : class { E.get_Item(E.field, Increment(), $""); } - static int Increment() => E.field.i++; + static int Increment() => (E.field = new MyClass() { i = E.field.i + 1 }).i; } """; - // See GetExtensionBlockMemberReceiverCaptureRefKind - var expectedOutput = "12337899"; + var expectedOutput = "00336699"; var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) .VerifyDiagnostics(); @@ -15873,7 +18315,141 @@ .locals init (T& V_0, } """); - var expectedIL = """ + verifier.VerifyIL("Program.Test2", """ +{ + // Code size 27 (0x1b) + .maxstack 5 + .locals init (T V_0) + IL_0000: ldsfld "T E.field" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call "int Program.Increment()" + IL_000c: ldc.i4.0 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0019: pop + IL_001a: ret +} +"""); + + verifier.VerifyIL("Program.Test3", """ +{ + // Code size 27 (0x1b) + .maxstack 5 + .locals init (T V_0) + IL_0000: ldsfld "T E.field" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call "int Program.Increment()" + IL_000c: ldc.i4.0 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0019: pop + IL_001a: ret +} +"""); + + verifier.VerifyIL("Program.Test4", """ +{ + // Code size 27 (0x1b) + .maxstack 5 + .locals init (T V_0) + IL_0000: ldsfld "T E.field" + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: call "int Program.Increment()" + IL_000c: ldc.i4.0 + IL_000d: ldc.i4.0 + IL_000e: ldloc.0 + IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0019: pop + IL_001a: ret +} +"""); + + var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); + + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) + .VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void InterpolationHandler_ClassReceiverParameter_Generic_ByValueThroughField(bool useMetadataRef) + { + var src = """ +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount, TR s) + { + System.Console.Write(((MyClass)(object)s).i); + E.field = new MyClass() { i = E.field.i + 1 }; + } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} + +public class MyClass +{ + public int i; +} + +public static class E +{ + extension(T s) where T : class + { + public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] + { + get + { + System.Console.Write(((MyClass)(object)s).i); + E.field = new MyClass() { i = E.field.i + 1 }; + return 0; + } + } + } +} + +public static class E +{ + public static T field; +} +"""; + + var exeSource = """ +class Program +{ + static void Main() + { + E.field = new MyClass(); + Test3(); + Test4(); + } + + static void Test3() where T : class + { + _ = E.field[Increment(), $""]; + } + + static void Test4() where T : class + { + E.get_Item(E.field, Increment(), $""); + } + + static int Increment() => (E.field = new MyClass() { i = E.field.i + 1 }).i; +} +"""; + + var expectedOutput = "0033"; + var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) + .VerifyDiagnostics(); + + verifier.VerifyIL("Program.Test3", """ { // Code size 27 (0x1b) .maxstack 5 @@ -15890,38 +18466,27 @@ .locals init (T V_0) IL_0019: pop IL_001a: ret } -"""; - verifier.VerifyIL("Program.Test2", expectedIL); +"""); - verifier.VerifyIL("Program.Test3", """ + verifier.VerifyIL("Program.Test4", """ { - // Code size 41 (0x29) - .maxstack 3 - .locals init (T& V_0, - int V_1, - InterpolationHandler V_2) - IL_0000: ldsflda "T E.field" + // Code size 27 (0x1b) + .maxstack 5 + .locals init (T V_0) + IL_0000: ldsfld "T E.field" IL_0005: stloc.0 - IL_0006: call "int Program.Increment()" - IL_000b: stloc.1 + IL_0006: ldloc.0 + IL_0007: call "int Program.Increment()" IL_000c: ldc.i4.0 IL_000d: ldc.i4.0 IL_000e: ldloc.0 - IL_000f: ldobj "T" - IL_0014: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0019: stloc.2 - IL_001a: ldloc.0 - IL_001b: ldobj "T" - IL_0020: ldloc.1 - IL_0021: ldloc.2 - IL_0022: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0027: pop - IL_0028: ret + IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" + IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" + IL_0019: pop + IL_001a: ret } """); - verifier.VerifyIL("Program.Test4", expectedIL); - var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) @@ -15929,1712 +18494,1937 @@ .locals init (T& V_0, } [Theory, CombinatorialData] - public void InterpolationHandler_StructReceiverParameter_Generic_ByValueThroughField_CompoundAssignment(bool useMetadataRef) + public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_01(bool useMetadataRef) { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +public ref struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, TR s) +#pragma warning disable CS0169 // The field 'InterpolationHandler.i' is never used + private ref int i; +#pragma warning restore CS0169 // The field 'InterpolationHandler.i' is never used + + public InterpolationHandler(int literalLength, int formattedCount, scoped MyStruct s) { - System.Console.Write(((MyStruct)(object)s).i); - E.field.i++; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -public struct MyStruct +public ref struct MyStruct { - public int i; + public ref int i; } public static class E { - extension(T s) + extension(MyStruct s) { - public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] + public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] { get { - System.Console.Write(((MyStruct)(object)s).i); - E.field.i++; - return 0; - } - set - { - System.Console.Write(((MyStruct)(object)s).i); - System.Console.Write(" "); - E.field.i++; + return new(); } } } } - -public static class E -{ - public static T field; -} """; var exeSource = """ -class Program +#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used +MyStruct localFunc() +#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { - static void Main() - { - Test1(); - Test3(); - } - - static void Test1() - { - E.field[Increment(), $""] += 0; - } - - static void Test3() where T : struct - { - E.field[Increment(), $""] += 0; - } - - static int Increment() => E.field.i++; + return new MyStruct()[$""]; } """; - var expectedOutput = "123 567"; - var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) - .VerifyDiagnostics(); + var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, verify: Verification.Fails).VerifyDiagnostics(); - var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); + verifier.VerifyIL("Program.<
$>g__localFunc|0_0()", """ +{ + // Code size 23 (0x17) + .maxstack 4 + .locals init (MyStruct V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "MyStruct" + IL_0008: ldloc.0 + IL_0009: ldc.i4.0 + IL_000a: ldc.i4.0 + IL_000b: ldloc.0 + IL_000c: newobj "InterpolationHandler..ctor(int, int, scoped MyStruct)" + IL_0011: call "MyStruct E.get_Item(MyStruct, InterpolationHandler)" + IL_0016: ret +} +"""); - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, verify: Verification.Fails) .VerifyDiagnostics(); } - [Theory, CombinatorialData] - public void InterpolationHandler_StructReceiverParameter_GenericStruct_ByValueThroughField(bool useMetadataRef) + [Fact] + public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_02() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +public ref struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, TR s) + public ref int i; + + public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { - System.Console.Write(((MyStruct)(object)s).i); - E.field.i++; + i = ref s2.i; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -public struct MyStruct +public ref struct MyStruct { - public int i; + public ref int i; } public static class E { - extension(T s) where T : struct + extension(MyStruct s1) { - public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] - { - get - { - System.Console.Write(((MyStruct)(object)s).i); - E.field.i++; - return 0; - } - } + public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] InterpolationHandler h] + => new() { i = ref h.i }; } } +"""; -public static class E + var exeSource = """ +#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used +MyStruct localFunc() +#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { - public static T field; + int i = 0; + return new MyStruct() { i = ref i }[$""]; } """; - var exeSource = """ -class Program -{ - static void Main() - { - Test3(); - Test4(); + CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics( + // (6,27): error CS8352: Cannot use variable 'i = ref i' in this context because it may expose referenced variables outside of their declaration scope + // return new MyStruct() { i = ref i }[$""]; + Diagnostic(ErrorCode.ERR_EscapeVariable, "{ i = ref i }").WithArguments("i = ref i").WithLocation(6, 27), + // (6,12): error CS8347: Cannot use a result of 'E.extension(MyStruct).this[InterpolationHandler]' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope + // return new MyStruct() { i = ref i }[$""]; + Diagnostic(ErrorCode.ERR_EscapeCall, @"new MyStruct() { i = ref i }[$""""]").WithArguments("E.extension(MyStruct).this[InterpolationHandler]", "s1").WithLocation(6, 12) + ); } - static void Test3() where T : struct + [Fact] + public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_05() { - _ = E.field[Increment(), $""]; - } + var src = """ +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public ref struct InterpolationHandler +{ + public ref int i; - static void Test4() where T : struct + public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { - E.get_Item(E.field, Increment(), $""); + i = ref s2.i; } - - static int Increment() => E.field.i++; + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -"""; - var expectedOutput = "1233"; - var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) - .VerifyDiagnostics(); +public ref struct MyStruct +{ + public ref int i; +} - verifier.VerifyIL("Program.Test3", """ +public static class E { - // Code size 41 (0x29) - .maxstack 3 - .locals init (T& V_0, - int V_1, - InterpolationHandler V_2) - IL_0000: ldsflda "T E.field" - IL_0005: stloc.0 - IL_0006: call "int Program.Increment()" - IL_000b: stloc.1 - IL_000c: ldc.i4.0 - IL_000d: ldc.i4.0 - IL_000e: ldloc.0 - IL_000f: ldobj "T" - IL_0014: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0019: stloc.2 - IL_001a: ldloc.0 - IL_001b: ldobj "T" - IL_0020: ldloc.1 - IL_0021: ldloc.2 - IL_0022: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0027: pop - IL_0028: ret + extension(scoped MyStruct s1) + { + public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] InterpolationHandler h] + => new() { i = ref h.i }; + } } -"""); +"""; - verifier.VerifyIL("Program.Test4", """ + var exeSource = """ +#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used +MyStruct localFunc() +#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { - // Code size 27 (0x1b) - .maxstack 5 - .locals init (T V_0) - IL_0000: ldsfld "T E.field" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call "int Program.Increment()" - IL_000c: ldc.i4.0 - IL_000d: ldc.i4.0 - IL_000e: ldloc.0 - IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0019: pop - IL_001a: ret + int i = 0; + return new MyStruct() { i = ref i }[$""]; } -"""); - - var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); +"""; - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) - .VerifyDiagnostics(); + CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics( + // (6,12): error CS8352: Cannot use variable 'new MyStruct() { i = ref i }' in this context because it may expose referenced variables outside of their declaration scope + // return new MyStruct() { i = ref i }[$""]; + Diagnostic(ErrorCode.ERR_EscapeVariable, "new MyStruct() { i = ref i }").WithArguments("new MyStruct() { i = ref i }").WithLocation(6, 12), + // (6,12): error CS8347: Cannot use a result of 'E.extension(scoped MyStruct).this[InterpolationHandler]' in this context because it may expose variables referenced by parameter 'h' outside of their declaration scope + // return new MyStruct() { i = ref i }[$""]; + Diagnostic(ErrorCode.ERR_EscapeCall, @"new MyStruct() { i = ref i }[$""""]").WithArguments("E.extension(scoped MyStruct).this[InterpolationHandler]", "h").WithLocation(6, 12), + // (6,41): error CS8347: Cannot use a result of 'InterpolationHandler.InterpolationHandler(int, int, MyStruct)' in this context because it may expose variables referenced by parameter 's2' outside of their declaration scope + // return new MyStruct() { i = ref i }[$""]; + Diagnostic(ErrorCode.ERR_EscapeCall, @"$""""").WithArguments("InterpolationHandler.InterpolationHandler(int, int, MyStruct)", "s2").WithLocation(6, 41) + ); } - [Theory, CombinatorialData] - public void InterpolationHandler_ClassReceiverParameter_GenericClass_ByValueThroughField(bool useMetadataRef) + [Fact] + public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_06() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +public ref struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, TR s) + public ref int i; + + public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) { - System.Console.Write(((MyClass)(object)s).i); - E.field = new MyClass() { i = E.field.i + 1 }; + i = ref s2.i; } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -public class MyClass +public ref struct MyStruct { - public int i; + public ref int i; } public static class E { - extension(T s) + extension(scoped MyStruct s1) { - public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] - { - get - { - System.Console.Write(((MyClass)(object)s).i); - E.field = new MyClass() { i = E.field.i + 1 }; - return 0; - } - } + public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] scoped InterpolationHandler h] + => new() { i = ref h.i }; } } +"""; -public static class E + var exeSource = """ +#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used +MyStruct localFunc() +#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used { - public static T field; + int i = 0; + return new MyStruct() { i = ref i }[$""]; } """; - var exeSource = """ -class Program -{ - static void Main() - { - E.field = new MyClass(); - Test1(); - Test2(); - Test3(); - Test4(); + CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics( + // (24,22): error CS8352: Cannot use variable 'i = ref h.i' in this context because it may expose referenced variables outside of their declaration scope + // => new() { i = ref h.i }; + Diagnostic(ErrorCode.ERR_EscapeVariable, "{ i = ref h.i }").WithArguments("i = ref h.i").WithLocation(24, 22) + ); } - static void Test1() + [Theory, CombinatorialData] + public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_07(bool useMetadataRef) { - _ = E.field[Increment(), $""]; - } + var src = """ +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public ref struct InterpolationHandler +{ +#pragma warning disable CS0169 // The field 'InterpolationHandler.i' is never used + private ref int i; +#pragma warning restore CS0169 // The field 'InterpolationHandler.i' is never used - static void Test2() + public InterpolationHandler(int literalLength, int formattedCount, scoped MyStruct s2) { - E.get_Item(E.field, Increment(), $""); } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} - static void Test3() where T : class - { - _ = E.field[Increment(), $""]; - } +public ref struct MyStruct +{ + public ref int i; +} - static void Test4() where T : class +public static class E +{ + extension(scoped MyStruct s1) { - E.get_Item(E.field, Increment(), $""); + public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] scoped InterpolationHandler h] + => new(); } +} +"""; - static int Increment() => (E.field = new MyClass() { i = E.field.i + 1 }).i; + var exeSource = """ +#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used +MyStruct localFunc() +#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used +{ + int i = 0; + return new MyStruct() { i = ref i }[$""]; } """; - var expectedOutput = "00336699"; - var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) - .VerifyDiagnostics(); + var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, verify: Verification.Fails).VerifyDiagnostics(); - verifier.VerifyIL("Program.Test1", """ + verifier.VerifyIL("Program.<
$>g__localFunc|0_0()", """ { - // Code size 73 (0x49) - .maxstack 3 - .locals init (T& V_0, - T V_1, - T& V_2, - int V_3, - InterpolationHandler V_4, - T V_5) - IL_0000: ldsflda "T E.field" - IL_0005: stloc.2 - IL_0006: ldloca.s V_5 - IL_0008: initobj "T" - IL_000e: ldloc.s V_5 - IL_0010: box "T" - IL_0015: brtrue.s IL_0022 - IL_0017: ldloc.2 - IL_0018: ldobj "T" - IL_001d: stloc.1 - IL_001e: ldloca.s V_1 - IL_0020: br.s IL_0023 - IL_0022: ldloc.2 - IL_0023: stloc.0 - IL_0024: call "int Program.Increment()" - IL_0029: stloc.3 - IL_002a: ldc.i4.0 - IL_002b: ldc.i4.0 - IL_002c: ldloc.0 - IL_002d: ldobj "T" - IL_0032: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0037: stloc.s V_4 - IL_0039: ldloc.0 - IL_003a: ldobj "T" - IL_003f: ldloc.3 - IL_0040: ldloc.s V_4 - IL_0042: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0047: pop - IL_0048: ret + // Code size 36 (0x24) + .maxstack 4 + .locals init (int V_0, //i + MyStruct V_1, + MyStruct V_2) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_2 + IL_0004: initobj "MyStruct" + IL_000a: ldloca.s V_2 + IL_000c: ldloca.s V_0 + IL_000e: stfld "ref int MyStruct.i" + IL_0013: ldloc.2 + IL_0014: stloc.1 + IL_0015: ldloc.1 + IL_0016: ldc.i4.0 + IL_0017: ldc.i4.0 + IL_0018: ldloc.1 + IL_0019: newobj "InterpolationHandler..ctor(int, int, scoped MyStruct)" + IL_001e: call "MyStruct E.get_Item(scoped MyStruct, scoped InterpolationHandler)" + IL_0023: ret } """); - verifier.VerifyIL("Program.Test2", """ + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, verify: Verification.Fails) + .VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void InterpolationHandler_ReceiverParameter_NullableMismatch_01(bool useMetadataRef, bool useOut) + { + string outParam = useOut ? ", out bool valid" : ""; + var src = $$""" +#nullable enable +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler { - // Code size 27 (0x1b) - .maxstack 5 - .locals init (T V_0) - IL_0000: ldsfld "T E.field" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call "int Program.Increment()" - IL_000c: ldc.i4.0 - IL_000d: ldc.i4.0 - IL_000e: ldloc.0 - IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0019: pop - IL_001a: ret + public InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{{outParam}}) + { + System.Console.Write(s1); + System.Console.Write(s2); + {{(useOut ? "valid = true;" : "")}} + } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string? format = null) => throw null!; } -"""); - verifier.VerifyIL("Program.Test3", """ +public static class E { - // Code size 27 (0x1b) - .maxstack 5 - .locals init (T V_0) - IL_0000: ldsfld "T E.field" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call "int Program.Increment()" - IL_000c: ldc.i4.0 - IL_000d: ldc.i4.0 - IL_000e: ldloc.0 - IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0019: pop - IL_001a: ret + extension(C? s1) + { + public int this[string? s2, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1", "s2")] InterpolationHandler h] { get => 0; } + } } -"""); - verifier.VerifyIL("Program.Test4", """ -{ - // Code size 27 (0x1b) - .maxstack 5 - .locals init (T V_0) - IL_0000: ldsfld "T E.field" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call "int Program.Increment()" - IL_000c: ldc.i4.0 - IL_000d: ldc.i4.0 - IL_000e: ldloc.0 - IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0019: pop - IL_001a: ret -} -"""); +public class C { } +"""; + + var exeSource = """ +#nullable enable +_ = ((C?)null)[null, $""]; // 1, 2 +_ = ((C?)null)["", $""]; // 3 +_ = new C()[null, $""]; // 4 +_ = new C()["", $""]; + +_ = E.get_Item(null, null, $""); // 5, 6 +_ = E.get_Item(new C(), null, $""); // 7 +_ = E.get_Item(null, "", $""); // 8 +_ = E.get_Item(new C(), "", $""); +"""; + + var expectedDiagnostics = new[] { + // (2,6): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = ((C?)null)[null, $""]; // 1, 2 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(C?)null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(2, 6), + // (2,16): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = ((C?)null)[null, $""]; // 1, 2 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(2, 16), + // (3,6): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = ((C?)null)["", $""]; // 3 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(C?)null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(3, 6), + // (4,13): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = new C()[null, $""]; // 4 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(4, 13), + // (7,16): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = E.get_Item(null, null, $""); // 5, 6 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(7, 16), + // (7,22): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = E.get_Item(null, null, $""); // 5, 6 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(7, 22), + // (8,25): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = E.get_Item(new C(), null, $""); // 7 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(8, 25), + // (9,16): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. + // _ = E.get_Item(null, "", $""); // 8 + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(9, 16) + }; + + CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); - var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) - .VerifyDiagnostics(); + CreateCompilation(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); } [Theory, CombinatorialData] - public void InterpolationHandler_ClassReceiverParameter_Generic_ByValueThroughField(bool useMetadataRef) + public void InterpolationHandler_ReceiverParameter_NullableMismatch_02(bool useMetadataRef, bool useOut) { - var src = """ + string outParam = useOut ? ", out bool valid" : ""; + var src = $$""" +#nullable enable [System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +public struct InterpolationHandler { - public InterpolationHandler(int literalLength, int formattedCount, TR s) + public InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{{outParam}}) { - System.Console.Write(((MyClass)(object)s).i); - E.field = new MyClass() { i = E.field.i + 1 }; + System.Console.Write(s1); + System.Console.Write(s2); + {{(useOut ? "valid = true;" : "")}} } public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; -} - -public class MyClass -{ - public int i; + public void AppendFormatted(T hole, int alignment = 0, string? format = null) => throw null!; } public static class E { - extension(T s) where T : class + extension(C? s1) { - public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] - { - get - { - System.Console.Write(((MyClass)(object)s).i); - E.field = new MyClass() { i = E.field.i + 1 }; - return 0; - } - } + public int this[string? s2, string? s3, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s2", "s3")] InterpolationHandler h] { get => 0; } } } -public static class E -{ - public static T field; -} +public class C { } """; var exeSource = """ -class Program -{ - static void Main() - { - E.field = new MyClass(); - Test3(); - Test4(); +#nullable enable +_ = new C()[null, null, $""]; +_ = new C()[null, "", $""]; +_ = new C()["", null, $""]; +_ = new C()["", "", $""]; + +E.get_Item(new C(), null, null, $""); +E.get_Item(new C(), "", null, $""); +E.get_Item(new C(), null, "", $""); +E.get_Item(new C(), "", "", $""); +"""; + + var expectedDiagnostics = new[] { + // (2,13): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // _ = new C()[null, null, $""]; + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 13), + // (2,19): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // _ = new C()[null, null, $""]; + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 19), + // (3,13): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // _ = new C()[null, "", $""]; + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(3, 13), + // (4,17): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // _ = new C()["", null, $""]; + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(4, 17), + // (7,21): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // E.get_Item(new C(), null, null, $""); + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(7, 21), + // (7,27): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // E.get_Item(new C(), null, null, $""); + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(7, 27), + // (8,25): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // E.get_Item(new C(), "", null, $""); + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(8, 25), + // (9,21): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. + // E.get_Item(new C(), null, "", $""); + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(9, 21) + }; + + CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); + + var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + + CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); } - static void Test3() where T : class + [Fact] + public void InterpolationHandler_ParameterErrors_MappedCorrectly_01() { - _ = E.field[Increment(), $""]; + var src = """ +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler +{ + public InterpolationHandler(int literalLength, int formattedCount, int i) + { + System.Console.WriteLine(i); } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; +} - static void Test4() where T : class +public static class E +{ + extension(int i) { - E.get_Item(E.field, Increment(), $""); + public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h] { get => 0; } } - - static int Increment() => (E.field = new MyClass() { i = E.field.i + 1 }).i; } """; - var expectedOutput = "0033"; - var verifier = CompileAndVerify([exeSource, src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute], expectedOutput: expectedOutput) - .VerifyDiagnostics(); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.VerifyDiagnostics( + // (16,26): error CS8945: 'nonexistent' is not a valid parameter name from 'E.extension(int).this[InterpolationHandler]'. + // public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h] { get => 0; } + Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""nonexistent"")").WithArguments("nonexistent", "E.extension(int).this[InterpolationHandler]").WithLocation(16, 26) + ); - verifier.VerifyIL("Program.Test3", """ + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.True(symbol.IsExtension); + var underlying = symbol.GetSymbol(); + var indexer = underlying.GetMember("this[]"); + Assert.False(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); + Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); + Assert.True(indexer.Parameters[0].HasInterpolatedStringHandlerArgumentError); + Assert.True(indexer.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); + + var implGetter = underlying.ContainingType.GetMember("get_Item"); + Assert.False(implGetter.Parameters[0].HasInterpolatedStringHandlerArgumentError); + Assert.True(implGetter.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); + Assert.True(implGetter.Parameters[1].HasInterpolatedStringHandlerArgumentError); + Assert.True(implGetter.Parameters[1].InterpolatedStringHandlerArgumentIndexes.IsEmpty); + } + + [Theory] + [InlineData("i")] + [InlineData("")] + [InlineData("nonexistent")] + public void InterpolationHandler_ParameterErrors_MappedCorrectly_02(string attributeValue) + { + var src = $$""" +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct InterpolationHandler { - // Code size 27 (0x1b) - .maxstack 5 - .locals init (T V_0) - IL_0000: ldsfld "T E.field" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call "int Program.Increment()" - IL_000c: ldc.i4.0 - IL_000d: ldc.i4.0 - IL_000e: ldloc.0 - IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0019: pop - IL_001a: ret + public InterpolationHandler(int literalLength, int formattedCount, InterpolationHandler i) + { + System.Console.WriteLine(i); + } + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -"""); - verifier.VerifyIL("Program.Test4", """ +public static class E { - // Code size 27 (0x1b) - .maxstack 5 - .locals init (T V_0) - IL_0000: ldsfld "T E.field" - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: call "int Program.Increment()" - IL_000c: ldc.i4.0 - IL_000d: ldc.i4.0 - IL_000e: ldloc.0 - IL_000f: newobj "InterpolationHandler..ctor(int, int, T)" - IL_0014: call "int E.get_Item(T, int, InterpolationHandler)" - IL_0019: pop - IL_001a: ret + extension([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("{{attributeValue}}")] InterpolationHandler i) + { + public int this[int j] { get => 0; } + } } -"""); +"""; - var comp1 = CreateCompilation([src, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute]); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.VerifyDiagnostics( + // (14,16): error CS9325: Interpolated string handler arguments are not allowed in this context. + // extension([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler i) + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentDisallowed, $@"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""{attributeValue}"")").WithLocation(14, 16) + ); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetDeclaredSymbol(extension); + Assert.True(symbol.IsExtension); + var underlying = symbol.GetSymbol(); + Assert.True(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); + Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], expectedOutput: expectedOutput) - .VerifyDiagnostics(); + var implGetter = underlying.ContainingType.GetMember("get_Item"); + Assert.True(implGetter.Parameters[0].HasInterpolatedStringHandlerArgumentError); + Assert.True(implGetter.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); } - [Theory, CombinatorialData] - public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_01(bool useMetadataRef) + [Fact] + public void InterpolationHandler_ParameterErrors_MappedCorrectly_03() { var src = """ [System.Runtime.CompilerServices.InterpolatedStringHandler] -public ref struct InterpolationHandler +public struct InterpolationHandler { -#pragma warning disable CS0169 // The field 'InterpolationHandler.i' is never used - private ref int i; -#pragma warning restore CS0169 // The field 'InterpolationHandler.i' is never used - - public InterpolationHandler(int literalLength, int formattedCount, scoped MyStruct s) + public InterpolationHandler(int literalLength, int formattedCount, int i) { + System.Console.WriteLine(i); } public void AppendLiteral(string value) { } public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -public ref struct MyStruct -{ - public ref int i; -} - public static class E { - extension(MyStruct s) + extension(int i) { - public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s")] InterpolationHandler h] - { - get - { - return new(); - } - } + public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler h] { get => 0; } } } """; - var exeSource = """ -#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used -MyStruct localFunc() -#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used -{ - return new MyStruct()[$""]; -} -"""; - - var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, verify: Verification.Fails).VerifyDiagnostics(); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.VerifyDiagnostics( + // (16,26): error CS8944: 'E.extension(int).this[InterpolationHandler]' is not an instance method, the receiver or extension receiver parameter cannot be an interpolated string handler argument. + // public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler h] { get => 0; } + Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("""")").WithArguments("E.extension(int).this[InterpolationHandler]").WithLocation(16, 26) + ); - verifier.VerifyIL("Program.<
$>g__localFunc|0_0()", """ -{ - // Code size 23 (0x17) - .maxstack 4 - .locals init (MyStruct V_0) - IL_0000: ldloca.s V_0 - IL_0002: initobj "MyStruct" - IL_0008: ldloc.0 - IL_0009: ldc.i4.0 - IL_000a: ldc.i4.0 - IL_000b: ldloc.0 - IL_000c: newobj "InterpolationHandler..ctor(int, int, scoped MyStruct)" - IL_0011: call "MyStruct E.get_Item(MyStruct, InterpolationHandler)" - IL_0016: ret -} -"""); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var extension = tree.GetRoot().DescendantNodes().OfType().Single(); - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + var symbol = model.GetDeclaredSymbol(extension); + Assert.True(symbol.IsExtension); + var underlying = symbol.GetSymbol(); + var indexer = underlying.GetMember("this[]"); + Assert.False(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); + Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); + Assert.True(indexer.Parameters[0].HasInterpolatedStringHandlerArgumentError); + Assert.True(indexer.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, verify: Verification.Fails) - .VerifyDiagnostics(); + var implGetter = underlying.ContainingType.GetMember("get_Item"); + Assert.False(implGetter.Parameters[0].HasInterpolatedStringHandlerArgumentError); + Assert.True(implGetter.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); + Assert.True(implGetter.Parameters[1].HasInterpolatedStringHandlerArgumentError); + Assert.True(implGetter.Parameters[1].InterpolatedStringHandlerArgumentIndexes.IsEmpty); } [Fact] - public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_02() + public void InterpolationHandler_ReferencesInstanceParameter_FromMetadata() { - var src = """ -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public ref struct InterpolationHandler + // Equivalent to: + // [System.Runtime.CompilerServices.InterpolatedStringHandler] + // public struct InterpolationHandler + // { + // public InterpolationHandler(int literalLength, int formattedCount, string param) + // { + // } + // public void AppendLiteral(string value) { } + // public void AppendFormatted(T hole, int alignment = 0, string? format = null) { } + // } + + //public static class E + //{ + // extension(int i) + // { + // public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] + // { + // } + // } + //} + + var il = """ +.class public sequential ansi sealed beforefieldinit InterpolationHandler + extends [mscorlib]System.ValueType { - public ref int i; + .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute::.ctor() = (01 00 00 00) + .pack 0 + .size 1 - public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) + // Methods + .method public hidebysig specialname rtspecialname instance void .ctor (int32 literalLength, int32 formattedCount, int32 param) cil managed { - i = ref s2.i; + nop + ret } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; -} -public ref struct MyStruct -{ - public ref int i; -} + .method public hidebysig instance void AppendLiteral (string 'value') cil managed + { + nop + ret + } -public static class E -{ - extension(MyStruct s1) + .method public hidebysig instance void AppendFormatted (!!T hole, [opt] int32 'alignment', [opt] string format) cil managed { - public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] InterpolationHandler h] - => new() { i = ref h.i }; + .param [2] = int32(0) + .param [3] = nullref + nop + ret } } -"""; - var exeSource = """ -#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used -MyStruct localFunc() -#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used +.class public auto ansi abstract sealed beforefieldinit E + extends System.Object { - int i = 0; - return new MyStruct() { i = ref i }[$""]; + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) + .class nested public auto ansi sealed specialname '$BA41CFE2B5EDAEB8C1B9062F59ED4D69' + extends System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6d 00 00 ) + .class nested public auto ansi abstract sealed specialname '$F4B4FFE41AB49E80A4ECF390CF6EB372' + extends [mscorlib]System.Object + { + .method public hidebysig specialname static void '$' ( int32 i ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + ret + } + } + + .method public hidebysig specialname instance int32 get_Item ( valuetype InterpolationHandler h ) cil managed + { + .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( + 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 + 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 + 46 36 45 42 33 37 32 00 00 + ) + .param [1] + .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = (01 00 00 00 00) + + newobj instance void [mscorlib]System.NotSupportedException::.ctor() + throw + } + + .property instance int32 Item( valuetype InterpolationHandler h ) + { + .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( + 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 + 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 + 46 36 45 42 33 37 32 00 00 + ) + .get instance int32 E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_Item(valuetype InterpolationHandler) + } + } + + .method public hidebysig static int32 get_Item ( int32 i, valuetype InterpolationHandler h ) cil managed + { + .param [2] + .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = (01 00 00 00 00) + + ldc.i4.0 + ret + } } +""" + ExtensionMarkerAttributeIL; + + var src = """ +_ = 1[$""]; +E.get_Item(1, $""); """; - CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics( - // (6,27): error CS8352: Cannot use variable 'i = ref i' in this context because it may expose referenced variables outside of their declaration scope - // return new MyStruct() { i = ref i }[$""]; - Diagnostic(ErrorCode.ERR_EscapeVariable, "{ i = ref i }").WithArguments("i = ref i").WithLocation(6, 27), - // (6,12): error CS8347: Cannot use a result of 'E.extension(MyStruct).this[InterpolationHandler]' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope - // return new MyStruct() { i = ref i }[$""]; - Diagnostic(ErrorCode.ERR_EscapeCall, @"new MyStruct() { i = ref i }[$""""]").WithArguments("E.extension(MyStruct).this[InterpolationHandler]", "s1").WithLocation(6, 12) + CreateCompilationWithIL(src, ilSource: il, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( + // (1,7): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. + // _ = 1[$""]; + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(1, 7), + // (1,7): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' + // _ = 1[$""]; + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(1, 7), + // (1,7): error CS1615: Argument 3 may not be passed with the 'out' keyword + // _ = 1[$""]; + Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(1, 7), + // (2,15): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. + // E.get_Item(1, $""); + Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(2, 15), + // (2,15): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' + // E.get_Item(1, $""); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(2, 15), + // (2,15): error CS1615: Argument 3 may not be passed with the 'out' keyword + // E.get_Item(1, $""); + Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(2, 15) ); } [Fact] - public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_05() + public void InterpolationHandler_AsExtensionParameter() { var src = """ +_ = $"{42}"[""]; + [System.Runtime.CompilerServices.InterpolatedStringHandler] -public ref struct InterpolationHandler +public struct InterpolationHandler { - public ref int i; - - public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) + public InterpolationHandler(int literalLength, int formattedCount) { - i = ref s2.i; } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; -} - -public ref struct MyStruct -{ - public ref int i; + + public void AppendLiteral(string value) { } + public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } public static class E { - extension(scoped MyStruct s1) + extension(InterpolationHandler h) { - public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] InterpolationHandler h] - => new() { i = ref h.i }; + public int this[string s] { get => 0; } } } """; - var exeSource = """ -#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used -MyStruct localFunc() -#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used -{ - int i = 0; - return new MyStruct() { i = ref i }[$""]; -} -"""; - - CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics( - // (6,12): error CS8352: Cannot use variable 'new MyStruct() { i = ref i }' in this context because it may expose referenced variables outside of their declaration scope - // return new MyStruct() { i = ref i }[$""]; - Diagnostic(ErrorCode.ERR_EscapeVariable, "new MyStruct() { i = ref i }").WithArguments("new MyStruct() { i = ref i }").WithLocation(6, 12), - // (6,12): error CS8347: Cannot use a result of 'E.extension(scoped MyStruct).this[InterpolationHandler]' in this context because it may expose variables referenced by parameter 'h' outside of their declaration scope - // return new MyStruct() { i = ref i }[$""]; - Diagnostic(ErrorCode.ERR_EscapeCall, @"new MyStruct() { i = ref i }[$""""]").WithArguments("E.extension(scoped MyStruct).this[InterpolationHandler]", "h").WithLocation(6, 12), - // (6,41): error CS8347: Cannot use a result of 'InterpolationHandler.InterpolationHandler(int, int, MyStruct)' in this context because it may expose variables referenced by parameter 's2' outside of their declaration scope - // return new MyStruct() { i = ref i }[$""]; - Diagnostic(ErrorCode.ERR_EscapeCall, @"$""""").WithArguments("InterpolationHandler.InterpolationHandler(int, int, MyStruct)", "s2").WithLocation(6, 41) - ); + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.VerifyDiagnostics( + // (1,13): error CS1503: Argument 1: cannot convert from 'string' to 'int' + // _ = $"{42}"[""]; + Diagnostic(ErrorCode.ERR_BadArgType, @"""""").WithArguments("1", "string", "int").WithLocation(1, 13)); } [Fact] - public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_06() + public void InterpolationHandler_ObjectInitializer_01() { - var src = """ -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public ref struct InterpolationHandler + var code = """ +public class Program { - public ref int i; - - public InterpolationHandler(int literalLength, int formattedCount, MyStruct s2) + public static void Main() { - i = ref s2.i; + /**/ + _ = new C() { [42, $"{43}"] = 1 }; + /**/ } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -public ref struct MyStruct +public class C { } + +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct CustomHandler { - public ref int i; + public CustomHandler(int literalLength, int formattedCount, int i) + { + System.Console.Write($"{i} "); + } + + public void AppendFormatted(int i) + { + System.Console.Write($"{i} "); + } } -public static class E +public static class CExt { - extension(scoped MyStruct s1) + extension(C c) { - public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] scoped InterpolationHandler h] - => new() { i = ref h.i }; + public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] CustomHandler h] + { + set { } + } } } """; - var exeSource = """ -#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used -MyStruct localFunc() -#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used -{ - int i = 0; - return new MyStruct() { i = ref i }[$""]; -} + var comp = CreateCompilation(code, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("42 43"), verify: Verification.Skipped).VerifyDiagnostics(); + + string expectedOperationTree = """ +IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... 3}"] = 1 };') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... 43}"] = 1 }') + Left: + IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') + Right: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... 43}"] = 1 }') + Arguments(0) + Initializer: + IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ [42, $"{43}"] = 1 }') + Initializers(1): + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: '[42, $"{43}"] = 1') + Left: + IPropertyReferenceOperation: System.Int32 CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: '[42, $"{43}"]') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: '[42, $"{43}"]') + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') + IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Creation: + IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') + IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 0) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + null + Content: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$"{43}"') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{43}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') """; - CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics( - // (24,22): error CS8352: Cannot use variable 'i = ref h.i' in this context because it may expose referenced variables outside of their declaration scope - // => new() { i = ref h.i }; - Diagnostic(ErrorCode.ERR_EscapeVariable, "{ i = ref h.i }").WithArguments("i = ref h.i").WithLocation(24, 22) - ); + VerifyOperationTreeAndDiagnosticsForTest(comp, expectedOperationTree, expectedDiagnostics: []); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var mainDeclaration = tree.GetRoot().DescendantNodes().OfType().First(); + + var (graph, symbol) = ControlFlowGraphVerifier.GetControlFlowGraph(mainDeclaration.Body, model); + ControlFlowGraphVerifier.VerifyGraph(comp, """ +Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Entering: {R1} +.locals {R1} +{ + CaptureIds: [0] + Block[B1] - Block + Predecessors: [B0] + Statements (1) + IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C() { [ ... 43}"] = 1 }') + Value: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... 43}"] = 1 }') + Arguments(0) + Initializer: + null + Next (Regular) Block[B2] + Entering: {R2} + .locals {R2} + { + CaptureIds: [1] [2] + Block[B2] - Block + Predecessors: [B1] + Statements (4) + IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '42') + Value: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') + IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '$"{43}"') + Value: + IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') + IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + null + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') + Instance Receiver: + IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: '[42, $"{43}"] = 1') + Left: + IPropertyReferenceOperation: System.Int32 CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: '[42, $"{43}"]') + Instance Receiver: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... 43}"] = 1 }') + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') + IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') + IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') + Next (Regular) Block[B3] + Leaving: {R2} + } + Block[B3] - Block + Predecessors: [B2] + Statements (1) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... 3}"] = 1 };') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... 43}"] = 1 }') + Left: + IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') + Right: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... 43}"] = 1 }') + Next (Regular) Block[B4] + Leaving: {R1} +} +Block[B4] - Exit + Predecessors: [B3] + Statements (0) +""", graph, symbol); } - [Theory, CombinatorialData] - public void InterpolationHandler_RefStructReceiverParameter_EscapeScopes_07(bool useMetadataRef) + [Fact] + public void InterpolationHandler_ObjectInitializer_02() { - var src = """ -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public ref struct InterpolationHandler + var code = """ +public class Program { -#pragma warning disable CS0169 // The field 'InterpolationHandler.i' is never used - private ref int i; -#pragma warning restore CS0169 // The field 'InterpolationHandler.i' is never used - - public InterpolationHandler(int literalLength, int formattedCount, scoped MyStruct s2) + public static void Main() { + /**/ + _ = new C() { [42, $"{43}"] = { Field = 0 } }; + /**/ } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } -public ref struct MyStruct +public class C { } + +public class D { - public ref int i; + public int Field; } -public static class E +[System.Runtime.CompilerServices.InterpolatedStringHandler] +public struct CustomHandler { - extension(scoped MyStruct s1) + public CustomHandler(int literalLength, int formattedCount, int i) { - public MyStruct this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1")] scoped InterpolationHandler h] - => new(); + System.Console.Write($"{i} "); + } + + public void AppendFormatted(int i) + { + System.Console.Write($"{i} "); } } -"""; - var exeSource = """ -#pragma warning disable CS8321 // The local function 'localFunc' is declared but never used -MyStruct localFunc() -#pragma warning restore CS8321 // The local function 'localFunc' is declared but never used +public static class CExt { - int i = 0; - return new MyStruct() { i = ref i }[$""]; + extension(C c) + { + public D this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] CustomHandler h] + { + get => new D(); + } + } } """; - var verifier = CompileAndVerify([exeSource, src], targetFramework: TargetFramework.Net100, verify: Verification.Fails).VerifyDiagnostics(); + var comp = CreateCompilation(code, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("42 43"), verify: Verification.Skipped).VerifyDiagnostics(); - verifier.VerifyIL("Program.<
$>g__localFunc|0_0()", """ -{ - // Code size 36 (0x24) - .maxstack 4 - .locals init (int V_0, //i - MyStruct V_1, - MyStruct V_2) - IL_0000: ldc.i4.0 - IL_0001: stloc.0 - IL_0002: ldloca.s V_2 - IL_0004: initobj "MyStruct" - IL_000a: ldloca.s V_2 - IL_000c: ldloca.s V_0 - IL_000e: stfld "ref int MyStruct.i" - IL_0013: ldloc.2 - IL_0014: stloc.1 - IL_0015: ldloc.1 - IL_0016: ldc.i4.0 - IL_0017: ldc.i4.0 - IL_0018: ldloc.1 - IL_0019: newobj "InterpolationHandler..ctor(int, int, scoped MyStruct)" - IL_001e: call "MyStruct E.get_Item(scoped MyStruct, scoped InterpolationHandler)" - IL_0023: ret -} -"""); + string expectedOperationTree = """ +IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... ld = 0 } };') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... eld = 0 } }') + Left: + IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') + Right: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... eld = 0 } }') + Arguments(0) + Initializer: + IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ [42, $"{4 ... eld = 0 } }') + Initializers(1): + IMemberInitializerOperation (OperationKind.MemberInitializer, Type: D) (Syntax: '[42, $"{43} ... Field = 0 }') + InitializedMember: + IPropertyReferenceOperation: D CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { get; } (OperationKind.PropertyReference, Type: D) (Syntax: '[42, $"{43}"]') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: '[42, $"{43}"]') + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') + IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Creation: + IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') + IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 0) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + null + Content: + IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$"{43}"') + Parts(1): + IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{43}') + AppendCall: + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: D) (Syntax: '{ Field = 0 }') + Initializers(1): + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'Field = 0') + Left: + IFieldReferenceOperation: System.Int32 D.Field (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Field') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: D, IsImplicit) (Syntax: 'Field') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') +"""; - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + VerifyOperationTreeAndDiagnosticsForTest(comp, expectedOperationTree, expectedDiagnostics: []); - CompileAndVerify(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100, verify: Verification.Fails) - .VerifyDiagnostics(); - } + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var mainDeclaration = tree.GetRoot().DescendantNodes().OfType().First(); - [Theory, CombinatorialData] - public void InterpolationHandler_ReceiverParameter_NullableMismatch_01(bool useMetadataRef, bool useOut) - { - string outParam = useOut ? ", out bool valid" : ""; - var src = $$""" -#nullable enable -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler + var (graph, symbol) = ControlFlowGraphVerifier.GetControlFlowGraph(mainDeclaration.Body, model); + ControlFlowGraphVerifier.VerifyGraph(comp, """ +Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Entering: {R1} +.locals {R1} { - public InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{{outParam}}) + CaptureIds: [0] + Block[B1] - Block + Predecessors: [B0] + Statements (1) + IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C() { [ ... eld = 0 } }') + Value: + IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... eld = 0 } }') + Arguments(0) + Initializer: + null + Next (Regular) Block[B2] + Entering: {R2} + .locals {R2} { - System.Console.Write(s1); - System.Console.Write(s2); - {{(useOut ? "valid = true;" : "")}} + CaptureIds: [1] [2] + Block[B2] - Block + Predecessors: [B1] + Statements (4) + IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '42') + Value: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') + IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '$"{43}"') + Value: + IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(3): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') + IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Initializer: + null + IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') + Instance Receiver: + IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'Field = 0') + Left: + IFieldReferenceOperation: System.Int32 D.Field (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Field') + Instance Receiver: + IPropertyReferenceOperation: D CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { get; } (OperationKind.PropertyReference, Type: D) (Syntax: '[42, $"{43}"]') + Instance Receiver: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... eld = 0 } }') + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') + IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') + IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') + Next (Regular) Block[B3] + Leaving: {R2} } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string? format = null) => throw null!; + Block[B3] - Block + Predecessors: [B2] + Statements (1) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... ld = 0 } };') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... eld = 0 } }') + Left: + IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') + Right: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... eld = 0 } }') + Next (Regular) Block[B4] + Leaving: {R1} } +Block[B4] - Exit + Predecessors: [B3] + Statements (0) +""", graph, symbol); + } + + [Fact] + public void UseSite_01() + { + // list-pattern with extension(Missing).Length + var missing_cs = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missing_cs, assemblyName: "missing", targetFramework: TargetFramework.Net100) + .EmitToImageReference(); -public static class E + var lib2_cs = """ +public static class E1 { - extension(C? s1) + extension(Missing m) { - public int this[string? s2, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s1", "s2")] InterpolationHandler h] { get => 0; } + public int Length => 1; + } + extension(object o) + { + public int this[System.Index i] => throw null; + public int this[System.Range r] => throw null; } } - -public class C { } -"""; - - var exeSource = """ -#nullable enable -_ = ((C?)null)[null, $""]; // 1, 2 -_ = ((C?)null)["", $""]; // 3 -_ = new C()[null, $""]; // 4 -_ = new C()["", $""]; - -_ = E.get_Item(null, null, $""); // 5, 6 -_ = E.get_Item(new C(), null, $""); // 7 -_ = E.get_Item(null, "", $""); // 8 -_ = E.get_Item(new C(), "", $""); """; + var lib2Ref = CreateCompilation(lib2_cs, references: [missingRef], targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - var expectedDiagnostics = new[] { - // (2,6): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = ((C?)null)[null, $""]; // 1, 2 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(C?)null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(2, 6), - // (2,16): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = ((C?)null)[null, $""]; // 1, 2 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(2, 16), - // (3,6): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = ((C?)null)["", $""]; // 3 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "(C?)null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(3, 6), - // (4,13): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = new C()[null, $""]; // 4 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(4, 13), - // (7,16): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = E.get_Item(null, null, $""); // 5, 6 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(7, 16), - // (7,22): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = E.get_Item(null, null, $""); // 5, 6 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(7, 22), - // (8,25): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = E.get_Item(new C(), null, $""); // 7 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(8, 25), - // (9,16): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2, out bool valid)'. - // _ = E.get_Item(null, "", $""); // 8 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, C s1, string s2{outParam})").WithLocation(9, 16) - }; - - CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); - - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); + var source = """ +using Outer; - CreateCompilation(exeSource, references: [AsReference(comp1, useMetadataRef)], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); - } +var o = new object(); +_ = o is [var x, .. var y]; - [Theory, CombinatorialData] - public void InterpolationHandler_ReceiverParameter_NullableMismatch_02(bool useMetadataRef, bool useOut) - { - string outParam = useOut ? ", out bool valid" : ""; - var src = $$""" -#nullable enable -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +namespace Outer { - public InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{{outParam}}) + public static class E2 { - System.Console.Write(s1); - System.Console.Write(s2); - {{(useOut ? "valid = true;" : "")}} + extension(object o) + { + public int Length => 1; + } } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string? format = null) => throw null!; } +"""; + var compilation = CreateCompilation(source, references: [lib2Ref], targetFramework: TargetFramework.Net100); + compilation.VerifyEmitDiagnostics( + // (4,10): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, "[var x, .. var y]").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 10)); + } -public static class E + [Fact] + public void UseSite_02() + { + // list-pattern with extension(Missing).this[Index] + var missing_cs = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missing_cs, assemblyName: "missing", targetFramework: TargetFramework.Net100) + .EmitToImageReference(); + + var lib2_cs = """ +public static class E1 { - extension(C? s1) + extension(Missing m) { - public int this[string? s2, string? s3, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("s2", "s3")] InterpolationHandler h] { get => 0; } + public int this[System.Index i] => throw null; + } + extension(object o) + { + public int Length => 1; + public int this[System.Range r] => throw null; } } - -public class C { } -"""; - - var exeSource = """ -#nullable enable -_ = new C()[null, null, $""]; -_ = new C()[null, "", $""]; -_ = new C()["", null, $""]; -_ = new C()["", "", $""]; - -E.get_Item(new C(), null, null, $""); -E.get_Item(new C(), "", null, $""); -E.get_Item(new C(), null, "", $""); -E.get_Item(new C(), "", "", $""); """; + var lib2Ref = CreateCompilation(lib2_cs, references: [missingRef], targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - var expectedDiagnostics = new[] { - // (2,13): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // _ = new C()[null, null, $""]; - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 13), - // (2,19): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // _ = new C()[null, null, $""]; - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(2, 19), - // (3,13): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // _ = new C()[null, "", $""]; - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(3, 13), - // (4,17): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // _ = new C()["", null, $""]; - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(4, 17), - // (7,21): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // E.get_Item(new C(), null, null, $""); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(7, 21), - // (7,27): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // E.get_Item(new C(), null, null, $""); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(7, 27), - // (8,25): warning CS8604: Possible null reference argument for parameter 's2' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // E.get_Item(new C(), "", null, $""); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s2", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(8, 25), - // (9,21): warning CS8604: Possible null reference argument for parameter 's1' in 'InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2)'. - // E.get_Item(new C(), null, "", $""); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "null").WithArguments("s1", $"InterpolationHandler.InterpolationHandler(int literalLength, int formattedCount, string s1, string s2{outParam})").WithLocation(9, 21) - }; - - CreateCompilation([exeSource, src], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); + var source = """ +using Outer; - var comp1 = CreateCompilation(src, targetFramework: TargetFramework.Net100); +var o = new object(); +_ = o is [var x, .. var y]; - CreateCompilation(exeSource, references: [useMetadataRef ? comp1.ToMetadataReference() : comp1.EmitToImageReference()], targetFramework: TargetFramework.Net100).VerifyDiagnostics(expectedDiagnostics); +namespace Outer +{ + public static class E2 + { + extension(object o) + { + public int this[System.Index i] => throw null; + } + } +} +"""; + var compilation = CreateCompilation(source, references: [lib2Ref], targetFramework: TargetFramework.Net100); + compilation.VerifyEmitDiagnostics( + // (4,10): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, "[var x, .. var y]").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 10), + // (4,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, ".. var y").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 18)); } [Fact] - public void InterpolationHandler_ParameterErrors_MappedCorrectly_01() + public void UseSite_03() { - var src = """ -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler + // list-pattern with extension(Missing).this[Range] + var missing_cs = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missing_cs, assemblyName: "missing", targetFramework: TargetFramework.Net100) + .EmitToImageReference(); + + var lib2_cs = """ +public static class E1 { - public InterpolationHandler(int literalLength, int formattedCount, int i) + extension(Missing m) { - System.Console.WriteLine(i); + public int this[System.Range r] => throw null; } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; -} - -public static class E -{ - extension(int i) + extension(object o) { - public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h] { get => 0; } + public int Length => 1; + public int this[System.Index i] => throw null; } } """; + var lib2Ref = CreateCompilation(lib2_cs, references: [missingRef], targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); - comp.VerifyDiagnostics( - // (16,26): error CS8945: 'nonexistent' is not a valid parameter name from 'E.extension(int).this[InterpolationHandler]'. - // public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("nonexistent")] InterpolationHandler h] { get => 0; } - Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""nonexistent"")").WithArguments("nonexistent", "E.extension(int).this[InterpolationHandler]").WithLocation(16, 26) - ); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + var source = """ +using Outer; - var symbol = model.GetDeclaredSymbol(extension); - Assert.True(symbol.IsExtension); - var underlying = symbol.GetSymbol(); - var indexer = underlying.GetMember("this[]"); - Assert.False(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); - Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); - Assert.True(indexer.Parameters[0].HasInterpolatedStringHandlerArgumentError); - Assert.True(indexer.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); +var o = new object(); +_ = o is [var x, .. var y]; - var implGetter = underlying.ContainingType.GetMember("get_Item"); - Assert.False(implGetter.Parameters[0].HasInterpolatedStringHandlerArgumentError); - Assert.True(implGetter.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); - Assert.True(implGetter.Parameters[1].HasInterpolatedStringHandlerArgumentError); - Assert.True(implGetter.Parameters[1].InterpolatedStringHandlerArgumentIndexes.IsEmpty); +namespace Outer +{ + public static class E2 + { + extension(object o) + { + public int this[System.Range r] => throw null; + } + } +} +"""; + var compilation = CreateCompilation(source, references: [lib2Ref], targetFramework: TargetFramework.Net100); + compilation.VerifyEmitDiagnostics( + // (4,10): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, "[var x, .. var y]").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 10), + // (4,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, ".. var y").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 18)); } - [Theory] - [InlineData("i")] - [InlineData("")] - [InlineData("nonexistent")] - public void InterpolationHandler_ParameterErrors_MappedCorrectly_02(string attributeValue) + [Fact] + public void UseSite_04() { - var src = $$""" -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler + // list-pattern with extension(Missing).this[int] + var missing_cs = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missing_cs, assemblyName: "missing", targetFramework: TargetFramework.Net100) + .EmitToImageReference(); + + var lib2_cs = """ +public static class E1 { - public InterpolationHandler(int literalLength, int formattedCount, InterpolationHandler i) + extension(Missing m) { - System.Console.WriteLine(i); + public int this[int i] => throw null; + } + extension(object o) + { + public int Length => 1; + public int this[System.Range r] => throw null; } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; } +"""; + var lib2Ref = CreateCompilation(lib2_cs, references: [missingRef], targetFramework: TargetFramework.Net100) + .EmitToImageReference(); -public static class E + var source = """ +using Outer; + +var o = new object(); +_ = o is [var x, .. var y]; + +namespace Outer { - extension([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("{{attributeValue}}")] InterpolationHandler i) + public static class E2 { - public int this[int j] { get => 0; } + extension(object o) + { + public int this[System.Index i] => throw null; + } } } """; - - var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); - comp.VerifyDiagnostics( - // (14,16): error CS9325: Interpolated string handler arguments are not allowed in this context. - // extension([System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler i) - Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentDisallowed, $@"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(""{attributeValue}"")").WithLocation(14, 16) - ); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var extension = tree.GetRoot().DescendantNodes().OfType().Single(); - - var symbol = model.GetDeclaredSymbol(extension); - Assert.True(symbol.IsExtension); - var underlying = symbol.GetSymbol(); - Assert.True(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); - Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); - - var implGetter = underlying.ContainingType.GetMember("get_Item"); - Assert.True(implGetter.Parameters[0].HasInterpolatedStringHandlerArgumentError); - Assert.True(implGetter.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); + var compilation = CreateCompilation(source, references: [lib2Ref], targetFramework: TargetFramework.Net100); + compilation.VerifyEmitDiagnostics( + // (4,10): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, "[var x, .. var y]").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 10), + // (4,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, ".. var y").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 18)); } [Fact] - public void InterpolationHandler_ParameterErrors_MappedCorrectly_03() + public void UseSite_05() { - var src = """ -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler + // list-pattern with extension(Missing).Slice(int, int) + var missing_cs = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missing_cs, assemblyName: "missing", targetFramework: TargetFramework.Net100) + .EmitToImageReference(); + + var lib2_cs = """ +public static class E1 { - public InterpolationHandler(int literalLength, int formattedCount, int i) + extension(Missing m) { - System.Console.WriteLine(i); + public object Slice(int i, int j) => throw null; } - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; -} - -public static class E -{ - extension(int i) + extension(object o) { - public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler h] { get => 0; } + public int Length => 1; + public int this[System.Index i] => throw null; } } """; + var lib2Ref = CreateCompilation(lib2_cs, references: [missingRef], targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); - comp.VerifyDiagnostics( - // (16,26): error CS8944: 'E.extension(int).this[InterpolationHandler]' is not an instance method, the receiver or extension receiver parameter cannot be an interpolated string handler argument. - // public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("")] InterpolationHandler h] { get => 0; } - Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("""")").WithArguments("E.extension(int).this[InterpolationHandler]").WithLocation(16, 26) - ); - - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var extension = tree.GetRoot().DescendantNodes().OfType().Single(); + var source = """ +using Outer; - var symbol = model.GetDeclaredSymbol(extension); - Assert.True(symbol.IsExtension); - var underlying = symbol.GetSymbol(); - var indexer = underlying.GetMember("this[]"); - Assert.False(underlying.ExtensionParameter.HasInterpolatedStringHandlerArgumentError); - Assert.True(underlying.ExtensionParameter.InterpolatedStringHandlerArgumentIndexes.IsEmpty); - Assert.True(indexer.Parameters[0].HasInterpolatedStringHandlerArgumentError); - Assert.True(indexer.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); +var o = new object(); +_ = o is [var x, .. var y]; - var implGetter = underlying.ContainingType.GetMember("get_Item"); - Assert.False(implGetter.Parameters[0].HasInterpolatedStringHandlerArgumentError); - Assert.True(implGetter.Parameters[0].InterpolatedStringHandlerArgumentIndexes.IsEmpty); - Assert.True(implGetter.Parameters[1].HasInterpolatedStringHandlerArgumentError); - Assert.True(implGetter.Parameters[1].InterpolatedStringHandlerArgumentIndexes.IsEmpty); +namespace Outer +{ + public static class E2 + { + extension(object o) + { + public int this[System.Index i] => throw null; + } + } +} +"""; + var compilation = CreateCompilation(source, references: [lib2Ref], targetFramework: TargetFramework.Net100); + compilation.VerifyEmitDiagnostics( + // (4,18): error CS0021: Cannot apply indexing with [] to an expression of type 'object' + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, ".. var y").WithArguments("object").WithLocation(4, 18), + // (4,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, ".. var y").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 18)); } [Fact] - public void InterpolationHandler_ReferencesInstanceParameter_FromMetadata() + public void UseSite_06() { - // Equivalent to: - // [System.Runtime.CompilerServices.InterpolatedStringHandler] - // public struct InterpolationHandler - // { - // public InterpolationHandler(int literalLength, int formattedCount, string param) - // { - // } - // public void AppendLiteral(string value) { } - // public void AppendFormatted(T hole, int alignment = 0, string? format = null) { } - // } - - //public static class E - //{ - // extension(int i) - // { - // public int this[[System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] InterpolationHandler h] - // { - // } - // } - //} + // list-pattern with extension(object).this[Index] returning Missing + var missing_cs = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missing_cs, assemblyName: "missing", targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - var il = """ -.class public sequential ansi sealed beforefieldinit InterpolationHandler - extends [mscorlib]System.ValueType + var lib2_cs = """ +public static class E1 { - .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute::.ctor() = (01 00 00 00) - .pack 0 - .size 1 - - // Methods - .method public hidebysig specialname rtspecialname instance void .ctor (int32 literalLength, int32 formattedCount, int32 param) cil managed + extension(object o) { - nop - ret + public int Length => 1; + public Missing this[System.Index i] => throw null; + public int this[System.Range r] => throw null; } +} +"""; + var lib2Ref = CreateCompilation(lib2_cs, references: [missingRef], targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - .method public hidebysig instance void AppendLiteral (string 'value') cil managed - { - nop - ret - } + var source = """ +using Outer; - .method public hidebysig instance void AppendFormatted (!!T hole, [opt] int32 'alignment', [opt] string format) cil managed - { - .param [2] = int32(0) - .param [3] = nullref - nop - ret - } -} +var o = new object(); +_ = o is [var x, .. var y]; -.class public auto ansi abstract sealed beforefieldinit E - extends System.Object +namespace Outer { - .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) - .class nested public auto ansi sealed specialname '$BA41CFE2B5EDAEB8C1B9062F59ED4D69' - extends System.Object + public static class E2 { - .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6d 00 00 ) - .class nested public auto ansi abstract sealed specialname '$F4B4FFE41AB49E80A4ECF390CF6EB372' - extends [mscorlib]System.Object - { - .method public hidebysig specialname static void '$' ( int32 i ) cil managed - { - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - - ret - } - } - - .method public hidebysig specialname instance int32 get_Item ( valuetype InterpolationHandler h ) cil managed - { - .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( - 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 - 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 - 46 36 45 42 33 37 32 00 00 - ) - .param [1] - .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = (01 00 00 00 00) - - newobj instance void [mscorlib]System.NotSupportedException::.ctor() - throw - } - - .property instance int32 Item( valuetype InterpolationHandler h ) + extension(object o) { - .custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = ( - 01 00 24 3c 4d 3e 24 46 34 42 34 46 46 45 34 31 - 41 42 34 39 45 38 30 41 34 45 43 46 33 39 30 43 - 46 36 45 42 33 37 32 00 00 - ) - .get instance int32 E/'$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_Item(valuetype InterpolationHandler) + public int this[System.Index i] => throw null; } } +} +"""; + var compilation = CreateCompilation(source, references: [lib2Ref], targetFramework: TargetFramework.Net100); + compilation.VerifyEmitDiagnostics( + // (4,10): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, "[var x, .. var y]").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 10), + // (4,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, ".. var y").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 18)); + } - .method public hidebysig static int32 get_Item ( int32 i, valuetype InterpolationHandler h ) cil managed + [Fact] + public void UseSite_07() { - .param [2] - .custom instance void [mscorlib]System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute::.ctor(string) = (01 00 00 00 00) + // list-pattern with extension(object).Slice(int, int) returning Missing + var missing_cs = """ +public class Missing { } +"""; + var missingRef = CreateCompilation(missing_cs, assemblyName: "missing", targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - ldc.i4.0 - ret + var lib2_cs = """ +public static class E1 +{ + extension(object o) + { + public int Length => 1; + public int this[System.Index i] => throw null; + public Missing Slice(int i, int j) => throw null; } } -""" + ExtensionMarkerAttributeIL; +"""; + var lib2Ref = CreateCompilation(lib2_cs, references: [missingRef], targetFramework: TargetFramework.Net100) + .EmitToImageReference(); - var src = """ -_ = 1[$""]; -E.get_Item(1, $""); + var source = """ +using Outer; + +var o = new object(); +_ = o is [var x, .. var y]; + +namespace Outer +{ + public static class E2 + { + extension(object o) + { + public int this[System.Index i] => throw null; + } + } +} """; - - CreateCompilationWithIL(src, ilSource: il, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( - // (1,7): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. - // _ = 1[$""]; - Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(1, 7), - // (1,7): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' - // _ = 1[$""]; - Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(1, 7), - // (1,7): error CS1615: Argument 3 may not be passed with the 'out' keyword - // _ = 1[$""]; - Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(1, 7), - // (2,15): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'InterpolationHandler h' is malformed and cannot be interpreted. Construct an instance of 'InterpolationHandler' manually. - // E.get_Item(1, $""); - Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("InterpolationHandler h", "InterpolationHandler").WithLocation(2, 15), - // (2,15): error CS7036: There is no argument given that corresponds to the required parameter 'param' of 'InterpolationHandler.InterpolationHandler(int, int, int)' - // E.get_Item(1, $""); - Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("param", "InterpolationHandler.InterpolationHandler(int, int, int)").WithLocation(2, 15), - // (2,15): error CS1615: Argument 3 may not be passed with the 'out' keyword - // E.get_Item(1, $""); - Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(2, 15) - ); + var compilation = CreateCompilation(source, references: [lib2Ref], targetFramework: TargetFramework.Net100); + compilation.VerifyEmitDiagnostics( + // (4,18): error CS0021: Cannot apply indexing with [] to an expression of type 'object' + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_BadIndexLHS, ".. var y").WithArguments("object").WithLocation(4, 18), + // (4,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // _ = o is [var x, .. var y]; + Diagnostic(ErrorCode.ERR_NoTypeDef, ".. var y").WithArguments("Missing", "missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 18)); } [Fact] - public void InterpolationHandler_AsExtensionParameter() + public void LengthPattern_NegativeLengthTest() { - var src = """ -_ = $"{42}"[""]; + var src = @" +object o = new object(); +_ = o is { Length: -1 }; // 1 +_ = o is { Length: -1 or 1 }; // 2 +_ = o is { Length: -1 } or { Length: 1 }; // 3 -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct InterpolationHandler +_ = o switch // 4 { - public InterpolationHandler(int literalLength, int formattedCount) - { - } + { Length: -1 } => 0, // 5 +}; - public void AppendLiteral(string value) { } - public void AppendFormatted(T hole, int alignment = 0, string format = null) => throw null; -} +_ = o switch // 6 +{ + { Length: -1 or 1 } => 0, +}; + +_ = o switch // 7 +{ + { Length: -1 } or { Length: 1 } => 0, +}; + +_ = o switch // 8 +{ + { Length: -1 } => 0, // 9 + { Length: 1 } => 0, +}; public static class E { - extension(InterpolationHandler h) + extension(object o) { - public int this[string s] { get => 0; } + public int Length => 0; + public int this[System.Index i] => 0; } } -"""; - +"; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); comp.VerifyDiagnostics( - // (1,13): error CS1503: Argument 1: cannot convert from 'string' to 'int' - // _ = $"{42}"[""]; - Diagnostic(ErrorCode.ERR_BadArgType, @"""""").WithArguments("1", "string", "int").WithLocation(1, 13)); + // 0.cs(3,5): error CS8518: An expression of type 'object' can never match the provided pattern. + // _ = o is { Length: -1 }; // 1 + Diagnostic(ErrorCode.ERR_IsPatternImpossible, "o is { Length: -1 }").WithArguments("object").WithLocation(3, 5), + // 0.cs(4,20): hidden CS9335: The pattern is redundant. + // _ = o is { Length: -1 or 1 }; // 2 + Diagnostic(ErrorCode.HDN_RedundantPattern, "-1").WithLocation(4, 20), + // 0.cs(5,10): hidden CS9335: The pattern is redundant. + // _ = o is { Length: -1 } or { Length: 1 }; // 3 + Diagnostic(ErrorCode.HDN_RedundantPattern, "{ Length: -1 }").WithLocation(5, 10), + // 0.cs(7,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = o switch // 4 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(7, 7), + // 0.cs(9,5): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. + // { Length: -1 } => 0, // 5 + Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "{ Length: -1 }").WithLocation(9, 5), + // 0.cs(12,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Length: 0 }' is not covered. + // _ = o switch // 6 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Length: 0 }").WithLocation(12, 7), + // 0.cs(17,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Length: 0 }' is not covered. + // _ = o switch // 7 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Length: 0 }").WithLocation(17, 7), + // 0.cs(22,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Length: 0 }' is not covered. + // _ = o switch // 8 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Length: 0 }").WithLocation(22, 7), + // 0.cs(24,5): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. + // { Length: -1 } => 0, // 9 + Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "{ Length: -1 }").WithLocation(24, 5) + ); } [Fact] - public void InterpolationHandler_ObjectInitializer_01() + public void LengthPattern_NegativeLengthTest_02() { - var code = """ -public class Program + var src = @" +int? i = 0; +_ = i is { Length: -1 }; // 1 +_ = i is { Length: -1 or 1 }; // 2 +_ = i is { Length: -1 } or { Length: 1 }; // 3 + +_ = i switch // 4 { - public static void Main() - { - /**/ - _ = new C() { [42, $"{43}"] = 1 }; - /**/ - } -} + { Length: -1 } => 0, // 5 +}; -public class C { } +_ = i switch // 6 +{ + { Length: -1 or 1 } => 0, +}; -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct CustomHandler +_ = i switch // 7 { - public CustomHandler(int literalLength, int formattedCount, int i) - { - System.Console.Write($"{i} "); - } + { Length: -1 } or { Length: 1 } => 0, +}; - public void AppendFormatted(int i) - { - System.Console.Write($"{i} "); - } -} +_ = i switch // 8 +{ + { Length: -1 } => 0, // 9 + { Length: 1 } => 0, +}; -public static class CExt +public static class E { - extension(C c) + extension(object o) { - public int this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] CustomHandler h] - { - set { } - } + public int Length => 0; + public int this[System.Index i] => 0; } } -"""; - - var comp = CreateCompilation(code, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: ExpectedOutput("42 43"), verify: Verification.Skipped).VerifyDiagnostics(); - - string expectedOperationTree = """ -IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... 3}"] = 1 };') - Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... 43}"] = 1 }') - Left: - IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') - Right: - IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... 43}"] = 1 }') - Arguments(0) - Initializer: - IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ [42, $"{43}"] = 1 }') - Initializers(1): - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: '[42, $"{43}"] = 1') - Left: - IPropertyReferenceOperation: System.Int32 CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: '[42, $"{43}"]') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: '[42, $"{43}"]') - Arguments(2): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') - IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Creation: - IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(3): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') - IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 0) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Content: - IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$"{43}"') - Parts(1): - IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{43}') - AppendCall: - IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') -"""; +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.VerifyDiagnostics( + // 0.cs(3,5): error CS8518: An expression of type 'int?' can never match the provided pattern. + // _ = i is { Length: -1 }; // 1 + Diagnostic(ErrorCode.ERR_IsPatternImpossible, "i is { Length: -1 }").WithArguments("int?").WithLocation(3, 5), + // 0.cs(4,20): hidden CS9335: The pattern is redundant. + // _ = i is { Length: -1 or 1 }; // 2 + Diagnostic(ErrorCode.HDN_RedundantPattern, "-1").WithLocation(4, 20), + // 0.cs(5,10): hidden CS9335: The pattern is redundant. + // _ = i is { Length: -1 } or { Length: 1 }; // 3 + Diagnostic(ErrorCode.HDN_RedundantPattern, "{ Length: -1 }").WithLocation(5, 10), + // 0.cs(7,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. + // _ = i switch // 4 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(7, 7), + // 0.cs(9,5): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. + // { Length: -1 } => 0, // 5 + Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "{ Length: -1 }").WithLocation(9, 5), + // 0.cs(12,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Length: 0 }' is not covered. + // _ = i switch // 6 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Length: 0 }").WithLocation(12, 7), + // 0.cs(17,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Length: 0 }' is not covered. + // _ = i switch // 7 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Length: 0 }").WithLocation(17, 7), + // 0.cs(22,7): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Length: 0 }' is not covered. + // _ = i switch // 8 + Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Length: 0 }").WithLocation(22, 7), + // 0.cs(24,5): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. + // { Length: -1 } => 0, // 9 + Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "{ Length: -1 }").WithLocation(24, 5) + ); + } - VerifyOperationTreeAndDiagnosticsForTest(comp, expectedOperationTree, expectedDiagnostics: []); + [Fact] + public void LengthPattern_NegativeLengthTest_03() + { + var src = @" +using Outer; - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var mainDeclaration = tree.GetRoot().DescendantNodes().OfType().First(); +object o = new object(); +_ = o is { Length: -1 }; // 1 - var (graph, symbol) = ControlFlowGraphVerifier.GetControlFlowGraph(mainDeclaration.Body, model); - ControlFlowGraphVerifier.VerifyGraph(comp, """ -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} +public static class E { - CaptureIds: [0] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C() { [ ... 43}"] = 1 }') - Value: - IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... 43}"] = 1 }') - Arguments(0) - Initializer: - null - Next (Regular) Block[B2] - Entering: {R2} - .locals {R2} + extension(object o) { - CaptureIds: [1] [2] - Block[B2] - Block - Predecessors: [B1] - Statements (4) - IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '42') - Value: - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') - IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '$"{43}"') - Value: - IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(3): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') - IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') - Instance Receiver: - IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: '[42, $"{43}"] = 1') - Left: - IPropertyReferenceOperation: System.Int32 CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: '[42, $"{43}"]') - Instance Receiver: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... 43}"] = 1 }') - Arguments(2): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') - IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') - IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') - Next (Regular) Block[B3] - Leaving: {R2} + public int Length => 0; + } +} + +namespace Outer +{ + public static class E2 + { + extension(object o) + { + public int this[System.Index i] => 0; + } } - Block[B3] - Block - Predecessors: [B2] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... 3}"] = 1 };') - Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... 43}"] = 1 }') - Left: - IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') - Right: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... 43}"] = 1 }') - Next (Regular) Block[B4] - Leaving: {R1} } -Block[B4] - Exit - Predecessors: [B3] - Statements (0) -""", graph, symbol); +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + comp.VerifyDiagnostics( + // (5,5): error CS8518: An expression of type 'object' can never match the provided pattern. + // _ = o is { Length: -1 }; // 1 + Diagnostic(ErrorCode.ERR_IsPatternImpossible, "o is { Length: -1 }").WithArguments("object").WithLocation(5, 5)); } [Fact] - public void InterpolationHandler_ObjectInitializer_02() + public void CollectionSpread_01() { - var code = """ -public class Program + var src = """ +C c = new C(); +int[] i = [0, .. c]; +foreach (var x in i) System.Console.Write(x); + +public class C : System.Collections.Generic.IEnumerable { - public static void Main() + public System.Collections.Generic.IEnumerator GetEnumerator() { - /**/ - _ = new C() { [42, $"{43}"] = { Field = 0 } }; - /**/ + yield return 3; } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); } -public class C { } +public static class E +{ + extension(object o) + { + public int Length => 1; + } +} +"""; + // Note: the Length extension is not used to calculate the size of the collection + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net100); + var verifier = CompileAndVerify(comp, expectedOutput: ExpectedOutput("03"), verify: Verification.FailsPEVerify).VerifyDiagnostics(); + verifier.VerifyIL("", """ +{ + // Code size 54 (0x36) + .maxstack 3 + .locals init (C V_0, //c + int[] V_1, + int V_2) + IL_0000: newobj "C..ctor()" + IL_0005: stloc.0 + IL_0006: newobj "System.Collections.Generic.List..ctor()" + IL_000b: dup + IL_000c: ldc.i4.0 + IL_000d: callvirt "void System.Collections.Generic.List.Add(int)" + IL_0012: dup + IL_0013: ldloc.0 + IL_0014: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_0019: callvirt "int[] System.Collections.Generic.List.ToArray()" + IL_001e: stloc.1 + IL_001f: ldc.i4.0 + IL_0020: stloc.2 + IL_0021: br.s IL_002f + IL_0023: ldloc.1 + IL_0024: ldloc.2 + IL_0025: ldelem.i4 + IL_0026: call "void System.Console.Write(int)" + IL_002b: ldloc.2 + IL_002c: ldc.i4.1 + IL_002d: add + IL_002e: stloc.2 + IL_002f: ldloc.2 + IL_0030: ldloc.1 + IL_0031: ldlen + IL_0032: conv.i4 + IL_0033: blt.s IL_0023 + IL_0035: ret +} +"""); + } -public class D + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void LoopWithPatternDeclaration_ListPattern() + { + var source = """ +#nullable enable + +object? o = new object(); + +for (var x = 0; x < 10; x++) { - public int Field; + var a = Infer(o); + if (a is [var z]) + { + z.ToString(); + } + + o = null; } -[System.Runtime.CompilerServices.InterpolatedStringHandler] -public struct CustomHandler +C Infer(T t) => throw null!; + +public class C { } + +public static class E { - public CustomHandler(int literalLength, int formattedCount, int i) + extension(C t) { - System.Console.Write($"{i} "); + public int Length => 1; + public T this[System.Index i] => throw null!; + } +} +"""; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (10,9): warning CS8602: Dereference of a possibly null reference. + // z.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(10, 9)); } - public void AppendFormatted(int i) + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void LoopWithPatternDeclaration_SpreadPattern() { - System.Console.Write($"{i} "); + var source = """ +#nullable enable + +object? o = new object(); + +for (var x = 0; x < 10; x++) +{ + var a = Infer(o); + if (a is [.. var z]) + { + z.ToString(); } + + o = null; } -public static class CExt +C Infer(T t) => throw null!; + +public class C { } + +public static class E { - extension(C c) + extension(C t) { - public D this[int i, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument("i")] CustomHandler h] - { - get => new D(); - } + public int Length => 1; + public T this[System.Index i] => throw null!; + public T this[System.Range i] => throw null!; } } """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (10,9): warning CS8602: Dereference of a possibly null reference. + // z.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(10, 9)); + } - var comp = CreateCompilation(code, targetFramework: TargetFramework.Net100, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: ExpectedOutput("42 43"), verify: Verification.Skipped).VerifyDiagnostics(); + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void LoopWithPatternDeclaration_SpreadPattern_Slice() + { + var source = """ +#nullable enable - string expectedOperationTree = """ -IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... ld = 0 } };') - Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... eld = 0 } }') - Left: - IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') - Right: - IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... eld = 0 } }') - Arguments(0) - Initializer: - IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: C) (Syntax: '{ [42, $"{4 ... eld = 0 } }') - Initializers(1): - IMemberInitializerOperation (OperationKind.MemberInitializer, Type: D) (Syntax: '[42, $"{43} ... Field = 0 }') - InitializedMember: - IPropertyReferenceOperation: D CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { get; } (OperationKind.PropertyReference, Type: D) (Syntax: '[42, $"{43}"]') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: '[42, $"{43}"]') - Arguments(2): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') - IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Creation: - IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(3): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') - IInterpolatedStringHandlerArgumentPlaceholderOperation (ArgumentIndex: 0) (OperationKind.InterpolatedStringHandlerArgumentPlaceholder, Type: null, IsImplicit) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - Content: - IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$"{43}"') - Parts(1): - IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{43}') - AppendCall: - IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: D) (Syntax: '{ Field = 0 }') - Initializers(1): - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'Field = 0') - Left: - IFieldReferenceOperation: System.Int32 D.Field (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Field') - Instance Receiver: - IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: D, IsImplicit) (Syntax: 'Field') - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') -"""; +object? o = new object(); - VerifyOperationTreeAndDiagnosticsForTest(comp, expectedOperationTree, expectedDiagnostics: []); +for (var x = 0; x < 10; x++) +{ + var a = Infer(o); + if (a is [.. var z]) + { + z.ToString(); + } - var tree = comp.SyntaxTrees[0]; - var model = comp.GetSemanticModel(tree); - var mainDeclaration = tree.GetRoot().DescendantNodes().OfType().First(); + o = null; +} - var (graph, symbol) = ControlFlowGraphVerifier.GetControlFlowGraph(mainDeclaration.Body, model); - ControlFlowGraphVerifier.VerifyGraph(comp, """ -Block[B0] - Entry - Statements (0) - Next (Regular) Block[B1] - Entering: {R1} -.locals {R1} +C Infer(T t) => throw null!; + +public class C { } + +public static class E { - CaptureIds: [0] - Block[B1] - Block - Predecessors: [B0] - Statements (1) - IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new C() { [ ... eld = 0 } }') - Value: - IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C() { [ ... eld = 0 } }') - Arguments(0) - Initializer: - null - Next (Regular) Block[B2] - Entering: {R2} - .locals {R2} + extension(C t) { - CaptureIds: [1] [2] - Block[B2] - Block - Predecessors: [B1] - Statements (4) - IFlowCaptureOperation: 1 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '42') - Value: - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 42) (Syntax: '42') - IFlowCaptureOperation: 2 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: '$"{43}"') - Value: - IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount, System.Int32 i)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(3): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: formattedCount) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$"{43}"') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '42') - IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Initializer: - null - IInvocationOperation ( void CustomHandler.AppendFormatted(System.Int32 i)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{43}') - Instance Receiver: - IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - Arguments(1): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '43') - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 43) (Syntax: '43') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'Field = 0') - Left: - IFieldReferenceOperation: System.Int32 D.Field (OperationKind.FieldReference, Type: System.Int32) (Syntax: 'Field') - Instance Receiver: - IPropertyReferenceOperation: D CExt.$9794DAFCCB9E752B29BFD6350ADA77F2.this[System.Int32 i, CustomHandler h] { get; } (OperationKind.PropertyReference, Type: D) (Syntax: '[42, $"{43}"]') - Instance Receiver: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... eld = 0 } }') - Arguments(2): - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: i) (OperationKind.Argument, Type: null) (Syntax: '42') - IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Int32, Constant: 42, IsImplicit) (Syntax: '42') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: h) (OperationKind.Argument, Type: null) (Syntax: '$"{43}"') - IFlowCaptureReferenceOperation: 2 (OperationKind.FlowCaptureReference, Type: CustomHandler, IsImplicit) (Syntax: '$"{43}"') - InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Right: - ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') - Next (Regular) Block[B3] - Leaving: {R2} + public int Length => 1; + public T this[System.Index i] => throw null!; + public T Slice(int i, int j) => throw null!; } - Block[B3] - Block - Predecessors: [B2] - Statements (1) - IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = new C() ... ld = 0 } };') - Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: C) (Syntax: '_ = new C() ... eld = 0 } }') - Left: - IDiscardOperation (Symbol: C _) (OperationKind.Discard, Type: C) (Syntax: '_') - Right: - IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: C, IsImplicit) (Syntax: 'new C() { [ ... eld = 0 } }') - Next (Regular) Block[B4] - Leaving: {R1} } -Block[B4] - Exit - Predecessors: [B3] - Statements (0) -""", graph, symbol); +"""; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (10,9): warning CS8602: Dereference of a possibly null reference. + // z.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(10, 9)); } } diff --git a/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs b/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs index bb229ff2ee3a6..fd67584989774 100644 --- a/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs +++ b/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs @@ -4187,15 +4187,9 @@ static class Extensions var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( - // (14,21): error CS8985: List patterns may not be used for a value of type 'object'. No suitable 'Length' or 'Count' property was found. - // return u is [10]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[10]").WithArguments("object").WithLocation(14, 21), // (14,21): error CS0021: Cannot apply indexing with [] to an expression of type 'object' // return u is [10]; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[10]").WithArguments("object").WithLocation(14, 21), - // (19,21): error CS8985: List patterns may not be used for a value of type 'object'. No suitable 'Length' or 'Count' property was found. - // return u is [10]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[10]").WithArguments("object").WithLocation(19, 21), // (19,21): error CS0021: Cannot apply indexing with [] to an expression of type 'object' // return u is [10]; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[10]").WithArguments("object").WithLocation(19, 21) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs index e0ede9af8f890..af05428953fd9 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/IndexAndRangeTests.cs @@ -3909,6 +3909,89 @@ class C ); } + [Fact] + public void Nullable_01() + { + var source = @" +#nullable enable + +object? o1 = null; +Infer(o1)[^1].ToString(); + +object? o2 = null; +Infer(o2)[..].ToString(); + +object? o3 = new object(); +Infer(o3)[^1].ToString(); +Infer(o3)[..].ToString(); + +C Infer(T t) => throw null!; + +class C +{ + public int Length => 0; + public T this[int i] => throw null!; + public T Slice(int i, int j) => throw null!; +} +"; + var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range, TestSources.GetSubArray }); + comp.VerifyDiagnostics( + // 0.cs(5,1): warning CS8602: Dereference of a possibly null reference. + // Infer(o1)[^1].ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Infer(o1)[^1]").WithLocation(5, 1), + // 0.cs(8,1): warning CS8602: Dereference of a possibly null reference. + // Infer(o2)[..].ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Infer(o2)[..]").WithLocation(8, 1)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82802")] + public void Nullable_02() + { + var source = @" +#nullable enable + +object? o1 = null; +if (Infer(o1) is [var x]) +{ + x.ToString(); +} + +object? o2 = null; +if (Infer(o2) is [.. var y]) +{ + y.ToString(); +} + +object? o3 = new object(); +if (Infer(o3) is [var z1]) +{ + z1.ToString(); +} + +if (Infer(o3) is [.. var z2]) +{ + z2.ToString(); +} + +C Infer(T t) => throw null!; + +class C +{ + public int Length => 0; + public T this[int i] => throw null!; + public T Slice(int i, int j) => throw null!; +} +"; + var comp = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range, TestSources.GetSubArray }); + comp.VerifyDiagnostics( + // 0.cs(7,5): warning CS8602: Dereference of a possibly null reference. + // x.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(7, 5), + // 0.cs(13,5): warning CS8602: Dereference of a possibly null reference. + // y.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(13, 5)); + } + [Fact] public void PatternIndexArrayAndAwait_01() { diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs index fb22b33c85797..bbda1d6b5d673 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs @@ -47653,5 +47653,24 @@ IEnumerator IEnumerable.GetEnumerator() CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]).VerifyEmitDiagnostics(); } + + [Fact] + public void MissingMember_ArrayLength() + { + var source = """ +int[] i = [1, 2]; +int[] j = [0, .. i]; +"""; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(source); + comp.MakeMemberMissing(SpecialMember.System_Array__Length); + comp.VerifyEmitDiagnostics( + // (2,18): error CS0656: Missing compiler required member 'System.Array.Length' + // int[] j = [0, .. i]; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "i").WithArguments("System.Array", "Length").WithLocation(2, 18)); + } } } diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs index a35328f16e6f4..820742d1e7119 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -27743,23 +27743,7 @@ static class E } """; - // PROTOTYPE implicit indexers in list-patterns var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [1]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[1]").WithArguments("C").WithLocation(1, 16)); - - src = """ -_ = new C() is [1]; - -class C -{ - public int this[int i] => throw null; - public int Length => throw null; -} -"""; - comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics(); } @@ -27826,71 +27810,52 @@ static class E public void ExtensionMemberLookup_PatternBased_SpreadPattern_Length() { var src = """ -_ = new C() is [_, .. var x]; +if (new C() is [_, .. var x]) + System.Console.Write(x); class C { public int this[System.Index i] => throw null; - public int Slice(int i, int j) => throw null; + public int Slice(int i, int j) { System.Console.Write($"Slice({i},{j}) "); return 42; } } static class E { extension(C c) { - public int Length => throw null; + public int Length { get { System.Console.Write("length "); return 2; } } } } """; - // PROTOTYPE implicit indexers in list-patterns var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics( - // (1,16): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // _ = new C() is [_, .. var x]; - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[_, .. var x]").WithArguments("C").WithLocation(1, 16)); - - src = """ -_ = new C() is [_, .. var x]; - -class C -{ - public int this[System.Index i] => throw null; - public int Slice(int i, int j) => throw null; - public int Length => throw null; -} -"""; - comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("length Slice(1,1) 42"), verify: Verification.Skipped).VerifyDiagnostics(); } - [Fact(Skip = "PROTOTYPE implicit indexers in list-patterns")] + [Fact] public void ExtensionMemberLookup_PatternBased_SpreadPattern_Slice() { var src = """ -_ = new C() is [_, .. var x]; +if (new C() is [_, .. var x]) + System.Console.Write(x); class C { public int this[System.Index i] => throw null; - public int Length => throw null; + public int Length { get { System.Console.Write("length "); return 2; } } } static class E { extension(C c) { - public int Slice(int i, int j) => throw null; + public int Slice(int i, int j) { System.Console.Write($"Slice({i},{j}) "); return 42; } } } """; - // PROTOTYPE implicit indexers in list-patterns var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics( - // (1,20): error CS1503: Argument 1: cannot convert from 'System.Range' to 'System.Index' - // _ = new C() is [_, .. var x]; - Diagnostic(ErrorCode.ERR_BadArgType, ".. var x").WithArguments("1", "System.Range", "System.Index").WithLocation(1, 20)); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("length Slice(1,1) 42"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] @@ -28493,19 +28458,14 @@ static class E { public int Length { - get { System.Console.Write("length "); return 42; } + get { System.Console.Write("length "); return 1; } } } } """; - // PROTOTYPE should extension Length/Count count? var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics( - // (1,33): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found. - // System.Console.Write(new C() is ["hi"]); - Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, @"[""hi""]").WithArguments("C").WithLocation(1, 33) - ); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("length indexer True"), verify: Verification.Skipped).VerifyDiagnostics(); } [Fact] @@ -47345,6 +47305,35 @@ static class E Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 69)); } + [Fact] + public void Nullability_Deconstruct_07() + { + // generic Deconstruct + var src = """ +#nullable enable + +object? o = null; +var (o1, o2) = Infer(o); +o1.ToString(); + +C Infer(T t) => throw null!; + +class C { } + +static class E +{ + extension(C c) + { + public void Deconstruct(out T t1, out T t2) => throw null!; + } +} +"""; + CreateCompilation(src).VerifyEmitDiagnostics( + // (5,1): warning CS8602: Dereference of a possibly null reference. + // o1.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o1").WithLocation(5, 1)); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78022")] public void Nullability_PositionalPattern_01() { diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_ListPatterns.cs index 82cfbc00dc625..282f822a2232d 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_ListPatterns.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_ListPatterns.cs @@ -1006,9 +1006,15 @@ public void M(int[] a) // (6,18): error CS0656: Missing compiler required member 'System.Array.Length' // _ = a is [0]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[0]").WithArguments("System.Array", "Length").WithLocation(6, 18), + // (6,18): error CS8985: List patterns may not be used for a value of type 'int[]'. No suitable 'Length' or 'Count' property was found. + // _ = a is [0]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[0]").WithArguments("int[]").WithLocation(6, 18), // (7,18): error CS0656: Missing compiler required member 'System.Array.Length' // _ = a is [.._]; - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[.._]").WithArguments("System.Array", "Length").WithLocation(7, 18)); + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[.._]").WithArguments("System.Array", "Length").WithLocation(7, 18), + // (7,18): error CS8985: List patterns may not be used for a value of type 'int[]'. No suitable 'Length' or 'Count' property was found. + // _ = a is [.._]; + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[.._]").WithArguments("int[]").WithLocation(7, 18)); } [Fact] @@ -4332,14 +4338,14 @@ public void M() rest.ToString(); // 1 if (new C() is [1, ..var rest2]) - rest2.Value.ToString(); // (assumed not-null) + rest2.Value.ToString(); // 2 else - rest2.Value.ToString(); // 2, 3 + rest2.Value.ToString(); // 3, 4 if (new C() is [1, ..var rest3]) - rest3.ToString(); // (assumed not-null) + rest3.ToString(); // 5 else - rest3.ToString(); // 4, 5 + rest3.ToString(); // 6, 7 if (new C() is [1, ..var rest4]) { @@ -4347,11 +4353,11 @@ public void M() rest4 = null; } else - rest4.ToString(); // 6, 7 + rest4.ToString(); // 8, 9 if (new C() is [1, ..var rest5]) { - rest5.ToString(); // (assumed not-null) + rest5.ToString(); // 10 rest5 = default; } } @@ -4359,27 +4365,36 @@ public void M() "; var compilation = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); compilation.VerifyEmitDiagnostics( - // (14,13): error CS0165: Use of unassigned local variable 'rest' - // rest.ToString(); // 1 - Diagnostic(ErrorCode.ERR_UseDefViolation, "rest").WithArguments("rest").WithLocation(14, 13), - // (19,13): warning CS8629: Nullable value type may be null. - // rest2.Value.ToString(); // 2, 3 - Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(19, 13), - // (19,13): error CS0165: Use of unassigned local variable 'rest2' - // rest2.Value.ToString(); // 2, 3 - Diagnostic(ErrorCode.ERR_UseDefViolation, "rest2").WithArguments("rest2").WithLocation(19, 13), - // (24,13): warning CS8602: Dereference of a possibly null reference. - // rest3.ToString(); // 4, 5 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(24, 13), - // (24,13): error CS0165: Use of unassigned local variable 'rest3' - // rest3.ToString(); // 4, 5 - Diagnostic(ErrorCode.ERR_UseDefViolation, "rest3").WithArguments("rest3").WithLocation(24, 13), - // (32,13): warning CS8602: Dereference of a possibly null reference. - // rest4.ToString(); // 6, 7 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest4").WithLocation(32, 13), - // (32,13): error CS0165: Use of unassigned local variable 'rest4' - // rest4.ToString(); // 6, 7 - Diagnostic(ErrorCode.ERR_UseDefViolation, "rest4").WithArguments("rest4").WithLocation(32, 13) + // 0.cs(14,13): error CS0165: Use of unassigned local variable 'rest' + // rest.ToString(); // 1 + Diagnostic(ErrorCode.ERR_UseDefViolation, "rest").WithArguments("rest").WithLocation(14, 13), + // 0.cs(17,13): warning CS8629: Nullable value type may be null. + // rest2.Value.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(17, 13), + // 0.cs(19,13): warning CS8629: Nullable value type may be null. + // rest2.Value.ToString(); // 3, 4 + Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(19, 13), + // 0.cs(19,13): error CS0165: Use of unassigned local variable 'rest2' + // rest2.Value.ToString(); // 3, 4 + Diagnostic(ErrorCode.ERR_UseDefViolation, "rest2").WithArguments("rest2").WithLocation(19, 13), + // 0.cs(22,13): warning CS8602: Dereference of a possibly null reference. + // rest3.ToString(); // 5 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(22, 13), + // 0.cs(24,13): warning CS8602: Dereference of a possibly null reference. + // rest3.ToString(); // 6, 7 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(24, 13), + // 0.cs(24,13): error CS0165: Use of unassigned local variable 'rest3' + // rest3.ToString(); // 6, 7 + Diagnostic(ErrorCode.ERR_UseDefViolation, "rest3").WithArguments("rest3").WithLocation(24, 13), + // 0.cs(32,13): warning CS8602: Dereference of a possibly null reference. + // rest4.ToString(); // 8, 9 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest4").WithLocation(32, 13), + // 0.cs(32,13): error CS0165: Use of unassigned local variable 'rest4' + // rest4.ToString(); // 8, 9 + Diagnostic(ErrorCode.ERR_UseDefViolation, "rest4").WithArguments("rest4").WithLocation(32, 13), + // 0.cs(36,13): warning CS8602: Dereference of a possibly null reference. + // rest5.ToString(); // 10 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest5").WithLocation(36, 13) ); var tree = compilation.SyntaxTrees.First(); @@ -4422,7 +4437,13 @@ public void M() } "; var compilation = CreateCompilationWithIndexAndRange(source); - compilation.VerifyEmitDiagnostics(); + compilation.VerifyEmitDiagnostics( + // (12,13): warning CS8602: Dereference of a possibly null reference. + // slice.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "slice").WithLocation(12, 13), + // (14,13): warning CS8602: Dereference of a possibly null reference. + // list.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "list").WithLocation(14, 13)); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); @@ -4468,14 +4489,14 @@ public void M() rest.ToString(); // 1 if (new C() is [1, ..var rest2]) - rest2.Value.ToString(); // (assumed not-null) + rest2.Value.ToString(); // 2 else - rest2.Value.ToString(); // 2, 3 + rest2.Value.ToString(); // 3, 4 if (new C() is [1, ..var rest3]) - rest3.ToString(); // (assumed not-null) + rest3.ToString(); // 5 else - rest3.ToString(); // 4, 5 + rest3.ToString(); // 6, 7 if (new C() is [1, ..var rest4]) { @@ -4483,32 +4504,38 @@ public void M() rest4 = null; } else - rest4.ToString(); // 6, 7 + rest4.ToString(); // 8, 9 } } "; var compilation = CreateCompilation(new[] { source, TestSources.Index, TestSources.Range }); compilation.VerifyEmitDiagnostics( - // (15,13): error CS0165: Use of unassigned local variable 'rest' + // 0.cs(15,13): error CS0165: Use of unassigned local variable 'rest' // rest.ToString(); // 1 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest").WithArguments("rest").WithLocation(15, 13), - // (20,13): warning CS8629: Nullable value type may be null. - // rest2.Value.ToString(); // 2, 3 + // 0.cs(18,13): warning CS8629: Nullable value type may be null. + // rest2.Value.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(18, 13), + // 0.cs(20,13): warning CS8629: Nullable value type may be null. + // rest2.Value.ToString(); // 3, 4 Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "rest2").WithLocation(20, 13), - // (20,13): error CS0165: Use of unassigned local variable 'rest2' - // rest2.Value.ToString(); // 2, 3 + // 0.cs(20,13): error CS0165: Use of unassigned local variable 'rest2' + // rest2.Value.ToString(); // 3, 4 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest2").WithArguments("rest2").WithLocation(20, 13), - // (25,13): warning CS8602: Dereference of a possibly null reference. - // rest3.ToString(); // 4, 5 + // 0.cs(23,13): warning CS8602: Dereference of a possibly null reference. + // rest3.ToString(); // 5 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(23, 13), + // 0.cs(25,13): warning CS8602: Dereference of a possibly null reference. + // rest3.ToString(); // 6, 7 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest3").WithLocation(25, 13), - // (25,13): error CS0165: Use of unassigned local variable 'rest3' - // rest3.ToString(); // 4, 5 + // 0.cs(25,13): error CS0165: Use of unassigned local variable 'rest3' + // rest3.ToString(); // 6, 7 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest3").WithArguments("rest3").WithLocation(25, 13), - // (33,13): warning CS8602: Dereference of a possibly null reference. - // rest4.ToString(); // 6, 7 + // 0.cs(33,13): warning CS8602: Dereference of a possibly null reference. + // rest4.ToString(); // 8, 9 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "rest4").WithLocation(33, 13), - // (33,13): error CS0165: Use of unassigned local variable 'rest4' - // rest4.ToString(); // 6, 7 + // 0.cs(33,13): error CS0165: Use of unassigned local variable 'rest4' + // rest4.ToString(); // 8, 9 Diagnostic(ErrorCode.ERR_UseDefViolation, "rest4").WithArguments("rest4").WithLocation(33, 13) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesVsPatterns.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesVsPatterns.cs index 610e92183f025..a0ceb1c377e7c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesVsPatterns.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesVsPatterns.cs @@ -3029,8 +3029,10 @@ class Collection } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics(); - // Slice is assumed to be never null + comp.VerifyDiagnostics( + // (10,9): warning CS8602: Dereference of a possibly null reference. + // z.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(10, 9)); } [Fact, WorkItem(65976, "https://github.com/dotnet/roslyn/issues/65976")]