@@ -1025,7 +1025,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1025
1025
isShift := n .Op == SHL || n .Op == SHR
1026
1026
if isShift {
1027
1027
// check LHS type compatibility
1028
- n .checkShiftLhs ( lt )
1028
+ n .assertShiftExprCompatible1 ( store , last , lt , rt )
1029
1029
// checkOrConvert RHS
1030
1030
if baseOf (rt ) != UintType {
1031
1031
// convert n.Right to (gno) uint type,
@@ -1036,6 +1036,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1036
1036
Op : n .Op ,
1037
1037
Right : rn ,
1038
1038
}
1039
+ n2 .Right .SetAttribute (ATTR_SHIFT_RHS , true )
1039
1040
resn := Preprocess (store , last , n2 )
1040
1041
return resn , TRANS_CONTINUE
1041
1042
}
@@ -1097,12 +1098,34 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1097
1098
// NOTE: binary operations are always computed in
1098
1099
// gno, never with reflect.
1099
1100
} else {
1100
- // convert n.Left to right type.
1101
- checkOrConvertType (store , last , & n .Left , rt , false )
1101
+ // right is untyped const, left is not const, typed/untyped
1102
+ checkUntypedShiftExpr := func (x Expr ) {
1103
+ if bx , ok := x .(* BinaryExpr ); ok {
1104
+ slt := evalStaticTypeOf (store , last , bx .Left )
1105
+ if bx .Op == SHL || bx .Op == SHR {
1106
+ srt := evalStaticTypeOf (store , last , bx .Right )
1107
+ bx .assertShiftExprCompatible1 (store , last , slt , srt )
1108
+ }
1109
+ }
1110
+ }
1111
+
1112
+ if ! isUntyped (rt ) { // right is typed
1113
+ checkOrConvertType (store , last , & n .Left , rt , false )
1114
+ } else {
1115
+ if shouldSwapOnSpecificity (lt , rt ) {
1116
+ checkUntypedShiftExpr (n .Right )
1117
+ } else {
1118
+ checkUntypedShiftExpr (n .Left )
1119
+ }
1120
+ }
1102
1121
}
1103
1122
} else if lcx .T == nil { // LHS is nil.
1104
1123
// convert n.Left to typed-nil type.
1105
1124
checkOrConvertType (store , last , & n .Left , rt , false )
1125
+ } else {
1126
+ if isUntyped (rt ) {
1127
+ checkOrConvertType (store , last , & n .Right , lt , false )
1128
+ }
1106
1129
}
1107
1130
} else if ric { // right is const, left is not
1108
1131
if isUntyped (rcx .T ) {
@@ -1134,12 +1157,33 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1134
1157
// NOTE: binary operations are always computed in
1135
1158
// gno, never with reflect.
1136
1159
} else {
1137
- // convert n.Right to left type.
1138
- checkOrConvertType (store , last , & n .Right , lt , false )
1160
+ // right is untyped const, left is not const, typed or untyped
1161
+ checkUntypedShiftExpr := func (x Expr ) {
1162
+ if bx , ok := x .(* BinaryExpr ); ok {
1163
+ if bx .Op == SHL || bx .Op == SHR {
1164
+ srt := evalStaticTypeOf (store , last , bx .Right )
1165
+ bx .assertShiftExprCompatible1 (store , last , rt , srt )
1166
+ }
1167
+ }
1168
+ }
1169
+ // both untyped, e.g. 1<<s != 1.0
1170
+ if ! isUntyped (lt ) { // left is typed
1171
+ checkOrConvertType (store , last , & n .Right , lt , false )
1172
+ } else { // if one side is untyped shift expression, check type with lower specificity
1173
+ if shouldSwapOnSpecificity (lt , rt ) {
1174
+ checkUntypedShiftExpr (n .Right )
1175
+ } else {
1176
+ checkUntypedShiftExpr (n .Left )
1177
+ }
1178
+ }
1139
1179
}
1140
1180
} else if rcx .T == nil { // RHS is nil
1141
1181
// refer to tests/files/types/eql_0f20.gno
1142
1182
checkOrConvertType (store , last , & n .Right , lt , false )
1183
+ } else { // left is not const, right is typed const
1184
+ if isUntyped (lt ) {
1185
+ checkOrConvertType (store , last , & n .Left , rt , false )
1186
+ }
1143
1187
}
1144
1188
} else {
1145
1189
// Left not const, Right not const ------------------
@@ -1267,27 +1311,28 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1267
1311
panic ("type conversion requires single argument" )
1268
1312
}
1269
1313
n .NumArgs = 1
1270
- if arg0 , ok := n .Args [0 ].(* ConstExpr ); ok {
1271
- var constConverted bool
1272
- ct := evalStaticType (store , last , n .Func )
1314
+ ct := evalStaticType (store , last , n .Func )
1315
+ at := evalStaticTypeOf (store , last , n .Args [0 ])
1316
+ var constConverted bool
1317
+ switch arg0 := n .Args [0 ].(type ) {
1318
+ case * ConstExpr :
1273
1319
// As a special case, if a decimal cannot
1274
1320
// be represented as an integer, it cannot be converted to one,
1275
1321
// and the error is handled here.
1276
1322
// Out of bounds errors are usually handled during evalConst().
1277
- switch ct .Kind () {
1278
- case IntKind , Int8Kind , Int16Kind , Int32Kind , Int64Kind ,
1279
- UintKind , Uint8Kind , Uint16Kind , Uint32Kind , Uint64Kind ,
1280
- BigintKind :
1323
+ if isIntNum (ct ) {
1281
1324
if bd , ok := arg0 .TypedValue .V .(BigdecValue ); ok {
1282
1325
if ! isInteger (bd .V ) {
1283
1326
panic (fmt .Sprintf (
1284
1327
"cannot convert %s to integer type" ,
1285
1328
arg0 ))
1286
1329
}
1287
1330
}
1288
- convertConst (store , last , arg0 , ct )
1289
- constConverted = true
1290
- case SliceKind :
1331
+ if isNumeric (at ) {
1332
+ convertConst (store , last , arg0 , ct )
1333
+ constConverted = true
1334
+ }
1335
+ } else if ct .Kind () == SliceKind {
1291
1336
if ct .Elem ().Kind () == Uint8Kind { // bypass []byte("xxx")
1292
1337
n .SetAttribute (ATTR_TYPEOF_VALUE , ct )
1293
1338
return n , TRANS_CONTINUE
@@ -1298,18 +1343,34 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1298
1343
if ! constConverted {
1299
1344
convertConst (store , last , arg0 , nil )
1300
1345
}
1301
-
1302
1346
// evaluate the new expression.
1303
1347
cx := evalConst (store , last , n )
1304
1348
// Though cx may be undefined if ct is interface,
1305
1349
// the ATTR_TYPEOF_VALUE is still interface.
1306
1350
cx .SetAttribute (ATTR_TYPEOF_VALUE , ct )
1307
1351
return cx , TRANS_CONTINUE
1308
- } else {
1309
- ct := evalStaticType (store , last , n .Func )
1310
- n .SetAttribute (ATTR_TYPEOF_VALUE , ct )
1311
- return n , TRANS_CONTINUE
1352
+ case * BinaryExpr : // special case to evaluate type of binaryExpr/UnaryExpr which has untyped shift nested
1353
+ if isUntyped (at ) {
1354
+ switch arg0 .Op {
1355
+ case EQL , NEQ , LSS , GTR , LEQ , GEQ :
1356
+ assertAssignableTo (at , ct , false )
1357
+ break
1358
+ default :
1359
+ checkOrConvertType (store , last , & n .Args [0 ], ct , false )
1360
+ }
1361
+ }
1362
+ case * UnaryExpr :
1363
+ if isUntyped (at ) {
1364
+ checkOrConvertType (store , last , & n .Args [0 ], ct , false )
1365
+ }
1366
+ default :
1367
+ // do nothing
1312
1368
}
1369
+ // general case, for non-const untyped && no nested untyped shift
1370
+ // after handling const, and special cases recursively, set the target node type
1371
+ // ct := evalStaticType(store, last, n.Func)
1372
+ n .SetAttribute (ATTR_TYPEOF_VALUE , ct )
1373
+ return n , TRANS_CONTINUE
1313
1374
default :
1314
1375
panic (fmt .Sprintf (
1315
1376
"unexpected func type %v (%v)" ,
@@ -1479,7 +1540,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1479
1540
}
1480
1541
}
1481
1542
} else {
1482
- for i := range n .Args {
1543
+ for i := range n .Args { // iterate args
1483
1544
if hasVarg {
1484
1545
if (len (spts ) - 1 ) <= i {
1485
1546
if isVarg {
@@ -1929,6 +1990,10 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
1929
1990
} else {
1930
1991
last .Define (ln , anyValue (rt ))
1931
1992
}
1993
+ // if rhs is untyped
1994
+ if isUntyped (rt ) {
1995
+ checkOrConvertType (store , last , & n .Rhs [i ], nil , false )
1996
+ }
1932
1997
}
1933
1998
}
1934
1999
} else { // ASSIGN, or assignment operation (+=, -=, <<=, etc.)
@@ -2018,9 +2083,6 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
2018
2083
}
2019
2084
} else { // len(Lhs) == len(Rhs)
2020
2085
if n .Op == SHL_ASSIGN || n .Op == SHR_ASSIGN {
2021
- if len (n .Lhs ) != 1 || len (n .Rhs ) != 1 {
2022
- panic ("should not happen" )
2023
- }
2024
2086
// Special case if shift assign <<= or >>=.
2025
2087
convertType (store , last , & n .Rhs [0 ], UintType )
2026
2088
} else if n .Op == ADD_ASSIGN || n .Op == SUB_ASSIGN || n .Op == MUL_ASSIGN || n .Op == QUO_ASSIGN || n .Op == REM_ASSIGN {
@@ -2281,10 +2343,15 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
2281
2343
vt := evalStaticTypeOf (store , last , vx )
2282
2344
sts [i ] = vt
2283
2345
}
2284
- } else {
2346
+ } else { // T is nil, n not const
2285
2347
// convert n.Value to default type.
2286
2348
for i , vx := range n .Values {
2287
- convertIfConst (store , last , vx )
2349
+ if cx , ok := vx .(* ConstExpr ); ok {
2350
+ convertConst (store , last , cx , nil )
2351
+ // convertIfConst(store, last, vx)
2352
+ } else {
2353
+ checkOrConvertType (store , last , & vx , nil , false )
2354
+ }
2288
2355
vt := evalStaticTypeOf (store , last , vx )
2289
2356
sts [i ] = vt
2290
2357
}
@@ -2840,9 +2907,25 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative
2840
2907
assertAssignableTo (cx .T , t , autoNative )
2841
2908
}
2842
2909
} else if bx , ok := (* x ).(* BinaryExpr ); ok && (bx .Op == SHL || bx .Op == SHR ) {
2843
- // "push" expected type into shift binary's left operand. recursively.
2844
- checkOrConvertType (store , last , & bx .Left , t , autoNative )
2845
- } else if * x != nil { // XXX if x != nil && t != nil {
2910
+ xt := evalStaticTypeOf (store , last , * x )
2911
+ if debug {
2912
+ debug .Printf ("shift, xt: %v, Op: %v, t: %v \n " , xt , bx .Op , t )
2913
+ }
2914
+ if isUntyped (xt ) {
2915
+ // check assignable first, see: types/shift_b6.gno
2916
+ assertAssignableTo (xt , t , autoNative )
2917
+
2918
+ if t == nil || t .Kind () == InterfaceKind {
2919
+ t = defaultTypeOf (xt )
2920
+ }
2921
+
2922
+ bx .assertShiftExprCompatible2 (t )
2923
+ checkOrConvertType (store , last , & bx .Left , t , autoNative )
2924
+ } else {
2925
+ assertAssignableTo (xt , t , autoNative )
2926
+ }
2927
+ return
2928
+ } else if * x != nil {
2846
2929
xt := evalStaticTypeOf (store , last , * x )
2847
2930
if t != nil {
2848
2931
assertAssignableTo (xt , t , autoNative )
@@ -2853,19 +2936,53 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative
2853
2936
switch bx .Op {
2854
2937
case ADD , SUB , MUL , QUO , REM , BAND , BOR , XOR ,
2855
2938
BAND_NOT , LAND , LOR :
2856
- // push t into bx.Left and bx.Right
2857
- checkOrConvertType (store , last , & bx .Left , t , autoNative )
2858
- checkOrConvertType (store , last , & bx .Right , t , autoNative )
2859
- return
2860
- case SHL , SHR :
2861
- // push t into bx.Left
2862
- checkOrConvertType (store , last , & bx .Left , t , autoNative )
2939
+ lt := evalStaticTypeOf (store , last , bx .Left )
2940
+ rt := evalStaticTypeOf (store , last , bx .Right )
2941
+ if t != nil {
2942
+ // push t into bx.Left and bx.Right
2943
+ checkOrConvertType (store , last , & bx .Left , t , autoNative )
2944
+ checkOrConvertType (store , last , & bx .Right , t , autoNative )
2945
+ return
2946
+ } else {
2947
+ if shouldSwapOnSpecificity (lt , rt ) {
2948
+ // e.g. 1.0<<s + 1
2949
+ // The expression '1.0<<s' does not trigger assertions of
2950
+ // incompatible types when evaluated alone.
2951
+ // However, when evaluating the full expression '1.0<<s + 1'
2952
+ // without a specific context type, '1.0<<s' is checked against
2953
+ // its default type, the BigDecKind, will trigger assertion failure.
2954
+ // so here in checkOrConvertType, shift expression is "finally" checked.
2955
+ checkOrConvertType (store , last , & bx .Left , lt , autoNative )
2956
+ checkOrConvertType (store , last , & bx .Right , lt , autoNative )
2957
+ } else {
2958
+ checkOrConvertType (store , last , & bx .Left , rt , autoNative )
2959
+ checkOrConvertType (store , last , & bx .Right , rt , autoNative )
2960
+ }
2961
+ }
2863
2962
return
2864
2963
case EQL , LSS , GTR , NEQ , LEQ , GEQ :
2865
- // do nothing
2964
+ lt := evalStaticTypeOf (store , last , bx .Left )
2965
+ rt := evalStaticTypeOf (store , last , bx .Right )
2966
+ if shouldSwapOnSpecificity (lt , rt ) {
2967
+ checkOrConvertType (store , last , & bx .Left , lt , autoNative )
2968
+ checkOrConvertType (store , last , & bx .Right , lt , autoNative )
2969
+ } else {
2970
+ checkOrConvertType (store , last , & bx .Left , rt , autoNative )
2971
+ checkOrConvertType (store , last , & bx .Right , rt , autoNative )
2972
+ }
2866
2973
default :
2867
2974
// do nothing
2868
2975
}
2976
+ } else if ux , ok := (* x ).(* UnaryExpr ); ok {
2977
+ xt := evalStaticTypeOf (store , last , * x )
2978
+ // check assignable first
2979
+ assertAssignableTo (xt , t , autoNative )
2980
+
2981
+ if t == nil || t .Kind () == InterfaceKind {
2982
+ t = defaultTypeOf (xt )
2983
+ }
2984
+ checkOrConvertType (store , last , & ux .X , t , autoNative )
2985
+ return
2869
2986
}
2870
2987
}
2871
2988
}
@@ -2891,9 +3008,6 @@ func convertType(store Store, last BlockNode, x *Expr, t Type) {
2891
3008
if t == nil {
2892
3009
t = defaultTypeOf (xt )
2893
3010
}
2894
- if debug {
2895
- debug .Printf ("default type of t: %v \n " , t )
2896
- }
2897
3011
// convert x to destination type t
2898
3012
doConvertType (store , last , x , t )
2899
3013
} else {
0 commit comments