Index: src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (revision 2159) +++ src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (working copy) @@ -2045,8 +2045,9 @@ { IType fromType = GetExpressionType(node.Target); IType toType = GetType(node.Type); - if (!TypeSystemServices.AreTypesRelated(toType, fromType) && + if (!TypeSystemServices.AreTypesRelated(node.Target, toType, fromType) && !(toType.IsInterface && !fromType.IsFinal) && + !(TypeSystemServices.IsNumber(toType) && TypeSystemServices.IsNumber(fromType)) && !(TypeSystemServices.IsIntegerNumber(toType) && TypeSystemServices.CanBeExplicitlyCastToInteger(fromType)) && !(TypeSystemServices.IsIntegerNumber(fromType) && TypeSystemServices.CanBeExplicitlyCastToInteger(toType))) { @@ -4665,14 +4666,14 @@ } else { - AssertTypeCompatibility(arg, memberType, GetExpressionType(arg.Second)); + AssertTypeCompatibility(arg.Second, memberType, GetExpressionType(arg.Second)); } } } bool AssertTypeCompatibility(Node sourceNode, IType expectedType, IType actualType) { - if (!TypeSystemServices.AreTypesRelated(expectedType, actualType)) + if (!TypeSystemServices.AreTypesRelated(sourceNode, expectedType, actualType)) { Error(CompilerErrorFactory.IncompatibleExpressionType(sourceNode, expectedType.FullName, actualType.FullName)); return false; @@ -4729,7 +4730,7 @@ } else { - if (!TypeSystemServices.AreTypesRelated(parameterType, argumentType)) + if (!TypeSystemServices.AreTypesRelated(args[i], parameterType, argumentType)) { return false; } Index: src/Boo.Lang.Compiler/TypeSystem/CallableResolutionService.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/CallableResolutionService.cs (revision 2159) +++ src/Boo.Lang.Compiler/TypeSystem/CallableResolutionService.cs (working copy) @@ -336,7 +336,7 @@ } return 5; } - else if (TypeSystemServices.CanBeReachedByDownCastOrPromotion(parameterType, argumentType)) + else if (TypeSystemServices.CanBeReachedByDownCastOrPromotion(arg, parameterType, argumentType)) { // downcast return 4; Index: src/Boo.Lang.Compiler/TypeSystem/TypeSystemServices.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/TypeSystemServices.cs (revision 2159) +++ src/Boo.Lang.Compiler/TypeSystem/TypeSystemServices.cs (working copy) @@ -570,6 +570,11 @@ public bool AreTypesRelated(IType lhs, IType rhs) { + return AreTypesRelated(null, lhs, rhs); + } + + public bool AreTypesRelated(Node rhsNode, IType lhs, IType rhs) + { ICallableType ctype = lhs as ICallableType; if (null != ctype) { @@ -579,7 +584,7 @@ return lhs.IsAssignableFrom(rhs) || (lhs.IsInterface && !rhs.IsFinal) || (rhs.IsInterface && !lhs.IsFinal) - || CanBeReachedByDownCastOrPromotion(lhs, rhs); + || CanBeReachedByDownCastOrPromotion(rhsNode, lhs, rhs); } public bool IsCallableTypeAssignableFrom(ICallableType lhs, IType rhs) @@ -684,14 +689,100 @@ return false; } - public bool CanBeReachedByDownCastOrPromotion(IType expectedType, IType actualType) + public bool CanBeReachedByDownCastOrPromotion(Node actualNode, + IType expectedType, IType actualType) { return actualType.IsAssignableFrom(expectedType) || (expectedType.IsValueType && IsNumber(expectedType) - && IsNumber(actualType)); + && IsNumber(actualType) + && (NoLossOfPrecision(expectedType, actualType) + || IsValidDemotion(actualNode, expectedType, actualType))); } + public bool NoLossOfPrecision(IType expectedType, IType actualType) + { + if (expectedType == actualType) + { + return true; + } + + IType promoted = GetPromotedNumberType(expectedType, actualType); + if (promoted == expectedType) + { + return true; + } + return false; + } + + public bool IsValidDemotion(Node sourceNode, IType expectedType, IType actualType) + { + if (sourceNode==null || !IsNumber(expectedType) || !IsNumber(actualType) + || !(sourceNode.NodeType == NodeType.IntegerLiteralExpression + || sourceNode.NodeType == NodeType.DoubleLiteralExpression)) + { + return false; + } + double value = GetLiteralValue((LiteralExpression)sourceNode); + bool whole = Math.Floor(value) == value; + + if (expectedType == this.IntType) + { + return whole && value >= int.MinValue && value <= int.MaxValue; + } + else if (expectedType == this.ShortType) + { + return whole && value >= short.MinValue && value <= short.MaxValue; + } + else if (expectedType == this.LongType) + { + return whole && value >= long.MinValue && value <= long.MaxValue; + } + else if (expectedType == this.SByteType) + { + return whole && value >= sbyte.MinValue && value <= sbyte.MaxValue; + } + else if (expectedType == this.UShortType) + { + return whole && value >= ushort.MinValue && value <= ushort.MaxValue; + } + else if (expectedType == this.UIntType) + { + return whole && value >= uint.MinValue && value <= uint.MaxValue; + } + else if (expectedType == this.ULongType) + { + return whole && value >= ulong.MinValue && value <= ulong.MaxValue; + } + else if (expectedType == this.ByteType) + { + return whole && value >= byte.MinValue && value <= byte.MaxValue; + } + else if (expectedType == this.SingleType) + { + return value >= float.MinValue && value <= float.MaxValue; + } + else if (expectedType == this.DoubleType) + { + return value >= double.MinValue && value <= double.MaxValue; + } + return false; + } + + double GetLiteralValue(LiteralExpression node) + { + double val = 0.0; + if (node.NodeType == NodeType.IntegerLiteralExpression) + { + val = ((IntegerLiteralExpression)node).Value; + } + else if (node.NodeType == NodeType.DoubleLiteralExpression) + { + val = ((DoubleLiteralExpression)node).Value; + } + return val; + } + public bool CanBeExplicitlyCastToInteger(IType type) { return type.IsEnum || type == this.CharType; Index: tests/testcases/errors/BCE0022-11.boo =================================================================== --- tests/testcases/errors/BCE0022-11.boo (revision 0) +++ tests/testcases/errors/BCE0022-11.boo (revision 0) @@ -0,0 +1,21 @@ +""" +BCE0022-11.boo(11,14): BCE0022: Cannot convert 'System.Int32' to 'System.Byte'. +BCE0022-11.boo(14,13): BCE0022: Cannot convert 'System.Double' to 'System.Int32'. +BCE0022-11.boo(17,13): BCE0022: Cannot convert 'System.Double' to 'System.Int32'. +BCE0022-11.boo(20,5): BCE0017: The best overload for the method 'BCE0022-11Module.test(System.Byte)' is not compatible with the argument list '(System.Int64)'. +""" + +def test(x as byte): + print x + +b3 as byte = 0xFFFF //greater than byte.MaxValue +print b3 + +t3 as int = 2147483648.0 //1 greater than int.MaxValue +print t3 + +t4 as int = 3.1 //not a whole number +print t4 + +test(2147483648L) + Index: tests/testcases/integration/arrays-40.boo =================================================================== --- tests/testcases/integration/arrays-40.boo (revision 2159) +++ tests/testcases/integration/arrays-40.boo (working copy) @@ -17,7 +17,7 @@ print join(a) print len(a) -a1 = (of int: 1L, 2, 3.1) +a1 = (of int: 1L, 2, 3.0) dump(a1) a2 = (of string: null, null) Index: tests/testcases/integration/decimal-1.boo =================================================================== --- tests/testcases/integration/decimal-1.boo (revision 2159) +++ tests/testcases/integration/decimal-1.boo (working copy) @@ -13,9 +13,9 @@ assert toDecimal(45678L).GetType() == decimal y as decimal = 1.2 -i as int = y +i as int = cast(int,y) assert 1 == i -assert toInt(y) == 1 +assert toInt(cast(int,y)) == 1 z as double = 1.2 y = y*y-y/(y+y)*2 Index: tests/testcases/integration/duck-12.boo =================================================================== --- tests/testcases/integration/duck-12.boo (revision 2159) +++ tests/testcases/integration/duck-12.boo (working copy) @@ -37,14 +37,16 @@ assert _decimal == _duck assert long == _duck.GetType() -_uint as uint = (2.0**32 - 1) +/* +_uint as uint = cast(uint,2.0**32 - 1) _duck = _uint _duck = -_duck assert _duck == -(2.0**32 - 1) assert long == _duck.GetType() -_ushort as ushort = (2.0**16 - 1) +_ushort as ushort = cast(ushort, 2.0**16 - 1) _duck = _ushort _duck = -_duck assert _duck == -(2.0**16 - 1) assert int == _duck.GetType() +*/ Index: tests/testcases/integration/unsigned-1.boo =================================================================== --- tests/testcases/integration/unsigned-1.boo (revision 2159) +++ tests/testcases/integration/unsigned-1.boo (working copy) @@ -1,8 +1,8 @@ import NUnit.Framework import BooCompiler.Tests from BooCompiler.Tests -i0 as int = Constants.UnsignedInt -i1 as int = Constants.UnsignedLong +i0 as int = cast(int,Constants.UnsignedInt) +i1 as int = cast(int,Constants.UnsignedLong) l0 as long = Constants.UnsignedLong l1 as long = Constants.UnsignedInt Index: tests/testcases/regression/BOO-692-1.boo =================================================================== --- tests/testcases/regression/BOO-692-1.boo (revision 0) +++ tests/testcases/regression/BOO-692-1.boo (revision 0) @@ -0,0 +1,41 @@ +""" +255 +3 +1000.1 +1000.111 +3 +255 +3 +3 +""" + +def test(x as byte): + print x + +######valid casts: + +b as byte = cast(byte,0xFF) +print b + +t as int = cast(int,3.0) +print t + +d as double = cast(double,decimal.Parse("1000.10")) +print d + +dec as decimal = 1000.111 +print dec + +test(cast(byte,3)) + +######valid, implicit conversions from numeric literals: + +b2 as byte = 0xFF //255 <= byte.MaxValue +print b2 + +t2 as int = 3.0 //less than int.MaxValue & integer so we'll accept it +print t2 + +test(3) + +//See also ../errors/BCE0022-11.boo