Skip to content

Commit

Permalink
Compilation: use System.Object from target corlib (#8507) (#11708)
Browse files Browse the repository at this point in the history
* Tests: fix minasync Task<T> to derive from Task

* Tests: provide MinAsyncCorlibRef

This combines the async features of minasync with mincorlib to produce
a minimum unversioned corlib with async stubs.

* Compilation: use System.Object from target corlib

When creating a script compilation without an explicit return type,
System.Object was being resolved via reflection from the host.

This resulted in an implicit dependency of a script compilation on the
host corlib, even if a different corlib was specified as a reference
for the compilation (e.g. Xamarin.iOS).

Fix this by using System.Object as defined in the corlib resovled
for the compilation.
  • Loading branch information
tmat committed Jun 2, 2016
1 parent 074ec72 commit 0d0d867
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,20 @@ private static void CalculateReturnType(
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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,33 @@ static void Main() { }
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()
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/Core/Portable/Compilation/Compilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ internal int GetSubmissionSlotIndex()
/// <summary>
/// The type object that represents the type of submission result the host requested.
/// </summary>
internal Type SubmissionReturnType => ScriptCompilationInfo?.ReturnType;
internal Type SubmissionReturnType => ScriptCompilationInfo?.ReturnTypeOpt;

internal static bool IsValidSubmissionReturnType(Type type)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
<Content Include="NetFX\Minimal\build.cmd" />
<Content Include="NetFX\Minimal\Key.snk" />
<Content Include="NetFX\Minimal\minasync.cs" />
<EmbeddedResource Include="NetFX\Minimal\minasynccorlib.dll" />
<Content Include="NetFX\Minimal\mincorlib.cs" />
<EmbeddedResource Include="SymbolsTests\Metadata\public-and-private.dll" />
<Content Include="SymbolsTests\NoPia\ParametersWithoutNames.cs" />
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/Test/Resources/Core/NetFX/Minimal/build.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class Task : IAsyncResult, IDisposable
public Awaiter GetAwaiter() => null;
}

public class Task<T> : IAsyncResult, IDisposable
public class Task<T> : Task, IAsyncResult, IDisposable
{
public Awaiter<T> GetAwaiter() => null;
public new Awaiter<T> GetAwaiter() => null;
}

public class Awaiter : INotifyCompletion
Expand Down
Binary file modified src/Compilers/Test/Resources/Core/NetFX/Minimal/minasync.dll
Binary file not shown.
Binary file not shown.
3 changes: 3 additions & 0 deletions src/Compilers/Test/Resources/Core/TestResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
End Namespace
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,32 @@ End Class
Assert.Equal("ModuleAssemblyName", c.Assembly.Identity.Name)
End Sub

<WorkItem(8506, "https://github.com/dotnet/roslyn/issues/8506")>
<Fact()>
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

<WorkItem(3719, "https://github.com/dotnet/roslyn/issues/3719")>
<Fact()>
Public Sub GetEntryPoint_Script()
Expand Down
14 changes: 14 additions & 0 deletions src/Test/Utilities/Shared/Mocks/TestReferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 silverlight_v5_0_5_0
Expand Down
2 changes: 2 additions & 0 deletions src/Test/Utilities/Shared/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ public static MetadataReference MscorlibRefSilverlight

public static MetadataReference MinCorlibRef => TestReferences.NetFx.Minimal.mincorlib;

public static MetadataReference MinAsyncCorlibRef => TestReferences.NetFx.Minimal.minasynccorlib;

private static MetadataReference s_msvbRef;
public static MetadataReference MsvbRef
{
Expand Down

0 comments on commit 0d0d867

Please sign in to comment.