#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
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.
 
 
 
 
 
 

543 lines
24 KiB

// Copyright (c) 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 ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
// assign short name to the fake reflection type
using dynamic = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.Dynamic;
[TestFixture]
public unsafe class BinaryOperatorTests : ResolverTestBase
{
[Test]
public void Multiplication()
{
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Multiply, MakeResult(typeof(int)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(int));
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Multiply, MakeConstant(0.0f),
Conversion.ImplicitNumericConversion, Conversion.IdentityConversion, typeof(float));
AssertConstant(3.0f, resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeConstant(1.5f), MakeConstant(2)));
AssertConstant(6, resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeConstant((byte)2), MakeConstant((byte)3)));
TestOperator(MakeResult(typeof(uint?)), BinaryOperatorType.Multiply, MakeResult(typeof(int?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(long?));
AssertError(typeof(decimal), resolver.ResolveBinaryOperator(
BinaryOperatorType.Multiply, MakeResult(typeof(float)), MakeResult(typeof(decimal))));
}
[Test]
public void Addition()
{
TestOperator(MakeResult(typeof(short)), BinaryOperatorType.Add, MakeResult(typeof(byte?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
AssertConstant(3.0, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(1.0f), MakeConstant(2.0)));
AssertConstant("Text", resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant("Te"), MakeConstant("xt")));
AssertConstant("", resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(null), resolver.ResolveCast(ResolveType(typeof(string)), MakeConstant(null))));
AssertError(typeof(ReflectionHelper.Null), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(null), MakeConstant(null)));
TestOperator(MakeResult(typeof(int?)), BinaryOperatorType.Add, MakeResult(typeof(uint?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(long?));
TestOperator(MakeResult(typeof(ushort?)), BinaryOperatorType.Add, MakeResult(typeof(ushort?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
TestOperator(MakeConstant(1), BinaryOperatorType.Add, MakeConstant(null),
Conversion.ImplicitNullableConversion, Conversion.NullLiteralConversion, typeof(int?));
}
[Test]
public void StringPlusNull()
{
ResolveResult left = MakeResult(typeof(string));
var rr = (BinaryOperatorResolveResult)resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, left, MakeConstant(null));
AssertType(typeof(string), rr);
Assert.AreSame(left, rr.Left);
Assert.AreEqual("System.String", rr.Right.Type.FullName);
Assert.IsTrue(rr.Right.IsCompileTimeConstant);
Assert.IsNull(rr.Right.ConstantValue);
}
[Test]
public void DelegateAddition()
{
TestOperator(MakeResult(typeof(Action)), BinaryOperatorType.Add, MakeResult(typeof(Action)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(Action));
TestOperator(MakeResult(typeof(Action<object>)), BinaryOperatorType.Add, MakeResult(typeof(Action<string>)),
Conversion.ImplicitReferenceConversion, Conversion.IdentityConversion, typeof(Action<string>));
TestOperator(MakeResult(typeof(Action<string>)), BinaryOperatorType.Add, MakeResult(typeof(Action<object>)),
Conversion.IdentityConversion, Conversion.ImplicitReferenceConversion, typeof(Action<string>));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeResult(typeof(Action<int>)), MakeResult(typeof(Action<long>))).IsError);
}
[Test]
public void EnumAddition()
{
AssertConstant(StringComparison.Ordinal, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(StringComparison.InvariantCulture), MakeConstant(2)));
AssertConstant(StringComparison.OrdinalIgnoreCase, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant((short)3), MakeConstant(StringComparison.InvariantCulture)));
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Add, MakeResult(typeof(int)),
Conversion.IdentityConversion, Conversion.ImplicitNullableConversion, typeof(StringComparison?));
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Add, MakeResult(typeof(int?)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(StringComparison?));
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Add, MakeResult(typeof(StringComparison?)),
Conversion.ImplicitNullableConversion, Conversion.IdentityConversion, typeof(StringComparison?));
TestOperator(MakeResult(typeof(int?)), BinaryOperatorType.Add, MakeResult(typeof(StringComparison?)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(StringComparison?));
}
[Test]
public void PointerAddition()
{
TestOperator(MakeResult(typeof(int*)), BinaryOperatorType.Add, MakeConstant(1),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(int*));
TestOperator(MakeResult(typeof(long)), BinaryOperatorType.Add, MakeResult(typeof(byte*)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(byte*));
}
[Test]
public void AdditionWithOverflow()
{
resolver.CheckForOverflow = false;
AssertConstant(int.MinValue, resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(int.MaxValue), MakeConstant(1)));
resolver.CheckForOverflow = true;
AssertError(typeof(int), resolver.ResolveBinaryOperator(
BinaryOperatorType.Add, MakeConstant(int.MaxValue), MakeConstant(1)));
}
[Test]
public void Subtraction()
{
TestOperator(MakeResult(typeof(short)), BinaryOperatorType.Subtract, MakeResult(typeof(byte?)),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
TestOperator(MakeResult(typeof(float)), BinaryOperatorType.Subtract, MakeResult(typeof(long)),
Conversion.IdentityConversion, Conversion.ImplicitNumericConversion, typeof(float));
AssertConstant(-1.0, resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant(1.0f), MakeConstant(2.0)));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant("Te"), MakeConstant("xt")).IsError);
}
[Test]
public void EnumSubtraction()
{
AssertConstant(StringComparison.InvariantCulture, resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant(StringComparison.Ordinal), MakeConstant(2)));
AssertConstant(3, resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeConstant(StringComparison.OrdinalIgnoreCase), MakeConstant(StringComparison.InvariantCulture)));
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Subtract, MakeResult(typeof(int)),
Conversion.IdentityConversion, Conversion.ImplicitNullableConversion, typeof(StringComparison?));
TestOperator(MakeResult(typeof(StringComparison?)), BinaryOperatorType.Subtract, MakeResult(typeof(StringComparison)),
Conversion.IdentityConversion, Conversion.ImplicitNullableConversion, typeof(int?));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(int?)), MakeResult(typeof(StringComparison))).IsError);
}
[Test]
public void DelegateSubtraction()
{
TestOperator(MakeResult(typeof(Action)), BinaryOperatorType.Subtract, MakeResult(typeof(Action)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(Action));
TestOperator(MakeResult(typeof(Action<object>)), BinaryOperatorType.Subtract, MakeResult(typeof(Action<string>)),
Conversion.ImplicitReferenceConversion, Conversion.IdentityConversion, typeof(Action<string>));
TestOperator(MakeResult(typeof(Action<string>)), BinaryOperatorType.Subtract, MakeResult(typeof(Action<object>)),
Conversion.IdentityConversion, Conversion.ImplicitReferenceConversion, typeof(Action<string>));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(Action<int>)), MakeResult(typeof(Action<long>))).IsError);
}
[Test]
public void PointerSubtraction()
{
TestOperator(MakeResult(typeof(int*)), BinaryOperatorType.Subtract, MakeConstant(1),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(int*));
TestOperator(MakeResult(typeof(byte*)), BinaryOperatorType.Subtract, MakeResult(typeof(uint)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(byte*));
TestOperator(MakeResult(typeof(byte*)), BinaryOperatorType.Subtract, MakeResult(typeof(short)),
Conversion.IdentityConversion, Conversion.ImplicitNumericConversion, typeof(byte*));
TestOperator(MakeResult(typeof(byte*)), BinaryOperatorType.Subtract, MakeResult(typeof(byte*)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(long));
AssertError(typeof(long), resolver.ResolveBinaryOperator(BinaryOperatorType.Subtract, MakeResult(typeof(byte*)), MakeResult(typeof(int*))));
}
[Test]
public void ShiftTest()
{
AssertConstant(6, resolver.ResolveBinaryOperator(
BinaryOperatorType.ShiftLeft, MakeConstant(3), MakeConstant(1)));
AssertConstant(ulong.MaxValue >> 2, resolver.ResolveBinaryOperator(
BinaryOperatorType.ShiftRight, MakeConstant(ulong.MaxValue), MakeConstant(2)));
TestOperator(MakeResult(typeof(ushort?)), BinaryOperatorType.ShiftLeft, MakeConstant(1),
Conversion.ImplicitNullableConversion, Conversion.ImplicitNullableConversion, typeof(int?));
TestOperator(MakeConstant(null), BinaryOperatorType.ShiftLeft, MakeConstant(1),
Conversion.NullLiteralConversion, Conversion.ImplicitNullableConversion, typeof(int?));
TestOperator(MakeResult(typeof(long)), BinaryOperatorType.ShiftLeft, MakeConstant(null),
Conversion.ImplicitNullableConversion, Conversion.NullLiteralConversion, typeof(long?));
TestOperator(MakeConstant(null), BinaryOperatorType.ShiftLeft, MakeConstant(null),
Conversion.NullLiteralConversion, Conversion.NullLiteralConversion, typeof(int?));
}
[Test]
public void ConstantEquality()
{
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(3), MakeConstant(3)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(3), MakeConstant(3.0)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(2.9), MakeConstant(3)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(double.NaN), MakeConstant(double.NaN)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(float.NaN), MakeConstant(float.NaN)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant("A"), MakeConstant("B")));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant("A"), MakeConstant("A")));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(""), MakeConstant(null)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(null), MakeConstant(null)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(1), MakeConstant(null)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(null), MakeConstant('a')));
}
[Test]
public void Equality()
{
TestOperator(MakeResult(typeof(int*)), BinaryOperatorType.Equality, MakeResult(typeof(uint*)),
Conversion.IdentityConversion, Conversion.IdentityConversion, typeof(bool));
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Equality, MakeResult(typeof(int?)),
Conversion.ImplicitNullableConversion, Conversion.IdentityConversion, typeof(bool));
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Equality, MakeResult(typeof(float)),
Conversion.ImplicitNumericConversion, Conversion.IdentityConversion, typeof(bool));
}
[Test]
public void Inequality()
{
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(3), MakeConstant(3)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(3), MakeConstant(3.0)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(2.9), MakeConstant(3)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(double.NaN), MakeConstant(double.NaN)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(float.NaN), MakeConstant(double.NaN)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(float.NaN), MakeConstant(float.NaN)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant("A"), MakeConstant("B")));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant("A"), MakeConstant("A")));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(""), MakeConstant(null)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(null), MakeConstant(null)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(1), MakeConstant(null)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeConstant(null), MakeConstant('a')));
AssertType(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.InEquality, MakeResult(typeof(int*)), MakeResult(typeof(uint*))));
}
[Test]
public void EqualityEnum()
{
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(0), MakeConstant(StringComparison.Ordinal)));
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(0), MakeConstant(StringComparison.CurrentCulture)));
Assert.IsFalse(resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeConstant(StringComparison.Ordinal), MakeConstant(1)).IsCompileTimeConstant);
}
[Test]
public void RelationalOperators()
{
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.LessThan, MakeConstant(0), MakeConstant(0)));
AssertType(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.LessThan, MakeResult(typeof(int*)), MakeResult(typeof(uint*))));
}
[Test]
public void RelationalEnum()
{
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.LessThan, MakeConstant(0), MakeConstant(StringComparison.Ordinal)));
AssertError(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.LessThanOrEqual, MakeConstant(1), MakeConstant(StringComparison.Ordinal)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.GreaterThan, MakeConstant(StringComparison.CurrentCultureIgnoreCase), MakeConstant(StringComparison.Ordinal)));
AssertType(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.GreaterThan, MakeResult(typeof(StringComparison?)), MakeResult(typeof(StringComparison?))));
}
[Test]
public void BitAnd()
{
AssertConstant(5, resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeConstant(7), MakeConstant(13)));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeConstant(null), MakeConstant((short)13)));
AssertType(typeof(long?), resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeResult(typeof(uint?)), MakeConstant((short)13)));
AssertType(typeof(uint?), resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeResult(typeof(uint?)), MakeConstant((int)13)));
AssertType(typeof(ulong?), resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeResult(typeof(ulong?)), MakeConstant((long)13)));
Assert.IsTrue(resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeResult(typeof(ulong?)), MakeConstant((short)13)).IsError);
}
[Test]
public void BitXor()
{
AssertConstant(6L ^ 3, resolver.ResolveBinaryOperator(
BinaryOperatorType.ExclusiveOr, MakeConstant(6L), MakeConstant(3)));
AssertConstant(6UL ^ 3L, resolver.ResolveBinaryOperator(
BinaryOperatorType.ExclusiveOr, MakeConstant(6UL), MakeConstant(3L)));
AssertError(typeof(ulong), resolver.ResolveBinaryOperator(
BinaryOperatorType.ExclusiveOr, MakeConstant(6UL), MakeConstant(-3L)));
}
[Test]
public void BitwiseEnum()
{
AssertConstant(AttributeTargets.Field | AttributeTargets.Property, resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseOr, MakeConstant(AttributeTargets.Field), MakeConstant(AttributeTargets.Property)));
AssertConstant(AttributeTargets.Field & AttributeTargets.All, resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeConstant(AttributeTargets.Field), MakeConstant(AttributeTargets.All)));
AssertConstant(AttributeTargets.Field & 0, resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseAnd, MakeConstant(AttributeTargets.Field), MakeConstant(0)));
AssertConstant(0 | AttributeTargets.Field, resolver.ResolveBinaryOperator(
BinaryOperatorType.BitwiseOr, MakeConstant(0), MakeConstant(AttributeTargets.Field)));
}
[Test]
public void LogicalAnd()
{
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.ConditionalAnd, MakeConstant(true), MakeConstant(true)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.ConditionalAnd, MakeConstant(false), MakeConstant(true)));
AssertError(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.ConditionalAnd, MakeConstant(false), MakeResult(typeof(bool?))));
}
[Test]
public void LogicalOr()
{
AssertConstant(true, resolver.ResolveBinaryOperator(
BinaryOperatorType.ConditionalOr, MakeConstant(false), MakeConstant(true)));
AssertConstant(false, resolver.ResolveBinaryOperator(
BinaryOperatorType.ConditionalOr, MakeConstant(false), MakeConstant(false)));
AssertError(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.ConditionalOr, MakeConstant(false), MakeResult(typeof(bool?))));
}
[Test]
public void NullCoalescing()
{
AssertType(typeof(int), resolver.ResolveBinaryOperator(
BinaryOperatorType.NullCoalescing, MakeResult(typeof(int?)), MakeResult(typeof(short))));
AssertType(typeof(int?), resolver.ResolveBinaryOperator(
BinaryOperatorType.NullCoalescing, MakeResult(typeof(int?)), MakeResult(typeof(short?))));
AssertType(typeof(object), resolver.ResolveBinaryOperator(
BinaryOperatorType.NullCoalescing, MakeResult(typeof(string)), MakeResult(typeof(object))));
AssertError(typeof(string), resolver.ResolveBinaryOperator(
BinaryOperatorType.NullCoalescing, MakeResult(typeof(string)), MakeResult(typeof(int))));
AssertType(typeof(dynamic), resolver.ResolveBinaryOperator(
BinaryOperatorType.NullCoalescing, MakeResult(typeof(dynamic)), MakeResult(typeof(string))));
AssertType(typeof(dynamic), resolver.ResolveBinaryOperator(
BinaryOperatorType.NullCoalescing, MakeResult(typeof(string)), MakeResult(typeof(dynamic))));
}
[Test]
public void LiftedUserDefined()
{
AssertType(typeof(TimeSpan), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime)), MakeResult(typeof(DateTime))));
AssertType(typeof(TimeSpan?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime?)), MakeResult(typeof(DateTime))));
AssertType(typeof(TimeSpan?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime)), MakeResult(typeof(DateTime?))));
AssertType(typeof(TimeSpan?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime?)), MakeResult(typeof(DateTime?))));
}
[Test]
public void UserDefinedNeedsLiftingDueToImplicitConversion()
{
string program = @"struct S {}
struct A {
public static implicit operator S?(A a) { return null; }
public static S operator +(A a, S s) { return s; }
}
class Test {
void M(A a) {
var s = $a + a$;
}
}
";
var irr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(irr.IsError);
Assert.IsTrue(irr.IsLiftedOperatorInvocation);
Assert.AreEqual("A.op_Addition", irr.Member.FullName);
// even though we're calling the lifted operator, trr.Member should be the original operator method
Assert.AreEqual("S", irr.Member.ReturnType.Resolve(context).ReflectionName);
Assert.AreEqual("System.Nullable`1[[S]]", irr.Type.ReflectionName);
Conversion lhsConv = ((ConversionResolveResult)irr.Arguments[0]).Conversion;
Conversion rhsConv = ((ConversionResolveResult)irr.Arguments[1]).Conversion;
Assert.AreEqual(Conversion.ImplicitNullableConversion, lhsConv);
Assert.IsTrue(rhsConv.IsUserDefined);
Assert.AreEqual("A.op_Implicit", rhsConv.Method.FullName);
}
[Test]
public void ThereAreNoLiftedOperatorsForClasses()
{
string program = @"struct S {}
class A {
public static implicit operator S?(A a) { return null; }
public static S operator +(A a, S s) { return s; }
}
class Test {
void M(A a) {
var s = $a + a$;
}
}
";
var irr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsTrue(irr.IsError); // cannot convert from A to S
Assert.AreEqual("A.op_Addition", irr.Member.FullName);
Assert.AreEqual("S", irr.Type.ReflectionName);
}
}
}