Skip to content

Commit

Permalink
Merge pull request #46285 from gafter/covariant-returns-e2e1
Browse files Browse the repository at this point in the history
Check in simple end-to-end test for covariant returns on net5.0
  • Loading branch information
Neal Gafter authored Jul 28, 2020
2 parents 3801a96 + 01be338 commit f9959b5
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 4 deletions.
3 changes: 2 additions & 1 deletion eng/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,8 @@ function TestUsingOptimizedRunner() {
}

# Exclude out the multi-targetted netcore app projects
$dlls = $dlls | ?{ -not ($_.FullName -match ".*netcoreapp.*") }
$dlls = $dlls | ?{ -not ($_.FullName -match ".*netcoreapp3.*") }
$dlls = $dlls | ?{ -not ($_.FullName -match ".*net5.0.*") }

# Exclude out the ref assemblies
$dlls = $dlls | ?{ -not ($_.FullName -match ".*\\ref\\.*") }
Expand Down
4 changes: 2 additions & 2 deletions eng/targets/Imports.targets
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
Only generate our runtimeconfig.json files for net core apps. It's unnecessary in desktop projects
but gets included in lots of output items like VSIX.
-->
<GenerateRuntimeConfigurationFiles Condition="'$(TargetFramework)' != 'netcoreapp3.1'">false</GenerateRuntimeConfigurationFiles>
<GenerateRuntimeConfigurationFiles Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">false</GenerateRuntimeConfigurationFiles>

<!--
When building a .NET Core exe make sure to include the template runtimeconfig.json file
Expand All @@ -36,7 +36,7 @@
This condition will be evaluated multiple times in multi-targeted projects hence need to be careful
to only set in the inner builds, not the outer build where only $(TargetFrameworks) is defined.
-->
<DisableNullableWarnings Condition="'$(DisableNullableWarnings)' == '' AND $(TargetFrameworks.Contains('netcoreapp3.1')) AND '$(TargetFramework)' != '' AND '$(TargetFramework)' != 'netcoreapp3.1'">true</DisableNullableWarnings>
<DisableNullableWarnings Condition="'$(DisableNullableWarnings)' == '' AND '$(TargetFramework)' != '' AND '$(TargetFrameworkIdentifier)' != '.NETCoreApp'">true</DisableNullableWarnings>

<!--
Disable code style analyzers in "older" targets for a multi-targeted project. These analyzers don't
Expand Down
310 changes: 310 additions & 0 deletions src/Compilers/CSharp/Test/Emit/Emit/CovariantReturnTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
// 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.

#if NETCOREAPP

using System.Collections.Generic;
using System.Linq;
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 CovariantReturnTests : EmitMetadataTestBase
{
private static readonly MetadataReference CorelibraryWithCovariantReturnSupport;

static CovariantReturnTests()
{
if (new CovarantReturnRuntimeOnly().ShouldSkip)
return;

const string corLibraryCore = @"
namespace System
{
public class Array
{
public static T[] Empty<T>() => throw null;
}
public class Console
{
public static void WriteLine(string message) => throw null;
}
public class Attribute { }
[Flags]
public enum AttributeTargets
{
Assembly = 0x1,
Module = 0x2,
Class = 0x4,
Struct = 0x8,
Enum = 0x10,
Constructor = 0x20,
Method = 0x40,
Property = 0x80,
Field = 0x100,
Event = 0x200,
Interface = 0x400,
Parameter = 0x800,
Delegate = 0x1000,
ReturnValue = 0x2000,
GenericParameter = 0x4000,
All = 0x7FFF
}
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets validOn) { }
public bool AllowMultiple
{
get => throw null;
set { }
}
public bool Inherited
{
get => throw null;
set { }
}
public AttributeTargets ValidOn => throw null;
}
public struct Boolean { }
public struct Byte { }
public class Delegate
{
public static Delegate CreateDelegate(Type type, object firstArgument, Reflection.MethodInfo method) => null;
}
public abstract class Enum : IComparable { }
public class Exception
{
public Exception(string message) => throw null;
}
public class FlagsAttribute : Attribute { }
public delegate T Func<out T>();
public delegate U Func<in T, out U>(T arg);
public interface IComparable { }
public interface IDisposable
{
void Dispose();
}
public struct Int16 { }
public struct Int32 { }
public struct IntPtr { }
public class MulticastDelegate : Delegate { }
public struct Nullable<T> { }
public class Object
{
public virtual string ToString() => throw null;
public virtual int GetHashCode() => throw null;
public virtual bool Equals(object other) => throw null;
}
public sealed class ParamArrayAttribute : Attribute { }
public struct RuntimeMethodHandle { }
public struct RuntimeTypeHandle { }
public class String : IComparable {
public static String Empty = null;
public override string ToString() => throw null;
public static bool operator ==(string a, string b) => throw null;
public static bool operator !=(string a, string b) => throw null;
public override bool Equals(object other) => throw null;
public override int GetHashCode() => throw null;
}
public class Type
{
public Reflection.FieldInfo GetField(string name) => null;
public static Type GetType(string name) => null;
public static Type GetTypeFromHandle(RuntimeTypeHandle handle) => null;
}
public class ValueType { }
public struct Void { }
namespace Collections
{
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerator
{
object Current
{
get;
}
bool MoveNext();
void Reset();
}
}
namespace Collections.Generic
{
public interface IEnumerable<out T> : IEnumerable
{
new IEnumerator<T> GetEnumerator();
}
public interface IEnumerator<out T> : IEnumerator, IDisposable
{
new T Current
{
get;
}
}
}
namespace Linq.Expressions
{
public class Expression
{
public static ParameterExpression Parameter(Type type) => throw null;
public static ParameterExpression Parameter(Type type, string name) => throw null;
public static MethodCallExpression Call(Expression instance, Reflection.MethodInfo method, params Expression[] arguments) => throw null;
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters) => throw null;
public static MemberExpression Property(Expression expression, Reflection.MethodInfo propertyAccessor) => throw null;
public static ConstantExpression Constant(object value, Type type) => throw null;
public static UnaryExpression Convert(Expression expression, Type type) => throw null;
}
public class ParameterExpression : Expression { }
public class MethodCallExpression : Expression { }
public abstract class LambdaExpression : Expression { }
public class Expression<T> : LambdaExpression { }
public class MemberExpression : Expression { }
public class ConstantExpression : Expression { }
public sealed class UnaryExpression : Expression { }
}
namespace Reflection
{
public class AssemblyVersionAttribute : Attribute
{
public AssemblyVersionAttribute(string version) { }
}
public class DefaultMemberAttribute : Attribute
{
public DefaultMemberAttribute(string name) { }
}
public abstract class MemberInfo { }
public abstract class MethodBase : MemberInfo
{
public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle) => throw null;
}
public abstract class MethodInfo : MethodBase
{
public virtual Delegate CreateDelegate(Type delegateType, object target) => throw null;
}
public abstract class FieldInfo : MemberInfo
{
public abstract object GetValue(object obj);
}
}
namespace Runtime.CompilerServices
{
public static class RuntimeHelpers
{
public static object GetObjectValue(object obj) => null;
}
}
}
";
const string corlibWithCovariantSupport = corLibraryCore + @"
namespace System.Runtime.CompilerServices
{
public static class RuntimeFeature
{
public const string CovariantReturnsOfClasses = nameof(CovariantReturnsOfClasses);
public const string DefaultImplementationsOfInterfaces = nameof(DefaultImplementationsOfInterfaces);
}
public sealed class PreserveBaseOverridesAttribute : Attribute { }
}
";
var compilation = CreateEmptyCompilation(new string[] {
corlibWithCovariantSupport,
@"[assembly: System.Reflection.AssemblyVersion(""4.0.0.0"")]"
}, assemblyName: "mscorlib");
compilation.VerifyDiagnostics();
CorelibraryWithCovariantReturnSupport = compilation.EmitToImageReference(options: new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "v5.1"));
}

