private static void CheckNumericConversion(ConversionBlock block, Expression expression, ResolveResult rr, IType expectedType, Conversion conversion) { var fromType = rr.Type; var toType = expectedType; if (fromType.Kind == TypeKind.Enum) { fromType = fromType.GetDefinition().EnumUnderlyingType; } if (toType.Kind == TypeKind.Enum) { toType = toType.GetDefinition().EnumUnderlyingType; } bool isArrayIndex = false; if (Helpers.Is64Type(toType, block.Emitter.Resolver) && expression.Parent is IndexerExpression && ((IndexerExpression)expression.Parent).Arguments.Contains(expression)) { var memberResolveResult = rr as MemberResolveResult; var isIgnore = true; var isAccessorsIndexer = false; IProperty member = null; IndexerAccessor current = null; if (memberResolveResult == null) { memberResolveResult = block.Emitter.Resolver.ResolveNode(expression.Parent, block.Emitter) as MemberResolveResult; } if (memberResolveResult != null) { var resolvedMember = memberResolveResult.Member; isIgnore = block.Emitter.Validator.IsExternalType(resolvedMember.DeclaringTypeDefinition); isAccessorsIndexer = block.Emitter.Validator.IsAccessorsIndexer(resolvedMember); var property = resolvedMember as IProperty; if (property != null) { member = property; current = IndexerBlock.GetIndexerAccessor(block.Emitter, member, block.Emitter.IsAssignment); } } if (!(current != null && current.InlineAttr != null) && !(!(isIgnore || (current != null && current.IgnoreAccessor)) || isAccessorsIndexer)) { block.Write(JS.Types.System.Int64.TONUMBER); block.Write("("); isArrayIndex = true; } } if ((conversion.IsNumericConversion || conversion.IsEnumerationConversion) && conversion.IsExplicit) { if (!(expression.Parent is ArrayInitializerExpression) && Helpers.Is64Type(fromType, block.Emitter.Resolver) && Helpers.IsFloatType(toType, block.Emitter.Resolver) && !Helpers.IsDecimalType(toType, block.Emitter.Resolver)) { var be = expression.Parent as BinaryOperatorExpression; if (be == null || be.Operator != BinaryOperatorType.Divide || be.Left != expression) { block.Write(JS.Types.System.Int64.TONUMBER); if (!(expression is CastExpression && ((CastExpression)expression).Expression is ParenthesizedExpression)) { block.Write("("); block.AfterOutput += ")"; } } } else if (Helpers.IsDecimalType(toType, block.Emitter.Resolver) && !Helpers.IsDecimalType(fromType, block.Emitter.Resolver)) { block.Write(JS.Types.SYSTEM_DECIMAL + "("); block.AfterOutput += ", null, " + BridgeTypes.ToJsName(fromType, block.Emitter) + ")"; } else if (Helpers.IsDecimalType(fromType, block.Emitter.Resolver)) { ClipDecimal(expression, block, toType); } else if (Helpers.Is64Type(fromType, block.Emitter.Resolver)) { CheckLong(block, expression, toType, fromType, IsInCheckedContext(block.Emitter, expression)); } else if (Helpers.IsFloatType(fromType, block.Emitter.Resolver) && Helpers.IsIntegerType(toType, block.Emitter.Resolver)) { FloatToInt(block, expression, fromType, toType, IsInCheckedContext(block.Emitter, expression)); } else if (NeedsNarrowingNumericConversion(fromType, toType)) { if (IsInCheckedContext(block.Emitter, expression)) { CheckInteger(block, expression, toType); } else { ClipInteger(block, expression, toType, true); } } } else if (conversion.IsNumericConversion && conversion.IsImplicit && !(expression.Parent is ArrayInitializerExpression) && Helpers.Is64Type(fromType, block.Emitter.Resolver) && Helpers.IsFloatType(toType, block.Emitter.Resolver) && !Helpers.IsDecimalType(toType, block.Emitter.Resolver)) { var be = expression.Parent as BinaryOperatorExpression; if (be == null || be.Operator != BinaryOperatorType.Divide || be.Left != expression) { block.Write(JS.Types.System.Int64.TONUMBER); if (!(expression is CastExpression && ((CastExpression)expression).Expression is ParenthesizedExpression)) { block.Write("("); block.AfterOutput += ")"; } } } else if (((!Helpers.Is64Type(toType, block.Emitter.Resolver) && Helpers.IsIntegerType(toType, block.Emitter.Resolver)) || (rr is OperatorResolveResult && !Helpers.Is64Type(fromType, block.Emitter.Resolver) && Helpers.IsIntegerType(fromType, block.Emitter.Resolver))) && (expression is BinaryOperatorExpression || expression is UnaryOperatorExpression || expression.Parent is AssignmentExpression) && IsInCheckedContext(block.Emitter, expression)) { var needCheck = false; var be = expression as BinaryOperatorExpression; bool isBitwiseOperator = be != null && (be.Operator == BinaryOperatorType.ShiftLeft || be.Operator == BinaryOperatorType.ShiftRight || be.Operator == BinaryOperatorType.BitwiseAnd || be.Operator == BinaryOperatorType.BitwiseOr || be.Operator == BinaryOperatorType.ExclusiveOr); if ((Helpers.IsKnownType(KnownTypeCode.Int32, toType, block.Emitter.Resolver) && isBitwiseOperator) || (Helpers.IsKnownType(KnownTypeCode.UInt32, toType, block.Emitter.Resolver) && be != null && be.Operator == BinaryOperatorType.ShiftRight)) { // Don't need to check even in checked context and don't need to clip } else if (be != null && (be.Operator == BinaryOperatorType.Add || be.Operator == BinaryOperatorType.Divide || be.Operator == BinaryOperatorType.Multiply || isBitwiseOperator || be.Operator == BinaryOperatorType.Subtract)) { if (isBitwiseOperator) { ClipInteger(block, expression, toType, false); } else { needCheck = true; } } else { var ue = expression as UnaryOperatorExpression; if (ue != null && (ue.Operator == UnaryOperatorType.Minus || ue.Operator == UnaryOperatorType.Increment || ue.Operator == UnaryOperatorType.Decrement || ue.Operator == UnaryOperatorType.PostIncrement || ue.Operator == UnaryOperatorType.PostDecrement)) { needCheck = true; } else { var ae = expression.Parent as AssignmentExpression; isBitwiseOperator = ae != null && (ae.Operator == AssignmentOperatorType.ShiftRight || ae.Operator == AssignmentOperatorType.ShiftLeft || ae.Operator == AssignmentOperatorType.BitwiseAnd || ae.Operator == AssignmentOperatorType.BitwiseOr || ae.Operator == AssignmentOperatorType.ExclusiveOr); if ((isBitwiseOperator && Helpers.IsKnownType(KnownTypeCode.Int32, toType, block.Emitter.Resolver)) || (ae != null && ae.Operator == AssignmentOperatorType.ShiftRight && Helpers.IsKnownType(KnownTypeCode.UInt32, toType, block.Emitter.Resolver))) { // Don't need to check even in checked context and don't need to clip } else if (ae != null && (isBitwiseOperator || ae.Operator == AssignmentOperatorType.Add || ae.Operator == AssignmentOperatorType.Divide || ae.Operator == AssignmentOperatorType.Multiply || ae.Operator == AssignmentOperatorType.Subtract)) { if (isBitwiseOperator) { ClipInteger(block, expression, toType, false); } else { needCheck = true; } } } } if (!Helpers.IsIntegerType(toType, block.Emitter.Resolver)) { if (rr is OperatorResolveResult) { toType = fromType; } } if (needCheck) { CheckInteger(block, expression, toType); } } else if (((!Helpers.Is64Type(toType, block.Emitter.Resolver) && Helpers.IsIntegerType(toType, block.Emitter.Resolver)) || (rr is OperatorResolveResult && !Helpers.Is64Type(fromType, block.Emitter.Resolver) && Helpers.IsIntegerType(fromType, block.Emitter.Resolver))) && (expression is BinaryOperatorExpression || expression is UnaryOperatorExpression || expression.Parent is AssignmentExpression) && IsInUncheckedContext(block.Emitter, expression)) { if (ConversionBlock.IsLongConversion(block, expression, rr, toType, conversion) || rr is ConstantResolveResult) { return; } if (!Helpers.IsIntegerType(toType, block.Emitter.Resolver)) { if (rr is OperatorResolveResult) { toType = fromType; } } var needCheck = false; var be = expression as BinaryOperatorExpression; bool isBitwiseOperator = be != null && (be.Operator == BinaryOperatorType.ShiftLeft || be.Operator == BinaryOperatorType.ShiftRight || be.Operator == BinaryOperatorType.BitwiseAnd || be.Operator == BinaryOperatorType.BitwiseOr || be.Operator == BinaryOperatorType.ExclusiveOr); if ((Helpers.IsKnownType(KnownTypeCode.Int32, toType, block.Emitter.Resolver) && isBitwiseOperator) || (Helpers.IsKnownType(KnownTypeCode.UInt32, toType, block.Emitter.Resolver) && be != null && be.Operator == BinaryOperatorType.ShiftRight)) { // Don't need to check even in checked context and don't need to clip } else if (be != null && !(be.Left is PrimitiveExpression && be.Right is PrimitiveExpression) && (be.Operator == BinaryOperatorType.Add || be.Operator == BinaryOperatorType.Divide || be.Operator == BinaryOperatorType.Multiply || isBitwiseOperator || be.Operator == BinaryOperatorType.Subtract)) { needCheck = true; } else { var ue = expression as UnaryOperatorExpression; if (ue != null && !(ue.Expression is PrimitiveExpression) && (ue.Operator == UnaryOperatorType.Minus || ue.Operator == UnaryOperatorType.Increment || ue.Operator == UnaryOperatorType.Decrement || ue.Operator == UnaryOperatorType.PostIncrement || ue.Operator == UnaryOperatorType.PostDecrement)) { needCheck = true; } else { var ae = expression.Parent as AssignmentExpression; isBitwiseOperator = ae != null && (ae.Operator == AssignmentOperatorType.ShiftRight || ae.Operator == AssignmentOperatorType.ShiftLeft || ae.Operator == AssignmentOperatorType.BitwiseAnd || ae.Operator == AssignmentOperatorType.BitwiseOr || ae.Operator == AssignmentOperatorType.ExclusiveOr); if ((isBitwiseOperator && Helpers.IsKnownType(KnownTypeCode.Int32, toType, block.Emitter.Resolver)) || (ae != null && ae.Operator == AssignmentOperatorType.ShiftRight && Helpers.IsKnownType(KnownTypeCode.UInt32, toType, block.Emitter.Resolver))) { // Don't need to check even in checked context and don't need to clip } else if (ae != null && (isBitwiseOperator || ae.Operator == AssignmentOperatorType.Add || ae.Operator == AssignmentOperatorType.Divide || ae.Operator == AssignmentOperatorType.Multiply || ae.Operator == AssignmentOperatorType.Subtract)) { needCheck = true; } } } if (needCheck) { ClipInteger(block, expression, toType, false); } } if (isArrayIndex) { block.AfterOutput += ")"; } }
private static void CheckNumericConversion(ConversionBlock block, Expression expression, ResolveResult rr, IType expectedType, Conversion conversion) { if (conversion.IsNumericConversion && conversion.IsExplicit) { var fromType = rr.Type; var toType = expectedType; if (Helpers.IsDecimalType(expectedType, block.Emitter.Resolver) && !Helpers.IsDecimalType(fromType, block.Emitter.Resolver)) { block.Write("Bridge.Decimal("); block.AfterOutput += ")"; } else if (Helpers.IsDecimalType(fromType, block.Emitter.Resolver)) { ClipDecimal(expression, block, toType); } else if (Helpers.Is64Type(fromType, block.Emitter.Resolver)) { CheckLong(block, expression, toType, fromType, IsInCheckedContext(block.Emitter, expression)); } else if (Helpers.IsFloatType(fromType, block.Emitter.Resolver) && Helpers.IsIntegerType(toType, block.Emitter.Resolver)) { FloatToInt(block, expression, fromType, toType, IsInCheckedContext(block.Emitter, expression)); } else if (NeedsNarrowingNumericConversion(fromType, toType)) { if (IsInCheckedContext(block.Emitter, expression)) { CheckInteger(block, expression, toType); } else { ClipInteger(block, expression, toType, true); } } } else if (conversion.IsNumericConversion && conversion.IsImplicit && !(expression.Parent is ArrayInitializerExpression) && Helpers.Is64Type(rr.Type, block.Emitter.Resolver) && Helpers.IsFloatType(expectedType, block.Emitter.Resolver) && !Helpers.IsDecimalType(expectedType, block.Emitter.Resolver)) { var be = expression.Parent as BinaryOperatorExpression; if (be == null || be.Operator != BinaryOperatorType.Divide || be.Left != expression) { block.Write("Bridge.Long.toNumber"); if (!(expression is CastExpression && ((CastExpression)expression).Expression is ParenthesizedExpression)) { block.Write("("); block.AfterOutput += ")"; } } } else if (((!Helpers.Is64Type(expectedType, block.Emitter.Resolver) && Helpers.IsIntegerType(expectedType, block.Emitter.Resolver)) || (rr is OperatorResolveResult && !Helpers.Is64Type(rr.Type, block.Emitter.Resolver) && Helpers.IsIntegerType(rr.Type, block.Emitter.Resolver))) && (expression is BinaryOperatorExpression || expression is UnaryOperatorExpression || expression.Parent is AssignmentExpression) && IsInCheckedContext(block.Emitter, expression)) { var needCheck = false; var be = expression as BinaryOperatorExpression; bool isBitwiseOperator = be != null && (be.Operator == BinaryOperatorType.ShiftLeft || be.Operator == BinaryOperatorType.ShiftRight || be.Operator == BinaryOperatorType.BitwiseAnd || be.Operator == BinaryOperatorType.BitwiseOr || be.Operator == BinaryOperatorType.ExclusiveOr); if ((Helpers.IsKnownType(KnownTypeCode.Int32, expectedType, block.Emitter.Resolver) && isBitwiseOperator) || (Helpers.IsKnownType(KnownTypeCode.UInt32, expectedType, block.Emitter.Resolver) && be != null && be.Operator == BinaryOperatorType.ShiftRight)) { // Don't need to check even in checked context and don't need to clip } else if (be != null && (be.Operator == BinaryOperatorType.Add || be.Operator == BinaryOperatorType.Divide || be.Operator == BinaryOperatorType.Multiply || isBitwiseOperator || be.Operator == BinaryOperatorType.Subtract)) { if (isBitwiseOperator) { ClipInteger(block, expression, expectedType, false); } else { needCheck = true; } } else { var ue = expression as UnaryOperatorExpression; if (ue != null && (ue.Operator == UnaryOperatorType.Minus || ue.Operator == UnaryOperatorType.Increment || ue.Operator == UnaryOperatorType.Decrement || ue.Operator == UnaryOperatorType.PostIncrement || ue.Operator == UnaryOperatorType.PostDecrement)) { needCheck = true; } else { var ae = expression.Parent as AssignmentExpression; isBitwiseOperator = ae != null && (ae.Operator == AssignmentOperatorType.ShiftRight || ae.Operator == AssignmentOperatorType.ShiftLeft || ae.Operator == AssignmentOperatorType.BitwiseAnd || ae.Operator == AssignmentOperatorType.BitwiseOr || ae.Operator == AssignmentOperatorType.ExclusiveOr); if ((isBitwiseOperator && Helpers.IsKnownType(KnownTypeCode.Int32, expectedType, block.Emitter.Resolver)) || (ae != null && ae.Operator == AssignmentOperatorType.ShiftRight && Helpers.IsKnownType(KnownTypeCode.UInt32, expectedType, block.Emitter.Resolver))) { // Don't need to check even in checked context and don't need to clip } else if (ae != null && (isBitwiseOperator || ae.Operator == AssignmentOperatorType.Add || ae.Operator == AssignmentOperatorType.Divide || ae.Operator == AssignmentOperatorType.Multiply || ae.Operator == AssignmentOperatorType.Subtract)) { if (isBitwiseOperator) { ClipInteger(block, expression, expectedType, false); } else { needCheck = true; } } } } if (!Helpers.IsIntegerType(expectedType, block.Emitter.Resolver)) { if (rr is OperatorResolveResult) { expectedType = rr.Type; } } if (needCheck) { CheckInteger(block, expression, expectedType); } } else if (((!Helpers.Is64Type(expectedType, block.Emitter.Resolver) && Helpers.IsIntegerType(expectedType, block.Emitter.Resolver)) || (rr is OperatorResolveResult && !Helpers.Is64Type(rr.Type, block.Emitter.Resolver) && Helpers.IsIntegerType(rr.Type, block.Emitter.Resolver))) && (expression is BinaryOperatorExpression || expression is UnaryOperatorExpression || expression.Parent is AssignmentExpression) && IsInUncheckedContext(block.Emitter, expression)) { if (ConversionBlock.IsLongConversion(block, expression, rr, expectedType, conversion) || rr is ConstantResolveResult) { return; } if (!Helpers.IsIntegerType(expectedType, block.Emitter.Resolver)) { if (rr is OperatorResolveResult) { expectedType = rr.Type; } } var needCheck = false; var be = expression as BinaryOperatorExpression; bool isBitwiseOperator = be != null && (be.Operator == BinaryOperatorType.ShiftLeft || be.Operator == BinaryOperatorType.ShiftRight || be.Operator == BinaryOperatorType.BitwiseAnd || be.Operator == BinaryOperatorType.BitwiseOr || be.Operator == BinaryOperatorType.ExclusiveOr); if ((Helpers.IsKnownType(KnownTypeCode.Int32, expectedType, block.Emitter.Resolver) && isBitwiseOperator) || (Helpers.IsKnownType(KnownTypeCode.UInt32, expectedType, block.Emitter.Resolver) && be != null && be.Operator == BinaryOperatorType.ShiftRight)) { // Don't need to check even in checked context and don't need to clip } else if (be != null && !(be.Left is PrimitiveExpression && be.Right is PrimitiveExpression) && (be.Operator == BinaryOperatorType.Add || be.Operator == BinaryOperatorType.Divide || be.Operator == BinaryOperatorType.Multiply || isBitwiseOperator || be.Operator == BinaryOperatorType.Subtract)) { needCheck = true; } else { var ue = expression as UnaryOperatorExpression; if (ue != null && !(ue.Expression is PrimitiveExpression) && (ue.Operator == UnaryOperatorType.Minus || ue.Operator == UnaryOperatorType.Increment || ue.Operator == UnaryOperatorType.Decrement || ue.Operator == UnaryOperatorType.PostIncrement || ue.Operator == UnaryOperatorType.PostDecrement)) { needCheck = true; } else { var ae = expression.Parent as AssignmentExpression; isBitwiseOperator = ae != null && (ae.Operator == AssignmentOperatorType.ShiftRight || ae.Operator == AssignmentOperatorType.ShiftLeft || ae.Operator == AssignmentOperatorType.BitwiseAnd || ae.Operator == AssignmentOperatorType.BitwiseOr || ae.Operator == AssignmentOperatorType.ExclusiveOr); if ((isBitwiseOperator && Helpers.IsKnownType(KnownTypeCode.Int32, expectedType, block.Emitter.Resolver)) || (ae != null && ae.Operator == AssignmentOperatorType.ShiftRight && Helpers.IsKnownType(KnownTypeCode.UInt32, expectedType, block.Emitter.Resolver))) { // Don't need to check even in checked context and don't need to clip } else if (ae != null && (isBitwiseOperator || ae.Operator == AssignmentOperatorType.Add || ae.Operator == AssignmentOperatorType.Divide || ae.Operator == AssignmentOperatorType.Multiply || ae.Operator == AssignmentOperatorType.Subtract)) { needCheck = true; } } } if (needCheck) { ClipInteger(block, expression, expectedType, false); } } }