117
117
import static org .codehaus .groovy .syntax .Types .DIVIDE_EQUAL ;
118
118
import static org .codehaus .groovy .syntax .Types .EQUAL ;
119
119
import static org .codehaus .groovy .syntax .Types .FIND_REGEX ;
120
+ import static org .codehaus .groovy .syntax .Types .INTDIV ;
121
+ import static org .codehaus .groovy .syntax .Types .INTDIV_EQUAL ;
120
122
import static org .codehaus .groovy .syntax .Types .KEYWORD_IN ;
121
123
import static org .codehaus .groovy .syntax .Types .KEYWORD_INSTANCEOF ;
122
124
import static org .codehaus .groovy .syntax .Types .LEFT_SQUARE_BRACKET ;
@@ -930,7 +932,7 @@ private boolean addedReadOnlyPropertyError(Expression expr) {
930
932
931
933
private void addPrecisionErrors (ClassNode leftRedirect , ClassNode lhsType , ClassNode inferredrhsType , Expression rightExpression ) {
932
934
if (isNumberType (leftRedirect ) && isNumberType (inferredrhsType )) {
933
- if (checkPossibleLooseOfPrecision (leftRedirect , inferredrhsType , rightExpression )) {
935
+ if (checkPossibleLossOfPrecision (leftRedirect , inferredrhsType , rightExpression )) {
934
936
addStaticTypeError ("Possible loss of precision from " + inferredrhsType + " to " + leftRedirect , rightExpression );
935
937
return ;
936
938
}
@@ -3077,6 +3079,16 @@ public void visitMethodCallExpression(MethodCallExpression call) {
3077
3079
}
3078
3080
}
3079
3081
}
3082
+ // adjust typing for explicit math methods which have special handling - operator variants handled elsewhere
3083
+ if (NUMBER_OPS .containsKey (name ) && isNumberType (receiver ) && argumentList .getExpressions ().size () == 1
3084
+ && isNumberType (getType (argumentList .getExpression (0 )))) {
3085
+ ClassNode right = getType (argumentList .getExpression (0 ));
3086
+ ClassNode resultType = getMathResultType (NUMBER_OPS .get (name ), receiver , right , name );
3087
+ if (resultType != null ) {
3088
+ storeType (call , resultType );
3089
+ }
3090
+ }
3091
+
3080
3092
// now that a method has been chosen, we are allowed to visit the closures
3081
3093
if (!callArgsVisited ) {
3082
3094
MethodNode mn = (MethodNode ) call .getNodeMetaData (StaticTypesMarker .DIRECT_METHOD_CALL_TARGET );
@@ -3111,8 +3123,9 @@ public void visitMethodCallExpression(MethodCallExpression call) {
3111
3123
*
3112
3124
* @param directMethodCallCandidate a method selected by the type checker
3113
3125
* @param receiver the receiver of the method call
3114
- *@param args the arguments of the method call
3115
- * @param returnType the original return type, as inferred by the type checker @return fixed return type if the selected method is {@link org.codehaus.groovy.runtime.DefaultGroovyMethods#withTraits(Object, Class[]) withTraits}
3126
+ * @param args the arguments of the method call
3127
+ * @param returnType the original return type, as inferred by the type checker
3128
+ * @return fixed return type if the selected method is {@link org.codehaus.groovy.runtime.DefaultGroovyMethods#withTraits(Object, Class[]) withTraits}
3116
3129
*/
3117
3130
private static ClassNode adjustWithTraits (final MethodNode directMethodCallCandidate , final ClassNode receiver , final ClassNode [] args , final ClassNode returnType ) {
3118
3131
if (directMethodCallCandidate instanceof ExtensionMethodNode ) {
@@ -3613,9 +3626,11 @@ protected ClassNode getResultType(ClassNode left, int op, ClassNode right, Binar
3613
3626
}
3614
3627
}
3615
3628
return right ;
3616
- } else if (isBoolIntrinsicOp (op )) {
3629
+ }
3630
+ if (isBoolIntrinsicOp (op )) {
3617
3631
return boolean_TYPE ;
3618
- } else if (isArrayOp (op )) {
3632
+ }
3633
+ if (isArrayOp (op )) {
3619
3634
// using getPNR() to ignore generics at this point
3620
3635
// and a different binary expression not to pollute the AST
3621
3636
BinaryExpression newExpr = binX (expr .getLeftExpression (), expr .getOperation (), rightExpression );
@@ -3625,21 +3640,48 @@ protected ClassNode getResultType(ClassNode left, int op, ClassNode right, Binar
3625
3640
return inferReturnTypeGenerics (left , method , rightExpression );
3626
3641
}
3627
3642
return method !=null ?inferComponentType (left , right ):null ;
3628
- } else if (op == FIND_REGEX ) {
3643
+ }
3644
+ if (op == FIND_REGEX ) {
3629
3645
// this case always succeeds the result is a Matcher
3630
3646
return Matcher_TYPE ;
3631
3647
}
3632
3648
// the left operand is determining the result of the operation
3633
3649
// for primitives and their wrapper we use a fixed table here
3634
- else if (isNumberType (leftRedirect ) && isNumberType (rightRedirect )) {
3650
+ String operationName = getOperationName (op );
3651
+ ClassNode mathResultType = getMathResultType (op , leftRedirect , rightRedirect , operationName );
3652
+ if (mathResultType != null ) {
3653
+ return mathResultType ;
3654
+ }
3655
+
3656
+ // GROOVY-5890
3657
+ // do not mix Class<Foo> with Foo
3658
+ if (leftExpression instanceof ClassExpression ) {
3659
+ left = CLASS_Type .getPlainNodeReference ();
3660
+ }
3661
+
3662
+ MethodNode method = findMethodOrFail (expr , left , operationName , right );
3663
+ if (method != null ) {
3664
+ storeTargetMethod (expr , method );
3665
+ typeCheckMethodsWithGenericsOrFail (left , new ClassNode []{right }, method , expr );
3666
+ if (isAssignment (op )) return left ;
3667
+ if (isCompareToBoolean (op )) return boolean_TYPE ;
3668
+ if (op == COMPARE_TO ) return int_TYPE ;
3669
+ return inferReturnTypeGenerics (left , method , args (rightExpression ));
3670
+ }
3671
+ //TODO: other cases
3672
+ return null ;
3673
+ }
3674
+
3675
+ private ClassNode getMathResultType (int op , ClassNode leftRedirect , ClassNode rightRedirect , String operationName ) {
3676
+ if (isNumberType (leftRedirect ) && isNumberType (rightRedirect )) {
3635
3677
if (isOperationInGroup (op )) {
3636
3678
if (isIntCategory (leftRedirect ) && isIntCategory (rightRedirect )) return int_TYPE ;
3637
3679
if (isLongCategory (leftRedirect ) && isLongCategory (rightRedirect )) return long_TYPE ;
3638
3680
if (isFloat (leftRedirect ) && isFloat (rightRedirect )) return float_TYPE ;
3639
3681
if (isDouble (leftRedirect ) && isDouble (rightRedirect )) return double_TYPE ;
3640
3682
} else if (isPowerOperator (op )) {
3641
3683
return Number_TYPE ;
3642
- } else if (isBitOperator (op )) {
3684
+ } else if (isBitOperator (op ) || op == INTDIV || op == INTDIV_EQUAL ) {
3643
3685
if (isIntCategory (getUnwrapper (leftRedirect )) && isIntCategory (getUnwrapper (rightRedirect ))) return int_TYPE ;
3644
3686
if (isLongCategory (getUnwrapper (leftRedirect )) && isLongCategory (getUnwrapper (rightRedirect ))) return long_TYPE ;
3645
3687
if (isBigIntCategory (getUnwrapper (leftRedirect )) && isBigIntCategory (getUnwrapper (rightRedirect ))) return BigInteger_TYPE ;
@@ -3652,9 +3694,7 @@ else if (isNumberType(leftRedirect) && isNumberType(rightRedirect)) {
3652
3694
}
3653
3695
}
3654
3696
3655
-
3656
3697
// try to find a method for the operation
3657
- String operationName = getOperationName (op );
3658
3698
if (isShiftOperation (operationName ) && isNumberCategory (leftRedirect ) && (isIntCategory (rightRedirect ) || isLongCategory (rightRedirect ))) {
3659
3699
return leftRedirect ;
3660
3700
}
@@ -3679,23 +3719,6 @@ else if (isNumberType(leftRedirect) && isNumberType(rightRedirect)) {
3679
3719
if (isNumberCategory (getWrapper (rightRedirect )) && isNumberCategory (getWrapper (leftRedirect )) && (MOD == op || MOD_EQUAL == op )) {
3680
3720
return leftRedirect ;
3681
3721
}
3682
-
3683
- // GROOVY-5890
3684
- // do not mix Class<Foo> with Foo
3685
- if (leftExpression instanceof ClassExpression ) {
3686
- left = CLASS_Type .getPlainNodeReference ();
3687
- }
3688
-
3689
- MethodNode method = findMethodOrFail (expr , left , operationName , right );
3690
- if (method != null ) {
3691
- storeTargetMethod (expr , method );
3692
- typeCheckMethodsWithGenericsOrFail (left , new ClassNode []{right }, method , expr );
3693
- if (isAssignment (op )) return left ;
3694
- if (isCompareToBoolean (op )) return boolean_TYPE ;
3695
- if (op == COMPARE_TO ) return int_TYPE ;
3696
- return inferReturnTypeGenerics (left , method , args (rightExpression ));
3697
- }
3698
- //TODO: other cases
3699
3722
return null ;
3700
3723
}
3701
3724
0 commit comments