File: CodeGen\CodeGenScriptTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit.UnitTests)
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit
{
    public class CodeGenScriptTests : CSharpTestBase
    {
        [Fact]
        public void AnonymousTypes_TopLevelVar()
        {
            string test = @"
using System;
var o = new { a = 1 };
Console.WriteLine(o.ToString());
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            CompileAndVerify(
                CreateCompilationWithMscorlib461(
                    new[] { tree },
                    options: TestOptions.ReleaseExe.WithScriptClassName("Script"),
                    references: new[] { SystemCoreRef }),
                expectedOutput: "{ a = 1 }"
            );
        }
 
        [Fact]
        public void AnonymousTypes_TopLevel_Object()
        {
            string test = @"
using System;
object o = new { a = 1 };
Console.WriteLine(o.ToString());
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            CompileAndVerify(
                CreateCompilationWithMscorlib461(
                    new[] { tree },
                    options: TestOptions.ReleaseExe.WithScriptClassName("Script"),
                    references: new[] { SystemCoreRef }),
                expectedOutput: "{ a = 1 }"
            );
        }
 
        [Fact]
        public void AnonymousTypes_TopLevel_NoLocal()
        {
            string test = @"
using System;
Console.WriteLine(new { a = 1 }.ToString());
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            CompileAndVerify(
                CreateCompilationWithMscorlib461(
                    new[] { tree },
                    options: TestOptions.ReleaseExe.WithScriptClassName("Script"),
                    references: new[] { SystemCoreRef }),
                expectedOutput: "{ a = 1 }"
            );
        }
 
        [Fact]
        public void AnonymousTypes_NestedClass_Method()
        {
            string test = @"
using System;
class CLS 
{
    public void M()
    {
        Console.WriteLine(new { a = 1 }.ToString());
    }
}
 
new CLS().M();
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            CompileAndVerify(
                CreateCompilationWithMscorlib461(
                    new[] { tree },
                    options: TestOptions.ReleaseExe.WithScriptClassName("Script"),
                    references: new[] { SystemCoreRef }),
                expectedOutput: "{ a = 1 }"
            );
        }
 
        [Fact]
        public void AnonymousTypes_NestedClass_MethodParamDefValue()
        {
            string test = @"
using System;
class CLS 
{
    public void M(object p = new { a = 1 })
    {
        Console.WriteLine(""OK"");
    }
}
new CLS().M();
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            var compilation = CreateCompilationWithMscorlib461(
                new[] { tree },
                options: TestOptions.ReleaseExe.WithScriptClassName("Script"));
 
            compilation.VerifyDiagnostics(
                // (5,30): error CS1736: Default parameter value for 'p' must be a compile-time constant
                //     public void M(object p = new { a = 1 })
                Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new { a = 1 }").WithArguments("p"));
        }
 
        [Fact]
        public void AnonymousTypes_TopLevel_MethodParamDefValue()
        {
            string test = @"
using System;
 
public void M(object p = new { a = 1 })
{
    Console.WriteLine(""OK"");
}
 
M();
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            var compilation = CreateCompilationWithMscorlib461(
                new[] { tree },
                options: TestOptions.ReleaseExe.WithScriptClassName("Script"));
 
            compilation.VerifyDiagnostics(
                // (4,26): error CS1736: Default parameter value for 'p' must be a compile-time constant
                // public void M(object p = new { a = 1 })
                Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "new { a = 1 }").WithArguments("p"));
        }
 
        [Fact]
        public void AnonymousTypes_TopLevel_MethodAttribute()
        {
            string test = @"
using System;
 
class A: Attribute
{
    public object P;
}
 
[A(P = new { a = 1 })]
public void M()
{
    Console.WriteLine(""OK"");
}
 
M();
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            var compilation = CreateCompilationWithMscorlib461(
                new[] { tree },
                options: TestOptions.ReleaseExe.WithScriptClassName("Script"));
 
            compilation.VerifyDiagnostics(
                // (9,8): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
                // [A(P = new { a = 1 })]
                Diagnostic(ErrorCode.ERR_BadAttributeArgument, "new { a = 1 }"));
        }
 
        [Fact]
        public void AnonymousTypes_NestedTypeAttribute()
        {
            string test = @"
using System;
 
class A: Attribute
{
    public object P;
}
 
[A(P = new { a = 1 })]
class CLS 
{
}
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            var compilation = CreateCompilationWithMscorlib461(
                new[] { tree },
                options: TestOptions.ReleaseExe.WithScriptClassName("Script"));
 
            compilation.VerifyDiagnostics(
                // (9,8): error CS0836: Cannot use anonymous type in a constant expression
                // [A(P = new { a = 1 })]
                Diagnostic(ErrorCode.ERR_AnonymousTypeNotAvailable, "new"));
        }
 
        [Fact]
        public void CompilationChain_AnonymousTypeTemplates()
        {
            var s0 = CreateSubmission("var x = new { a = 1 }; ");
            var sx = CreateSubmission("var y = new { b = 2 }; ", previous: s0);
            var s1 = CreateSubmission("var y = new { b = new { a = 3 } };", previous: s0);
            var s2 = CreateSubmission("x = y.b; ", previous: s1);
 
            s2.VerifyDiagnostics();
            s2.EmitToArray();
 
            Assert.True(s2.AnonymousTypeManager.AreTemplatesSealed);
            Assert.Equal(0, s2.AnonymousTypeManager.GetAllCreatedTemplates().Length);
 
            Assert.True(s1.AnonymousTypeManager.AreTemplatesSealed);
            Assert.Equal(1, s1.AnonymousTypeManager.GetAllCreatedTemplates().Length);
 
            Assert.True(s0.AnonymousTypeManager.AreTemplatesSealed);
            Assert.Equal(1, s0.AnonymousTypeManager.GetAllCreatedTemplates().Length);
 
            Assert.False(sx.AnonymousTypeManager.AreTemplatesSealed);
        }
 
        [Fact]
        public void CompilationChain_DynamicSiteDelegates()
        {
            // TODO: references should be inherited
            MetadataReference[] references = { SystemCoreRef, CSharpRef };
 
            var s0 = CreateSubmission("var i = 1; dynamic d = null; d.m(ref i);", references);
            var sx = CreateSubmission("var i = 1; dynamic d = null; d.m(ref i, ref i);", references, previous: s0);
            var s1 = CreateSubmission("var i = 1; dynamic d = null; d.m(out i);", references, previous: s0);
 
            s1.VerifyDiagnostics();
            s1.EmitToArray();
 
            // no new delegates should have been created:
            Assert.True(s1.AnonymousTypeManager.AreTemplatesSealed);
            Assert.Equal(0, s1.AnonymousTypeManager.GetAllCreatedTemplates().Length);
 
            // delegate for (ref)
            Assert.True(s0.AnonymousTypeManager.AreTemplatesSealed);
            Assert.Equal(1, s0.AnonymousTypeManager.GetAllCreatedTemplates().Length);
 
            Assert.False(sx.AnonymousTypeManager.AreTemplatesSealed);
        }
 
        [Fact]
        public void Submissions_EmitToPeStream()
        {
            var s0 = CreateSubmission("int a = 1;");
            var s11 = CreateSubmission("a + 1", previous: s0);
            var s12 = CreateSubmission("a + 2", previous: s0);
 
            s11.VerifyEmitDiagnostics();
            s12.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void CrossSubmissionGenericInterfaceImplementation_Generic()
        {
            var c0 = CreateSubmission(@"
public interface I<T>
{
    void m<TT>(T x, TT y);
}
");
 
            var c1 = CreateSubmission(@"
abstract public class C : I<int>
{
    public void m<TT>(int x, TT y)
    {
    }
}", previous: c0);
 
            c0.VerifyEmitDiagnostics();
            c1.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void CrossSubmissionGenericInterfaceImplementation_Explicit_GenericMethod()
        {
            var c0 = CreateSubmission(@"
public interface I<T>
{
    void m<S>(T x, S y);
}
");
 
            var c1 = CreateSubmission(@"
abstract public class C : I<int>
{
    void I<int>.m<S>(int x, S y)
    {
    }
}", previous: c0);
 
            c0.VerifyEmitDiagnostics();
            c1.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void CrossSubmissionGenericInterfaceImplementation_Explicit()
        {
            var c0 = CreateSubmission(@"
public interface I<T>
{
    void m(T x);
}
");
 
            var c1 = CreateSubmission(@"
abstract public class C : I<int>
{
    void I<int>.m(int x)
    {
    }
}", previous: c0);
 
            c0.VerifyEmitDiagnostics();
            c1.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void CrossSubmissionGenericInterfaceImplementation_Explicit_NoGenericParametersInSignature()
        {
            var c0 = CreateSubmission(@"
public interface I<T>
{
    void m(byte x);
}
");
 
            var c1 = CreateSubmission(@"
abstract public class C : I<int>
{
    void I<int>.m(byte x)
    {
    }
}", previous: c0);
 
            c0.VerifyEmitDiagnostics();
            c1.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void GenericInterfaceImplementation_Explicit_NoGenericParametersInSignature()
        {
            var c0 = CreateSubmission(@"
public interface I<T>
{
    void m(byte x);
}
abstract public class C : I<int>
{
    void I<int>.m(byte x)
    {
    }
}");
            c0.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void CrossSubmissionInterfaceImplementation_Explicit_NoGenericParametersInSignature()
        {
            var c0 = CreateSubmission(@"
public interface I
{
    void m(byte x);
}
");
 
            var c1 = CreateSubmission(@"
abstract public class C : I
{
    void I.m(byte x)
    {
    }
}", previous: c0);
 
            c0.VerifyEmitDiagnostics();
            c1.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void CrossSubmissionNestedGenericInterfaceImplementation_Explicit()
        {
            var c0 = CreateSubmission(@"
class C<T>
{
    public interface I
    {
        void m(T x);
    }
}
");
 
            var c1 = CreateSubmission(@"
abstract public class D : C<int>.I
{
    void C<int>.I.m(int x)
    {
    }
}", previous: c0);
 
            c0.VerifyEmitDiagnostics();
            c1.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void NestedGenericInterfaceImplementation_Explicit()
        {
            var c0 = CreateSubmission(@"
class C<T>
{
    public interface I
    {
        void m(T x);
    }
}
abstract public class D : C<int>.I
{
    void C<int>.I.m(int x)
    {
    }
}");
            c0.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void ExternalInterfaceImplementation_Explicit()
        {
            var c0 = CreateSubmission(@"
using System.Collections;
using System.Collections.Generic;
 
abstract public class C : IEnumerable<int>
{
    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        return null;
    }
 
    IEnumerator IEnumerable.GetEnumerator()
    {
        return null;
    }
}");
            c0.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void AbstractAccessors()
        {
            var c0 = CreateSubmission(@"
public abstract class C
{
    public abstract event System.Action vEv;
    public abstract int prop { get; set; }
}
");
            c0.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void ExprStmtWithMethodCall()
        {
            var s0 = CreateSubmission("int Goo() { return 2;}");
            var s1 = CreateSubmission("(4 + 5) * Goo()", previous: s0);
 
            s0.VerifyEmitDiagnostics();
            s1.VerifyEmitDiagnostics();
        }
 
        /// <summary>
        /// The script entry point should complete synchronously.
        /// </summary>
        [WorkItem(4495, "https://github.com/dotnet/roslyn/issues/4495")]
        [ConditionalFact(typeof(DesktopOnly))]
        public void ScriptEntryPoint()
        {
            var source =
@"{
    await System.Threading.Tasks.Task.Delay(100);
    System.Console.Write(""complete"");
}";
            var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
            var verifier = CompileAndVerify(compilation, expectedOutput: @"complete");
            var methodData = verifier.TestData.GetMethodData("<Initialize>");
            Assert.Equal("System.Threading.Tasks.Task<object>", ((MethodSymbol)methodData.Method).ReturnType.ToDisplayString());
            methodData.VerifyIL(
@"{
  // Code size       57 (0x39)
  .maxstack  2
  .locals init (<<Initialize>>d__0 V_0)
  IL_0000:  newobj     ""<<Initialize>>d__0..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  call       ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object>.Create()""
  IL_000c:  stfld      ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> <<Initialize>>d__0.<>t__builder""
  IL_0011:  ldloc.0
  IL_0012:  ldarg.0
  IL_0013:  stfld      ""Script <<Initialize>>d__0.<>4__this""
  IL_0018:  ldloc.0
  IL_0019:  ldc.i4.m1
  IL_001a:  stfld      ""int <<Initialize>>d__0.<>1__state""
  IL_001f:  ldloc.0
  IL_0020:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> <<Initialize>>d__0.<>t__builder""
  IL_0025:  ldloca.s   V_0
  IL_0027:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object>.Start<<<Initialize>>d__0>(ref <<Initialize>>d__0)""
  IL_002c:  nop
  IL_002d:  ldloc.0
  IL_002e:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> <<Initialize>>d__0.<>t__builder""
  IL_0033:  call       ""System.Threading.Tasks.Task<object> System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object>.Task.get""
  IL_0038:  ret
}");
            methodData = verifier.TestData.GetMethodData("<Main>");
            Assert.True(((MethodSymbol)methodData.Method).ReturnsVoid);
            methodData.VerifyIL(
@"{
  // Code size       25 (0x19)
  .maxstack  1
  .locals init (System.Runtime.CompilerServices.TaskAwaiter<object> V_0)
  IL_0000:  newobj     "".ctor()""
  IL_0005:  callvirt   ""System.Threading.Tasks.Task<object> <Initialize>()""
  IL_000a:  callvirt   ""System.Runtime.CompilerServices.TaskAwaiter<object> System.Threading.Tasks.Task<object>.GetAwaiter()""
  IL_000f:  stloc.0
  IL_0010:  ldloca.s   V_0
  IL_0012:  call       ""object System.Runtime.CompilerServices.TaskAwaiter<object>.GetResult()""
  IL_0017:  pop
  IL_0018:  ret
}");
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        public void SubmissionEntryPoint()
        {
            var references = new[] { MscorlibRef_v4_0_30316_17626, SystemCoreRef };
            var source0 =
@"{
    await System.Threading.Tasks.Task.Delay(100);
    System.Console.Write(""complete"");
}";
            var s0 = CSharpCompilation.CreateScriptCompilation(
                "s0.dll",
                SyntaxFactory.ParseSyntaxTree(source0, options: TestOptions.Script),
                references);
            var verifier = CompileAndVerify(s0, verify: Verification.FailsPEVerify);
            var methodData = verifier.TestData.GetMethodData("<Initialize>");
            Assert.Equal("System.Threading.Tasks.Task<object>", ((MethodSymbol)methodData.Method).ReturnType.ToDisplayString());
            methodData.VerifyIL(
@"{
  // Code size       57 (0x39)
  .maxstack  2
  .locals init (<<Initialize>>d__0 V_0)
  IL_0000:  newobj     ""<<Initialize>>d__0..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  call       ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object>.Create()""
  IL_000c:  stfld      ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> <<Initialize>>d__0.<>t__builder""
  IL_0011:  ldloc.0
  IL_0012:  ldarg.0
  IL_0013:  stfld      ""Script <<Initialize>>d__0.<>4__this""
  IL_0018:  ldloc.0
  IL_0019:  ldc.i4.m1
  IL_001a:  stfld      ""int <<Initialize>>d__0.<>1__state""
  IL_001f:  ldloc.0
  IL_0020:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> <<Initialize>>d__0.<>t__builder""
  IL_0025:  ldloca.s   V_0
  IL_0027:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object>.Start<<<Initialize>>d__0>(ref <<Initialize>>d__0)""
  IL_002c:  nop
  IL_002d:  ldloc.0
  IL_002e:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object> <<Initialize>>d__0.<>t__builder""
  IL_0033:  call       ""System.Threading.Tasks.Task<object> System.Runtime.CompilerServices.AsyncTaskMethodBuilder<object>.Task.get""
  IL_0038:  ret
}");
            methodData = verifier.TestData.GetMethodData("<Factory>");
            Assert.Equal("System.Threading.Tasks.Task<object>", ((MethodSymbol)methodData.Method).ReturnType.ToDisplayString());
            methodData.VerifyIL(
@"{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  newobj     "".ctor(object[])""
  IL_0006:  callvirt   ""System.Threading.Tasks.Task<object> <Initialize>()""
  IL_000b:  ret
}");
        }
 
        [Fact]
        public void ScriptEntryPoint_MissingMethods()
        {
            var source = "System.Console.WriteLine(1);";
            var compilation = CreateCompilationWithMscorlib40(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe);
            compilation.VerifyEmitDiagnostics(
                // error CS1061: 'Task<object>' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'Task<object>' could be found (are you missing a using directive or an assembly reference?)
                //
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "").WithArguments("System.Threading.Tasks.Task<object>", "GetAwaiter").WithLocation(1, 1),
                // (1,1): error CS0518: Predefined type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1' is not defined or imported
                // System.Console.WriteLine(1);
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "System.Console.WriteLine(1);").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1").WithLocation(1, 1),
                // (1,1): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Create'
                // System.Console.WriteLine(1);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "System.Console.WriteLine(1);").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1", "Create").WithLocation(1, 1),
                // (1,1): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Task'
                // System.Console.WriteLine(1);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "System.Console.WriteLine(1);").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1", "Task").WithLocation(1, 1),
                // (1,1): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext'
                // System.Console.WriteLine(1);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "System.Console.WriteLine(1);").WithArguments("System.Runtime.CompilerServices.IAsyncStateMachine", "MoveNext").WithLocation(1, 1),
                // (1,1): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine'
                // System.Console.WriteLine(1);
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "System.Console.WriteLine(1);").WithArguments("System.Runtime.CompilerServices.IAsyncStateMachine", "SetStateMachine").WithLocation(1, 1));
        }
 
        [Fact]
        public void ExplicitImplementation()
        {
            string test = @"
interface I1
{
    void M();
}
 
void I1.M() {}
";
            var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script);
 
            var compilation = CreateCompilationWithMscorlib461(
                new[] { tree },
                options: TestOptions.ReleaseExe.WithScriptClassName("Script"));
 
            compilation.VerifyDiagnostics(
                // (7,6): error CS0540: 'I1.M()': containing type does not implement interface 'I1'
                // void I1.M() {}
                Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "I1").WithArguments("I1.M()", "I1").WithLocation(7, 6)
                );
 
            var s = CreateSubmission(test);
 
            s.VerifyDiagnostics(
                // (7,9): error CS0541: 'M()': explicit interface declaration can only be declared in a class, record, struct or interface
                // void I1.M() {}
                Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "M").WithArguments("M()").WithLocation(7, 9)
                );
        }
    }
}