diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs index 5ae3468323ad8c96f9fce58395e73b5dc40b9488..ba473a5e763b7aad0f6edf80e0a32fd8b75a2026 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs @@ -236,14 +236,20 @@ internal TypeSymbol ResultType out TypeSymbol resultType, out TypeSymbol returnType) { - var submissionReturnType = compilation.SubmissionReturnType ?? typeof(object); + var submissionReturnTypeOpt = compilation.ScriptCompilationInfo?.ReturnTypeOpt; var taskT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); var useSiteDiagnostic = taskT.GetUseSiteDiagnostic(); if (useSiteDiagnostic != null) { diagnostics.Add(useSiteDiagnostic, NoLocation.Singleton); } - resultType = compilation.GetTypeByReflectionType(submissionReturnType, diagnostics); + // If no explicit return type is set on ScriptCompilationInfo, default to + // System.Object from the target corlib. This allows cross compiling scripts + // to run on a target corlib that may differ from the host compiler's corlib. + // cf. https://github.com/dotnet/roslyn/issues/8506 + resultType = (object)submissionReturnTypeOpt == null + ? compilation.GetSpecialType(SpecialType.System_Object) + : compilation.GetTypeByReflectionType(submissionReturnTypeOpt, diagnostics); returnType = taskT.Construct(resultType); } } diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs index 90fa3f80d163f1059b6f583f1e1a7a23b340750e..001dabf6c0284906d22ca1437a193aedcfd1372f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs @@ -1484,6 +1484,33 @@ class A Assert.Equal("ModuleAssemblyName", compilation.Assembly.Identity.Name); } + [WorkItem(8506, "https://github.com/dotnet/roslyn/issues/8506")] + [Fact] + public void CrossCorlibSystemObjectReturnType_Script() + { + // MinAsyncCorlibRef corlib is used since it provides just enough corlib type definitions + // and Task APIs necessary for script hosting are provided by MinAsyncRef. This ensures that + // `System.Object, mscorlib, Version=4.0.0.0` will not be provided (since it's unversioned). + // + // In the original bug, Xamarin iOS, Android, and Mac Mobile profile corlibs were + // realistic cross-compilation targets. + var compilation = CSharpCompilation.CreateScriptCompilation( + "submission-assembly", + references: new [] { MinAsyncCorlibRef }, + syntaxTree: Parse("true", options: TestOptions.Script) + ).VerifyDiagnostics(); + + Assert.True(compilation.IsSubmission); + + var taskOfT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); + var taskOfObject = taskOfT.Construct(compilation.ObjectType); + var entryPoint = compilation.GetEntryPoint(default(CancellationToken)); + + Assert.Same(compilation.ObjectType.ContainingAssembly, taskOfT.ContainingAssembly); + Assert.Same(compilation.ObjectType.ContainingAssembly, taskOfObject.ContainingAssembly); + Assert.Equal(taskOfObject, entryPoint.ReturnType); + } + [WorkItem(3719, "https://github.com/dotnet/roslyn/issues/3719")] [Fact] public void GetEntryPoint_Script() diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index e6e1e8bac0a9640e9a1d4a58110bd19f382244b5..154c14b85bef297ef3ed0f91fd6917dfd3169660 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -330,7 +330,7 @@ internal int GetSubmissionSlotIndex() /// /// The type object that represents the type of submission result the host requested. /// - internal Type SubmissionReturnType => ScriptCompilationInfo?.ReturnType; + internal Type SubmissionReturnType => ScriptCompilationInfo?.ReturnTypeOpt; internal static bool IsValidSubmissionReturnType(Type type) { diff --git a/src/Compilers/Core/Portable/Compilation/ScriptCompilationInfo.cs b/src/Compilers/Core/Portable/Compilation/ScriptCompilationInfo.cs index 927a52c7670829a661611a77eaa8f3d0f2eeb867..8f45663b1ec55df84e027902fda98af51945d7f2 100644 --- a/src/Compilers/Core/Portable/Compilation/ScriptCompilationInfo.cs +++ b/src/Compilers/Core/Portable/Compilation/ScriptCompilationInfo.cs @@ -6,12 +6,13 @@ namespace Microsoft.CodeAnalysis { public abstract class ScriptCompilationInfo { - public Type ReturnType { get; } + internal Type ReturnTypeOpt { get; } + public Type ReturnType => ReturnTypeOpt ?? typeof(object); public Type GlobalsType { get; } internal ScriptCompilationInfo(Type returnType, Type globalsType) { - ReturnType = returnType ?? typeof(object); + ReturnTypeOpt = returnType; GlobalsType = globalsType; } diff --git a/src/Compilers/Test/Resources/Core/CompilerTestResources.csproj b/src/Compilers/Test/Resources/Core/CompilerTestResources.csproj index 4bb2c2ab0bb96a1080740c7d143e42fe4561c5cf..de418166daa10084d5cf0f97fca3633b9d28dae7 100644 --- a/src/Compilers/Test/Resources/Core/CompilerTestResources.csproj +++ b/src/Compilers/Test/Resources/Core/CompilerTestResources.csproj @@ -136,6 +136,7 @@ + diff --git a/src/Compilers/Test/Resources/Core/NetFX/Minimal/build.cmd b/src/Compilers/Test/Resources/Core/NetFX/Minimal/build.cmd index ba14a626bc9eaa157c7626f82075898c79728880..c465afaf1dd816d13251730ef4e450e0b969e726 100644 --- a/src/Compilers/Test/Resources/Core/NetFX/Minimal/build.cmd +++ b/src/Compilers/Test/Resources/Core/NetFX/Minimal/build.cmd @@ -2,3 +2,4 @@ csc /target:library /nostdlib /noconfig /keyfile:Key.snk /out:mincorlib.dll mincorlib.cs csc /target:library /nostdlib /noconfig /keyfile:Key.snk /r:mincorlib.dll /out:minasync.dll minasync.cs +csc /target:library /nostdlib /noconfig /keyfile:Key.snk /out:minasynccorlib.dll mincorlib.cs minasync.cs diff --git a/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.cs b/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.cs index d31e1f78056f88d3b0b75fcff1aaefaa3b65db7d..fc97264291b88dbeada90b23d7a63827ff84a439 100644 --- a/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.cs +++ b/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.cs @@ -14,9 +14,9 @@ public class Task : IAsyncResult, IDisposable public Awaiter GetAwaiter() => null; } - public class Task : IAsyncResult, IDisposable + public class Task : Task, IAsyncResult, IDisposable { - public Awaiter GetAwaiter() => null; + public new Awaiter GetAwaiter() => null; } public class Awaiter : INotifyCompletion diff --git a/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.dll b/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.dll index f9e08aaab65303d142554546ea9d000b165702eb..979309bb0ef25bf7bffdeadb9113ca5915e6600d 100644 Binary files a/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.dll and b/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.dll differ diff --git a/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasynccorlib.dll b/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasynccorlib.dll new file mode 100644 index 0000000000000000000000000000000000000000..79bee6784a7d3c91b38a33dbb549c17a65aaa5e9 Binary files /dev/null and b/src/Compilers/Test/Resources/Core/NetFX/Minimal/minasynccorlib.dll differ diff --git a/src/Compilers/Test/Resources/Core/TestResources.cs b/src/Compilers/Test/Resources/Core/TestResources.cs index 3fc5d83bcc36f29ff2aa538f780ad3cf6a6efa51..13961b2741d78741c5535e304c3991633ca10b1a 100644 --- a/src/Compilers/Test/Resources/Core/TestResources.cs +++ b/src/Compilers/Test/Resources/Core/TestResources.cs @@ -165,6 +165,9 @@ public static class Minimal private static byte[] s_minasync; public static byte[] minasync => ResourceLoader.GetOrCreateResource(ref s_minasync, "NetFX.Minimal.minasync.dll"); + + private static byte [] s_minasynccorlib; + public static byte [] minasynccorlib => ResourceLoader.GetOrCreateResource(ref s_minasynccorlib, "NetFX.Minimal.minasynccorlib.dll"); } public static class ValueTuple diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedInteractiveInitializerMethod.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedInteractiveInitializerMethod.vb index 3f6aad78210ea80573b195361f763187915d6591..d9e88c538a8cbc69b0945d98a70fbd977c8edeaf 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedInteractiveInitializerMethod.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SynthesizedInteractiveInitializerMethod.vb @@ -149,16 +149,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ByRef resultType As TypeSymbol, ByRef returnType As TypeSymbol) - Dim submissionReturnType = If(compilation.SubmissionReturnType, GetType(Object)) + Dim submissionReturnType As Type = Nothing + If compilation.ScriptCompilationInfo IsNot Nothing Then + submissionReturnType = compilation.ScriptCompilationInfo.ReturnTypeOpt + End If + Dim taskT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T) Dim useSiteDiagnostic = taskT.GetUseSiteErrorInfo() If useSiteDiagnostic IsNot Nothing Then diagnostics.Add(useSiteDiagnostic, NoLocation.Singleton) End If - resultType = compilation.GetTypeByReflectionType(submissionReturnType, diagnostics) + ' If no explicit return type is set on ScriptCompilationInfo, default to + ' System.Object from the target corlib. This allows cross compiling scripts + ' to run on a target corlib that may differ from the host compiler's corlib. + ' cf. https://github.com/dotnet/roslyn/issues/8506 + If submissionReturnType Is Nothing Then + resultType = compilation.GetSpecialType(SpecialType.System_Object) + Else + resultType = compilation.GetTypeByReflectionType(submissionReturnType, diagnostics) + End If returnType = taskT.Construct(resultType) End Sub End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb index 93a83ce98969615b09233814004332ea499f7417..0355b7bb8a352329e8e373ea756e02caaf383192 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb @@ -1311,6 +1311,32 @@ End Class Assert.Equal("ModuleAssemblyName", c.Assembly.Identity.Name) End Sub + + + Public Sub CrossCorlibSystemObjectReturnType_Script() + ' MinAsyncCorlibRef corlib Is used since it provides just enough corlib type definitions + ' And Task APIs necessary for script hosting are provided by MinAsyncRef. This ensures that + ' `System.Object, mscorlib, Version=4.0.0.0` will Not be provided (since it's unversioned). + ' + ' In the original bug, Xamarin iOS, Android, And Mac Mobile profile corlibs were + ' realistic cross-compilation targets. + Dim compilation = VisualBasicCompilation.CreateScriptCompilation( + "submission-assembly", + references:={MinAsyncCorlibRef}, + syntaxTree:=Parse("? True", options:=TestOptions.Script) + ).VerifyDiagnostics() + + Assert.True(compilation.IsSubmission) + + Dim taskOfT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T) + Dim taskOfObject = taskOfT.Construct(compilation.ObjectType) + Dim entryPoint = compilation.GetEntryPoint(Nothing) + + Assert.Same(compilation.ObjectType.ContainingAssembly, taskOfT.ContainingAssembly) + Assert.Same(compilation.ObjectType.ContainingAssembly, taskOfObject.ContainingAssembly) + Assert.Equal(taskOfObject, entryPoint.ReturnType) + End Sub + Public Sub GetEntryPoint_Script() diff --git a/src/Test/Utilities/Shared/Mocks/TestReferences.cs b/src/Test/Utilities/Shared/Mocks/TestReferences.cs index 51436e8191f9948b91af2afe32c261f6701e28cc..09be1347e672ffb0b28c086efb035782e15150f5 100644 --- a/src/Test/Utilities/Shared/Mocks/TestReferences.cs +++ b/src/Test/Utilities/Shared/Mocks/TestReferences.cs @@ -170,6 +170,20 @@ public static PortableExecutableReference minasync return s_minasync; } } + + private static PortableExecutableReference s_minasynccorlib; + public static PortableExecutableReference minasynccorlib + { + get + { + if (s_minasynccorlib == null) + { + s_minasynccorlib = AssemblyMetadata.CreateFromImage(TestResources.NetFX.Minimal.minasynccorlib).GetReference(display: "minasynccorlib.dll"); + } + + return s_minasynccorlib; + } + } } public static class ValueTuple diff --git a/src/Test/Utilities/Shared/TestBase.cs b/src/Test/Utilities/Shared/TestBase.cs index 6f9375eef9a2ff412c411e976e6fc6c49da1cf88..445a43529b2fc75041ab2b64bc125895bd51957f 100644 --- a/src/Test/Utilities/Shared/TestBase.cs +++ b/src/Test/Utilities/Shared/TestBase.cs @@ -325,6 +325,8 @@ public static MetadataReference MscorlibRefSilverlight public static MetadataReference MinCorlibRef => TestReferences.NetFx.Minimal.mincorlib; + public static MetadataReference MinAsyncCorlibRef => TestReferences.NetFx.Minimal.minasynccorlib; + public static MetadataReference ValueTupleRef => TestReferences.NetFx.ValueTuple.tuplelib; private static MetadataReference s_msvbRef;