mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1613 lines
59 KiB
1613 lines
59 KiB
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this |
|
// software and associated documentation files (the "Software"), to deal in the Software |
|
// without restriction, including without limitation the rights to use, copy, modify, merge, |
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
|
// to whom the Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in all copies or |
|
// substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
// DEALINGS IN THE SOFTWARE. |
|
|
|
using System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using System.Collections.Immutable; |
|
|
|
using ICSharpCode.Decompiler.CSharp.Resolver; |
|
using ICSharpCode.Decompiler.Semantics; |
|
using ICSharpCode.Decompiler.Tests.TypeSystem; |
|
using ICSharpCode.Decompiler.TypeSystem; |
|
using ICSharpCode.Decompiler.TypeSystem.Implementation; |
|
|
|
using NUnit.Framework; |
|
|
|
namespace ICSharpCode.Decompiler.Tests.Semantics |
|
{ |
|
// assign short names to the fake reflection types |
|
using C = Conversion; |
|
using dynamic = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.Dynamic; |
|
using nint = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.NInt; |
|
using nuint = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.NUInt; |
|
using Null = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.Null; |
|
|
|
[TestFixture, Parallelizable(ParallelScope.All)] |
|
public unsafe class ConversionTest |
|
{ |
|
CSharpConversions conversions; |
|
ICompilation compilation; |
|
|
|
[OneTimeSetUp] |
|
public void SetUp() |
|
{ |
|
compilation = new SimpleCompilation(TypeSystemLoaderTests.TestAssembly, |
|
TypeSystemLoaderTests.Mscorlib, |
|
TypeSystemLoaderTests.SystemCore); |
|
conversions = new CSharpConversions(compilation); |
|
} |
|
|
|
Conversion ImplicitConversion(Type from, Type to) |
|
{ |
|
IType from2 = compilation.FindType(from); |
|
IType to2 = compilation.FindType(to); |
|
return conversions.ImplicitConversion(from2, to2); |
|
} |
|
|
|
Conversion ExplicitConversion(Type from, Type to) |
|
{ |
|
IType from2 = compilation.FindType(from); |
|
IType to2 = compilation.FindType(to); |
|
return conversions.ExplicitConversion(from2, to2); |
|
} |
|
|
|
[Test] |
|
public void IdentityConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(char), typeof(char)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(string), typeof(string)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(object), typeof(object)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(bool), typeof(char)), Is.EqualTo(C.None)); |
|
|
|
Assert.That(conversions.ImplicitConversion(SpecialType.Dynamic, SpecialType.Dynamic), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(conversions.ImplicitConversion(SpecialType.UnknownType, SpecialType.UnknownType), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(conversions.ImplicitConversion(SpecialType.NullType, SpecialType.NullType), Is.EqualTo(C.IdentityConversion)); |
|
} |
|
|
|
[Test] |
|
public void DynamicIdentityConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(object), typeof(dynamic)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(dynamic), typeof(object)), Is.EqualTo(C.IdentityConversion)); |
|
} |
|
|
|
[Test] |
|
public void ComplexDynamicIdentityConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(List<object>), typeof(List<dynamic>)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(List<dynamic>), typeof(List<object>)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(List<string>), typeof(List<dynamic>)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(List<dynamic>), typeof(List<string>)), Is.EqualTo(C.None)); |
|
|
|
Assert.That(ImplicitConversion(typeof(List<List<dynamic>[]>), typeof(List<List<object>[]>)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(List<List<object>[]>), typeof(List<List<dynamic>[]>)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ImplicitConversion(typeof(List<List<object>[,]>), typeof(List<List<dynamic>[]>)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void TupleIdentityConversions() |
|
{ |
|
var intType = compilation.FindType(typeof(int)); |
|
var stringType = compilation.FindType(typeof(string)); |
|
Assert.That(conversions.ImplicitConversion( |
|
new TupleType(compilation, ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "b")), |
|
new TupleType(compilation, ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "c"))), Is.EqualTo(C.IdentityConversion)); |
|
|
|
Assert.That(conversions.ImplicitConversion( |
|
new TupleType(compilation, ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "b")), |
|
new TupleType(compilation, ImmutableArray.Create(stringType, intType), ImmutableArray.Create("a", "b"))), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void TupleConversions() |
|
{ |
|
Assert.That( |
|
ImplicitConversion(typeof((int, string)), typeof((long, object))), Is.EqualTo(C.TupleConversion(ImmutableArray.Create(C.ImplicitNumericConversion, C.ImplicitReferenceConversion)))); |
|
|
|
Assert.That( |
|
ImplicitConversion(typeof(ValueTuple<float>), typeof(ValueTuple<double>)), Is.EqualTo(C.TupleConversion(ImmutableArray.Create(C.ImplicitNumericConversion)))); |
|
} |
|
|
|
[Test] |
|
public void PrimitiveConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(char), typeof(ushort)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(byte), typeof(char)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(int), typeof(long)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(long), typeof(int)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(int), typeof(float)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(bool), typeof(float)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(float), typeof(double)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(float), typeof(decimal)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(char), typeof(long)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(uint), typeof(long)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
} |
|
|
|
[Test] |
|
public void EnumerationConversion() |
|
{ |
|
ResolveResult zero = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 0); |
|
ResolveResult one = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1); |
|
C implicitEnumerationConversion = C.EnumerationConversion(true, false); |
|
Assert.That(conversions.ImplicitConversion(zero, compilation.FindType(typeof(StringComparison))), Is.EqualTo(implicitEnumerationConversion)); |
|
Assert.That(conversions.ImplicitConversion(one, compilation.FindType(typeof(StringComparison))), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void NullableConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(char), typeof(ushort?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(byte), typeof(char?)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(int), typeof(long?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(long), typeof(int?)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(int), typeof(float?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(bool), typeof(float?)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(float), typeof(double?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(float), typeof(decimal?)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void NullableConversions2() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(char?), typeof(ushort?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(byte?), typeof(char?)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(int?), typeof(long?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(long?), typeof(int?)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(int?), typeof(float?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(bool?), typeof(float?)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(float?), typeof(double?)), Is.EqualTo(C.ImplicitLiftedNumericConversion)); |
|
Assert.That(ImplicitConversion(typeof(float?), typeof(decimal?)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void NullLiteralConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(int?)), Is.EqualTo(C.NullLiteralConversion)); |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(char?)), Is.EqualTo(C.NullLiteralConversion)); |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(int)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(object)), Is.EqualTo(C.NullLiteralConversion)); |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(dynamic)), Is.EqualTo(C.NullLiteralConversion)); |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(string)), Is.EqualTo(C.NullLiteralConversion)); |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(int[])), Is.EqualTo(C.NullLiteralConversion)); |
|
} |
|
|
|
[Test] |
|
public void SimpleReferenceConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(string), typeof(object)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(BitArray), typeof(ICollection)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(IList), typeof(IEnumerable)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(object), typeof(string)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(ICollection), typeof(BitArray)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(IEnumerable), typeof(IList)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void ConversionToDynamic() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(string), typeof(dynamic)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(int), typeof(dynamic)), Is.EqualTo(C.BoxingConversion)); |
|
} |
|
|
|
[Test] |
|
public void ConversionFromDynamic() |
|
{ |
|
// There is no conversion from the type 'dynamic' to other types (except the identity conversion to object). |
|
// Such conversions only exists from dynamic expression. |
|
// This is an important distinction for type inference (see TypeInferenceTests.IEnumerableCovarianceWithDynamic) |
|
Assert.That(ImplicitConversion(typeof(dynamic), typeof(string)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(dynamic), typeof(int)), Is.EqualTo(C.None)); |
|
|
|
var dynamicRR = new ResolveResult(SpecialType.Dynamic); |
|
Assert.That(conversions.ImplicitConversion(dynamicRR, compilation.FindType(typeof(string))), Is.EqualTo(C.ImplicitDynamicConversion)); |
|
Assert.That(conversions.ImplicitConversion(dynamicRR, compilation.FindType(typeof(int))), Is.EqualTo(C.ImplicitDynamicConversion)); |
|
} |
|
|
|
[Test] |
|
public void ParameterizedTypeConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(List<string>), typeof(ICollection<string>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(IList<string>), typeof(ICollection<string>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(List<string>), typeof(ICollection<object>)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(IList<string>), typeof(ICollection<object>)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void ArrayConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(string[]), typeof(object[])), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(string[,]), typeof(object[,])), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(string[]), typeof(object[,])), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(object[]), typeof(string[])), Is.EqualTo(C.None)); |
|
|
|
Assert.That(ImplicitConversion(typeof(string[]), typeof(IList<string>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(string[,]), typeof(IList<string>)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(string[]), typeof(IList<object>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
|
|
Assert.That(ImplicitConversion(typeof(string[]), typeof(Array)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(string[]), typeof(ICloneable)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(Array), typeof(string[])), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(object), typeof(object[])), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void VarianceConversions() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(List<string>), typeof(IEnumerable<object>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(List<object>), typeof(IEnumerable<string>)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(IEnumerable<string>), typeof(IEnumerable<object>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(ICollection<string>), typeof(ICollection<object>)), Is.EqualTo(C.None)); |
|
|
|
Assert.That(ImplicitConversion(typeof(Comparer<object>), typeof(IComparer<string>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(Comparer<object>), typeof(IComparer<Array>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(Comparer<object>), typeof(Comparer<string>)), Is.EqualTo(C.None)); |
|
|
|
Assert.That(ImplicitConversion(typeof(List<object>), typeof(IEnumerable<string>)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(IEnumerable<string>), typeof(IEnumerable<object>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
|
|
Assert.That(ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IList, IEnumerable>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(Func<IEnumerable, IList>), typeof(Func<ICollection, ICollection>)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IEnumerable, IList>)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(Func<IList, IEnumerable>), typeof(Func<ICollection, ICollection>)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void ImplicitPointerConversion() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(Null), typeof(int*)), Is.EqualTo(C.ImplicitPointerConversion)); |
|
Assert.That(ImplicitConversion(typeof(int*), typeof(void*)), Is.EqualTo(C.ImplicitPointerConversion)); |
|
} |
|
|
|
[Test] |
|
public void NoConversionFromPointerTypeToObject() |
|
{ |
|
Assert.That(ImplicitConversion(typeof(int*), typeof(object)), Is.EqualTo(C.None)); |
|
Assert.That(ImplicitConversion(typeof(int*), typeof(dynamic)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void ConversionToNInt() |
|
{ |
|
// Test based on the table in https://github.com/dotnet/csharplang/blob/master/proposals/native-integers.md |
|
Assert.That(ExplicitConversion(typeof(object), typeof(nint)), Is.EqualTo(C.UnboxingConversion)); |
|
Assert.That(ExplicitConversion(typeof(void*), typeof(nint)), Is.EqualTo(C.ExplicitPointerConversion)); |
|
Assert.That(ExplicitConversion(typeof(sbyte), typeof(nint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(byte), typeof(nint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(short), typeof(nint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(ushort), typeof(nint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(int), typeof(nint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(uint), typeof(nint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(long), typeof(nint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(ulong), typeof(nint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(char), typeof(nint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(float), typeof(nint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(double), typeof(nint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(decimal), typeof(nint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(IntPtr), typeof(nint)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ExplicitConversion(typeof(UIntPtr), typeof(nint)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void ConversionToNUInt() |
|
{ |
|
// Test based on the table in https://github.com/dotnet/csharplang/blob/master/proposals/native-integers.md |
|
Assert.That(ExplicitConversion(typeof(object), typeof(nuint)), Is.EqualTo(C.UnboxingConversion)); |
|
Assert.That(ExplicitConversion(typeof(void*), typeof(nuint)), Is.EqualTo(C.ExplicitPointerConversion)); |
|
Assert.That(ExplicitConversion(typeof(sbyte), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(byte), typeof(nuint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(short), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(ushort), typeof(nuint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(int), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(uint), typeof(nuint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(long), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(ulong), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(char), typeof(nuint)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(float), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(double), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(decimal), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(IntPtr), typeof(nuint)), Is.EqualTo(C.None)); |
|
Assert.That(ExplicitConversion(typeof(UIntPtr), typeof(nuint)), Is.EqualTo(C.IdentityConversion)); |
|
} |
|
|
|
[Test] |
|
public void ConversionFromNInt() |
|
{ |
|
// Test based on the table in https://github.com/dotnet/csharplang/blob/master/proposals/native-integers.md |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(object)), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(void*)), Is.EqualTo(C.ExplicitPointerConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(nuint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(sbyte)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(byte)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(short)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(ushort)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(int)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(uint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(long)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(ulong)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(char)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(float)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(double)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(decimal)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(IntPtr)), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(UIntPtr)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void ConversionFromNUInt() |
|
{ |
|
// Test based on the table in https://github.com/dotnet/csharplang/blob/master/proposals/native-integers.md |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(object)), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(void*)), Is.EqualTo(C.ExplicitPointerConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(nint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(sbyte)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(byte)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(short)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(ushort)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(int)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(uint)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(long)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(ulong)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(char)), Is.EqualTo(C.ExplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(float)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(double)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(decimal)), Is.EqualTo(C.ImplicitNumericConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(IntPtr)), Is.EqualTo(C.None)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(UIntPtr)), Is.EqualTo(C.IdentityConversion)); |
|
} |
|
|
|
|
|
[Test] |
|
public void NIntEnumConversion() |
|
{ |
|
var explicitEnumConversion = C.EnumerationConversion(isImplicit: false, isLifted: false); |
|
Assert.That(ExplicitConversion(typeof(nint), typeof(StringComparison)), Is.EqualTo(explicitEnumConversion)); |
|
Assert.That(ExplicitConversion(typeof(nuint), typeof(StringComparison)), Is.EqualTo(explicitEnumConversion)); |
|
Assert.That(ExplicitConversion(typeof(StringComparison), typeof(nint)), Is.EqualTo(explicitEnumConversion)); |
|
Assert.That(ExplicitConversion(typeof(StringComparison), typeof(nuint)), Is.EqualTo(explicitEnumConversion)); |
|
} |
|
|
|
[Test] |
|
public void IntegerLiteralToNIntConversions() |
|
{ |
|
Assert.That(IntegerLiteralConversion(0, typeof(nint))); |
|
Assert.That(IntegerLiteralConversion(-1, typeof(nint))); |
|
Assert.That(!IntegerLiteralConversion(uint.MaxValue, typeof(nint))); |
|
Assert.That(!IntegerLiteralConversion(long.MaxValue, typeof(nint))); |
|
} |
|
|
|
|
|
[Test] |
|
public void IntegerLiteralToNUIntConversions() |
|
{ |
|
Assert.That(IntegerLiteralConversion(0, typeof(nuint))); |
|
Assert.That(!IntegerLiteralConversion(-1, typeof(nuint))); |
|
Assert.That(IntegerLiteralConversion(uint.MaxValue, typeof(nuint))); |
|
Assert.That(!IntegerLiteralConversion(long.MaxValue, typeof(nuint))); |
|
} |
|
|
|
[Test] |
|
public void UnconstrainedTypeParameter() |
|
{ |
|
ITypeParameter t = new DefaultTypeParameter(compilation, SymbolKind.TypeDefinition, 0, "T"); |
|
ITypeParameter t2 = new DefaultTypeParameter(compilation, SymbolKind.TypeDefinition, 1, "T2"); |
|
ITypeParameter tm = new DefaultTypeParameter(compilation, SymbolKind.Method, 0, "TM"); |
|
|
|
Assert.That(conversions.ImplicitConversion(SpecialType.NullType, t), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, SpecialType.Dynamic), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))), Is.EqualTo(C.None)); |
|
|
|
Assert.That(conversions.ImplicitConversion(t, t), Is.EqualTo(C.IdentityConversion)); |
|
Assert.That(conversions.ImplicitConversion(t2, t), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, t2), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, tm), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(tm, t), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void TypeParameterWithReferenceTypeConstraint() |
|
{ |
|
ITypeParameter t = new DefaultTypeParameter(compilation, SymbolKind.TypeDefinition, 0, "T", hasReferenceTypeConstraint: true); |
|
|
|
Assert.That(conversions.ImplicitConversion(SpecialType.NullType, t), Is.EqualTo(C.NullLiteralConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, SpecialType.Dynamic), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void TypeParameterWithValueTypeConstraint() |
|
{ |
|
ITypeParameter t = new DefaultTypeParameter(compilation, SymbolKind.TypeDefinition, 0, "T", hasValueTypeConstraint: true); |
|
|
|
Assert.That(conversions.ImplicitConversion(SpecialType.NullType, t), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, SpecialType.Dynamic), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))), Is.EqualTo(C.BoxingConversion)); |
|
} |
|
|
|
[Test] |
|
public void TypeParameterWithClassConstraint() |
|
{ |
|
ITypeParameter t = new DefaultTypeParameter(compilation, SymbolKind.TypeDefinition, 0, "T", |
|
constraints: new[] { compilation.FindType(typeof(StringComparer)) }); |
|
|
|
Assert.That(conversions.ImplicitConversion(SpecialType.NullType, t), Is.EqualTo(C.NullLiteralConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, SpecialType.Dynamic), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(StringComparer))), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(IComparer))), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(IComparer<int>))), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(IComparer<string>))), Is.EqualTo(C.ImplicitReferenceConversion)); |
|
} |
|
|
|
[Test] |
|
public void TypeParameterWithInterfaceConstraint() |
|
{ |
|
ITypeParameter t = new DefaultTypeParameter(compilation, SymbolKind.TypeDefinition, 0, "T", |
|
constraints: new[] { compilation.FindType(typeof(IList)) }); |
|
|
|
Assert.That(conversions.ImplicitConversion(SpecialType.NullType, t), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, SpecialType.Dynamic), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))), Is.EqualTo(C.None)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(IList))), Is.EqualTo(C.BoxingConversion)); |
|
Assert.That(conversions.ImplicitConversion(t, compilation.FindType(typeof(IEnumerable))), Is.EqualTo(C.BoxingConversion)); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion() |
|
{ |
|
Conversion c = ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset)); |
|
Assert.That(c.IsImplicit && c.IsUserDefined); |
|
Assert.That(c.Method.FullName, Is.EqualTo("System.DateTimeOffset.op_Implicit")); |
|
|
|
Assert.That(ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)), Is.EqualTo(C.None)); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitNullableConversion() |
|
{ |
|
// User-defined conversion followed by nullable conversion |
|
Conversion c = ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset?)); |
|
Assert.That(c.IsValid && c.IsUserDefined); |
|
Assert.That(!c.IsLifted); |
|
// Lifted user-defined conversion |
|
c = ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset?)); |
|
Assert.That(c.IsValid && c.IsUserDefined && c.IsLifted); |
|
// User-defined conversion doesn't drop the nullability |
|
c = ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset)); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
bool IntegerLiteralConversion(object value, Type to) |
|
{ |
|
IType fromType = compilation.FindType(value.GetType()); |
|
ConstantResolveResult crr = new ConstantResolveResult(fromType, value); |
|
IType to2 = compilation.FindType(to); |
|
return conversions.ImplicitConversion(crr, to2).IsValid; |
|
} |
|
|
|
[Test] |
|
public void IntegerLiteralToEnumConversions() |
|
{ |
|
Assert.That(IntegerLiteralConversion(0, typeof(LoaderOptimization))); |
|
Assert.That(IntegerLiteralConversion(0L, typeof(LoaderOptimization))); |
|
Assert.That(IntegerLiteralConversion(0, typeof(LoaderOptimization?))); |
|
Assert.That(!IntegerLiteralConversion(0, typeof(string))); |
|
Assert.That(!IntegerLiteralConversion(1, typeof(LoaderOptimization))); |
|
} |
|
|
|
[Test] |
|
public void ImplicitConstantExpressionConversion() |
|
{ |
|
Assert.That(IntegerLiteralConversion(0, typeof(int))); |
|
Assert.That(IntegerLiteralConversion(0, typeof(ushort))); |
|
Assert.That(IntegerLiteralConversion(0, typeof(sbyte))); |
|
|
|
Assert.That(IntegerLiteralConversion(-1, typeof(int))); |
|
Assert.That(!IntegerLiteralConversion(-1, typeof(ushort))); |
|
Assert.That(IntegerLiteralConversion(-1, typeof(sbyte))); |
|
|
|
Assert.That(IntegerLiteralConversion(200, typeof(int))); |
|
Assert.That(IntegerLiteralConversion(200, typeof(ushort))); |
|
Assert.That(!IntegerLiteralConversion(200, typeof(sbyte))); |
|
} |
|
|
|
[Test] |
|
public void ImplicitLongConstantExpressionConversion() |
|
{ |
|
Assert.That(!IntegerLiteralConversion(0L, typeof(int))); |
|
Assert.That(!IntegerLiteralConversion(0L, typeof(short))); |
|
Assert.That(IntegerLiteralConversion(0L, typeof(long))); |
|
Assert.That(IntegerLiteralConversion(0L, typeof(ulong))); |
|
|
|
Assert.That(IntegerLiteralConversion(-1L, typeof(long))); |
|
Assert.That(!IntegerLiteralConversion(-1L, typeof(ulong))); |
|
} |
|
|
|
[Test] |
|
public void ImplicitConstantExpressionConversionToNullable() |
|
{ |
|
Assert.That(IntegerLiteralConversion(0, typeof(uint?))); |
|
Assert.That(IntegerLiteralConversion(0, typeof(short?))); |
|
Assert.That(IntegerLiteralConversion(0, typeof(byte?))); |
|
|
|
Assert.That(!IntegerLiteralConversion(-1, typeof(uint?))); |
|
Assert.That(IntegerLiteralConversion(-1, typeof(short?))); |
|
Assert.That(!IntegerLiteralConversion(-1, typeof(byte?))); |
|
|
|
Assert.That(IntegerLiteralConversion(200, typeof(uint?))); |
|
Assert.That(IntegerLiteralConversion(200, typeof(short?))); |
|
Assert.That(IntegerLiteralConversion(200, typeof(byte?))); |
|
|
|
Assert.That(!IntegerLiteralConversion(0L, typeof(uint?))); |
|
Assert.That(IntegerLiteralConversion(0L, typeof(long?))); |
|
Assert.That(IntegerLiteralConversion(0L, typeof(ulong?))); |
|
|
|
Assert.That(IntegerLiteralConversion(-1L, typeof(long?))); |
|
Assert.That(!IntegerLiteralConversion(-1L, typeof(ulong?))); |
|
} |
|
|
|
[Test] |
|
public void ImplicitConstantExpressionConversionNumberInterfaces() |
|
{ |
|
Assert.That(IntegerLiteralConversion(0, typeof(IFormattable))); |
|
Assert.That(IntegerLiteralConversion(0, typeof(IComparable<int>))); |
|
Assert.That(!IntegerLiteralConversion(0, typeof(IComparable<short>))); |
|
Assert.That(!IntegerLiteralConversion(0, typeof(IComparable<long>))); |
|
} |
|
|
|
int BetterConversion(Type s, Type t1, Type t2) |
|
{ |
|
IType sType = compilation.FindType(s); |
|
IType t1Type = compilation.FindType(t1); |
|
IType t2Type = compilation.FindType(t2); |
|
return conversions.BetterConversion(sType, t1Type, t2Type); |
|
} |
|
|
|
int BetterConversion(object value, Type t1, Type t2) |
|
{ |
|
IType fromType = compilation.FindType(value.GetType()); |
|
ConstantResolveResult crr = new ConstantResolveResult(fromType, value); |
|
IType t1Type = compilation.FindType(t1); |
|
IType t2Type = compilation.FindType(t2); |
|
return conversions.BetterConversion(crr, t1Type, t2Type); |
|
} |
|
|
|
[Test] |
|
public void BetterConversion() |
|
{ |
|
Assert.That(BetterConversion(typeof(string), typeof(string), typeof(object)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(typeof(string), typeof(object), typeof(IComparable<string>)), Is.EqualTo(2)); |
|
Assert.That(BetterConversion(typeof(string), typeof(IEnumerable<char>), typeof(IComparable<string>)), Is.EqualTo(0)); |
|
} |
|
|
|
[Test] |
|
public void BetterPrimitiveConversion() |
|
{ |
|
Assert.That(BetterConversion(typeof(short), typeof(int), typeof(long)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(typeof(short), typeof(int), typeof(uint)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(typeof(ushort), typeof(uint), typeof(int)), Is.EqualTo(2)); |
|
Assert.That(BetterConversion(typeof(char), typeof(short), typeof(int)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(typeof(char), typeof(ushort), typeof(int)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(typeof(sbyte), typeof(long), typeof(ulong)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(typeof(byte), typeof(ushort), typeof(short)), Is.EqualTo(2)); |
|
|
|
Assert.That(BetterConversion(1, typeof(sbyte), typeof(byte)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(1, typeof(ushort), typeof(sbyte)), Is.EqualTo(2)); |
|
} |
|
|
|
[Test] |
|
public void BetterNullableConversion() |
|
{ |
|
Assert.That(BetterConversion(typeof(byte), typeof(int), typeof(uint?)), Is.EqualTo(0)); |
|
Assert.That(BetterConversion(typeof(byte?), typeof(int?), typeof(uint?)), Is.EqualTo(0)); |
|
Assert.That(BetterConversion(typeof(byte), typeof(ushort?), typeof(uint?)), Is.EqualTo(1)); |
|
Assert.That(BetterConversion(typeof(byte?), typeof(ulong?), typeof(uint?)), Is.EqualTo(2)); |
|
Assert.That(BetterConversion(typeof(byte), typeof(ushort?), typeof(uint)), Is.EqualTo(0)); |
|
Assert.That(BetterConversion(typeof(byte), typeof(ushort?), typeof(int)), Is.EqualTo(0)); |
|
Assert.That(BetterConversion(typeof(byte), typeof(ulong?), typeof(uint)), Is.EqualTo(2)); |
|
Assert.That(BetterConversion(typeof(byte), typeof(ulong?), typeof(int)), Is.EqualTo(0)); |
|
Assert.That(BetterConversion(typeof(ushort?), typeof(long?), typeof(int?)), Is.EqualTo(2)); |
|
Assert.That(BetterConversion(typeof(sbyte), typeof(int?), typeof(uint?)), Is.EqualTo(0)); |
|
} |
|
|
|
/* TODO: we should probably revive these tests somehow |
|
[Test] |
|
public void ExpansiveInheritance() |
|
{ |
|
var a = new DefaultUnresolvedTypeDefinition(string.Empty, "A"); |
|
var b = new DefaultUnresolvedTypeDefinition(string.Empty, "B"); |
|
// interface A<in U> |
|
a.Kind = TypeKind.Interface; |
|
a.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.TypeDefinition, 0, "U") { Variance = VarianceModifier.Contravariant }); |
|
// interface B<X> : A<A<B<X>>> { } |
|
b.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.TypeDefinition, 0, "X")); |
|
b.BaseTypes.Add(new ParameterizedTypeReference( |
|
a, new[] { new ParameterizedTypeReference( |
|
a, new [] { new ParameterizedTypeReference( |
|
b, new [] { new TypeParameterReference(SymbolKind.TypeDefinition, 0) } |
|
) } ) })); |
|
|
|
ICompilation compilation = TypeSystemHelper.CreateCompilation(a, b); |
|
ITypeDefinition resolvedA = compilation.MainAssembly.GetTypeDefinition(a.FullTypeName); |
|
ITypeDefinition resolvedB = compilation.MainAssembly.GetTypeDefinition(b.FullTypeName); |
|
|
|
IType type1 = new ParameterizedType(resolvedB, new[] { compilation.FindType(KnownTypeCode.Double) }); |
|
IType type2 = new ParameterizedType(resolvedA, new[] { new ParameterizedType(resolvedB, new[] { compilation.FindType(KnownTypeCode.String) }) }); |
|
Assert.That(!conversions.ImplicitConversion(type1, type2).IsValid); |
|
} |
|
|
|
[Test] |
|
public void ImplicitTypeParameterConversion() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void M<T, U>(T t) where T : U { |
|
U u = $t$; |
|
} |
|
}"; |
|
Assert.AreEqual(C.BoxingConversion, GetConversion(program)); |
|
} |
|
|
|
[Test] |
|
public void InvalidImplicitTypeParameterConversion() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void M<T, U>(T t) where U : T { |
|
U u = $t$; |
|
} |
|
}"; |
|
Assert.AreEqual(C.None, GetConversion(program)); |
|
} |
|
|
|
[Test] |
|
public void ImplicitTypeParameterArrayConversion() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void M<T, U>(T[] t) where T : U { |
|
U[] u = $t$; |
|
} |
|
}"; |
|
// invalid, e.g. T=int[], U=object[] |
|
Assert.AreEqual(C.None, GetConversion(program)); |
|
} |
|
|
|
[Test] |
|
public void ImplicitTypeParameterConversionWithClassConstraint() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void M<T, U>(T t) where T : class, U where U : class { |
|
U u = $t$; |
|
} |
|
}"; |
|
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program)); |
|
} |
|
|
|
[Test] |
|
public void ImplicitTypeParameterArrayConversionWithClassConstraint() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void M<T, U>(T[] t) where T : class, U where U : class { |
|
U[] u = $t$; |
|
} |
|
}"; |
|
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program)); |
|
} |
|
|
|
[Test] |
|
public void ImplicitTypeParameterConversionWithClassConstraintOnlyOnT() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void M<T, U>(T t) where T : class, U { |
|
U u = $t$; |
|
} |
|
}"; |
|
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program)); |
|
} |
|
|
|
[Test] |
|
public void ImplicitTypeParameterArrayConversionWithClassConstraintOnlyOnT() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void M<T, U>(T[] t) where T : class, U { |
|
U[] u = $t$; |
|
} |
|
}"; |
|
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program)); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_Void() |
|
{ |
|
string program = @"using System; |
|
delegate void D(); |
|
class Test { |
|
D d = $M$; |
|
public static void M() {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
Assert.That(!c.DelegateCapturesFirstArgument); |
|
Assert.IsNotNull(c.Method); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_Void_InstanceMethod() |
|
{ |
|
string program = @"using System; |
|
delegate void D(); |
|
class Test { |
|
D d; |
|
public void M() { |
|
d = $M$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
Assert.That(c.DelegateCapturesFirstArgument); |
|
Assert.IsNotNull(c.Method); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_MatchingSignature() |
|
{ |
|
string program = @"using System; |
|
delegate object D(int argument); |
|
class Test { |
|
D d = $M$; |
|
public static object M(int argument) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_InvalidReturnType() |
|
{ |
|
string program = @"using System; |
|
delegate object D(int argument); |
|
class Test { |
|
D d = $M$; |
|
public static int M(int argument) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_CovariantReturnType() |
|
{ |
|
string program = @"using System; |
|
delegate object D(int argument); |
|
class Test { |
|
D d = $M$; |
|
public static string M(int argument) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_RefArgumentTypesEqual() |
|
{ |
|
string program = @"using System; |
|
delegate void D(ref object o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(ref object o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_RefArgumentObjectVsDynamic() |
|
{ |
|
string program = @"using System; |
|
delegate void D(ref object o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(ref dynamic o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_RefVsOut() |
|
{ |
|
string program = @"using System; |
|
delegate void D(ref object o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(out object o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_RefVsNormal() |
|
{ |
|
string program = @"using System; |
|
delegate void D(ref object o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(object o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_NormalVsOut() |
|
{ |
|
string program = @"using System; |
|
delegate void D(object o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(out object o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_MatchingNormalParameter() |
|
{ |
|
string program = @"using System; |
|
delegate void D(object o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(object o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_IdentityConversion() |
|
{ |
|
string program = @"using System; |
|
delegate void D(object o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(dynamic o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_Contravariance() |
|
{ |
|
string program = @"using System; |
|
delegate void D(string o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(object o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
|
|
} |
|
|
|
[Test, Ignore("Not sure if this conversion should be valid or not... NR and mcs both accept it as valid, csc treats it as invalid")] |
|
public void MethodGroupConversion_NoContravarianceDynamic() |
|
{ |
|
string program = @"using System; |
|
delegate void D(string o); |
|
class Test { |
|
D d = $M$; |
|
public static void M(dynamic o) {} |
|
}"; |
|
var c = GetConversion(program); |
|
//Assert.IsFrue(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_ExactMatchIsBetter() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
delegate void D(string a); |
|
D d = $M$; |
|
static void M(object x) {} |
|
static void M(string x = null) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
Assert.AreEqual("System.String", c.Method.Parameters.Single().Type.FullName); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_CannotLeaveOutOptionalParameters() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
delegate void D(string a); |
|
D d = $M$; |
|
static void M(object x) {} |
|
static void M(string x, string y = null) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_CannotUseExpandedParams() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
delegate void D(string a); |
|
D d = $M$; |
|
static void M(object x) {} |
|
static void M(params string[] x) {} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_ExtensionMethod() |
|
{ |
|
string program = @"using System; |
|
static class Ext { |
|
public static void M(this string s, int x) {} |
|
} |
|
class Test { |
|
delegate void D(int a); |
|
void F() { |
|
string s = """"; |
|
D d = $s.M$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
Assert.That(c.DelegateCapturesFirstArgument); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_ExtensionMethodUsedAsStaticMethod() |
|
{ |
|
string program = @"using System; |
|
static class Ext { |
|
public static void M(this string s, int x) {} |
|
} |
|
class Test { |
|
delegate void D(string s, int a); |
|
void F() { |
|
D d = $Ext.M$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsMethodGroupConversion); |
|
Assert.That(!c.DelegateCapturesFirstArgument); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_ObjectToDynamic() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void F(object o) {} |
|
public void M() { |
|
Action<dynamic> x = $F$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_ObjectToDynamicGenericArgument() |
|
{ |
|
string program = @"using System; |
|
using System.Collections.Generic; |
|
class Test { |
|
public void F(List<object> l) {} |
|
public void M() { |
|
Action<List<dynamic>> x = $F$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_ObjectToDynamicReturnValue() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public object F() {} |
|
public void M() { |
|
Func<dynamic> x = $F$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_DynamicToObject() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public void F(dynamic o) {} |
|
public void M() { |
|
Action<object> x = $F$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_DynamicToObjectGenericArgument() |
|
{ |
|
string program = @"using System; |
|
using System.Collections.Generic; |
|
class Test { |
|
public void F(List<dynamic> l) {} |
|
public void M() { |
|
Action<List<object>> x = $F$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void MethodGroupConversion_DynamicToObjectReturnValue() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public dynamic F() {} |
|
public void M() { |
|
Func<object> x = $F$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void UserDefined_IntLiteral_ViaUInt_ToCustomStruct() |
|
{ |
|
string program = @"using System; |
|
struct T { |
|
public static implicit operator T(uint a) { return new T(); } |
|
} |
|
class Test { |
|
static void M() { |
|
T t = $1$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
} |
|
|
|
[Test] |
|
public void UserDefined_NullLiteral_ViaString_ToCustomStruct() |
|
{ |
|
string program = @"using System; |
|
struct T { |
|
public static implicit operator T(string a) { return new T(); } |
|
|
|
} |
|
class Test { |
|
static void M() { |
|
T t = $null$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
} |
|
|
|
|
|
[Test] |
|
public void UserDefined_CanUseLiftedEvenIfReturnTypeAlreadyNullable() |
|
{ |
|
string program = @"using System; |
|
struct S { |
|
public static implicit operator short?(S s) { return 0; } |
|
} |
|
|
|
class Test { |
|
static void M(S? s) { |
|
int? i = $s$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.That(c.IsLifted); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_PicksExactSourceTypeIfPossible() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator Convertible(int i) {return new Convertible(); } |
|
public static implicit operator Convertible(short s) {return new Convertible(); } |
|
} |
|
class Test { |
|
public void M() { |
|
Convertible a = $33$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("i", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_PicksMostEncompassedSourceType() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator Convertible(long l) {return new Convertible(); } |
|
public static implicit operator Convertible(uint ui) {return new Convertible(); } |
|
} |
|
class Test { |
|
public void M() { |
|
Convertible a = $(ushort)33$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("ui", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_NoMostEncompassedSourceTypeIsInvalid() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator Convertible(ulong l) {return new Convertible(); } |
|
public static implicit operator Convertible(int ui) {return new Convertible(); } |
|
} |
|
class Test { |
|
public void M() { |
|
Convertible a = $(ushort)33$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_PicksExactTargetTypeIfPossible() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator int(Convertible i) {return 0; } |
|
public static implicit operator short(Convertible s) {return 0; } |
|
} |
|
class Test { |
|
public void M() { |
|
int a = $new Convertible()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("i", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_PicksMostEncompassingTargetType() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator int(Convertible i) {return 0; } |
|
public static implicit operator ushort(Convertible us) {return 0; } |
|
} |
|
class Test { |
|
public void M() { |
|
ulong a = $new Convertible()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("us", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_NoMostEncompassingTargetTypeIsInvalid() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator uint(Convertible i) {return 0; } |
|
public static implicit operator short(Convertible us) {return 0; } |
|
} |
|
class Test { |
|
public void M() { |
|
long a = $new Convertible()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_AmbiguousIsInvalid() |
|
{ |
|
string program = @"using System; |
|
class Convertible1 { |
|
public static implicit operator Convertible2(Convertible1 c) {return 0; } |
|
} |
|
class Convertible2 { |
|
public static implicit operator Convertible2(Convertible1 c) {return 0; } |
|
} |
|
class Test { |
|
public void M() { |
|
Convertible2 a = $new Convertible1()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_DefinedNullableTakesPrecedenceOverLifted() |
|
{ |
|
string program = @"using System; |
|
struct Convertible { |
|
public static implicit operator Convertible(int i) {return new Convertible(); } |
|
public static implicit operator Convertible?(int? ni) {return new Convertible(); } |
|
} |
|
class Test { |
|
public void M() { |
|
Convertible? a = $(int?)33$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.That(!c.IsLifted); |
|
Assert.AreEqual("ni", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_UIntConstant() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator Convertible(long l) {return new Convertible(); } |
|
public static implicit operator Convertible(uint ui) {return new Convertible(); } |
|
} |
|
class Test { |
|
public void M() { |
|
Convertible a = $33$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("ui", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_NullableUIntConstant() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator Convertible(long? l) {return new Convertible(); } |
|
public static implicit operator Convertible(uint? ui) {return new Convertible(); } |
|
} |
|
class Test { |
|
public void M() { |
|
Convertible a = $33$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("ui", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_UseShortResult_BecauseNullableCannotBeUnpacked() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public static implicit operator int?(Test i) { return 0; } |
|
public static implicit operator short(Test s) { return 0; } |
|
} |
|
class Program { |
|
public static void Main(string[] args) |
|
{ |
|
int x = $new Test()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_Short_Or_NullableByte_Target() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public static implicit operator short(Test s) { return 0; } |
|
public static implicit operator byte?(Test b) { return 0; } |
|
} |
|
class Program { |
|
public static void Main(string[] args) |
|
{ |
|
int? x = $new Test()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_Byte_Or_NullableShort_Target() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public static implicit operator byte(Test b) { return 0; } |
|
public static implicit operator short?(Test s) { return 0; } |
|
} |
|
class Program { |
|
public static void Main(string[] args) |
|
{ |
|
int? x = $new Test()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("s", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_Int_Or_NullableLong_Source() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public static implicit operator Test(int i) { return new Test(); } |
|
public static implicit operator Test(long? l) { return new Test(); } |
|
} |
|
class Program { |
|
static void Main() { |
|
short s = 0; |
|
Test t = $s$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("i", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_NullableInt_Or_Long_Source() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public static implicit operator Test(int? i) { return new Test(); } |
|
public static implicit operator Test(long l) { return new Test(); } |
|
} |
|
class Program { |
|
static void Main() { |
|
short s = 0; |
|
Test t = $s$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_NullableInt_Or_Long_Constant_Source() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public static implicit operator Test(int? i) { return new Test(); } |
|
public static implicit operator Test(long l) { return new Test(); } |
|
} |
|
class Program { |
|
static void Main() { |
|
Test t = $1$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(!c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_NullableInt_Or_NullableLong_Source() |
|
{ |
|
string program = @"using System; |
|
class Test { |
|
public static implicit operator Test(int? i) { return new Test(); } |
|
public static implicit operator Test(long? l) { return new Test(); } |
|
} |
|
class Program { |
|
static void Main() { |
|
short s = 0; |
|
Test t = $s$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsUserDefined); |
|
Assert.AreEqual("i", c.Method.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void PreferUserDefinedConversionOverReferenceConversion() |
|
{ |
|
// actually this is not because user-defined conversions are better; |
|
// but because string is a better conversion target |
|
string program = @" |
|
class AA { |
|
public static implicit operator string(AA a) { return null; } |
|
} |
|
class Test { |
|
static void M(object obj) {} |
|
static void M(string str) {} |
|
|
|
static void Main() { |
|
$M(new AA())$; |
|
} |
|
}"; |
|
|
|
var rr = Resolve<CSharpInvocationResolveResult>(program); |
|
Assert.That(!rr.IsError); |
|
Assert.AreEqual("str", rr.Member.Parameters[0].Name); |
|
} |
|
|
|
[Test] |
|
public void PreferAmbiguousConversionOverReferenceConversion() |
|
{ |
|
// Ambiguous conversions are a compiler error; but they are not |
|
// preventing the overload from being chosen. |
|
|
|
// The user-defined conversion wins because BB is a better conversion target than object. |
|
string program = @" |
|
class AA { |
|
public static implicit operator BB(AA a) { return null; } |
|
} |
|
class BB { |
|
public static implicit operator BB(AA a) { return null; } |
|
} |
|
|
|
class Test { |
|
static void M(BB b) {} |
|
static void M(object o) {} |
|
|
|
static void Main() { |
|
M($new AA()$); |
|
} |
|
}"; |
|
|
|
var c = GetConversion(program); |
|
Assert.That(c.IsUserDefined); |
|
Assert.That(!c.IsValid); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_ConversionBeforeUserDefinedOperatorIsCorrect() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator Convertible(long l) {return new Convertible(); } |
|
} |
|
class Test { |
|
public void M() { |
|
int i = 33; |
|
Convertible a = $i$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.ConversionBeforeUserDefinedOperator.IsImplicit); |
|
Assert.That(c.ConversionBeforeUserDefinedOperator.IsNumericConversion); |
|
Assert.That(c.ConversionBeforeUserDefinedOperator.IsValid); |
|
Assert.That(c.ConversionAfterUserDefinedOperator.IsIdentityConversion); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_ConversionAfterUserDefinedOperatorIsCorrect() |
|
{ |
|
string program = @"using System; |
|
class Convertible { |
|
public static implicit operator int(Convertible i) {return 0; } |
|
} |
|
class Test { |
|
public void M() { |
|
long a = $new Convertible()$; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.ConversionBeforeUserDefinedOperator.IsIdentityConversion); |
|
Assert.That(c.ConversionAfterUserDefinedOperator.IsImplicit); |
|
Assert.That(c.ConversionAfterUserDefinedOperator.IsNumericConversion); |
|
Assert.That(c.ConversionAfterUserDefinedOperator.IsValid); |
|
} |
|
|
|
[Test] |
|
public void UserDefinedImplicitConversion_IsImplicit() |
|
{ |
|
// Bug icsharpcode/NRefactory#183: conversions from constant expressions were incorrectly marked as explicit |
|
string program = @"using System; |
|
class Test { |
|
void Hello(JsNumber3 x) { |
|
Hello($7$); |
|
} |
|
} |
|
public class JsNumber3 { |
|
public static implicit operator JsNumber3(int d) { |
|
return null; |
|
} |
|
}"; |
|
var c = GetConversion(program); |
|
Assert.That(c.IsValid); |
|
Assert.That(c.IsImplicit); |
|
Assert.That(!c.IsExplicit); |
|
Assert.AreEqual(Conversion.IdentityConversion, c.ConversionBeforeUserDefinedOperator); |
|
Assert.AreEqual(Conversion.IdentityConversion, c.ConversionAfterUserDefinedOperator); |
|
} |
|
*/ |
|
} |
|
}
|
|
|