private static CSharpCompilation CreateCovariantCompilation(
string source,
CSharpCompilationOptions options = null,
IEnumerable<MetadataReference> references = null)
{
Assert.NotNull(CorelibraryWithCovariantReturnSupport);
references = (references == null) ?
new[] { CorelibraryWithCovariantReturnSupport } :
references.ToArray().Prepend(CorelibraryWithCovariantReturnSupport);
return CreateEmptyCompilation(
source,
options: options,
parseOptions: TestOptions.WithCovariantReturns,
references: references);
}

[ConditionalFact(typeof(CovarantReturnRuntimeOnly))]
public void SimpleCovariantReturnEndToEndTest()
{
var source = @"
using System;
class Base
{
public virtual object M() => ""Base.M"";
}
class Derived : Base
{
public override string M() => ""Derived.M"";
}
class Program
{
static void Main()
{
Derived d = new Derived();
Base b = d;
string s = d.M();
object o = b.M();
Console.WriteLine(s.ToString());
Console.WriteLine(o.ToString());
}
}
";
var compilation = CreateCovariantCompilation(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics();
var expectedOutput =
@"Derived.M
Derived.M";
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.Skipped);
}

[ConditionalFact(typeof(CovarantReturnRuntimeOnly))]
public void CovariantRuntimeHasRequiredMembers()
{
var source = @"
using System;
class Base
{
public virtual object M() => ""Base.M"";
}
class Derived : Base
{
public override string M() => ""Derived.M"";
}
class Program
{
static void Main()
{
var value = (string)Type.GetType(""System.Runtime.CompilerServices.RuntimeFeature"").GetField(""CovariantReturnsOfClasses"").GetValue(null);
if (value != ""CovariantReturnsOfClasses"")
throw new Exception(value.ToString());
var attr = Type.GetType(""System.Runtime.CompilerServices.PreserveBaseOverridesAttribute"");
if (attr == null)
throw new Exception(""missing System.Runtime.CompilerServices.PreserveBaseOverridesAttribute"");
}
}
";
var compilation = CreateCovariantCompilation(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics();
var expectedOutput = @"";
CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.Skipped);
}
}
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<RootNamespace>Microsoft.CodeAnalysis.CSharp.UnitTests</RootNamespace>
<TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks>
<TargetFrameworks>net5.0;net472</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup Label="Project References">
Expand Down
13 changes: 13 additions & 0 deletions src/Test/Utilities/Portable/Assert/ConditionalFactAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@ public class WindowsDesktopOnly : ExecutionCondition
public override string SkipReason => "Test only supported on Windows desktop";
}

public class CovarantReturnRuntimeOnly : ExecutionCondition
{
public override bool ShouldSkip
{
get
{
// See if the runtime supports covariant returns.
return Type.GetType("System.Runtime.CompilerServices.RuntimeFeature")?.GetField("CovariantReturnsOfClasses") == null;
}
}
public override string SkipReason => "Test only supported on runtimes that support covariant returns";
}

public class UnixLikeOnly : ExecutionCondition
{
public override bool ShouldSkip => !PathUtilities.IsUnixLikePlatform;
Expand Down
1 change: 1 addition & 0 deletions src/Tools/BuildBoss/ProjectCheckerUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ private bool CheckTargetFrameworks(TextWriter textWriter)
case "net20":
case "net472":
case "netcoreapp3.1":
case "net5.0":
continue;
}

Expand Down

0 comments on commit f9959b5

Please sign in to comment.