|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
public class InterpolationTests : CompilingTestBase
{
[Fact]
public void TestSimpleInterp()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
var number = 8675309;
Console.WriteLine($""Jenny don\'t change your number { number }."");
Console.WriteLine($""Jenny don\'t change your number { number , -12 }."");
Console.WriteLine($""Jenny don\'t change your number { number , 12 }."");
Console.WriteLine($""Jenny don\'t change your number { number :###-####}."");
Console.WriteLine($""Jenny don\'t change your number { number , -12 :###-####}."");
Console.WriteLine($""Jenny don\'t change your number { number , 12 :###-####}."");
Console.WriteLine($""{number}"");
}
}";
string expectedOutput =
@"Jenny don't change your number 8675309.
Jenny don't change your number 8675309 .
Jenny don't change your number 8675309.
Jenny don't change your number 867-5309.
Jenny don't change your number 867-5309 .
Jenny don't change your number 867-5309.
8675309";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TestOnlyInterp()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
var number = 8675309;
Console.WriteLine($""{number}"");
}
}";
string expectedOutput =
@"8675309";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TestDoubleInterp01()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
var number = 8675309;
Console.WriteLine($""{number}{number}"");
}
}";
string expectedOutput =
@"86753098675309";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TestDoubleInterp02()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
var number = 8675309;
Console.WriteLine($""Jenny don\'t change your number { number :###-####} { number :###-####}."");
}
}";
string expectedOutput =
@"Jenny don't change your number 867-5309 867-5309.";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TestEmptyInterp()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""Jenny don\'t change your number { /*trash*/ }."");
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (5,73): error CS1733: Expected expression
// Console.WriteLine("Jenny don\'t change your number \{ /*trash*/ }.");
Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(5, 73)
);
}
[Fact]
public void TestHalfOpenInterp01()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""Jenny don\'t change your number { "");
}
}";
// too many diagnostics perhaps, but it starts the right way.
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (5,63): error CS1010: Newline in constant
// Console.WriteLine($"Jenny don\'t change your number { ");
Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(5, 63),
// (6,5): error CS1039: Unterminated string literal
// }
Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "}").WithLocation(6, 5),
// (6,6): error CS1026: ) expected
// }
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 6),
// (6,6): error CS1002: ; expected
// }
Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 6),
// (7,2): error CS1513: } expected
// }
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2));
}
[Fact]
public void TestHalfOpenInterp02()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""Jenny don\'t change your number { 8675309 // "");
}
}";
// too many diagnostics perhaps, but it starts the right way.
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,5): error CS1039: Unterminated string literal
// }
Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "}").WithLocation(6, 5),
// (6,6): error CS1026: ) expected
// }
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 6),
// (6,6): error CS1002: ; expected
// }
Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 6),
// (7,2): error CS1513: } expected
// }
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2));
}
[Fact]
public void TestHalfOpenInterp03()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""Jenny don\'t change your number { 8675309 /* "");
}
}";
// too many diagnostics perhaps, but it starts the right way.
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (5,60): error CS8076: Missing close delimiter '}' for interpolated expression started with '{'.
// Console.WriteLine($"Jenny don\'t change your number { 8675309 /* ");
Diagnostic(ErrorCode.ERR_UnclosedExpressionHole, " {").WithLocation(5, 60),
// (5,71): error CS1035: End-of-file found, '*/' expected
// Console.WriteLine($"Jenny don\'t change your number { 8675309 /* ");
Diagnostic(ErrorCode.ERR_OpenEndedComment, "").WithLocation(5, 71),
// (7,2): error CS1026: ) expected
// }
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 2),
// (7,2): error CS1002: ; expected
// }
Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(7, 2),
// (7,2): error CS1513: } expected
// }
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2),
// (7,2): error CS1513: } expected
// }
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(7, 2));
}
[Fact]
public void LambdaInInterp()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
//Console.WriteLine(""jenny {0:(408) ###-####}"", new object[] { ((Func<int>)(() => { return number; })).Invoke() });
Console.WriteLine($""jenny { ((Func<int>)(() => { return number; })).Invoke() :(408) ###-####}"");
}
static int number = 8675309;
}
";
string expectedOutput = @"jenny (408) 867-5309";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void OneLiteral()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $""Hello"" );
}
}";
string expectedOutput = @"Hello";
var verifier = CompileAndVerify(source, expectedOutput: expectedOutput);
verifier.VerifyIL("Program.Main", @"
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldstr ""Hello""
IL_0005: call ""void System.Console.WriteLine(string)""
IL_000a: ret
}
");
}
[Fact]
public void OneInsert()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
var hello = $""Hello"";
Console.WriteLine( $""{hello}"" );
}
}";
string expectedOutput = @"Hello";
var verifier = CompileAndVerify(source, expectedOutput: expectedOutput);
verifier.VerifyIL("Program.Main", @"
{
// Code size 20 (0x14)
.maxstack 2
IL_0000: ldstr ""Hello""
IL_0005: dup
IL_0006: brtrue.s IL_000e
IL_0008: pop
IL_0009: ldstr """"
IL_000e: call ""void System.Console.WriteLine(string)""
IL_0013: ret
}
");
}
[Fact]
public void TwoInserts()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
var hello = $""Hello"";
var world = $""world"" ;
Console.WriteLine( $""{hello}, { world }."" );
}
}";
string expectedOutput = @"Hello, world.";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void TwoInserts02()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
var hello = $""Hello"";
var world = $""world"" ;
Console.WriteLine( $@""{
hello
},
{
world }."" );
}
}";
string expectedOutput = @"Hello,
world.";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact, WorkItem(306, "https://github.com/dotnet/roslyn/issues/306"), WorkItem(308, "https://github.com/dotnet/roslyn/issues/308")]
public void DynamicInterpolation()
{
string source =
@"using System;
using System.Linq.Expressions;
class Program
{
static void Main(string[] args)
{
dynamic nil = null;
dynamic a = new string[] {""Hello"", ""world""};
Console.WriteLine($""<{nil}>"");
Console.WriteLine($""<{a}>"");
}
Expression<Func<string>> M(dynamic d) {
return () => $""Dynamic: {d}"";
}
}";
string expectedOutput = @"<>
<System.String[]>";
var verifier = CompileAndVerify(source, new[] { CSharpRef }, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
public void UnclosedInterpolation01()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $""{"" );
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,31): error CS1010: Newline in constant
// Console.WriteLine( $"{" );
Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(6, 31),
// (7,5): error CS1039: Unterminated string literal
// }
Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "}").WithLocation(7, 5),
// (7,6): error CS1026: ) expected
// }
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 6),
// (7,6): error CS1002: ; expected
// }
Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(7, 6),
// (8,2): error CS1513: } expected
// }
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(8, 2));
}
[Fact]
public void UnclosedInterpolation02()
{
string source =
@"class Program
{
static void Main(string[] args)
{
var x = $"";";
// The precise error messages are not important, but this must be an error.
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (5,19): error CS1039: Unterminated string literal
// var x = $";
Diagnostic(ErrorCode.ERR_UnterminatedStringLit, ";").WithLocation(5, 19),
// (5,20): error CS1002: ; expected
// var x = $";
Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 20),
// (5,20): error CS1513: } expected
// var x = $";
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 20),
// (5,20): error CS1513: } expected
// var x = $";
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 20));
}
[Fact]
public void EmptyFormatSpecifier()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $""{3:}"" );
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,32): error CS8089: Empty format specifier.
// Console.WriteLine( $"{3:}" );
Diagnostic(ErrorCode.ERR_EmptyFormatSpecifier, ":").WithLocation(6, 32)
);
}
[Fact]
public void InvalidCharInFormatSpecifier()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $""{3:{}"" );
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,33): error CS1056: Unerwartetes Zeichen "{".
// Console.WriteLine( $"{3:{}" );
Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "{").WithArguments("{").WithLocation(6, 33)
);
}
[Fact]
public void TrailingSpaceInFormatSpecifier()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $""{3:d }"" );
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,32): error CS8088: A format specifier may not contain trailing whitespace.
// Console.WriteLine( $"{3:d }" );
Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, ":d ").WithLocation(6, 32)
);
}
[Fact]
public void TrailingSpaceInFormatSpecifier02()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $@""{3:d
}"" );
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,33): error CS8088: A format specifier may not contain trailing whitespace.
// Console.WriteLine( $@"{3:d
Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, @":d
").WithLocation(6, 33)
);
}
[Fact]
public void MissingInterpolationExpression01()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $""{ }"" );
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,32): error CS1733: Expected expression
// Console.WriteLine( $"{ }" );
Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 32)
);
}
[Fact]
public void MissingInterpolationExpression02()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( $@""{ }"" );
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (6,33): error CS1733: Expected expression
// Console.WriteLine( $@"{ }" );
Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 33)
);
}
[Fact]
public void MissingInterpolationExpression03()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine( ";
var normal = "$\"";
var verbat = "$@\"";
// ensure reparsing of interpolated string token is precise in error scenarios (assertions do not fail)
Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal + " ").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal + "{").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
Assert.True(SyntaxFactory.ParseSyntaxTree(source + normal + "{ ").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
Assert.True(SyntaxFactory.ParseSyntaxTree(source + verbat).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
Assert.True(SyntaxFactory.ParseSyntaxTree(source + verbat + " ").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
Assert.True(SyntaxFactory.ParseSyntaxTree(source + verbat + "{").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
Assert.True(SyntaxFactory.ParseSyntaxTree(source + verbat + "{ ").GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
}
[Fact]
public void MisplacedNewline01()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
var s = $""{ @""
"" }
"";
}
}";
// The precise error messages are not important, but this must be an error.
Assert.True(SyntaxFactory.ParseSyntaxTree(source).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
}
[Fact]
public void MisplacedNewline02()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
var s = $""{ @""
""}
"";
}
}";
// The precise error messages are not important, but this must be an error.
Assert.True(SyntaxFactory.ParseSyntaxTree(source).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
}
[Fact]
public void PreprocessorInsideInterpolation()
{
string source =
@"class Program
{
static void Main()
{
var s = $@""{
#region :
#endregion
0
}"";
}
}";
// The precise error messages are not important, but this must be an error.
Assert.True(SyntaxFactory.ParseSyntaxTree(source).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
}
[Fact]
public void EscapedCurly()
{
string source =
@"class Program
{
static void Main()
{
var s1 = $"" \u007B "";
var s2 = $"" \u007D"";
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (5,21): error CS8087: A '{' character may only be escaped by doubling '{{' in an interpolated string.
// var s1 = $" \u007B ";
Diagnostic(ErrorCode.ERR_EscapedCurly, @"\u007B").WithArguments("{").WithLocation(5, 21),
// (6,21): error CS8087: A '}' character may only be escaped by doubling '}}' in an interpolated string.
// var s2 = $" \u007D";
Diagnostic(ErrorCode.ERR_EscapedCurly, @"\u007D").WithArguments("}").WithLocation(6, 21)
);
}
[Fact, WorkItem(1119878, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1119878")]
public void NoFillIns01()
{
string source =
@"class Program
{
static void Main()
{
System.Console.Write($""{{ x }}"");
System.Console.WriteLine($@""This is a test"");
}
}";
string expectedOutput = @"{ x }This is a test";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
[Fact]
public void BadAlignment()
{
string source =
@"class Program
{
static void Main()
{
var s = $""{1,1E10}"";
var t = $""{1,(int)1E10}"";
}
}";
CreateCompilationWithMscorlib461(source).VerifyDiagnostics(
// (5,22): error CS0266: Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?)
// var s = $"{1,1E10}";
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "1E10").WithArguments("double", "int").WithLocation(5, 22),
// (5,22): error CS0150: A constant value is expected
// var s = $"{1,1E10}";
Diagnostic(ErrorCode.ERR_ConstantExpected, "1E10").WithLocation(5, 22),
// (6,22): error CS0221: Constant value '10000000000' cannot be converted to a 'int' (use 'unchecked' syntax to override)
// var t = $"{1,(int)1E10}";
Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "(int)1E10").WithArguments("10000000000", "int").WithLocation(6, 22),
// (6,22): error CS0150: A constant value is expected
// var t = $"{1,(int)1E10}";
Diagnostic(ErrorCode.ERR_ConstantExpected, "(int)1E10").WithLocation(6, 22)
);
}
[Fact]
public void NestedInterpolatedVerbatim()
{
string source =
@"using System;
class Program
{
static void Main(string[] args)
{
var s = $@""{$@""{1}""}"";
Console.WriteLine(s);
}
}";
string expectedOutput = @"1";
CompileAndVerify(source, expectedOutput: expectedOutput);
}
// Since the platform type System.FormattableString is not yet in our platforms (at the
// time of writing), we explicitly include the required platform types into the sources under test.
private const string formattableString = @"
/*============================================================
**
** Class: FormattableString
**
**
** Purpose: implementation of the FormattableString
** class.
**
===========================================================*/
namespace System
{
/// <summary>
/// A composite format string along with the arguments to be formatted. An instance of this
/// type may result from the use of the C# or VB language primitive ""interpolated string"".
/// </summary>
public abstract class FormattableString : IFormattable
{
/// <summary>
/// The composite format string.
/// </summary>
public abstract string Format { get; }
/// <summary>
/// Returns an object array that contains zero or more objects to format. Clients should not
/// mutate the contents of the array.
/// </summary>
public abstract object[] GetArguments();
/// <summary>
/// The number of arguments to be formatted.
/// </summary>
public abstract int ArgumentCount { get; }
/// <summary>
/// Returns one argument to be formatted from argument position <paramref name=""index""/>.
/// </summary>
public abstract object GetArgument(int index);
/// <summary>
/// Format to a string using the given culture.
/// </summary>
public abstract string ToString(IFormatProvider formatProvider);
string IFormattable.ToString(string ignored, IFormatProvider formatProvider)
{
return ToString(formatProvider);
}
/// <summary>
/// Format the given object in the invariant culture. This static method may be
/// imported in C# by
/// <code>
/// using static System.FormattableString;
/// </code>.
/// Within the scope
/// of that import directive an interpolated string may be formatted in the
/// invariant culture by writing, for example,
/// <code>
/// Invariant($""{{ lat = {latitude}; lon = {longitude} }}"")
/// </code>
/// </summary>
public static string Invariant(FormattableString formattable)
{
if (formattable == null)
{
throw new ArgumentNullException(""formattable"");
}
return formattable.ToString(Globalization.CultureInfo.InvariantCulture);
}
public override string ToString()
{
return ToString(Globalization.CultureInfo.CurrentCulture);
}
}
}
/*============================================================
**
** Class: FormattableStringFactory
**
**
** Purpose: implementation of the FormattableStringFactory
** class.
**
===========================================================*/
namespace System.Runtime.CompilerServices
{
/// <summary>
/// A factory type used by compilers to create instances of the type <see cref=""FormattableString""/>.
/// </summary>
public static class FormattableStringFactory
{
/// <summary>
/// Create a <see cref=""FormattableString""/> from a composite format string and object
/// array containing zero or more objects to format.
/// </summary>
public static FormattableString Create(string format, params object[] arguments)
{
if (format == null)
{
throw new ArgumentNullException(""format"");
}
if (arguments == null)
{
throw new ArgumentNullException(""arguments"");
}
return new ConcreteFormattableString(format, arguments);
}
private sealed class ConcreteFormattableString : FormattableString
{
private readonly string _format;
private readonly object[] _arguments;
internal ConcreteFormattableString(string format, object[] arguments)
{
_format = format;
_arguments = arguments;
}
public override string Format { get { return _format; } }
public override object[] GetArguments() { return _arguments; }
public override int ArgumentCount { get { return _arguments.Length; } }
public override object GetArgument(int index) { return _arguments[index]; }
public override string ToString(IFormatProvider formatProvider) { return string.Format(formatProvider, Format, _arguments); }
}
}
}
";
[Fact]
public void TargetType01()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
IFormattable f = $""test"";
Console.Write(f is System.FormattableString);
}
}";
CompileAndVerify(source + formattableString, expectedOutput: "True");
}
[Fact]
public void TargetType02()
{
string source =
@"using System;
interface I1 { void M(String s); }
interface I2 { void M(FormattableString s); }
interface I3 { void M(IFormattable s); }
interface I4 : I1, I2 {}
interface I5 : I1, I3 {}
interface I6 : I2, I3 {}
interface I7 : I1, I2, I3 {}
class C : I1, I2, I3, I4, I5, I6, I7
{
public void M(String s) { Console.Write(1); }
public void M(FormattableString s) { Console.Write(2); }
public void M(IFormattable s) { Console.Write(3); }
}
class Program {
public static void Main(string[] args)
{
C c = new C();
((I1)c).M($"""");
((I2)c).M($"""");
((I3)c).M($"""");
((I4)c).M($"""");
((I5)c).M($"""");
((I6)c).M($"""");
((I7)c).M($"""");
((C)c).M($"""");
}
}";
CompileAndVerify(source + formattableString, expectedOutput: "12311211");
}
[Fact]
public void MissingHelper()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
IFormattable f = $""test"";
}
}";
CreateCompilationWithMscorlib40(source).VerifyEmitDiagnostics(
// (5,26): error CS0518: Predefined type 'System.Runtime.CompilerServices.FormattableStringFactory' is not defined or imported
// IFormattable f = $"test";
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"$""test""").WithArguments("System.Runtime.CompilerServices.FormattableStringFactory").WithLocation(5, 26)
);
}
[Fact]
public void AsyncInterp()
{
string source =
@"using System;
using System.Threading.Tasks;
class Program {
public static void Main(string[] args)
{
Task<string> hello = Task.FromResult(""Hello"");
Task<string> world = Task.FromResult(""world"");
M(hello, world).Wait();
}
public static async Task M(Task<string> hello, Task<string> world)
{
Console.WriteLine($""{ await hello }, { await world }!"");
}
}";
CompileAndVerify(
source, references: new[] { MscorlibRef_v4_0_30316_17626, SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929 }, expectedOutput: "Hello, world!", targetFramework: TargetFramework.Empty);
}
[Fact]
public void AlignmentExpression()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""X = { 123 , -(3+4) }."");
}
}";
CompileAndVerify(source + formattableString, expectedOutput: "X = 123 .");
}
[Fact]
public void AlignmentMagnitude()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""X = { 123 , (32768) }."");
Console.WriteLine($""X = { 123 , -(32768) }."");
Console.WriteLine($""X = { 123 , (32767) }."");
Console.WriteLine($""X = { 123 , -(32767) }."");
Console.WriteLine($""X = { 123 , int.MaxValue }."");
Console.WriteLine($""X = { 123 , int.MinValue }."");
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (5,42): warning CS8094: Alignment value 32768 has a magnitude greater than 32767 and may result in a large formatted string.
// Console.WriteLine($"X = { 123 , (32768) }.");
Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "32768").WithArguments("32768", "32767").WithLocation(5, 42),
// (6,41): warning CS8094: Alignment value -32768 has a magnitude greater than 32767 and may result in a large formatted string.
// Console.WriteLine($"X = { 123 , -(32768) }.");
Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "-(32768)").WithArguments("-32768", "32767").WithLocation(6, 41),
// (9,41): warning CS8094: Alignment value 2147483647 has a magnitude greater than 32767 and may result in a large formatted string.
// Console.WriteLine($"X = { 123 , int.MaxValue }.");
Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "int.MaxValue").WithArguments("2147483647", "32767").WithLocation(9, 41),
// (10,41): warning CS8094: Alignment value -2147483648 has a magnitude greater than 32767 and may result in a large formatted string.
// Console.WriteLine($"X = { 123 , int.MinValue }.");
Diagnostic(ErrorCode.WRN_AlignmentMagnitude, "int.MinValue").WithArguments("-2147483648", "32767").WithLocation(10, 41)
);
}
[WorkItem(1097388, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097388")]
[Fact]
public void InterpolationExpressionMustBeValue01()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""X = { String }."");
Console.WriteLine($""X = { null }."");
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (5,35): error CS0119: 'string' is a type, which is not valid in the given context
// Console.WriteLine($"X = { String }.");
Diagnostic(ErrorCode.ERR_BadSKunknown, "String").WithArguments("string", "type").WithLocation(5, 35)
);
}
[Fact]
public void InterpolationExpressionMustBeValue02()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
Console.WriteLine($""X = { x=>3 }."");
Console.WriteLine($""X = { Program.Main }."");
Console.WriteLine($""X = { Program.Main(null) }."");
}
}";
CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics(
// (5,36): error CS1660: Cannot convert lambda expression to type 'object' because it is not a delegate type
// Console.WriteLine($"X = { x=>3 }.");
Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "=>").WithArguments("lambda expression", "object").WithLocation(5, 36),
// (6,43): error CS0428: Cannot convert method group 'Main' to non-delegate type 'object'. Did you intend to invoke the method?
// Console.WriteLine($"X = { Program.Main }.");
Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "Main").WithArguments("Main", "object").WithLocation(6, 43),
// (7,35): error CS0029: Cannot implicitly convert type 'void' to 'object'
// Console.WriteLine($"X = { Program.Main(null) }.");
Diagnostic(ErrorCode.ERR_NoImplicitConv, "Program.Main(null)").WithArguments("void", "object").WithLocation(7, 35));
CreateCompilation(source).VerifyDiagnostics(
// (5,36): error CS8917: The delegate type could not be inferred.
// Console.WriteLine($"X = { x=>3 }.");
Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "=>").WithLocation(5, 36),
// (6,35): warning CS8974: Converting method group 'Main' to non-delegate type 'object'. Did you intend to invoke the method?
// Console.WriteLine($"X = { Program.Main }.");
Diagnostic(ErrorCode.WRN_MethGrpToNonDel, "Program.Main").WithArguments("Main", "object").WithLocation(6, 35),
// (7,35): error CS0029: Cannot implicitly convert type 'void' to 'object'
// Console.WriteLine($"X = { Program.Main(null) }.");
Diagnostic(ErrorCode.ERR_NoImplicitConv, "Program.Main(null)").WithArguments("void", "object").WithLocation(7, 35));
}
[WorkItem(1097428, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097428")]
[Fact]
public void BadCorelib01()
{
var text =
@"namespace System
{
public class Object { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { private Boolean m_value; Boolean Use(Boolean b) { m_value = b; return m_value; } }
public struct Int32 { private Int32 m_value; Int32 Use(Int32 b) { m_value = b; return m_value; } }
public struct Char { }
public class String { }
internal class Program
{
public static void Main()
{
var s = $""X = { 1 } "";
}
}
}";
CreateEmptyCompilation(text, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugExe)
.VerifyEmitDiagnostics(new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "x.y"),
// (15,21): error CS0117: 'string' does not contain a definition for 'Format'
// var s = $"X = { 1 } ";
Diagnostic(ErrorCode.ERR_NoSuchMember, @"$""X = { 1 } """).WithArguments("string", "Format").WithLocation(15, 21)
);
}
[WorkItem(1097428, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097428")]
[Fact]
public void BadCorelib02()
{
var text =
@"namespace System
{
public class Object { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { private Boolean m_value; Boolean Use(Boolean b) { m_value = b; return m_value; } }
public struct Int32 { private Int32 m_value; Int32 Use(Int32 b) { m_value = b; return m_value; } }
public struct Char { }
public class String {
public static Boolean Format(string format, int arg) { return true; }
}
internal class Program
{
public static void Main()
{
var s = $""X = { 1 } "";
}
}
}";
CreateEmptyCompilation(text, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugExe)
.VerifyEmitDiagnostics(new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "x.y"),
// (17,21): error CS0029: Cannot implicitly convert type 'bool' to 'string'
// var s = $"X = { 1 } ";
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""X = { 1 } """).WithArguments("bool", "string").WithLocation(17, 21)
);
}
[Fact]
public void SillyCoreLib01()
{
var text =
@"namespace System
{
interface IFormattable { }
namespace Runtime.CompilerServices {
public static class FormattableStringFactory {
public static Bozo Create(string format, int arg) { return new Bozo(); }
}
}
public class Object { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { private Boolean m_value; Boolean Use(Boolean b) { m_value = b; return m_value; } }
public struct Int32 { private Int32 m_value; Int32 Use(Int32 b) { m_value = b; return m_value; } }
public struct Char { }
public class String {
public static Bozo Format(string format, int arg) { return new Bozo(); }
}
public class FormattableString {
}
public class Bozo {
public static implicit operator string(Bozo bozo) { return ""zz""; }
public static implicit operator FormattableString(Bozo bozo) { return new FormattableString(); }
}
internal class Program
{
public static void Main()
{
var s1 = $""X = { 1 } "";
FormattableString s2 = $""X = { 1 } "";
}
}
}";
var comp = CreateEmptyCompilation(text, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: Test.Utilities.TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
var compilation = CompileAndVerify(comp, verify: Verification.Fails);
compilation.VerifyIL("System.Program.Main",
@"{
// Code size 35 (0x23)
.maxstack 2
IL_0000: ldstr ""X = {0} ""
IL_0005: ldc.i4.1
IL_0006: call ""System.Bozo string.Format(string, int)""
IL_000b: call ""string System.Bozo.op_Implicit(System.Bozo)""
IL_0010: pop
IL_0011: ldstr ""X = {0} ""
IL_0016: ldc.i4.1
IL_0017: call ""System.Bozo System.Runtime.CompilerServices.FormattableStringFactory.Create(string, int)""
IL_001c: call ""System.FormattableString System.Bozo.op_Implicit(System.Bozo)""
IL_0021: pop
IL_0022: ret
}");
}
[WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")]
#if NET
[InlineData(TargetFramework.Net60)]
[InlineData(TargetFramework.Net50)]
#endif
[InlineData(TargetFramework.NetFramework)]
[InlineData(TargetFramework.NetStandard20)]
[InlineData(TargetFramework.Mscorlib461)]
[InlineData(TargetFramework.Mscorlib40)]
[Theory]
public void InterpolatedStringWithCurlyBracesAndFormatSpecifier(TargetFramework framework)
{
var text =
@"using System;
class App{
public static void Main(){
var str = $""Before {{{12:X}}} After"";
Console.WriteLine(str);
}
}";
var parseOptions = new CSharpParseOptions(
languageVersion: LanguageVersion.CSharp10,
documentationMode: DocumentationMode.Parse,
kind: SourceCodeKind.Regular
);
var compOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication);
//string.Format was fixed in dotnet core 3
var expectedOutput =
#if NETCOREAPP3_0_OR_GREATER
"Before {C} After"
#else
"Before {X} After"
#endif
;
var comp = CreateCompilation(text, targetFramework: framework,
parseOptions: parseOptions, options: compOptions);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
switch (framework)
{
case TargetFramework.Net60:
checkNet60IL(verifier);
break;
default:
checkNet50IL(verifier);
break;
}
static void checkNet50IL(CompilationVerifier verifier)
{
verifier.VerifyIL("App.Main", @"{
// Code size 27 (0x1b)
.maxstack 2
.locals init (string V_0) //str
IL_0000: nop
IL_0001: ldstr ""Before {{{0:X}}} After""
IL_0006: ldc.i4.s 12
IL_0008: box ""int""
IL_000d: call ""string string.Format(string, object)""
IL_0012: stloc.0
IL_0013: ldloc.0
IL_0014: call ""void System.Console.WriteLine(string)""
IL_0019: nop
IL_001a: ret
}");
}
static void checkNet60IL(CompilationVerifier verifier)
{
verifier.VerifyIL("App.Main", @"{
// Code size 68 (0x44)
.maxstack 3
.locals init (string V_0, //str
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: nop
IL_0001: ldloca.s V_1
IL_0003: ldc.i4.s 15
IL_0005: ldc.i4.1
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldstr ""Before {""
IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0017: nop
IL_0018: ldloca.s V_1
IL_001a: ldc.i4.s 12
IL_001c: ldstr ""X""
IL_0021: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)""
IL_0026: nop
IL_0027: ldloca.s V_1
IL_0029: ldstr ""} After""
IL_002e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0033: nop
IL_0034: ldloca.s V_1
IL_0036: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_003b: stloc.0
IL_003c: ldloc.0
IL_003d: call ""void System.Console.WriteLine(string)""
IL_0042: nop
IL_0043: ret
}");
}
}
[WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")]
#if NET
[InlineData(TargetFramework.Net60)]
[InlineData(TargetFramework.Net50)]
#endif
[InlineData(TargetFramework.NetFramework)]
[InlineData(TargetFramework.NetStandard20)]
[InlineData(TargetFramework.Mscorlib461)]
[InlineData(TargetFramework.Mscorlib40)]
[Theory]
public void RawInterpolatedStringWithCurlyBracesAndFormatSpecifier(TargetFramework framework)
{
var text =
@"using System;
class App{
public static void Main(){
var str = $$""""""Before {{{12:X}}} After"""""";
Console.WriteLine(str);
}
}";
var parseOptions = TestOptions.Regular11;
var compOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication);
//string.Format was fixed in dotnet core 3
var expectedOutput =
#if NETCOREAPP3_0_OR_GREATER
"Before {C} After"
#else
"Before {X} After"
#endif
;
var comp = CreateCompilation(text, targetFramework: framework,
parseOptions: parseOptions, options: compOptions);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
switch (framework)
{
case TargetFramework.Net60:
checkNet60IL(verifier);
break;
default:
checkNet50IL(verifier);
break;
}
static void checkNet50IL(CompilationVerifier verifier)
{
verifier.VerifyIL("App.Main", @"{
// Code size 27 (0x1b)
.maxstack 2
.locals init (string V_0) //str
IL_0000: nop
IL_0001: ldstr ""Before {{{0:X}}} After""
IL_0006: ldc.i4.s 12
IL_0008: box ""int""
IL_000d: call ""string string.Format(string, object)""
IL_0012: stloc.0
IL_0013: ldloc.0
IL_0014: call ""void System.Console.WriteLine(string)""
IL_0019: nop
IL_001a: ret
}");
}
static void checkNet60IL(CompilationVerifier verifier)
{
verifier.VerifyIL("App.Main", @"{
// Code size 68 (0x44)
.maxstack 3
.locals init (string V_0, //str
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: nop
IL_0001: ldloca.s V_1
IL_0003: ldc.i4.s 15
IL_0005: ldc.i4.1
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldstr ""Before {""
IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0017: nop
IL_0018: ldloca.s V_1
IL_001a: ldc.i4.s 12
IL_001c: ldstr ""X""
IL_0021: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)""
IL_0026: nop
IL_0027: ldloca.s V_1
IL_0029: ldstr ""} After""
IL_002e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0033: nop
IL_0034: ldloca.s V_1
IL_0036: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_003b: stloc.0
IL_003c: ldloc.0
IL_003d: call ""void System.Console.WriteLine(string)""
IL_0042: nop
IL_0043: ret
}");
}
}
[WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")]
#if NET
[InlineData(TargetFramework.Net60)]
[InlineData(TargetFramework.Net50)]
#endif
[InlineData(TargetFramework.NetFramework)]
[InlineData(TargetFramework.NetStandard20)]
[InlineData(TargetFramework.Mscorlib461)]
[InlineData(TargetFramework.Mscorlib40)]
[Theory]
public void InterpolatedStringWithCurlyBracesAndAllStringValues(TargetFramework framework)
{
var text =
@"using System;
class App{
public static void Main(){
string a = ""a"";
var str = $""Before {{{a}}} After"";
Console.WriteLine(str);
}
}";
var parseOptions = new CSharpParseOptions(
languageVersion: LanguageVersion.CSharp10,
documentationMode: DocumentationMode.Parse,
kind: SourceCodeKind.Regular
);
var compOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication);
var expectedOutput = "Before {a} After";
var comp = CreateCompilation(text, targetFramework: framework,
parseOptions: parseOptions, options: compOptions);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
verifier.VerifyIL("App.Main", @"{
// Code size 32 (0x20)
.maxstack 3
.locals init (string V_0, //a
string V_1) //str
IL_0000: nop
IL_0001: ldstr ""a""
IL_0006: stloc.0
IL_0007: ldstr ""Before {""
IL_000c: ldloc.0
IL_000d: ldstr ""} After""
IL_0012: call ""string string.Concat(string, string, string)""
IL_0017: stloc.1
IL_0018: ldloc.1
IL_0019: call ""void System.Console.WriteLine(string)""
IL_001e: nop
IL_001f: ret
}");
}
[WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")]
#if NET
[InlineData(TargetFramework.Net60)]
[InlineData(TargetFramework.Net50)]
#endif
[InlineData(TargetFramework.NetFramework)]
[InlineData(TargetFramework.NetStandard20)]
[InlineData(TargetFramework.Mscorlib461)]
[InlineData(TargetFramework.Mscorlib40)]
[Theory]
public void RawInterpolatedStringWithCurlyBracesAndAllStringValues(TargetFramework framework)
{
var text =
@"using System;
class App{
public static void Main(){
string a = ""a"";
var str = $$""""""Before {{{a}}} After"""""";
Console.WriteLine(str);
}
}";
var parseOptions = TestOptions.Regular11;
var compOptions = new CSharpCompilationOptions(OutputKind.ConsoleApplication);
var expectedOutput = "Before {a} After";
var comp = CreateCompilation(text, targetFramework: framework,
parseOptions: parseOptions, options: compOptions);
comp.VerifyDiagnostics();
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
verifier.VerifyIL("App.Main", @"{
// Code size 32 (0x20)
.maxstack 3
.locals init (string V_0, //a
string V_1) //str
IL_0000: nop
IL_0001: ldstr ""a""
IL_0006: stloc.0
IL_0007: ldstr ""Before {""
IL_000c: ldloc.0
IL_000d: ldstr ""} After""
IL_0012: call ""string string.Concat(string, string, string)""
IL_0017: stloc.1
IL_0018: ldloc.1
IL_0019: call ""void System.Console.WriteLine(string)""
IL_001e: nop
IL_001f: ret
}");
}
[WorkItem(1097386, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097386")]
[Fact]
public void Syntax01()
{
var text =
@"using System;
class Program
{
static void Main(string[] args)
{
var x = $""{ Math.Abs(value: 1):\}"";
var y = x;
}
}";
CreateCompilation(text).VerifyDiagnostics(
// (6,40): error CS8087: A '}' character may only be escaped by doubling '}}' in an interpolated string.
// var x = $"{ Math.Abs(value: 1):\}";
Diagnostic(ErrorCode.ERR_EscapedCurly, @"\").WithArguments("}").WithLocation(6, 40),
// (6,40): error CS1009: Unrecognized escape sequence
// var x = $"{ Math.Abs(value: 1):\}";
Diagnostic(ErrorCode.ERR_IllegalEscape, @"\}").WithLocation(6, 40)
);
}
[WorkItem(1097941, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097941")]
[Fact]
public void Syntax02()
{
var text =
@"using S = System;
class C
{
void M()
{
var x = $""{ (S:
}
}";
// the precise diagnostics do not matter, as long as it is an error and not a crash.
Assert.True(SyntaxFactory.ParseSyntaxTree(text).GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error));
}
[WorkItem(1097386, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097386")]
[Fact]
public void Syntax03()
{
var text =
@"using System;
class Program
{
static void Main(string[] args)
{
var x = $""{ Math.Abs(value: 1):}}"";
var y = x;
}
}
";
CreateCompilation(text).VerifyDiagnostics(
// (6,39): error CS8089: Empty format specifier.
// var x = $"{ Math.Abs(value: 1):}}";
Diagnostic(ErrorCode.ERR_EmptyFormatSpecifier, ":").WithLocation(6, 39),
// (6,41): error CS8086: A '}' character must be escaped (by doubling) in an interpolated string.
// var x = $"{ Math.Abs(value: 1):}}";
Diagnostic(ErrorCode.ERR_UnescapedCurly, "}").WithArguments("}").WithLocation(6, 41)
);
}
[WorkItem(1099105, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1099105")]
[Fact]
public void NoUnexpandedForm()
{
string source =
@"using System;
class Program {
public static void Main(string[] args)
{
string[] arr1 = new string[] { ""xyzzy"" };
object[] arr2 = arr1;
Console.WriteLine($""-{null}-"");
Console.WriteLine($""-{arr1}-"");
Console.WriteLine($""-{arr2}-"");
}
}";
CompileAndVerify(source + formattableString, expectedOutput:
@"--
-System.String[]-
-System.String[]-");
}
[WorkItem(1097386, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1097386")]
[Fact]
public void Dynamic01()
{
var text =
@"class C
{
const dynamic a = a;
string s = $""{0,a}"";
}";
CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(
// (3,19): error CS0110: The evaluation of the constant value for 'C.a' involves a circular definition
// const dynamic a = a;
Diagnostic(ErrorCode.ERR_CircConstValue, "a").WithArguments("C.a").WithLocation(3, 19),
// (3,23): error CS0134: 'C.a' is of type 'dynamic'. A const field of a reference type other than string can only be initialized with null.
// const dynamic a = a;
Diagnostic(ErrorCode.ERR_NotNullConstRefField, "a").WithArguments("C.a", "dynamic").WithLocation(3, 23),
// (4,21): error CS0150: A constant value is expected
// string s = $"{0,a}";
Diagnostic(ErrorCode.ERR_ConstantExpected, "a").WithLocation(4, 21)
);
}
[WorkItem(1099238, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1099238")]
[Fact]
public void Syntax04()
{
var text =
@"using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
Expression<Func<string>> e = () => $""\u1{0:\u2}"";
Console.WriteLine(e);
}
}";
CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(
// (8,46): error CS1009: Unrecognized escape sequence
// Expression<Func<string>> e = () => $"\u1{0:\u2}";
Diagnostic(ErrorCode.ERR_IllegalEscape, @"\u1").WithLocation(8, 46),
// (8,52): error CS1009: Unrecognized escape sequence
// Expression<Func<string>> e = () => $"\u1{0:\u2}";
Diagnostic(ErrorCode.ERR_IllegalEscape, @"\u2").WithLocation(8, 52)
);
}
[Fact, WorkItem(1098612, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1098612")]
public void MissingConversionFromFormattableStringToIFormattable()
{
var text =
@"namespace System.Runtime.CompilerServices
{
public static class FormattableStringFactory
{
public static FormattableString Create(string format, params object[] arguments)
{
return null;
}
}
}
namespace System
{
public abstract class FormattableString
{
}
}
static class C
{
static void Main()
{
System.IFormattable i = $""{""""}"";
}
}";
CreateCompilationWithMscorlib40AndSystemCore(text).VerifyEmitDiagnostics(
// (23,33): error CS0029: Cannot implicitly convert type 'FormattableString' to 'IFormattable'
// System.IFormattable i = $"{""}";
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""{""""}""").WithArguments("System.FormattableString", "System.IFormattable").WithLocation(23, 33)
);
}
[Fact]
public void VoidReturningFactory()
{
var text =
@"
namespace System.Runtime.CompilerServices
{
public static class FormattableStringFactory
{
public static void Create(string format, params object[] arguments)
{
}
}
}
static class C
{
static void Main()
{
System.IFormattable i = $""{""""}"";
}
}";
CreateCompilation(text).VerifyDiagnostics(
// (16,33): error CS0029: Cannot implicitly convert type 'void' to 'IFormattable'
// System.IFormattable i = $"{""}";
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""{""""}""").WithArguments("void", "System.IFormattable").WithLocation(16, 33)
);
}
[Theory, WorkItem(54702, "https://github.com/dotnet/roslyn/issues/54702")]
[InlineData(@"$""{s1}{s2}""", @"$""{s1}{s2}{s3}""", @"$""{s1}{s2}{s3}{s4}""", @"$""{s1}{s2}{s3}{s4}{s5}""")]
[InlineData(@"$""{s1}"" + $""{s2}""", @"$""{s1}"" + $""{s2}"" + $""{s3}""", @"$""{s1}"" + $""{s2}"" + $""{s3}"" + $""{s4}""", @"$""{s1}"" + $""{s2}"" + $""{s3}"" + $""{s4}"" + $""{s5}""")]
public void InterpolatedStringHandler_ConcatPreferencesForAllStringElements(string twoComponents, string threeComponents, string fourComponents, string fiveComponents)
{
var code = @"
using System;
Console.WriteLine(TwoComponents());
Console.WriteLine(ThreeComponents());
Console.WriteLine(FourComponents());
Console.WriteLine(FiveComponents());
string TwoComponents()
{
string s1 = ""1"";
string s2 = ""2"";
return " + twoComponents + @";
}
string ThreeComponents()
{
string s1 = ""1"";
string s2 = ""2"";
string s3 = ""3"";
return " + threeComponents + @";
}
string FourComponents()
{
string s1 = ""1"";
string s2 = ""2"";
string s3 = ""3"";
string s4 = ""4"";
return " + fourComponents + @";
}
string FiveComponents()
{
string s1 = ""1"";
string s2 = ""2"";
string s3 = ""3"";
string s4 = ""4"";
string s5 = ""5"";
return " + fiveComponents + @";
}
";
var handler = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { code, handler }, expectedOutput: @"
12
123
1234
value:1
value:2
value:3
value:4
value:5
");
verifier.VerifyIL("Program.<<Main>$>g__TwoComponents|0_0()", @"
{
// Code size 18 (0x12)
.maxstack 2
.locals init (string V_0) //s2
IL_0000: ldstr ""1""
IL_0005: ldstr ""2""
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: call ""string string.Concat(string, string)""
IL_0011: ret
}
");
verifier.VerifyIL("Program.<<Main>$>g__ThreeComponents|0_1()", @"
{
// Code size 25 (0x19)
.maxstack 3
.locals init (string V_0, //s2
string V_1) //s3
IL_0000: ldstr ""1""
IL_0005: ldstr ""2""
IL_000a: stloc.0
IL_000b: ldstr ""3""
IL_0010: stloc.1
IL_0011: ldloc.0
IL_0012: ldloc.1
IL_0013: call ""string string.Concat(string, string, string)""
IL_0018: ret
}
");
verifier.VerifyIL("Program.<<Main>$>g__FourComponents|0_2()", @"
{
// Code size 32 (0x20)
.maxstack 4
.locals init (string V_0, //s2
string V_1, //s3
string V_2) //s4
IL_0000: ldstr ""1""
IL_0005: ldstr ""2""
IL_000a: stloc.0
IL_000b: ldstr ""3""
IL_0010: stloc.1
IL_0011: ldstr ""4""
IL_0016: stloc.2
IL_0017: ldloc.0
IL_0018: ldloc.1
IL_0019: ldloc.2
IL_001a: call ""string string.Concat(string, string, string, string)""
IL_001f: ret
}
");
verifier.VerifyIL("Program.<<Main>$>g__FiveComponents|0_3()", @"
{
// Code size 89 (0x59)
.maxstack 3
.locals init (string V_0, //s1
string V_1, //s2
string V_2, //s3
string V_3, //s4
string V_4, //s5
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
IL_0000: ldstr ""1""
IL_0005: stloc.0
IL_0006: ldstr ""2""
IL_000b: stloc.1
IL_000c: ldstr ""3""
IL_0011: stloc.2
IL_0012: ldstr ""4""
IL_0017: stloc.3
IL_0018: ldstr ""5""
IL_001d: stloc.s V_4
IL_001f: ldloca.s V_5
IL_0021: ldc.i4.0
IL_0022: ldc.i4.5
IL_0023: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0028: ldloca.s V_5
IL_002a: ldloc.0
IL_002b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_0030: ldloca.s V_5
IL_0032: ldloc.1
IL_0033: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_0038: ldloca.s V_5
IL_003a: ldloc.2
IL_003b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_0040: ldloca.s V_5
IL_0042: ldloc.3
IL_0043: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_0048: ldloca.s V_5
IL_004a: ldloc.s V_4
IL_004c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_0051: ldloca.s V_5
IL_0053: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0058: ret
}
");
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandler_OverloadsAndBoolReturns(
bool useDefaultParameters,
bool useBoolReturns,
bool constructorBoolArg,
[CombinatorialValues(@"$""base{a}{a,1}{a:X}{a,2:Y}""", @"$""base"" + $""{a}"" + $""{a,1}"" + $""{a:X}"" + $""{a,2:Y}""")] string expression)
{
var source =
@"int a = 1;
System.Console.WriteLine(" + expression + @");";
string interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters, useBoolReturns, constructorBoolArg: constructorBoolArg);
string expectedOutput = useDefaultParameters ?
@"base
value:1,alignment:0:format:
value:1,alignment:1:format:
value:1,alignment:0:format:X
value:1,alignment:2:format:Y" :
@"base
value:1
value:1,alignment:1
value:1:format:X
value:1,alignment:2:format:Y";
string expectedIl = getIl();
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: expectedOutput);
verifier.VerifyIL("<top-level-statements-entry-point>", expectedIl);
var comp1 = CreateCompilation(interpolatedStringBuilder);
foreach (var reference in new[] { comp1.EmitToImageReference(), comp1.ToMetadataReference() })
{
var comp2 = CreateCompilation(source, new[] { reference });
verifier = CompileAndVerify(comp2, expectedOutput: expectedOutput);
verifier.VerifyIL("<top-level-statements-entry-point>", expectedIl);
}
string getIl() => (useDefaultParameters, useBoolReturns, constructorBoolArg) switch
{
(useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: false) => @"
{
// Code size 80 (0x50)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.4
IL_0005: ldc.i4.4
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldstr ""base""
IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0017: ldloca.s V_1
IL_0019: ldloc.0
IL_001a: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_001f: ldloca.s V_1
IL_0021: ldloc.0
IL_0022: ldc.i4.1
IL_0023: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int)""
IL_0028: ldloca.s V_1
IL_002a: ldloc.0
IL_002b: ldstr ""X""
IL_0030: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)""
IL_0035: ldloca.s V_1
IL_0037: ldloc.0
IL_0038: ldc.i4.2
IL_0039: ldstr ""Y""
IL_003e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0043: ldloca.s V_1
IL_0045: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_004a: call ""void System.Console.WriteLine(string)""
IL_004f: ret
}
",
(useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: false) => @"
{
// Code size 84 (0x54)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.4
IL_0005: ldc.i4.4
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldstr ""base""
IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0017: ldloca.s V_1
IL_0019: ldloc.0
IL_001a: ldc.i4.0
IL_001b: ldnull
IL_001c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0021: ldloca.s V_1
IL_0023: ldloc.0
IL_0024: ldc.i4.1
IL_0025: ldnull
IL_0026: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_002b: ldloca.s V_1
IL_002d: ldloc.0
IL_002e: ldc.i4.0
IL_002f: ldstr ""X""
IL_0034: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0039: ldloca.s V_1
IL_003b: ldloc.0
IL_003c: ldc.i4.2
IL_003d: ldstr ""Y""
IL_0042: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0047: ldloca.s V_1
IL_0049: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_004e: call ""void System.Console.WriteLine(string)""
IL_0053: ret
}
",
(useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: false) => @"
{
// Code size 92 (0x5c)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.4
IL_0005: ldc.i4.4
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldstr ""base""
IL_0012: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0017: brfalse.s IL_004d
IL_0019: ldloca.s V_1
IL_001b: ldloc.0
IL_001c: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0021: brfalse.s IL_004d
IL_0023: ldloca.s V_1
IL_0025: ldloc.0
IL_0026: ldc.i4.1
IL_0027: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int)""
IL_002c: brfalse.s IL_004d
IL_002e: ldloca.s V_1
IL_0030: ldloc.0
IL_0031: ldstr ""X""
IL_0036: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)""
IL_003b: brfalse.s IL_004d
IL_003d: ldloca.s V_1
IL_003f: ldloc.0
IL_0040: ldc.i4.2
IL_0041: ldstr ""Y""
IL_0046: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_004b: br.s IL_004e
IL_004d: ldc.i4.0
IL_004e: pop
IL_004f: ldloca.s V_1
IL_0051: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0056: call ""void System.Console.WriteLine(string)""
IL_005b: ret
}
",
(useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: false) => @"
{
// Code size 96 (0x60)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.4
IL_0005: ldc.i4.4
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldstr ""base""
IL_0012: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0017: brfalse.s IL_0051
IL_0019: ldloca.s V_1
IL_001b: ldloc.0
IL_001c: ldc.i4.0
IL_001d: ldnull
IL_001e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0023: brfalse.s IL_0051
IL_0025: ldloca.s V_1
IL_0027: ldloc.0
IL_0028: ldc.i4.1
IL_0029: ldnull
IL_002a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_002f: brfalse.s IL_0051
IL_0031: ldloca.s V_1
IL_0033: ldloc.0
IL_0034: ldc.i4.0
IL_0035: ldstr ""X""
IL_003a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_003f: brfalse.s IL_0051
IL_0041: ldloca.s V_1
IL_0043: ldloc.0
IL_0044: ldc.i4.2
IL_0045: ldstr ""Y""
IL_004a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_004f: br.s IL_0052
IL_0051: ldc.i4.0
IL_0052: pop
IL_0053: ldloca.s V_1
IL_0055: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_005a: call ""void System.Console.WriteLine(string)""
IL_005f: ret
}
",
(useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: true) => @"
{
// Code size 84 (0x54)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.4
IL_0003: ldc.i4.4
IL_0004: ldloca.s V_2
IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_000b: stloc.1
IL_000c: ldloc.2
IL_000d: brfalse.s IL_0047
IL_000f: ldloca.s V_1
IL_0011: ldstr ""base""
IL_0016: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_001b: ldloca.s V_1
IL_001d: ldloc.0
IL_001e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0023: ldloca.s V_1
IL_0025: ldloc.0
IL_0026: ldc.i4.1
IL_0027: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int)""
IL_002c: ldloca.s V_1
IL_002e: ldloc.0
IL_002f: ldstr ""X""
IL_0034: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)""
IL_0039: ldloca.s V_1
IL_003b: ldloc.0
IL_003c: ldc.i4.2
IL_003d: ldstr ""Y""
IL_0042: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0047: ldloca.s V_1
IL_0049: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_004e: call ""void System.Console.WriteLine(string)""
IL_0053: ret
}
",
(useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: true) => @"
{
// Code size 88 (0x58)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.4
IL_0003: ldc.i4.4
IL_0004: ldloca.s V_2
IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_000b: stloc.1
IL_000c: ldloc.2
IL_000d: brfalse.s IL_004b
IL_000f: ldloca.s V_1
IL_0011: ldstr ""base""
IL_0016: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_001b: ldloca.s V_1
IL_001d: ldloc.0
IL_001e: ldc.i4.0
IL_001f: ldnull
IL_0020: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0025: ldloca.s V_1
IL_0027: ldloc.0
IL_0028: ldc.i4.1
IL_0029: ldnull
IL_002a: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_002f: ldloca.s V_1
IL_0031: ldloc.0
IL_0032: ldc.i4.0
IL_0033: ldstr ""X""
IL_0038: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_003d: ldloca.s V_1
IL_003f: ldloc.0
IL_0040: ldc.i4.2
IL_0041: ldstr ""Y""
IL_0046: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_004b: ldloca.s V_1
IL_004d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0052: call ""void System.Console.WriteLine(string)""
IL_0057: ret
}
",
(useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: true) => @"
{
// Code size 96 (0x60)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.4
IL_0003: ldc.i4.4
IL_0004: ldloca.s V_2
IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_000b: stloc.1
IL_000c: ldloc.2
IL_000d: brfalse.s IL_0051
IL_000f: ldloca.s V_1
IL_0011: ldstr ""base""
IL_0016: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_001b: brfalse.s IL_0051
IL_001d: ldloca.s V_1
IL_001f: ldloc.0
IL_0020: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0025: brfalse.s IL_0051
IL_0027: ldloca.s V_1
IL_0029: ldloc.0
IL_002a: ldc.i4.1
IL_002b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int)""
IL_0030: brfalse.s IL_0051
IL_0032: ldloca.s V_1
IL_0034: ldloc.0
IL_0035: ldstr ""X""
IL_003a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)""
IL_003f: brfalse.s IL_0051
IL_0041: ldloca.s V_1
IL_0043: ldloc.0
IL_0044: ldc.i4.2
IL_0045: ldstr ""Y""
IL_004a: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_004f: br.s IL_0052
IL_0051: ldc.i4.0
IL_0052: pop
IL_0053: ldloca.s V_1
IL_0055: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_005a: call ""void System.Console.WriteLine(string)""
IL_005f: ret
}
",
(useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: true) => @"
{
// Code size 100 (0x64)
.maxstack 4
.locals init (int V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.4
IL_0003: ldc.i4.4
IL_0004: ldloca.s V_2
IL_0006: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_000b: stloc.1
IL_000c: ldloc.2
IL_000d: brfalse.s IL_0055
IL_000f: ldloca.s V_1
IL_0011: ldstr ""base""
IL_0016: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_001b: brfalse.s IL_0055
IL_001d: ldloca.s V_1
IL_001f: ldloc.0
IL_0020: ldc.i4.0
IL_0021: ldnull
IL_0022: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0027: brfalse.s IL_0055
IL_0029: ldloca.s V_1
IL_002b: ldloc.0
IL_002c: ldc.i4.1
IL_002d: ldnull
IL_002e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0033: brfalse.s IL_0055
IL_0035: ldloca.s V_1
IL_0037: ldloc.0
IL_0038: ldc.i4.0
IL_0039: ldstr ""X""
IL_003e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0043: brfalse.s IL_0055
IL_0045: ldloca.s V_1
IL_0047: ldloc.0
IL_0048: ldc.i4.2
IL_0049: ldstr ""Y""
IL_004e: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, int, string)""
IL_0053: br.s IL_0056
IL_0055: ldc.i4.0
IL_0056: pop
IL_0057: ldloca.s V_1
IL_0059: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_005e: call ""void System.Console.WriteLine(string)""
IL_0063: ret
}
",
};
}
[Fact]
public void UseOfSpanInInterpolationHole_CSharp9()
{
var source = @"
using System;
ReadOnlySpan<char> span = stackalloc char[1];
Console.WriteLine($""{span}"");";
var comp = CreateCompilation(new[] { source, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false) }, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.NetCoreApp);
comp.VerifyDiagnostics(
// (4,22): error CS8773: Feature 'interpolated string handlers' is not available in C# 9.0. Please use language version 10.0 or greater.
// Console.WriteLine($"{span}");
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "span").WithArguments("interpolated string handlers", "10.0").WithLocation(4, 22)
);
}
[ConditionalTheory(typeof(MonoOrCoreClrOnly))]
[CombinatorialData]
public void UseOfSpanInInterpolationHole(bool useDefaultParameters, bool useBoolReturns, bool constructorBoolArg,
[CombinatorialValues(@"$""base{a}{a,1}{a:X}{a,2:Y}""", @"$""base"" + $""{a}"" + $""{a,1}"" + $""{a:X}"" + $""{a,2:Y}""")] string expression)
{
var source =
@"
using System;
ReadOnlySpan<char> a = ""1"";
System.Console.WriteLine(" + expression + ");";
string interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters, useBoolReturns, constructorBoolArg: constructorBoolArg);
string expectedOutput = useDefaultParameters ?
@"base
value:1,alignment:0:format:
value:1,alignment:1:format:
value:1,alignment:0:format:X
value:1,alignment:2:format:Y" :
@"base
value:1
value:1,alignment:1
value:1:format:X
value:1,alignment:2:format:Y";
string expectedIl = getIl();
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: expectedOutput, targetFramework: TargetFramework.Net50, parseOptions: TestOptions.Regular10);
verifier.VerifyIL("<top-level-statements-entry-point>", expectedIl);
var comp1 = CreateCompilation(interpolatedStringBuilder, targetFramework: TargetFramework.Net50);
foreach (var reference in new[] { comp1.EmitToImageReference(), comp1.ToMetadataReference() })
{
var comp2 = CreateCompilation(source, new[] { reference }, targetFramework: TargetFramework.Net50, parseOptions: TestOptions.Regular10);
verifier = CompileAndVerify(comp2, expectedOutput: expectedOutput);
verifier.VerifyIL("<top-level-statements-entry-point>", expectedIl);
}
string getIl() => (useDefaultParameters, useBoolReturns, constructorBoolArg) switch
{
(useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: false) => @"
{
// Code size 89 (0x59)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldloca.s V_1
IL_000d: ldc.i4.4
IL_000e: ldc.i4.4
IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0014: ldloca.s V_1
IL_0016: ldstr ""base""
IL_001b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0020: ldloca.s V_1
IL_0022: ldloc.0
IL_0023: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>)""
IL_0028: ldloca.s V_1
IL_002a: ldloc.0
IL_002b: ldc.i4.1
IL_002c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int)""
IL_0031: ldloca.s V_1
IL_0033: ldloc.0
IL_0034: ldstr ""X""
IL_0039: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, string)""
IL_003e: ldloca.s V_1
IL_0040: ldloc.0
IL_0041: ldc.i4.2
IL_0042: ldstr ""Y""
IL_0047: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_004c: ldloca.s V_1
IL_004e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0053: call ""void System.Console.WriteLine(string)""
IL_0058: ret
}
",
(useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: false) => @"
{
// Code size 93 (0x5d)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldloca.s V_1
IL_000d: ldc.i4.4
IL_000e: ldc.i4.4
IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0014: ldloca.s V_1
IL_0016: ldstr ""base""
IL_001b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0020: ldloca.s V_1
IL_0022: ldloc.0
IL_0023: ldc.i4.0
IL_0024: ldnull
IL_0025: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_002a: ldloca.s V_1
IL_002c: ldloc.0
IL_002d: ldc.i4.1
IL_002e: ldnull
IL_002f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0034: ldloca.s V_1
IL_0036: ldloc.0
IL_0037: ldc.i4.0
IL_0038: ldstr ""X""
IL_003d: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0042: ldloca.s V_1
IL_0044: ldloc.0
IL_0045: ldc.i4.2
IL_0046: ldstr ""Y""
IL_004b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0050: ldloca.s V_1
IL_0052: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0057: call ""void System.Console.WriteLine(string)""
IL_005c: ret
}
",
(useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: false) => @"
{
// Code size 101 (0x65)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldloca.s V_1
IL_000d: ldc.i4.4
IL_000e: ldc.i4.4
IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0014: ldloca.s V_1
IL_0016: ldstr ""base""
IL_001b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0020: brfalse.s IL_0056
IL_0022: ldloca.s V_1
IL_0024: ldloc.0
IL_0025: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>)""
IL_002a: brfalse.s IL_0056
IL_002c: ldloca.s V_1
IL_002e: ldloc.0
IL_002f: ldc.i4.1
IL_0030: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int)""
IL_0035: brfalse.s IL_0056
IL_0037: ldloca.s V_1
IL_0039: ldloc.0
IL_003a: ldstr ""X""
IL_003f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, string)""
IL_0044: brfalse.s IL_0056
IL_0046: ldloca.s V_1
IL_0048: ldloc.0
IL_0049: ldc.i4.2
IL_004a: ldstr ""Y""
IL_004f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0054: br.s IL_0057
IL_0056: ldc.i4.0
IL_0057: pop
IL_0058: ldloca.s V_1
IL_005a: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_005f: call ""void System.Console.WriteLine(string)""
IL_0064: ret
}
",
(useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: false) => @"
{
// Code size 105 (0x69)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldloca.s V_1
IL_000d: ldc.i4.4
IL_000e: ldc.i4.4
IL_000f: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0014: ldloca.s V_1
IL_0016: ldstr ""base""
IL_001b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0020: brfalse.s IL_005a
IL_0022: ldloca.s V_1
IL_0024: ldloc.0
IL_0025: ldc.i4.0
IL_0026: ldnull
IL_0027: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_002c: brfalse.s IL_005a
IL_002e: ldloca.s V_1
IL_0030: ldloc.0
IL_0031: ldc.i4.1
IL_0032: ldnull
IL_0033: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0038: brfalse.s IL_005a
IL_003a: ldloca.s V_1
IL_003c: ldloc.0
IL_003d: ldc.i4.0
IL_003e: ldstr ""X""
IL_0043: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0048: brfalse.s IL_005a
IL_004a: ldloca.s V_1
IL_004c: ldloc.0
IL_004d: ldc.i4.2
IL_004e: ldstr ""Y""
IL_0053: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0058: br.s IL_005b
IL_005a: ldc.i4.0
IL_005b: pop
IL_005c: ldloca.s V_1
IL_005e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0063: call ""void System.Console.WriteLine(string)""
IL_0068: ret
}
",
(useDefaultParameters: false, useBoolReturns: false, constructorBoolArg: true) => @"
{
// Code size 93 (0x5d)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldc.i4.4
IL_000c: ldc.i4.4
IL_000d: ldloca.s V_2
IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_0014: stloc.1
IL_0015: ldloc.2
IL_0016: brfalse.s IL_0050
IL_0018: ldloca.s V_1
IL_001a: ldstr ""base""
IL_001f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0024: ldloca.s V_1
IL_0026: ldloc.0
IL_0027: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>)""
IL_002c: ldloca.s V_1
IL_002e: ldloc.0
IL_002f: ldc.i4.1
IL_0030: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int)""
IL_0035: ldloca.s V_1
IL_0037: ldloc.0
IL_0038: ldstr ""X""
IL_003d: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, string)""
IL_0042: ldloca.s V_1
IL_0044: ldloc.0
IL_0045: ldc.i4.2
IL_0046: ldstr ""Y""
IL_004b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0050: ldloca.s V_1
IL_0052: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0057: call ""void System.Console.WriteLine(string)""
IL_005c: ret
}
",
(useDefaultParameters: false, useBoolReturns: true, constructorBoolArg: true) => @"
{
// Code size 105 (0x69)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldc.i4.4
IL_000c: ldc.i4.4
IL_000d: ldloca.s V_2
IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_0014: stloc.1
IL_0015: ldloc.2
IL_0016: brfalse.s IL_005a
IL_0018: ldloca.s V_1
IL_001a: ldstr ""base""
IL_001f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0024: brfalse.s IL_005a
IL_0026: ldloca.s V_1
IL_0028: ldloc.0
IL_0029: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>)""
IL_002e: brfalse.s IL_005a
IL_0030: ldloca.s V_1
IL_0032: ldloc.0
IL_0033: ldc.i4.1
IL_0034: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int)""
IL_0039: brfalse.s IL_005a
IL_003b: ldloca.s V_1
IL_003d: ldloc.0
IL_003e: ldstr ""X""
IL_0043: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, string)""
IL_0048: brfalse.s IL_005a
IL_004a: ldloca.s V_1
IL_004c: ldloc.0
IL_004d: ldc.i4.2
IL_004e: ldstr ""Y""
IL_0053: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0058: br.s IL_005b
IL_005a: ldc.i4.0
IL_005b: pop
IL_005c: ldloca.s V_1
IL_005e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0063: call ""void System.Console.WriteLine(string)""
IL_0068: ret
}
",
(useDefaultParameters: true, useBoolReturns: false, constructorBoolArg: true) => @"
{
// Code size 97 (0x61)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldc.i4.4
IL_000c: ldc.i4.4
IL_000d: ldloca.s V_2
IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_0014: stloc.1
IL_0015: ldloc.2
IL_0016: brfalse.s IL_0054
IL_0018: ldloca.s V_1
IL_001a: ldstr ""base""
IL_001f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0024: ldloca.s V_1
IL_0026: ldloc.0
IL_0027: ldc.i4.0
IL_0028: ldnull
IL_0029: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_002e: ldloca.s V_1
IL_0030: ldloc.0
IL_0031: ldc.i4.1
IL_0032: ldnull
IL_0033: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0038: ldloca.s V_1
IL_003a: ldloc.0
IL_003b: ldc.i4.0
IL_003c: ldstr ""X""
IL_0041: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0046: ldloca.s V_1
IL_0048: ldloc.0
IL_0049: ldc.i4.2
IL_004a: ldstr ""Y""
IL_004f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0054: ldloca.s V_1
IL_0056: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_005b: call ""void System.Console.WriteLine(string)""
IL_0060: ret
}
",
(useDefaultParameters: true, useBoolReturns: true, constructorBoolArg: true) => @"
{
// Code size 109 (0x6d)
.maxstack 4
.locals init (System.ReadOnlySpan<char> V_0, //a
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
bool V_2)
IL_0000: ldstr ""1""
IL_0005: call ""System.ReadOnlySpan<char> string.op_Implicit(string)""
IL_000a: stloc.0
IL_000b: ldc.i4.4
IL_000c: ldc.i4.4
IL_000d: ldloca.s V_2
IL_000f: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int, out bool)""
IL_0014: stloc.1
IL_0015: ldloc.2
IL_0016: brfalse.s IL_005e
IL_0018: ldloca.s V_1
IL_001a: ldstr ""base""
IL_001f: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0024: brfalse.s IL_005e
IL_0026: ldloca.s V_1
IL_0028: ldloc.0
IL_0029: ldc.i4.0
IL_002a: ldnull
IL_002b: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_0030: brfalse.s IL_005e
IL_0032: ldloca.s V_1
IL_0034: ldloc.0
IL_0035: ldc.i4.1
IL_0036: ldnull
IL_0037: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_003c: brfalse.s IL_005e
IL_003e: ldloca.s V_1
IL_0040: ldloc.0
IL_0041: ldc.i4.0
IL_0042: ldstr ""X""
IL_0047: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_004c: brfalse.s IL_005e
IL_004e: ldloca.s V_1
IL_0050: ldloc.0
IL_0051: ldc.i4.2
IL_0052: ldstr ""Y""
IL_0057: call ""bool System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>, int, string)""
IL_005c: br.s IL_005f
IL_005e: ldc.i4.0
IL_005f: pop
IL_0060: ldloca.s V_1
IL_0062: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0067: call ""void System.Console.WriteLine(string)""
IL_006c: ret
}
",
};
}
[Theory]
[InlineData(@"$""base{Throw()}{a = 2}""")]
[InlineData(@"$""base"" + $""{Throw()}"" + $""{a = 2}""")]
public void BoolReturns_ShortCircuit(string expression)
{
var source = @"
using System;
int a = 1;
Console.Write(" + expression + @");
Console.WriteLine(a);
string Throw() => throw new Exception();";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: true, returnExpression: "false");
CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"
base
1");
}
[Theory]
[CombinatorialData]
public void BoolOutParameter_ShortCircuits(bool useBoolReturns,
[CombinatorialValues(@"$""{Throw()}{a = 2}""", @"$""{Throw()}"" + $""{a = 2}""")] string expression)
{
var source = @"
using System;
int a = 1;
Console.WriteLine(a);
Console.WriteLine(" + expression + @");
Console.WriteLine(a);
string Throw() => throw new Exception();
";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: useBoolReturns, constructorBoolArg: true, constructorSuccessResult: false);
CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"
1
1");
}
[Theory]
[InlineData(@"$""base{await Hole()}""")]
[InlineData(@"$""base"" + $""{await Hole()}""")]
public void AwaitInHoles_UsesFormat(string expression)
{
var source = @"
using System;
using System.Threading.Tasks;
Console.WriteLine(" + expression + @");
Task<int> Hole() => Task.FromResult(1);";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"base1");
verifier.VerifyIL("Program.<<Main>$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", !expression.Contains("+") ? @"
{
// Code size 164 (0xa4)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_003e
IL_000a: call ""System.Threading.Tasks.Task<int> Program.<<Main>$>g__Hole|0_0()""
IL_000f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0014: stloc.2
IL_0015: ldloca.s V_2
IL_0017: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_001c: brtrue.s IL_005a
IL_001e: ldarg.0
IL_001f: ldc.i4.0
IL_0020: dup
IL_0021: stloc.0
IL_0022: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0027: ldarg.0
IL_0028: ldloc.2
IL_0029: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_002e: ldarg.0
IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0034: ldloca.s V_2
IL_0036: ldarg.0
IL_0037: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<<Main>$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<<Main>$>d__0)""
IL_003c: leave.s IL_00a3
IL_003e: ldarg.0
IL_003f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_0044: stloc.2
IL_0045: ldarg.0
IL_0046: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_004b: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0051: ldarg.0
IL_0052: ldc.i4.m1
IL_0053: dup
IL_0054: stloc.0
IL_0055: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_005a: ldloca.s V_2
IL_005c: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0061: stloc.1
IL_0062: ldstr ""base{0}""
IL_0067: ldloc.1
IL_0068: box ""int""
IL_006d: call ""string string.Format(string, object)""
IL_0072: call ""void System.Console.WriteLine(string)""
IL_0077: leave.s IL_0090
}
catch System.Exception
{
IL_0079: stloc.3
IL_007a: ldarg.0
IL_007b: ldc.i4.s -2
IL_007d: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0082: ldarg.0
IL_0083: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0088: ldloc.3
IL_0089: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_008e: leave.s IL_00a3
}
IL_0090: ldarg.0
IL_0091: ldc.i4.s -2
IL_0093: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0098: ldarg.0
IL_0099: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_009e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00a3: ret
}
"
: @"
{
// Code size 174 (0xae)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Exception V_3)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_003e
IL_000a: call ""System.Threading.Tasks.Task<int> Program.<<Main>$>g__Hole|0_0()""
IL_000f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0014: stloc.2
IL_0015: ldloca.s V_2
IL_0017: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_001c: brtrue.s IL_005a
IL_001e: ldarg.0
IL_001f: ldc.i4.0
IL_0020: dup
IL_0021: stloc.0
IL_0022: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0027: ldarg.0
IL_0028: ldloc.2
IL_0029: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_002e: ldarg.0
IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0034: ldloca.s V_2
IL_0036: ldarg.0
IL_0037: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<<Main>$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<<Main>$>d__0)""
IL_003c: leave.s IL_00ad
IL_003e: ldarg.0
IL_003f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_0044: stloc.2
IL_0045: ldarg.0
IL_0046: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_004b: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0051: ldarg.0
IL_0052: ldc.i4.m1
IL_0053: dup
IL_0054: stloc.0
IL_0055: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_005a: ldloca.s V_2
IL_005c: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0061: stloc.1
IL_0062: ldstr ""base""
IL_0067: ldstr ""{0}""
IL_006c: ldloc.1
IL_006d: box ""int""
IL_0072: call ""string string.Format(string, object)""
IL_0077: call ""string string.Concat(string, string)""
IL_007c: call ""void System.Console.WriteLine(string)""
IL_0081: leave.s IL_009a
}
catch System.Exception
{
IL_0083: stloc.3
IL_0084: ldarg.0
IL_0085: ldc.i4.s -2
IL_0087: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_008c: ldarg.0
IL_008d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0092: ldloc.3
IL_0093: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_0098: leave.s IL_00ad
}
IL_009a: ldarg.0
IL_009b: ldc.i4.s -2
IL_009d: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_00a2: ldarg.0
IL_00a3: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_00a8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00ad: ret
}");
}
[Theory]
[InlineData(@"$""base{hole}""")]
[InlineData(@"$""base"" + $""{hole}""")]
public void NoAwaitInHoles_UsesBuilder(string expression)
{
var source = @"
using System;
using System.Threading.Tasks;
var hole = await Hole();
Console.WriteLine(" + expression + @");
Task<int> Hole() => Task.FromResult(1);";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"
base
value:1");
verifier.VerifyIL("Program.<<Main>$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
// Code size 185 (0xb9)
.maxstack 3
.locals init (int V_0,
int V_1, //hole
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3,
System.Exception V_4)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_003e
IL_000a: call ""System.Threading.Tasks.Task<int> Program.<<Main>$>g__Hole|0_0()""
IL_000f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0014: stloc.2
IL_0015: ldloca.s V_2
IL_0017: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_001c: brtrue.s IL_005a
IL_001e: ldarg.0
IL_001f: ldc.i4.0
IL_0020: dup
IL_0021: stloc.0
IL_0022: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0027: ldarg.0
IL_0028: ldloc.2
IL_0029: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_002e: ldarg.0
IL_002f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0034: ldloca.s V_2
IL_0036: ldarg.0
IL_0037: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<<Main>$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<<Main>$>d__0)""
IL_003c: leave.s IL_00b8
IL_003e: ldarg.0
IL_003f: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_0044: stloc.2
IL_0045: ldarg.0
IL_0046: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_004b: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0051: ldarg.0
IL_0052: ldc.i4.m1
IL_0053: dup
IL_0054: stloc.0
IL_0055: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_005a: ldloca.s V_2
IL_005c: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0061: stloc.1
IL_0062: ldc.i4.4
IL_0063: ldc.i4.1
IL_0064: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0069: stloc.3
IL_006a: ldloca.s V_3
IL_006c: ldstr ""base""
IL_0071: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0076: ldloca.s V_3
IL_0078: ldloc.1
IL_0079: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_007e: ldloca.s V_3
IL_0080: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0085: call ""void System.Console.WriteLine(string)""
IL_008a: leave.s IL_00a5
}
catch System.Exception
{
IL_008c: stloc.s V_4
IL_008e: ldarg.0
IL_008f: ldc.i4.s -2
IL_0091: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0096: ldarg.0
IL_0097: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_009c: ldloc.s V_4
IL_009e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00a3: leave.s IL_00b8
}
IL_00a5: ldarg.0
IL_00a6: ldc.i4.s -2
IL_00a8: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_00ad: ldarg.0
IL_00ae: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_00b3: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00b8: ret
}
");
}
[Theory]
[InlineData(@"$""base{hole}""")]
[InlineData(@"$""base"" + $""{hole}""")]
public void NoAwaitInHoles_AwaitInExpression_UsesBuilder(string expression)
{
var source = @"
using System;
using System.Threading.Tasks;
var hole = 2;
Test(await M(1), " + expression + @", await M(3));
void Test(int i1, string s, int i2) => Console.WriteLine(s);
Task<int> M(int i)
{
Console.WriteLine(i);
return Task.FromResult(1);
}";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"
1
3
base
value:2");
verifier.VerifyIL("Program.<<Main>$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
// Code size 328 (0x148)
.maxstack 3
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3,
System.Exception V_4)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0050
IL_000a: ldloc.0
IL_000b: ldc.i4.1
IL_000c: beq IL_00dc
IL_0011: ldarg.0
IL_0012: ldc.i4.2
IL_0013: stfld ""int Program.<<Main>$>d__0.<hole>5__2""
IL_0018: ldc.i4.1
IL_0019: call ""System.Threading.Tasks.Task<int> Program.<<Main>$>g__M|0_1(int)""
IL_001e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0023: stloc.2
IL_0024: ldloca.s V_2
IL_0026: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_002b: brtrue.s IL_006c
IL_002d: ldarg.0
IL_002e: ldc.i4.0
IL_002f: dup
IL_0030: stloc.0
IL_0031: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0036: ldarg.0
IL_0037: ldloc.2
IL_0038: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_003d: ldarg.0
IL_003e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0043: ldloca.s V_2
IL_0045: ldarg.0
IL_0046: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<<Main>$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<<Main>$>d__0)""
IL_004b: leave IL_0147
IL_0050: ldarg.0
IL_0051: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_0056: stloc.2
IL_0057: ldarg.0
IL_0058: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_005d: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0063: ldarg.0
IL_0064: ldc.i4.m1
IL_0065: dup
IL_0066: stloc.0
IL_0067: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_006c: ldarg.0
IL_006d: ldloca.s V_2
IL_006f: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0074: stfld ""int Program.<<Main>$>d__0.<>7__wrap2""
IL_0079: ldarg.0
IL_007a: ldc.i4.4
IL_007b: ldc.i4.1
IL_007c: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0081: stloc.3
IL_0082: ldloca.s V_3
IL_0084: ldstr ""base""
IL_0089: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_008e: ldloca.s V_3
IL_0090: ldarg.0
IL_0091: ldfld ""int Program.<<Main>$>d__0.<hole>5__2""
IL_0096: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_009b: ldloca.s V_3
IL_009d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_00a2: stfld ""string Program.<<Main>$>d__0.<>7__wrap3""
IL_00a7: ldc.i4.3
IL_00a8: call ""System.Threading.Tasks.Task<int> Program.<<Main>$>g__M|0_1(int)""
IL_00ad: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_00b2: stloc.2
IL_00b3: ldloca.s V_2
IL_00b5: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_00ba: brtrue.s IL_00f8
IL_00bc: ldarg.0
IL_00bd: ldc.i4.1
IL_00be: dup
IL_00bf: stloc.0
IL_00c0: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_00c5: ldarg.0
IL_00c6: ldloc.2
IL_00c7: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_00cc: ldarg.0
IL_00cd: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_00d2: ldloca.s V_2
IL_00d4: ldarg.0
IL_00d5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<<Main>$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<<Main>$>d__0)""
IL_00da: leave.s IL_0147
IL_00dc: ldarg.0
IL_00dd: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_00e2: stloc.2
IL_00e3: ldarg.0
IL_00e4: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_00e9: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_00ef: ldarg.0
IL_00f0: ldc.i4.m1
IL_00f1: dup
IL_00f2: stloc.0
IL_00f3: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_00f8: ldloca.s V_2
IL_00fa: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_00ff: stloc.1
IL_0100: ldarg.0
IL_0101: ldfld ""int Program.<<Main>$>d__0.<>7__wrap2""
IL_0106: ldarg.0
IL_0107: ldfld ""string Program.<<Main>$>d__0.<>7__wrap3""
IL_010c: ldloc.1
IL_010d: call ""void Program.<<Main>$>g__Test|0_0(int, string, int)""
IL_0112: ldarg.0
IL_0113: ldnull
IL_0114: stfld ""string Program.<<Main>$>d__0.<>7__wrap3""
IL_0119: leave.s IL_0134
}
catch System.Exception
{
IL_011b: stloc.s V_4
IL_011d: ldarg.0
IL_011e: ldc.i4.s -2
IL_0120: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0125: ldarg.0
IL_0126: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_012b: ldloc.s V_4
IL_012d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_0132: leave.s IL_0147
}
IL_0134: ldarg.0
IL_0135: ldc.i4.s -2
IL_0137: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_013c: ldarg.0
IL_013d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0142: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_0147: ret
}
");
}
[Theory, WorkItem(55609, "https://github.com/dotnet/roslyn/issues/55609")]
[InlineData(@"$""base{hole}""")]
[InlineData(@"$""base"" + $""{hole}""")]
public void DynamicInHoles_UsesFormat(string expression)
{
var source = @"
using System;
using System.Threading.Tasks;
dynamic hole = 1;
Console.WriteLine(" + expression + @");
";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerifyWithCSharp(new[] { source, interpolatedStringBuilder }, expectedOutput: @"base1");
verifier.VerifyIL("<top-level-statements-entry-point>", expression.Contains('+')
? @"
{
// Code size 34 (0x22)
.maxstack 3
.locals init (object V_0) //hole
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.0
IL_0007: ldstr ""base""
IL_000c: ldstr ""{0}""
IL_0011: ldloc.0
IL_0012: call ""string string.Format(string, object)""
IL_0017: call ""string string.Concat(string, string)""
IL_001c: call ""void System.Console.WriteLine(string)""
IL_0021: ret
}
"
: @"
{
// Code size 24 (0x18)
.maxstack 2
.locals init (object V_0) //hole
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.0
IL_0007: ldstr ""base{0}""
IL_000c: ldloc.0
IL_000d: call ""string string.Format(string, object)""
IL_0012: call ""void System.Console.WriteLine(string)""
IL_0017: ret
}
");
}
[Theory, WorkItem(55609, "https://github.com/dotnet/roslyn/issues/55609")]
[InlineData(@"$""{hole}base""")]
[InlineData(@"$""{hole}"" + $""base""")]
public void DynamicInHoles_UsesFormat2(string expression)
{
var source = @"
using System;
using System.Threading.Tasks;
dynamic hole = 1;
Console.WriteLine(" + expression + @");
";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerifyWithCSharp(new[] { source, interpolatedStringBuilder }, expectedOutput: @"1base");
verifier.VerifyIL("<top-level-statements-entry-point>", expression.Contains('+')
? @"
{
// Code size 34 (0x22)
.maxstack 2
.locals init (object V_0) //hole
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.0
IL_0007: ldstr ""{0}""
IL_000c: ldloc.0
IL_000d: call ""string string.Format(string, object)""
IL_0012: ldstr ""base""
IL_0017: call ""string string.Concat(string, string)""
IL_001c: call ""void System.Console.WriteLine(string)""
IL_0021: ret
}
"
: @"
{
// Code size 24 (0x18)
.maxstack 2
.locals init (object V_0) //hole
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.0
IL_0007: ldstr ""{0}base""
IL_000c: ldloc.0
IL_000d: call ""string string.Format(string, object)""
IL_0012: call ""void System.Console.WriteLine(string)""
IL_0017: ret
}
");
}
[Fact]
public void ImplicitConversionsInConstructor()
{
var code = @"
using System.Runtime.CompilerServices;
CustomHandler c = $"""";
[InterpolatedStringHandler]
struct CustomHandler
{
public CustomHandler(object literalLength, object formattedCount) {}
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerAttribute });
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 19 (0x13)
.maxstack 2
IL_0000: ldc.i4.0
IL_0001: box ""int""
IL_0006: ldc.i4.0
IL_0007: box ""int""
IL_000c: newobj ""CustomHandler..ctor(object, object)""
IL_0011: pop
IL_0012: ret
}
");
}
[Fact]
public void MissingCreate_01()
{
var code = @"_ = $""{(object)1}"";";
var interpolatedStringBuilder = @"
namespace System.Runtime.CompilerServices
{
public ref struct DefaultInterpolatedStringHandler
{
public override string ToString() => throw null;
public void Dispose() => throw null;
public void AppendLiteral(string value) => throw null;
public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null;
}
}
";
var comp = CreateCompilation(new[] { code, interpolatedStringBuilder });
comp.VerifyDiagnostics(
// (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 2 arguments
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""{(object)1}""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "2").WithLocation(1, 5),
// (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 3 arguments
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""{(object)1}""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "3").WithLocation(1, 5)
);
}
[Fact]
public void MissingCreate_02()
{
var code = @"_ = $""{(object)1}"";";
var interpolatedStringBuilder = @"
namespace System.Runtime.CompilerServices
{
public ref struct DefaultInterpolatedStringHandler
{
public DefaultInterpolatedStringHandler(int literalLength) => throw null;
public override string ToString() => throw null;
public void Dispose() => throw null;
public void AppendLiteral(string value) => throw null;
public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null;
}
}
";
var comp = CreateCompilation(new[] { code, interpolatedStringBuilder });
comp.VerifyDiagnostics(
// (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 2 arguments
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""{(object)1}""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "2").WithLocation(1, 5),
// (1,5): error CS1729: 'DefaultInterpolatedStringHandler' does not contain a constructor that takes 3 arguments
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""{(object)1}""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "3").WithLocation(1, 5)
);
}
[Fact]
public void MissingCreate_03()
{
var code = @"_ = $""{(object)1}"";";
var interpolatedStringBuilder = @"
namespace System.Runtime.CompilerServices
{
public ref struct DefaultInterpolatedStringHandler
{
public DefaultInterpolatedStringHandler(ref int literalLength, int formattedCount) => throw null;
public override string ToString() => throw null;
public void Dispose() => throw null;
public void AppendLiteral(string value) => throw null;
public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null;
}
}
";
var comp = CreateCompilation(new[] { code, interpolatedStringBuilder });
comp.VerifyDiagnostics(
// (1,5): error CS1620: Argument 1 must be passed with the 'ref' keyword
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_BadArgRef, @"$""{(object)1}""").WithArguments("1", "ref").WithLocation(1, 5)
);
}
[Theory]
[InlineData(null)]
[InlineData("public string ToStringAndClear(int literalLength) => throw null;")]
[InlineData("public void ToStringAndClear() => throw null;")]
[InlineData("public static string ToStringAndClear() => throw null;")]
public void MissingWellKnownMethod_ToStringAndClear(string toStringAndClearMethod)
{
var code = @"_ = $""{(object)1}"";";
var interpolatedStringBuilder = @"
namespace System.Runtime.CompilerServices
{
public ref struct DefaultInterpolatedStringHandler
{
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null;
" + toStringAndClearMethod + @"
public override string ToString() => throw null;
public void AppendLiteral(string value) => throw null;
public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null;
}
}
";
var comp = CreateCompilation(new[] { code, interpolatedStringBuilder });
comp.VerifyDiagnostics();
comp.VerifyEmitDiagnostics(
// (1,5): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear'
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"$""{(object)1}""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "ToStringAndClear").WithLocation(1, 5)
);
}
[Fact]
public void ObsoleteCreateMethod()
{
var code = @"_ = $""{(object)1}"";";
var interpolatedStringBuilder = @"
namespace System.Runtime.CompilerServices
{
public ref struct DefaultInterpolatedStringHandler
{
[System.Obsolete(""Constructor is obsolete"", error: true)]
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null;
public void Dispose() => throw null;
public override string ToString() => throw null;
public void AppendLiteral(string value) => throw null;
public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null;
}
}
";
var comp = CreateCompilation(new[] { code, interpolatedStringBuilder });
comp.VerifyDiagnostics(
// (1,5): error CS0619: 'DefaultInterpolatedStringHandler.DefaultInterpolatedStringHandler(int, int)' is obsolete: 'Constructor is obsolete'
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, @"$""{(object)1}""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.DefaultInterpolatedStringHandler(int, int)", "Constructor is obsolete").WithLocation(1, 5)
);
}
[Fact]
public void ObsoleteAppendLiteralMethod()
{
var code = @"_ = $""base{(object)1}"";";
var interpolatedStringBuilder = @"
namespace System.Runtime.CompilerServices
{
public ref struct DefaultInterpolatedStringHandler
{
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null;
public void Dispose() => throw null;
public override string ToString() => throw null;
[System.Obsolete(""AppendLiteral is obsolete"", error: true)]
public void AppendLiteral(string value) => throw null;
public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null;
}
}
";
var comp = CreateCompilation(new[] { code, interpolatedStringBuilder });
comp.VerifyDiagnostics(
// (1,7): error CS0619: 'DefaultInterpolatedStringHandler.AppendLiteral(string)' is obsolete: 'AppendLiteral is obsolete'
// _ = $"base{(object)1}";
Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "base").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "AppendLiteral is obsolete").WithLocation(1, 7)
);
}
[Fact]
public void ObsoleteAppendFormattedMethod()
{
var code = @"_ = $""base{(object)1}"";";
var interpolatedStringBuilder = @"
namespace System.Runtime.CompilerServices
{
public ref struct DefaultInterpolatedStringHandler
{
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) => throw null;
public void Dispose() => throw null;
public override string ToString() => throw null;
public void AppendLiteral(string value) => throw null;
[System.Obsolete(""AppendFormatted is obsolete"", error: true)]
public void AppendFormatted<T>(T hole, int alignment = 0, string format = null) => throw null;
}
}
";
var comp = CreateCompilation(new[] { code, interpolatedStringBuilder });
comp.VerifyDiagnostics(
// (1,11): error CS0619: 'DefaultInterpolatedStringHandler.AppendFormatted<T>(T, int, string)' is obsolete: 'AppendFormatted is obsolete'
// _ = $"base{(object)1}";
Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "{(object)1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<T>(T, int, string)", "AppendFormatted is obsolete").WithLocation(1, 11)
);
}
private const string UnmanagedCallersOnlyIl = @"
.class public auto ansi sealed beforefieldinit System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute extends [mscorlib]System.Attribute
{
.custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = (
01 00 40 00 00 00 01 00 54 02 09 49 6e 68 65 72
69 74 65 64 00
)
.field public class [mscorlib]System.Type[] CallConvs
.field public string EntryPoint
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
ldarg.0
call instance void [mscorlib]System.Attribute::.ctor()
ret
}
}";
[Fact]
public void UnmanagedCallersOnlyAppendFormattedMethod()
{
var code = @"_ = $""{(object)1}"";";
var interpolatedStringBuilder = @"
.class public sequential ansi sealed beforefieldinit System.Runtime.CompilerServices.DefaultInterpolatedStringHandler
extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string, bool) = (
01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d
62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65
73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72
74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73
69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70
69 6c 65 72 2e 01 00 00
)
.pack 0
.size 1
.method public hidebysig specialname rtspecialname
instance void .ctor (
int32 literalLength,
int32 formattedCount
) cil managed
{
ldnull
throw
}
.method public hidebysig
instance void Dispose () cil managed
{
ldnull
throw
}
.method public hidebysig virtual
instance string ToString () cil managed
{
ldnull
throw
}
.method public hidebysig
instance void AppendLiteral (
string 'value'
) cil managed
{
ldnull
throw
}
.method public hidebysig
instance void AppendFormatted<T> (
!!T hole,
[opt] int32 'alignment',
[opt] string format
) cil managed
{
.custom instance void System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = (
01 00 00 00
)
.param [2] = int32(0)
.param [3] = nullref
ldnull
throw
}
}
";
var comp = CreateCompilationWithIL(code, ilSource: interpolatedStringBuilder + UnmanagedCallersOnlyIl);
comp.VerifyDiagnostics(
// (1,7): error CS0570: 'DefaultInterpolatedStringHandler.AppendFormatted<T>(T, int, string)' is not supported by the language
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_BindToBogus, "{(object)1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<T>(T, int, string)").WithLocation(1, 7)
);
}
[Fact]
public void UnmanagedCallersOnlyToStringMethod()
{
var code = @"_ = $""{(object)1}"";";
var interpolatedStringBuilder = @"
.class public sequential ansi sealed beforefieldinit System.Runtime.CompilerServices.DefaultInterpolatedStringHandler
extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
01 00 00 00
)
.custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string, bool) = (
01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d
62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65
73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72
74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73
69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70
69 6c 65 72 2e 01 00 00
)
.pack 0
.size 1
.method public hidebysig specialname rtspecialname
instance void .ctor (
int32 literalLength,
int32 formattedCount
) cil managed
{
ldnull
throw
}
.method public hidebysig instance string ToStringAndClear () cil managed
{
.custom instance void System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = (
01 00 00 00
)
ldnull
throw
}
.method public hidebysig
instance void AppendLiteral (
string 'value'
) cil managed
{
ldnull
throw
}
.method public hidebysig
instance void AppendFormatted<T> (
!!T hole,
[opt] int32 'alignment',
[opt] string format
) cil managed
{
.param [2] = int32(0)
.param [3] = nullref
ldnull
throw
}
}
";
var comp = CreateCompilationWithIL(code, ilSource: interpolatedStringBuilder + UnmanagedCallersOnlyIl);
comp.VerifyDiagnostics();
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'DefaultInterpolatedStringHandler.ToStringAndClear()' is not supported by the language
// _ = $"{(object)1}";
Diagnostic(ErrorCode.ERR_BindToBogus, @"$""{(object)1}""").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()").WithLocation(1, 5)
);
}
[Theory]
[InlineData(@"$""{i}{s}""")]
[InlineData(@"$""{i}"" + $""{s}""")]
public void UnsupportedArgumentType(string expression)
{
var source = @"
unsafe
{
int* i = null;
var s = new S();
_ = " + expression + @";
}
ref struct S
{
}";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: true, useBoolReturns: false);
var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, options: TestOptions.UnsafeReleaseExe, targetFramework: TargetFramework.NetCoreApp);
comp.VerifyDiagnostics(
// 0.cs(6,11): error CS0306: The type 'int*' may not be used as a type argument
// _ = $"{i}{s}";
Diagnostic(ErrorCode.ERR_BadTypeArgument, "{i}").WithArguments("int*").WithLocation(6, 11),
// 0.cs(6,14): error CS9244: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'DefaultInterpolatedStringHandler.AppendFormatted<T>(T, int, string)'
// _ = $"{i}{s}";
Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "{s}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<T>(T, int, string)", "T", "S").WithLocation(6, 5 + expression.Length)
);
}
[Theory]
[InlineData(@"$""{b switch { true => 1, false => null }}{(!b ? null : 2)}{default}{null}""")]
[InlineData(@"$""{b switch { true => 1, false => null }}"" + $""{(!b ? null : 2)}"" + $""{default}"" + $""{null}""")]
public void TargetTypedInterpolationHoles(string expression)
{
var source = @"
bool b = true;
System.Console.WriteLine(" + expression + @");";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"
value:1
value:2
value:
value:");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 81 (0x51)
.maxstack 3
.locals init (bool V_0, //b
object V_1,
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_2
IL_0004: ldc.i4.0
IL_0005: ldc.i4.4
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloc.0
IL_000c: brfalse.s IL_0017
IL_000e: ldc.i4.1
IL_000f: box ""int""
IL_0014: stloc.1
IL_0015: br.s IL_0019
IL_0017: ldnull
IL_0018: stloc.1
IL_0019: ldloca.s V_2
IL_001b: ldloc.1
IL_001c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)""
IL_0021: ldloca.s V_2
IL_0023: ldloc.0
IL_0024: brfalse.s IL_002e
IL_0026: ldc.i4.2
IL_0027: box ""int""
IL_002c: br.s IL_002f
IL_002e: ldnull
IL_002f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)""
IL_0034: ldloca.s V_2
IL_0036: ldnull
IL_0037: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_003c: ldloca.s V_2
IL_003e: ldnull
IL_003f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_0044: ldloca.s V_2
IL_0046: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_004b: call ""void System.Console.WriteLine(string)""
IL_0050: ret
}
");
}
[Theory]
[InlineData(@"$""{(null, default)}{new()}""")]
[InlineData(@"$""{(null, default)}"" + $""{new()}""")]
public void TargetTypedInterpolationHoles_Errors(string expression)
{
var source = @"System.Console.WriteLine(" + expression + @");";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, parseOptions: TestOptions.Regular9);
comp.VerifyDiagnostics(
// (1,29): error CS1503: Argument 1: cannot convert from '(<null>, default)' to 'object'
// System.Console.WriteLine($"{(null, default)}{new()}");
Diagnostic(ErrorCode.ERR_BadArgType, "(null, default)").WithArguments("1", "(<null>, default)", "object").WithLocation(1, 29),
// (1,29): error CS8773: Feature 'interpolated string handlers' is not available in C# 9.0. Please use language version 10.0 or greater.
// System.Console.WriteLine($"{(null, default)}{new()}");
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "(null, default)").WithArguments("interpolated string handlers", "10.0").WithLocation(1, 29),
// (1,46): error CS1729: 'string' does not contain a constructor that takes 0 arguments
// System.Console.WriteLine($"{(null, default)}{new()}");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "new()").WithArguments("string", "0").WithLocation(1, 19 + expression.Length)
);
}
[Fact]
public void RefTernary()
{
var source = @"
bool b = true;
int i = 1;
System.Console.WriteLine($""{(!b ? ref i : ref i)}"");";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"value:1");
}
[Fact]
public void NestedInterpolatedStrings_01()
{
var source = @"
int i = 1;
System.Console.WriteLine($""{$""{i}""}"");";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"value:1");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 32 (0x20)
.maxstack 3
.locals init (int V_0, //i
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.0
IL_0005: ldc.i4.1
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldloc.0
IL_000e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0013: ldloca.s V_1
IL_0015: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_001a: call ""void System.Console.WriteLine(string)""
IL_001f: ret
}
");
}
[Theory]
[InlineData(@"$""{$""{i1}""}{$""{i2}""}""")]
[InlineData(@"$""{$""{i1}""}"" + $""{$""{i2}""}""")]
public void NestedInterpolatedStrings_02(string expression)
{
var source = @"
int i1 = 1;
int i2 = 2;
System.Console.WriteLine(" + expression + @");";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"
value:1
value:2");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 63 (0x3f)
.maxstack 4
.locals init (int V_0, //i1
int V_1, //i2
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.2
IL_0003: stloc.1
IL_0004: ldloca.s V_2
IL_0006: ldc.i4.0
IL_0007: ldc.i4.1
IL_0008: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000d: ldloca.s V_2
IL_000f: ldloc.0
IL_0010: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0015: ldloca.s V_2
IL_0017: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_001c: ldloca.s V_2
IL_001e: ldc.i4.0
IL_001f: ldc.i4.1
IL_0020: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0025: ldloca.s V_2
IL_0027: ldloc.1
IL_0028: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_002d: ldloca.s V_2
IL_002f: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0034: call ""string string.Concat(string, string)""
IL_0039: call ""void System.Console.WriteLine(string)""
IL_003e: ret
}
");
}
[Fact]
public void ExceptionFilter_01()
{
var source = @"
using System;
int i = 1;
try
{
Console.WriteLine(""Starting try"");
throw new MyException { Prop = i };
}
// Test DefaultInterpolatedStringHandler renders specially, so we're actually comparing to ""value:Prop"" plus some whitespace
catch (MyException e) when (e.ToString() == $""{i}"".Trim())
{
Console.WriteLine(""Caught"");
}
class MyException : Exception
{
public int Prop { get; set; }
public override string ToString() => ""value:"" + Prop.ToString();
}";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"
Starting try
Caught");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 95 (0x5f)
.maxstack 4
.locals init (int V_0, //i
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
.try
{
IL_0002: ldstr ""Starting try""
IL_0007: call ""void System.Console.WriteLine(string)""
IL_000c: newobj ""MyException..ctor()""
IL_0011: dup
IL_0012: ldloc.0
IL_0013: callvirt ""void MyException.Prop.set""
IL_0018: throw
}
filter
{
IL_0019: isinst ""MyException""
IL_001e: dup
IL_001f: brtrue.s IL_0025
IL_0021: pop
IL_0022: ldc.i4.0
IL_0023: br.s IL_004f
IL_0025: callvirt ""string object.ToString()""
IL_002a: ldloca.s V_1
IL_002c: ldc.i4.0
IL_002d: ldc.i4.1
IL_002e: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0033: ldloca.s V_1
IL_0035: ldloc.0
IL_0036: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_003b: ldloca.s V_1
IL_003d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0042: callvirt ""string string.Trim()""
IL_0047: call ""bool string.op_Equality(string, string)""
IL_004c: ldc.i4.0
IL_004d: cgt.un
IL_004f: endfilter
} // end filter
{ // handler
IL_0051: pop
IL_0052: ldstr ""Caught""
IL_0057: call ""void System.Console.WriteLine(string)""
IL_005c: leave.s IL_005e
}
IL_005e: ret
}
");
}
[ConditionalFact(typeof(MonoOrCoreClrOnly), typeof(NoIOperationValidation))]
public void ExceptionFilter_02()
{
var source = @"
using System;
Span<char> s = new char[] { 'i' };
try
{
Console.WriteLine(""Starting try"");
throw new MyException { Prop = s.ToString() };
}
// Test DefaultInterpolatedStringHandler renders specially, so we're actually comparing to ""value:Prop"" plus some whitespace
catch (MyException e) when (e.ToString() == $""{(ReadOnlySpan<char>)s}"".Trim())
{
Console.WriteLine(""Caught"");
}
class MyException : Exception
{
public string Prop { get; set; }
public override string ToString() => ""value:"" + Prop.ToString();
}";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false);
var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, targetFramework: TargetFramework.NetCoreApp, expectedOutput: @"
Starting try
Caught");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 127 (0x7f)
.maxstack 4
.locals init (System.Span<char> V_0, //s
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: newarr ""char""
IL_0006: dup
IL_0007: ldc.i4.0
IL_0008: ldc.i4.s 105
IL_000a: stelem.i2
IL_000b: call ""System.Span<char> System.Span<char>.op_Implicit(char[])""
IL_0010: stloc.0
.try
{
IL_0011: ldstr ""Starting try""
IL_0016: call ""void System.Console.WriteLine(string)""
IL_001b: newobj ""MyException..ctor()""
IL_0020: dup
IL_0021: ldloca.s V_0
IL_0023: constrained. ""System.Span<char>""
IL_0029: callvirt ""string object.ToString()""
IL_002e: callvirt ""void MyException.Prop.set""
IL_0033: throw
}
filter
{
IL_0034: isinst ""MyException""
IL_0039: dup
IL_003a: brtrue.s IL_0040
IL_003c: pop
IL_003d: ldc.i4.0
IL_003e: br.s IL_006f
IL_0040: callvirt ""string object.ToString()""
IL_0045: ldloca.s V_1
IL_0047: ldc.i4.0
IL_0048: ldc.i4.1
IL_0049: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_004e: ldloca.s V_1
IL_0050: ldloc.0
IL_0051: call ""System.ReadOnlySpan<char> System.Span<char>.op_Implicit(System.Span<char>)""
IL_0056: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>)""
IL_005b: ldloca.s V_1
IL_005d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0062: callvirt ""string string.Trim()""
IL_0067: call ""bool string.op_Equality(string, string)""
IL_006c: ldc.i4.0
IL_006d: cgt.un
IL_006f: endfilter
} // end filter
{ // handler
IL_0071: pop
IL_0072: ldstr ""Caught""
IL_0077: call ""void System.Console.WriteLine(string)""
IL_007c: leave.s IL_007e
}
IL_007e: ret
}
");
}
[ConditionalTheory(typeof(MonoOrCoreClrOnly), typeof(NoIOperationValidation))]
[InlineData(@"$""{s}{c}""")]
[InlineData(@"$""{s}"" + $""{c}""")]
public void ImplicitUserDefinedConversionInHole(string expression)
{
var source = @"
using System;
S s = default;
C c = new C();
Console.WriteLine(" + expression + @");
ref struct S
{
public static implicit operator ReadOnlySpan<char>(S s) => ""S converted"";
}
class C
{
public static implicit operator ReadOnlySpan<char>(C s) => ""C converted"";
}";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false);
var comp = CreateCompilation(new[] { source, interpolatedStringBuilder },
targetFramework: TargetFramework.NetCoreApp);
// ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator.
var verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: @"
value:S converted
value:C");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 57 (0x39)
.maxstack 3
.locals init (S V_0, //s
C V_1, //c
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2)
IL_0000: ldloca.s V_0
IL_0002: initobj ""S""
IL_0008: newobj ""C..ctor()""
IL_000d: stloc.1
IL_000e: ldloca.s V_2
IL_0010: ldc.i4.0
IL_0011: ldc.i4.2
IL_0012: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0017: ldloca.s V_2
IL_0019: ldloc.0
IL_001a: call ""System.ReadOnlySpan<char> S.op_Implicit(S)""
IL_001f: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(System.ReadOnlySpan<char>)""
IL_0024: ldloca.s V_2
IL_0026: ldloc.1
IL_0027: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<C>(C)""
IL_002c: ldloca.s V_2
IL_002e: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0033: call ""void System.Console.WriteLine(string)""
IL_0038: ret
}
");
}
[Fact]
public void ExplicitUserDefinedConversionInHole()
{
var source = @"
using System;
S s = default;
Console.WriteLine($""{s}"");
ref struct S
{
public static explicit operator ReadOnlySpan<char>(S s) => ""S converted"";
}
";
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: true, useDefaultParameters: false, useBoolReturns: false);
var comp = CreateCompilation(new[] { source, interpolatedStringBuilder }, targetFramework: TargetFramework.NetCoreApp);
comp.VerifyDiagnostics(
// 0.cs(5,21): error CS9244: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'DefaultInterpolatedStringHandler.AppendFormatted<T>(T)'
// Console.WriteLine($"{s}");
Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "{s}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<T>(T)", "T", "S").WithLocation(5, 21)
);
}
[Theory]
[InlineData(@"$""Text{1}""")]
[InlineData(@"$""Text"" + $""{1}""")]
public void ImplicitUserDefinedConversionInLiteral(string expression)
{
var source = @"
using System;
Console.WriteLine(" + expression + @");
public struct CustomStruct
{
public static implicit operator CustomStruct(string s) => new CustomStruct { S = s };
public string S { get; set; }
public override string ToString() => ""literal:"" + S;
}
namespace System.Runtime.CompilerServices
{
using System.Text;
public ref struct DefaultInterpolatedStringHandler
{
private readonly StringBuilder _builder;
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount)
{
_builder = new StringBuilder();
}
public string ToStringAndClear() => _builder.ToString();
public void AppendLiteral(CustomStruct s) => _builder.AppendLine(s.ToString());
public void AppendFormatted(object o) => _builder.AppendLine(""value:"" + o.ToString());
}
}";
var verifier = CompileAndVerify(source, expectedOutput: @"
literal:Text
value:1");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 52 (0x34)
.maxstack 3
.locals init (System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.4
IL_0003: ldc.i4.1
IL_0004: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldstr ""Text""
IL_0010: call ""CustomStruct CustomStruct.op_Implicit(string)""
IL_0015: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(CustomStruct)""
IL_001a: ldloca.s V_0
IL_001c: ldc.i4.1
IL_001d: box ""int""
IL_0022: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)""
IL_0027: ldloca.s V_0
IL_0029: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_002e: call ""void System.Console.WriteLine(string)""
IL_0033: ret
}
");
}
[Theory]
[InlineData(@"$""Text{1}""")]
[InlineData(@"$""Text"" + $""{1}""")]
public void ExplicitUserDefinedConversionInLiteral(string expression)
{
var source = @"
using System;
Console.WriteLine(" + expression + @");
public struct CustomStruct
{
public static explicit operator CustomStruct(string s) => new CustomStruct { S = s };
public string S { get; set; }
public override string ToString() => ""literal:"" + S;
}
namespace System.Runtime.CompilerServices
{
using System.Text;
public ref struct DefaultInterpolatedStringHandler
{
private readonly StringBuilder _builder;
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount)
{
_builder = new StringBuilder();
}
public string ToStringAndClear() => _builder.ToString();
public void AppendLiteral(CustomStruct s) => _builder.AppendLine(s.ToString());
public void AppendFormatted(object o) => _builder.AppendLine(""value:"" + o.ToString());
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,21): error CS1503: Argument 1: cannot convert from 'string' to 'CustomStruct'
// Console.WriteLine($"Text{1}");
Diagnostic(ErrorCode.ERR_BadArgType, "Text").WithArguments("1", "string", "CustomStruct").WithLocation(4, 21)
);
}
[Fact, WorkItem(58346, "https://github.com/dotnet/roslyn/issues/58346")]
public void UserDefinedConversion_AsFromTypeOfConversion_01()
{
var code = @"
struct S
{
public static implicit operator S(CustomHandler c) => default;
static void M()
{
/*<bind>*/S s = $"""";/*</bind>*/
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, handler });
comp.VerifyDiagnostics(
// (8,25): error CS0029: Cannot implicitly convert type 'string' to 'S'
// /*<bind>*/S s = $"";/*<bind>*/
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""""").WithArguments("string", "S").WithLocation(8, 25)
);
VerifyOperationTreeForTest<LocalDeclarationStatementSyntax>(comp, @"
IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'S s = $"""";')
IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'S s = $""""')
Declarators:
IVariableDeclaratorOperation (Symbol: S s) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 's = $""""')
Initializer:
IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= $""""')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S, IsInvalid, IsImplicit) (Syntax: '$""""')
Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: """", IsInvalid) (Syntax: '$""""')
Parts(0)
Initializer:
null
");
}
[Fact, WorkItem(58346, "https://github.com/dotnet/roslyn/issues/58346")]
public void UserDefinedConversion_AsFromTypeOfConversion_02()
{
var code = @"
struct S
{
public static implicit operator S(CustomHandler c) => default;
static void M()
{
/*<bind>*/S s = (S)$"""";/*</bind>*/
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, handler });
comp.VerifyDiagnostics(
// (8,25): error CS0030: Cannot convert type 'string' to 'S'
// /*<bind>*/S s = (S)$"";/*<bind>*/
Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(S)$""""").WithArguments("string", "S").WithLocation(8, 25)
);
VerifyOperationTreeForTest<LocalDeclarationStatementSyntax>(comp, @"
IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'S s = (S)$"""";')
IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'S s = (S)$""""')
Declarators:
IVariableDeclaratorOperation (Symbol: S s) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 's = (S)$""""')
Initializer:
IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= (S)$""""')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S, IsInvalid) (Syntax: '(S)$""""')
Conversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String, Constant: """", IsInvalid) (Syntax: '$""""')
Parts(0)
Initializer:
null
");
}
[Fact, WorkItem(58346, "https://github.com/dotnet/roslyn/issues/58346")]
public void UserDefinedConversion_AsFromTypeOfConversion_03()
{
var code = @"
/*<bind>*/S s = (CustomHandler)$"""";/*</bind>*/
struct S
{
public static implicit operator S(CustomHandler c)
{
System.Console.WriteLine(""In handler"");
return default;
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, handler });
CompileAndVerify(comp, expectedOutput: "In handler").VerifyDiagnostics();
VerifyOperationTreeForTest<LocalDeclarationStatementSyntax>(comp, @"
IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'S s = (Cust ... andler)$"""";')
IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'S s = (CustomHandler)$""""')
Declarators:
IVariableDeclaratorOperation (Symbol: S s) (OperationKind.VariableDeclarator, Type: null) (Syntax: 's = (CustomHandler)$""""')
Initializer:
IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= (CustomHandler)$""""')
IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S S.op_Implicit(CustomHandler c)) (OperationKind.Conversion, Type: S, IsImplicit) (Syntax: '(CustomHandler)$""""')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: S S.op_Implicit(CustomHandler c))
Operand:
IInterpolatedStringHandlerCreationOperation (HandlerAppendCallsReturnBool: False, HandlerCreationHasSuccessParameter: False) (OperationKind.InterpolatedStringHandlerCreation, Type: CustomHandler) (Syntax: '(CustomHandler)$""""')
Creation:
IObjectCreationOperation (Constructor: CustomHandler..ctor(System.Int32 literalLength, System.Int32 formattedCount)) (OperationKind.ObjectCreation, Type: CustomHandler, IsImplicit) (Syntax: '$""""')
Arguments(2):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: literalLength) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '$""""')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""""')
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: '$""""')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '$""""')
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, Constant: """") (Syntax: '$""""')
Parts(0)
Initializer:
null
");
}
[Theory]
[InlineData(@"$""Text{1}""")]
[InlineData(@"$""Text"" + $""{1}""")]
public void InvalidBuilderReturnType(string expression)
{
var source = @"
using System;
Console.WriteLine(" + expression + @");
namespace System.Runtime.CompilerServices
{
using System.Text;
public ref struct DefaultInterpolatedStringHandler
{
private readonly StringBuilder _builder;
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount)
{
_builder = new StringBuilder();
}
public string ToStringAndClear() => _builder.ToString();
public int AppendLiteral(string s) => 0;
public int AppendFormatted(object o) => 0;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,21): error CS8941: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' is malformed. It does not return 'void' or 'bool'.
// Console.WriteLine($"Text{1}");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)").WithLocation(4, 21),
// (4,25): error CS8941: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' is malformed. It does not return 'void' or 'bool'.
// Console.WriteLine($"Text{1}");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)").WithLocation(4, 15 + expression.Length)
);
}
[Fact]
public void MissingAppendMethods()
{
var source = @"
using System.Runtime.CompilerServices;
CustomHandler c = $""Literal{1}"";
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
}
";
var comp = CreateCompilation(new[] { source, InterpolatedStringHandlerAttribute });
comp.VerifyDiagnostics(
// (4,21): error CS1061: 'CustomHandler' does not contain a definition for 'AppendLiteral' and no accessible extension method 'AppendLiteral' accepting a first argument of type 'CustomHandler' could be found (are you missing a using directive or an assembly reference?)
// CustomHandler c = $"Literal{1}";
Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Literal").WithArguments("CustomHandler", "AppendLiteral").WithLocation(4, 21),
// (4,21): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'.
// CustomHandler c = $"Literal{1}";
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "Literal").WithArguments("?.()").WithLocation(4, 21),
// (4,28): error CS1061: 'CustomHandler' does not contain a definition for 'AppendFormatted' and no accessible extension method 'AppendFormatted' accepting a first argument of type 'CustomHandler' could be found (are you missing a using directive or an assembly reference?)
// CustomHandler c = $"Literal{1}";
Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "{1}").WithArguments("CustomHandler", "AppendFormatted").WithLocation(4, 28),
// (4,28): error CS8941: Interpolated string handler method '?.()' is malformed. It does not return 'void' or 'bool'.
// CustomHandler c = $"Literal{1}";
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, "{1}").WithArguments("?.()").WithLocation(4, 28)
);
}
[Fact]
public void MissingBoolType()
{
var handlerSource = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var handlerRef = CreateCompilation(handlerSource).EmitToImageReference();
var source = @"CustomHandler c = $""Literal{1}"";";
var comp = CreateCompilation(source, references: new[] { handlerRef });
comp.MakeTypeMissing(SpecialType.System_Boolean);
comp.VerifyDiagnostics(
// (1,19): error CS0518: Predefined type 'System.Boolean' is not defined or imported
// CustomHandler c = $"Literal{1}";
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"$""Literal{1}""").WithArguments("System.Boolean").WithLocation(1, 19)
);
}
[Fact]
public void MissingVoidType()
{
var handlerSource = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false);
var handlerRef = CreateCompilation(handlerSource).EmitToImageReference();
var source = @"
class C
{
public bool M()
{
CustomHandler c = $""Literal{1}"";
return true;
}
}
";
var comp = CreateCompilation(source, references: new[] { handlerRef });
comp.MakeTypeMissing(SpecialType.System_Void);
comp.VerifyEmitDiagnostics();
}
[Theory]
[InlineData(@"$""Text{1}""", @"$""{1}Text""")]
[InlineData(@"$""Text"" + $""{1}""", @"$""{1}"" + $""Text""")]
public void MixedBuilderReturnTypes_01(string expression1, string expression2)
{
var source = @"
using System;
Console.WriteLine(" + expression1 + @");
Console.WriteLine(" + expression2 + @");
namespace System.Runtime.CompilerServices
{
using System.Text;
public ref struct DefaultInterpolatedStringHandler
{
private readonly StringBuilder _builder;
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount)
{
_builder = new StringBuilder();
}
public string ToStringAndClear() => _builder.ToString();
public bool AppendLiteral(string s) => true;
public void AppendFormatted(object o) { }
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,25): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' has inconsistent return type. Expected to return 'bool'.
// Console.WriteLine($"Text{1}");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)", "bool").WithLocation(4, 15 + expression1.Length),
// (5,24): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' has inconsistent return type. Expected to return 'void'.
// Console.WriteLine($"{1}Text");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "void").WithLocation(5, 14 + expression2.Length)
);
}
[Theory]
[InlineData(@"$""Text{1}""", @"$""{1}Text""")]
[InlineData(@"$""Text"" + $""{1}""", @"$""{1}"" + $""Text""")]
public void MixedBuilderReturnTypes_02(string expression1, string expression2)
{
var source = @"
using System;
Console.WriteLine(" + expression1 + @");
Console.WriteLine(" + expression2 + @");
namespace System.Runtime.CompilerServices
{
using System.Text;
public ref struct DefaultInterpolatedStringHandler
{
private readonly StringBuilder _builder;
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount)
{
_builder = new StringBuilder();
}
public string ToStringAndClear() => _builder.ToString();
public void AppendLiteral(string s) { }
public bool AppendFormatted(object o) => true;
}
}";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (4,25): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendFormatted(object)' has inconsistent return type. Expected to return 'void'.
// Console.WriteLine($"Text{1}");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "{1}").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(object)", "void").WithLocation(4, 15 + expression1.Length),
// (5,24): error CS8942: Interpolated string handler method 'DefaultInterpolatedStringHandler.AppendLiteral(string)' has inconsistent return type. Expected to return 'bool'.
// Console.WriteLine($"{1}Text");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, "Text").WithArguments("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)", "bool").WithLocation(5, 14 + expression2.Length)
);
}
[Fact]
public void MixedBuilderReturnTypes_03()
{
var source = @"
using System;
Console.WriteLine($""{1}"");
namespace System.Runtime.CompilerServices
{
using System.Text;
public ref struct DefaultInterpolatedStringHandler
{
private readonly StringBuilder _builder;
public DefaultInterpolatedStringHandler(int literalLength, int formattedCount)
{
_builder = new StringBuilder();
}
public string ToStringAndClear() => _builder.ToString();
public bool AppendLiteral(string s) => true;
public void AppendFormatted(object o)
{
_builder.AppendLine(""value:"" + o.ToString());
}
}
}";
CompileAndVerify(source, expectedOutput: "value:1");
}
[Fact]
public void MixedBuilderReturnTypes_04()
{
var source = @"
using System;
using System.Text;
using System.Runtime.CompilerServices;
Console.WriteLine((CustomHandler)$""l"");
[InterpolatedStringHandler]
public class CustomHandler
{
private readonly StringBuilder _builder;
public CustomHandler(int literalLength, int formattedCount)
{
_builder = new StringBuilder();
}
public override string ToString() => _builder.ToString();
public bool AppendFormatted(object o) => true;
public void AppendLiteral(string s)
{
_builder.AppendLine(""literal:"" + s.ToString());
}
}
";
CompileAndVerify(new[] { source, InterpolatedStringHandlerAttribute }, expectedOutput: "literal:l");
}
private static void VerifyInterpolatedStringExpression(CSharpCompilation comp, string handlerType = "CustomHandler")
{
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var descendentNodes = tree.GetRoot().DescendantNodes();
var interpolatedString =
(ExpressionSyntax)descendentNodes.OfType<BinaryExpressionSyntax>()
.Where(b => b.DescendantNodes().OfType<InterpolatedStringExpressionSyntax>().Any())
.FirstOrDefault()
?? descendentNodes.OfType<InterpolatedStringExpressionSyntax>().Single();
var semanticInfo = model.GetSemanticInfoSummary(interpolatedString);
Assert.Equal(SpecialType.System_String, semanticInfo.Type.SpecialType);
Assert.Equal(handlerType, semanticInfo.ConvertedType.ToTestDisplayString());
Assert.Equal(ConversionKind.InterpolatedStringHandler, semanticInfo.ImplicitConversion.Kind);
Assert.True(semanticInfo.ImplicitConversion.Exists);
Assert.True(semanticInfo.ImplicitConversion.IsValid);
Assert.True(semanticInfo.ImplicitConversion.IsInterpolatedStringHandler);
Assert.Null(semanticInfo.ImplicitConversion.Method);
if (interpolatedString is BinaryExpressionSyntax)
{
Assert.False(semanticInfo.ConstantValue.HasValue);
AssertEx.Equal("System.String System.String.op_Addition(System.String left, System.String right)", semanticInfo.Symbol.ToTestDisplayString());
}
// https://github.com/dotnet/roslyn/issues/54505 Assert IConversionOperation.IsImplicit when IOperation is implemented for interpolated strings.
}
private CompilationVerifier CompileAndVerifyOnCorrectPlatforms(CSharpCompilation compilation, string expectedOutput)
=> CompileAndVerify(
compilation,
expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null,
verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped);
[Theory]
[CombinatorialData]
public void CustomHandlerLocal([CombinatorialValues("class", "struct")] string type, bool useBoolReturns,
[CombinatorialValues(@"$""Literal{1,2:f}""", @"$""Literal"" + $""{1,2:f}""")] string expression)
{
var code = @"
CustomHandler builder = " + expression + @";
System.Console.WriteLine(builder.ToString());";
var builder = GetInterpolatedStringCustomHandlerType("CustomHandler", type, useBoolReturns);
var comp = CreateCompilation(new[] { code, builder });
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
literal:Literal
value:1
alignment:2
format:f");
verifier.VerifyIL("<top-level-statements-entry-point>", getIl());
string getIl() => (type, useBoolReturns) switch
{
(type: "struct", useBoolReturns: true) => @"
{
// Code size 67 (0x43)
.maxstack 4
.locals init (CustomHandler V_0, //builder
CustomHandler V_1)
IL_0000: ldloca.s V_1
IL_0002: ldc.i4.7
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_1
IL_000b: ldstr ""Literal""
IL_0010: call ""bool CustomHandler.AppendLiteral(string)""
IL_0015: brfalse.s IL_002c
IL_0017: ldloca.s V_1
IL_0019: ldc.i4.1
IL_001a: box ""int""
IL_001f: ldc.i4.2
IL_0020: ldstr ""f""
IL_0025: call ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_002a: br.s IL_002d
IL_002c: ldc.i4.0
IL_002d: pop
IL_002e: ldloc.1
IL_002f: stloc.0
IL_0030: ldloca.s V_0
IL_0032: constrained. ""CustomHandler""
IL_0038: callvirt ""string object.ToString()""
IL_003d: call ""void System.Console.WriteLine(string)""
IL_0042: ret
}
",
(type: "struct", useBoolReturns: false) => @"
{
// Code size 61 (0x3d)
.maxstack 4
.locals init (CustomHandler V_0, //builder
CustomHandler V_1)
IL_0000: ldloca.s V_1
IL_0002: ldc.i4.7
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_1
IL_000b: ldstr ""Literal""
IL_0010: call ""void CustomHandler.AppendLiteral(string)""
IL_0015: ldloca.s V_1
IL_0017: ldc.i4.1
IL_0018: box ""int""
IL_001d: ldc.i4.2
IL_001e: ldstr ""f""
IL_0023: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0028: ldloc.1
IL_0029: stloc.0
IL_002a: ldloca.s V_0
IL_002c: constrained. ""CustomHandler""
IL_0032: callvirt ""string object.ToString()""
IL_0037: call ""void System.Console.WriteLine(string)""
IL_003c: ret
}
",
(type: "class", useBoolReturns: true) => @"
{
// Code size 55 (0x37)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldstr ""Literal""
IL_000e: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0013: brfalse.s IL_0029
IL_0015: ldloc.0
IL_0016: ldc.i4.1
IL_0017: box ""int""
IL_001c: ldc.i4.2
IL_001d: ldstr ""f""
IL_0022: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.0
IL_002c: callvirt ""string object.ToString()""
IL_0031: call ""void System.Console.WriteLine(string)""
IL_0036: ret
}
",
(type: "class", useBoolReturns: false) => @"
{
// Code size 47 (0x2f)
.maxstack 5
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: dup
IL_0008: ldstr ""Literal""
IL_000d: callvirt ""void CustomHandler.AppendLiteral(string)""
IL_0012: dup
IL_0013: ldc.i4.1
IL_0014: box ""int""
IL_0019: ldc.i4.2
IL_001a: ldstr ""f""
IL_001f: callvirt ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0024: callvirt ""string object.ToString()""
IL_0029: call ""void System.Console.WriteLine(string)""
IL_002e: ret
}
",
_ => throw ExceptionUtilities.Unreachable()
};
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void CustomHandlerMethodArgument(string expression)
{
var code = @"
M(" + expression + @");
void M(CustomHandler b)
{
System.Console.WriteLine(b.ToString());
}";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL(@"<top-level-statements-entry-point>", @"
{
// Code size 50 (0x32)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: box ""int""
IL_000f: ldc.i4.2
IL_0010: ldstr ""f""
IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_001a: brfalse.s IL_0029
IL_001c: ldloc.0
IL_001d: ldstr ""Literal""
IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.0
IL_002c: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_0031: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"($""{1,2:f}"" + $""Literal"")")]
public void ExplicitHandlerCast_InCode(string expression)
{
var code = @"System.Console.WriteLine((CustomHandler)" + expression + @");";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false) });
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
SyntaxNode syntax = tree.GetRoot().DescendantNodes().OfType<CastExpressionSyntax>().Single();
var semanticInfo = model.GetSemanticInfoSummary(syntax);
Assert.Equal("CustomHandler", semanticInfo.Type.ToTestDisplayString());
Assert.Equal(SpecialType.System_Object, semanticInfo.ConvertedType.SpecialType);
Assert.Equal(ConversionKind.ImplicitReference, semanticInfo.ImplicitConversion.Kind);
syntax = ((CastExpressionSyntax)syntax).Expression;
Assert.Equal(expression, syntax.ToString());
semanticInfo = model.GetSemanticInfoSummary(syntax);
Assert.Equal(SpecialType.System_String, semanticInfo.Type.SpecialType);
Assert.Equal(SpecialType.System_String, semanticInfo.ConvertedType.SpecialType);
Assert.Equal(ConversionKind.Identity, semanticInfo.ImplicitConversion.Kind);
// https://github.com/dotnet/roslyn/issues/54505 Assert cast is explicit after IOperation is implemented
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 42 (0x2a)
.maxstack 5
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: dup
IL_0008: ldc.i4.1
IL_0009: box ""int""
IL_000e: ldc.i4.2
IL_000f: ldstr ""f""
IL_0014: callvirt ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0019: dup
IL_001a: ldstr ""Literal""
IL_001f: callvirt ""void CustomHandler.AppendLiteral(string)""
IL_0024: call ""void System.Console.WriteLine(object)""
IL_0029: ret
}
");
}
[Theory, WorkItem(55345, "https://github.com/dotnet/roslyn/issues/55345")]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void HandlerConversionPreferredOverStringForNonConstant(string expression)
{
var code = @"
CultureInfoNormalizer.Normalize();
C.M(" + expression + @");
class C
{
public static void M(CustomHandler b)
{
System.Console.WriteLine(b.ToString());
}
public static void M(string s)
{
System.Console.WriteLine(s);
}
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }, parseOptions: TestOptions.Regular10);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL(@"<top-level-statements-entry-point>", @"
{
// Code size 55 (0x37)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: call ""void CultureInfoNormalizer.Normalize()""
IL_0005: ldc.i4.7
IL_0006: ldc.i4.1
IL_0007: newobj ""CustomHandler..ctor(int, int)""
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: ldc.i4.1
IL_000f: box ""int""
IL_0014: ldc.i4.2
IL_0015: ldstr ""f""
IL_001a: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_001f: brfalse.s IL_002e
IL_0021: ldloc.0
IL_0022: ldstr ""Literal""
IL_0027: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_002c: br.s IL_002f
IL_002e: ldc.i4.0
IL_002f: pop
IL_0030: ldloc.0
IL_0031: call ""void C.M(CustomHandler)""
IL_0036: ret
}
");
comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }, parseOptions: TestOptions.Regular9);
verifier = CompileAndVerify(comp, expectedOutput: @"1.00Literal");
verifier.VerifyIL(@"<top-level-statements-entry-point>", expression.Contains('+') ? @"
{
// Code size 37 (0x25)
.maxstack 2
IL_0000: call ""void CultureInfoNormalizer.Normalize()""
IL_0005: ldstr ""{0,2:f}""
IL_000a: ldc.i4.1
IL_000b: box ""int""
IL_0010: call ""string string.Format(string, object)""
IL_0015: ldstr ""Literal""
IL_001a: call ""string string.Concat(string, string)""
IL_001f: call ""void C.M(string)""
IL_0024: ret
}
"
: @"
{
// Code size 27 (0x1b)
.maxstack 2
IL_0000: call ""void CultureInfoNormalizer.Normalize()""
IL_0005: ldstr ""{0,2:f}Literal""
IL_000a: ldc.i4.1
IL_000b: box ""int""
IL_0010: call ""string string.Format(string, object)""
IL_0015: call ""void C.M(string)""
IL_001a: ret
}
");
}
[Theory]
[InlineData(@"$""{""Literal""}""")]
[InlineData(@"$""{""Lit""}"" + $""{""eral""}""")]
public void StringPreferredOverHandlerConversionForConstant(string expression)
{
var code = @"
C.M(" + expression + @");
class C
{
public static void M(CustomHandler b)
{
throw null;
}
public static void M(string s)
{
System.Console.WriteLine(s);
}
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
var verifier = CompileAndVerify(comp, expectedOutput: @"Literal");
verifier.VerifyIL(@"<top-level-statements-entry-point>", @"
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldstr ""Literal""
IL_0005: call ""void C.M(string)""
IL_000a: ret
}
");
}
[Theory]
[InlineData(@"$""{1}{2}""")]
[InlineData(@"$""{1}"" + $""{2}""")]
public void HandlerConversionPreferredOverStringForNonConstant_AttributeConstructor(string expression)
{
var code = @"
using System;
[Attr(" + expression + @")]
class Attr : Attribute
{
public Attr(string s) {}
public Attr(CustomHandler c) {}
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
comp.VerifyDiagnostics(
// (4,7): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Attr($"{1}{2}")]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, expression).WithLocation(4, 7)
);
var attr = comp.SourceAssembly.SourceModule.GlobalNamespace.GetTypeMember("Attr");
// Note that for usage in attributes, we don't use the custom handler. This is because it's an error scenario regardless, and we want to avoid
// potential binding cycles.
Assert.Equal("Attr..ctor(System.String s)", attr.GetAttributes().Single().AttributeConstructor.ToTestDisplayString());
}
[Theory]
[InlineData(@"$""{""Literal""}""")]
[InlineData(@"$""{""Lit""}"" + $""{""eral""}""")]
public void StringPreferredOverHandlerConversionForConstant_AttributeConstructor(string expression)
{
var code = @"
using System;
[Attr(" + expression + @")]
class Attr : Attribute
{
public Attr(string s) {}
public Attr(CustomHandler c) {}
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate);
void validate(ModuleSymbol m)
{
var attr = m.GlobalNamespace.GetTypeMember("Attr");
Assert.Equal("Attr..ctor(System.String s)", attr.GetAttributes().Single().AttributeConstructor.ToTestDisplayString());
}
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void MultipleBuilderTypes(string expression)
{
var code = @"
C.M(" + expression + @");
class C
{
public static void M(CustomHandler1 c) => throw null;
public static void M(CustomHandler2 c) => throw null;
}";
var comp = CreateCompilation(new[]
{
code,
GetInterpolatedStringCustomHandlerType("CustomHandler1", "struct", useBoolReturns: false),
GetInterpolatedStringCustomHandlerType("CustomHandler2", "struct", useBoolReturns: false, includeOneTimeHelpers: false)
});
comp.VerifyDiagnostics(
// (2,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(CustomHandler1)' and 'C.M(CustomHandler2)'
// C.M($"");
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(CustomHandler1)", "C.M(CustomHandler2)").WithLocation(2, 3)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void GenericOverloadResolution_01(string expression)
{
var code = @"
using System;
C.M(" + expression + @");
class C
{
public static void M<T>(T t) => throw null;
public static void M(CustomHandler c) => Console.WriteLine(c);
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 50 (0x32)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: box ""int""
IL_000f: ldc.i4.2
IL_0010: ldstr ""f""
IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_001a: brfalse.s IL_0029
IL_001c: ldloc.0
IL_001d: ldstr ""Literal""
IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.0
IL_002c: call ""void C.M(CustomHandler)""
IL_0031: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void GenericOverloadResolution_02(string expression)
{
var code = @"
using System;
C.M(" + expression + @");
class C
{
public static void M<T>(T t) where T : CustomHandler => throw null;
public static void M(CustomHandler c) => Console.WriteLine(c);
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 50 (0x32)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: box ""int""
IL_000f: ldc.i4.2
IL_0010: ldstr ""f""
IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_001a: brfalse.s IL_0029
IL_001c: ldloc.0
IL_001d: ldstr ""Literal""
IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.0
IL_002c: call ""void C.M(CustomHandler)""
IL_0031: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void GenericOverloadResolution_03(string expression)
{
var code = @"
C.M(" + expression + @");
class C
{
public static void M<T>(T t) where T : CustomHandler => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
comp.VerifyDiagnostics(
// (2,3): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'C.M<T>(T)'. There is no implicit reference conversion from 'string' to 'CustomHandler'.
// C.M($"{1,2:f}Literal");
Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("C.M<T>(T)", "CustomHandler", "T", "string").WithLocation(2, 3)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void GenericInference_01(string expression)
{
var code = @"
C.M(" + expression + @", default(CustomHandler));
C.M(default(CustomHandler), " + expression + @");
class C
{
public static void M<T>(T t1, T t2) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) }, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (2,3): error CS0411: The type arguments for method 'C.M<T>(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// C.M($"{1,2:f}Literal", default(CustomHandler));
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M<T>(T, T)").WithLocation(2, 3),
// (3,3): error CS0411: The type arguments for method 'C.M<T>(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// C.M(default(CustomHandler), $"{1,2:f}Literal");
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M<T>(T, T)").WithLocation(3, 3)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void GenericInference_02(string expression)
{
var code = @"
using System;
C.M(default(CustomHandler), () => " + expression + @");
class C
{
public static void M<T>(T t1, Func<T> t2) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
comp.VerifyDiagnostics(
// (3,3): error CS0411: The type arguments for method 'C.M<T>(T, Func<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// C.M(default(CustomHandler), () => $"{1,2:f}Literal");
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M<T>(T, System.Func<T>)").WithLocation(3, 3)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void GenericInference_03(string expression)
{
var code = @"
using System;
C.M(" + expression + @", default(CustomHandler));
class C
{
public static void M<T>(T t1, T t2) => Console.WriteLine(t1);
}
partial class CustomHandler
{
public static implicit operator CustomHandler(string s) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: true) });
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 51 (0x33)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: box ""int""
IL_000f: ldc.i4.2
IL_0010: ldstr ""f""
IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_001a: brfalse.s IL_0029
IL_001c: ldloc.0
IL_001d: ldstr ""Literal""
IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.0
IL_002c: ldnull
IL_002d: call ""void C.M<CustomHandler>(CustomHandler, CustomHandler)""
IL_0032: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void GenericInference_04(string expression)
{
var code = @"
using System;
C.M(default(CustomHandler), () => " + expression + @");
class C
{
public static void M<T>(T t1, Func<T> t2) => Console.WriteLine(t2());
}
partial class CustomHandler
{
public static implicit operator CustomHandler(string s) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: true) });
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("Program.<>c.<<Main>$>b__0_0()", @"
{
// Code size 45 (0x2d)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: box ""int""
IL_000f: ldc.i4.2
IL_0010: ldstr ""f""
IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_001a: brfalse.s IL_0029
IL_001c: ldloc.0
IL_001d: ldstr ""Literal""
IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.0
IL_002c: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void LambdaReturnInference_01(string expression)
{
var code = @"
using System;
Func<CustomHandler> f = () => " + expression + @";
Console.WriteLine(f());
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL(@"Program.<>c.<<Main>$>b__0_0()", @"
{
// Code size 45 (0x2d)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: box ""int""
IL_000f: ldc.i4.2
IL_0010: ldstr ""f""
IL_0015: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_001a: brfalse.s IL_0029
IL_001c: ldloc.0
IL_001d: ldstr ""Literal""
IL_0022: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.0
IL_002c: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void LambdaReturnInference_02(string expression)
{
var code = @"
using System;
CultureInfoNormalizer.Normalize();
C.M(() => " + expression + @");
class C
{
public static void M(Func<string> f) => Console.WriteLine(f());
public static void M(Func<CustomHandler> f) => throw null;
}
";
// Interpolated string handler conversions are not considered when determining the natural type of an expression: the natural return type of this lambda is string,
// so we don't even consider that there is a conversion from interpolated string expression to CustomHandler here (Sections 12.6.3.13 and 12.6.3.15 of the spec).
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: true) });
var verifier = CompileAndVerify(comp, expectedOutput: @"1.00Literal");
// No DefaultInterpolatedStringHandler was included in the compilation, so it falls back to string.Format
verifier.VerifyIL(@"Program.<>c.<<Main>$>b__0_0()", !expression.Contains('+') ? @"
{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldstr ""{0,2:f}Literal""
IL_0005: ldc.i4.1
IL_0006: box ""int""
IL_000b: call ""string string.Format(string, object)""
IL_0010: ret
}
"
: @"
{
// Code size 27 (0x1b)
.maxstack 2
IL_0000: ldstr ""{0,2:f}""
IL_0005: ldc.i4.1
IL_0006: box ""int""
IL_000b: call ""string string.Format(string, object)""
IL_0010: ldstr ""Literal""
IL_0015: call ""string string.Concat(string, string)""
IL_001a: ret
}
");
}
[Theory]
[InlineData(@"$""{new S { Field = ""Field"" }}""")]
[InlineData(@"$""{new S { Field = ""Field"" }}"" + $""""")]
public void LambdaReturnInference_03(string expression)
{
// Same as 2, but using a type that isn't allowed in an interpolated string. There is an implicit conversion error on the ref struct
// when converting to a string, because S cannot be a component of an interpolated string. This conversion error causes the lambda to
// fail to bind as Func<string>, even though the natural return type is string, and the only successful bind is Func<CustomHandler>.
var code = @"
using System;
C.M(() => " + expression + @");
static class C
{
public static void M(Func<string> f) => throw null;
public static void M(Func<CustomHandler> f) => Console.WriteLine(f());
}
public partial class CustomHandler
{
public void AppendFormatted(S value) => _builder.AppendLine(""value:"" + value.Field);
}
public ref struct S
{
public string Field { get; set; }
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"value:Field");
verifier.VerifyIL(@"Program.<>c.<<Main>$>b__0_0()", @"
{
// Code size 35 (0x23)
.maxstack 4
.locals init (S V_0)
IL_0000: ldc.i4.0
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: dup
IL_0008: ldloca.s V_0
IL_000a: initobj ""S""
IL_0010: ldloca.s V_0
IL_0012: ldstr ""Field""
IL_0017: call ""void S.Field.set""
IL_001c: ldloc.0
IL_001d: callvirt ""void CustomHandler.AppendFormatted(S)""
IL_0022: ret
}
");
}
[Theory]
[InlineData(@"$""{new S { Field = ""Field"" }}""")]
[InlineData(@"$""{new S { Field = ""Field"" }}"" + $""""")]
public void LambdaReturnInference_04(string expression)
{
// Same as 3, but with S added to DefaultInterpolatedStringHandler (which then allows the lambda to be bound as Func<string>, matching the natural return type)
var code = @"
using System;
C.M(() => " + expression + @");
static class C
{
public static void M(Func<string> f) => Console.WriteLine(f());
public static void M(Func<CustomHandler> f) => throw null;
}
public partial class CustomHandler
{
public void AppendFormatted(S value) => throw null;
}
public ref struct S
{
public string Field { get; set; }
}
namespace System.Runtime.CompilerServices
{
public ref partial struct DefaultInterpolatedStringHandler
{
public void AppendFormatted(S value) => _builder.AppendLine(""value:"" + value.Field);
}
}
";
string[] source = new[] {
code,
GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: false),
GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: true, useBoolReturns: false)
};
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (3,11): error CS8773: Feature 'interpolated string handlers' is not available in C# 9.0. Please use language version 10.0 or greater.
// C.M(() => $"{new S { Field = "Field" }}");
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, expression).WithArguments("interpolated string handlers", "10.0").WithLocation(3, 11),
// (3,14): error CS8773: Feature 'interpolated string handlers' is not available in C# 9.0. Please use language version 10.0 or greater.
// C.M(() => $"{new S { Field = "Field" }}");
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, @"new S { Field = ""Field"" }").WithArguments("interpolated string handlers", "10.0").WithLocation(3, 14)
);
comp = CreateCompilation(source, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"value:Field");
verifier.VerifyIL(@"Program.<>c.<<Main>$>b__0_0()", @"
{
// Code size 45 (0x2d)
.maxstack 3
.locals init (System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_0,
S V_1)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.0
IL_0003: ldc.i4.1
IL_0004: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldloca.s V_1
IL_000d: initobj ""S""
IL_0013: ldloca.s V_1
IL_0015: ldstr ""Field""
IL_001a: call ""void S.Field.set""
IL_001f: ldloc.1
IL_0020: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(S)""
IL_0025: ldloca.s V_0
IL_0027: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_002c: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void LambdaReturnInference_05(string expression)
{
var code = @"
using System;
C.M(b =>
{
if (b) return default(CustomHandler);
else return " + expression + @";
});
static class C
{
public static void M(Func<bool, string> f) => throw null;
public static void M(Func<bool, CustomHandler> f) => Console.WriteLine(f(false));
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL(@"Program.<>c.<<Main>$>b__0_0(bool)", @"
{
// Code size 55 (0x37)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldarg.1
IL_0001: brfalse.s IL_000d
IL_0003: ldloca.s V_0
IL_0005: initobj ""CustomHandler""
IL_000b: ldloc.0
IL_000c: ret
IL_000d: ldloca.s V_0
IL_000f: ldc.i4.7
IL_0010: ldc.i4.1
IL_0011: call ""CustomHandler..ctor(int, int)""
IL_0016: ldloca.s V_0
IL_0018: ldc.i4.1
IL_0019: box ""int""
IL_001e: ldc.i4.2
IL_001f: ldstr ""f""
IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0029: ldloca.s V_0
IL_002b: ldstr ""Literal""
IL_0030: call ""void CustomHandler.AppendLiteral(string)""
IL_0035: ldloc.0
IL_0036: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void LambdaReturnInference_06(string expression)
{
// Same as 5, but with an implicit conversion from the builder type to string. This implicit conversion
// means that a best common type can be inferred for all branches of the lambda expression (Section 12.6.3.15 of the spec)
// and because there is a best common type, the inferred return type of the lambda is string. Since the inferred return type
// has an identity conversion to the return type of Func<bool, string>, that is preferred.
var code = @"
using System;
CultureInfoNormalizer.Normalize();
C.M(b =>
{
if (b) return default(CustomHandler);
else return " + expression + @";
});
static class C
{
public static void M(Func<bool, string> f) => Console.WriteLine(f(false));
public static void M(Func<bool, CustomHandler> f) => throw null;
}
public partial struct CustomHandler
{
public static implicit operator string(CustomHandler c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"1.00Literal");
verifier.VerifyIL(@"Program.<>c.<<Main>$>b__0_0(bool)", !expression.Contains('+') ? @"
{
// Code size 35 (0x23)
.maxstack 2
.locals init (CustomHandler V_0)
IL_0000: ldarg.1
IL_0001: brfalse.s IL_0012
IL_0003: ldloca.s V_0
IL_0005: initobj ""CustomHandler""
IL_000b: ldloc.0
IL_000c: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0011: ret
IL_0012: ldstr ""{0,2:f}Literal""
IL_0017: ldc.i4.1
IL_0018: box ""int""
IL_001d: call ""string string.Format(string, object)""
IL_0022: ret
}
"
: @"
{
// Code size 45 (0x2d)
.maxstack 2
.locals init (CustomHandler V_0)
IL_0000: ldarg.1
IL_0001: brfalse.s IL_0012
IL_0003: ldloca.s V_0
IL_0005: initobj ""CustomHandler""
IL_000b: ldloc.0
IL_000c: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0011: ret
IL_0012: ldstr ""{0,2:f}""
IL_0017: ldc.i4.1
IL_0018: box ""int""
IL_001d: call ""string string.Format(string, object)""
IL_0022: ldstr ""Literal""
IL_0027: call ""string string.Concat(string, string)""
IL_002c: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void LambdaReturnInference_07(string expression)
{
// Same as 5, but with an implicit conversion from string to the builder type.
var code = @"
using System;
C.M(b =>
{
if (b) return default(CustomHandler);
else return " + expression + @";
});
static class C
{
public static void M(Func<bool, string> f) => Console.WriteLine(f(false));
public static void M(Func<bool, CustomHandler> f) => Console.WriteLine(f(false));
}
public partial struct CustomHandler
{
public static implicit operator CustomHandler(string s) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL(@"Program.<>c.<<Main>$>b__0_0(bool)", @"
{
// Code size 55 (0x37)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldarg.1
IL_0001: brfalse.s IL_000d
IL_0003: ldloca.s V_0
IL_0005: initobj ""CustomHandler""
IL_000b: ldloc.0
IL_000c: ret
IL_000d: ldloca.s V_0
IL_000f: ldc.i4.7
IL_0010: ldc.i4.1
IL_0011: call ""CustomHandler..ctor(int, int)""
IL_0016: ldloca.s V_0
IL_0018: ldc.i4.1
IL_0019: box ""int""
IL_001e: ldc.i4.2
IL_001f: ldstr ""f""
IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0029: ldloca.s V_0
IL_002b: ldstr ""Literal""
IL_0030: call ""void CustomHandler.AppendLiteral(string)""
IL_0035: ldloc.0
IL_0036: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void LambdaReturnInference_08(string expression)
{
// Same as 5, but with an implicit conversion from the builder type to string and from string to the builder type.
var code = @"
using System;
C.M(b =>
{
if (b) return default(CustomHandler);
else return " + expression + @";
});
static class C
{
public static void M(Func<bool, string> f) => Console.WriteLine(f(false));
public static void M(Func<bool, CustomHandler> f) => throw null;
}
public partial struct CustomHandler
{
public static implicit operator string(CustomHandler c) => throw null;
public static implicit operator CustomHandler(string c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (3,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(Func<bool, string>)' and 'C.M(Func<bool, CustomHandler>)'
// C.M(b =>
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(System.Func<bool, string>)", "C.M(System.Func<bool, CustomHandler>)").WithLocation(3, 3)
);
}
[Theory]
[InlineData(@"$""{1}""")]
[InlineData(@"$""{1}"" + $""{2}""")]
public void LambdaInference_AmbiguousInOlderLangVersions(string expression)
{
var code = @"
using System;
C.M(param =>
{
param = " + expression + @";
});
static class C
{
public static void M(Action<string> f) => throw null;
public static void M(Action<CustomHandler> f) => throw null;
}
";
var source = new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) };
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9);
// This successful emit is being caused by https://github.com/dotnet/roslyn/issues/53761, along with the duplicate diagnostics in LambdaReturnInference_04
// We should not be changing binding behavior based on LangVersion.
comp.VerifyEmitDiagnostics();
comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (3,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(Action<string>)' and 'C.M(Action<CustomHandler>)'
// C.M(param =>
Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(System.Action<string>)", "C.M(System.Action<CustomHandler>)").WithLocation(3, 3)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void TernaryTypes_01(string expression)
{
var code = @"
using System;
var x = (bool)(object)false ? default(CustomHandler) : " + expression + @";
Console.WriteLine(x);
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 76 (0x4c)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.0
IL_0001: box ""bool""
IL_0006: unbox.any ""bool""
IL_000b: brtrue.s IL_0038
IL_000d: ldloca.s V_0
IL_000f: ldc.i4.7
IL_0010: ldc.i4.1
IL_0011: call ""CustomHandler..ctor(int, int)""
IL_0016: ldloca.s V_0
IL_0018: ldc.i4.1
IL_0019: box ""int""
IL_001e: ldc.i4.2
IL_001f: ldstr ""f""
IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0029: ldloca.s V_0
IL_002b: ldstr ""Literal""
IL_0030: call ""void CustomHandler.AppendLiteral(string)""
IL_0035: ldloc.0
IL_0036: br.s IL_0041
IL_0038: ldloca.s V_0
IL_003a: initobj ""CustomHandler""
IL_0040: ldloc.0
IL_0041: box ""CustomHandler""
IL_0046: call ""void System.Console.WriteLine(object)""
IL_004b: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void TernaryTypes_02(string expression)
{
// Same as 01, but with a conversion from CustomHandler to string. The rules here are similar to LambdaReturnInference_06
var code = @"
using System;
CultureInfoNormalizer.Normalize();
var x = (bool)(object)false ? default(CustomHandler) : " + expression + @";
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator string(CustomHandler c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"1.00Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", !expression.Contains('+') ? @"
{
// Code size 56 (0x38)
.maxstack 2
.locals init (CustomHandler V_0)
IL_0000: call ""void CultureInfoNormalizer.Normalize()""
IL_0005: ldc.i4.0
IL_0006: box ""bool""
IL_000b: unbox.any ""bool""
IL_0010: brtrue.s IL_0024
IL_0012: ldstr ""{0,2:f}Literal""
IL_0017: ldc.i4.1
IL_0018: box ""int""
IL_001d: call ""string string.Format(string, object)""
IL_0022: br.s IL_0032
IL_0024: ldloca.s V_0
IL_0026: initobj ""CustomHandler""
IL_002c: ldloc.0
IL_002d: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0032: call ""void System.Console.WriteLine(string)""
IL_0037: ret
}
"
: @"
{
// Code size 66 (0x42)
.maxstack 2
.locals init (CustomHandler V_0)
IL_0000: call ""void CultureInfoNormalizer.Normalize()""
IL_0005: ldc.i4.0
IL_0006: box ""bool""
IL_000b: unbox.any ""bool""
IL_0010: brtrue.s IL_002e
IL_0012: ldstr ""{0,2:f}""
IL_0017: ldc.i4.1
IL_0018: box ""int""
IL_001d: call ""string string.Format(string, object)""
IL_0022: ldstr ""Literal""
IL_0027: call ""string string.Concat(string, string)""
IL_002c: br.s IL_003c
IL_002e: ldloca.s V_0
IL_0030: initobj ""CustomHandler""
IL_0036: ldloc.0
IL_0037: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_003c: call ""void System.Console.WriteLine(string)""
IL_0041: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void TernaryTypes_03(string expression)
{
// Same as 02, but with a target-type
var code = @"
using System;
CustomHandler x = (bool)(object)false ? default(CustomHandler) : " + expression + @";
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator string(CustomHandler c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (4,19): error CS0029: Cannot implicitly convert type 'string' to 'CustomHandler'
// CustomHandler x = (bool)(object)false ? default(CustomHandler) : $"{1,2:f}Literal";
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"(bool)(object)false ? default(CustomHandler) : " + expression).WithArguments("string", "CustomHandler").WithLocation(4, 19)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void TernaryTypes_04(string expression)
{
// Same 01, but with a conversion from string to CustomHandler. The rules here are similar to LambdaReturnInference_07
var code = @"
using System;
var x = (bool)(object)false ? default(CustomHandler) : " + expression + @";
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator CustomHandler(string c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 76 (0x4c)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.0
IL_0001: box ""bool""
IL_0006: unbox.any ""bool""
IL_000b: brtrue.s IL_0038
IL_000d: ldloca.s V_0
IL_000f: ldc.i4.7
IL_0010: ldc.i4.1
IL_0011: call ""CustomHandler..ctor(int, int)""
IL_0016: ldloca.s V_0
IL_0018: ldc.i4.1
IL_0019: box ""int""
IL_001e: ldc.i4.2
IL_001f: ldstr ""f""
IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0029: ldloca.s V_0
IL_002b: ldstr ""Literal""
IL_0030: call ""void CustomHandler.AppendLiteral(string)""
IL_0035: ldloc.0
IL_0036: br.s IL_0041
IL_0038: ldloca.s V_0
IL_003a: initobj ""CustomHandler""
IL_0040: ldloc.0
IL_0041: box ""CustomHandler""
IL_0046: call ""void System.Console.WriteLine(object)""
IL_004b: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void TernaryTypes_05(string expression)
{
// Same 01, but with a conversion from string to CustomHandler and CustomHandler to string.
var code = @"
using System;
var x = (bool)(object)false ? default(CustomHandler) : " + expression + @";
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator CustomHandler(string c) => throw null;
public static implicit operator string(CustomHandler c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (4,9): error CS0172: Type of conditional expression cannot be determined because 'CustomHandler' and 'string' implicitly convert to one another
// var x = (bool)(object)false ? default(CustomHandler) : $"{1,2:f}Literal";
Diagnostic(ErrorCode.ERR_AmbigQM, @"(bool)(object)false ? default(CustomHandler) : " + expression).WithArguments("CustomHandler", "string").WithLocation(4, 9)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void TernaryTypes_06(string expression)
{
// Same 05, but with a target type
var code = @"
using System;
CustomHandler x = (bool)(object)false ? default(CustomHandler) : " + expression + @";
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator CustomHandler(string c) => throw null;
public static implicit operator string(CustomHandler c) => c.ToString();
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 76 (0x4c)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.0
IL_0001: box ""bool""
IL_0006: unbox.any ""bool""
IL_000b: brtrue.s IL_0038
IL_000d: ldloca.s V_0
IL_000f: ldc.i4.7
IL_0010: ldc.i4.1
IL_0011: call ""CustomHandler..ctor(int, int)""
IL_0016: ldloca.s V_0
IL_0018: ldc.i4.1
IL_0019: box ""int""
IL_001e: ldc.i4.2
IL_001f: ldstr ""f""
IL_0024: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0029: ldloca.s V_0
IL_002b: ldstr ""Literal""
IL_0030: call ""void CustomHandler.AppendLiteral(string)""
IL_0035: ldloc.0
IL_0036: br.s IL_0041
IL_0038: ldloca.s V_0
IL_003a: initobj ""CustomHandler""
IL_0040: ldloc.0
IL_0041: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0046: call ""void System.Console.WriteLine(string)""
IL_004b: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void SwitchTypes_01(string expression)
{
// Switch expressions infer a best type based on _types_, not based on expressions (section 12.6.3.15 of the spec). Because this is based on types
// and not on expression conversions, no best type can be found for this switch expression.
var code = @"
using System;
var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" };
Console.WriteLine(x);
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (4,29): error CS8506: No best type was found for the switch expression.
// var x = (bool)(object)false switch { true => default(CustomHandler), false => $"{1,2:f}Literal" };
Diagnostic(ErrorCode.ERR_SwitchExpressionNoBestType, "switch").WithLocation(4, 29)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void SwitchTypes_02(string expression)
{
// Same as 01, but with a conversion from CustomHandler. This allows the switch expression to infer a best-common type, which is string.
var code = @"
using System;
CultureInfoNormalizer.Normalize();
var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" };
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator string(CustomHandler c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"1.00Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", !expression.Contains('+') ? @"
{
// Code size 59 (0x3b)
.maxstack 2
.locals init (string V_0,
CustomHandler V_1)
IL_0000: call ""void CultureInfoNormalizer.Normalize()""
IL_0005: ldc.i4.0
IL_0006: box ""bool""
IL_000b: unbox.any ""bool""
IL_0010: brfalse.s IL_0023
IL_0012: ldloca.s V_1
IL_0014: initobj ""CustomHandler""
IL_001a: ldloc.1
IL_001b: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0020: stloc.0
IL_0021: br.s IL_0034
IL_0023: ldstr ""{0,2:f}Literal""
IL_0028: ldc.i4.1
IL_0029: box ""int""
IL_002e: call ""string string.Format(string, object)""
IL_0033: stloc.0
IL_0034: ldloc.0
IL_0035: call ""void System.Console.WriteLine(string)""
IL_003a: ret
}
"
: @"
{
// Code size 69 (0x45)
.maxstack 2
.locals init (string V_0,
CustomHandler V_1)
IL_0000: call ""void CultureInfoNormalizer.Normalize()""
IL_0005: ldc.i4.0
IL_0006: box ""bool""
IL_000b: unbox.any ""bool""
IL_0010: brfalse.s IL_0023
IL_0012: ldloca.s V_1
IL_0014: initobj ""CustomHandler""
IL_001a: ldloc.1
IL_001b: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0020: stloc.0
IL_0021: br.s IL_003e
IL_0023: ldstr ""{0,2:f}""
IL_0028: ldc.i4.1
IL_0029: box ""int""
IL_002e: call ""string string.Format(string, object)""
IL_0033: ldstr ""Literal""
IL_0038: call ""string string.Concat(string, string)""
IL_003d: stloc.0
IL_003e: ldloc.0
IL_003f: call ""void System.Console.WriteLine(string)""
IL_0044: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void SwitchTypes_03(string expression)
{
// Same 02, but with a target-type. The natural type will fail to compile, so the switch will use a target type (unlike TernaryTypes_03, which fails to compile).
var code = @"
using System;
CustomHandler x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" };
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator string(CustomHandler c) => c.ToString();
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 79 (0x4f)
.maxstack 4
.locals init (CustomHandler V_0,
CustomHandler V_1)
IL_0000: ldc.i4.0
IL_0001: box ""bool""
IL_0006: unbox.any ""bool""
IL_000b: brfalse.s IL_0019
IL_000d: ldloca.s V_1
IL_000f: initobj ""CustomHandler""
IL_0015: ldloc.1
IL_0016: stloc.0
IL_0017: br.s IL_0043
IL_0019: ldloca.s V_1
IL_001b: ldc.i4.7
IL_001c: ldc.i4.1
IL_001d: call ""CustomHandler..ctor(int, int)""
IL_0022: ldloca.s V_1
IL_0024: ldc.i4.1
IL_0025: box ""int""
IL_002a: ldc.i4.2
IL_002b: ldstr ""f""
IL_0030: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0035: ldloca.s V_1
IL_0037: ldstr ""Literal""
IL_003c: call ""void CustomHandler.AppendLiteral(string)""
IL_0041: ldloc.1
IL_0042: stloc.0
IL_0043: ldloc.0
IL_0044: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0049: call ""void System.Console.WriteLine(string)""
IL_004e: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void SwitchTypes_04(string expression)
{
// Same as 01, but with a conversion to CustomHandler. This allows the switch expression to infer a best-common type, which is CustomHandler.
var code = @"
using System;
var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" };
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator CustomHandler(string c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 79 (0x4f)
.maxstack 4
.locals init (CustomHandler V_0,
CustomHandler V_1)
IL_0000: ldc.i4.0
IL_0001: box ""bool""
IL_0006: unbox.any ""bool""
IL_000b: brfalse.s IL_0019
IL_000d: ldloca.s V_1
IL_000f: initobj ""CustomHandler""
IL_0015: ldloc.1
IL_0016: stloc.0
IL_0017: br.s IL_0043
IL_0019: ldloca.s V_1
IL_001b: ldc.i4.7
IL_001c: ldc.i4.1
IL_001d: call ""CustomHandler..ctor(int, int)""
IL_0022: ldloca.s V_1
IL_0024: ldc.i4.1
IL_0025: box ""int""
IL_002a: ldc.i4.2
IL_002b: ldstr ""f""
IL_0030: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0035: ldloca.s V_1
IL_0037: ldstr ""Literal""
IL_003c: call ""void CustomHandler.AppendLiteral(string)""
IL_0041: ldloc.1
IL_0042: stloc.0
IL_0043: ldloc.0
IL_0044: box ""CustomHandler""
IL_0049: call ""void System.Console.WriteLine(object)""
IL_004e: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void SwitchTypes_05(string expression)
{
// Same as 01, but with conversions in both directions. No best common type can be found.
var code = @"
using System;
var x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" };
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator CustomHandler(string c) => throw null;
public static implicit operator string(CustomHandler c) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (4,29): error CS8506: No best type was found for the switch expression.
// var x = (bool)(object)false switch { true => default(CustomHandler), false => $"{1,2:f}Literal" };
Diagnostic(ErrorCode.ERR_SwitchExpressionNoBestType, "switch").WithLocation(4, 29)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void SwitchTypes_06(string expression)
{
// Same as 05, but with a target type.
var code = @"
using System;
CustomHandler x = (bool)(object)false switch { true => default(CustomHandler), false => " + expression + @" };
Console.WriteLine(x);
public partial struct CustomHandler
{
public static implicit operator CustomHandler(string c) => throw null;
public static implicit operator string(CustomHandler c) => c.ToString();
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 79 (0x4f)
.maxstack 4
.locals init (CustomHandler V_0,
CustomHandler V_1)
IL_0000: ldc.i4.0
IL_0001: box ""bool""
IL_0006: unbox.any ""bool""
IL_000b: brfalse.s IL_0019
IL_000d: ldloca.s V_1
IL_000f: initobj ""CustomHandler""
IL_0015: ldloc.1
IL_0016: stloc.0
IL_0017: br.s IL_0043
IL_0019: ldloca.s V_1
IL_001b: ldc.i4.7
IL_001c: ldc.i4.1
IL_001d: call ""CustomHandler..ctor(int, int)""
IL_0022: ldloca.s V_1
IL_0024: ldc.i4.1
IL_0025: box ""int""
IL_002a: ldc.i4.2
IL_002b: ldstr ""f""
IL_0030: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0035: ldloca.s V_1
IL_0037: ldstr ""Literal""
IL_003c: call ""void CustomHandler.AppendLiteral(string)""
IL_0041: ldloc.1
IL_0042: stloc.0
IL_0043: ldloc.0
IL_0044: call ""string CustomHandler.op_Implicit(CustomHandler)""
IL_0049: call ""void System.Console.WriteLine(string)""
IL_004e: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void PassAsRefWithoutKeyword_01(string expression)
{
var code = @"
M(" + expression + @");
void M(ref CustomHandler c) => System.Console.WriteLine(c);";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 48 (0x30)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.7
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldc.i4.1
IL_000c: box ""int""
IL_0011: ldc.i4.2
IL_0012: ldstr ""f""
IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_001c: ldloca.s V_0
IL_001e: ldstr ""Literal""
IL_0023: call ""void CustomHandler.AppendLiteral(string)""
IL_0028: ldloca.s V_0
IL_002a: call ""void Program.<<Main>$>g__M|0_0(ref CustomHandler)""
IL_002f: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void PassAsRefWithoutKeyword_02(string expression)
{
var code = $$"""
M({{expression}});
M(ref {{expression}});
void M(ref CustomHandler c) => System.Console.WriteLine(c);
""";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false) }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (1,3): error CS1620: Argument 1 must be passed with the 'ref' keyword
// M($"{1,2:f}Literal");
Diagnostic(ErrorCode.ERR_BadArgRef, expression).WithArguments("1", "ref").WithLocation(1, 3),
// (2,7): error CS1510: A ref or out value must be an assignable variable
// M(ref $"{1,2:f}Literal");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, expression).WithLocation(2, 7)
);
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void PassAsRefWithoutKeyword_03(string expression)
{
var code = @"
M(" + expression + @");
void M(in CustomHandler c) => System.Console.WriteLine(c);";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 45 (0x2d)
.maxstack 5
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.1
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: dup
IL_0008: ldc.i4.1
IL_0009: box ""int""
IL_000e: ldc.i4.2
IL_000f: ldstr ""f""
IL_0014: callvirt ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0019: dup
IL_001a: ldstr ""Literal""
IL_001f: callvirt ""void CustomHandler.AppendLiteral(string)""
IL_0024: stloc.0
IL_0025: ldloca.s V_0
IL_0027: call ""void Program.<<Main>$>g__M|0_0(in CustomHandler)""
IL_002c: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void PassAsRefWithoutKeyword_04(string expression)
{
var code = @"
M(" + expression + @");
void M(in CustomHandler c) => System.Console.WriteLine(c);";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 48 (0x30)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.7
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldc.i4.1
IL_000c: box ""int""
IL_0011: ldc.i4.2
IL_0012: ldstr ""f""
IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_001c: ldloca.s V_0
IL_001e: ldstr ""Literal""
IL_0023: call ""void CustomHandler.AppendLiteral(string)""
IL_0028: ldloca.s V_0
IL_002a: call ""void Program.<<Main>$>g__M|0_0(in CustomHandler)""
IL_002f: ret
}
");
}
[Theory]
[CombinatorialData]
public void RefOverloadResolution_Struct([CombinatorialValues("in", "ref")] string refKind, [CombinatorialValues(@"$""{1,2:f}Literal""", @"$""{1,2:f}"" + $""Literal""")] string expression)
{
var code = @"
C.M(" + expression + @");
class C
{
public static void M(CustomHandler c) => System.Console.WriteLine(c);
public static void M(" + refKind + @" CustomHandler c) => throw null;
}";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 47 (0x2f)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.7
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldc.i4.1
IL_000c: box ""int""
IL_0011: ldc.i4.2
IL_0012: ldstr ""f""
IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_001c: ldloca.s V_0
IL_001e: ldstr ""Literal""
IL_0023: call ""void CustomHandler.AppendLiteral(string)""
IL_0028: ldloc.0
IL_0029: call ""void C.M(CustomHandler)""
IL_002e: ret
}
");
}
[Theory]
[CombinatorialData]
public void RefOverloadResolution_Class([CombinatorialValues("in", "ref")] string refKind, [CombinatorialValues(@"$""{1,2:f}Literal""", @"$""{1,2:f}"" + $""Literal""")] string expression)
{
var code = @"
C.M(" + expression + @");
class C
{
public static void M(CustomHandler c) => System.Console.WriteLine(c);
public static void M(" + refKind + @" CustomHandler c) => System.Console.WriteLine(c);
}";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, targetFramework: TargetFramework.NetCoreApp);
VerifyInterpolatedStringExpression(comp);
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 47 (0x2f)
.maxstack 4
.locals init (CustomHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.7
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldc.i4.1
IL_000c: box ""int""
IL_0011: ldc.i4.2
IL_0012: ldstr ""f""
IL_0017: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_001c: ldloca.s V_0
IL_001e: ldstr ""Literal""
IL_0023: call ""void CustomHandler.AppendLiteral(string)""
IL_0028: ldloc.0
IL_0029: call ""void C.M(CustomHandler)""
IL_002e: ret
}
");
}
[Theory]
[InlineData(@"$""{1,2:f}Literal""")]
[InlineData(@"$""{1,2:f}"" + $""Literal""")]
public void RefOverloadResolution_MultipleBuilderTypes(string expression)
{
var code = @"
C.M(" + expression + @");
class C
{
public static void M(CustomHandler1 c) => System.Console.WriteLine(c);
public static void M(ref CustomHandler2 c) => throw null;
}";
var comp = CreateCompilation(new[]
{
code,
GetInterpolatedStringCustomHandlerType("CustomHandler1", "struct", useBoolReturns: false),
GetInterpolatedStringCustomHandlerType("CustomHandler2", "struct", useBoolReturns: false, includeOneTimeHelpers: false)
});
VerifyInterpolatedStringExpression(comp, "CustomHandler1");
var verifier = CompileAndVerifyOnCorrectPlatforms(comp, expectedOutput: @"
value:1
alignment:2
format:f
literal:Literal");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 47 (0x2f)
.maxstack 4
.locals init (CustomHandler1 V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.7
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler1..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldc.i4.1
IL_000c: box ""int""
IL_0011: ldc.i4.2
IL_0012: ldstr ""f""
IL_0017: call ""void CustomHandler1.AppendFormatted(object, int, string)""
IL_001c: ldloca.s V_0
IL_001e: ldstr ""Literal""
IL_0023: call ""void CustomHandler1.AppendLiteral(string)""
IL_0028: ldloc.0
IL_0029: call ""void C.M(CustomHandler1)""
IL_002e: ret
}
");
}
private const string InterpolatedStringHandlerAttributesVB = @"
Namespace System.Runtime.CompilerServices
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Struct, AllowMultiple:=False, Inherited:=False)>
Public NotInheritable Class InterpolatedStringHandlerAttribute
Inherits Attribute
End Class
<AttributeUsage(AttributeTargets.Parameter, AllowMultiple:=False, Inherited:=False)>
Public NotInheritable Class InterpolatedStringHandlerArgumentAttribute
Inherits Attribute
Public Sub New(argument As String)
Arguments = { argument }
End Sub
Public Sub New(ParamArray arguments() as String)
Me.Arguments = arguments
End Sub
Public ReadOnly Property Arguments As String()
End Class
End Namespace
";
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_NonHandlerType(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(" + expression + @");
class C
{
public static void M([InterpolatedStringHandlerArgumentAttribute] string s) {}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute });
comp.VerifyDiagnostics(
// (8,27): error CS8946: 'string' is not an interpolated string handler type.
// public static void M([InterpolatedStringHandlerArgumentAttribute] string s) {}
Diagnostic(ErrorCode.ERR_TypeIsNotAnInterpolatedStringHandlerType, "InterpolatedStringHandlerArgumentAttribute").WithArguments("string").WithLocation(8, 27)
);
var sParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
sParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(sParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(sParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_NonHandlerType_Metadata()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(i as Integer, <InterpolatedStringHandlerArgument(""i"")> c As String)
End Sub
End Class
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
// Note: there is no compilation error here because the natural type of a string is still string, and
// we just bind to that method without checking the handler attribute.
var comp = CreateCompilation(@"C.M(1, $"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics();
var sParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
sParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(sParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(sParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_InvalidArgument(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(" + expression + @");
class C
{
public static void M([InterpolatedStringHandlerArgumentAttribute(1)] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (8,70): error CS1503: Argument 1: cannot convert from 'int' to 'string'
// public static void M([InterpolatedStringHandlerArgumentAttribute(1)] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("1", "int", "string").WithLocation(8, 70)
);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.False(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_01(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(" + expression + @");
class C
{
public static void M([InterpolatedStringHandlerArgumentAttribute(""NonExistant"")] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M($"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 5),
// (8,27): error CS8945: 'NonExistant' is not a valid parameter name from 'C.M(CustomHandler)'.
// public static void M([InterpolatedStringHandlerArgumentAttribute("NonExistant")] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""NonExistant"")").WithArguments("NonExistant", "C.M(CustomHandler)").WithLocation(8, 27)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_01_FromMetadata()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(<InterpolatedStringHandlerArgument(""NonExistant"")> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M($"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 5),
// (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 5),
// (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 5)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_02(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(1, " + expression + @");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"", ""NonExistant"")] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 8),
// (8,34): error CS8945: 'NonExistant' is not a valid parameter name from 'C.M(int, CustomHandler)'.
// public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("i", "NonExistant")] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""i"", ""NonExistant"")").WithArguments("NonExistant", "C.M(int, CustomHandler)").WithLocation(8, 34)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_02_FromMetadata()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(i As Integer, <InterpolatedStringHandlerArgument(""i"", ""NonExistant"")> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M(1, $"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_03(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(1, " + expression + @");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""NonExistant1"", ""NonExistant2"")] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 8),
// (8,34): error CS8945: 'NonExistant1' is not a valid parameter name from 'C.M(int, CustomHandler)'.
// public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("NonExistant1", "NonExistant2")] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""NonExistant1"", ""NonExistant2"")").WithArguments("NonExistant1", "C.M(int, CustomHandler)").WithLocation(8, 34),
// (8,34): error CS8945: 'NonExistant2' is not a valid parameter name from 'C.M(int, CustomHandler)'.
// public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("NonExistant1", "NonExistant2")] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_InvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute(""NonExistant1"", ""NonExistant2"")").WithArguments("NonExistant2", "C.M(int, CustomHandler)").WithLocation(8, 34)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_UnknownName_03_FromMetadata()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(i As Integer, <InterpolatedStringHandlerArgument(""NonExistant1"", ""NonExistant2"")> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M(1, $"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_ReferenceSelf(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(1, " + expression + @");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""c"")] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 8),
// (8,34): error CS8948: InterpolatedStringHandlerArgumentAttribute arguments cannot refer to the parameter the attribute is used on.
// public static void M(int i, [InterpolatedStringHandlerArgumentAttribute("c")] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_CannotUseSelfAsInterpolatedStringHandlerArgument, @"InterpolatedStringHandlerArgumentAttribute(""c"")").WithLocation(8, 34)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_ReferencesSelf_FromMetadata()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(<InterpolatedStringHandlerArgument(""c"")> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M($"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 5),
// (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 5),
// (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 5)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_01(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(1, " + expression + @");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(new string[] { null })] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 8),
// (8,34): error CS8943: null is not a valid parameter name. To get access to the receiver of an instance method, use the empty string as the parameter name.
// public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(new string[] { null })] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_NullInvalidInterpolatedStringHandlerArgumentName, "InterpolatedStringHandlerArgumentAttribute(new string[] { null })").WithLocation(8, 34)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact, WorkItem(58025, "https://github.com/dotnet/roslyn/issues/58025")]
public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_02()
{
var code = @"
using System.Runtime.CompilerServices;
C.M(1, $"""");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute((string[])null)] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 8),
// (8,34): error CS8943: null is not a valid parameter name. To get access to the receiver of an instance method, use the empty string as the parameter name.
// public static void M(int i, [InterpolatedStringHandlerArgumentAttribute((string[])null)] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_NullInvalidInterpolatedStringHandlerArgumentName, "InterpolatedStringHandlerArgumentAttribute((string[])null)").WithLocation(8, 34)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_FromMetadata_01()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(i As Integer, <InterpolatedStringHandlerArgument({ Nothing })> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M(1, $"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_FromMetadata_02()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(i As Integer, <InterpolatedStringHandlerArgument({ Nothing, ""i"" })> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M(1, $"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_FromMetadata_03()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(i As Integer, <InterpolatedStringHandlerArgument(CStr(Nothing))> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M(1, $"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_NullConstant_FromMetadata_04()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(i As Integer, <InterpolatedStringHandlerArgument(DirectCast(Nothing, String()))> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M(1, $"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,8): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 8)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_ThisOnStaticMethod(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(" + expression + @");
class C
{
public static void M([InterpolatedStringHandlerArgumentAttribute("""")] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M($"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 5),
// (8,27): error CS8944: 'C.M(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument.
// public static void M([InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute("""")").WithArguments("C.M(CustomHandler)").WithLocation(8, 27)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"{""""}")]
[InlineData(@"""""")]
public void InterpolatedStringHandlerArgumentAttributeError_ThisOnStaticMethod_FromMetadata(string arg)
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(<InterpolatedStringHandlerArgument(" + arg + @")> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C.M($"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C.M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 5),
// (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 5),
// (1,5): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 5)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_ThisOnConstructor(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
_ = new C(" + expression + @");
class C
{
public C([InterpolatedStringHandlerArgumentAttribute("""")] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (4,11): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// _ = new C($"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 11),
// (8,15): error CS8944: 'C.C(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument.
// public C([InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c) {}
Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgumentAttribute("""")").WithArguments("C.C(CustomHandler)").WithLocation(8, 15)
);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod(".ctor").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"{""""}")]
[InlineData(@"""""")]
public void InterpolatedStringHandlerArgumentAttributeError_ThisOnConstructor_FromMetadata(string arg)
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Sub New(<InterpolatedStringHandlerArgument(" + arg + @")> c As CustomHandler)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"_ = new C($"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,11): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// _ = new C($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 11),
// (1,11): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// _ = new C($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 11),
// (1,11): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// _ = new C($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 11)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod(".ctor").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerAttributeArgumentError_SubstitutedTypeSymbol(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C<CustomHandler>.M(" + expression + @");
public class C<T>
{
public static void M([InterpolatedStringHandlerArgumentAttribute] T t) { }
}
";
var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, customHandler });
comp.VerifyDiagnostics(
// (4,20): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler t' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C<CustomHandler>.M($"" + $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, expression).WithArguments("CustomHandler t", "CustomHandler").WithLocation(4, 20),
// (8,27): error CS8946: 'T' is not an interpolated string handler type.
// public static void M([InterpolatedStringHandlerArgumentAttribute] T t) { }
Diagnostic(ErrorCode.ERR_TypeIsNotAnInterpolatedStringHandlerType, "InterpolatedStringHandlerArgumentAttribute").WithArguments("T").WithLocation(8, 27)
);
var c = comp.SourceModule.GlobalNamespace.GetTypeMember("C");
var handler = comp.SourceModule.GlobalNamespace.GetTypeMember("CustomHandler");
var substitutedC = c.WithTypeArguments(ImmutableArray.Create(TypeWithAnnotations.Create(handler)));
var cParam = substitutedC.GetMethod("M").Parameters.Single();
Assert.IsType<SubstitutedParameterSymbol>(cParam);
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_SubstitutedTypeSymbol_FromMetadata()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C(Of T)
Public Shared Sub M(<InterpolatedStringHandlerArgument()> c As T)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation(@"C<CustomHandler>.M($"""");", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics(
// (1,20): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// C<CustomHandler>.M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(1, 20),
// (1,20): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// C<CustomHandler>.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(1, 20),
// (1,20): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C<CustomHandler>.M($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(1, 20)
);
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C`1").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
Assert.True(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttributeWarn_ParameterAfterHandler([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""text""", @"$""text"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
public class C
{
public static void M([InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c, int i) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i:"" + i.ToString());
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var goodCode = @"
int i = 10;
C.M(i: i, c: " + expression + @");
";
var comp = CreateCompilation(new[] { code, goodCode, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate, expectedOutput: @"
i:10
literal:text
");
verifier.VerifyDiagnostics(
// (6,27): warning CS8947: Parameter 'i' occurs after 'c' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to
// reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved.
// public static void M([InterpolatedStringHandlerArgumentAttribute("i")] CustomHandler c, int i) => Console.WriteLine(c.ToString());
Diagnostic(ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter, @"InterpolatedStringHandlerArgumentAttribute(""i"")").WithArguments("i", "c").WithLocation(6, 27)
);
verifyIL(verifier);
var badCode = @"C.M(" + expression + @", 1);";
comp = CreateCompilation(new[] { code, badCode, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (1,10): error CS8950: Parameter 'i' is an argument to the interpolated string handler conversion on parameter 'c', but is specified after the interpolated string constant. Reorder the arguments to move 'i' before 'c'.
// C.M($"", 1);
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentLocatedAfterInterpolatedString, "1").WithArguments("i", "c").WithLocation(1, 7 + expression.Length),
// (6,27): warning CS8947: Parameter 'i' occurs after 'c' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to
// reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved.
// public static void M([InterpolatedStringHandlerArgumentAttribute("i")] CustomHandler c, int i) => Console.WriteLine(c.ToString());
Diagnostic(ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter, @"InterpolatedStringHandlerArgumentAttribute(""i"")").WithArguments("i", "c").WithLocation(6, 27)
);
static void validate(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.First();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(1, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
Assert.False(cParam.HasInterpolatedStringHandlerArgumentError);
}
void verifyIL(CompilationVerifier verifier)
{
verifier.VerifyIL("<top-level-statements-entry-point>", extraConstructorArg == ""
? @"
{
// Code size 36 (0x24)
.maxstack 4
.locals init (int V_0,
int V_1,
CustomHandler V_2)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: stloc.1
IL_0005: ldloca.s V_2
IL_0007: ldc.i4.4
IL_0008: ldc.i4.0
IL_0009: ldloc.0
IL_000a: call ""CustomHandler..ctor(int, int, int)""
IL_000f: ldloca.s V_2
IL_0011: ldstr ""text""
IL_0016: call ""bool CustomHandler.AppendLiteral(string)""
IL_001b: pop
IL_001c: ldloc.2
IL_001d: ldloc.1
IL_001e: call ""void C.M(CustomHandler, int)""
IL_0023: ret
}
"
: @"
{
// Code size 43 (0x2b)
.maxstack 4
.locals init (int V_0,
int V_1,
CustomHandler V_2,
bool V_3)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: stloc.1
IL_0005: ldc.i4.4
IL_0006: ldc.i4.0
IL_0007: ldloc.0
IL_0008: ldloca.s V_3
IL_000a: newobj ""CustomHandler..ctor(int, int, int, out bool)""
IL_000f: stloc.2
IL_0010: ldloc.3
IL_0011: brfalse.s IL_0021
IL_0013: ldloca.s V_2
IL_0015: ldstr ""text""
IL_001a: call ""bool CustomHandler.AppendLiteral(string)""
IL_001f: br.s IL_0022
IL_0021: ldc.i4.0
IL_0022: pop
IL_0023: ldloc.2
IL_0024: ldloc.1
IL_0025: call ""void C.M(CustomHandler, int)""
IL_002a: ret
}
");
}
}
[Fact]
public void InterpolatedStringHandlerArgumentAttributeWarn_ParameterAfterHandler_FromMetadata()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(<InterpolatedStringHandlerArgument(""i"")> c As CustomHandler, i As Integer)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var comp = CreateCompilation("", references: new[] { vbComp.EmitToImageReference() });
comp.VerifyEmitDiagnostics();
var customHandler = comp.GetTypeByMetadataName("CustomHandler");
Assert.True(customHandler.IsInterpolatedStringHandlerType);
var cParam = comp.GetTypeByMetadataName("C").GetMethod("M").Parameters.First();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(1, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
Assert.False(cParam.HasInterpolatedStringHandlerArgumentError);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_OptionalNotSpecifiedAtCallsite(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(" + expression + @");
public class C
{
public static void M([InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c, int i = 0) { }
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount)
{
}
}
";
var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, customHandler });
comp.VerifyDiagnostics(
// (4,5): error CS8951: Parameter 'i' is not explicitly provided, but is used as an argument to the interpolated string handler conversion on parameter 'c'. Specify the value of 'i' before 'c'.
// C.M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentOptionalNotSpecified, expression).WithArguments("i", "c").WithLocation(4, 5),
// (8,27): warning CS8947: Parameter 'i' occurs after 'c' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder
// parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved.
// public static void M([InterpolatedStringHandlerArgumentAttribute("i")] CustomHandler c, int i = 0) { }
Diagnostic(ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter, @"InterpolatedStringHandlerArgumentAttribute(""i"")").WithArguments("i", "c").WithLocation(8, 27)
);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttributeError_ParamsNotSpecifiedAtCallsite(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C.M(" + expression + @");
public class C
{
public static void M([InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c, params int[] i) { }
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int[] i) : this(literalLength, formattedCount)
{
}
}
";
var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, customHandler });
comp.VerifyDiagnostics(
// (4,5): error CS8951: Parameter 'i' is not explicitly provided, but is used as an argument to the interpolated string handler conversion on parameter 'c'. Specify the value of 'i' before 'c'.
// C.M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentOptionalNotSpecified, expression).WithArguments("i", "c").WithLocation(4, 5),
// (8,27): warning CS8947: Parameter 'i' occurs after 'c' in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder
// parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved.
// public static void M([InterpolatedStringHandlerArgumentAttribute("i")] CustomHandler c, params int[] i) { }
Diagnostic(ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter, @"InterpolatedStringHandlerArgumentAttribute(""i"")").WithArguments("i", "c").WithLocation(8, 27)
);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MissingConstructor(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
public class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
// https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback.
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate).VerifyDiagnostics();
CreateCompilation(@"C.M(1, " + expression + @");", new[] { comp.ToMetadataReference() }).VerifyDiagnostics(
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "3").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 4 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "4").WithLocation(1, 8)
);
static void validate(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
Assert.False(cParam.HasInterpolatedStringHandlerArgumentError);
}
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_InaccessibleConstructor_01(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
public class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) {}
}
public partial struct CustomHandler
{
private CustomHandler(int literalLength, int formattedCount, int i) : this() {}
static void InCustomHandler()
{
C.M(1, " + expression + @");
}
}
";
var executableCode = @"C.M(1, " + expression + @");";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (1,8): error CS0122: 'CustomHandler.CustomHandler(int, int, int)' is inaccessible due to its protection level
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadAccess, expression).WithArguments("CustomHandler.CustomHandler(int, int, int)").WithLocation(1, 8)
);
var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
// https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback.
CompileAndVerify(dependency, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics();
comp = CreateCompilation(executableCode, new[] { dependency.EmitToImageReference() });
comp.VerifyDiagnostics(
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 4 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "4").WithLocation(1, 8),
// (1,8): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, expression).WithArguments("CustomHandler", "3").WithLocation(1, 8)
);
comp = CreateCompilation(executableCode, new[] { dependency.ToMetadataReference() });
comp.VerifyDiagnostics(
// (1,8): error CS0122: 'CustomHandler.CustomHandler(int, int, int)' is inaccessible due to its protection level
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadAccess, expression).WithArguments("CustomHandler.CustomHandler(int, int, int)").WithLocation(1, 8)
);
static void validate(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
}
}
private void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(CSharpParseOptions parseOptions, string mRef, string customHandlerRef, string expression, params DiagnosticDescription[] expectedDiagnostics)
{
var code = @"
using System.Runtime.CompilerServices;
int i = 0;
C.M(" + mRef + @" i, " + expression + @");
public class C
{
public static void M(" + mRef + @" int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) { " + (mRef == "out" ? "i = 0;" : "") + @" }
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, " + customHandlerRef + @" int i) : this() { " + (customHandlerRef == "out" ? "i = 0;" : "") + @" }
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, parseOptions: parseOptions);
comp.VerifyDiagnostics(expectedDiagnostics);
var cParam = comp.SourceModule.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_RefNone(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "ref", "", expression,
// (5,9): error CS1615: Argument 3 may not be passed with the 'ref' keyword
// C.M(ref i, $"");
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "ref").WithLocation(5, 9));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_RefOut(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "ref", "out", expression,
// (5,9): error CS1620: Argument 3 must be passed with the 'out' keyword
// C.M(ref i, $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "out").WithLocation(5, 9));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_RefIn(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(TestOptions.Regular11, "ref", "in", expression,
// 0.cs(5,9): error CS9194: Argument 3 may not be passed with the 'ref' keyword in language version 11.0. To pass 'ref' arguments to 'in' parameters, upgrade to language version 12.0 or greater.
// C.M(ref i, $"");
Diagnostic(ErrorCode.ERR_BadArgExtraRefLangVersion, "i").WithArguments("3", "11.0", "12.0").WithLocation(5, 9));
}
[Theory, CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_RefIn_CSharp12(
[CombinatorialValues(@"$""text""", @"$""text"" + $""""")] string expression)
{
var code = $$"""
using System;
using System.Runtime.CompilerServices;
int x = 10;
C.M(ref x, {{expression}});
public class C
{
public static void M(ref int i, [InterpolatedStringHandlerArgumentAttribute("i")] CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, in int i) : this(literalLength, formattedCount)
{
_builder.AppendLine("i:" + i.ToString());
}
}
""";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate, expectedOutput: """
i:10
literal:text
""");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", """
{
// Code size 36 (0x24)
.maxstack 4
.locals init (int V_0, //x
int& V_1,
CustomHandler V_2)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldloca.s V_0
IL_0005: stloc.1
IL_0006: ldloc.1
IL_0007: ldc.i4.4
IL_0008: ldc.i4.0
IL_0009: ldloc.1
IL_000a: newobj "CustomHandler..ctor(int, int, in int)"
IL_000f: stloc.2
IL_0010: ldloca.s V_2
IL_0012: ldstr "text"
IL_0017: call "bool CustomHandler.AppendLiteral(string)"
IL_001c: pop
IL_001d: ldloc.2
IL_001e: call "void C.M(ref int, CustomHandler)"
IL_0023: ret
}
""");
static void validate(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
Assert.False(cParam.HasInterpolatedStringHandlerArgumentError);
}
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_InNone(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "in", "", expression,
// (5,8): error CS1615: Argument 3 may not be passed with the 'in' keyword
// C.M(in i, $"");
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "in").WithLocation(5, 8));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_InOut(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "in", "out", expression,
// (5,8): error CS1620: Argument 3 must be passed with the 'out' keyword
// C.M(in i, $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "out").WithLocation(5, 8));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_InRef(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "in", "ref", expression,
// (5,8): error CS1620: Argument 3 must be passed with the 'ref' keyword
// C.M(in i, $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(5, 8));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_OutNone(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "out", "", expression,
// (5,9): error CS1615: Argument 3 may not be passed with the 'out' keyword
// C.M(out i, $"");
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("3", "out").WithLocation(5, 9));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_OutRef(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "out", "ref", expression,
// (5,9): error CS1620: Argument 3 must be passed with the 'ref' keyword
// C.M(out i, $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(5, 9));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_NoneRef(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "", "ref", expression,
// (5,6): error CS1620: Argument 3 must be passed with the 'ref' keyword
// C.M( i, $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "ref").WithLocation(5, 6));
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes_NoneOut(string expression)
{
InterpolatedStringHandlerArgumentAttribute_MismatchedRefTypes(null, "", "out", expression,
// (5,6): error CS1620: Argument 3 must be passed with the 'out' keyword
// C.M( i, $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("3", "out").WithLocation(5, 6));
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_MismatchedType([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""""", @"$"""" + $""""")] string expression)
{
var code = @"
using System.Runtime.CompilerServices;
public class C
{
public static void M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) {}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, string s" + extraConstructorArg + @") : this()
{
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var executableCode = @"C.M(1, " + expression + @");";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var expectedDiagnostics = extraConstructorArg == ""
? new DiagnosticDescription[]
{
// (1,5): error CS1503: Argument 3: cannot convert from 'int' to 'string'
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("3", "int", "string").WithLocation(1, 5)
}
: new DiagnosticDescription[]
{
// (1,5): error CS1503: Argument 3: cannot convert from 'int' to 'string'
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("3", "int", "string").WithLocation(1, 5),
// (1,8): error CS7036: There is no argument given that corresponds to the required parameter 'success' of 'CustomHandler.CustomHandler(int, int, string, out bool)'
// C.M(1, $"");
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("success", "CustomHandler.CustomHandler(int, int, string, out bool)").WithLocation(1, 8)
};
var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(expectedDiagnostics);
// https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback.
var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
CompileAndVerify(dependency, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics();
foreach (var d in new[] { dependency.EmitToImageReference(), dependency.ToMetadataReference() })
{
comp = CreateCompilation(executableCode, new[] { d });
comp.VerifyDiagnostics(expectedDiagnostics);
}
static void validate(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_SingleArg([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""2""", @"$""2"" + $""""")] string expression)
{
var code = @"
using System.Runtime.CompilerServices;
public class C
{
public static string M(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")] CustomHandler c) => c.ToString();
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i:"" + i.ToString());
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var executableCode = @"
using System;
int i = 10;
Console.WriteLine(C.M(i, " + expression + @"));
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
i:10
literal:2");
verifier.VerifyDiagnostics();
verifyIL(extraConstructorArg, verifier);
var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
foreach (var d in new[] { dependency.EmitToImageReference(), dependency.ToMetadataReference() })
{
verifier = CompileAndVerify(executableCode, new[] { d }, expectedOutput: @"
i:10
literal:2");
verifier.VerifyDiagnostics();
verifyIL(extraConstructorArg, verifier);
}
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(0, cParam.InterpolatedStringHandlerArgumentIndexes.Single());
}
static void verifyIL(string extraConstructorArg, CompilationVerifier verifier)
{
verifier.VerifyIL("<top-level-statements-entry-point>", extraConstructorArg == ""
? @"
{
// Code size 39 (0x27)
.maxstack 5
.locals init (int V_0,
CustomHandler V_1)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldloca.s V_1
IL_0006: ldc.i4.1
IL_0007: ldc.i4.0
IL_0008: ldloc.0
IL_0009: call ""CustomHandler..ctor(int, int, int)""
IL_000e: ldloca.s V_1
IL_0010: ldstr ""2""
IL_0015: call ""bool CustomHandler.AppendLiteral(string)""
IL_001a: pop
IL_001b: ldloc.1
IL_001c: call ""string C.M(int, CustomHandler)""
IL_0021: call ""void System.Console.WriteLine(string)""
IL_0026: ret
}
"
: @"
{
// Code size 46 (0x2e)
.maxstack 5
.locals init (int V_0,
CustomHandler V_1,
bool V_2)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldc.i4.1
IL_0005: ldc.i4.0
IL_0006: ldloc.0
IL_0007: ldloca.s V_2
IL_0009: newobj ""CustomHandler..ctor(int, int, int, out bool)""
IL_000e: stloc.1
IL_000f: ldloc.2
IL_0010: brfalse.s IL_0020
IL_0012: ldloca.s V_1
IL_0014: ldstr ""2""
IL_0019: call ""bool CustomHandler.AppendLiteral(string)""
IL_001e: br.s IL_0021
IL_0020: ldc.i4.0
IL_0021: pop
IL_0022: ldloc.1
IL_0023: call ""string C.M(int, CustomHandler)""
IL_0028: call ""void System.Console.WriteLine(string)""
IL_002d: ret
}
");
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_MultipleArgs([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
public class C
{
public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i, string s" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i:"" + i.ToString());
_builder.AppendLine(""s:"" + s);
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var executableCode = @"
int i = 10;
string s = ""arg"";
C.M(i, s, " + expression + @");
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler });
string expectedOutput = @"
i:10
s:arg
literal:literal
";
var verifier = base.CompileAndVerify((Compilation)comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: expectedOutput);
verifier.VerifyDiagnostics();
verifyIL(extraConstructorArg, verifier);
var dependency = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
foreach (var d in new[] { dependency.EmitToImageReference(), dependency.ToMetadataReference() })
{
verifier = CompileAndVerify(executableCode, new[] { d }, expectedOutput: expectedOutput);
verifier.VerifyDiagnostics();
verifyIL(extraConstructorArg, verifier);
}
static void validator(ModuleSymbol verifier)
{
var cParam = verifier.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 0, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
static void verifyIL(string extraConstructorArg, CompilationVerifier verifier)
{
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 44 (0x2c)
.maxstack 7
.locals init (string V_0, //s
int V_1,
string V_2,
CustomHandler V_3)
IL_0000: ldc.i4.s 10
IL_0002: ldstr ""arg""
IL_0007: stloc.0
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: ldloc.0
IL_000b: stloc.2
IL_000c: ldloc.2
IL_000d: ldloca.s V_3
IL_000f: ldc.i4.7
IL_0010: ldc.i4.0
IL_0011: ldloc.1
IL_0012: ldloc.2
IL_0013: call ""CustomHandler..ctor(int, int, int, string)""
IL_0018: ldloca.s V_3
IL_001a: ldstr ""literal""
IL_001f: call ""bool CustomHandler.AppendLiteral(string)""
IL_0024: pop
IL_0025: ldloc.3
IL_0026: call ""void C.M(int, string, CustomHandler)""
IL_002b: ret
}
"
: @"
{
// Code size 52 (0x34)
.maxstack 7
.locals init (string V_0, //s
int V_1,
string V_2,
CustomHandler V_3,
bool V_4)
IL_0000: ldc.i4.s 10
IL_0002: ldstr ""arg""
IL_0007: stloc.0
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: ldloc.0
IL_000b: stloc.2
IL_000c: ldloc.2
IL_000d: ldc.i4.7
IL_000e: ldc.i4.0
IL_000f: ldloc.1
IL_0010: ldloc.2
IL_0011: ldloca.s V_4
IL_0013: newobj ""CustomHandler..ctor(int, int, int, string, out bool)""
IL_0018: stloc.3
IL_0019: ldloc.s V_4
IL_001b: brfalse.s IL_002b
IL_001d: ldloca.s V_3
IL_001f: ldstr ""literal""
IL_0024: call ""bool CustomHandler.AppendLiteral(string)""
IL_0029: br.s IL_002c
IL_002b: ldc.i4.0
IL_002c: pop
IL_002d: ldloc.3
IL_002e: call ""void C.M(int, string, CustomHandler)""
IL_0033: ret
}
");
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_RefKindsMatch([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression,
[CombinatorialValues("in", "ref readonly")] string modifier)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
int i = 1;
string s = null;
object o;
C.M(i, ref s, out o, " + expression + @");
Console.WriteLine(s);
Console.WriteLine(o);
public class C
{
public static void M(" + modifier + @" int i, ref string s, out object o, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"", ""o"")] CustomHandler c)
{
Console.WriteLine(s);
o = ""o in M"";
s = ""s in M"";
Console.Write(c.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, " + modifier + @" int i, ref string s, out object o" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
o = null;
s = ""s in constructor"";
_builder.AppendLine(""i:"" + i.ToString());
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
s in constructor
i:1
literal:literal
s in M
o in M
");
verifier.VerifyDiagnostics(modifier == "ref readonly"
? new[]
{
// 0.cs(8,5): warning CS9192: Argument 1 should be passed with 'ref' or 'in' keyword
// C.M(i, ref s, out o, $"literal");
Diagnostic(ErrorCode.WRN_ArgExpectedRefOrIn, "i").WithArguments("1").WithLocation(8, 5)
}
: DiagnosticDescription.None);
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 67 (0x43)
.maxstack 8
.locals init (int V_0, //i
string V_1, //s
object V_2, //o
int& V_3,
string& V_4,
object& V_5,
CustomHandler V_6)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldloca.s V_0
IL_0006: stloc.3
IL_0007: ldloc.3
IL_0008: ldloca.s V_1
IL_000a: stloc.s V_4
IL_000c: ldloc.s V_4
IL_000e: ldloca.s V_2
IL_0010: stloc.s V_5
IL_0012: ldloc.s V_5
IL_0014: ldc.i4.7
IL_0015: ldc.i4.0
IL_0016: ldloc.3
IL_0017: ldloc.s V_4
IL_0019: ldloc.s V_5
IL_001b: newobj ""CustomHandler..ctor(int, int, " + modifier + @" int, ref string, out object)""
IL_0020: stloc.s V_6
IL_0022: ldloca.s V_6
IL_0024: ldstr ""literal""
IL_0029: call ""bool CustomHandler.AppendLiteral(string)""
IL_002e: pop
IL_002f: ldloc.s V_6
IL_0031: call ""void C.M(" + modifier + @" int, ref string, out object, CustomHandler)""
IL_0036: ldloc.1
IL_0037: call ""void System.Console.WriteLine(string)""
IL_003c: ldloc.2
IL_003d: call ""void System.Console.WriteLine(object)""
IL_0042: ret
}
"
: @"
{
// Code size 76 (0x4c)
.maxstack 9
.locals init (int V_0, //i
string V_1, //s
object V_2, //o
int& V_3,
string& V_4,
object& V_5,
CustomHandler V_6,
bool V_7)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldnull
IL_0003: stloc.1
IL_0004: ldloca.s V_0
IL_0006: stloc.3
IL_0007: ldloc.3
IL_0008: ldloca.s V_1
IL_000a: stloc.s V_4
IL_000c: ldloc.s V_4
IL_000e: ldloca.s V_2
IL_0010: stloc.s V_5
IL_0012: ldloc.s V_5
IL_0014: ldc.i4.7
IL_0015: ldc.i4.0
IL_0016: ldloc.3
IL_0017: ldloc.s V_4
IL_0019: ldloc.s V_5
IL_001b: ldloca.s V_7
IL_001d: newobj ""CustomHandler..ctor(int, int, " + modifier + @" int, ref string, out object, out bool)""
IL_0022: stloc.s V_6
IL_0024: ldloc.s V_7
IL_0026: brfalse.s IL_0036
IL_0028: ldloca.s V_6
IL_002a: ldstr ""literal""
IL_002f: call ""bool CustomHandler.AppendLiteral(string)""
IL_0034: br.s IL_0037
IL_0036: ldc.i4.0
IL_0037: pop
IL_0038: ldloc.s V_6
IL_003a: call ""void C.M(" + modifier + @" int, ref string, out object, CustomHandler)""
IL_003f: ldloc.1
IL_0040: call ""void System.Console.WriteLine(string)""
IL_0045: ldloc.2
IL_0046: call ""void System.Console.WriteLine(object)""
IL_004b: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(3).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 0, 1, 2 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_ReorderedAttributePositions([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(GetInt(), GetString(), " + expression + @");
int GetInt()
{
Console.WriteLine(""GetInt"");
return 10;
}
string GetString()
{
Console.WriteLine(""GetString"");
return ""str"";
}
public class C
{
public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""s"", ""i"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, string s, int i" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""s:"" + s);
_builder.AppendLine(""i:"" + i.ToString());
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
GetInt
GetString
s:str
i:10
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 45 (0x2d)
.maxstack 7
.locals init (string V_0,
int V_1,
CustomHandler V_2)
IL_0000: call ""int Program.<<Main>$>g__GetInt|0_0()""
IL_0005: stloc.1
IL_0006: ldloc.1
IL_0007: call ""string Program.<<Main>$>g__GetString|0_1()""
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: ldloca.s V_2
IL_0010: ldc.i4.7
IL_0011: ldc.i4.0
IL_0012: ldloc.0
IL_0013: ldloc.1
IL_0014: call ""CustomHandler..ctor(int, int, string, int)""
IL_0019: ldloca.s V_2
IL_001b: ldstr ""literal""
IL_0020: call ""bool CustomHandler.AppendLiteral(string)""
IL_0025: pop
IL_0026: ldloc.2
IL_0027: call ""void C.M(int, string, CustomHandler)""
IL_002c: ret
}
"
: @"
{
// Code size 52 (0x34)
.maxstack 7
.locals init (string V_0,
int V_1,
CustomHandler V_2,
bool V_3)
IL_0000: call ""int Program.<<Main>$>g__GetInt|0_0()""
IL_0005: stloc.1
IL_0006: ldloc.1
IL_0007: call ""string Program.<<Main>$>g__GetString|0_1()""
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: ldc.i4.7
IL_000f: ldc.i4.0
IL_0010: ldloc.0
IL_0011: ldloc.1
IL_0012: ldloca.s V_3
IL_0014: newobj ""CustomHandler..ctor(int, int, string, int, out bool)""
IL_0019: stloc.2
IL_001a: ldloc.3
IL_001b: brfalse.s IL_002b
IL_001d: ldloca.s V_2
IL_001f: ldstr ""literal""
IL_0024: call ""bool CustomHandler.AppendLiteral(string)""
IL_0029: br.s IL_002c
IL_002b: ldc.i4.0
IL_002c: pop
IL_002d: ldloc.2
IL_002e: call ""void C.M(int, string, CustomHandler)""
IL_0033: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 1, 0 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_ParametersReordered([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
GetC().M(s: GetString(), i: GetInt(), c: " + expression + @");
C GetC()
{
Console.WriteLine(""GetC"");
return new C { Field = 5 };
}
int GetInt()
{
Console.WriteLine(""GetInt"");
return 10;
}
string GetString()
{
Console.WriteLine(""GetString"");
return ""str"";
}
public class C
{
public int Field;
public void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""s"", """", ""i"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, string s, C c, int i" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""s:"" + s);
_builder.AppendLine(""c.Field:"" + c.Field.ToString());
_builder.AppendLine(""i:"" + i.ToString());
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
GetC
GetString
GetInt
s:str
c.Field:5
i:10
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 56 (0x38)
.maxstack 9
.locals init (C V_0,
string V_1,
int V_2,
string V_3,
CustomHandler V_4)
IL_0000: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call ""string Program.<<Main>$>g__GetString|0_2()""
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: stloc.3
IL_000f: call ""int Program.<<Main>$>g__GetInt|0_1()""
IL_0014: stloc.2
IL_0015: ldloc.2
IL_0016: ldloc.3
IL_0017: ldloca.s V_4
IL_0019: ldc.i4.7
IL_001a: ldc.i4.0
IL_001b: ldloc.1
IL_001c: ldloc.0
IL_001d: ldloc.2
IL_001e: call ""CustomHandler..ctor(int, int, string, C, int)""
IL_0023: ldloca.s V_4
IL_0025: ldstr ""literal""
IL_002a: call ""bool CustomHandler.AppendLiteral(string)""
IL_002f: pop
IL_0030: ldloc.s V_4
IL_0032: callvirt ""void C.M(int, string, CustomHandler)""
IL_0037: ret
}
"
: @"
{
// Code size 65 (0x41)
.maxstack 9
.locals init (C V_0,
string V_1,
int V_2,
string V_3,
CustomHandler V_4,
bool V_5)
IL_0000: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call ""string Program.<<Main>$>g__GetString|0_2()""
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: stloc.3
IL_000f: call ""int Program.<<Main>$>g__GetInt|0_1()""
IL_0014: stloc.2
IL_0015: ldloc.2
IL_0016: ldloc.3
IL_0017: ldc.i4.7
IL_0018: ldc.i4.0
IL_0019: ldloc.1
IL_001a: ldloc.0
IL_001b: ldloc.2
IL_001c: ldloca.s V_5
IL_001e: newobj ""CustomHandler..ctor(int, int, string, C, int, out bool)""
IL_0023: stloc.s V_4
IL_0025: ldloc.s V_5
IL_0027: brfalse.s IL_0037
IL_0029: ldloca.s V_4
IL_002b: ldstr ""literal""
IL_0030: call ""bool CustomHandler.AppendLiteral(string)""
IL_0035: br.s IL_0038
IL_0037: ldc.i4.0
IL_0038: pop
IL_0039: ldloc.s V_4
IL_003b: callvirt ""void C.M(int, string, CustomHandler)""
IL_0040: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 1, -1, 0 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_Duplicated([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(GetInt(), """", " + expression + @");
int GetInt()
{
Console.WriteLine(""GetInt"");
return 10;
}
public class C
{
public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""i"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i1, int i2" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i1:"" + i1.ToString());
_builder.AppendLine(""i2:"" + i2.ToString());
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
GetInt
i1:10
i2:10
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 43 (0x2b)
.maxstack 7
.locals init (int V_0,
CustomHandler V_1)
IL_0000: call ""int Program.<<Main>$>g__GetInt|0_0()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldstr """"
IL_000c: ldloca.s V_1
IL_000e: ldc.i4.7
IL_000f: ldc.i4.0
IL_0010: ldloc.0
IL_0011: ldloc.0
IL_0012: call ""CustomHandler..ctor(int, int, int, int)""
IL_0017: ldloca.s V_1
IL_0019: ldstr ""literal""
IL_001e: call ""bool CustomHandler.AppendLiteral(string)""
IL_0023: pop
IL_0024: ldloc.1
IL_0025: call ""void C.M(int, string, CustomHandler)""
IL_002a: ret
}
"
: @"
{
// Code size 50 (0x32)
.maxstack 7
.locals init (int V_0,
CustomHandler V_1,
bool V_2)
IL_0000: call ""int Program.<<Main>$>g__GetInt|0_0()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldstr """"
IL_000c: ldc.i4.7
IL_000d: ldc.i4.0
IL_000e: ldloc.0
IL_000f: ldloc.0
IL_0010: ldloca.s V_2
IL_0012: newobj ""CustomHandler..ctor(int, int, int, int, out bool)""
IL_0017: stloc.1
IL_0018: ldloc.2
IL_0019: brfalse.s IL_0029
IL_001b: ldloca.s V_1
IL_001d: ldstr ""literal""
IL_0022: call ""bool CustomHandler.AppendLiteral(string)""
IL_0027: br.s IL_002a
IL_0029: ldc.i4.0
IL_002a: pop
IL_002b: ldloc.1
IL_002c: call ""void C.M(int, string, CustomHandler)""
IL_0031: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 0, 0 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_EmptyWithMatchingConstructor([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""""", @"$"""" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(1, """", " + expression + @");
public class C
{
public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute()] CustomHandler c) => Console.WriteLine(c.ToString());
}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount" + extraConstructorArg + @")
{
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: "CustomHandler").VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 19 (0x13)
.maxstack 4
IL_0000: ldc.i4.1
IL_0001: ldstr """"
IL_0006: ldc.i4.0
IL_0007: ldc.i4.0
IL_0008: newobj ""CustomHandler..ctor(int, int)""
IL_000d: call ""void C.M(int, string, CustomHandler)""
IL_0012: ret
}
"
: @"
{
// Code size 21 (0x15)
.maxstack 5
.locals init (bool V_0)
IL_0000: ldc.i4.1
IL_0001: ldstr """"
IL_0006: ldc.i4.0
IL_0007: ldc.i4.0
IL_0008: ldloca.s V_0
IL_000a: newobj ""CustomHandler..ctor(int, int, out bool)""
IL_000f: call ""void C.M(int, string, CustomHandler)""
IL_0014: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_EmptyWithoutMatchingConstructor([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""""", @"$"""" + $""""")] string expression)
{
var code = @"
using System.Runtime.CompilerServices;
public class C
{
public static void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute()] CustomHandler c) { }
}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i" + extraConstructorArg + @")
{
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute });
// https://github.com/dotnet/roslyn/issues/53981 tracks warning here in the future, with user feedback.
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics();
CreateCompilation(@"C.M(1, """", " + expression + @");", new[] { comp.EmitToImageReference() }).VerifyDiagnostics(
(extraConstructorArg == "")
? new[]
{
// (1,12): error CS7036: There is no argument given that corresponds to the required parameter 'i' of 'CustomHandler.CustomHandler(int, int, int)'
// C.M(1, "", $"");
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("i", "CustomHandler.CustomHandler(int, int, int)").WithLocation(1, 12),
// (1,12): error CS1615: Argument 3 may not be passed with the 'out' keyword
// C.M(1, "", $"");
Diagnostic(ErrorCode.ERR_BadArgExtraRef, expression).WithArguments("3", "out").WithLocation(1, 12)
}
: new[]
{
// (1,12): error CS7036: There is no argument given that corresponds to the required parameter 'i' of 'CustomHandler.CustomHandler(int, int, int, out bool)'
// C.M(1, "", $"");
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("i", "CustomHandler.CustomHandler(int, int, int, out bool)").WithLocation(1, 12),
// (1,12): error CS7036: There is no argument given that corresponds to the required parameter 'success' of 'CustomHandler.CustomHandler(int, int, int, out bool)'
// C.M(1, "", $"");
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("success", "CustomHandler.CustomHandler(int, int, int, out bool)").WithLocation(1, 12)
}
);
static void validate(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Empty(cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_OnIndexerRvalue([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
var c = new C();
Console.WriteLine(c[10, ""str"", " + expression + @"]);
public class C
{
public string this[int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"")] CustomHandler c] { get => c.ToString(); }
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i1, string s" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i1:"" + i1.ToString());
_builder.AppendLine(""s:"" + s);
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
i1:10
s:str
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 52 (0x34)
.maxstack 8
.locals init (int V_0,
string V_1,
CustomHandler V_2)
IL_0000: newobj ""C..ctor()""
IL_0005: ldc.i4.s 10
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldstr ""str""
IL_000e: stloc.1
IL_000f: ldloc.1
IL_0010: ldloca.s V_2
IL_0012: ldc.i4.7
IL_0013: ldc.i4.0
IL_0014: ldloc.0
IL_0015: ldloc.1
IL_0016: call ""CustomHandler..ctor(int, int, int, string)""
IL_001b: ldloca.s V_2
IL_001d: ldstr ""literal""
IL_0022: call ""bool CustomHandler.AppendLiteral(string)""
IL_0027: pop
IL_0028: ldloc.2
IL_0029: callvirt ""string C.this[int, string, CustomHandler].get""
IL_002e: call ""void System.Console.WriteLine(string)""
IL_0033: ret
}
"
: @"
{
// Code size 59 (0x3b)
.maxstack 8
.locals init (int V_0,
string V_1,
CustomHandler V_2,
bool V_3)
IL_0000: newobj ""C..ctor()""
IL_0005: ldc.i4.s 10
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldstr ""str""
IL_000e: stloc.1
IL_000f: ldloc.1
IL_0010: ldc.i4.7
IL_0011: ldc.i4.0
IL_0012: ldloc.0
IL_0013: ldloc.1
IL_0014: ldloca.s V_3
IL_0016: newobj ""CustomHandler..ctor(int, int, int, string, out bool)""
IL_001b: stloc.2
IL_001c: ldloc.3
IL_001d: brfalse.s IL_002d
IL_001f: ldloca.s V_2
IL_0021: ldstr ""literal""
IL_0026: call ""bool CustomHandler.AppendLiteral(string)""
IL_002b: br.s IL_002e
IL_002d: ldc.i4.0
IL_002e: pop
IL_002f: ldloc.2
IL_0030: callvirt ""string C.this[int, string, CustomHandler].get""
IL_0035: call ""void System.Console.WriteLine(string)""
IL_003a: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetIndexer<PropertySymbol>("Item").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 0, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_OnIndexerLvalue([CombinatorialValues("", ", out bool success")] string extraConstructorArg,
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
var c = new C();
c[10, ""str"", " + expression + @"] = """";
public class C
{
public string this[int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", ""s"")] CustomHandler c] { set => Console.WriteLine(c.ToString()); }
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i1, string s" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i1:"" + i1.ToString());
_builder.AppendLine(""s:"" + s);
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
i1:10
s:str
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 52 (0x34)
.maxstack 8
.locals init (int V_0,
string V_1,
CustomHandler V_2)
IL_0000: newobj ""C..ctor()""
IL_0005: ldc.i4.s 10
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldstr ""str""
IL_000e: stloc.1
IL_000f: ldloc.1
IL_0010: ldloca.s V_2
IL_0012: ldc.i4.7
IL_0013: ldc.i4.0
IL_0014: ldloc.0
IL_0015: ldloc.1
IL_0016: call ""CustomHandler..ctor(int, int, int, string)""
IL_001b: ldloca.s V_2
IL_001d: ldstr ""literal""
IL_0022: call ""bool CustomHandler.AppendLiteral(string)""
IL_0027: pop
IL_0028: ldloc.2
IL_0029: ldstr """"
IL_002e: callvirt ""void C.this[int, string, CustomHandler].set""
IL_0033: ret
}
"
: @"
{
// Code size 59 (0x3b)
.maxstack 8
.locals init (int V_0,
string V_1,
CustomHandler V_2,
bool V_3)
IL_0000: newobj ""C..ctor()""
IL_0005: ldc.i4.s 10
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldstr ""str""
IL_000e: stloc.1
IL_000f: ldloc.1
IL_0010: ldc.i4.7
IL_0011: ldc.i4.0
IL_0012: ldloc.0
IL_0013: ldloc.1
IL_0014: ldloca.s V_3
IL_0016: newobj ""CustomHandler..ctor(int, int, int, string, out bool)""
IL_001b: stloc.2
IL_001c: ldloc.3
IL_001d: brfalse.s IL_002d
IL_001f: ldloca.s V_2
IL_0021: ldstr ""literal""
IL_0026: call ""bool CustomHandler.AppendLiteral(string)""
IL_002b: br.s IL_002e
IL_002d: ldc.i4.0
IL_002e: pop
IL_002f: ldloc.2
IL_0030: ldstr """"
IL_0035: callvirt ""void C.this[int, string, CustomHandler].set""
IL_003a: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetIndexer<PropertySymbol>("Item").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 0, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_ThisParameter([CombinatorialValues("", ", out bool success")] string extraConstructorArg, [CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
(new C(5)).M((int)10, ""str"", " + expression + @");
public class C
{
public int Prop { get; }
public C(int i) => Prop = i;
public void M(int i, string s, [InterpolatedStringHandlerArgumentAttribute(""i"", """", ""s"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i1, C c, string s" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i1:"" + i1.ToString());
_builder.AppendLine(""c.Prop:"" + c.Prop.ToString());
_builder.AppendLine(""s:"" + s);
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
i1:10
c.Prop:5
s:str
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", (extraConstructorArg == "")
? @"
{
// Code size 51 (0x33)
.maxstack 9
.locals init (C V_0,
int V_1,
string V_2,
CustomHandler V_3)
IL_0000: ldc.i4.5
IL_0001: newobj ""C..ctor(int)""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 10
IL_000a: stloc.1
IL_000b: ldloc.1
IL_000c: ldstr ""str""
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: ldloca.s V_3
IL_0015: ldc.i4.7
IL_0016: ldc.i4.0
IL_0017: ldloc.1
IL_0018: ldloc.0
IL_0019: ldloc.2
IL_001a: call ""CustomHandler..ctor(int, int, int, C, string)""
IL_001f: ldloca.s V_3
IL_0021: ldstr ""literal""
IL_0026: call ""bool CustomHandler.AppendLiteral(string)""
IL_002b: pop
IL_002c: ldloc.3
IL_002d: callvirt ""void C.M(int, string, CustomHandler)""
IL_0032: ret
}
"
: @"
{
// Code size 59 (0x3b)
.maxstack 9
.locals init (C V_0,
int V_1,
string V_2,
CustomHandler V_3,
bool V_4)
IL_0000: ldc.i4.5
IL_0001: newobj ""C..ctor(int)""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 10
IL_000a: stloc.1
IL_000b: ldloc.1
IL_000c: ldstr ""str""
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: ldc.i4.7
IL_0014: ldc.i4.0
IL_0015: ldloc.1
IL_0016: ldloc.0
IL_0017: ldloc.2
IL_0018: ldloca.s V_4
IL_001a: newobj ""CustomHandler..ctor(int, int, int, C, string, out bool)""
IL_001f: stloc.3
IL_0020: ldloc.s V_4
IL_0022: brfalse.s IL_0032
IL_0024: ldloca.s V_3
IL_0026: ldstr ""literal""
IL_002b: call ""bool CustomHandler.AppendLiteral(string)""
IL_0030: br.s IL_0033
IL_0032: ldc.i4.0
IL_0033: pop
IL_0034: ldloc.3
IL_0035: callvirt ""void C.M(int, string, CustomHandler)""
IL_003a: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(2).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 0, -1, 1 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[InlineData(@"$""literal""")]
[InlineData(@"$"""" + $""literal""")]
public void InterpolatedStringHandlerArgumentAttribute_OnConstructor(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
_ = new C(5, " + expression + @");
public class C
{
public int Prop { get; }
public C(int i, [InterpolatedStringHandlerArgumentAttribute(""i"")]CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount)
{
_builder.AppendLine(""i:"" + i.ToString());
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"
i:5
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 34 (0x22)
.maxstack 5
.locals init (int V_0,
CustomHandler V_1)
IL_0000: ldc.i4.5
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldloca.s V_1
IL_0005: ldc.i4.7
IL_0006: ldc.i4.0
IL_0007: ldloc.0
IL_0008: call ""CustomHandler..ctor(int, int, int)""
IL_000d: ldloca.s V_1
IL_000f: ldstr ""literal""
IL_0014: call ""bool CustomHandler.AppendLiteral(string)""
IL_0019: pop
IL_001a: ldloc.1
IL_001b: newobj ""C..ctor(int, CustomHandler)""
IL_0020: pop
IL_0021: ret
}
");
}
[Theory]
[CombinatorialData]
public void RefReturningMethodAsReceiver_RefParameter([CombinatorialValues("", ", out bool success")] string extraConstructorArg, [CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression, [CombinatorialValues("class", "struct")] string receiverType)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C c = new C(1);
GetC(ref c).M(" + expression + @");
Console.WriteLine(c.I);
ref C GetC(ref C c)
{
Console.WriteLine(""GetC"");
return ref c;
}
public " + receiverType + @" C
{
public int I;
public C(int i)
{
I = i;
}
public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref C c" + extraConstructorArg + @") : this(literalLength, formattedCount)
{
c = new C(2);
" + (extraConstructorArg != "" ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(extraConstructorArg != "" ?
new[] {
// (6,1): error CS1620: Argument 3 must be passed with the 'ref' keyword
// GetC(ref c).M($"literal" + $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "GetC(ref c)").WithArguments("3", "ref").WithLocation(6, 1),
// (6,15): error CS7036: There is no argument given that corresponds to the required parameter 'success' of 'CustomHandler.CustomHandler(int, int, ref C, out bool)'
// GetC(ref c).M($"literal" + $"");
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, expression).WithArguments("success", "CustomHandler.CustomHandler(int, int, ref C, out bool)").WithLocation(6, 15)
}
: new[] {
// (6,1): error CS1620: Argument 3 must be passed with the 'ref' keyword
// GetC(ref c).M($"literal" + $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "GetC(ref c)").WithArguments("3", "ref").WithLocation(6, 1)
});
}
[Theory]
[CombinatorialData]
public void RefReturningMethodAsReceiver_MismatchedRefness_01([CombinatorialValues("ref readonly", "")] string refness, [CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System.Runtime.CompilerServices;
C c = new C(1);
GetC().M(" + expression + @");
" + refness + @" C GetC() => throw null;
public class C
{
public C(int i) { }
public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) { }
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref C c) : this(literalLength, formattedCount) { }
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (5,1): error CS1620: Argument 3 must be passed with the 'ref' keyword
// GetC().M($"literal" + $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "GetC()").WithArguments("3", "ref").WithLocation(5, 1)
);
}
[Theory]
[CombinatorialData]
public void RefReturningMethodAsReceiver_MismatchedRefness_02([CombinatorialValues("in", "")] string refness, [CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C c = new C(1);
GetC(ref c).M(" + expression + @");
ref C GetC(ref C c) => ref c;
public class C
{
public int I;
public C(int i) { I = i; }
public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount," + refness + @" C c) : this(literalLength, formattedCount)
{
_builder.Append(c.I);
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
// ILVerify: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator.
var verifier = CompileAndVerify(
new[] { code, InterpolatedStringHandlerArgumentAttribute, handler },
expectedOutput: "1literal:literal",
symbolValidator: validator,
sourceSymbolValidator: validator,
verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.FailsILVerify : Verification.Skipped);
verifier.VerifyIL("<top-level-statements-entry-point>", refness == "in" ? @"
{
// Code size 47 (0x2f)
.maxstack 4
.locals init (C V_0, //c
C V_1,
CustomHandler V_2)
IL_0000: ldc.i4.1
IL_0001: newobj ""C..ctor(int)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""ref C Program.<<Main>$>g__GetC|0_0(ref C)""
IL_000e: ldind.ref
IL_000f: stloc.1
IL_0010: ldloc.1
IL_0011: ldc.i4.7
IL_0012: ldc.i4.0
IL_0013: ldloca.s V_1
IL_0015: newobj ""CustomHandler..ctor(int, int, in C)""
IL_001a: stloc.2
IL_001b: ldloca.s V_2
IL_001d: ldstr ""literal""
IL_0022: call ""bool CustomHandler.AppendLiteral(string)""
IL_0027: pop
IL_0028: ldloc.2
IL_0029: callvirt ""void C.M(CustomHandler)""
IL_002e: ret
}
"
: @"
{
// Code size 47 (0x2f)
.maxstack 5
.locals init (C V_0, //c
C V_1,
CustomHandler V_2)
IL_0000: ldc.i4.1
IL_0001: newobj ""C..ctor(int)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""ref C Program.<<Main>$>g__GetC|0_0(ref C)""
IL_000e: ldind.ref
IL_000f: stloc.1
IL_0010: ldloc.1
IL_0011: ldloca.s V_2
IL_0013: ldc.i4.7
IL_0014: ldc.i4.0
IL_0015: ldloc.1
IL_0016: call ""CustomHandler..ctor(int, int, C)""
IL_001b: ldloca.s V_2
IL_001d: ldstr ""literal""
IL_0022: call ""bool CustomHandler.AppendLiteral(string)""
IL_0027: pop
IL_0028: ldloc.2
IL_0029: callvirt ""void C.M(CustomHandler)""
IL_002e: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { -1 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory, CombinatorialData]
[WorkItem(56624, "https://github.com/dotnet/roslyn/issues/56624")]
public void RefOrOutParameter_AsReceiver([CombinatorialValues("ref", "out")] string parameterRefness, [CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C c = default;
localFunc(" + parameterRefness + @" c);
void localFunc(" + parameterRefness + @" C c)
{
c = new C(1);
c.M(" + expression + @");
}
public class C
{
public int I;
public C(int i) { I = i; }
public void M([InterpolatedStringHandlerArgument("""")]CustomHandler c) => Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount)
{
_builder.Append(c.I);
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, expectedOutput: "1literal:literal", symbolValidator: validator, sourceSymbolValidator: validator);
verifier.VerifyDiagnostics();
verifier.VerifyIL($"Program.<<Main>$>g__localFunc|0_0({parameterRefness} C)", @"
{
// Code size 42 (0x2a)
.maxstack 5
.locals init (C V_0,
CustomHandler V_1)
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: newobj ""C..ctor(int)""
IL_0007: stind.ref
IL_0008: ldarg.0
IL_0009: ldind.ref
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: ldloca.s V_1
IL_000e: ldc.i4.7
IL_000f: ldc.i4.0
IL_0010: ldloc.0
IL_0011: call ""CustomHandler..ctor(int, int, C)""
IL_0016: ldloca.s V_1
IL_0018: ldstr ""literal""
IL_001d: call ""bool CustomHandler.AppendLiteral(string)""
IL_0022: pop
IL_0023: ldloc.1
IL_0024: callvirt ""void C.M(CustomHandler)""
IL_0029: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { -1 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void StructReceiver_Rvalue(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
S s1 = new S { I = 1 };
S s2 = new S { I = 2 };
s1.M(s2, " + expression + @");
public struct S
{
public int I;
public void M(S s2, [InterpolatedStringHandlerArgument("""", ""s2"")]CustomHandler handler)
{
Console.WriteLine(""s1.I:"" + this.I.ToString());
Console.WriteLine(""s2.I:"" + s2.I.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, S s1, S s2) : this(literalLength, formattedCount)
{
s1.I = 3;
s2.I = 4;
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"
s1.I:1
s2.I:2");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 63 (0x3f)
.maxstack 6
.locals init (S V_0, //s1
S V_1, //s2
S V_2,
S& V_3)
IL_0000: ldloca.s V_2
IL_0002: initobj ""S""
IL_0008: ldloca.s V_2
IL_000a: ldc.i4.1
IL_000b: stfld ""int S.I""
IL_0010: ldloc.2
IL_0011: stloc.0
IL_0012: ldloca.s V_2
IL_0014: initobj ""S""
IL_001a: ldloca.s V_2
IL_001c: ldc.i4.2
IL_001d: stfld ""int S.I""
IL_0022: ldloc.2
IL_0023: stloc.1
IL_0024: ldloca.s V_0
IL_0026: stloc.3
IL_0027: ldloc.3
IL_0028: ldloc.1
IL_0029: stloc.2
IL_002a: ldloc.2
IL_002b: ldc.i4.0
IL_002c: ldc.i4.0
IL_002d: ldloc.3
IL_002e: ldobj ""S""
IL_0033: ldloc.2
IL_0034: newobj ""CustomHandler..ctor(int, int, S, S)""
IL_0039: call ""void S.M(S, CustomHandler)""
IL_003e: ret
}
");
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, options: TestOptions.DebugExe);
CompileAndVerify(comp, expectedOutput: @"
s1.I:1
s2.I:2");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void StructReceiver_Rvalue_ObjectCreationReceiver_01()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
new StructLogger(true, 1).Log($""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
internal readonly struct StructLogger
{
private readonly bool _disabled;
private readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public StructLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
Console.WriteLine(""Creating StructLogger"");
}
public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler) => Console.WriteLine($""StructLogger#{_id}: "" + handler.GetContent());
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}"");
enabled = !structLogger.Disabled;
_builder = structLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
Creating StructLogger
Creating DummyHandler from StructLogger#1
StructLogger#1:
(1) i=0");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 79 (0x4f)
.maxstack 4
.locals init (int V_0, //i
StructLogger V_1,
DummyHandler V_2,
bool V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.1
IL_0005: ldc.i4.1
IL_0006: call ""StructLogger..ctor(bool, int)""
IL_000b: ldc.i4.4
IL_000c: ldc.i4.1
IL_000d: ldloc.1
IL_000e: ldloca.s V_3
IL_0010: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)""
IL_0015: stloc.2
IL_0016: ldloc.3
IL_0017: brfalse.s IL_0031
IL_0019: ldloca.s V_2
IL_001b: ldstr ""log:""
IL_0020: call ""void DummyHandler.AppendLiteral(string)""
IL_0025: ldloca.s V_2
IL_0027: ldloc.0
IL_0028: dup
IL_0029: ldc.i4.1
IL_002a: add
IL_002b: stloc.0
IL_002c: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0031: ldloca.s V_1
IL_0033: ldloc.2
IL_0034: call ""void StructLogger.Log(DummyHandler)""
IL_0039: ldstr ""(1) i={0}""
IL_003e: ldloc.0
IL_003f: box ""int""
IL_0044: call ""string string.Format(string, object)""
IL_0049: call ""void System.Console.WriteLine(string)""
IL_004e: ret
}
");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void StructReceiver_Rvalue_ObjectCreationReceiver_02()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
new StructLogger(true, 1).Log($""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
var s = new StructLogger(true, 2);
s.Log($""log:{i++}"");
Console.WriteLine($""(2) i={i}"");
internal readonly struct StructLogger
{
private readonly bool _disabled;
private readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public StructLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler) => Console.WriteLine($""StructLogger#{_id}: "" + handler.GetContent());
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}"");
enabled = !structLogger.Disabled;
_builder = structLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.DebugExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
Creating DummyHandler from StructLogger#1
StructLogger#1:
(1) i=0
Creating DummyHandler from StructLogger#2
StructLogger#2:
(2) i=0
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 175 (0xaf)
.maxstack 4
.locals init (int V_0, //i
StructLogger V_1, //s
StructLogger V_2,
DummyHandler V_3,
bool V_4,
StructLogger& V_5)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_2
IL_0004: ldc.i4.1
IL_0005: ldc.i4.1
IL_0006: call ""StructLogger..ctor(bool, int)""
IL_000b: ldc.i4.4
IL_000c: ldc.i4.1
IL_000d: ldloc.2
IL_000e: ldloca.s V_4
IL_0010: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)""
IL_0015: stloc.3
IL_0016: ldloc.s V_4
IL_0018: brfalse.s IL_0034
IL_001a: ldloca.s V_3
IL_001c: ldstr ""log:""
IL_0021: call ""void DummyHandler.AppendLiteral(string)""
IL_0026: nop
IL_0027: ldloca.s V_3
IL_0029: ldloc.0
IL_002a: dup
IL_002b: ldc.i4.1
IL_002c: add
IL_002d: stloc.0
IL_002e: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0033: nop
IL_0034: ldloca.s V_2
IL_0036: ldloc.3
IL_0037: call ""void StructLogger.Log(DummyHandler)""
IL_003c: nop
IL_003d: ldstr ""(1) i={0}""
IL_0042: ldloc.0
IL_0043: box ""int""
IL_0048: call ""string string.Format(string, object)""
IL_004d: call ""void System.Console.WriteLine(string)""
IL_0052: nop
IL_0053: ldloca.s V_1
IL_0055: ldc.i4.1
IL_0056: ldc.i4.2
IL_0057: call ""StructLogger..ctor(bool, int)""
IL_005c: ldloca.s V_1
IL_005e: stloc.s V_5
IL_0060: ldc.i4.4
IL_0061: ldc.i4.1
IL_0062: ldloc.s V_5
IL_0064: ldobj ""StructLogger""
IL_0069: ldloca.s V_4
IL_006b: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)""
IL_0070: stloc.3
IL_0071: ldloc.s V_4
IL_0073: brfalse.s IL_008f
IL_0075: ldloca.s V_3
IL_0077: ldstr ""log:""
IL_007c: call ""void DummyHandler.AppendLiteral(string)""
IL_0081: nop
IL_0082: ldloca.s V_3
IL_0084: ldloc.0
IL_0085: dup
IL_0086: ldc.i4.1
IL_0087: add
IL_0088: stloc.0
IL_0089: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_008e: nop
IL_008f: ldloc.s V_5
IL_0091: ldloc.3
IL_0092: call ""void StructLogger.Log(DummyHandler)""
IL_0097: nop
IL_0098: ldstr ""(2) i={0}""
IL_009d: ldloc.0
IL_009e: box ""int""
IL_00a3: call ""string string.Format(string, object)""
IL_00a8: call ""void System.Console.WriteLine(string)""
IL_00ad: nop
IL_00ae: ret
}
");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void StructArgument_Rvalue_ObjectCreationArgument_01()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
Log(new StructLogger(true, 1), $""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
static void Log(StructLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""StructLogger#{logger._id}: "" + handler.GetContent());
internal readonly struct StructLogger
{
private readonly bool _disabled;
public readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public StructLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}"");
enabled = !structLogger.Disabled;
_builder = structLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
Creating DummyHandler from StructLogger#1
StructLogger#1:
(1) i=0");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 78 (0x4e)
.maxstack 5
.locals init (int V_0, //i
StructLogger V_1,
DummyHandler V_2,
bool V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.1
IL_0005: ldc.i4.1
IL_0006: call ""StructLogger..ctor(bool, int)""
IL_000b: ldloc.1
IL_000c: ldc.i4.4
IL_000d: ldc.i4.1
IL_000e: ldloc.1
IL_000f: ldloca.s V_3
IL_0011: newobj ""DummyHandler..ctor(int, int, StructLogger, out bool)""
IL_0016: stloc.2
IL_0017: ldloc.3
IL_0018: brfalse.s IL_0032
IL_001a: ldloca.s V_2
IL_001c: ldstr ""log:""
IL_0021: call ""void DummyHandler.AppendLiteral(string)""
IL_0026: ldloca.s V_2
IL_0028: ldloc.0
IL_0029: dup
IL_002a: ldc.i4.1
IL_002b: add
IL_002c: stloc.0
IL_002d: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0032: ldloc.2
IL_0033: call ""void Program.<<Main>$>g__Log|0_0(StructLogger, DummyHandler)""
IL_0038: ldstr ""(1) i={0}""
IL_003d: ldloc.0
IL_003e: box ""int""
IL_0043: call ""string string.Format(string, object)""
IL_0048: call ""void System.Console.WriteLine(string)""
IL_004d: ret
}
");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void StructArgument_Rvalue_ObjectCreationArgument_02()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
Log(new StructLogger(true, 1), $""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
static void Log(in StructLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""StructLogger#{logger._id}: "" + handler.GetContent());
internal readonly struct StructLogger
{
private readonly bool _disabled;
public readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public StructLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, in StructLogger structLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}"");
enabled = !structLogger.Disabled;
_builder = structLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
Creating DummyHandler from StructLogger#1
StructLogger#1:
(1) i=0");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 80 (0x50)
.maxstack 4
.locals init (int V_0, //i
StructLogger V_1,
DummyHandler V_2,
bool V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.1
IL_0005: ldc.i4.1
IL_0006: call ""StructLogger..ctor(bool, int)""
IL_000b: ldc.i4.4
IL_000c: ldc.i4.1
IL_000d: ldloca.s V_1
IL_000f: ldloca.s V_3
IL_0011: newobj ""DummyHandler..ctor(int, int, in StructLogger, out bool)""
IL_0016: stloc.2
IL_0017: ldloc.3
IL_0018: brfalse.s IL_0032
IL_001a: ldloca.s V_2
IL_001c: ldstr ""log:""
IL_0021: call ""void DummyHandler.AppendLiteral(string)""
IL_0026: ldloca.s V_2
IL_0028: ldloc.0
IL_0029: dup
IL_002a: ldc.i4.1
IL_002b: add
IL_002c: stloc.0
IL_002d: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0032: ldloca.s V_1
IL_0034: ldloc.2
IL_0035: call ""void Program.<<Main>$>g__Log|0_0(in StructLogger, DummyHandler)""
IL_003a: ldstr ""(1) i={0}""
IL_003f: ldloc.0
IL_0040: box ""int""
IL_0045: call ""string string.Format(string, object)""
IL_004a: call ""void System.Console.WriteLine(string)""
IL_004f: ret
}");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void StructArgument_Rvalue_ObjectCreationArgument_03()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
Log(ref new StructLogger(true, 1), $""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
static void Log(ref StructLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""StructLogger#{logger._id}: "" + handler.GetContent());
internal readonly struct StructLogger
{
private readonly bool _disabled;
public readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public StructLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, ref StructLogger structLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from StructLogger#{structLogger.Id}"");
enabled = !structLogger.Disabled;
_builder = structLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics(
// (7,9): error CS1510: A ref or out value must be an assignable variable
// Log(ref new StructLogger(true, 1), $"log:{i++}");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new StructLogger(true, 1)").WithLocation(7, 9)
);
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void ReferenceReceiver_Rvalue_ObjectCreationReceiver_01()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
new ClassLogger(true, 1).Log($""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
internal readonly struct ClassLogger
{
private readonly bool _disabled;
private readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public ClassLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{_id}: "" + handler.GetContent());
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, ClassLogger ClassLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}"");
enabled = !ClassLogger.Disabled;
_builder = ClassLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
Creating DummyHandler from ClassLogger#1
ClassLogger#1:
(1) i=0");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 79 (0x4f)
.maxstack 4
.locals init (int V_0, //i
ClassLogger V_1,
DummyHandler V_2,
bool V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.1
IL_0005: ldc.i4.1
IL_0006: call ""ClassLogger..ctor(bool, int)""
IL_000b: ldc.i4.4
IL_000c: ldc.i4.1
IL_000d: ldloc.1
IL_000e: ldloca.s V_3
IL_0010: newobj ""DummyHandler..ctor(int, int, ClassLogger, out bool)""
IL_0015: stloc.2
IL_0016: ldloc.3
IL_0017: brfalse.s IL_0031
IL_0019: ldloca.s V_2
IL_001b: ldstr ""log:""
IL_0020: call ""void DummyHandler.AppendLiteral(string)""
IL_0025: ldloca.s V_2
IL_0027: ldloc.0
IL_0028: dup
IL_0029: ldc.i4.1
IL_002a: add
IL_002b: stloc.0
IL_002c: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0031: ldloca.s V_1
IL_0033: ldloc.2
IL_0034: call ""void ClassLogger.Log(DummyHandler)""
IL_0039: ldstr ""(1) i={0}""
IL_003e: ldloc.0
IL_003f: box ""int""
IL_0044: call ""string string.Format(string, object)""
IL_0049: call ""void System.Console.WriteLine(string)""
IL_004e: ret
}
");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void ReferenceArgument_Rvalue_ObjectCreationArgument_01()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
Log(new ClassLogger(true, 1), $""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
static void Log(ClassLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{logger._id}: "" + handler.GetContent());
internal readonly struct ClassLogger
{
private readonly bool _disabled;
public readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public ClassLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, ClassLogger ClassLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}"");
enabled = !ClassLogger.Disabled;
_builder = ClassLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
Creating DummyHandler from ClassLogger#1
ClassLogger#1:
(1) i=0");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 78 (0x4e)
.maxstack 5
.locals init (int V_0, //i
ClassLogger V_1,
DummyHandler V_2,
bool V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.1
IL_0005: ldc.i4.1
IL_0006: call ""ClassLogger..ctor(bool, int)""
IL_000b: ldloc.1
IL_000c: ldc.i4.4
IL_000d: ldc.i4.1
IL_000e: ldloc.1
IL_000f: ldloca.s V_3
IL_0011: newobj ""DummyHandler..ctor(int, int, ClassLogger, out bool)""
IL_0016: stloc.2
IL_0017: ldloc.3
IL_0018: brfalse.s IL_0032
IL_001a: ldloca.s V_2
IL_001c: ldstr ""log:""
IL_0021: call ""void DummyHandler.AppendLiteral(string)""
IL_0026: ldloca.s V_2
IL_0028: ldloc.0
IL_0029: dup
IL_002a: ldc.i4.1
IL_002b: add
IL_002c: stloc.0
IL_002d: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0032: ldloc.2
IL_0033: call ""void Program.<<Main>$>g__Log|0_0(ClassLogger, DummyHandler)""
IL_0038: ldstr ""(1) i={0}""
IL_003d: ldloc.0
IL_003e: box ""int""
IL_0043: call ""string string.Format(string, object)""
IL_0048: call ""void System.Console.WriteLine(string)""
IL_004d: ret
}
");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void ReferenceArgument_Rvalue_ObjectCreationArgument_02()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
Log(new ClassLogger(true, 1), $""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
static void Log(in ClassLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{logger._id}: "" + handler.GetContent());
internal readonly struct ClassLogger
{
private readonly bool _disabled;
public readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public ClassLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, in ClassLogger ClassLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}"");
enabled = !ClassLogger.Disabled;
_builder = ClassLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
Creating DummyHandler from ClassLogger#1
ClassLogger#1:
(1) i=0");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 80 (0x50)
.maxstack 4
.locals init (int V_0, //i
ClassLogger V_1,
DummyHandler V_2,
bool V_3)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.1
IL_0005: ldc.i4.1
IL_0006: call ""ClassLogger..ctor(bool, int)""
IL_000b: ldc.i4.4
IL_000c: ldc.i4.1
IL_000d: ldloca.s V_1
IL_000f: ldloca.s V_3
IL_0011: newobj ""DummyHandler..ctor(int, int, in ClassLogger, out bool)""
IL_0016: stloc.2
IL_0017: ldloc.3
IL_0018: brfalse.s IL_0032
IL_001a: ldloca.s V_2
IL_001c: ldstr ""log:""
IL_0021: call ""void DummyHandler.AppendLiteral(string)""
IL_0026: ldloca.s V_2
IL_0028: ldloc.0
IL_0029: dup
IL_002a: ldc.i4.1
IL_002b: add
IL_002c: stloc.0
IL_002d: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0032: ldloca.s V_1
IL_0034: ldloc.2
IL_0035: call ""void Program.<<Main>$>g__Log|0_0(in ClassLogger, DummyHandler)""
IL_003a: ldstr ""(1) i={0}""
IL_003f: ldloc.0
IL_0040: box ""int""
IL_0045: call ""string string.Format(string, object)""
IL_004a: call ""void System.Console.WriteLine(string)""
IL_004f: ret
}");
}
[Fact, WorkItem(58514, "https://github.com/dotnet/roslyn/issues/58514")]
public void ReferenceArgument_Rvalue_ObjectCreationArgument_03()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var i = 0;
Log(ref new ClassLogger(true, 1), $""log:{i++}"");
Console.WriteLine($""(1) i={i}"");
static void Log(ref ClassLogger logger, [InterpolatedStringHandlerArgument(""logger"")] DummyHandler handler) => Console.WriteLine($""ClassLogger#{logger._id}: "" + handler.GetContent());
internal readonly struct ClassLogger
{
private readonly bool _disabled;
public readonly int _id;
public bool Disabled => _disabled;
public int Id => _id;
public ClassLogger(bool disabled, int id)
{
_disabled = disabled;
_id = id;
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, ref ClassLogger ClassLogger, out bool enabled)
{
Console.WriteLine($""Creating DummyHandler from ClassLogger#{ClassLogger.Id}"");
enabled = !ClassLogger.Disabled;
_builder = ClassLogger.Disabled ? null : new StringBuilder();
}
public string GetContent() => _builder?.ToString();
public void AppendLiteral(string s) => _builder?.Append(s);
public void AppendFormatted<T>(T t) => _builder?.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics(
// (7,9): error CS1510: A ref or out value must be an assignable variable
// Log(ref new ClassLogger(true, 1), $"log:{i++}");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new ClassLogger(true, 1)").WithLocation(7, 9)
);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void StructReceiver_Lvalue_01(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
S s1 = new S { I = 1 };
S s2 = new S { I = 2 };
s1.M(ref s2, " + expression + @");
public struct S
{
public int I;
public void M(ref S s2, [InterpolatedStringHandlerArgument("""", ""s2"")]CustomHandler handler)
{
Console.WriteLine(""s1.I:"" + this.I.ToString());
Console.WriteLine(""s2.I:"" + s2.I.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref S s1, ref S s2) : this(literalLength, formattedCount)
{
s1.I = 3;
s2.I = 4;
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (8,1): error CS1620: Argument 3 must be passed with the 'ref' keyword
// s1.M(ref s2, $"");
Diagnostic(ErrorCode.ERR_BadArgRef, "s1").WithArguments("3", "ref").WithLocation(8, 1)
);
}
[Fact]
[WorkItem(65470, "https://github.com/dotnet/roslyn/issues/65470")]
public void StructReceiver_Lvalue_02()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var l = new StructLogger();
Console.WriteLine(""logged = {0}"", l._logged);
l = test(l);
Console.WriteLine(""logged = {0}"", l._logged);
StructLogger test(StructLogger l)
{
l.Log($""log:{0}"");
return l;
}
internal struct StructLogger
{
public int _logged;
public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler)
{
_logged++;
Console.WriteLine($""StructLogger: "" + handler.GetContent());
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger)
{
Console.WriteLine($""Creating DummyHandler"");
_builder = new StringBuilder();
}
public string GetContent() => _builder.ToString();
public void AppendLiteral(string s) => _builder.Append(s);
public void AppendFormatted<T>(T t) => _builder.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
logged = 0
Creating DummyHandler
StructLogger: log:0
logged = 1
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.<<Main>$>g__test|0_0",
@"
{
// Code size 47 (0x2f)
.maxstack 5
.locals init (StructLogger& V_0,
DummyHandler V_1)
IL_0000: ldarga.s V_0
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldloca.s V_1
IL_0006: ldc.i4.4
IL_0007: ldc.i4.1
IL_0008: ldloc.0
IL_0009: ldobj ""StructLogger""
IL_000e: call ""DummyHandler..ctor(int, int, StructLogger)""
IL_0013: ldloca.s V_1
IL_0015: ldstr ""log:""
IL_001a: call ""void DummyHandler.AppendLiteral(string)""
IL_001f: ldloca.s V_1
IL_0021: ldc.i4.0
IL_0022: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0027: ldloc.1
IL_0028: call ""void StructLogger.Log(DummyHandler)""
IL_002d: ldarg.0
IL_002e: ret
}
");
}
[Fact]
public void StructReceiver_Lvalue_03()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var l = new StructLogger();
Console.WriteLine(""logged = {0}"", l._logged);
test(ref l);
Console.WriteLine(""logged = {0}"", l._logged);
void test(ref StructLogger l)
{
l.Log($""log:{0}"");
}
internal struct StructLogger
{
public int _logged;
public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler)
{
_logged++;
Console.WriteLine($""StructLogger: "" + handler.GetContent());
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger)
{
Console.WriteLine($""Creating DummyHandler"");
_builder = new StringBuilder();
}
public string GetContent() => _builder.ToString();
public void AppendLiteral(string s) => _builder.Append(s);
public void AppendFormatted<T>(T t) => _builder.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
logged = 0
Creating DummyHandler
StructLogger: log:0
logged = 1
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.<<Main>$>g__test|0_0",
@"
{
// Code size 45 (0x2d)
.maxstack 5
.locals init (StructLogger& V_0,
DummyHandler V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldloca.s V_1
IL_0005: ldc.i4.4
IL_0006: ldc.i4.1
IL_0007: ldloc.0
IL_0008: ldobj ""StructLogger""
IL_000d: call ""DummyHandler..ctor(int, int, StructLogger)""
IL_0012: ldloca.s V_1
IL_0014: ldstr ""log:""
IL_0019: call ""void DummyHandler.AppendLiteral(string)""
IL_001e: ldloca.s V_1
IL_0020: ldc.i4.0
IL_0021: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0026: ldloc.1
IL_0027: call ""void StructLogger.Log(DummyHandler)""
IL_002c: ret
}
");
}
[Fact]
public void StructReceiver_Lvalue_04()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var l = new StructLogger();
Console.WriteLine(""logged = {0}"", l._logged);
l = test1(l);
Console.WriteLine(""logged = {0}"", l._logged);
l = test2(l);
Console.WriteLine(""logged = {0}"", l._logged);
test3(ref l);
Console.WriteLine(""logged = {0}"", l._logged);
test4(ref l);
Console.WriteLine(""logged = {0}"", l._logged);
T test1<T>(T l) where T : ILogger
{
l.Log($""log:{-1}"");
return l;
}
T test2<T>(T l) where T : struct, ILogger
{
l.Log($""log:{-2}"");
return l;
}
void test3<T>(ref T l) where T : ILogger
{
l.Log($""log:{-3}"");
}
void test4<T>(ref T l) where T : struct, ILogger
{
l.Log($""log:{-4}"");
}
interface ILogger
{
void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler);
}
internal struct StructLogger : ILogger
{
public int _logged;
public void Log([InterpolatedStringHandlerArgument("""")] DummyHandler handler)
{
_logged++;
Console.WriteLine($""StructLogger: "" + handler.GetContent());
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, ILogger structLogger)
{
Console.WriteLine($""Creating DummyHandler"");
_builder = new StringBuilder();
}
public string GetContent() => _builder.ToString();
public void AppendLiteral(string s) => _builder.Append(s);
public void AppendFormatted<T>(T t) => _builder.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
logged = 0
Creating DummyHandler
StructLogger: log:-1
logged = 1
Creating DummyHandler
StructLogger: log:-2
logged = 2
Creating DummyHandler
StructLogger: log:-3
logged = 3
Creating DummyHandler
StructLogger: log:-4
logged = 4
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.<<Main>$>g__test1|0_0<T>",
@"
{
// Code size 88 (0x58)
.maxstack 5
.locals init (T& V_0,
T V_1,
T& V_2,
T V_3,
DummyHandler V_4)
IL_0000: ldarga.s V_0
IL_0002: stloc.2
IL_0003: ldloca.s V_3
IL_0005: initobj ""T""
IL_000b: ldloc.3
IL_000c: box ""T""
IL_0011: brtrue.s IL_001e
IL_0013: ldloc.2
IL_0014: ldobj ""T""
IL_0019: stloc.1
IL_001a: ldloca.s V_1
IL_001c: br.s IL_001f
IL_001e: ldloc.2
IL_001f: stloc.0
IL_0020: ldloc.0
IL_0021: ldloca.s V_4
IL_0023: ldc.i4.4
IL_0024: ldc.i4.1
IL_0025: ldloc.0
IL_0026: ldobj ""T""
IL_002b: box ""T""
IL_0030: call ""DummyHandler..ctor(int, int, ILogger)""
IL_0035: ldloca.s V_4
IL_0037: ldstr ""log:""
IL_003c: call ""void DummyHandler.AppendLiteral(string)""
IL_0041: ldloca.s V_4
IL_0043: ldc.i4.m1
IL_0044: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0049: ldloc.s V_4
IL_004b: constrained. ""T""
IL_0051: callvirt ""void ILogger.Log(DummyHandler)""
IL_0056: ldarg.0
IL_0057: ret
}
");
verifier.VerifyIL("Program.<<Main>$>g__test2|0_1<T>",
@"
{
// Code size 59 (0x3b)
.maxstack 5
.locals init (T& V_0,
DummyHandler V_1)
IL_0000: ldarga.s V_0
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldloca.s V_1
IL_0006: ldc.i4.4
IL_0007: ldc.i4.1
IL_0008: ldloc.0
IL_0009: ldobj ""T""
IL_000e: box ""T""
IL_0013: call ""DummyHandler..ctor(int, int, ILogger)""
IL_0018: ldloca.s V_1
IL_001a: ldstr ""log:""
IL_001f: call ""void DummyHandler.AppendLiteral(string)""
IL_0024: ldloca.s V_1
IL_0026: ldc.i4.s -2
IL_0028: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_002d: ldloc.1
IL_002e: constrained. ""T""
IL_0034: callvirt ""void ILogger.Log(DummyHandler)""
IL_0039: ldarg.0
IL_003a: ret
}
");
verifier.VerifyIL("Program.<<Main>$>g__test3|0_2<T>",
@"
{
// Code size 87 (0x57)
.maxstack 5
.locals init (T& V_0,
T V_1,
T& V_2,
T V_3,
DummyHandler V_4)
IL_0000: ldarg.0
IL_0001: stloc.2
IL_0002: ldloca.s V_3
IL_0004: initobj ""T""
IL_000a: ldloc.3
IL_000b: box ""T""
IL_0010: brtrue.s IL_001d
IL_0012: ldloc.2
IL_0013: ldobj ""T""
IL_0018: stloc.1
IL_0019: ldloca.s V_1
IL_001b: br.s IL_001e
IL_001d: ldloc.2
IL_001e: stloc.0
IL_001f: ldloc.0
IL_0020: ldloca.s V_4
IL_0022: ldc.i4.4
IL_0023: ldc.i4.1
IL_0024: ldloc.0
IL_0025: ldobj ""T""
IL_002a: box ""T""
IL_002f: call ""DummyHandler..ctor(int, int, ILogger)""
IL_0034: ldloca.s V_4
IL_0036: ldstr ""log:""
IL_003b: call ""void DummyHandler.AppendLiteral(string)""
IL_0040: ldloca.s V_4
IL_0042: ldc.i4.s -3
IL_0044: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0049: ldloc.s V_4
IL_004b: constrained. ""T""
IL_0051: callvirt ""void ILogger.Log(DummyHandler)""
IL_0056: ret
}
");
verifier.VerifyIL("Program.<<Main>$>g__test4|0_3<T>",
@"
{
// Code size 57 (0x39)
.maxstack 5
.locals init (T& V_0,
DummyHandler V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldloca.s V_1
IL_0005: ldc.i4.4
IL_0006: ldc.i4.1
IL_0007: ldloc.0
IL_0008: ldobj ""T""
IL_000d: box ""T""
IL_0012: call ""DummyHandler..ctor(int, int, ILogger)""
IL_0017: ldloca.s V_1
IL_0019: ldstr ""log:""
IL_001e: call ""void DummyHandler.AppendLiteral(string)""
IL_0023: ldloca.s V_1
IL_0025: ldc.i4.s -4
IL_0027: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_002c: ldloc.1
IL_002d: constrained. ""T""
IL_0033: callvirt ""void ILogger.Log(DummyHandler)""
IL_0038: ret
}
");
}
[Fact]
public void StructReceiver_Lvalue_05()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var l = new StructLogger();
Console.WriteLine(""logged = {0}"", l._logged);
test3(ref l);
Console.WriteLine(""logged = {0}"", l._logged);
test4(ref l);
Console.WriteLine(""logged = {0}"", l._logged);
void test3<T>(ref T l) where T : ILogger
{
get3(ref l)[$""log:{-3}""] += 1;
}
void test4<T>(ref T l) where T : struct, ILogger
{
get4(ref l)[$""log:{-4}""] += 1;
}
ref T get3<T>(ref T l) where T : ILogger
{
Console.WriteLine(""get3"");
return ref l;
}
ref T get4<T>(ref T l) where T : struct, ILogger
{
Console.WriteLine(""get4"");
return ref l;
}
interface ILogger
{
int this[[InterpolatedStringHandlerArgument("""")] DummyHandler handler] { get;set; }
}
internal struct StructLogger : ILogger
{
public int _logged;
public int this[[InterpolatedStringHandlerArgument("""")] DummyHandler handler]
{
get
{
Console.WriteLine($""StructLogger get: "" + handler.GetContent());
Console.WriteLine(_logged);
_logged++;
return 0;
}
set
{
Console.WriteLine($""StructLogger set: "" + handler.GetContent());
Console.WriteLine(_logged);
_logged++;
}
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, ILogger structLogger)
{
Console.WriteLine($""Creating DummyHandler"");
_builder = new StringBuilder();
}
public string GetContent() => _builder.ToString();
public void AppendLiteral(string s) => _builder.Append(s);
public void AppendFormatted<T>(T t) => _builder.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
logged = 0
get3
Creating DummyHandler
StructLogger get: log:-3
0
StructLogger set: log:-3
1
logged = 2
get4
Creating DummyHandler
StructLogger get: log:-4
2
StructLogger set: log:-4
3
logged = 4
", verify: Verification.Skipped);
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.<<Main>$>g__test3|0_0<T>",
@"
{
// Code size 110 (0x6e)
.maxstack 4
.locals init (T& V_0,
T V_1,
T& V_2,
DummyHandler V_3,
T V_4,
DummyHandler V_5)
IL_0000: ldarg.0
IL_0001: call ""ref T Program.<<Main>$>g__get3|0_2<T>(ref T)""
IL_0006: stloc.2
IL_0007: ldloca.s V_4
IL_0009: initobj ""T""
IL_000f: ldloc.s V_4
IL_0011: box ""T""
IL_0016: brtrue.s IL_0023
IL_0018: ldloc.2
IL_0019: ldobj ""T""
IL_001e: stloc.1
IL_001f: ldloca.s V_1
IL_0021: br.s IL_0024
IL_0023: ldloc.2
IL_0024: stloc.0
IL_0025: ldloca.s V_5
IL_0027: ldc.i4.4
IL_0028: ldc.i4.1
IL_0029: ldloc.0
IL_002a: ldobj ""T""
IL_002f: box ""T""
IL_0034: call ""DummyHandler..ctor(int, int, ILogger)""
IL_0039: ldloca.s V_5
IL_003b: ldstr ""log:""
IL_0040: call ""void DummyHandler.AppendLiteral(string)""
IL_0045: ldloca.s V_5
IL_0047: ldc.i4.s -3
IL_0049: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_004e: ldloc.s V_5
IL_0050: stloc.3
IL_0051: ldloc.0
IL_0052: ldloc.3
IL_0053: ldloc.0
IL_0054: ldloc.3
IL_0055: constrained. ""T""
IL_005b: callvirt ""int ILogger.this[DummyHandler].get""
IL_0060: ldc.i4.1
IL_0061: add
IL_0062: constrained. ""T""
IL_0068: callvirt ""void ILogger.this[DummyHandler].set""
IL_006d: ret
}
");
verifier.VerifyIL("Program.<<Main>$>g__test4|0_1<T>",
@"
{
// Code size 79 (0x4f)
.maxstack 4
.locals init (T& V_0,
DummyHandler V_1,
DummyHandler V_2)
IL_0000: ldarg.0
IL_0001: call ""ref T Program.<<Main>$>g__get4|0_3<T>(ref T)""
IL_0006: stloc.0
IL_0007: ldloca.s V_2
IL_0009: ldc.i4.4
IL_000a: ldc.i4.1
IL_000b: ldloc.0
IL_000c: ldobj ""T""
IL_0011: box ""T""
IL_0016: call ""DummyHandler..ctor(int, int, ILogger)""
IL_001b: ldloca.s V_2
IL_001d: ldstr ""log:""
IL_0022: call ""void DummyHandler.AppendLiteral(string)""
IL_0027: ldloca.s V_2
IL_0029: ldc.i4.s -4
IL_002b: call ""void DummyHandler.AppendFormatted<int>(int)""
IL_0030: ldloc.2
IL_0031: stloc.1
IL_0032: ldloc.0
IL_0033: ldloc.1
IL_0034: ldloc.0
IL_0035: ldloc.1
IL_0036: constrained. ""T""
IL_003c: callvirt ""int ILogger.this[DummyHandler].get""
IL_0041: ldc.i4.1
IL_0042: add
IL_0043: constrained. ""T""
IL_0049: callvirt ""void ILogger.this[DummyHandler].set""
IL_004e: ret
}
");
}
[Fact]
public void StructReceiver_Lvalue_06()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var c = new Container();
Console.WriteLine(""logged = {0}"", c.Logger._logged);
test3(c);
Console.WriteLine(""logged = {0}"", c.Logger._logged);
void test3(Container c)
{
get3(c).Logger[$""log:{-3}""] += 1;
}
Container get3(Container c)
{
Console.WriteLine(""get3"");
return c;
}
class Container
{
public StructLogger Logger = default;
}
internal struct StructLogger
{
public int _logged;
public int this[[InterpolatedStringHandlerArgument("""")] DummyHandler handler]
{
get
{
Console.WriteLine($""StructLogger get: "" + handler.GetContent());
Console.WriteLine(_logged);
_logged++;
return 0;
}
set
{
Console.WriteLine($""StructLogger set: "" + handler.GetContent());
Console.WriteLine(_logged);
_logged++;
}
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, StructLogger structLogger)
{
Console.WriteLine($""Creating DummyHandler"");
_builder = new StringBuilder();
}
public string GetContent() => _builder.ToString();
public void AppendLiteral(string s) => _builder.Append(s);
public void AppendFormatted<T>(T t) => _builder.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
logged = 0
get3
Creating DummyHandler
StructLogger get: log:-3
0
StructLogger set: log:-3
1
logged = 2
", verify: Verification.Skipped);
verifier.VerifyDiagnostics();
}
[Fact]
public void StructReceiver_Lvalue_07()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
using System.Text;
var c = new Container<StructLogger>();
Console.WriteLine(""logged = {0}"", c.Logger._logged);
test3(c);
Console.WriteLine(""logged = {0}"", c.Logger._logged);
test4(c);
Console.WriteLine(""logged = {0}"", c.Logger._logged);
void test3<T>(Container<T> c) where T : ILogger
{
get3(c).Logger[$""log:{-3}""] += 1;
}
void test4<T>(Container<T> c) where T : struct, ILogger
{
get4(c).Logger[$""log:{-4}""] += 1;
}
Container<T> get3<T>(Container<T> c) where T : ILogger
{
Console.WriteLine(""get3"");
return c;
}
Container<T> get4<T>(Container<T> c) where T : ILogger
{
Console.WriteLine(""get4"");
return c;
}
class Container<T> where T : ILogger
{
public T Logger = default;
}
interface ILogger
{
int this[[InterpolatedStringHandlerArgument("""")] DummyHandler handler] { get;set; }
}
internal struct StructLogger : ILogger
{
public int _logged;
public int this[[InterpolatedStringHandlerArgument("""")] DummyHandler handler]
{
get
{
Console.WriteLine($""StructLogger get: "" + handler.GetContent());
Console.WriteLine(_logged);
_logged++;
return 0;
}
set
{
Console.WriteLine($""StructLogger set: "" + handler.GetContent());
Console.WriteLine(_logged);
_logged++;
}
}
}
[InterpolatedStringHandler]
internal ref struct DummyHandler
{
private readonly StringBuilder _builder;
public DummyHandler(int literalLength, int formattedCount, ILogger structLogger)
{
Console.WriteLine($""Creating DummyHandler"");
_builder = new StringBuilder();
}
public string GetContent() => _builder.ToString();
public void AppendLiteral(string s) => _builder.Append(s);
public void AppendFormatted<T>(T t) => _builder.Append(t);
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(comp, expectedOutput: @"
logged = 0
get3
Creating DummyHandler
StructLogger get: log:-3
0
StructLogger set: log:-3
1
logged = 2
get4
Creating DummyHandler
StructLogger get: log:-4
2
StructLogger set: log:-4
3
logged = 4
", verify: Verification.Skipped);
verifier.VerifyDiagnostics();
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void StructParameter_ByVal(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
S s = new S { I = 1 };
S.M(s, " + expression + @");
public struct S
{
public int I;
public static void M(S s, [InterpolatedStringHandlerArgument(""s"")]CustomHandler handler)
{
Console.WriteLine(""s.I:"" + s.I.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, S s) : this(literalLength, formattedCount)
{
s.I = 2;
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"s.I:1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 33 (0x21)
.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: ldc.i4.1
IL_000b: stfld ""int S.I""
IL_0010: ldloc.0
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: ldc.i4.0
IL_0014: ldc.i4.0
IL_0015: ldloc.0
IL_0016: newobj ""CustomHandler..ctor(int, int, S)""
IL_001b: call ""void S.M(S, CustomHandler)""
IL_0020: ret
}
");
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void StructParameter_ByRef(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
S s = new S { I = 1 };
S.M(ref s, " + expression + @");
public struct S
{
public int I;
public static void M(ref S s, [InterpolatedStringHandlerArgument(""s"")]CustomHandler handler)
{
Console.WriteLine(""s.I:"" + s.I.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref S s) : this(literalLength, formattedCount)
{
s.I = 2;
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"s.I:2");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 36 (0x24)
.maxstack 4
.locals init (S V_0, //s
S V_1,
S& V_2)
IL_0000: ldloca.s V_1
IL_0002: initobj ""S""
IL_0008: ldloca.s V_1
IL_000a: ldc.i4.1
IL_000b: stfld ""int S.I""
IL_0010: ldloc.1
IL_0011: stloc.0
IL_0012: ldloca.s V_0
IL_0014: stloc.2
IL_0015: ldloc.2
IL_0016: ldc.i4.0
IL_0017: ldc.i4.0
IL_0018: ldloc.2
IL_0019: newobj ""CustomHandler..ctor(int, int, ref S)""
IL_001e: call ""void S.M(ref S, CustomHandler)""
IL_0023: ret
}
");
}
[Theory]
[CombinatorialData]
public void SideEffects(bool useBoolReturns, bool validityParameter, [CombinatorialValues(@"$""literal""", @"$"""" + $""literal""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
GetReceiver().M(
GetArg(""Unrelated parameter 1""),
GetArg(""Second value""),
GetArg(""Unrelated parameter 2""),
GetArg(""First value""),
" + expression + @",
GetArg(""Unrelated parameter 4""));
C GetReceiver()
{
Console.WriteLine(""GetReceiver"");
return new C() { Prop = ""Prop"" };
}
string GetArg(string s)
{
Console.WriteLine(s);
return s;
}
public class C
{
public string Prop { get; set; }
public void M(string param1, string param2, string param3, string param4, [InterpolatedStringHandlerArgument(""param4"", """", ""param2"")] CustomHandler c, string param6)
=> Console.WriteLine(c.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, string s1, C c, string s2" + (validityParameter ? ", out bool success" : "") + @")
: this(literalLength, formattedCount)
{
Console.WriteLine(""Handler constructor"");
_builder.AppendLine(""s1:"" + s1);
_builder.AppendLine(""c.Prop:"" + c.Prop);
_builder.AppendLine(""s2:"" + s2);
" + (validityParameter ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns);
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, expectedOutput: @"
GetReceiver
Unrelated parameter 1
Second value
Unrelated parameter 2
First value
Handler constructor
Unrelated parameter 4
s1:First value
c.Prop:Prop
s2:Second value
literal:literal
");
verifier.VerifyDiagnostics();
}
[Theory]
[InlineData(@"$""literal""")]
[InlineData(@"$""literal"" + $""""")]
public void InterpolatedStringHandlerArgumentsAttribute_ConversionFromArgumentType(string expression)
{
var code = @"
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
int i = 1;
C.M(i, " + expression + @");
public class C
{
public static implicit operator C(int i) => throw null;
public static implicit operator C(double d)
{
Console.WriteLine(d.ToString(""G"", CultureInfo.InvariantCulture));
return new C();
}
public override string ToString() => ""C"";
public static void M(double d, [InterpolatedStringHandlerArgument(""d"")] CustomHandler handler) => Console.WriteLine(handler.ToString());
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount) { }
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator, expectedOutput: @"
1
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 39 (0x27)
.maxstack 5
.locals init (double V_0,
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: conv.r8
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldloca.s V_1
IL_0006: ldc.i4.7
IL_0007: ldc.i4.0
IL_0008: ldloc.0
IL_0009: call ""C C.op_Implicit(double)""
IL_000e: call ""CustomHandler..ctor(int, int, C)""
IL_0013: ldloca.s V_1
IL_0015: ldstr ""literal""
IL_001a: call ""bool CustomHandler.AppendLiteral(string)""
IL_001f: pop
IL_0020: ldloc.1
IL_0021: call ""void C.M(double, CustomHandler)""
IL_0026: ret
}
");
static void validator(ModuleSymbol module)
{
var cParam = module.GlobalNamespace.GetTypeMember("C").GetMethod("M").Parameters.Skip(1).Single();
AssertEx.Equal("System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute",
cParam.GetAttributes().Single().AttributeClass.ToTestDisplayString());
Assert.Equal(new[] { 0 }, cParam.InterpolatedStringHandlerArgumentIndexes);
}
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentsAttribute_CompoundAssignment_Indexer_01(bool useBoolReturns, bool validityParameter, [CombinatorialValues(@"$""literal{i}""", @"$""literal"" + $""{i}""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
int i = 3;
GetC()[GetInt(1), " + expression + @"] += GetInt(2);
static C GetC()
{
Console.WriteLine(""GetC"");
return new C() { Prop = 2 };
}
static int GetInt(int i)
{
Console.WriteLine(""GetInt"" + i.ToString());
return 1;
}
public class C
{
public int Prop { get; set; }
public int this[int arg1, [InterpolatedStringHandlerArgument(""arg1"", """")] CustomHandler c]
{
get
{
Console.WriteLine(""Indexer getter"");
return 0;
}
set
{
Console.WriteLine(""Indexer setter"");
Console.WriteLine(c.ToString());
}
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int arg1, C c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount)
{
Console.WriteLine(""Handler constructor"");
_builder.AppendLine(""arg1:"" + arg1);
_builder.AppendLine(""C.Prop:"" + c.Prop.ToString());
" + (validityParameter ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: useBoolReturns);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"
GetC
GetInt1
Handler constructor
Indexer getter
GetInt2
Indexer setter
arg1:1
C.Prop:2
literal:literal
value:3
alignment:0
format:
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", getIl());
string getIl() => (useBoolReturns, validityParameter) switch
{
(useBoolReturns: false, validityParameter: false) => @"
{
// Code size 85 (0x55)
.maxstack 6
.locals init (int V_0, //i
C V_1,
int V_2,
int V_3,
CustomHandler V_4,
CustomHandler V_5)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldc.i4.1
IL_0009: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000e: stloc.2
IL_000f: ldloc.2
IL_0010: stloc.3
IL_0011: ldloca.s V_5
IL_0013: ldc.i4.7
IL_0014: ldc.i4.1
IL_0015: ldloc.2
IL_0016: ldloc.1
IL_0017: call ""CustomHandler..ctor(int, int, int, C)""
IL_001c: ldloca.s V_5
IL_001e: ldstr ""literal""
IL_0023: call ""void CustomHandler.AppendLiteral(string)""
IL_0028: ldloca.s V_5
IL_002a: ldloc.0
IL_002b: box ""int""
IL_0030: ldc.i4.0
IL_0031: ldnull
IL_0032: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0037: ldloc.s V_5
IL_0039: stloc.s V_4
IL_003b: ldloc.1
IL_003c: ldloc.3
IL_003d: ldloc.s V_4
IL_003f: ldloc.1
IL_0040: ldloc.3
IL_0041: ldloc.s V_4
IL_0043: callvirt ""int C.this[int, CustomHandler].get""
IL_0048: ldc.i4.2
IL_0049: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_004e: add
IL_004f: callvirt ""void C.this[int, CustomHandler].set""
IL_0054: ret
}
",
(useBoolReturns: false, validityParameter: true) => @"
{
// Code size 94 (0x5e)
.maxstack 6
.locals init (int V_0, //i
CustomHandler V_1,
bool V_2,
C V_3,
int V_4,
int V_5,
CustomHandler V_6)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.3
IL_0008: ldc.i4.1
IL_0009: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000e: stloc.s V_4
IL_0010: ldloc.s V_4
IL_0012: stloc.s V_5
IL_0014: ldc.i4.7
IL_0015: ldc.i4.1
IL_0016: ldloc.s V_4
IL_0018: ldloc.3
IL_0019: ldloca.s V_2
IL_001b: newobj ""CustomHandler..ctor(int, int, int, C, out bool)""
IL_0020: stloc.1
IL_0021: ldloc.2
IL_0022: brfalse.s IL_003f
IL_0024: ldloca.s V_1
IL_0026: ldstr ""literal""
IL_002b: call ""void CustomHandler.AppendLiteral(string)""
IL_0030: ldloca.s V_1
IL_0032: ldloc.0
IL_0033: box ""int""
IL_0038: ldc.i4.0
IL_0039: ldnull
IL_003a: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_003f: ldloc.1
IL_0040: stloc.s V_6
IL_0042: ldloc.3
IL_0043: ldloc.s V_5
IL_0045: ldloc.s V_6
IL_0047: ldloc.3
IL_0048: ldloc.s V_5
IL_004a: ldloc.s V_6
IL_004c: callvirt ""int C.this[int, CustomHandler].get""
IL_0051: ldc.i4.2
IL_0052: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_0057: add
IL_0058: callvirt ""void C.this[int, CustomHandler].set""
IL_005d: ret
}
",
(useBoolReturns: true, validityParameter: false) => @"
{
// Code size 91 (0x5b)
.maxstack 6
.locals init (int V_0, //i
C V_1,
int V_2,
int V_3,
CustomHandler V_4,
CustomHandler V_5)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldc.i4.1
IL_0009: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000e: stloc.2
IL_000f: ldloc.2
IL_0010: stloc.3
IL_0011: ldloca.s V_5
IL_0013: ldc.i4.7
IL_0014: ldc.i4.1
IL_0015: ldloc.2
IL_0016: ldloc.1
IL_0017: call ""CustomHandler..ctor(int, int, int, C)""
IL_001c: ldloca.s V_5
IL_001e: ldstr ""literal""
IL_0023: call ""bool CustomHandler.AppendLiteral(string)""
IL_0028: brfalse.s IL_003b
IL_002a: ldloca.s V_5
IL_002c: ldloc.0
IL_002d: box ""int""
IL_0032: ldc.i4.0
IL_0033: ldnull
IL_0034: call ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_0039: br.s IL_003c
IL_003b: ldc.i4.0
IL_003c: pop
IL_003d: ldloc.s V_5
IL_003f: stloc.s V_4
IL_0041: ldloc.1
IL_0042: ldloc.3
IL_0043: ldloc.s V_4
IL_0045: ldloc.1
IL_0046: ldloc.3
IL_0047: ldloc.s V_4
IL_0049: callvirt ""int C.this[int, CustomHandler].get""
IL_004e: ldc.i4.2
IL_004f: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_0054: add
IL_0055: callvirt ""void C.this[int, CustomHandler].set""
IL_005a: ret
}
",
(useBoolReturns: true, validityParameter: true) => @"
{
// Code size 97 (0x61)
.maxstack 6
.locals init (int V_0, //i
C V_1,
int V_2,
int V_3,
CustomHandler V_4,
CustomHandler V_5,
bool V_6)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldc.i4.1
IL_0009: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000e: stloc.2
IL_000f: ldloc.2
IL_0010: stloc.3
IL_0011: ldc.i4.7
IL_0012: ldc.i4.1
IL_0013: ldloc.2
IL_0014: ldloc.1
IL_0015: ldloca.s V_6
IL_0017: newobj ""CustomHandler..ctor(int, int, int, C, out bool)""
IL_001c: stloc.s V_5
IL_001e: ldloc.s V_6
IL_0020: brfalse.s IL_0041
IL_0022: ldloca.s V_5
IL_0024: ldstr ""literal""
IL_0029: call ""bool CustomHandler.AppendLiteral(string)""
IL_002e: brfalse.s IL_0041
IL_0030: ldloca.s V_5
IL_0032: ldloc.0
IL_0033: box ""int""
IL_0038: ldc.i4.0
IL_0039: ldnull
IL_003a: call ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_003f: br.s IL_0042
IL_0041: ldc.i4.0
IL_0042: pop
IL_0043: ldloc.s V_5
IL_0045: stloc.s V_4
IL_0047: ldloc.1
IL_0048: ldloc.3
IL_0049: ldloc.s V_4
IL_004b: ldloc.1
IL_004c: ldloc.3
IL_004d: ldloc.s V_4
IL_004f: callvirt ""int C.this[int, CustomHandler].get""
IL_0054: ldc.i4.2
IL_0055: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_005a: add
IL_005b: callvirt ""void C.this[int, CustomHandler].set""
IL_0060: ret
}
",
};
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentsAttribute_CompoundAssignment_Indexer_02(bool useBoolReturns, bool validityParameter, [CombinatorialValues(@"$""literal{i}""", @"$""literal"" + $""{i}""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
int i = 3;
GetC()[GetInt(1), " + expression + @"] += GetInt(2);
static C GetC()
{
Console.WriteLine(""GetC"");
return new C() { Prop = 2 };
}
static int GetInt(int i)
{
Console.WriteLine(""GetInt"" + i.ToString());
return 1;
}
public class C
{
private int field;
public int Prop { get; set; }
public ref int this[int arg1, [InterpolatedStringHandlerArgument(""arg1"", """")] CustomHandler c]
{
get
{
Console.WriteLine(""Indexer getter"");
Console.WriteLine(c.ToString());
return ref field;
}
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int arg1, C c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount)
{
Console.WriteLine(""Handler constructor"");
_builder.AppendLine(""arg1:"" + arg1);
_builder.AppendLine(""C.Prop:"" + c.Prop.ToString());
" + (validityParameter ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: useBoolReturns);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"
GetC
GetInt1
Handler constructor
Indexer getter
arg1:1
C.Prop:2
literal:literal
value:3
alignment:0
format:
GetInt2
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", getIl());
string getIl() => (useBoolReturns, validityParameter) switch
{
(useBoolReturns: false, validityParameter: false) => @"
{
// Code size 72 (0x48)
.maxstack 7
.locals init (int V_0, //i
C V_1,
int V_2,
CustomHandler V_3)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldloca.s V_3
IL_0013: ldc.i4.7
IL_0014: ldc.i4.1
IL_0015: ldloc.2
IL_0016: ldloc.1
IL_0017: call ""CustomHandler..ctor(int, int, int, C)""
IL_001c: ldloca.s V_3
IL_001e: ldstr ""literal""
IL_0023: call ""void CustomHandler.AppendLiteral(string)""
IL_0028: ldloca.s V_3
IL_002a: ldloc.0
IL_002b: box ""int""
IL_0030: ldc.i4.0
IL_0031: ldnull
IL_0032: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0037: ldloc.3
IL_0038: callvirt ""ref int C.this[int, CustomHandler].get""
IL_003d: dup
IL_003e: ldind.i4
IL_003f: ldc.i4.2
IL_0040: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_0045: add
IL_0046: stind.i4
IL_0047: ret
}
",
(useBoolReturns: false, validityParameter: true) => @"
{
// Code size 81 (0x51)
.maxstack 6
.locals init (int V_0, //i
C V_1,
int V_2,
int V_3,
CustomHandler V_4,
bool V_5)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: stloc.3
IL_0012: ldc.i4.7
IL_0013: ldc.i4.1
IL_0014: ldloc.2
IL_0015: ldloc.1
IL_0016: ldloca.s V_5
IL_0018: newobj ""CustomHandler..ctor(int, int, int, C, out bool)""
IL_001d: stloc.s V_4
IL_001f: ldloc.s V_5
IL_0021: brfalse.s IL_003e
IL_0023: ldloca.s V_4
IL_0025: ldstr ""literal""
IL_002a: call ""void CustomHandler.AppendLiteral(string)""
IL_002f: ldloca.s V_4
IL_0031: ldloc.0
IL_0032: box ""int""
IL_0037: ldc.i4.0
IL_0038: ldnull
IL_0039: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_003e: ldloc.3
IL_003f: ldloc.s V_4
IL_0041: callvirt ""ref int C.this[int, CustomHandler].get""
IL_0046: dup
IL_0047: ldind.i4
IL_0048: ldc.i4.2
IL_0049: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_004e: add
IL_004f: stind.i4
IL_0050: ret
}
",
(useBoolReturns: true, validityParameter: false) => @"
{
// Code size 78 (0x4e)
.maxstack 7
.locals init (int V_0, //i
C V_1,
int V_2,
CustomHandler V_3)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldloca.s V_3
IL_0013: ldc.i4.7
IL_0014: ldc.i4.1
IL_0015: ldloc.2
IL_0016: ldloc.1
IL_0017: call ""CustomHandler..ctor(int, int, int, C)""
IL_001c: ldloca.s V_3
IL_001e: ldstr ""literal""
IL_0023: call ""bool CustomHandler.AppendLiteral(string)""
IL_0028: brfalse.s IL_003b
IL_002a: ldloca.s V_3
IL_002c: ldloc.0
IL_002d: box ""int""
IL_0032: ldc.i4.0
IL_0033: ldnull
IL_0034: call ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_0039: br.s IL_003c
IL_003b: ldc.i4.0
IL_003c: pop
IL_003d: ldloc.3
IL_003e: callvirt ""ref int C.this[int, CustomHandler].get""
IL_0043: dup
IL_0044: ldind.i4
IL_0045: ldc.i4.2
IL_0046: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_004b: add
IL_004c: stind.i4
IL_004d: ret
}
",
(useBoolReturns: true, validityParameter: true) => @"
{
// Code size 83 (0x53)
.maxstack 7
.locals init (int V_0, //i
C V_1,
int V_2,
CustomHandler V_3,
bool V_4)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldc.i4.7
IL_0012: ldc.i4.1
IL_0013: ldloc.2
IL_0014: ldloc.1
IL_0015: ldloca.s V_4
IL_0017: newobj ""CustomHandler..ctor(int, int, int, C, out bool)""
IL_001c: stloc.3
IL_001d: ldloc.s V_4
IL_001f: brfalse.s IL_0040
IL_0021: ldloca.s V_3
IL_0023: ldstr ""literal""
IL_0028: call ""bool CustomHandler.AppendLiteral(string)""
IL_002d: brfalse.s IL_0040
IL_002f: ldloca.s V_3
IL_0031: ldloc.0
IL_0032: box ""int""
IL_0037: ldc.i4.0
IL_0038: ldnull
IL_0039: call ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_003e: br.s IL_0041
IL_0040: ldc.i4.0
IL_0041: pop
IL_0042: ldloc.3
IL_0043: callvirt ""ref int C.this[int, CustomHandler].get""
IL_0048: dup
IL_0049: ldind.i4
IL_004a: ldc.i4.2
IL_004b: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_0050: add
IL_0051: stind.i4
IL_0052: ret
}
",
};
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentsAttribute_CompoundAssignment_RefReturningMethod(bool useBoolReturns, bool validityParameter, [CombinatorialValues(@"$""literal{i}""", @"$""literal"" + $""{i}""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
int i = 3;
GetC().M(GetInt(1), " + expression + @") += GetInt(2);
static C GetC()
{
Console.WriteLine(""GetC"");
return new C() { Prop = 2 };
}
static int GetInt(int i)
{
Console.WriteLine(""GetInt"" + i.ToString());
return 1;
}
public class C
{
private int field;
public int Prop { get; set; }
public ref int M(int arg1, [InterpolatedStringHandlerArgument(""arg1"", """")] CustomHandler c)
{
Console.WriteLine(""M"");
Console.WriteLine(c.ToString());
return ref field;
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int arg1, C c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount)
{
Console.WriteLine(""Handler constructor"");
_builder.AppendLine(""arg1:"" + arg1);
_builder.AppendLine(""C.Prop:"" + c.Prop.ToString());
" + (validityParameter ? "success = true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: useBoolReturns);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"
GetC
GetInt1
Handler constructor
M
arg1:1
C.Prop:2
literal:literal
value:3
alignment:0
format:
GetInt2
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", getIl());
string getIl() => (useBoolReturns, validityParameter) switch
{
(useBoolReturns: false, validityParameter: false) => @"
{
// Code size 72 (0x48)
.maxstack 7
.locals init (int V_0, //i
C V_1,
int V_2,
CustomHandler V_3)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldloca.s V_3
IL_0013: ldc.i4.7
IL_0014: ldc.i4.1
IL_0015: ldloc.2
IL_0016: ldloc.1
IL_0017: call ""CustomHandler..ctor(int, int, int, C)""
IL_001c: ldloca.s V_3
IL_001e: ldstr ""literal""
IL_0023: call ""void CustomHandler.AppendLiteral(string)""
IL_0028: ldloca.s V_3
IL_002a: ldloc.0
IL_002b: box ""int""
IL_0030: ldc.i4.0
IL_0031: ldnull
IL_0032: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0037: ldloc.3
IL_0038: callvirt ""ref int C.M(int, CustomHandler)""
IL_003d: dup
IL_003e: ldind.i4
IL_003f: ldc.i4.2
IL_0040: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_0045: add
IL_0046: stind.i4
IL_0047: ret
}
",
(useBoolReturns: false, validityParameter: true) => @"
{
// Code size 81 (0x51)
.maxstack 6
.locals init (int V_0, //i
C V_1,
int V_2,
int V_3,
CustomHandler V_4,
bool V_5)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: stloc.3
IL_0012: ldc.i4.7
IL_0013: ldc.i4.1
IL_0014: ldloc.2
IL_0015: ldloc.1
IL_0016: ldloca.s V_5
IL_0018: newobj ""CustomHandler..ctor(int, int, int, C, out bool)""
IL_001d: stloc.s V_4
IL_001f: ldloc.s V_5
IL_0021: brfalse.s IL_003e
IL_0023: ldloca.s V_4
IL_0025: ldstr ""literal""
IL_002a: call ""void CustomHandler.AppendLiteral(string)""
IL_002f: ldloca.s V_4
IL_0031: ldloc.0
IL_0032: box ""int""
IL_0037: ldc.i4.0
IL_0038: ldnull
IL_0039: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_003e: ldloc.3
IL_003f: ldloc.s V_4
IL_0041: callvirt ""ref int C.M(int, CustomHandler)""
IL_0046: dup
IL_0047: ldind.i4
IL_0048: ldc.i4.2
IL_0049: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_004e: add
IL_004f: stind.i4
IL_0050: ret
}
",
(useBoolReturns: true, validityParameter: false) => @"
{
// Code size 78 (0x4e)
.maxstack 7
.locals init (int V_0, //i
C V_1,
int V_2,
CustomHandler V_3)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldloca.s V_3
IL_0013: ldc.i4.7
IL_0014: ldc.i4.1
IL_0015: ldloc.2
IL_0016: ldloc.1
IL_0017: call ""CustomHandler..ctor(int, int, int, C)""
IL_001c: ldloca.s V_3
IL_001e: ldstr ""literal""
IL_0023: call ""bool CustomHandler.AppendLiteral(string)""
IL_0028: brfalse.s IL_003b
IL_002a: ldloca.s V_3
IL_002c: ldloc.0
IL_002d: box ""int""
IL_0032: ldc.i4.0
IL_0033: ldnull
IL_0034: call ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_0039: br.s IL_003c
IL_003b: ldc.i4.0
IL_003c: pop
IL_003d: ldloc.3
IL_003e: callvirt ""ref int C.M(int, CustomHandler)""
IL_0043: dup
IL_0044: ldind.i4
IL_0045: ldc.i4.2
IL_0046: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_004b: add
IL_004c: stind.i4
IL_004d: ret
}
",
(useBoolReturns: true, validityParameter: true) => @"
{
// Code size 83 (0x53)
.maxstack 7
.locals init (int V_0, //i
C V_1,
int V_2,
CustomHandler V_3,
bool V_4)
IL_0000: ldc.i4.3
IL_0001: stloc.0
IL_0002: call ""C Program.<<Main>$>g__GetC|0_0()""
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldc.i4.7
IL_0012: ldc.i4.1
IL_0013: ldloc.2
IL_0014: ldloc.1
IL_0015: ldloca.s V_4
IL_0017: newobj ""CustomHandler..ctor(int, int, int, C, out bool)""
IL_001c: stloc.3
IL_001d: ldloc.s V_4
IL_001f: brfalse.s IL_0040
IL_0021: ldloca.s V_3
IL_0023: ldstr ""literal""
IL_0028: call ""bool CustomHandler.AppendLiteral(string)""
IL_002d: brfalse.s IL_0040
IL_002f: ldloca.s V_3
IL_0031: ldloc.0
IL_0032: box ""int""
IL_0037: ldc.i4.0
IL_0038: ldnull
IL_0039: call ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_003e: br.s IL_0041
IL_0040: ldc.i4.0
IL_0041: pop
IL_0042: ldloc.3
IL_0043: callvirt ""ref int C.M(int, CustomHandler)""
IL_0048: dup
IL_0049: ldind.i4
IL_004a: ldc.i4.2
IL_004b: call ""int Program.<<Main>$>g__GetInt|0_1(int)""
IL_0050: add
IL_0051: stind.i4
IL_0052: ret
}
",
};
}
[Theory]
[InlineData(@"$""literal""")]
[InlineData(@"$"""" + $""literal""")]
public void InterpolatedStringHandlerArgumentsAttribute_CollectionInitializerAdd(string expression)
{
var code = @"
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
_ = new C(1) { " + expression + @" };
public class C : IEnumerable<int>
{
public int Field;
public C(int i)
{
Field = i;
}
public void Add([InterpolatedStringHandlerArgument("""")] CustomHandler c)
{
Console.WriteLine(c.ToString());
}
public IEnumerator<int> GetEnumerator() => throw null;
IEnumerator IEnumerable.GetEnumerator() => throw null;
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount)
{
_builder.AppendLine(""c.Field:"" + c.Field.ToString());
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"
c.Field:1
literal:literal
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 37 (0x25)
.maxstack 5
.locals init (C V_0,
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: newobj ""C..ctor(int)""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldloca.s V_1
IL_000a: ldc.i4.7
IL_000b: ldc.i4.0
IL_000c: ldloc.0
IL_000d: call ""CustomHandler..ctor(int, int, C)""
IL_0012: ldloca.s V_1
IL_0014: ldstr ""literal""
IL_0019: call ""void CustomHandler.AppendLiteral(string)""
IL_001e: ldloc.1
IL_001f: callvirt ""void C.Add(CustomHandler)""
IL_0024: ret
}
");
}
[Theory]
[InlineData(@"$""literal""")]
[InlineData(@"$"""" + $""literal""")]
public void InterpolatedStringHandlerArgumentsAttribute_DictionaryInitializer(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
_ = new C(1) { [" + expression + @"] = 1 };
public class C
{
public int Field;
public C(int i)
{
Field = i;
}
public int this[[InterpolatedStringHandlerArgument("""")] CustomHandler c]
{
set => Console.WriteLine(c.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount)
{
_builder.AppendLine(""c.Field:"" + c.Field.ToString());
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
comp.VerifyDiagnostics(
// (5,17): error CS8976: Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers.
// _ = new C(1) { [$"literal"] = 1 };
Diagnostic(ErrorCode.ERR_InterpolatedStringsReferencingInstanceCannotBeInObjectInitializers, expression).WithLocation(5, 17)
);
}
[Theory]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_AttributeOnAppendFormatCall(bool useBoolReturns, bool validityParameter,
[CombinatorialValues(@"$""{$""Inner string""}{2}""", @"$""{$""Inner string""}"" + $""{2}""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(1, " + expression + @");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgument(""i"")]CustomHandler handler)
{
Console.WriteLine(handler.ToString());
}
}
public partial class CustomHandler
{
private int I = 0;
public CustomHandler(int literalLength, int formattedCount, int i" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount)
{
Console.WriteLine(""int constructor"");
I = i;
" + (validityParameter ? "success = true;" : "") + @"
}
public CustomHandler(int literalLength, int formattedCount, CustomHandler c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount)
{
Console.WriteLine(""CustomHandler constructor"");
_builder.AppendLine(""c.I:"" + c.I.ToString());
" + (validityParameter ? "success = true;" : "") + @"
}
public " + (useBoolReturns ? "bool" : "void") + @" AppendFormatted([InterpolatedStringHandlerArgument("""")]CustomHandler c)
{
_builder.AppendLine(""CustomHandler AppendFormatted"");
_builder.Append(c.ToString());
" + (useBoolReturns ? "return true;" : "") + @"
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: useBoolReturns);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"
int constructor
CustomHandler constructor
CustomHandler AppendFormatted
c.I:1
literal:Inner string
value:2
alignment:0
format:
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", getIl());
string getIl() => (useBoolReturns, validityParameter) switch
{
(useBoolReturns: false, validityParameter: false) => @"
{
// Code size 59 (0x3b)
.maxstack 6
.locals init (int V_0,
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.2
IL_0005: ldloc.0
IL_0006: newobj ""CustomHandler..ctor(int, int, int)""
IL_000b: dup
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: ldc.i4.s 12
IL_0010: ldc.i4.0
IL_0011: ldloc.1
IL_0012: newobj ""CustomHandler..ctor(int, int, CustomHandler)""
IL_0017: dup
IL_0018: ldstr ""Inner string""
IL_001d: callvirt ""void CustomHandler.AppendLiteral(string)""
IL_0022: callvirt ""void CustomHandler.AppendFormatted(CustomHandler)""
IL_0027: dup
IL_0028: ldc.i4.2
IL_0029: box ""int""
IL_002e: ldc.i4.0
IL_002f: ldnull
IL_0030: callvirt ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0035: call ""void C.M(int, CustomHandler)""
IL_003a: ret
}
",
(useBoolReturns: false, validityParameter: true) => @"
{
// Code size 77 (0x4d)
.maxstack 6
.locals init (int V_0,
CustomHandler V_1,
bool V_2,
CustomHandler V_3,
CustomHandler V_4,
bool V_5)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.2
IL_0005: ldloc.0
IL_0006: ldloca.s V_2
IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)""
IL_000d: stloc.1
IL_000e: ldloc.2
IL_000f: brfalse.s IL_0046
IL_0011: ldloc.1
IL_0012: stloc.3
IL_0013: ldloc.3
IL_0014: ldc.i4.s 12
IL_0016: ldc.i4.0
IL_0017: ldloc.3
IL_0018: ldloca.s V_5
IL_001a: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)""
IL_001f: stloc.s V_4
IL_0021: ldloc.s V_5
IL_0023: brfalse.s IL_0031
IL_0025: ldloc.s V_4
IL_0027: ldstr ""Inner string""
IL_002c: callvirt ""void CustomHandler.AppendLiteral(string)""
IL_0031: ldloc.s V_4
IL_0033: callvirt ""void CustomHandler.AppendFormatted(CustomHandler)""
IL_0038: ldloc.1
IL_0039: ldc.i4.2
IL_003a: box ""int""
IL_003f: ldc.i4.0
IL_0040: ldnull
IL_0041: callvirt ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0046: ldloc.1
IL_0047: call ""void C.M(int, CustomHandler)""
IL_004c: ret
}
",
(useBoolReturns: true, validityParameter: false) => @"
{
// Code size 68 (0x44)
.maxstack 5
.locals init (int V_0,
CustomHandler V_1,
CustomHandler V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.2
IL_0005: ldloc.0
IL_0006: newobj ""CustomHandler..ctor(int, int, int)""
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: stloc.2
IL_000e: ldloc.2
IL_000f: ldc.i4.s 12
IL_0011: ldc.i4.0
IL_0012: ldloc.2
IL_0013: newobj ""CustomHandler..ctor(int, int, CustomHandler)""
IL_0018: dup
IL_0019: ldstr ""Inner string""
IL_001e: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0023: pop
IL_0024: callvirt ""bool CustomHandler.AppendFormatted(CustomHandler)""
IL_0029: brfalse.s IL_003b
IL_002b: ldloc.1
IL_002c: ldc.i4.2
IL_002d: box ""int""
IL_0032: ldc.i4.0
IL_0033: ldnull
IL_0034: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_0039: br.s IL_003c
IL_003b: ldc.i4.0
IL_003c: pop
IL_003d: ldloc.1
IL_003e: call ""void C.M(int, CustomHandler)""
IL_0043: ret
}
",
(useBoolReturns: true, validityParameter: true) => @"
{
// Code size 87 (0x57)
.maxstack 6
.locals init (int V_0,
CustomHandler V_1,
bool V_2,
CustomHandler V_3,
CustomHandler V_4,
bool V_5)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.2
IL_0005: ldloc.0
IL_0006: ldloca.s V_2
IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)""
IL_000d: stloc.1
IL_000e: ldloc.2
IL_000f: brfalse.s IL_004e
IL_0011: ldloc.1
IL_0012: stloc.3
IL_0013: ldloc.3
IL_0014: ldc.i4.s 12
IL_0016: ldc.i4.0
IL_0017: ldloc.3
IL_0018: ldloca.s V_5
IL_001a: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)""
IL_001f: stloc.s V_4
IL_0021: ldloc.s V_5
IL_0023: brfalse.s IL_0033
IL_0025: ldloc.s V_4
IL_0027: ldstr ""Inner string""
IL_002c: callvirt ""bool CustomHandler.AppendLiteral(string)""
IL_0031: br.s IL_0034
IL_0033: ldc.i4.0
IL_0034: pop
IL_0035: ldloc.s V_4
IL_0037: callvirt ""bool CustomHandler.AppendFormatted(CustomHandler)""
IL_003c: brfalse.s IL_004e
IL_003e: ldloc.1
IL_003f: ldc.i4.2
IL_0040: box ""int""
IL_0045: ldc.i4.0
IL_0046: ldnull
IL_0047: callvirt ""bool CustomHandler.AppendFormatted(object, int, string)""
IL_004c: br.s IL_004f
IL_004e: ldc.i4.0
IL_004f: pop
IL_0050: ldloc.1
IL_0051: call ""void C.M(int, CustomHandler)""
IL_0056: ret
}
",
};
}
[Theory]
[InlineData(@"$""literal""")]
[InlineData(@"$"""" + $""literal""")]
public void DiscardsUsedAsParameters(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(out _, " + expression + @");
public class C
{
public static void M(out int i, [InterpolatedStringHandlerArgument(""i"")]CustomHandler c)
{
i = 0;
Console.WriteLine(c.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, out int i) : this(literalLength, formattedCount)
{
i = 1;
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: @"literal:literal");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 31 (0x1f)
.maxstack 4
.locals init (int V_0,
CustomHandler V_1)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.7
IL_0003: ldc.i4.0
IL_0004: ldloca.s V_0
IL_0006: newobj ""CustomHandler..ctor(int, int, out int)""
IL_000b: stloc.1
IL_000c: ldloca.s V_1
IL_000e: ldstr ""literal""
IL_0013: call ""void CustomHandler.AppendLiteral(string)""
IL_0018: ldloc.1
IL_0019: call ""void C.M(out int, CustomHandler)""
IL_001e: ret
}
");
}
[Fact]
public void DiscardsUsedAsParameters_DefinedInVB()
{
var vb = @"
Imports System
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Public Class C
Public Shared Sub M(<Out> ByRef i As Integer, <InterpolatedStringHandlerArgument(""i"")>c As CustomHandler)
Console.WriteLine(i)
End Sub
End Class
<InterpolatedStringHandler>
Public Structure CustomHandler
Public Sub New(literalLength As Integer, formattedCount As Integer, <Out> ByRef i As Integer)
i = 1
End Sub
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vb, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var code = @"C.M(out _, $"""");";
var comp = CreateCompilation(code, new[] { vbComp.EmitToImageReference() });
var verifier = CompileAndVerify(comp, expectedOutput: @"1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 17 (0x11)
.maxstack 4
.locals init (int V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.0
IL_0003: ldc.i4.0
IL_0004: ldloca.s V_0
IL_0006: newobj ""CustomHandler..ctor(int, int, out int)""
IL_000b: call ""void C.M(out int, CustomHandler)""
IL_0010: ret
}
");
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void DisallowedInExpressionTrees(string expression)
{
var code = @"
using System;
using System.Linq.Expressions;
Expression<Func<CustomHandler>> expr = () => " + expression + @";
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, handler });
comp.VerifyDiagnostics(
// (5,46): error CS8952: An expression tree may not contain an interpolated string handler conversion.
// Expression<Func<CustomHandler>> expr = () => $"";
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsInterpolatedStringHandlerConversion, expression).WithLocation(5, 46)
);
}
[Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")]
public void AsStringInExpressionTrees_01()
{
var code = @"
using System;
using System.Linq.Expressions;
Expression<Func<string, string>> e = o => $""{o.Length}"";";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
var verifier = CompileAndVerify(comp);
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 127 (0x7f)
.maxstack 7
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""string""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""o""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldnull
IL_0016: ldtoken ""string string.Format(string, object)""
IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0020: castclass ""System.Reflection.MethodInfo""
IL_0025: ldc.i4.2
IL_0026: newarr ""System.Linq.Expressions.Expression""
IL_002b: dup
IL_002c: ldc.i4.0
IL_002d: ldstr ""{0}""
IL_0032: ldtoken ""string""
IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0041: stelem.ref
IL_0042: dup
IL_0043: ldc.i4.1
IL_0044: ldloc.0
IL_0045: ldtoken ""int string.Length.get""
IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_004f: castclass ""System.Reflection.MethodInfo""
IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0059: ldtoken ""object""
IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0068: stelem.ref
IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_006e: ldc.i4.1
IL_006f: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0074: dup
IL_0075: ldc.i4.0
IL_0076: ldloc.0
IL_0077: stelem.ref
IL_0078: call ""System.Linq.Expressions.Expression<System.Func<string, string>> System.Linq.Expressions.Expression.Lambda<System.Func<string, string>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_007d: pop
IL_007e: ret
}
");
}
[Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")]
public void AsStringInExpressionTrees_02()
{
var code = @"
using System.Linq.Expressions;
Expression e = (string o) => $""{o.Length}"";";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
var verifier = CompileAndVerify(comp);
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 127 (0x7f)
.maxstack 7
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""string""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""o""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldnull
IL_0016: ldtoken ""string string.Format(string, object)""
IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0020: castclass ""System.Reflection.MethodInfo""
IL_0025: ldc.i4.2
IL_0026: newarr ""System.Linq.Expressions.Expression""
IL_002b: dup
IL_002c: ldc.i4.0
IL_002d: ldstr ""{0}""
IL_0032: ldtoken ""string""
IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0041: stelem.ref
IL_0042: dup
IL_0043: ldc.i4.1
IL_0044: ldloc.0
IL_0045: ldtoken ""int string.Length.get""
IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_004f: castclass ""System.Reflection.MethodInfo""
IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0059: ldtoken ""object""
IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0068: stelem.ref
IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_006e: ldc.i4.1
IL_006f: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0074: dup
IL_0075: ldc.i4.0
IL_0076: ldloc.0
IL_0077: stelem.ref
IL_0078: call ""System.Linq.Expressions.Expression<System.Func<string, string>> System.Linq.Expressions.Expression.Lambda<System.Func<string, string>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_007d: pop
IL_007e: ret
}
");
}
[Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")]
public void AsStringInExpressionTrees_03()
{
var code = @"
using System;
using System.Linq.Expressions;
Expression<Func<Func<string, string>>> e = () => o => $""{o.Length}"";";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
var verifier = CompileAndVerify(comp);
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 137 (0x89)
.maxstack 7
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""string""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""o""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldnull
IL_0016: ldtoken ""string string.Format(string, object)""
IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0020: castclass ""System.Reflection.MethodInfo""
IL_0025: ldc.i4.2
IL_0026: newarr ""System.Linq.Expressions.Expression""
IL_002b: dup
IL_002c: ldc.i4.0
IL_002d: ldstr ""{0}""
IL_0032: ldtoken ""string""
IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0041: stelem.ref
IL_0042: dup
IL_0043: ldc.i4.1
IL_0044: ldloc.0
IL_0045: ldtoken ""int string.Length.get""
IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_004f: castclass ""System.Reflection.MethodInfo""
IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0059: ldtoken ""object""
IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0068: stelem.ref
IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_006e: ldc.i4.1
IL_006f: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0074: dup
IL_0075: ldc.i4.0
IL_0076: ldloc.0
IL_0077: stelem.ref
IL_0078: call ""System.Linq.Expressions.Expression<System.Func<string, string>> System.Linq.Expressions.Expression.Lambda<System.Func<string, string>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_007d: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty<System.Linq.Expressions.ParameterExpression>()""
IL_0082: call ""System.Linq.Expressions.Expression<System.Func<System.Func<string, string>>> System.Linq.Expressions.Expression.Lambda<System.Func<System.Func<string, string>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0087: pop
IL_0088: ret
}
");
}
[Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")]
public void AsStringInExpressionTrees_04()
{
var code = @"
using System;
using System.Linq.Expressions;
Expression e = Func<string, string> () => (string o) => $""{o.Length}"";";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
var verifier = CompileAndVerify(comp);
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 137 (0x89)
.maxstack 7
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""string""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""o""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldnull
IL_0016: ldtoken ""string string.Format(string, object)""
IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0020: castclass ""System.Reflection.MethodInfo""
IL_0025: ldc.i4.2
IL_0026: newarr ""System.Linq.Expressions.Expression""
IL_002b: dup
IL_002c: ldc.i4.0
IL_002d: ldstr ""{0}""
IL_0032: ldtoken ""string""
IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0041: stelem.ref
IL_0042: dup
IL_0043: ldc.i4.1
IL_0044: ldloc.0
IL_0045: ldtoken ""int string.Length.get""
IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_004f: castclass ""System.Reflection.MethodInfo""
IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0059: ldtoken ""object""
IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0068: stelem.ref
IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_006e: ldc.i4.1
IL_006f: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0074: dup
IL_0075: ldc.i4.0
IL_0076: ldloc.0
IL_0077: stelem.ref
IL_0078: call ""System.Linq.Expressions.Expression<System.Func<string, string>> System.Linq.Expressions.Expression.Lambda<System.Func<string, string>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_007d: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty<System.Linq.Expressions.ParameterExpression>()""
IL_0082: call ""System.Linq.Expressions.Expression<System.Func<System.Func<string, string>>> System.Linq.Expressions.Expression.Lambda<System.Func<System.Func<string, string>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0087: pop
IL_0088: ret
}
");
}
[Fact, WorkItem(55114, "https://github.com/dotnet/roslyn/issues/55114")]
public void AsStringInExpressionTrees_05()
{
var code = @"
using System;
using System.Linq.Expressions;
Expression<Func<string, string>> e = o => $""{o.Length}"" + $""literal"";";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
var verifier = CompileAndVerify(comp);
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 167 (0xa7)
.maxstack 7
.locals init (System.Linq.Expressions.ParameterExpression V_0)
IL_0000: ldtoken ""string""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""o""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldnull
IL_0016: ldtoken ""string string.Format(string, object)""
IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0020: castclass ""System.Reflection.MethodInfo""
IL_0025: ldc.i4.2
IL_0026: newarr ""System.Linq.Expressions.Expression""
IL_002b: dup
IL_002c: ldc.i4.0
IL_002d: ldstr ""{0}""
IL_0032: ldtoken ""string""
IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0041: stelem.ref
IL_0042: dup
IL_0043: ldc.i4.1
IL_0044: ldloc.0
IL_0045: ldtoken ""int string.Length.get""
IL_004a: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_004f: castclass ""System.Reflection.MethodInfo""
IL_0054: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0059: ldtoken ""object""
IL_005e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0063: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0068: stelem.ref
IL_0069: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_006e: ldstr ""literal""
IL_0073: ldtoken ""string""
IL_0078: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_007d: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0082: ldtoken ""string string.Concat(string, string)""
IL_0087: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_008c: castclass ""System.Reflection.MethodInfo""
IL_0091: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression.Add(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_0096: ldc.i4.1
IL_0097: newarr ""System.Linq.Expressions.ParameterExpression""
IL_009c: dup
IL_009d: ldc.i4.0
IL_009e: ldloc.0
IL_009f: stelem.ref
IL_00a0: call ""System.Linq.Expressions.Expression<System.Func<string, string>> System.Linq.Expressions.Expression.Lambda<System.Func<string, string>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_00a5: pop
IL_00a6: ret
}
");
}
[Theory]
[CombinatorialData]
public void CustomHandlerUsedAsArgumentToCustomHandler(bool useBoolReturns, bool validityParameter, [CombinatorialValues(@"$""""", @"$"""" + $""""")] string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(1, " + expression + @", " + expression + @");
public class C
{
public static void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c1, [InterpolatedStringHandlerArgument(""c1"")] CustomHandler c2) => Console.WriteLine(c2.ToString());
}
public partial class CustomHandler
{
private int i;
public CustomHandler(int literalLength, int formattedCount, int i" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""i:"" + i.ToString());
this.i = i;
" + (validityParameter ? "success = true;" : "") + @"
}
public CustomHandler(int literalLength, int formattedCount, CustomHandler c" + (validityParameter ? ", out bool success" : "") + @") : this(literalLength, formattedCount)
{
_builder.AppendLine(""c.i:"" + c.i.ToString());
" + (validityParameter ? "success = true;" : "") + @"
}
}";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: "c.i:1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", getIl());
string getIl() => (useBoolReturns, validityParameter) switch
{
(useBoolReturns: false, validityParameter: false) => @"
{
// Code size 27 (0x1b)
.maxstack 5
.locals init (int V_0,
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: newobj ""CustomHandler..ctor(int, int, int)""
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: ldc.i4.0
IL_000e: ldc.i4.0
IL_000f: ldloc.1
IL_0010: newobj ""CustomHandler..ctor(int, int, CustomHandler)""
IL_0015: call ""void C.M(int, CustomHandler, CustomHandler)""
IL_001a: ret
}
",
(useBoolReturns: false, validityParameter: true) => @"
{
// Code size 31 (0x1f)
.maxstack 6
.locals init (int V_0,
CustomHandler V_1,
bool V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: ldloca.s V_2
IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)""
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldc.i4.0
IL_0010: ldc.i4.0
IL_0011: ldloc.1
IL_0012: ldloca.s V_2
IL_0014: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)""
IL_0019: call ""void C.M(int, CustomHandler, CustomHandler)""
IL_001e: ret
}
",
(useBoolReturns: true, validityParameter: false) => @"
{
// Code size 27 (0x1b)
.maxstack 5
.locals init (int V_0,
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: newobj ""CustomHandler..ctor(int, int, int)""
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: ldc.i4.0
IL_000e: ldc.i4.0
IL_000f: ldloc.1
IL_0010: newobj ""CustomHandler..ctor(int, int, CustomHandler)""
IL_0015: call ""void C.M(int, CustomHandler, CustomHandler)""
IL_001a: ret
}
",
(useBoolReturns: true, validityParameter: true) => @"
{
// Code size 31 (0x1f)
.maxstack 6
.locals init (int V_0,
CustomHandler V_1,
bool V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: ldloca.s V_2
IL_0008: newobj ""CustomHandler..ctor(int, int, int, out bool)""
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldc.i4.0
IL_0010: ldc.i4.0
IL_0011: ldloc.1
IL_0012: ldloca.s V_2
IL_0014: newobj ""CustomHandler..ctor(int, int, CustomHandler, out bool)""
IL_0019: call ""void C.M(int, CustomHandler, CustomHandler)""
IL_001e: ret
}
",
};
}
[Fact, WorkItem(1370647, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1370647")]
public void AsFormattableString()
{
var code = @"
M($""{1}"" + $""literal"");
System.FormattableString s = $""{1}"" + $""literal"";
void M(System.FormattableString s)
{
}
";
var comp = CreateCompilation(code);
comp.VerifyDiagnostics(
// (2,3): error CS1503: Argument 1: cannot convert from 'string' to 'System.FormattableString'
// M($"{1}" + $"literal");
Diagnostic(ErrorCode.ERR_BadArgType, @"$""{1}"" + $""literal""").WithArguments("1", "string", "System.FormattableString").WithLocation(2, 3),
// (3,30): error CS0029: Cannot implicitly convert type 'string' to 'System.FormattableString'
// System.FormattableString s = $"{1}" + $"literal";
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""{1}"" + $""literal""").WithArguments("string", "System.FormattableString").WithLocation(3, 30)
);
}
[Fact, WorkItem(1370647, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1370647")]
public void AsIFormattable()
{
var code = @"
M($""{1}"" + $""literal"");
System.IFormattable s = $""{1}"" + $""literal"";
void M(System.IFormattable s)
{
}
";
var comp = CreateCompilation(code);
comp.VerifyDiagnostics(
// (2,3): error CS1503: Argument 1: cannot convert from 'string' to 'System.IFormattable'
// M($"{1}" + $"literal");
Diagnostic(ErrorCode.ERR_BadArgType, @"$""{1}"" + $""literal""").WithArguments("1", "string", "System.IFormattable").WithLocation(2, 3),
// (3,25): error CS0029: Cannot implicitly convert type 'string' to 'System.IFormattable'
// System.IFormattable s = $"{1}" + $"literal";
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"$""{1}"" + $""literal""").WithArguments("string", "System.IFormattable").WithLocation(3, 25)
);
}
[Theory]
[CombinatorialData]
public void DefiniteAssignment_01(bool useBoolReturns, bool trailingOutParameter,
[CombinatorialValues(@"$""{i = 1}{M(out var o)}{s = o.ToString()}""", @"$""{i = 1}"" + $""{M(out var o)}"" + $""{s = o.ToString()}""")] string expression)
{
var code = @"
int i;
string s;
CustomHandler c = " + expression + @";
_ = i.ToString();
_ = o.ToString();
_ = s.ToString();
string M(out object o)
{
o = null;
return null;
}
";
var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns, includeTrailingOutConstructorParameter: trailingOutParameter);
var comp = CreateCompilation(new[] { code, customHandler });
if (trailingOutParameter)
{
comp.VerifyDiagnostics(
// (6,5): error CS0165: Use of unassigned local variable 'i'
// _ = i.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "i").WithArguments("i").WithLocation(6, 5),
// (7,5): error CS0165: Use of unassigned local variable 'o'
// _ = o.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "o").WithArguments("o").WithLocation(7, 5),
// (8,5): error CS0165: Use of unassigned local variable 's'
// _ = s.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(8, 5)
);
}
else if (useBoolReturns)
{
comp.VerifyDiagnostics(
// (7,5): error CS0165: Use of unassigned local variable 'o'
// _ = o.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "o").WithArguments("o").WithLocation(7, 5),
// (8,5): error CS0165: Use of unassigned local variable 's'
// _ = s.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(8, 5)
);
}
else
{
comp.VerifyDiagnostics();
}
}
[Theory]
[CombinatorialData]
public void DefiniteAssignment_02(bool useBoolReturns, bool trailingOutParameter, [CombinatorialValues(@"$""{i = 1}""", @"$"""" + $""{i = 1}""", @"$""{i = 1}"" + $""""")] string expression)
{
var code = @"
int i;
CustomHandler c = " + expression + @";
_ = i.ToString();
";
var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns, includeTrailingOutConstructorParameter: trailingOutParameter);
var comp = CreateCompilation(new[] { code, customHandler });
if (trailingOutParameter)
{
comp.VerifyDiagnostics(
// (5,5): error CS0165: Use of unassigned local variable 'i'
// _ = i.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "i").WithArguments("i").WithLocation(5, 5)
);
}
else
{
comp.VerifyDiagnostics();
}
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void DynamicConstruction_01(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
dynamic d = 1;
M(d, " + expression + @");
void M(dynamic d, [InterpolatedStringHandlerArgument(""d"")]CustomHandler c) {}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int d) : this() {}
public CustomHandler(int literalLength, int formattedCount, long d) : this() {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute });
comp.VerifyDiagnostics(
// (4,6): error CS8953: An interpolated string handler construction cannot use dynamic. Manually construct an instance of 'CustomHandler'.
// M(d, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerCreationCannotUseDynamic, expression).WithArguments("CustomHandler").WithLocation(4, 6)
);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void DynamicConstruction_02(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
int i = 1;
M(i, " + expression + @");
void M(dynamic d, [InterpolatedStringHandlerArgument(""d"")]CustomHandler c) {}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int d) : this() {}
public CustomHandler(int literalLength, int formattedCount, long d) : this() {}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute });
comp.VerifyDiagnostics(
// (4,6): error CS8953: An interpolated string handler construction cannot use dynamic. Manually construct an instance of 'CustomHandler'.
// M(d, $"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerCreationCannotUseDynamic, expression).WithArguments("CustomHandler").WithLocation(4, 6)
);
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void DynamicConstruction_03(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
int i = 1;
M(i, " + expression + @");
void M(int i, [InterpolatedStringHandlerArgument(""i"")]CustomHandler c) {}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, dynamic d) : this(literalLength, formattedCount)
{
Console.WriteLine(""d:"" + d.ToString());
}
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false, includeOneTimeHelpers: false);
var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: "d:1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 22 (0x16)
.maxstack 4
.locals init (int V_0)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: box ""int""
IL_000b: newobj ""CustomHandler..ctor(int, int, dynamic)""
IL_0010: call ""void Program.<<Main>$>g__M|0_0(int, CustomHandler)""
IL_0015: ret
}
");
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void DynamicConstruction_04(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
M(" + expression + @");
void M(CustomHandler c) {}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(dynamic literalLength, int formattedCount)
{
Console.WriteLine(""ctor"");
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: "ctor");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldc.i4.0
IL_0001: box ""int""
IL_0006: ldc.i4.0
IL_0007: newobj ""CustomHandler..ctor(dynamic, int)""
IL_000c: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_0011: ret
}
");
}
[Theory]
[InlineData(@"$""""")]
[InlineData(@"$"""" + $""""")]
public void DynamicConstruction_05(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
M(" + expression + @");
void M(CustomHandler c) {}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount)
{
Console.WriteLine(""ctor"");
}
public CustomHandler(dynamic literalLength, int formattedCount)
{
throw null;
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: "ctor");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: newobj ""CustomHandler..ctor(int, int)""
IL_0007: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_000c: ret
}
");
}
[Theory]
[InlineData(@"$""Literal""")]
[InlineData(@"$"""" + $""Literal""")]
public void DynamicConstruction_06(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
M(" + expression + @");
void M(CustomHandler c) {}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount)
{
}
public void AppendLiteral(dynamic d)
{
Console.WriteLine(""AppendLiteral"");
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: "AppendLiteral");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 28 (0x1c)
.maxstack 3
.locals init (CustomHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.7
IL_0003: ldc.i4.0
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldstr ""Literal""
IL_0010: call ""void CustomHandler.AppendLiteral(dynamic)""
IL_0015: ldloc.0
IL_0016: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_001b: ret
}
");
}
[Theory]
[InlineData(@"$""{1}""")]
[InlineData(@"$""{1}"" + $""""")]
public void DynamicConstruction_07(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
M(" + expression + @");
void M(CustomHandler c) {}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount)
{
}
public void AppendFormatted(dynamic d)
{
Console.WriteLine(""AppendFormatted"");
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: "AppendFormatted");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 29 (0x1d)
.maxstack 3
.locals init (CustomHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.0
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_0
IL_000b: ldc.i4.1
IL_000c: box ""int""
IL_0011: call ""void CustomHandler.AppendFormatted(dynamic)""
IL_0016: ldloc.0
IL_0017: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_001c: ret
}
");
}
[Theory]
[InlineData(@"$""literal{d}""")]
[InlineData(@"$""literal"" + $""{d}""")]
public void DynamicConstruction_08_01(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
dynamic d = 1;
M(" + expression + @");
void M(CustomHandler c) {}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount)
{
}
public void AppendLiteral(dynamic d)
{
Console.WriteLine(""AppendLiteral"");
}
public void AppendFormatted(dynamic d)
{
Console.WriteLine(""AppendFormatted"");
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
AppendLiteral
AppendFormatted");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 128 (0x80)
.maxstack 9
.locals init (object V_0, //d
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.0
IL_0007: ldloca.s V_1
IL_0009: ldc.i4.7
IL_000a: ldc.i4.1
IL_000b: call ""CustomHandler..ctor(int, int)""
IL_0010: ldloca.s V_1
IL_0012: ldstr ""literal""
IL_0017: call ""void CustomHandler.AppendLiteral(dynamic)""
IL_001c: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0021: brtrue.s IL_0062
IL_0023: ldc.i4 0x100
IL_0028: ldstr ""AppendFormatted""
IL_002d: ldnull
IL_002e: ldtoken ""Program""
IL_0033: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0038: ldc.i4.2
IL_0039: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo""
IL_003e: dup
IL_003f: ldc.i4.0
IL_0040: ldc.i4.s 9
IL_0042: ldnull
IL_0043: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_0048: stelem.ref
IL_0049: dup
IL_004a: ldc.i4.1
IL_004b: ldc.i4.0
IL_004c: ldnull
IL_004d: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_0052: stelem.ref
IL_0053: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable<System.Type>, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)""
IL_0058: call ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_005d: stsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0062: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0067: ldfld ""<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic> System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>>.Target""
IL_006c: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0071: ldloca.s V_1
IL_0073: ldloc.0
IL_0074: callvirt ""void <>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, ref CustomHandler, dynamic)""
IL_0079: ldloc.1
IL_007a: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_007f: ret
}
");
}
[Theory]
[InlineData(@"$""literal{d}""")]
[InlineData(@"$""literal"" + $""{d}""")]
public void DynamicConstruction_08_02(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
dynamic d = 1;
M(" + expression + @");
void M(CustomHandler c) {}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount)
{
}
public void AppendLiteral(dynamic d)
{
Console.WriteLine(""AppendLiteral"");
}
public void AppendFormatted(dynamic d)
{
Console.WriteLine(""---"");
}
public void AppendFormatted(int d)
{
Console.WriteLine(""AppendFormatted"");
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
AppendLiteral
AppendFormatted");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 128 (0x80)
.maxstack 9
.locals init (object V_0, //d
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.0
IL_0007: ldloca.s V_1
IL_0009: ldc.i4.7
IL_000a: ldc.i4.1
IL_000b: call ""CustomHandler..ctor(int, int)""
IL_0010: ldloca.s V_1
IL_0012: ldstr ""literal""
IL_0017: call ""void CustomHandler.AppendLiteral(dynamic)""
IL_001c: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0021: brtrue.s IL_0062
IL_0023: ldc.i4 0x100
IL_0028: ldstr ""AppendFormatted""
IL_002d: ldnull
IL_002e: ldtoken ""Program""
IL_0033: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0038: ldc.i4.2
IL_0039: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo""
IL_003e: dup
IL_003f: ldc.i4.0
IL_0040: ldc.i4.s 9
IL_0042: ldnull
IL_0043: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_0048: stelem.ref
IL_0049: dup
IL_004a: ldc.i4.1
IL_004b: ldc.i4.0
IL_004c: ldnull
IL_004d: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_0052: stelem.ref
IL_0053: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable<System.Type>, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)""
IL_0058: call ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_005d: stsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0062: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0067: ldfld ""<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic> System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>>.Target""
IL_006c: ldsfld ""System.Runtime.CompilerServices.CallSite<<>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>> Program.<>o__0.<>p__0""
IL_0071: ldloca.s V_1
IL_0073: ldloc.0
IL_0074: callvirt ""void <>A{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, ref CustomHandler, dynamic)""
IL_0079: ldloc.1
IL_007a: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_007f: ret
}
");
}
[Theory]
[InlineData(@"$""literal{d}""")]
[InlineData(@"$""literal"" + $""{d}""")]
public void DynamicConstruction_09(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
dynamic d = 1;
M(" + expression + @");
void M(CustomHandler c) {}
[InterpolatedStringHandler]
public struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount)
{
}
public bool AppendLiteral(dynamic d)
{
Console.WriteLine(""AppendLiteral"");
return true;
}
public bool AppendFormatted(dynamic d)
{
Console.WriteLine(""---"");
return true;
}
public bool AppendFormatted(long d)
{
Console.WriteLine(""AppendFormatted"");
return true;
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp);
var verifier = CompileAndVerify(comp, expectedOutput: @"
AppendLiteral
AppendFormatted");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 196 (0xc4)
.maxstack 11
.locals init (object V_0, //d
CustomHandler V_1)
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.0
IL_0007: ldloca.s V_1
IL_0009: ldc.i4.7
IL_000a: ldc.i4.1
IL_000b: call ""CustomHandler..ctor(int, int)""
IL_0010: ldloca.s V_1
IL_0012: ldstr ""literal""
IL_0017: call ""bool CustomHandler.AppendLiteral(dynamic)""
IL_001c: brfalse IL_00bb
IL_0021: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>> Program.<>o__0.<>p__1""
IL_0026: brtrue.s IL_004c
IL_0028: ldc.i4.0
IL_0029: ldtoken ""bool""
IL_002e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0033: ldtoken ""Program""
IL_0038: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003d: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.Convert(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, System.Type, System.Type)""
IL_0042: call ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_0047: stsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>> Program.<>o__0.<>p__1""
IL_004c: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>> Program.<>o__0.<>p__1""
IL_0051: ldfld ""System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>>.Target""
IL_0056: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>> Program.<>o__0.<>p__1""
IL_005b: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>> Program.<>o__0.<>p__0""
IL_0060: brtrue.s IL_009d
IL_0062: ldc.i4.0
IL_0063: ldstr ""AppendFormatted""
IL_0068: ldnull
IL_0069: ldtoken ""Program""
IL_006e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0073: ldc.i4.2
IL_0074: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo""
IL_0079: dup
IL_007a: ldc.i4.0
IL_007b: ldc.i4.s 9
IL_007d: ldnull
IL_007e: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_0083: stelem.ref
IL_0084: dup
IL_0085: ldc.i4.1
IL_0086: ldc.i4.0
IL_0087: ldnull
IL_0088: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_008d: stelem.ref
IL_008e: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable<System.Type>, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)""
IL_0093: call ""System.Runtime.CompilerServices.CallSite<<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>> System.Runtime.CompilerServices.CallSite<<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_0098: stsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>> Program.<>o__0.<>p__0""
IL_009d: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>> Program.<>o__0.<>p__0""
IL_00a2: ldfld ""<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic> System.Runtime.CompilerServices.CallSite<<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>>.Target""
IL_00a7: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>> Program.<>o__0.<>p__0""
IL_00ac: ldloca.s V_1
IL_00ae: ldloc.0
IL_00af: callvirt ""dynamic <>F{00000008}<System.Runtime.CompilerServices.CallSite, CustomHandler, dynamic, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, ref CustomHandler, dynamic)""
IL_00b4: callvirt ""bool System.Func<System.Runtime.CompilerServices.CallSite, dynamic, bool>.Invoke(System.Runtime.CompilerServices.CallSite, dynamic)""
IL_00b9: br.s IL_00bc
IL_00bb: ldc.i4.0
IL_00bc: pop
IL_00bd: ldloc.1
IL_00be: call ""void Program.<<Main>$>g__M|0_0(CustomHandler)""
IL_00c3: ret
}
");
}
[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
public void DynamicConstruction10(
[CombinatorialValues(@"$""literal{d}""", @"$""literal"" + $""{d}""")] string expression,
[CombinatorialValues("object", "dynamic", "string")] string type)
{
var source = $$"""
using System;
using System.Runtime.CompilerServices;
using System.Text;
dynamic d = "Hello world!";
Console.WriteLine(Interpolate({{expression}}));
static string Interpolate(CustomInterpolationHandler text)
{
return text.ToString();
}
[InterpolatedStringHandler]
public ref struct CustomInterpolationHandler
{
private StringBuilder StringBuilder;
public CustomInterpolationHandler(int literalLength, int formattedCount)
{
StringBuilder = new StringBuilder();
}
public void AppendLiteral(string text)
{
StringBuilder.Append(text);
}
public void AppendFormatted({{type}} item)
{
StringBuilder.Append(item);
}
public override string ToString()
{
return StringBuilder.ToString();
}
}
""";
var comp = CreateCompilation([source, InterpolatedStringHandlerAttribute], targetFramework: TargetFramework.StandardAndCSharp);
comp.VerifyDiagnostics(
// (7,31): error CS9230: Cannot perform a dynamic invocation on an expression with type 'CustomInterpolationHandler'.
// Console.WriteLine(Interpolate($"literal" + $"{d}"));
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnExpression, expression).WithArguments("CustomInterpolationHandler").WithLocation(7, 31)
);
}
[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
public void DynamicConstruction11([CombinatorialValues(@"$""literal{d}""", @"$""literal"" + $""{d}""")] string expression)
{
var source = $$"""
using System;
using System.Runtime.CompilerServices;
using System.Text;
dynamic d = "Hello world!";
Console.WriteLine(Interpolate({{expression}}));
static string Interpolate(CustomInterpolationHandler text)
{
return text.ToString();
}
[InterpolatedStringHandler]
public ref struct CustomInterpolationHandler
{
private StringBuilder StringBuilder;
public CustomInterpolationHandler(int literalLength, int formattedCount)
{
StringBuilder = new StringBuilder();
}
public void AppendLiteral(string text)
{
StringBuilder.Append(text);
}
public void AppendFormatted<T>(T item)
{
StringBuilder.Append(item);
}
public override string ToString()
{
return StringBuilder.ToString();
}
}
""";
CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp).VerifyDiagnostics(
// (7,31): error CS9230: Cannot perform a dynamic invocation on an expression with type 'CustomInterpolationHandler'.
// Console.WriteLine(Interpolate($"literal" + $"{d}"));
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnExpression, expression).WithArguments("CustomInterpolationHandler").WithLocation(7, 31)
);
}
[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
public void DynamicConstruction12([CombinatorialValues(@"$""literal{d}""", @"$""literal"" + $""{d}""")] string expression)
{
var source = $$"""
using System;
using System.Runtime.CompilerServices;
using System.Text;
dynamic d = "Hello world!";
Console.WriteLine(Interpolate({{expression}}));
static string Interpolate(CustomInterpolationHandler text)
{
return text.ToString();
}
[InterpolatedStringHandler]
public ref struct CustomInterpolationHandler
{
private StringBuilder StringBuilder;
public CustomInterpolationHandler(int literalLength, int formattedCount)
{
StringBuilder = new StringBuilder();
}
public void AppendLiteral(string text)
{
StringBuilder.Append(text);
}
public void AppendFormatted(object item)
{
StringBuilder.Append(item);
}
public void AppendFormatted(string item)
{
StringBuilder.Append(item);
}
public override string ToString()
{
return StringBuilder.ToString();
}
}
""";
CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp).VerifyDiagnostics(
// (7,31): error CS9230: Cannot perform a dynamic invocation on an expression with type 'CustomInterpolationHandler'.
// Console.WriteLine(Interpolate($"literal" + $"{d}"));
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnExpression, expression).WithArguments("CustomInterpolationHandler").WithLocation(7, 31)
);
}
[Theory]
[InlineData(@"$""{s}""")]
[InlineData(@"$""{s}"" + $""""")]
public void RefEscape_01A(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
Span<char> s;
public CustomHandler(int literalLength, int formattedCount) : this() {}
public void AppendFormatted(Span<char> s) => this.s = s;
public static CustomHandler M()
{
Span<char> s = stackalloc char[10];
return " + expression + @";
}
}
";
var expectedDiagnostics = new[]
{
// (17,19): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// return $"{s}";
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(17, 19)
};
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(expectedDiagnostics);
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(expectedDiagnostics);
}
// As above but with scoped parameter in AppendFormatted().
[WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")]
[Theory]
[InlineData(@"$""{s}""")]
[InlineData(@"$""{s}"" + $""""")]
public void RefEscape_01B(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(scoped Span<char> s) { }
public static CustomHandler M()
{
Span<char> s = stackalloc char[10];
return " + expression + @";
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
}
[Theory]
[InlineData(@"$""{s}""")]
[InlineData(@"$""{s}"" + $""""")]
public void RefEscape_02(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
Span<char> s;
public CustomHandler(int literalLength, int formattedCount) : this() {}
public void AppendFormatted(Span<char> s) => this.s = s;
public static ref CustomHandler M()
{
Span<char> s = stackalloc char[10];
return " + expression + @";
}
}
";
var expectedDiagnostics = new[]
{
// (17,9): error CS8150: By-value returns may only be used in methods that return by value
// return $"{s}";
Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(17, 9)
};
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(expectedDiagnostics);
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(expectedDiagnostics);
}
[Theory]
[InlineData(@"$""{s}""")]
[InlineData(@"$""{s}"" + $""""")]
public void RefEscape_03(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
Span<char> s;
public CustomHandler(int literalLength, int formattedCount) : this() {}
public void AppendFormatted(Span<char> s) => this.s = s;
public static ref CustomHandler M()
{
Span<char> s = stackalloc char[10];
return ref " + expression + @";
}
}
";
var expectedDiagnostics = new[]
{
// (17,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref $"{s}";
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, expression).WithLocation(17, 20)
};
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(expectedDiagnostics);
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(expectedDiagnostics);
}
[Theory]
[InlineData(@"$""{s}""")]
[InlineData(@"$""{s}"" + $""""")]
public void RefEscape_04(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
S1 s1;
public CustomHandler(int literalLength, int formattedCount, ref S1 s1) : this() { this.s1 = s1; }
public void AppendFormatted(Span<char> s) => this.s1.s = s;
public static void M(ref S1 s1)
{
Span<char> s = stackalloc char[10];
M2(ref s1, " + expression + @");
}
public static void M2(ref S1 s1, [InterpolatedStringHandlerArgument(""s1"")] ref CustomHandler handler) {}
}
public ref struct S1
{
public Span<char> s;
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (17,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, ref CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope
// M2(ref s1, $"{s}");
Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, " + expression + @")").WithArguments("CustomHandler.M2(ref S1, ref CustomHandler)", "handler").WithLocation(17, 9),
// (17,23): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// M2(ref s1, $"{s}");
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(17, 23));
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (17,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, ref CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope
// M2(ref s1, $"{s}");
Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, " + expression + @")").WithArguments("CustomHandler.M2(ref S1, ref CustomHandler)", "handler").WithLocation(17, 9),
// (17,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// M2(ref s1, $"{s}");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1").WithLocation(17, 16),
// (17,20): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope
// M2(ref s1, $"{s}");
Diagnostic(ErrorCode.ERR_EscapeCall, expression).WithArguments("CustomHandler.CustomHandler(int, int, ref S1)", "s1").WithLocation(17, 20),
// (17,23): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// M2(ref s1, $"{s}");
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(17, 23));
}
[Theory]
[InlineData(@"$""{s1}""")]
[InlineData(@"$""{s1}"" + $""""")]
public void RefEscape_05(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
Span<char> s;
public CustomHandler(int literalLength, int formattedCount, ref Span<char> s) : this() { this.s = s; }
public void AppendFormatted(S1 s1) => s1.s = this.s;
public static void M(ref S1 s1)
{
Span<char> s = stackalloc char[10];
M2(ref s, " + expression + @");
}
public static void M2(ref Span<char> s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler handler) {}
}
public ref struct S1
{
public Span<char> s;
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
}
[Theory]
[InlineData(@"$""{s2}""")]
[InlineData(@"$""{s2}"" + $""""")]
public void RefEscape_06(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
Span<char> s = stackalloc char[5];
Span<char> s2 = stackalloc char[10];
s.TryWrite(" + expression + @");
public static class MemoryExtensions
{
public static bool TryWrite(this Span<char> span, [InterpolatedStringHandlerArgument(""span"")] CustomHandler builder) => true;
}
[InterpolatedStringHandler]
public ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, Span<char> s) : this() { }
public bool AppendFormatted(Span<char> s) => true;
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
}
[Theory]
[InlineData(@"$""{s2}""")]
[InlineData(@"$""{s2}"" + $""""")]
public void RefEscape_07(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
Span<char> s = stackalloc char[5];
Span<char> s2 = stackalloc char[10];
s.TryWrite(" + expression + @");
public static class MemoryExtensions
{
public static bool TryWrite(this Span<char> span, [InterpolatedStringHandlerArgument(""span"")] ref CustomHandler builder) => true;
}
[InterpolatedStringHandler]
public ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, Span<char> s) : this() { }
public bool AppendFormatted(Span<char> s) => true;
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefEscape_08(LanguageVersion languageVersion)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
Span<char> s;
public CustomHandler(int literalLength, int formattedCount, ref Span<char> s) : this() { this.s = s; }
public static CustomHandler M()
{
Span<char> s = stackalloc char[10];
ref CustomHandler c = ref M2(ref s, $"""");
return c;
}
public static ref CustomHandler M2(ref Span<char> s, [InterpolatedStringHandlerArgument(""s"")] ref CustomHandler handler)
{
return ref handler;
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (16,16): error CS8352: Cannot use variable 'c' in this context because it may expose referenced variables outside of their declaration scope
// return c;
Diagnostic(ErrorCode.ERR_EscapeVariable, "c").WithArguments("c").WithLocation(16, 16)
);
}
[Fact]
public void RefEscape_09()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct CustomHandler
{
Span<char> s;
public CustomHandler(int literalLength, int formattedCount, ref S1 s1) : this() { s1.Handler = this; }
public static void M(ref S1 s1)
{
Span<char> s2 = stackalloc char[10];
M2(ref s1, $""{s2}"");
}
public static void M2(ref S1 s1, [InterpolatedStringHandlerArgument(""s1"")] CustomHandler handler) { }
public void AppendFormatted(Span<char> s) { this.s = s; }
}
public ref struct S1
{
public CustomHandler Handler;
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (15,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope
// M2(ref s1, $"{s2}");
Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, $""{s2}"")").WithArguments("CustomHandler.M2(ref S1, CustomHandler)", "handler").WithLocation(15, 9),
// (15,23): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// M2(ref s1, $"{s2}");
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(15, 23)
);
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (10,100): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope
// public CustomHandler(int literalLength, int formattedCount, ref S1 s1) : this() { s1.Handler = this; }
Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(10, 100),
// (15,9): error CS8350: This combination of arguments to 'CustomHandler.M2(ref S1, CustomHandler)' is disallowed because it may expose variables referenced by parameter 'handler' outside of their declaration scope
// M2(ref s1, $"{s2}");
Diagnostic(ErrorCode.ERR_CallArgMixing, @"M2(ref s1, $""{s2}"")").WithArguments("CustomHandler.M2(ref S1, CustomHandler)", "handler").WithLocation(15, 9),
// (15,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// M2(ref s1, $"{s2}");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1").WithLocation(15, 16),
// (15,20): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope
// M2(ref s1, $"{s2}");
Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{s2}""").WithArguments("CustomHandler.CustomHandler(int, int, ref S1)", "s1").WithLocation(15, 20),
// (15,23): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// M2(ref s1, $"{s2}");
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(15, 23)
);
}
[Fact]
public void RefEscape_10()
{
var code =
@"using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref S s) : this() { s.Handler = this; }
public void AppendFormatted(int i) { }
}
ref struct S
{
public CustomHandler Handler;
}
class Program
{
static void Main()
{
S s = default;
M(ref s, $""{1}"");
}
static void M(ref S s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler handler) { }
}";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular10, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute, InterpolatedStringHandlerArgumentAttribute }, parseOptions: TestOptions.Regular11, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope
// public CustomHandler(int literalLength, int formattedCount, ref S s) : this() { s.Handler = this; }
Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97),
// (17,15): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// M(ref s, $"{1}");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s").WithLocation(17, 15),
// (17,18): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
// M(ref s, $"{1}");
Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref S)", "s").WithLocation(17, 18));
}
[WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefEscape_11A(LanguageVersion languageVersion)
{
var code =
@"using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(Span<char> s) { }
}
class Program
{
static void F1()
{
Span<char> s = stackalloc char[10];
M($""{s}"");
}
static void F2()
{
Span<char> s = stackalloc char[10];
CustomHandler h2 = new CustomHandler(0, 1);
h2.AppendFormatted(s); // 1
M(ref h2);
}
static void M(ref CustomHandler handler) { }
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (20,9): error CS8350: This combination of arguments to 'CustomHandler.AppendFormatted(Span<char>)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// h2.AppendFormatted(s); // 1
Diagnostic(ErrorCode.ERR_CallArgMixing, "h2.AppendFormatted(s)").WithArguments("CustomHandler.AppendFormatted(System.Span<char>)", "s").WithLocation(20, 9),
// (20,28): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// h2.AppendFormatted(s); // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(20, 28));
}
// As above but with scoped parameter in AppendFormatted().
[WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")]
[Fact]
public void RefEscape_11B()
{
var code =
@"using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(scoped Span<char> s) { }
}
class Program
{
static void F1()
{
Span<char> s = stackalloc char[10];
M($""{s}"");
}
static void F2()
{
Span<char> s = stackalloc char[10];
CustomHandler h2 = new CustomHandler(0, 1);
h2.AppendFormatted(s);
M(ref h2);
}
static void M(ref CustomHandler handler) { }
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
}
[WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefEscape_12A(LanguageVersion languageVersion)
{
var code =
@"using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(Span<char> s) { }
}
class Program
{
static CustomHandler F1()
{
Span<char> s = stackalloc char[10];
CustomHandler h1 = $""{s}"";
return h1; // 1
}
static CustomHandler F2()
{
Span<char> s = stackalloc char[10];
CustomHandler h2 = new CustomHandler(0, 1);
h2.AppendFormatted(s); // 2
return h2;
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (15,16): error CS8352: Cannot use variable 'h1' in this context because it may expose referenced variables outside of their declaration scope
// return h1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "h1").WithArguments("h1").WithLocation(15, 16),
// (21,9): error CS8350: This combination of arguments to 'CustomHandler.AppendFormatted(Span<char>)' is disallowed because it may expose variables referenced by parameter 's' outside of their declaration scope
// h2.AppendFormatted(s); // 2
Diagnostic(ErrorCode.ERR_CallArgMixing, "h2.AppendFormatted(s)").WithArguments("CustomHandler.AppendFormatted(System.Span<char>)", "s").WithLocation(21, 9),
// (21,28): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope
// h2.AppendFormatted(s); // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(21, 28));
}
// As above but with scoped parameter in AppendFormatted().
[WorkItem(63262, "https://github.com/dotnet/roslyn/issues/63262")]
[Fact]
public void RefEscape_12B()
{
var code =
@"using System;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(scoped Span<char> s) { }
}
class Program
{
static CustomHandler F1()
{
Span<char> s = stackalloc char[10];
CustomHandler h1 = $""{s}"";
return h1;
}
static CustomHandler F2()
{
Span<char> s = stackalloc char[10];
CustomHandler h2 = new CustomHandler(0, 1);
h2.AppendFormatted(s);
return h2;
}
static CustomHandler F3()
{
Span<char> s = stackalloc char[10];
scoped CustomHandler h3 = new CustomHandler(0, 1);
h3.AppendFormatted(s);
return h3; // 1
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics(
// (29,16): error CS8352: Cannot use variable 'h3' in this context because it may expose referenced variables outside of their declaration scope
// return h3; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "h3").WithArguments("h3").WithLocation(29, 16));
}
[WorkItem(63306, "https://github.com/dotnet/roslyn/issues/63306")]
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefEscape_13A(LanguageVersion languageVersion)
{
var code =
@"using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(in int i) { }
}
class Program
{
static CustomHandler F1()
{
int i = 1;
return $""{i}""; // 1
}
static CustomHandler F2()
{
return $""{2}""; // 2
}
static CustomHandler F3()
{
int i = 3;
CustomHandler h3 = $""{i}""; // 3
return h3;
}
static CustomHandler F4()
{
CustomHandler h4 = $""{4}""; // 4
return h4;
}
}
";
// https://github.com/dotnet/roslyn/issues/63306: Should report an error in each case.
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
}
// As above but with scoped parameter in AppendFormatted().
[Fact]
public void RefEscape_13B()
{
var code =
@"using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(scoped in int i) { }
}
class Program
{
static CustomHandler F1()
{
int i = 1;
return $""{i}"";
}
static CustomHandler F2()
{
return $""{2}"";
}
static CustomHandler F3()
{
int i = 3;
CustomHandler h3 = $""{i}"";
return h3;
}
static CustomHandler F4()
{
CustomHandler h4 = $""{4}"";
return h4;
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Net50);
comp.VerifyDiagnostics();
}
[Fact]
public void RefEscape_14()
{
string source = """
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount) { }
}
ref struct R { }
class Program
{
static R F1()
{
R r = F2($"");
return r;
}
static R F2(ref CustomHandler handler)
{
return default;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return r;
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(13, 16));
}
[Fact]
public void RefEscape_15()
{
string source = """
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
public void AppendFormatted(int i) { }
}
ref struct R
{
public CustomHandler Handler;
public object this[[InterpolatedStringHandlerArgument("")] CustomHandler handler] => null;
}
class Program
{
static R F()
{
R r = new R();
_ = r[$"{1}"];
return r;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope
// public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97),
// (18,13): error CS1620: Argument 3 must be passed with the 'ref' keyword
// _ = r[$"{1}"];
Diagnostic(ErrorCode.ERR_BadArgRef, "r").WithArguments("3", "ref").WithLocation(18, 13));
}
[Fact]
public void RefEscape_16()
{
string source = """
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
public void AppendFormatted(int i) { }
}
ref struct R
{
public CustomHandler Handler;
public object this[ref R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler] => null;
}
class Program
{
static R F()
{
R r = new R();
_ = r[ref r, $"{1}"];
return r;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope
// public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97),
// (11,24): error CS0631: ref and out are not valid in this context
// public object this[ref R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler] => null;
Diagnostic(ErrorCode.ERR_IllegalRefParam, "ref").WithLocation(11, 24),
// (18,19): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// _ = r[ref r, $"{1}"];
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "r").WithLocation(18, 19),
// (18,19): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// _ = r[ref r, $"{1}"];
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "r").WithLocation(18, 19),
// (18,22): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope
// _ = r[ref r, $"{1}"];
Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref R)", "r").WithLocation(18, 22),
// (18,22): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope
// _ = r[ref r, $"{1}"];
Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref R)", "r").WithLocation(18, 22));
}
[Fact]
public void RefEscape_17()
{
string source = """
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
public void AppendFormatted(int i) { }
}
ref struct R
{
public CustomHandler Handler;
public R(ref R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler) { }
}
class Program
{
static R F()
{
R x = new R();
R y = new R(ref x, $"{1}");
return x;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope
// public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97),
// (18,25): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// R y = new R(ref x, $"{1}");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "x").WithLocation(18, 25),
// (18,28): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope
// R y = new R(ref x, $"{1}");
Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref R)", "r").WithLocation(18, 28));
}
[Fact]
public void RefEscape_18()
{
string source = """
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
private ref readonly int _i;
public CustomHandler(int literalLength, int formattedCount, in int i = 0) { _i = ref i; }
public void AppendFormatted(int i) { }
}
class Program
{
static CustomHandler F1()
{
return $"{1}";
}
static CustomHandler F2()
{
CustomHandler h2 = $"{2}";
return h2;
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (13,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return $"{1}";
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, @"$""{1}""").WithLocation(13, 16),
// (13,16): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, in int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return $"{1}";
Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, in int)", "i").WithLocation(13, 16),
// (18,16): error CS8352: Cannot use variable 'h2' in this context because it may expose referenced variables outside of their declaration scope
// return h2;
Diagnostic(ErrorCode.ERR_EscapeVariable, "h2").WithArguments("h2").WithLocation(18, 16));
}
[WorkItem(63306, "https://github.com/dotnet/roslyn/issues/63306")]
[Fact]
public void RefEscape_19()
{
string source = """
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
private ref readonly int _i;
public CustomHandler(int literalLength, int formattedCount) { }
public void AppendFormatted(int x, [UnscopedRef] in int y = 0) { _i = ref y; }
}
class Program
{
static CustomHandler F1()
{
return $"{1}";
}
static CustomHandler F2()
{
CustomHandler h2 = $"{2}";
return h2;
}
}
""";
// https://github.com/dotnet/roslyn/issues/63306: Should report an error that a reference to y will escape F1() and F2().
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[WorkItem(67070, "https://github.com/dotnet/roslyn/issues/67070")]
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_01()
{
string source = """
using System;
using System.Runtime.CompilerServices;
static class Program
{
static void Main()
{
var r = new R();
r
.F($"[{42}]")
.F($"[{"str".AsSpan()}]");
}
}
readonly ref struct R
{
public R F([InterpolatedStringHandlerArgument("")] CustomHandler handler)
=> this;
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
public void AppendFormatted(ReadOnlySpan<char> value)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[WorkItem(67070, "https://github.com/dotnet/roslyn/issues/67070")]
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_02()
{
string source = """
using System.Runtime.CompilerServices;
static class Program
{
static void Main()
{
var r = new R();
r
.F($"{42}")
.F($"{42}");
}
}
readonly ref struct R
{
public R F([InterpolatedStringHandlerArgument("")] CustomHandler handler)
=> this;
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[WorkItem(67070, "https://github.com/dotnet/roslyn/issues/67070")]
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_03()
{
string source = """
using System.Runtime.CompilerServices;
static class Program
{
static void Main()
{
var r = new R();
F(
F(r, $"{42}"),
$"{42}");
}
static R F(R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler)
=> r;
}
readonly ref struct R
{
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[WorkItem(67070, "https://github.com/dotnet/roslyn/issues/67070")]
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_04()
{
string source = """
using System.Runtime.CompilerServices;
static class Program
{
static void Main()
{
var r = new R();
r = new R(
new R(r, $"{42}"),
$"{42}");
}
}
readonly ref struct R
{
public R(R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler)
{
}
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[WorkItem(67070, "https://github.com/dotnet/roslyn/issues/67070")]
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_05()
{
string source = """
using System.Runtime.CompilerServices;
static class Program
{
static void Main()
{
var r = new R();
r = r
[$"{42}"]
[$"{42}"];
}
}
readonly ref struct R
{
public R this[[InterpolatedStringHandlerArgument("")] CustomHandler handler]
=> this;
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[WorkItem(67070, "https://github.com/dotnet/roslyn/issues/67070")]
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_06()
{
string source = """
using System;
using System.Runtime.CompilerServices;
static class Program
{
static R M()
{
R r = default;
Span<byte> span = stackalloc byte[42];
return r
.F($"{span}")
.F($"{span}");
}
}
readonly ref struct R
{
public R F([InterpolatedStringHandlerArgument("")] CustomHandler handler)
=> this;
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
public void AppendFormatted(Span<byte> span)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (9,16): error CS8347: Cannot use a result of 'R.F(CustomHandler)' in this context because it may expose variables referenced by parameter 'handler' outside of their declaration scope
// return r
Diagnostic(ErrorCode.ERR_EscapeCall, @"r
.F($""{span}"")").WithArguments("R.F(CustomHandler)", "handler").WithLocation(9, 16),
// (10,19): error CS8352: Cannot use variable 'span' in this context because it may expose referenced variables outside of their declaration scope
// .F($"{span}")
Diagnostic(ErrorCode.ERR_EscapeVariable, "span").WithArguments("span").WithLocation(10, 19));
}
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_07()
{
string source = """
using System.Runtime.CompilerServices;
static class Program
{
static R M()
{
int i = 0;
var r = new R(ref i);
return r
.F($"{i}")
.F($"{i}");
}
}
readonly ref struct R
{
private readonly ref int _i;
public R(ref int i) { _i = ref i; }
public R F([InterpolatedStringHandlerArgument("")] CustomHandler handler)
=> this;
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (8,16): error CS8352: Cannot use variable 'r' in this context because it may expose referenced variables outside of their declaration scope
// return r
Diagnostic(ErrorCode.ERR_EscapeVariable, "r").WithArguments("r").WithLocation(8, 16));
}
[WorkItem(67070, "https://github.com/dotnet/roslyn/issues/67070")]
[ConditionalFact(typeof(CoreClrOnly))]
public void RefEscape_NestedCalls_08()
{
string source = """
using System.Runtime.CompilerServices;
static class Program
{
static void Main()
{
var r = new R();
r
.F($"{1}", $"{2}")
.F($"{3}", $"{4}");
}
}
readonly ref struct R
{
public R F([InterpolatedStringHandlerArgument("")] CustomHandler h1, [InterpolatedStringHandlerArgument("")] CustomHandler h2)
=> this;
}
[InterpolatedStringHandler]
readonly ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, R r)
{
}
public void AppendLiteral(string value)
{
}
public void AppendFormatted<T>(T value)
{
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics();
}
[Fact]
public void RefEscape_ForEachExpression()
{
string source = """
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
ref struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
public void AppendFormatted(int i) { }
}
ref struct R
{
public CustomHandler Handler;
}
ref struct Enumerable
{
public static Enumerable Create(ref R r, [InterpolatedStringHandlerArgument("r")] CustomHandler handler) => default;
public Enumerator GetEnumerator() => default;
}
ref struct Enumerator
{
public R Current => throw null;
public bool MoveNext() => false;
}
class Program
{
static void F(ref R r)
{
foreach (var i in Enumerable.Create(ref r, $"{1}"))
{
}
}
}
""";
var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70);
comp.VerifyDiagnostics(
// (5,97): error CS8352: Cannot use variable 'out CustomHandler this' in this context because it may expose referenced variables outside of their declaration scope
// public CustomHandler(int literalLength, int formattedCount, ref R r) : this() { r.Handler = this; }
Diagnostic(ErrorCode.ERR_EscapeVariable, "this").WithArguments("out CustomHandler this").WithLocation(5, 97),
// (26,49): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// foreach (var i in Enumerable.Create(ref r, $"{1}"))
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "r").WithLocation(26, 49),
// (26,52): error CS8347: Cannot use a result of 'CustomHandler.CustomHandler(int, int, ref R)' in this context because it may expose variables referenced by parameter 'r' outside of their declaration scope
// foreach (var i in Enumerable.Create(ref r, $"{1}"))
Diagnostic(ErrorCode.ERR_EscapeCall, @"$""{1}""").WithArguments("CustomHandler.CustomHandler(int, int, ref R)", "r").WithLocation(26, 52));
}
[Theory, WorkItem(54703, "https://github.com/dotnet/roslyn/issues/54703")]
[InlineData(@"$""{{ {i} }}""")]
[InlineData(@"$""{{ "" + $""{i}"" + $"" }}""")]
public void BracesAreEscaped_01(string expression)
{
var code = @"
int i = 1;
System.Console.WriteLine(" + expression + @");";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
var verifier = CompileAndVerify(comp, expectedOutput: @"
{
value:1
}"{
value:1
}");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 56 (0x38)
.maxstack 3
.locals init (int V_0, //i
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.4
IL_0005: ldc.i4.1
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldstr ""{ ""
IL_0012: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_0017: ldloca.s V_1
IL_0019: ldloc.0
IL_001a: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_001f: ldloca.s V_1
IL_0021: ldstr "" }""
IL_0026: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)""
IL_002b: ldloca.s V_1
IL_002d: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0032: call ""void System.Console.WriteLine(string)""
IL_0037: ret
}
");
}
[Theory, WorkItem(54703, "https://github.com/dotnet/roslyn/issues/54703")]
[InlineData(@"$""{{ {i} }}""")]
[InlineData(@"$""{{ "" + $""{i}"" + $"" }}""")]
public void BracesAreEscaped_02(string expression)
{
var code = @"
int i = 1;
CustomHandler c = " + expression + @";
System.Console.WriteLine(c.ToString());";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
var verifier = CompileAndVerify(comp, expectedOutput: @"
literal:{
value:1
alignment:0
format:
literal: }");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 71 (0x47)
.maxstack 4
.locals init (int V_0, //i
CustomHandler V_1, //c
CustomHandler V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_2
IL_0004: ldc.i4.4
IL_0005: ldc.i4.1
IL_0006: call ""CustomHandler..ctor(int, int)""
IL_000b: ldloca.s V_2
IL_000d: ldstr ""{ ""
IL_0012: call ""void CustomHandler.AppendLiteral(string)""
IL_0017: ldloca.s V_2
IL_0019: ldloc.0
IL_001a: box ""int""
IL_001f: ldc.i4.0
IL_0020: ldnull
IL_0021: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0026: ldloca.s V_2
IL_0028: ldstr "" }""
IL_002d: call ""void CustomHandler.AppendLiteral(string)""
IL_0032: ldloc.2
IL_0033: stloc.1
IL_0034: ldloca.s V_1
IL_0036: constrained. ""CustomHandler""
IL_003c: callvirt ""string object.ToString()""
IL_0041: call ""void System.Console.WriteLine(string)""
IL_0046: ret
}
");
}
[Fact]
public void InterpolatedStringsAddedUnderObjectAddition()
{
var code = @"
int i1 = 1;
int i2 = 2;
int i3 = 3;
int i4 = 4;
System.Console.WriteLine($""{i1}"" + $""{i2}"" + $""{i3}"" + i4);";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
value:2
value:3
4
");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 66 (0x42)
.maxstack 3
.locals init (int V_0, //i1
int V_1, //i2
int V_2, //i3
int V_3, //i4
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.2
IL_0003: stloc.1
IL_0004: ldc.i4.3
IL_0005: stloc.2
IL_0006: ldc.i4.4
IL_0007: stloc.3
IL_0008: ldloca.s V_4
IL_000a: ldc.i4.0
IL_000b: ldc.i4.3
IL_000c: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_0011: ldloca.s V_4
IL_0013: ldloc.0
IL_0014: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0019: ldloca.s V_4
IL_001b: ldloc.1
IL_001c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0021: ldloca.s V_4
IL_0023: ldloc.2
IL_0024: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0029: ldloca.s V_4
IL_002b: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_0030: ldloca.s V_3
IL_0032: call ""string int.ToString()""
IL_0037: call ""string string.Concat(string, string)""
IL_003c: call ""void System.Console.WriteLine(string)""
IL_0041: ret
}
");
}
[Theory]
[InlineData(@"$""({i1}),"" + $""[{i2}],"" + $""{{{i3}}}""")]
[InlineData(@"($""({i1}),"" + $""[{i2}],"") + $""{{{i3}}}""")]
[InlineData(@"$""({i1}),"" + ($""[{i2}],"" + $""{{{i3}}}"")")]
public void InterpolatedStringsAddedUnderObjectAddition2(string expression)
{
var code = $@"
int i1 = 1;
int i2 = 2;
int i3 = 3;
System.Console.WriteLine({expression});";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
CompileAndVerify(comp, expectedOutput: @"
(
value:1
),
[
value:2
],
{
value:3
}
");
}
[Fact]
public void InterpolatedStringsAddedUnderObjectAddition3()
{
var code = @"
#nullable enable
using System;
try
{
var s = string.Empty;
Console.WriteLine($""{s = null}{s.Length}"" + $"""");
}
catch (NullReferenceException)
{
Console.WriteLine(""Null reference exception caught."");
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
CompileAndVerify(comp, expectedOutput: "Null reference exception caught.").VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 65 (0x41)
.maxstack 3
.locals init (string V_0, //s
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
.try
{
IL_0000: ldsfld ""string string.Empty""
IL_0005: stloc.0
IL_0006: ldc.i4.0
IL_0007: ldc.i4.2
IL_0008: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000d: stloc.1
IL_000e: ldloca.s V_1
IL_0010: ldnull
IL_0011: dup
IL_0012: stloc.0
IL_0013: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
IL_0018: ldloca.s V_1
IL_001a: ldloc.0
IL_001b: callvirt ""int string.Length.get""
IL_0020: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0025: ldloca.s V_1
IL_0027: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_002c: call ""void System.Console.WriteLine(string)""
IL_0031: leave.s IL_0040
}
catch System.NullReferenceException
{
IL_0033: pop
IL_0034: ldstr ""Null reference exception caught.""
IL_0039: call ""void System.Console.WriteLine(string)""
IL_003e: leave.s IL_0040
}
IL_0040: ret
}
").VerifyDiagnostics(
// (9,36): warning CS8602: Dereference of a possibly null reference.
// Console.WriteLine($"{s = null}{s.Length}" + $"");
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(9, 36)
);
}
[Fact, WorkItem("https://github.com/dotnet/runtime/issues/78991")]
public void InterpolatedStringsAddedUnderObjectAddition_AdditionsWithMoreParts_01()
{
var code = """
using System;
_ = $"1{Environment.NewLine}" +
$"2{Environment.NewLine}";
""";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
CompileAndVerify(comp).VerifyIL("<top-level-statements-entry-point>",
"""
{
// Code size 27 (0x1b)
.maxstack 4
IL_0000: ldstr "1"
IL_0005: call "string System.Environment.NewLine.get"
IL_000a: ldstr "2"
IL_000f: call "string System.Environment.NewLine.get"
IL_0014: call "string string.Concat(string, string, string, string)"
IL_0019: pop
IL_001a: ret
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/runtime/issues/78991")]
public void InterpolatedStringsAddedUnderObjectAddition_AdditionsWithMoreParts_02()
{
var code = """
using System;
_ = $"1{Environment.NewLine}" +
$"2{Environment.NewLine}" +
$"3";
""";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
CompileAndVerify(comp).VerifyIL("<top-level-statements-entry-point>",
"""
{
// Code size 78 (0x4e)
.maxstack 3
.locals init (System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.3
IL_0003: ldc.i4.2
IL_0004: call "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
IL_0009: ldloca.s V_0
IL_000b: ldstr "1"
IL_0010: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
IL_0015: ldloca.s V_0
IL_0017: call "string System.Environment.NewLine.get"
IL_001c: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
IL_0021: ldloca.s V_0
IL_0023: ldstr "2"
IL_0028: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
IL_002d: ldloca.s V_0
IL_002f: call "string System.Environment.NewLine.get"
IL_0034: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
IL_0039: ldloca.s V_0
IL_003b: ldstr "3"
IL_0040: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
IL_0045: ldloca.s V_0
IL_0047: call "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
IL_004c: pop
IL_004d: ret
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/runtime/issues/78991")]
public void InterpolatedStringsAddedUnderObjectAddition_AdditionsWithMoreParts_03()
{
var code = """
using System;
_ = $"1{Environment.NewLine}" +
$"2{Environment.NewLine}" +
$"3{Environment.NewLine}" +
$"4{Environment.NewLine}";
""";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) });
CompileAndVerify(comp).VerifyIL("<top-level-statements-entry-point>",
"""
{
// Code size 114 (0x72)
.maxstack 3
.locals init (System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_0)
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.4
IL_0003: ldc.i4.4
IL_0004: call "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
IL_0009: ldloca.s V_0
IL_000b: ldstr "1"
IL_0010: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
IL_0015: ldloca.s V_0
IL_0017: call "string System.Environment.NewLine.get"
IL_001c: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
IL_0021: ldloca.s V_0
IL_0023: ldstr "2"
IL_0028: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
IL_002d: ldloca.s V_0
IL_002f: call "string System.Environment.NewLine.get"
IL_0034: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
IL_0039: ldloca.s V_0
IL_003b: ldstr "3"
IL_0040: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
IL_0045: ldloca.s V_0
IL_0047: call "string System.Environment.NewLine.get"
IL_004c: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
IL_0051: ldloca.s V_0
IL_0053: ldstr "4"
IL_0058: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
IL_005d: ldloca.s V_0
IL_005f: call "string System.Environment.NewLine.get"
IL_0064: call "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
IL_0069: ldloca.s V_0
IL_006b: call "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
IL_0070: pop
IL_0071: ret
}
""");
}
[Fact]
public void InterpolatedStringsAddedUnderObjectAddition_DefiniteAssignment()
{
var code = @"
object o1;
object o2;
object o3;
_ = $""{o1 = null}"" + $""{o2 = null}"" + $""{o3 = null}"" + 1;
o1.ToString();
o2.ToString();
o3.ToString();
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: true) });
comp.VerifyDiagnostics(
// (7,1): error CS0165: Use of unassigned local variable 'o2'
// o2.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "o2").WithArguments("o2").WithLocation(7, 1),
// (8,1): error CS0165: Use of unassigned local variable 'o3'
// o3.ToString();
Diagnostic(ErrorCode.ERR_UseDefViolation, "o3").WithArguments("o3").WithLocation(8, 1)
);
}
[Theory]
[InlineData(@"($""{i1}"" + $""{i2}"") + $""{i3}""")]
[InlineData(@"$""{i1}"" + ($""{i2}"" + $""{i3}"")")]
public void ParenthesizedAdditiveExpression_01(string expression)
{
var code = @"
int i1 = 1;
int i2 = 2;
int i3 = 3;
CustomHandler c = " + expression + @";
System.Console.WriteLine(c.ToString());";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:0
format:
value:2
alignment:0
format:
value:3
alignment:0
format:
");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 82 (0x52)
.maxstack 4
.locals init (int V_0, //i1
int V_1, //i2
int V_2, //i3
CustomHandler V_3, //c
CustomHandler V_4)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldc.i4.2
IL_0003: stloc.1
IL_0004: ldc.i4.3
IL_0005: stloc.2
IL_0006: ldloca.s V_4
IL_0008: ldc.i4.0
IL_0009: ldc.i4.3
IL_000a: call ""CustomHandler..ctor(int, int)""
IL_000f: ldloca.s V_4
IL_0011: ldloc.0
IL_0012: box ""int""
IL_0017: ldc.i4.0
IL_0018: ldnull
IL_0019: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_001e: ldloca.s V_4
IL_0020: ldloc.1
IL_0021: box ""int""
IL_0026: ldc.i4.0
IL_0027: ldnull
IL_0028: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_002d: ldloca.s V_4
IL_002f: ldloc.2
IL_0030: box ""int""
IL_0035: ldc.i4.0
IL_0036: ldnull
IL_0037: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_003c: ldloc.s V_4
IL_003e: stloc.3
IL_003f: ldloca.s V_3
IL_0041: constrained. ""CustomHandler""
IL_0047: callvirt ""string object.ToString()""
IL_004c: call ""void System.Console.WriteLine(string)""
IL_0051: ret
}");
}
[Fact]
public void ParenthesizedAdditiveExpression_02()
{
var code = @"
int i1 = 1;
int i2 = 2;
int i3 = 3;
int i4 = 4;
int i5 = 5;
int i6 = 6;
CustomHandler c = /*<bind>*/((($""{i1}"" + $""{i2}"") + $""{i3}"") + ($""{i4}"" + ($""{i5}"" + $""{i6}""))) + (($""{i1}"" + ($""{i2}"" + $""{i3}"")) + (($""{i4}"" + $""{i5}"") + $""{i6}""))/*</bind>*/;
System.Console.WriteLine(c.ToString());";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:0
format:
value:2
alignment:0
format:
value:3
alignment:0
format:
value:4
alignment:0
format:
value:5
alignment:0
format:
value:6
alignment:0
format:
value:1
alignment:0
format:
value:2
alignment:0
format:
value:3
alignment:0
format:
value:4
alignment:0
format:
value:5
alignment:0
format:
value:6
alignment:0
format:
");
verifier.VerifyDiagnostics();
VerifyOperationTreeForTest<BinaryExpressionSyntax>(comp, @"
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Left:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '(($""{i1}"" + ... + $""{i6}""))')
Left:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '($""{i1}"" + ... ) + $""{i3}""')
Left:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""{i1}"" + $""{i2}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i1}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i1}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i1}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i1')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i1')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i1}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i1}')
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:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i2}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i2}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i2}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i2')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i2')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i2}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i2}')
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:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i3}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i3}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i3}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i3')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i3')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i3}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i3}')
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:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""{i4}"" + ( ... + $""{i6}"")')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i4}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i4}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i4}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i4')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i4')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i4}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i4}')
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:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""{i5}"" + $""{i6}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i5}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i5}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i5}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i5')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i5')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i5}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i5}')
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:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i6}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i6}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i6}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i6')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i6')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i6}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i6}')
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:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '($""{i1}"" + ... + $""{i6}"")')
Left:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""{i1}"" + ( ... + $""{i3}"")')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i1}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i1}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i1}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i1')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i1')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i1}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i1}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i1}')
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:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""{i2}"" + $""{i3}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i2}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i2}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i2}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i2')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i2')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i2}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i2}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i2}')
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:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i3}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i3}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i3}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i3')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i3')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i3}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i3}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i3}')
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:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '($""{i4}"" + ... ) + $""{i6}""')
Left:
IInterpolatedStringAdditionOperation (OperationKind.InterpolatedStringAddition, Type: null) (Syntax: '$""{i4}"" + $""{i5}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i4}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i4}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i4}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i4')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i4')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i4}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i4}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i4}')
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:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i5}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i5}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i5}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i5')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i5')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i5}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i5}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i5}')
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:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i6}""')
Parts(1):
IInterpolatedStringAppendOperation (OperationKind.InterpolatedStringAppendFormatted, Type: null, IsImplicit) (Syntax: '{i6}')
AppendCall:
IInvocationOperation ( void CustomHandler.AppendFormatted(System.Object o, [System.Int32 alignment = 0], [System.String format = null])) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '{i6}')
Instance Receiver:
IInstanceReferenceOperation (ReferenceKind: InterpolatedStringHandler) (OperationKind.InstanceReference, Type: CustomHandler, IsImplicit) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Arguments(3):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: o) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'i6')
IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'i6')
Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Operand:
ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6')
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.DefaultValue, Matching Parameter: alignment) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}')
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsImplicit) (Syntax: '{i6}')
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.DefaultValue, Matching Parameter: format) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '{i6}')
IDefaultValueOperation (OperationKind.DefaultValue, Type: System.String, Constant: null, IsImplicit) (Syntax: '{i6}')
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)
");
}
[Fact]
public void ParenthesizedAdditiveExpression_03()
{
var code = @"
int i1 = 1;
int i2 = 2;
int i3 = 3;
int i4 = 4;
int i5 = 5;
int i6 = 6;
string s = (($""{i1}"" + $""{i2}"") + $""{i3}"") + ($""{i4}"" + ($""{i5}"" + $""{i6}""));
System.Console.WriteLine(s);";
var verifier = CompileAndVerify(code, expectedOutput: @"123456");
verifier.VerifyDiagnostics();
}
[Fact]
public void ParenthesizedAdditiveExpression_04()
{
var code = @"
using System.Threading.Tasks;
int i1 = 2;
int i2 = 3;
string s = $""{await GetInt()}"" + ($""{i1}"" + $""{i2}"");
System.Console.WriteLine(s);
Task<int> GetInt() => Task.FromResult(1);
";
var verifier = CompileAndVerify(new[] { code, GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false) }, expectedOutput: @"
1value:2
value:3");
verifier.VerifyDiagnostics();
// Note the two DefaultInterpolatedStringHandlers in the IL here. In a future rewrite step in the LocalRewriter, we can potentially
// transform the tree to change its shape and pull out all individual Append calls in a sequence (regardless of the level of the tree)
// and combine these and other unequal tree shapes. For now, we're going with a simple solution where, if the entire binary expression
// cannot be combined, none of it is.
verifier.VerifyIL("Program.<<Main>$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
// Code size 244 (0xf4)
.maxstack 4
.locals init (int V_0,
int V_1,
System.Runtime.CompilerServices.TaskAwaiter<int> V_2,
System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3,
System.Exception V_4)
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0006: stloc.0
.try
{
IL_0007: ldloc.0
IL_0008: brfalse.s IL_004f
IL_000a: ldarg.0
IL_000b: ldc.i4.2
IL_000c: stfld ""int Program.<<Main>$>d__0.<i1>5__2""
IL_0011: ldarg.0
IL_0012: ldc.i4.3
IL_0013: stfld ""int Program.<<Main>$>d__0.<i2>5__3""
IL_0018: call ""System.Threading.Tasks.Task<int> Program.<<Main>$>g__GetInt|0_0()""
IL_001d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0022: stloc.2
IL_0023: ldloca.s V_2
IL_0025: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_002a: brtrue.s IL_006b
IL_002c: ldarg.0
IL_002d: ldc.i4.0
IL_002e: dup
IL_002f: stloc.0
IL_0030: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_0035: ldarg.0
IL_0036: ldloc.2
IL_0037: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_003c: ldarg.0
IL_003d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_0042: ldloca.s V_2
IL_0044: ldarg.0
IL_0045: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, Program.<<Main>$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref Program.<<Main>$>d__0)""
IL_004a: leave IL_00f3
IL_004f: ldarg.0
IL_0050: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_0055: stloc.2
IL_0056: ldarg.0
IL_0057: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> Program.<<Main>$>d__0.<>u__1""
IL_005c: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0062: ldarg.0
IL_0063: ldc.i4.m1
IL_0064: dup
IL_0065: stloc.0
IL_0066: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_006b: ldloca.s V_2
IL_006d: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_0072: stloc.1
IL_0073: ldstr ""{0}""
IL_0078: ldloc.1
IL_0079: box ""int""
IL_007e: call ""string string.Format(string, object)""
IL_0083: ldc.i4.0
IL_0084: ldc.i4.1
IL_0085: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_008a: stloc.3
IL_008b: ldloca.s V_3
IL_008d: ldarg.0
IL_008e: ldfld ""int Program.<<Main>$>d__0.<i1>5__2""
IL_0093: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_0098: ldloca.s V_3
IL_009a: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_009f: ldc.i4.0
IL_00a0: ldc.i4.1
IL_00a1: newobj ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_00a6: stloc.3
IL_00a7: ldloca.s V_3
IL_00a9: ldarg.0
IL_00aa: ldfld ""int Program.<<Main>$>d__0.<i2>5__3""
IL_00af: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)""
IL_00b4: ldloca.s V_3
IL_00b6: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
IL_00bb: call ""string string.Concat(string, string, string)""
IL_00c0: call ""void System.Console.WriteLine(string)""
IL_00c5: leave.s IL_00e0
}
catch System.Exception
{
IL_00c7: stloc.s V_4
IL_00c9: ldarg.0
IL_00ca: ldc.i4.s -2
IL_00cc: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_00d1: ldarg.0
IL_00d2: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_00d7: ldloc.s V_4
IL_00d9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
IL_00de: leave.s IL_00f3
}
IL_00e0: ldarg.0
IL_00e1: ldc.i4.s -2
IL_00e3: stfld ""int Program.<<Main>$>d__0.<>1__state""
IL_00e8: ldarg.0
IL_00e9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<Main>$>d__0.<>t__builder""
IL_00ee: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
IL_00f3: ret
}");
}
[Fact]
public void ParenthesizedAdditiveExpression_05()
{
var code = @"
int i1 = 1;
int i2 = 2;
int i3 = 3;
int i4 = 4;
int i5 = 5;
int i6 = 6;
string s = /*<bind>*/((($""{i1}"" + $""{i2}"") + $""{i3}"") + ($""{i4}"" + ($""{i5}"" + $""{i6}""))) + (($""{i1}"" + ($""{i2}"" + $""{i3}"")) + (($""{i4}"" + $""{i5}"") + $""{i6}""))/*</bind>*/;
System.Console.WriteLine(s);";
var comp = CreateCompilation(code);
var verifier = CompileAndVerify(comp, expectedOutput: @"123456123456");
verifier.VerifyDiagnostics();
VerifyOperationTreeForTest<BinaryExpressionSyntax>(comp, @"
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '((($""{i1}"" ... + $""{i6}""))')
Left:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '(($""{i1}"" + ... + $""{i6}""))')
Left:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '($""{i1}"" + ... ) + $""{i3}""')
Left:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i1}"" + $""{i2}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i1}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i1}')
Expression:
ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1')
Alignment:
null
FormatString:
null
Right:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i2}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i2}')
Expression:
ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2')
Alignment:
null
FormatString:
null
Right:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i3}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i3}')
Expression:
ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3')
Alignment:
null
FormatString:
null
Right:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i4}"" + ( ... + $""{i6}"")')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i4}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i4}')
Expression:
ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4')
Alignment:
null
FormatString:
null
Right:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i5}"" + $""{i6}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i5}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i5}')
Expression:
ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5')
Alignment:
null
FormatString:
null
Right:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i6}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i6}')
Expression:
ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6')
Alignment:
null
FormatString:
null
Right:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '($""{i1}"" + ... + $""{i6}"")')
Left:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i1}"" + ( ... + $""{i3}"")')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i1}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i1}')
Expression:
ILocalReferenceOperation: i1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i1')
Alignment:
null
FormatString:
null
Right:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i2}"" + $""{i3}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i2}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i2}')
Expression:
ILocalReferenceOperation: i2 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i2')
Alignment:
null
FormatString:
null
Right:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i3}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i3}')
Expression:
ILocalReferenceOperation: i3 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i3')
Alignment:
null
FormatString:
null
Right:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '($""{i4}"" + ... ) + $""{i6}""')
Left:
IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String) (Syntax: '$""{i4}"" + $""{i5}""')
Left:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i4}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i4}')
Expression:
ILocalReferenceOperation: i4 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i4')
Alignment:
null
FormatString:
null
Right:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i5}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i5}')
Expression:
ILocalReferenceOperation: i5 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i5')
Alignment:
null
FormatString:
null
Right:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$""{i6}""')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i6}')
Expression:
ILocalReferenceOperation: i6 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i6')
Alignment:
null
FormatString:
null
");
}
[ConditionalFact(typeof(CoreClrOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/68834")]
public void ParenthesizedAdditiveExpression_06()
{
var src = """
using System.Runtime.CompilerServices;
DefaultInterpolatedStringHandler s1 = $"a" + $"b" + ($"c" + $"-");
System.Console.Write(s1.ToString());
DefaultInterpolatedStringHandler s2 = $"a" + ($"b" + $"c") + $"-";
System.Console.Write(s2.ToString());
DefaultInterpolatedStringHandler s3 = ($"a" + $"b") + $"c" + $"-";
System.Console.Write(s3.ToString());
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70);
CompileAndVerify(comp, expectedOutput: "abc-abc-abc-").VerifyDiagnostics();
}
[Theory]
[InlineData(@"$""{1}"", $""{2}""")]
[InlineData(@"$""{1}"" + $"""", $""{2}"" + $""""")]
public void TupleDeclaration_01(string initializer)
{
var code = @"
(CustomHandler c1, CustomHandler c2) = (" + initializer + @");
System.Console.Write(c1.ToString());
System.Console.WriteLine(c2.ToString());";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:0
format:
value:2
alignment:0
format:
");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 89 (0x59)
.maxstack 5
.locals init (CustomHandler V_0, //c1
CustomHandler V_1, //c2
CustomHandler V_2)
IL_0000: ldloca.s V_2
IL_0002: ldc.i4.0
IL_0003: ldc.i4.1
IL_0004: call ""CustomHandler..ctor(int, int)""
IL_0009: ldloca.s V_2
IL_000b: ldc.i4.1
IL_000c: box ""int""
IL_0011: ldc.i4.0
IL_0012: ldnull
IL_0013: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0018: ldloc.2
IL_0019: ldloca.s V_2
IL_001b: ldc.i4.0
IL_001c: ldc.i4.1
IL_001d: call ""CustomHandler..ctor(int, int)""
IL_0022: ldloca.s V_2
IL_0024: ldc.i4.2
IL_0025: box ""int""
IL_002a: ldc.i4.0
IL_002b: ldnull
IL_002c: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0031: ldloc.2
IL_0032: stloc.1
IL_0033: stloc.0
IL_0034: ldloca.s V_0
IL_0036: constrained. ""CustomHandler""
IL_003c: callvirt ""string object.ToString()""
IL_0041: call ""void System.Console.Write(string)""
IL_0046: ldloca.s V_1
IL_0048: constrained. ""CustomHandler""
IL_004e: callvirt ""string object.ToString()""
IL_0053: call ""void System.Console.WriteLine(string)""
IL_0058: ret
}
");
}
[Theory]
[InlineData(@"$""{1}"", $""{2}""")]
[InlineData(@"$""{1}"" + $"""", $""{2}"" + $""""")]
public void TupleDeclaration_02(string initializer)
{
var code = @"
(CustomHandler c1, CustomHandler c2) t = (" + initializer + @");
System.Console.Write(t.c1.ToString());
System.Console.WriteLine(t.c2.ToString());";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
var verifier = CompileAndVerify(comp, expectedOutput: @"
value:1
alignment:0
format:
value:2
alignment:0
format:
");
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 104 (0x68)
.maxstack 6
.locals init (System.ValueTuple<CustomHandler, CustomHandler> V_0, //t
CustomHandler V_1)
IL_0000: ldloca.s V_0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.0
IL_0005: ldc.i4.1
IL_0006: call ""CustomHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
IL_000d: ldc.i4.1
IL_000e: box ""int""
IL_0013: ldc.i4.0
IL_0014: ldnull
IL_0015: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_001a: ldloc.1
IL_001b: ldloca.s V_1
IL_001d: ldc.i4.0
IL_001e: ldc.i4.1
IL_001f: call ""CustomHandler..ctor(int, int)""
IL_0024: ldloca.s V_1
IL_0026: ldc.i4.2
IL_0027: box ""int""
IL_002c: ldc.i4.0
IL_002d: ldnull
IL_002e: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0033: ldloc.1
IL_0034: call ""System.ValueTuple<CustomHandler, CustomHandler>..ctor(CustomHandler, CustomHandler)""
IL_0039: ldloca.s V_0
IL_003b: ldflda ""CustomHandler System.ValueTuple<CustomHandler, CustomHandler>.Item1""
IL_0040: constrained. ""CustomHandler""
IL_0046: callvirt ""string object.ToString()""
IL_004b: call ""void System.Console.Write(string)""
IL_0050: ldloca.s V_0
IL_0052: ldflda ""CustomHandler System.ValueTuple<CustomHandler, CustomHandler>.Item2""
IL_0057: constrained. ""CustomHandler""
IL_005d: callvirt ""string object.ToString()""
IL_0062: call ""void System.Console.WriteLine(string)""
IL_0067: ret
}
");
}
[Theory, WorkItem(55609, "https://github.com/dotnet/roslyn/issues/55609")]
[InlineData(@"$""{h1}{h2}""")]
[InlineData(@"$""{h1}"" + $""{h2}""")]
public void RefStructHandler_DynamicInHole(string expression)
{
var code = @"
dynamic h1 = 1;
dynamic h2 = 2;
CustomHandler c = " + expression + ";";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "ref struct", useBoolReturns: false);
var comp = CreateCompilationWithCSharp(new[] { code, handler });
comp.VerifyDiagnostics(
// 0.cs(4,19): error CS9230: Cannot perform a dynamic invocation on an expression with type 'CustomHandler'.
// CustomHandler c = $"{h1}" + $"{h2}";
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnExpression, expression).WithArguments("CustomHandler").WithLocation(4, 19),
// 0.cs(4,19): error CS9230: Cannot perform a dynamic invocation on an expression with type 'CustomHandler'.
// CustomHandler c = $"{h1}" + $"{h2}";
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnExpression, expression).WithArguments("CustomHandler").WithLocation(4, 19)
);
}
[Theory]
[InlineData(@"$""Literal{1}""")]
[InlineData(@"$""Literal"" + $""{1}""")]
public void ConversionInParamsArguments_01(string expression)
{
var code = @"
using System;
using System.Linq;
M(" + expression + ", " + expression + @");
void M(params CustomHandler[] handlers)
{
Console.WriteLine(string.Join(Environment.NewLine, handlers.Select(h => h.ToString())));
}
";
var verifier = CompileAndVerify(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) }, expectedOutput: @"
literal:Literal
value:1
alignment:0
format:
literal:Literal
value:1
alignment:0
format:
");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 100 (0x64)
.maxstack 7
.locals init (CustomHandler V_0)
IL_0000: ldc.i4.2
IL_0001: newarr ""CustomHandler""
IL_0006: dup
IL_0007: ldc.i4.0
IL_0008: ldloca.s V_0
IL_000a: ldc.i4.7
IL_000b: ldc.i4.1
IL_000c: call ""CustomHandler..ctor(int, int)""
IL_0011: ldloca.s V_0
IL_0013: ldstr ""Literal""
IL_0018: call ""void CustomHandler.AppendLiteral(string)""
IL_001d: ldloca.s V_0
IL_001f: ldc.i4.1
IL_0020: box ""int""
IL_0025: ldc.i4.0
IL_0026: ldnull
IL_0027: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_002c: ldloc.0
IL_002d: stelem ""CustomHandler""
IL_0032: dup
IL_0033: ldc.i4.1
IL_0034: ldloca.s V_0
IL_0036: ldc.i4.7
IL_0037: ldc.i4.1
IL_0038: call ""CustomHandler..ctor(int, int)""
IL_003d: ldloca.s V_0
IL_003f: ldstr ""Literal""
IL_0044: call ""void CustomHandler.AppendLiteral(string)""
IL_0049: ldloca.s V_0
IL_004b: ldc.i4.1
IL_004c: box ""int""
IL_0051: ldc.i4.0
IL_0052: ldnull
IL_0053: call ""void CustomHandler.AppendFormatted(object, int, string)""
IL_0058: ldloc.0
IL_0059: stelem ""CustomHandler""
IL_005e: call ""void Program.<<Main>$>g__M|0_0(CustomHandler[])""
IL_0063: ret
}
");
}
[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/71488")]
public void ConversionInParamsArguments_02()
{
var code = @"
using System;
using System.Linq;
using System.Runtime.CompilerServices;
M("""", $""test"");
void M(string s, [InterpolatedStringHandlerArgument(nameof(s))] params CustomHandler[] handlers)
{
Console.WriteLine(string.Join(Environment.NewLine, handlers.Select(h => h.ToString())));
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
comp.VerifyEmitDiagnostics(
// 0.cs(8,19): error CS8946: 'CustomHandler[]' is not an interpolated string handler type.
// void M(string s, [InterpolatedStringHandlerArgument(nameof(s))] params CustomHandler[] handlers)
Diagnostic(ErrorCode.ERR_TypeIsNotAnInterpolatedStringHandlerType, "InterpolatedStringHandlerArgument(nameof(s))").WithArguments("CustomHandler[]").WithLocation(8, 19)
);
}
[Theory]
[InlineData("static")]
[InlineData("")]
public void ArgumentsOnLocalFunctions_01(string mod)
{
var code = @"
using System.Runtime.CompilerServices;
M($"""");
" + mod + @" void M([InterpolatedStringHandlerArgument("""")] CustomHandler c) { }
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (4,3): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 3),
// (6,10): error CS8944: 'M(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument.
// void M([InterpolatedStringHandlerArgument("")] CustomHandler c) { }
Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("M(CustomHandler)").WithLocation(6, 10 + mod.Length)
);
}
[Theory]
[InlineData("static")]
[InlineData("")]
public void ArgumentsOnLocalFunctions_02(string mod)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
M(1, $"""");
" + mod + @" void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString());
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount) => _builder.Append(""i:"" + i.ToString());
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: @"i:1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 17 (0x11)
.maxstack 4
.locals init (int V_0)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: newobj ""CustomHandler..ctor(int, int, int)""
IL_000b: call ""void Program.<<Main>$>g__M|0_0(int, CustomHandler)""
IL_0010: ret
}
");
}
[Theory]
[InlineData("static")]
[InlineData("")]
public void ArgumentsOnLambdas_01(string mod)
{
var code = @"
using System.Runtime.CompilerServices;
var a = " + mod + @" ([InterpolatedStringHandlerArgument("""")] CustomHandler c) => { };
a($"""");
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (4,12): warning CS8971: InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site.
// var a = ([InterpolatedStringHandlerArgument("")] CustomHandler c) => { };
Diagnostic(ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters, @"InterpolatedStringHandlerArgument("""")").WithLocation(4, 12 + mod.Length),
// (4,12): error CS8944: 'lambda expression' is not an instance method, the receiver cannot be an interpolated string handler argument.
// var a = ([InterpolatedStringHandlerArgument("")] CustomHandler c) => { };
Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("lambda expression").WithLocation(4, 12 + mod.Length)
);
}
[Theory]
[InlineData("static")]
[InlineData("")]
public void ArgumentsOnLambdas_02(string mod)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
var a = " + mod + @" (int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString());
a(1, $"""");
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i) => throw null;
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: @"");
verifier.VerifyDiagnostics(
// (5,19): warning CS8971: InterpolatedStringHandlerArgument has no effect when applied to lambda parameters and will be ignored at the call site.
// var a = (int i, [InterpolatedStringHandlerArgument("i")] CustomHandler c) => Console.WriteLine(c.ToString());
Diagnostic(ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters, @"InterpolatedStringHandlerArgument(""i"")").WithLocation(5, 19 + mod.Length)
);
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 45 (0x2d)
.maxstack 4
IL_0000: ldsfld ""System.Action<int, CustomHandler> Program.<>c.<>9__0_0""
IL_0005: dup
IL_0006: brtrue.s IL_001f
IL_0008: pop
IL_0009: ldsfld ""Program.<>c Program.<>c.<>9""
IL_000e: ldftn ""void Program.<>c.<<Main>$>b__0_0(int, CustomHandler)""
IL_0014: newobj ""System.Action<int, CustomHandler>..ctor(object, System.IntPtr)""
IL_0019: dup
IL_001a: stsfld ""System.Action<int, CustomHandler> Program.<>c.<>9__0_0""
IL_001f: ldc.i4.1
IL_0020: ldc.i4.0
IL_0021: ldc.i4.0
IL_0022: newobj ""CustomHandler..ctor(int, int)""
IL_0027: callvirt ""void System.Action<int, CustomHandler>.Invoke(int, CustomHandler)""
IL_002c: ret
}
");
}
[Fact]
public void ArgumentsOnDelegateTypes_01()
{
var code = @"
using System.Runtime.CompilerServices;
M m = null;
m($"""");
delegate void M([InterpolatedStringHandlerArgument("""")] CustomHandler c);
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (6,3): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// m($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(6, 3),
// (8,18): error CS8944: 'M.Invoke(CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument.
// delegate void M([InterpolatedStringHandlerArgument("")] CustomHandler c);
Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("M.Invoke(CustomHandler)").WithLocation(8, 18)
);
}
[Fact]
public void ArgumentsOnDelegateTypes_02()
{
var vbCode = @"
Imports System.Runtime.CompilerServices
Public Delegate Sub M(<InterpolatedStringHandlerArgument("""")> c As CustomHandler)
<InterpolatedStringHandler>
Public Structure CustomHandler
End Structure
";
var vbComp = CreateVisualBasicCompilation(new[] { vbCode, InterpolatedStringHandlerAttributesVB });
vbComp.VerifyDiagnostics();
var code = @"
M m = null;
m($"""");
";
var comp = CreateCompilation(code, references: new[] { vbComp.EmitToImageReference() });
comp.VerifyDiagnostics(
// (4,3): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// m($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(4, 3),
// (4,3): error CS1729: 'CustomHandler' does not contain a constructor that takes 2 arguments
// m($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "2").WithLocation(4, 3),
// (4,3): error CS1729: 'CustomHandler' does not contain a constructor that takes 3 arguments
// m($"");
Diagnostic(ErrorCode.ERR_BadCtorArgCount, @"$""""").WithArguments("CustomHandler", "3").WithLocation(4, 3)
);
}
[Fact]
public void ArgumentsOnDelegateTypes_03()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
M m = (i, c) => Console.WriteLine(c.ToString());
m(1, $"""");
delegate void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c);
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int i) : this(literalLength, formattedCount) => _builder.Append(""i:"" + i.ToString());
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: @"i:1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 48 (0x30)
.maxstack 5
.locals init (int V_0)
IL_0000: ldsfld ""M Program.<>c.<>9__0_0""
IL_0005: dup
IL_0006: brtrue.s IL_001f
IL_0008: pop
IL_0009: ldsfld ""Program.<>c Program.<>c.<>9""
IL_000e: ldftn ""void Program.<>c.<<Main>$>b__0_0(int, CustomHandler)""
IL_0014: newobj ""M..ctor(object, System.IntPtr)""
IL_0019: dup
IL_001a: stsfld ""M Program.<>c.<>9__0_0""
IL_001f: ldc.i4.1
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: ldc.i4.0
IL_0023: ldc.i4.0
IL_0024: ldloc.0
IL_0025: newobj ""CustomHandler..ctor(int, int, int)""
IL_002a: callvirt ""void M.Invoke(int, CustomHandler)""
IL_002f: ret
}
");
}
[Fact]
public void HandlerConstructorWithDefaultArgument_01()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M($"""");
class C
{
public static void M(CustomHandler c) => Console.WriteLine(c.ToString());
}
[InterpolatedStringHandler]
partial struct CustomHandler
{
private int _i = 0;
public CustomHandler(int literalLength, int formattedCount, int i = 1) => _i = i;
public override string ToString() => _i.ToString();
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 14 (0xe)
.maxstack 3
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: ldc.i4.1
IL_0003: newobj ""CustomHandler..ctor(int, int, int)""
IL_0008: call ""void C.M(CustomHandler)""
IL_000d: ret
}
");
}
[Fact]
public void HandlerConstructorWithDefaultArgument_02()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M($""Literal"");
class C
{
public static void M(CustomHandler c) => Console.WriteLine(c.ToString());
}
[InterpolatedStringHandler]
partial struct CustomHandler
{
private string _s = null;
public CustomHandler(int literalLength, int formattedCount, out bool isValid, int i = 1) { _s = i.ToString(); isValid = false; }
public void AppendLiteral(string s) => _s += s;
public override string ToString() => _s;
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 33 (0x21)
.maxstack 4
.locals init (CustomHandler V_0,
bool V_1)
IL_0000: ldc.i4.7
IL_0001: ldc.i4.0
IL_0002: ldloca.s V_1
IL_0004: ldc.i4.1
IL_0005: newobj ""CustomHandler..ctor(int, int, out bool, int)""
IL_000a: stloc.0
IL_000b: ldloc.1
IL_000c: brfalse.s IL_001a
IL_000e: ldloca.s V_0
IL_0010: ldstr ""Literal""
IL_0015: call ""void CustomHandler.AppendLiteral(string)""
IL_001a: ldloc.0
IL_001b: call ""void C.M(CustomHandler)""
IL_0020: ret
}
");
}
[Fact]
public void HandlerConstructorWithDefaultArgument_03()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(1, $"""");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
[InterpolatedStringHandler]
partial struct CustomHandler
{
private string _s = null;
public CustomHandler(int literalLength, int formattedCount, int i1, int i2 = 2) { _s = i1.ToString() + i2.ToString(); }
public void AppendLiteral(string s) => _s += s;
public override string ToString() => _s;
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"12");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 18 (0x12)
.maxstack 5
.locals init (int V_0)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.0
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: ldc.i4.2
IL_0007: newobj ""CustomHandler..ctor(int, int, int, int)""
IL_000c: call ""void C.M(int, CustomHandler)""
IL_0011: ret
}
");
}
[Fact]
public void HandlerConstructorWithDefaultArgument_04()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
C.M(1, $""Literal"");
class C
{
public static void M(int i, [InterpolatedStringHandlerArgument(""i"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
[InterpolatedStringHandler]
partial struct CustomHandler
{
private string _s = null;
public CustomHandler(int literalLength, int formattedCount, int i1, out bool isValid, int i2 = 2) { _s = i1.ToString() + i2.ToString(); isValid = false; }
public void AppendLiteral(string s) => _s += s;
public override string ToString() => _s;
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, expectedOutput: @"12");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 37 (0x25)
.maxstack 6
.locals init (int V_0,
CustomHandler V_1,
bool V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldc.i4.7
IL_0004: ldc.i4.0
IL_0005: ldloc.0
IL_0006: ldloca.s V_2
IL_0008: ldc.i4.2
IL_0009: newobj ""CustomHandler..ctor(int, int, int, out bool, int)""
IL_000e: stloc.1
IL_000f: ldloc.2
IL_0010: brfalse.s IL_001e
IL_0012: ldloca.s V_1
IL_0014: ldstr ""Literal""
IL_0019: call ""void CustomHandler.AppendLiteral(string)""
IL_001e: ldloc.1
IL_001f: call ""void C.M(int, CustomHandler)""
IL_0024: ret
}
");
}
[Fact]
public void HandlerExtensionMethod_01()
{
var code = @"
$""Test"".M();
public static class StringExt
{
public static void M(this CustomHandler handler) => throw null;
}
";
var comp = CreateCompilation(new[] { code, GetInterpolatedStringCustomHandlerType("CustomHandler", "struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (2,1): error CS1929: 'string' does not contain a definition for 'M' and the best extension method overload 'StringExt.M(CustomHandler)' requires a receiver of type 'CustomHandler'
// $"Test".M();
Diagnostic(ErrorCode.ERR_BadInstanceArgType, @"$""Test""").WithArguments("string", "M", "StringExt.M(CustomHandler)", "CustomHandler").WithLocation(2, 1)
);
}
[Fact]
public void HandlerExtensionMethod_02()
{
var code = @"
using System.Runtime.CompilerServices;
var s = new S1();
s.M($"""");
public struct S1
{
public S1() { }
public int Field = 1;
}
public static class S1Ext
{
public static void M(this S1 s, [InterpolatedStringHandlerArgument("""")] CustomHandler c) => throw null;
}
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, S1 s) => throw null;
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (5,5): error CS8949: The InterpolatedStringHandlerArgumentAttribute applied to parameter 'CustomHandler c' is malformed and cannot be interpreted. Construct an instance of 'CustomHandler' manually.
// s.M($"");
Diagnostic(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, @"$""""").WithArguments("CustomHandler c", "CustomHandler").WithLocation(5, 5),
// (15,38): error CS8944: 'S1Ext.M(S1, CustomHandler)' is not an instance method, the receiver cannot be an interpolated string handler argument.
// public static void M(this S1 s, [InterpolatedStringHandlerArgument("")] CustomHandler c) => throw null;
Diagnostic(ErrorCode.ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName, @"InterpolatedStringHandlerArgument("""")").WithArguments("S1Ext.M(S1, CustomHandler)").WithLocation(15, 38)
);
}
[Fact]
public void HandlerExtensionMethod_03()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
var s = new S1();
s.M($"""");
public struct S1
{
public S1() { }
public int Field = 1;
}
public static class S1Ext
{
public static void M(this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, S1 s) : this(literalLength, formattedCount) => _builder.Append(""s.Field:"" + s.Field);
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: "s.Field:1");
verifier.VerifyDiagnostics();
}
[Fact]
public void HandlerExtensionMethod_04()
{
var code = @"
using System;
using System.Runtime.CompilerServices;
var s = new S1();
s.M($"""");
public struct S1
{
public S1() { }
public int Field = 1;
}
public static class S1Ext
{
public static void M(ref this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => Console.WriteLine(s.Field);
}
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref S1 s) : this(literalLength, formattedCount) => s.Field = 2;
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: "2");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 25 (0x19)
.maxstack 4
.locals init (S1 V_0, //s
S1& V_1)
IL_0000: ldloca.s V_0
IL_0002: call ""S1..ctor()""
IL_0007: ldloca.s V_0
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: ldc.i4.0
IL_000c: ldc.i4.0
IL_000d: ldloc.1
IL_000e: newobj ""CustomHandler..ctor(int, int, ref S1)""
IL_0013: call ""void S1Ext.M(ref S1, CustomHandler)""
IL_0018: ret
}
");
}
[Theory, CombinatorialData]
public void HandlerExtensionMethod_05([CombinatorialValues("in", "ref readonly")] string modifier)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
var s = new S1();
s.M($"""");
public struct S1
{
public S1() { }
public int Field = 1;
}
public static class S1Ext
{
public static void M(" + modifier + @" this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => Console.WriteLine(c.ToString());
}
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, " + modifier + @" S1 s) : this(literalLength, formattedCount) => _builder.Append(""s.Field:"" + s.Field);
}
";
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) }, expectedOutput: "s.Field:1");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", @"
{
// Code size 25 (0x19)
.maxstack 4
.locals init (S1 V_0, //s
S1& V_1)
IL_0000: ldloca.s V_0
IL_0002: call ""S1..ctor()""
IL_0007: ldloca.s V_0
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: ldc.i4.0
IL_000c: ldc.i4.0
IL_000d: ldloc.1
IL_000e: newobj ""CustomHandler..ctor(int, int, " + modifier + @" S1)""
IL_0013: call ""void S1Ext.M(" + modifier + @" S1, CustomHandler)""
IL_0018: ret
}
");
}
[Fact]
public void HandlerExtensionMethod_06()
{
var code = @"
using System.Runtime.CompilerServices;
var s = new S1();
s.M($"""");
public struct S1
{
public S1() { }
public int Field = 1;
}
public static class S1Ext
{
public static void M(in this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => throw null;
}
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, ref S1 s) => throw null;
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (5,1): error CS1620: Argument 3 must be passed with the 'ref' keyword
// s.M($"");
Diagnostic(ErrorCode.ERR_BadArgRef, "s").WithArguments("3", "ref").WithLocation(5, 1)
);
}
[Fact]
public void HandlerExtensionMethod_07()
{
var code = @"
using System.Runtime.CompilerServices;
var s = new S1();
s.M($""text"");
public struct S1
{
public S1() { }
public int Field = 1;
}
public static class S1Ext
{
public static void M(ref this S1 s, [InterpolatedStringHandlerArgument(""s"")] CustomHandler c) => System.Console.WriteLine(c.ToString());
}
partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, in S1 s) : this(literalLength, formattedCount) { }
}
";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, parseOptions: TestOptions.Regular11);
comp.VerifyDiagnostics(
// 0.cs(5,1): error CS9194: Argument 3 may not be passed with the 'ref' keyword in language version 11.0. To pass 'ref' arguments to 'in' parameters, upgrade to language version 12.0 or greater.
// s.M($"text");
Diagnostic(ErrorCode.ERR_BadArgExtraRefLangVersion, "s").WithArguments("3", "11.0", "12.0").WithLocation(5, 1)
);
var verifier = CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler },
expectedOutput: "literal:text");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", """
{
// Code size 39 (0x27)
.maxstack 4
.locals init (S1 V_0, //s
S1& V_1,
CustomHandler V_2)
IL_0000: ldloca.s V_0
IL_0002: call "S1..ctor()"
IL_0007: ldloca.s V_0
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: ldc.i4.4
IL_000c: ldc.i4.0
IL_000d: ldloc.1
IL_000e: newobj "CustomHandler..ctor(int, int, in S1)"
IL_0013: stloc.2
IL_0014: ldloca.s V_2
IL_0016: ldstr "text"
IL_001b: call "void CustomHandler.AppendLiteral(string)"
IL_0020: ldloc.2
IL_0021: call "void S1Ext.M(ref S1, CustomHandler)"
IL_0026: ret
}
""");
}
[Fact]
public void NoStandaloneConstructor()
{
var code = @"
using System.Runtime.CompilerServices;
CustomHandler c = $"""";
[InterpolatedStringHandler]
struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, string s) {}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute });
comp.VerifyDiagnostics(
// (4,19): error CS7036: There is no argument given that corresponds to the required parameter 's' of 'CustomHandler.CustomHandler(int, int, string)'
// CustomHandler c = $"";
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, @"$""""").WithArguments("s", "CustomHandler.CustomHandler(int, int, string)").WithLocation(4, 19),
// (4,19): error CS1615: Argument 3 may not be passed with the 'out' keyword
// CustomHandler c = $"";
Diagnostic(ErrorCode.ERR_BadArgExtraRef, @"$""""").WithArguments("3", "out").WithLocation(4, 19)
);
}
[Theory]
[InlineData(@"$""literal{1}""")]
[InlineData(@"$""literal"" + $""{1}""")]
public void ReferencingThis_TopLevelObjectInitializer(string expression)
{
var code = @"
using System.Runtime.CompilerServices;
_ = new C2 { [" + expression + @"] = { A = 1, B = 2 } };
public class C2
{
public C3 this[[InterpolatedStringHandlerArgument("""")] CustomHandler c]
{
get => new C3();
set { }
}
}
public class C3
{
public int A
{
get => 0;
set { }
}
public int B
{
get => 0;
set { }
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C2 c) : this(literalLength, formattedCount)
{
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (4,15): error CS8976: Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers.
// _ = new C2 { [$"literal" + $"{1}"] = { A = 1, B = 2 } };
Diagnostic(ErrorCode.ERR_InterpolatedStringsReferencingInstanceCannotBeInObjectInitializers, expression).WithLocation(4, 15)
);
}
[Theory]
[InlineData(@"$""literal{1}""")]
[InlineData(@"$""literal"" + $""{1}""")]
public void ReferencingThis_NestedObjectInitializer(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
_ = new C1 { C2 = { [" + expression + @"] = { A = 1, B = 2 } } };
class C1
{
public C2 C2 { get => null; set { } }
}
public class C2
{
public C3 this[[InterpolatedStringHandlerArgument("""")] CustomHandler c]
{
get => new C3();
set { }
}
}
public class C3
{
public int A
{
get => 0;
set { }
}
public int B
{
get => 0;
set { }
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C2 c) : this(literalLength, formattedCount)
{
Console.WriteLine(""CustomHandler ctor"");
}
}
";
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) });
comp.VerifyDiagnostics(
// (5,22): error CS8976: Interpolated string handler conversions that reference the instance being indexed cannot be used in indexer member initializers.
// _ = new C1 { C2 = { [$"literal{1}"] = { A = 1, B = 2 } } };
Diagnostic(ErrorCode.ERR_InterpolatedStringsReferencingInstanceCannotBeInObjectInitializers, expression).WithLocation(5, 22)
);
}
[Theory]
[InlineData(@"$""literal{1}""")]
[InlineData(@"$""literal"" + $""{1}""")]
public void NotReferencingThis_NestedObjectInitializer(string expression)
{
var code = @"
using System;
using System.Runtime.CompilerServices;
_ = new C1 { C2 = { [3, " + expression + @"] = { A = 1, B = 2 } } };
class C1
{
public C2 C2 { get { Console.WriteLine(""get_C2""); return new C2(); } set { } }
}
public class C2
{
public C3 this[int arg1, [InterpolatedStringHandlerArgument(""arg1"")] CustomHandler c]
{
get { Console.WriteLine(""Indexer""); return new C3(); }
set { }
}
}
public class C3
{
public int A
{
get => 0;
set { }
}
public int B
{
get => 0;
set { }
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, int arg1) : this(literalLength, formattedCount)
{
Console.WriteLine(""CustomHandler ctor"");
}
}
";
CompileAndVerify(new[] { code, InterpolatedStringHandlerArgumentAttribute, GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false) },
expectedOutput: @"
CustomHandler ctor
get_C2
Indexer
get_C2
Indexer");
}
[Fact]
public void InterpolatedStringBeforeCSharp6()
{
var text = @"
class C
{
string M()
{
return $""hello"";
}
}";
CreateCompilation(text, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics(
// (6,16): error CS8026: Feature 'interpolated strings' is not available in C# 5. Please use language version 6 or greater.
// return $"hello";
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, @"$""hello""").WithArguments("interpolated strings", "6").WithLocation(6, 16));
}
[Fact]
public void InterpolatedStringWithReplacementBeforeCSharp6()
{
var text = @"
class C
{
string M()
{
string other = ""world"";
return $""hello + {other}"";
}
}";
CreateCompilation(text, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics(
// (7,16): error CS8026: Feature 'interpolated strings' is not available in C# 5. Please use language version 6 or greater.
// return $"hello + {other}";
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, @"$""hello + {other}""").WithArguments("interpolated strings", "6").WithLocation(7, 16));
}
[Fact, WorkItem(1566008, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1566008")]
public void InterpolatedStringInForeach_HasErrors()
{
var text = """
int i = 1;
/*<bind>*/foreach (($"{i}") in new int[0]) {}/*</bind>*/
""";
var comp = CreateCompilation(text).VerifyDiagnostics(
// (1,5): warning CS0219: The variable 'i' is assigned but its value is never used
// int i = 1;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "i").WithArguments("i").WithLocation(1, 5),
// (2,29): error CS0230: Type and identifier are both required in a foreach statement
// /*<bind>*/foreach (($"{i}") in new int[0]) {}/*</bind>*/
Diagnostic(ErrorCode.ERR_BadForeachDecl, "in").WithLocation(2, 29)
);
VerifyOperationTreeForTest<ForEachVariableStatementSyntax>(comp, expectedOperationTree: """
IForEachLoopOperation (LoopKind.ForEach, Continue Label Id: 0, Exit Label Id: 1) (OperationKind.Loop, Type: null, IsInvalid) (Syntax: 'foreach (($ ... int[0]) {}')
LoopControlVariable:
IInterpolatedStringOperation (OperationKind.InterpolatedString, Type: System.String) (Syntax: '$"{i}"')
Parts(1):
IInterpolationOperation (OperationKind.Interpolation, Type: null) (Syntax: '{i}')
Expression:
ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i')
Alignment:
null
FormatString:
null
Collection:
IArrayCreationOperation (OperationKind.ArrayCreation, Type: System.Int32[]) (Syntax: 'new int[0]')
Dimension Sizes(1):
ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0')
Initializer:
null
Body:
IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{}')
NextVariables(0)
""");
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/66235")]
[InlineData(@"""""")]
[InlineData(@"@""""")]
[InlineData(@"""""""test""""""")]
public void ConvertStringLiteralToInterpolatedStringHandlerError_ByVal(string stringLiteral)
{
var code = $$"""
class C
{
void M()
{
ByVal({{stringLiteral}});
ByVal(ref {{stringLiteral}});
ByVal(in {{stringLiteral}});
ByVal(out {{stringLiteral}});
}
void ByVal(System.Runtime.CompilerServices.DefaultInterpolatedStringHandler s) { }
}
""";
CreateCompilation(code, targetFramework: TargetFramework.Net60).VerifyDiagnostics(
// (5,15): error CS9205: Expected interpolated string
// ByVal("");
Diagnostic(ErrorCode.ERR_ExpectedInterpolatedString, stringLiteral).WithLocation(5, 15),
// (6,19): error CS1510: A ref or out value must be an assignable variable
// ByVal(ref "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(6, 19),
// (7,18): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// ByVal(in "");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, stringLiteral).WithLocation(7, 18),
// (8,19): error CS1510: A ref or out value must be an assignable variable
// ByVal(out "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(8, 19)
);
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/66235")]
[InlineData(@"""""")]
[InlineData(@"@""""")]
[InlineData(@"""""""test""""""")]
public void ConvertStringLiteralToInterpolatedStringHandlerError_ByRef(string stringLiteral)
{
var code = $$"""
class C
{
void M()
{
ByRef({{stringLiteral}});
ByRef(ref {{stringLiteral}});
ByRef(in {{stringLiteral}});
ByRef(out {{stringLiteral}});
}
void ByRef(ref System.Runtime.CompilerServices.DefaultInterpolatedStringHandler s) { }
}
""";
CreateCompilation(code, targetFramework: TargetFramework.Net60).VerifyDiagnostics(
// (5,15): error CS9205: Expected interpolated string
// ByRef("");
Diagnostic(ErrorCode.ERR_ExpectedInterpolatedString, stringLiteral).WithLocation(5, 15),
// (6,19): error CS1510: A ref or out value must be an assignable variable
// ByRef(ref "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(6, 19),
// (7,18): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// ByRef(in "");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, stringLiteral).WithLocation(7, 18),
// (8,19): error CS1510: A ref or out value must be an assignable variable
// ByRef(out "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(8, 19)
);
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/66235")]
[InlineData(@"""""")]
[InlineData(@"@""""")]
[InlineData(@"""""""test""""""")]
public void ConvertStringLiteralToInterpolatedStringHandlerError_ByIn(string stringLiteral)
{
var code = $$"""
class C
{
void M()
{
ByIn({{stringLiteral}});
ByIn(ref {{stringLiteral}});
ByIn(in {{stringLiteral}});
ByIn(out {{stringLiteral}});
}
void ByIn(in System.Runtime.CompilerServices.DefaultInterpolatedStringHandler s) { }
}
""";
CreateCompilation(code, targetFramework: TargetFramework.Net60).VerifyDiagnostics(
// (5,14): error CS9205: Expected interpolated string
// ByIn("");
Diagnostic(ErrorCode.ERR_ExpectedInterpolatedString, stringLiteral).WithLocation(5, 14),
// (6,18): error CS1510: A ref or out value must be an assignable variable
// ByIn(ref "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(6, 18),
// (7,17): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// ByIn(in "");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, stringLiteral).WithLocation(7, 17),
// (8,18): error CS1510: A ref or out value must be an assignable variable
// ByIn(out "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(8, 18)
);
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/66235")]
[InlineData(@"""""")]
[InlineData(@"@""""")]
[InlineData(@"""""""test""""""")]
public void ConvertStringLiteralToInterpolatedStringHandlerError_ByOut(string stringLiteral)
{
var code = $$"""
class C
{
void M()
{
ByOut({{stringLiteral}});
ByOut(ref {{stringLiteral}});
ByOut(in {{stringLiteral}});
ByOut(out {{stringLiteral}});
}
void ByOut(out System.Runtime.CompilerServices.DefaultInterpolatedStringHandler s) { s = default; }
}
""";
CreateCompilation(code, targetFramework: TargetFramework.Net60).VerifyDiagnostics(
// (5,15): error CS1620: Argument 1 must be passed with the 'out' keyword
// ByOut("");
Diagnostic(ErrorCode.ERR_BadArgRef, stringLiteral).WithArguments("1", "out").WithLocation(5, 15),
// (6,19): error CS1510: A ref or out value must be an assignable variable
// ByOut(ref "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(6, 19),
// (7,18): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// ByOut(in "");
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, stringLiteral).WithLocation(7, 18),
// (8,19): error CS1510: A ref or out value must be an assignable variable
// ByOut(out "");
Diagnostic(ErrorCode.ERR_RefLvalueExpected, stringLiteral).WithLocation(8, 19)
);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/66235")]
public void ConvertStringLiteralToInterpolatedStringHandlerError_NotStringLiteral()
{
var code = """
class C
{
void M(string s)
{
ByVal(s);
ByRef(s);
ByIn(s);
}
void ByVal(System.Runtime.CompilerServices.DefaultInterpolatedStringHandler s) { }
void ByRef(ref System.Runtime.CompilerServices.DefaultInterpolatedStringHandler s) { }
void ByIn(in System.Runtime.CompilerServices.DefaultInterpolatedStringHandler s) { }
}
""";
CreateCompilation(code, targetFramework: TargetFramework.Net60).VerifyDiagnostics(
// (5,15): error CS1503: Argument 1: cannot convert from 'string' to 'System.Runtime.CompilerServices.DefaultInterpolatedStringHandler'
// ByVal(s);
Diagnostic(ErrorCode.ERR_BadArgType, "s").WithArguments("1", "string", "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler").WithLocation(5, 15),
// (6,15): error CS1620: Argument 1 must be passed with the 'ref' keyword
// ByRef(s);
Diagnostic(ErrorCode.ERR_BadArgRef, "s").WithArguments("1", "ref").WithLocation(6, 15),
// (7,14): error CS1503: Argument 1: cannot convert from 'string' to 'System.Runtime.CompilerServices.DefaultInterpolatedStringHandler'
// ByIn(s);
Diagnostic(ErrorCode.ERR_BadArgType, "s").WithArguments("1", "string", "in System.Runtime.CompilerServices.DefaultInterpolatedStringHandler").WithLocation(7, 14));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/68110")]
public void DefaultSyntaxValueReentrancy_01()
{
var source =
"""
#nullable enable
[A(3, X = 6)]
public struct A
{
public int X;
public A(int x, A a = $"{1}") { }
}
""";
var compilation = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp);
var a = compilation.GlobalNamespace.GetTypeMember("A").InstanceConstructors.Where(c => !c.IsDefaultValueTypeConstructor()).Single();
Assert.Null(a.Parameters[1].ExplicitDefaultValue);
Assert.True(a.Parameters[1].HasExplicitDefaultValue);
compilation.VerifyDiagnostics(
// (3,2): error CS0616: 'A' is not an attribute class
// [A(3, X = 6)]
Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "A").WithArguments("A").WithLocation(3, 2),
// (3,2): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [A(3, X = 6)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "A(3, X = 6)").WithLocation(3, 2),
// (8,27): error CS1736: Default parameter value for 'a' must be a compile-time constant
// public A(int x, A a = $"{1}") { }
Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"$""{1}""").WithArguments("a").WithLocation(8, 27));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/68110")]
public void DefaultSyntaxValueReentrancy_02()
{
var source =
"""
#nullable enable
[A(3, X = 6)]
public struct A
{
public int X;
public A(int x, A a = M($"{1}")) { }
public static void M(ref A a) {}
}
""";
var compilation = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp);
var a = compilation.GlobalNamespace.GetTypeMember("A").InstanceConstructors.Where(c => !c.IsDefaultValueTypeConstructor()).Single();
Assert.Null(a.Parameters[1].ExplicitDefaultValue);
Assert.True(a.Parameters[1].HasExplicitDefaultValue);
compilation.VerifyDiagnostics(
// (3,2): error CS0616: 'A' is not an attribute class
// [A(3, X = 6)]
Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "A").WithArguments("A").WithLocation(3, 2),
// (3,2): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [A(3, X = 6)]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "A(3, X = 6)").WithLocation(3, 2),
// (8,29): error CS1620: Argument 1 must be passed with the 'ref' keyword
// public A(int x, A a = M($"{1}")) { }
Diagnostic(ErrorCode.ERR_BadArgRef, @"$""{1}""").WithArguments("1", "ref").WithLocation(8, 29));
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73667")]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_ThisParameter_ReferenceTypeReferenceReceiver(
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = $$"""
using System;
using System.Runtime.CompilerServices;
C c = new C(5);
ref C c2 = ref c;
c2.M({{expression}}, c2 = null);
public class C
{
public int Prop { get; }
public C(int i) => Prop = i;
public void M([InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c, C cNull)
{
Console.WriteLine(cNull is null ? "cNull" : null);
Console.WriteLine(c.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount)
{
_builder.AppendLine("c.Prop:" + c.Prop.ToString());
}
}
""";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: """
cNull
c.Prop:5
literal:literal
""");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", """
{
// Code size 52 (0x34)
.maxstack 5
.locals init (C V_0, //c
C& V_1, //c2
C V_2,
CustomHandler V_3,
C V_4)
IL_0000: ldc.i4.5
IL_0001: newobj "C..ctor(int)"
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: ldind.ref
IL_000c: stloc.2
IL_000d: ldloc.2
IL_000e: ldloca.s V_3
IL_0010: ldc.i4.7
IL_0011: ldc.i4.0
IL_0012: ldloc.2
IL_0013: call "CustomHandler..ctor(int, int, C)"
IL_0018: ldloca.s V_3
IL_001a: ldstr "literal"
IL_001f: call "bool CustomHandler.AppendLiteral(string)"
IL_0024: pop
IL_0025: ldloc.3
IL_0026: ldloc.1
IL_0027: ldnull
IL_0028: dup
IL_0029: stloc.s V_4
IL_002b: stind.ref
IL_002c: ldloc.s V_4
IL_002e: callvirt "void C.M(CustomHandler, C)"
IL_0033: ret
}
""");
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73667")]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_ThisParameter_ReferenceTypeReferenceReceiver_ReverseOrder(
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = $$"""
using System;
using System.Runtime.CompilerServices;
C c = new C(5);
ref C c2 = ref c;
c2.M(c2 = null, {{expression}});
public class C
{
public int Prop { get; }
public C(int i) => Prop = i;
public void M(C cNull, [InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c)
{
Console.WriteLine(cNull is null ? "cNull" : null);
Console.WriteLine(c.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, C c) : this(literalLength, formattedCount)
{
_builder.AppendLine("c.Prop:" + c.Prop.ToString());
}
}
""";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler });
var verifier = CompileAndVerify(comp, expectedOutput: """
cNull
c.Prop:5
literal:literal
""");
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", """
{
// Code size 51 (0x33)
.maxstack 6
.locals init (C V_0, //c
C& V_1, //c2
C V_2,
C V_3,
CustomHandler V_4)
IL_0000: ldc.i4.5
IL_0001: newobj "C..ctor(int)"
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: ldind.ref
IL_000c: stloc.2
IL_000d: ldloc.2
IL_000e: ldloc.1
IL_000f: ldnull
IL_0010: dup
IL_0011: stloc.3
IL_0012: stind.ref
IL_0013: ldloc.3
IL_0014: ldloca.s V_4
IL_0016: ldc.i4.7
IL_0017: ldc.i4.0
IL_0018: ldloc.2
IL_0019: call "CustomHandler..ctor(int, int, C)"
IL_001e: ldloca.s V_4
IL_0020: ldstr "literal"
IL_0025: call "bool CustomHandler.AppendLiteral(string)"
IL_002a: pop
IL_002b: ldloc.s V_4
IL_002d: callvirt "void C.M(C, CustomHandler)"
IL_0032: ret
}
""");
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73667")]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_ThisParameter_InterfaceConstrainedRefReceiver(
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = $$"""
using System;
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
C c = new C(5);
Test(ref c);
}
static void Test<T>(ref T c2) where T : I1
{
c2.M(c2 = default, {{expression}});
}
}
public interface I1
{
int Prop { get; }
void M(I1 cNull, [InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c);
}
public class C : I1
{
public int Prop { get; }
public C(int i) => Prop = i;
public void M(I1 cNull, [InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c)
{
Console.WriteLine(cNull is null);
Console.WriteLine(c.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, I1 c) : this(literalLength, formattedCount)
{
_builder.AppendLine("c.Prop:" + c.Prop.ToString());
}
}
""";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, options: TestOptions.DebugExe);
var verifier = CompileAndVerify(comp, expectedOutput: """
True
c.Prop:5
literal:literal
""");
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Test<T>(ref T)", """
{
// Code size 104 (0x68)
.maxstack 6
.locals init (T& V_0,
T V_1,
T& V_2,
T V_3,
CustomHandler V_4)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: stloc.2
IL_0003: ldloca.s V_3
IL_0005: initobj "T"
IL_000b: ldloc.3
IL_000c: box "T"
IL_0011: brtrue.s IL_001e
IL_0013: ldloc.2
IL_0014: ldobj "T"
IL_0019: stloc.1
IL_001a: ldloca.s V_1
IL_001c: br.s IL_001f
IL_001e: ldloc.2
IL_001f: stloc.0
IL_0020: ldloc.0
IL_0021: ldarg.0
IL_0022: ldloca.s V_3
IL_0024: initobj "T"
IL_002a: ldloc.3
IL_002b: dup
IL_002c: stloc.3
IL_002d: stobj "T"
IL_0032: ldloc.3
IL_0033: box "T"
IL_0038: ldloca.s V_4
IL_003a: ldc.i4.7
IL_003b: ldc.i4.0
IL_003c: ldloc.0
IL_003d: ldobj "T"
IL_0042: box "T"
IL_0047: call "CustomHandler..ctor(int, int, I1)"
IL_004c: ldloca.s V_4
IL_004e: ldstr "literal"
IL_0053: call "bool CustomHandler.AppendLiteral(string)"
IL_0058: pop
IL_0059: ldloc.s V_4
IL_005b: constrained. "T"
IL_0061: callvirt "void I1.M(I1, CustomHandler)"
IL_0066: nop
IL_0067: ret
}
""");
}
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73667")]
[CombinatorialData]
public void InterpolatedStringHandlerArgumentAttribute_ThisParameter_InterfaceAndClassConstrainedRefReceiver(
[CombinatorialValues(@"$""literal""", @"$""literal"" + $""""")] string expression)
{
var code = $$"""
using System;
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
C c = new C(5);
Test(ref c);
}
static void Test<T>(ref T c2) where T : class, I1
{
c2.M(c2 = default, {{expression}});
}
}
public interface I1
{
int Prop { get; }
void M(I1 cNull, [InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c);
}
public class C : I1
{
public int Prop { get; }
public C(int i) => Prop = i;
public void M(I1 cNull, [InterpolatedStringHandlerArgumentAttribute("")] CustomHandler c)
{
Console.WriteLine(cNull is null);
Console.WriteLine(c.ToString());
}
}
public partial struct CustomHandler
{
public CustomHandler(int literalLength, int formattedCount, I1 c) : this(literalLength, formattedCount)
{
_builder.AppendLine("c.Prop:" + c.Prop.ToString());
}
}
""";
var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);
var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, options: TestOptions.DebugExe);
var verifier = CompileAndVerify(comp, expectedOutput: """
True
c.Prop:5
literal:literal
""");
verifier.VerifyDiagnostics();
verifier.VerifyIL("Program.Test<T>(ref T)", """
{
// Code size 73 (0x49)
.maxstack 6
.locals init (T V_0,
T V_1,
CustomHandler V_2)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldobj "T"
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: box "T"
IL_000e: ldarg.0
IL_000f: ldloca.s V_1
IL_0011: initobj "T"
IL_0017: ldloc.1
IL_0018: dup
IL_0019: stloc.1
IL_001a: stobj "T"
IL_001f: ldloc.1
IL_0020: box "T"
IL_0025: ldloca.s V_2
IL_0027: ldc.i4.7
IL_0028: ldc.i4.0
IL_0029: ldloc.0
IL_002a: box "T"
IL_002f: call "CustomHandler..ctor(int, int, I1)"
IL_0034: ldloca.s V_2
IL_0036: ldstr "literal"
IL_003b: call "bool CustomHandler.AppendLiteral(string)"
IL_0040: pop
IL_0041: ldloc.2
IL_0042: callvirt "void I1.M(I1, CustomHandler)"
IL_0047: nop
IL_0048: ret
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74427")]
public void InterpolatedStringAsInputToUserDefinedConversion_01()
{
var source = """
class C
{
static void Main()
{
var y = (C1)$"dog"; // works
System.Console.WriteLine(y);
}
}
class C1
{
System.FormattableString x;
public C1(System.FormattableString x)
{
this.x = x;
}
public static implicit operator C1(System.FormattableString x) => new C1(x);
public override string ToString()
{
return ("C1:") + x.ToString();
}
}
""";
CompileAndVerify(source, expectedOutput: "C1:dog");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74427")]
public void InterpolatedStringAsInputToUserDefinedConversion_02()
{
var source = """
class C
{
static void Main()
{
var y = (C1)$"dog";
System.Console.WriteLine(y);
}
}
class C1
{
System.IFormattable x;
public C1(System.IFormattable x)
{
this.x = x;
}
public static implicit operator C1(System.IFormattable x) => new C1(x);
public override string ToString()
{
return ("C1:") + x.ToString();
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (18,37): error CS0552: 'C1.implicit operator C1(IFormattable)': user-defined conversions to or from an interface are not allowed
// public static implicit operator C1(System.IFormattable x) => new C1(x);
Diagnostic(ErrorCode.ERR_ConversionWithInterface, "C1").WithArguments("C1.implicit operator C1(System.IFormattable)").WithLocation(18, 37)
);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74677")]
public void StackOverflow()
{
var source = """
using System;
[Obsolete($"{Test2}")]
class Test2
{
}
""";
CreateCompilation(source).VerifyEmitDiagnostics(
// (3,14): error CS0119: 'Test2' is a type, which is not valid in the given context
// [Obsolete($"{Test2}")]
Diagnostic(ErrorCode.ERR_BadSKunknown, "Test2").WithArguments("Test2", "type").WithLocation(3, 14)
);
}
}
}
|