|
// 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.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
{
public class GenericConstraintConversionTests : CSharpTestBase
{
/// <summary>
/// 6.1.10, bullet 1
/// </summary>
[Fact]
public void ImplicitInterfaceAndBaseTypeConversions01()
{
var source =
@"interface I { }
interface IA : I { }
interface IB : I { }
class A : IA { }
class B : A, IB { }
class C<T>
where T : B
{
static I i;
static IA ia;
static IB ib;
static A a;
static B b;
static void M<U, V>(T t, U u, V v)
where U : struct, IA
where V : class, IA
{
i = t;
i = u;
i = v;
ia = t;
ia = u;
ia = v;
ib = t;
ib = u;
ib = v;
a = t;
a = u;
b = t;
b = u;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (25,14): error CS0266: Cannot implicitly convert type 'U' to 'IB'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "u").WithArguments("U", "IB").WithLocation(25, 14),
// (26,14): error CS0266: Cannot implicitly convert type 'V' to 'IB'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "v").WithArguments("V", "IB").WithLocation(26, 14),
// (28,13): error CS0029: Cannot implicitly convert type 'U' to 'A'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "u").WithArguments("U", "A").WithLocation(28, 13),
// (30,13): error CS0029: Cannot implicitly convert type 'U' to 'B'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "u").WithArguments("U", "B").WithLocation(30, 13));
}
[Fact]
public void ImplicitInterfaceAndBaseTypeConversions02()
{
var source =
@"interface IA { }
interface IB { }
class A : IA { }
class B : A, IB { }
class C<T, U>
where T : A
where U : B, T
{
static IA ia;
static IB ib;
static void M<V>(T t, U u, V v)
where V : B, T
{
ia = t;
ia = u;
ia = v;
ib = t;
ib = u;
ib = v;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (17,14): error CS0266: Cannot implicitly convert type 'T' to 'IB'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "IB").WithLocation(17, 14));
}
/// <summary>
/// 6.1.10, bullet 2
/// </summary>
[Fact]
public void ImplicitConversionEffectiveInterfaceSet()
{
var source =
@"interface IA { }
interface IB { }
class A : IA { }
class B : IB { }
class C<T, U, V>
where T : A
where U : IB
where V : B, IA
{
static IA a;
static IB b;
static void M(T t, U u, V v)
{
a = t;
a = u;
b = t;
b = u;
}
static void M1<X>(X x) where X : T
{
a = x;
b = x;
}
static void M2<X>(X x) where X : U
{
a = x;
b = x;
}
static void M3<X>(X x) where X : T, U
{
a = x;
b = x;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (15,13): error CS0266: Cannot implicitly convert type 'U' to 'IA'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "u").WithArguments("U", "IA").WithLocation(15, 13),
// (16,13): error CS0266: Cannot implicitly convert type 'T' to 'IB'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "IB").WithLocation(16, 13),
// (22,13): error CS0266: Cannot implicitly convert type 'X' to 'IB'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("X", "IB").WithLocation(22, 13),
// (26,13): error CS0266: Cannot implicitly convert type 'X' to 'IA'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("X", "IA").WithLocation(26, 13));
}
/// <summary>
/// 6.1.10, bullet 3
/// </summary>
[Fact]
public void ImplicitConversionToTypeParameter()
{
var source =
@"class C<T, U, V, W>
where T : U, V
where U : W
{
static T t;
static U u;
static V v;
static W w;
static void M()
{
t = u;
t = v;
t = w;
u = t;
u = v;
u = w;
v = t;
v = u;
v = w;
w = t;
w = u;
w = v;
}
static void M1<X>(X x) where X : T
{
t = x;
u = x;
v = x;
w = x;
x = t;
x = u;
x = v;
x = w;
}
static void M2<X>(X x) where X : U
{
t = x;
u = x;
v = x;
w = x;
x = t;
x = u;
x = v;
x = w;
}
static void M3<X>(X x) where X : U, V, W
{
t = x;
u = x;
v = x;
w = x;
x = t;
x = u;
x = v;
x = w;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (11,13): error CS0266: Cannot implicitly convert type 'U' to 'T'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "u").WithArguments("U", "T").WithLocation(11, 13),
// (12,13): error CS0266: Cannot implicitly convert type 'V' to 'T'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "v").WithArguments("V", "T").WithLocation(12, 13),
// (13,13): error CS0266: Cannot implicitly convert type 'W' to 'T'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "w").WithArguments("W", "T").WithLocation(13, 13),
// (15,13): error CS0029: Cannot implicitly convert type 'V' to 'U'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "v").WithArguments("V", "U").WithLocation(15, 13),
// (16,13): error CS0266: Cannot implicitly convert type 'W' to 'U'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "w").WithArguments("W", "U").WithLocation(16, 13),
// (18,13): error CS0029: Cannot implicitly convert type 'U' to 'V'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "u").WithArguments("U", "V").WithLocation(18, 13),
// (19,13): error CS0029: Cannot implicitly convert type 'W' to 'V'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "w").WithArguments("W", "V").WithLocation(19, 13),
// (22,13): error CS0029: Cannot implicitly convert type 'V' to 'W'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "v").WithArguments("V", "W").WithLocation(22, 13),
// (30,13): error CS0266: Cannot implicitly convert type 'T' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "X").WithLocation(30, 13),
// (31,13): error CS0266: Cannot implicitly convert type 'U' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "u").WithArguments("U", "X").WithLocation(31, 13),
// (32,13): error CS0266: Cannot implicitly convert type 'V' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "v").WithArguments("V", "X").WithLocation(32, 13),
// (33,13): error CS0266: Cannot implicitly convert type 'W' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "w").WithArguments("W", "X").WithLocation(33, 13),
// (37,13): error CS0029: Cannot implicitly convert type 'X' to 'T'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("X", "T").WithLocation(37, 13),
// (39,13): error CS0029: Cannot implicitly convert type 'X' to 'V'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("X", "V").WithLocation(39, 13),
// (41,13): error CS0029: Cannot implicitly convert type 'T' to 'X'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "t").WithArguments("T", "X").WithLocation(41, 13),
// (42,13): error CS0266: Cannot implicitly convert type 'U' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "u").WithArguments("U", "X").WithLocation(42, 13),
// (43,13): error CS0029: Cannot implicitly convert type 'V' to 'X'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "v").WithArguments("V", "X").WithLocation(43, 13),
// (44,13): error CS0266: Cannot implicitly convert type 'W' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "w").WithArguments("W", "X").WithLocation(44, 13),
// (48,13): error CS0029: Cannot implicitly convert type 'X' to 'T'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("X", "T").WithLocation(48, 13),
// (52,13): error CS0029: Cannot implicitly convert type 'T' to 'X'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "t").WithArguments("T", "X").WithLocation(52, 13),
// (53,13): error CS0266: Cannot implicitly convert type 'U' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "u").WithArguments("U", "X").WithLocation(53, 13),
// (54,13): error CS0266: Cannot implicitly convert type 'V' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "v").WithArguments("V", "X").WithLocation(54, 13),
// (55,13): error CS0266: Cannot implicitly convert type 'W' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "w").WithArguments("W", "X").WithLocation(55, 13));
}
/// <summary>
/// 6.1.10, bullet 4
/// </summary>
[Fact]
public void ImplicitConversionFromNull()
{
var source =
@"interface I { }
class A { }
class B<T1, T2, T3, T4, T5, T6>
where T2 : class
where T3 : struct
where T4 : new()
where T5: I
where T6: A
{
static T1 F1 = null;
static T2 F2 = null;
static T3 F3 = null;
static T4 F4 = null;
static T5 F5 = null;
static T6 F6 = null;
}";
CreateCompilation(source).VerifyDiagnostics(
// (10,20): error CS0403: Cannot convert null to type parameter 'T1' because it could be a non-nullable value type. Consider using 'default(T1)' instead.
// static T1 F1 = null;
Diagnostic(ErrorCode.ERR_TypeVarCantBeNull, "null").WithArguments("T1"),
// (12,20): error CS0403: Cannot convert null to type parameter 'T3' because it could be a non-nullable value type. Consider using 'default(T3)' instead.
// static T3 F3 = null;
Diagnostic(ErrorCode.ERR_TypeVarCantBeNull, "null").WithArguments("T3"),
// (13,20): error CS0403: Cannot convert null to type parameter 'T4' because it could be a non-nullable value type. Consider using 'default(T4)' instead.
// static T4 F4 = null;
Diagnostic(ErrorCode.ERR_TypeVarCantBeNull, "null").WithArguments("T4"),
// (14,20): error CS0403: Cannot convert null to type parameter 'T5' because it could be a non-nullable value type. Consider using 'default(T5)' instead.
// static T5 F5 = null;
Diagnostic(ErrorCode.ERR_TypeVarCantBeNull, "null").WithArguments("T5"),
// (11,15): warning CS0414: The field 'B<T1, T2, T3, T4, T5, T6>.F2' is assigned but its value is never used
// static T2 F2 = null;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "F2").WithArguments("B<T1, T2, T3, T4, T5, T6>.F2"),
// (15,15): warning CS0414: The field 'B<T1, T2, T3, T4, T5, T6>.F6' is assigned but its value is never used
// static T6 F6 = null;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "F6").WithArguments("B<T1, T2, T3, T4, T5, T6>.F6")
);
}
/// <summary>
/// 6.1.10, bullet 5
/// </summary>
[Fact]
public void ImplicitReferenceConversionToInterface()
{
var source =
@"interface IA { }
interface IB : IA { }
class A : IA { }
class B : A, IB { }
class C<T, U>
where T : A
where U : B
{
static void M(T t, U u)
{
IA a;
IB b;
a = t;
a = u;
b = t;
b = u;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (15,13): error CS0266: Cannot implicitly convert type 'T' to 'IB'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "IB").WithLocation(15, 13));
}
/// <summary>
/// 6.1.10, bullet 6
/// </summary>
[Fact]
public void ImplicitInterfaceVarianceConversions01()
{
var source =
@"interface IIn<in T> { }
interface IOut<out T> { }
interface IInDerived<T> : IIn<T> { }
interface IOutDerived<T> : IOut<T> { }
class CIn<T> : IIn<T> { }
class COut<T> : IOut<T> { }
class C<T, U>
where T : class
where U : class, T
{
static IIn<T> it;
static IOut<T> ot;
static IIn<U> iu;
static IOut<U> ou;
static void M1<X, Y>(X x, Y y)
where X : IIn<T>
where Y : IIn<U>
{
it = x;
it = y;
iu = x;
iu = y;
}
static void M2<X, Y>(X x, Y y)
where X : IOut<T>
where Y : IOut<U>
{
ot = x;
ot = y;
ou = x;
ou = y;
}
static void M3<X, Y>(X x, Y y)
where X : IInDerived<T>
where Y : IInDerived<U>
{
it = x;
it = y;
iu = x;
iu = y;
}
static void M4<X, Y>(X x, Y y)
where X : IOutDerived<T>
where Y : IOutDerived<U>
{
ot = x;
ot = y;
ou = x;
ou = y;
}
static void M5<X, Y>(X x, Y y)
where X : CIn<T>
where Y : CIn<U>
{
it = x;
it = y;
iu = x;
iu = y;
}
static void M6<X, Y>(X x, Y y)
where X : COut<T>
where Y : COut<U>
{
ot = x;
ot = y;
ou = x;
ou = y;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (20,14): error CS0266: Cannot implicitly convert type 'Y' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "y").WithArguments("Y", "IIn<T>").WithLocation(20, 14),
// (30,14): error CS0266: Cannot implicitly convert type 'X' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("X", "IOut<U>").WithLocation(30, 14),
// (38,14): error CS0266: Cannot implicitly convert type 'Y' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "y").WithArguments("Y", "IIn<T>").WithLocation(38, 14),
// (48,14): error CS0266: Cannot implicitly convert type 'X' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("X", "IOut<U>").WithLocation(48, 14),
// (56,14): error CS0266: Cannot implicitly convert type 'Y' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "y").WithArguments("Y", "IIn<T>").WithLocation(56, 14),
// (66,14): error CS0266: Cannot implicitly convert type 'X' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("X", "IOut<U>").WithLocation(66, 14));
}
[Fact]
public void ImplicitInterfaceVarianceConversions02()
{
var source =
@"interface I<T> { }
interface IIn<in T> { }
interface IOut<out T> { }
class A<T, U>
where U : T
{
static void M(I<T> it, I<U> iu)
{
it = iu;
iu = it;
}
static void M(IIn<T> it, IIn<U> iu)
{
it = iu;
iu = it;
}
static void M(IOut<T> it, IOut<U> iu)
{
it = iu;
iu = it;
}
}
class B<T, U>
where T : class
where U : T
{
static void M(I<T> it, I<U> iu)
{
it = iu;
iu = it;
}
static void M(IIn<T> it, IIn<U> iu)
{
it = iu;
iu = it;
}
static void M(IOut<T> it, IOut<U> iu)
{
it = iu;
iu = it;
}
}
class C<T, U>
where T : class
where U : class, T
{
static void M(I<T> it, I<U> iu)
{
it = iu;
iu = it;
}
static void M(IIn<T> it, IIn<U> iu)
{
it = iu;
iu = it; // valid
}
static void M(IOut<T> it, IOut<U> iu)
{
it = iu; // valid
iu = it;
}
}
class D<T, U>
where U : struct, T
{
static void M(I<T> it, I<U> iu)
{
it = iu;
iu = it;
}
static void M(IIn<T> it, IIn<U> iu)
{
it = iu;
iu = it;
}
static void M(IOut<T> it, IOut<U> iu)
{
it = iu;
iu = it;
}
}
class E<T, U>
where T : class
where U : struct, T
{
static void M(I<T> it, I<U> iu)
{
it = iu;
iu = it;
}
static void M(IIn<T> it, IIn<U> iu)
{
it = iu;
iu = it;
}
static void M(IOut<T> it, IOut<U> iu)
{
it = iu;
iu = it;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (9,14): error CS0266: Cannot implicitly convert type 'I<U>' to 'I<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("I<U>", "I<T>").WithLocation(9, 14),
// (10,14): error CS0266: Cannot implicitly convert type 'I<T>' to 'I<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("I<T>", "I<U>").WithLocation(10, 14),
// (14,14): error CS0266: Cannot implicitly convert type 'IIn<U>' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IIn<U>", "IIn<T>").WithLocation(14, 14),
// (15,14): error CS0266: Cannot implicitly convert type 'IIn<T>' to 'IIn<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IIn<T>", "IIn<U>").WithLocation(15, 14),
// (19,14): error CS0266: Cannot implicitly convert type 'IOut<U>' to 'IOut<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IOut<U>", "IOut<T>").WithLocation(19, 14),
// (20,14): error CS0266: Cannot implicitly convert type 'IOut<T>' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IOut<T>", "IOut<U>").WithLocation(20, 14),
// (29,14): error CS0266: Cannot implicitly convert type 'I<U>' to 'I<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("I<U>", "I<T>").WithLocation(29, 14),
// (30,14): error CS0266: Cannot implicitly convert type 'I<T>' to 'I<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("I<T>", "I<U>").WithLocation(30, 14),
// (34,14): error CS0266: Cannot implicitly convert type 'IIn<U>' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IIn<U>", "IIn<T>").WithLocation(34, 14),
// (35,14): error CS0266: Cannot implicitly convert type 'IIn<T>' to 'IIn<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IIn<T>", "IIn<U>").WithLocation(35, 14),
// (39,14): error CS0266: Cannot implicitly convert type 'IOut<U>' to 'IOut<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IOut<U>", "IOut<T>").WithLocation(39, 14),
// (40,14): error CS0266: Cannot implicitly convert type 'IOut<T>' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IOut<T>", "IOut<U>").WithLocation(40, 14),
// (49,14): error CS0266: Cannot implicitly convert type 'I<U>' to 'I<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("I<U>", "I<T>").WithLocation(49, 14),
// (50,14): error CS0266: Cannot implicitly convert type 'I<T>' to 'I<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("I<T>", "I<U>").WithLocation(50, 14),
// (54,14): error CS0266: Cannot implicitly convert type 'IIn<U>' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IIn<U>", "IIn<T>").WithLocation(54, 14),
// (60,14): error CS0266: Cannot implicitly convert type 'IOut<T>' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IOut<T>", "IOut<U>").WithLocation(60, 14),
// (68,14): error CS0266: Cannot implicitly convert type 'I<U>' to 'I<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("I<U>", "I<T>").WithLocation(68, 14),
// (69,14): error CS0266: Cannot implicitly convert type 'I<T>' to 'I<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("I<T>", "I<U>").WithLocation(69, 14),
// (73,14): error CS0266: Cannot implicitly convert type 'IIn<U>' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IIn<U>", "IIn<T>").WithLocation(73, 14),
// (74,14): error CS0266: Cannot implicitly convert type 'IIn<T>' to 'IIn<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IIn<T>", "IIn<U>").WithLocation(74, 14),
// (78,14): error CS0266: Cannot implicitly convert type 'IOut<U>' to 'IOut<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IOut<U>", "IOut<T>").WithLocation(78, 14),
// (79,14): error CS0266: Cannot implicitly convert type 'IOut<T>' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IOut<T>", "IOut<U>").WithLocation(79, 14),
// (88,14): error CS0266: Cannot implicitly convert type 'I<U>' to 'I<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("I<U>", "I<T>").WithLocation(88, 14),
// (89,14): error CS0266: Cannot implicitly convert type 'I<T>' to 'I<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("I<T>", "I<U>").WithLocation(89, 14),
// (93,14): error CS0266: Cannot implicitly convert type 'IIn<U>' to 'IIn<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IIn<U>", "IIn<T>").WithLocation(93, 14),
// (94,14): error CS0266: Cannot implicitly convert type 'IIn<T>' to 'IIn<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IIn<T>", "IIn<U>").WithLocation(94, 14),
// (98,14): error CS0266: Cannot implicitly convert type 'IOut<U>' to 'IOut<T>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "iu").WithArguments("IOut<U>", "IOut<T>").WithLocation(98, 14),
// (99,14): error CS0266: Cannot implicitly convert type 'IOut<T>' to 'IOut<U>'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "it").WithArguments("IOut<T>", "IOut<U>").WithLocation(99, 14));
}
[Fact]
public void ImplicitReferenceConversions()
{
var source =
@"class C<T, U>
where T : U
where U : class
{
static void M<X>(X x, U u) where X : class, T
{
u = x;
x = u;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (8,13): error CS0266: Cannot implicitly convert type 'U' to 'X'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "u").WithArguments("U", "X").WithLocation(8, 13));
}
[Fact]
public void ImplicitBoxingConversions()
{
var source =
@"class C<T, U>
where T : class
where U : T
{
static void M<X, Y>(Y y, T t)
where X : U
where Y : struct, X
{
t = y;
y = t;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (10,13): error CS0266: Cannot implicitly convert type 'T' to 'Y'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "Y").WithLocation(10, 13));
}
[Fact]
public void ImplicitInterfaceConversionsCircularConstraint()
{
var source =
@"interface I { }
class C<T, U>
where T : T
where U : U, I
{
static void M<V>(T t, U u, V v)
where V : U
{
I i;
i = t;
i = u;
i = v;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (2,9): error CS0454: Circular constraint dependency involving 'T' and 'T'
Diagnostic(ErrorCode.ERR_CircularConstraint, "T").WithArguments("T", "T").WithLocation(2, 9),
// (2,12): error CS0454: Circular constraint dependency involving 'U' and 'U'
Diagnostic(ErrorCode.ERR_CircularConstraint, "U").WithArguments("U", "U").WithLocation(2, 12),
// (10,13): error CS0266: Cannot implicitly convert type 'T' to 'I'. An explicit conversion exists (are you missing a cast?)
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "I").WithLocation(10, 13));
}
/// <summary>
/// 6.2.7, bullet 1
/// </summary>
[Fact]
public void ExplicitBaseClassConversions()
{
var source =
@"class A { }
class B1<T> : A { }
class C<T> : B1<T> { }
class B2 : A { }
class D<T>
where T : C<object>
{
static void M<U>(object o, A a, B1<T> b1t, B1<object> b1o, B2 b2)
where U : C<T>
{
T t;
t = (T)o;
t = (T)a;
t = (T)b1t;
t = (T)b1o;
t = (T)b2;
U u;
u = (U)o;
u = (U)a;
u = (U)b1t;
u = (U)b1o;
u = (U)b2;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (14,13): error CS0030: Cannot convert type 'B1<T>' to 'T'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(T)b1t").WithArguments("B1<T>", "T").WithLocation(14, 13),
// (16,13): error CS0030: Cannot convert type 'B2' to 'T'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(T)b2").WithArguments("B2", "T").WithLocation(16, 13),
// (21,13): error CS0030: Cannot convert type 'B1<object>' to 'U'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(U)b1o").WithArguments("B1<object>", "U").WithLocation(21, 13),
// (22,13): error CS0030: Cannot convert type 'B2' to 'U'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(U)b2").WithArguments("B2", "U").WithLocation(22, 13));
}
/// <summary>
/// 6.2.7, bullet 2
/// </summary>
[Fact]
public void ExplicitConversionFromInterface()
{
var source =
@"interface IA { }
interface IB : IA { }
interface IC<T> { }
class A<T>
where T : IA
{
static void M<U>(IA a, IB b, IC<object> co, IC<T> ct)
where U : IC<T>
{
T t;
t = (T)a;
t = (T)b;
t = (T)co;
t = (T)ct;
U u;
u = (U)a;
u = (U)b;
u = (U)co;
u = (U)ct;
}
}";
CreateCompilation(source).VerifyDiagnostics();
}
/// <summary>
/// 6.2.7, bullet 3
/// </summary>
[Fact]
public void ExplicitConversionToInterface()
{
var source =
@"interface IA { }
interface IB : IA { }
interface IC<T> { }
class A<T>
where T : IA
{
static void M<U>(T t, U u)
where U : IC<T>
{
IA a;
IB b;
IC<object> co;
IC<T> ct;
b = (IB)t;
co = (IC<object>)t;
ct = (IC<T>)t;
a = (IA)u;
b = (IB)u;
co = (IC<object>)u;
ct = (IC<T>)u;
}
}";
CreateCompilation(source).VerifyDiagnostics();
}
/// <summary>
/// 6.2.7, bullet 4
/// </summary>
[Fact]
public void ExplicitConversionToTypeParameter()
{
var source =
@"class C<T, U, V, W>
where T : U, V, W
where U : V, W
{
static T t;
static U u;
static V v;
static W w;
static void M()
{
t = (T)u;
t = (T)v;
t = (T)w;
u = (U)v;
u = (U)w;
v = (V)w;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (16,13): error CS0030: Cannot convert type 'W' to 'V'
// v = (V)w;
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(V)w").WithArguments("W", "V"),
// (8,14): warning CS0649: Field 'C<T, U, V, W>.w' is never assigned to, and will always have its default value
// static W w;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "w").WithArguments("C<T, U, V, W>.w", "")
);
}
[Fact]
public void NoConversionsToValueType()
{
var source =
@"abstract class A<T>
{
internal abstract void M<U>(T t, U u) where U : T;
}
class B : A<int>
{
internal override void M<U>(int t, U u)
{
u = t;
u = (U)t;
t = u;
t = (int)u;
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (9,13): error CS0029: Cannot implicitly convert type 'int' to 'U'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "t").WithArguments("int", "U").WithLocation(9, 13),
// (10,13): error CS0030: Cannot convert type 'int' to 'U'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(U)t").WithArguments("int", "U").WithLocation(10, 13),
// (11,13): error CS0029: Cannot implicitly convert type 'U' to 'int'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "u").WithArguments("U", "int").WithLocation(11, 13),
// (12,13): error CS0030: Cannot convert type 'U' to 'int'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int)u").WithArguments("U", "int").WithLocation(12, 13));
}
/// <summary>
/// 6.1.10
/// </summary>
[ClrOnlyFact]
public void EmitImplicitConversions()
{
var source =
@"interface I { }
interface I<in T> { }
class A { }
class B : A { }
class C<T1, T2, T3, T4, T5, T6>
where T2 : I
where T3 : T4
where T5 : B
where T6 : I<A>
{
static void F1(object o) { }
static void F2(I i) { }
static void F3(T4 t) { }
static void F5(A a) { }
static void F6(I<B> b) { }
static void M(T1 a, T2 b, T3 c, T5 d, T6 e)
{
// 6.1.10 bullet 1: conversion to base type.
F1(a);
// 6.1.10 bullet 2: conversion to interface.
F2(b);
// 6.1.10 bullet 3: conversion to type parameter.
F3(c);
// 6.1.10 bullet 4: conversion from null to reference type.
// ... no test
// 6.1.10 bullet 5: conversion to reference type.
F5(d);
// 6.1.10 bullet 6: conversion to variance-convertible interface.
F6(e);
}
}";
var compilation = CompileAndVerify(source);
compilation.VerifyIL("C<T1, T2, T3, T4, T5, T6>.M(T1, T2, T3, T5, T6)",
@"{
// Code size 62 (0x3e)
.maxstack 1
IL_0000: ldarg.0
IL_0001: box ""T1""
IL_0006: call ""void C<T1, T2, T3, T4, T5, T6>.F1(object)""
IL_000b: ldarg.1
IL_000c: box ""T2""
IL_0011: call ""void C<T1, T2, T3, T4, T5, T6>.F2(I)""
IL_0016: ldarg.2
IL_0017: box ""T3""
IL_001c: unbox.any ""T4""
IL_0021: call ""void C<T1, T2, T3, T4, T5, T6>.F3(T4)""
IL_0026: ldarg.3
IL_0027: box ""T5""
IL_002c: call ""void C<T1, T2, T3, T4, T5, T6>.F5(A)""
IL_0031: ldarg.s V_4
IL_0033: box ""T6""
IL_0038: call ""void C<T1, T2, T3, T4, T5, T6>.F6(I<B>)""
IL_003d: ret
}");
}
/// <summary>
/// 6.2.7
/// </summary>
[ClrOnlyFact]
public void EmitExplicitConversions()
{
var source =
@"interface I { }
class C<T1, T2, T3, T4, T5>
where T2 : I
where T5 : T4
{
static void F1(T1 t) { }
static void F2(T2 t) { }
static void F3(I i) { }
static void F5(T5 t) { }
static void M(object a, I b, T3 c, T4 d)
{
// 6.2.7 bullet 1: conversion from base class to type parameter.
F1((T1)a);
// 6.2.7 bullet 2: conversion from interface to type parameter.
F2((T2)b);
// 6.2.7 bullet 3: conversion from type parameter to interface
// not in interface set.
F3((I)c);
// 6.2.7 bullet 4: conversion from type parameter to type parameter.
F5((T5)d);
}
}";
var compilation = CompileAndVerify(source);
compilation.VerifyIL("C<T1, T2, T3, T4, T5>.M(object, I, T3, T4)",
@"{
// Code size 55 (0x37)
.maxstack 1
IL_0000: ldarg.0
IL_0001: unbox.any ""T1""
IL_0006: call ""void C<T1, T2, T3, T4, T5>.F1(T1)""
IL_000b: ldarg.1
IL_000c: unbox.any ""T2""
IL_0011: call ""void C<T1, T2, T3, T4, T5>.F2(T2)""
IL_0016: ldarg.2
IL_0017: box ""T3""
IL_001c: castclass ""I""
IL_0021: call ""void C<T1, T2, T3, T4, T5>.F3(I)""
IL_0026: ldarg.3
IL_0027: box ""T4""
IL_002c: unbox.any ""T5""
IL_0031: call ""void C<T1, T2, T3, T4, T5>.F5(T5)""
IL_0036: ret
}");
}
[Fact]
public void ImplicitUserDefinedConversion()
{
var source =
@"class C0 { }
class C1
{
public static implicit operator C0(C1 o) { return null; }
}
class C2 { }
class C3<T>
{
public static implicit operator T(C3<T> t) { return default(T); }
}
class C4<T> { }
class C
{
// Implicit conversion from type parameter (success).
static C0 F1<T>(T t) where T : C1 { return t; }
// Implicit conversion from type parameter (error).
static C0 F2<T>(T t) where T : C2 { return t; }
// Implicit conversion to type parameter (success).
static T F3<T>(C3<T> c) { return c; }
// Implicit conversion to type parameter (error).
static T F4<T>(C4<T> c) { return c; }
}";
CreateCompilation(source).VerifyDiagnostics(
// (17,48): error CS0029: Cannot implicitly convert type 'T' to 'C0'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "t").WithArguments("T", "C0").WithLocation(17, 48),
// (21,38): error CS0029: Cannot implicitly convert type 'C4<T>' to 'T'
Diagnostic(ErrorCode.ERR_NoImplicitConv, "c").WithArguments("C4<T>", "T").WithLocation(21, 38));
}
[Fact]
public void ExplicitUserDefinedConversion()
{
var source =
@"class C0 { }
class C1
{
public static explicit operator C0(C1 o) { return null; }
}
class C2 { }
class C3<T>
{
public static explicit operator T(C3<T> t) { return default(T); }
}
class C4<T> { }
class C
{
// Explicit conversion from type parameter (success).
static C0 F1<T>(T t) where T : C1 { return (C0)t; }
// Explicit conversion from type parameter (error).
static C0 F2<T>(T t) where T : C2 { return (C0)t; }
// Explicit conversion to type parameter (success).
static T F3<T>(C3<T> c) { return (T)c; }
// Explicit conversion to type parameter (error).
static T F4<T>(C4<T> c) { return (T)c; }
}";
// Note: Dev10 also reports "CS0030: Cannot convert type 'T' to 'C0'" in F1<T>(T),
// although there is an explicit conversion from C1 to C0.
CreateCompilation(source).VerifyDiagnostics(
// (17,48): error CS0030: Cannot convert type 'T' to 'C0'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C0)t").WithArguments("T", "C0").WithLocation(17, 48),
// (21,38): error CS0030: Cannot convert type 'C4<T>' to 'T'
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(T)c").WithArguments("C4<T>", "T").WithLocation(21, 38));
}
/// <summary>
/// Dev10 does not report errors for implicit or explicit conversions between
/// base and derived types if one of those types is a type parameter.
/// </summary>
[Fact]
public void UserDefinedConversionsBaseToFromDerived()
{
var source =
@"class A { }
class B1 : A
{
public static implicit operator A(B1 b) { return null; }
}
class B2 : A
{
public static explicit operator A(B2 b) { return null; }
}
class B3 : A
{
public static implicit operator B3(A a) { return null; }
}
class B4 : A
{
public static explicit operator B4(A a) { return null; }
}
class C1<T> where T : C1<T>
{
public static implicit operator C1<T>(T t) { return null; }
}
class C2<T> where T : C2<T>
{
public static explicit operator C2<T>(T t) { return null; }
}
class C3<T> where T : C3<T>
{
public static implicit operator T(C3<T> c) { return null; }
}
class C4<T> where T : C4<T>
{
public static explicit operator T(C4<T> c) { return null; }
}";
CreateCompilation(source).VerifyDiagnostics(
// (4,37): error CS0553: 'B1.implicit operator A(B1)': user-defined conversions to or from a base type are not allowed
Diagnostic(ErrorCode.ERR_ConversionWithBase, "A").WithArguments("B1.implicit operator A(B1)").WithLocation(4, 37),
// (8,37): error CS0553: 'B2.explicit operator A(B2)': user-defined conversions to or from a base type are not allowed
Diagnostic(ErrorCode.ERR_ConversionWithBase, "A").WithArguments("B2.explicit operator A(B2)").WithLocation(8, 37),
// (12,37): error CS0553: 'B3.implicit operator B3(A)': user-defined conversions to or from a base type are not allowed
Diagnostic(ErrorCode.ERR_ConversionWithBase, "B3").WithArguments("B3.implicit operator B3(A)").WithLocation(12, 37),
// (16,37): error CS0553: 'B4.explicit operator B4(A)': user-defined conversions to or from a base type are not allowed
Diagnostic(ErrorCode.ERR_ConversionWithBase, "B4").WithArguments("B4.explicit operator B4(A)").WithLocation(16, 37));
}
}
}
|