github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/typecheck/const.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package typecheck 6 7 import ( 8 "fmt" 9 "go/constant" 10 "go/token" 11 "math" 12 "math/big" 13 "unicode" 14 15 "github.com/go-asm/go/cmd/compile/base" 16 "github.com/go-asm/go/cmd/compile/ir" 17 "github.com/go-asm/go/cmd/compile/types" 18 ) 19 20 func roundFloat(v constant.Value, sz int64) constant.Value { 21 switch sz { 22 case 4: 23 f, _ := constant.Float32Val(v) 24 return makeFloat64(float64(f)) 25 case 8: 26 f, _ := constant.Float64Val(v) 27 return makeFloat64(f) 28 } 29 base.Fatalf("unexpected size: %v", sz) 30 panic("unreachable") 31 } 32 33 // truncate float literal fv to 32-bit or 64-bit precision 34 // according to type; return truncated value. 35 func truncfltlit(v constant.Value, t *types.Type) constant.Value { 36 if t.IsUntyped() { 37 return v 38 } 39 40 return roundFloat(v, t.Size()) 41 } 42 43 // truncate Real and Imag parts of Mpcplx to 32-bit or 64-bit 44 // precision, according to type; return truncated value. In case of 45 // overflow, calls Errorf but does not truncate the input value. 46 func trunccmplxlit(v constant.Value, t *types.Type) constant.Value { 47 if t.IsUntyped() { 48 return v 49 } 50 51 fsz := t.Size() / 2 52 return makeComplex(roundFloat(constant.Real(v), fsz), roundFloat(constant.Imag(v), fsz)) 53 } 54 55 // TODO(mdempsky): Replace these with better APIs. 56 func convlit(n ir.Node, t *types.Type) ir.Node { return convlit1(n, t, false, nil) } 57 func DefaultLit(n ir.Node, t *types.Type) ir.Node { return convlit1(n, t, false, nil) } 58 59 // convlit1 converts an untyped expression n to type t. If n already 60 // has a type, convlit1 has no effect. 61 // 62 // For explicit conversions, t must be non-nil, and integer-to-string 63 // conversions are allowed. 64 // 65 // For implicit conversions (e.g., assignments), t may be nil; if so, 66 // n is converted to its default type. 67 // 68 // If there's an error converting n to t, context is used in the error 69 // message. 70 func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir.Node { 71 if explicit && t == nil { 72 base.Fatalf("explicit conversion missing type") 73 } 74 if t != nil && t.IsUntyped() { 75 base.Fatalf("bad conversion to untyped: %v", t) 76 } 77 78 if n == nil || n.Type() == nil { 79 // Allow sloppy callers. 80 return n 81 } 82 if !n.Type().IsUntyped() { 83 // Already typed; nothing to do. 84 return n 85 } 86 87 // Nil is technically not a constant, so handle it specially. 88 if n.Type().Kind() == types.TNIL { 89 if n.Op() != ir.ONIL { 90 base.Fatalf("unexpected op: %v (%v)", n, n.Op()) 91 } 92 n = ir.Copy(n) 93 if t == nil { 94 base.Fatalf("use of untyped nil") 95 } 96 97 if !t.HasNil() { 98 // Leave for caller to handle. 99 return n 100 } 101 102 n.SetType(t) 103 return n 104 } 105 106 if t == nil || !ir.OKForConst[t.Kind()] { 107 t = defaultType(n.Type()) 108 } 109 110 switch n.Op() { 111 default: 112 base.Fatalf("unexpected untyped expression: %v", n) 113 114 case ir.OLITERAL: 115 v := ConvertVal(n.Val(), t, explicit) 116 if v.Kind() == constant.Unknown { 117 n = ir.NewConstExpr(n.Val(), n) 118 break 119 } 120 n = ir.NewConstExpr(v, n) 121 n.SetType(t) 122 return n 123 124 case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.OREAL, ir.OIMAG: 125 ot := operandType(n.Op(), t) 126 if ot == nil { 127 n = DefaultLit(n, nil) 128 break 129 } 130 131 n := n.(*ir.UnaryExpr) 132 n.X = convlit(n.X, ot) 133 if n.X.Type() == nil { 134 n.SetType(nil) 135 return n 136 } 137 n.SetType(t) 138 return n 139 140 case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT, ir.OOROR, ir.OANDAND, ir.OCOMPLEX: 141 ot := operandType(n.Op(), t) 142 if ot == nil { 143 n = DefaultLit(n, nil) 144 break 145 } 146 147 var l, r ir.Node 148 switch n := n.(type) { 149 case *ir.BinaryExpr: 150 n.X = convlit(n.X, ot) 151 n.Y = convlit(n.Y, ot) 152 l, r = n.X, n.Y 153 case *ir.LogicalExpr: 154 n.X = convlit(n.X, ot) 155 n.Y = convlit(n.Y, ot) 156 l, r = n.X, n.Y 157 } 158 159 if l.Type() == nil || r.Type() == nil { 160 n.SetType(nil) 161 return n 162 } 163 if !types.Identical(l.Type(), r.Type()) { 164 base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type()) 165 n.SetType(nil) 166 return n 167 } 168 169 n.SetType(t) 170 return n 171 172 case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: 173 n := n.(*ir.BinaryExpr) 174 if !t.IsBoolean() { 175 break 176 } 177 n.SetType(t) 178 return n 179 180 case ir.OLSH, ir.ORSH: 181 n := n.(*ir.BinaryExpr) 182 n.X = convlit1(n.X, t, explicit, nil) 183 n.SetType(n.X.Type()) 184 if n.Type() != nil && !n.Type().IsInteger() { 185 base.Errorf("invalid operation: %v (shift of type %v)", n, n.Type()) 186 n.SetType(nil) 187 } 188 return n 189 } 190 191 if explicit { 192 base.Fatalf("cannot convert %L to type %v", n, t) 193 } else if context != nil { 194 base.Fatalf("cannot use %L as type %v in %s", n, t, context()) 195 } else { 196 base.Fatalf("cannot use %L as type %v", n, t) 197 } 198 199 n.SetType(nil) 200 return n 201 } 202 203 func operandType(op ir.Op, t *types.Type) *types.Type { 204 switch op { 205 case ir.OCOMPLEX: 206 if t.IsComplex() { 207 return types.FloatForComplex(t) 208 } 209 case ir.OREAL, ir.OIMAG: 210 if t.IsFloat() { 211 return types.ComplexForFloat(t) 212 } 213 default: 214 if okfor[op][t.Kind()] { 215 return t 216 } 217 } 218 return nil 219 } 220 221 // ConvertVal converts v into a representation appropriate for t. If 222 // no such representation exists, it returns constant.MakeUnknown() 223 // instead. 224 // 225 // If explicit is true, then conversions from integer to string are 226 // also allowed. 227 func ConvertVal(v constant.Value, t *types.Type, explicit bool) constant.Value { 228 switch ct := v.Kind(); ct { 229 case constant.Bool: 230 if t.IsBoolean() { 231 return v 232 } 233 234 case constant.String: 235 if t.IsString() { 236 return v 237 } 238 239 case constant.Int: 240 if explicit && t.IsString() { 241 return tostr(v) 242 } 243 fallthrough 244 case constant.Float, constant.Complex: 245 switch { 246 case t.IsInteger(): 247 v = toint(v) 248 return v 249 case t.IsFloat(): 250 v = toflt(v) 251 v = truncfltlit(v, t) 252 return v 253 case t.IsComplex(): 254 v = tocplx(v) 255 v = trunccmplxlit(v, t) 256 return v 257 } 258 } 259 260 return constant.MakeUnknown() 261 } 262 263 func tocplx(v constant.Value) constant.Value { 264 return constant.ToComplex(v) 265 } 266 267 func toflt(v constant.Value) constant.Value { 268 if v.Kind() == constant.Complex { 269 v = constant.Real(v) 270 } 271 272 return constant.ToFloat(v) 273 } 274 275 func toint(v constant.Value) constant.Value { 276 if v.Kind() == constant.Complex { 277 v = constant.Real(v) 278 } 279 280 if v := constant.ToInt(v); v.Kind() == constant.Int { 281 return v 282 } 283 284 // The value of v cannot be represented as an integer; 285 // so we need to print an error message. 286 // Unfortunately some float values cannot be 287 // reasonably formatted for inclusion in an error 288 // message (example: 1 + 1e-100), so first we try to 289 // format the float; if the truncation resulted in 290 // something that looks like an integer we omit the 291 // value from the error message. 292 // (See issue #11371). 293 f := ir.BigFloat(v) 294 if f.MantExp(nil) > 2*ir.ConstPrec { 295 base.Errorf("integer too large") 296 } else { 297 var t big.Float 298 t.Parse(fmt.Sprint(v), 0) 299 if t.IsInt() { 300 base.Errorf("constant truncated to integer") 301 } else { 302 base.Errorf("constant %v truncated to integer", v) 303 } 304 } 305 306 // Prevent follow-on errors. 307 return constant.MakeUnknown() 308 } 309 310 func tostr(v constant.Value) constant.Value { 311 if v.Kind() == constant.Int { 312 r := unicode.ReplacementChar 313 if x, ok := constant.Uint64Val(v); ok && x <= unicode.MaxRune { 314 r = rune(x) 315 } 316 v = constant.MakeString(string(r)) 317 } 318 return v 319 } 320 321 func makeFloat64(f float64) constant.Value { 322 if math.IsInf(f, 0) { 323 base.Fatalf("infinity is not a valid constant") 324 } 325 return constant.MakeFloat64(f) 326 } 327 328 func makeComplex(real, imag constant.Value) constant.Value { 329 return constant.BinaryOp(constant.ToFloat(real), token.ADD, constant.MakeImag(constant.ToFloat(imag))) 330 } 331 332 // DefaultLit on both nodes simultaneously; 333 // if they're both ideal going in they better 334 // get the same type going out. 335 // force means must assign concrete (non-ideal) type. 336 // The results of defaultlit2 MUST be assigned back to l and r, e.g. 337 // 338 // n.Left, n.Right = defaultlit2(n.Left, n.Right, force) 339 func defaultlit2(l ir.Node, r ir.Node, force bool) (ir.Node, ir.Node) { 340 if l.Type() == nil || r.Type() == nil { 341 return l, r 342 } 343 344 if !l.Type().IsInterface() && !r.Type().IsInterface() { 345 // Can't mix bool with non-bool, string with non-string. 346 if l.Type().IsBoolean() != r.Type().IsBoolean() { 347 return l, r 348 } 349 if l.Type().IsString() != r.Type().IsString() { 350 return l, r 351 } 352 } 353 354 if !l.Type().IsUntyped() { 355 r = convlit(r, l.Type()) 356 return l, r 357 } 358 359 if !r.Type().IsUntyped() { 360 l = convlit(l, r.Type()) 361 return l, r 362 } 363 364 if !force { 365 return l, r 366 } 367 368 // Can't mix nil with anything untyped. 369 if ir.IsNil(l) || ir.IsNil(r) { 370 return l, r 371 } 372 t := defaultType(mixUntyped(l.Type(), r.Type())) 373 l = convlit(l, t) 374 r = convlit(r, t) 375 return l, r 376 } 377 378 func mixUntyped(t1, t2 *types.Type) *types.Type { 379 if t1 == t2 { 380 return t1 381 } 382 383 rank := func(t *types.Type) int { 384 switch t { 385 case types.UntypedInt: 386 return 0 387 case types.UntypedRune: 388 return 1 389 case types.UntypedFloat: 390 return 2 391 case types.UntypedComplex: 392 return 3 393 } 394 base.Fatalf("bad type %v", t) 395 panic("unreachable") 396 } 397 398 if rank(t2) > rank(t1) { 399 return t2 400 } 401 return t1 402 } 403 404 func defaultType(t *types.Type) *types.Type { 405 if !t.IsUntyped() || t.Kind() == types.TNIL { 406 return t 407 } 408 409 switch t { 410 case types.UntypedBool: 411 return types.Types[types.TBOOL] 412 case types.UntypedString: 413 return types.Types[types.TSTRING] 414 case types.UntypedInt: 415 return types.Types[types.TINT] 416 case types.UntypedRune: 417 return types.RuneType 418 case types.UntypedFloat: 419 return types.Types[types.TFLOAT64] 420 case types.UntypedComplex: 421 return types.Types[types.TCOMPLEX128] 422 } 423 424 base.Fatalf("bad type %v", t) 425 return nil 426 } 427 428 // IndexConst checks if Node n contains a constant expression 429 // representable as a non-negative int and returns its value. 430 // If n is not a constant expression, not representable as an 431 // integer, or negative, it returns -1. If n is too large, it 432 // returns -2. 433 func IndexConst(n ir.Node) int64 { 434 if n.Op() != ir.OLITERAL { 435 return -1 436 } 437 if !n.Type().IsInteger() && n.Type().Kind() != types.TIDEAL { 438 return -1 439 } 440 441 v := toint(n.Val()) 442 if v.Kind() != constant.Int || constant.Sign(v) < 0 { 443 return -1 444 } 445 if ir.ConstOverflow(v, types.Types[types.TINT]) { 446 return -2 447 } 448 return ir.IntVal(types.Types[types.TINT], v) 449 } 450 451 // callOrChan reports whether n is a call or channel operation. 452 func callOrChan(n ir.Node) bool { 453 switch n.Op() { 454 case ir.OAPPEND, 455 ir.OCALL, 456 ir.OCALLFUNC, 457 ir.OCALLINTER, 458 ir.OCALLMETH, 459 ir.OCAP, 460 ir.OCLEAR, 461 ir.OCLOSE, 462 ir.OCOMPLEX, 463 ir.OCOPY, 464 ir.ODELETE, 465 ir.OIMAG, 466 ir.OLEN, 467 ir.OMAKE, 468 ir.OMAX, 469 ir.OMIN, 470 ir.ONEW, 471 ir.OPANIC, 472 ir.OPRINT, 473 ir.OPRINTLN, 474 ir.OREAL, 475 ir.ORECOVER, 476 ir.ORECOVERFP, 477 ir.ORECV, 478 ir.OUNSAFEADD, 479 ir.OUNSAFESLICE, 480 ir.OUNSAFESLICEDATA, 481 ir.OUNSAFESTRING, 482 ir.OUNSAFESTRINGDATA: 483 return true 484 } 485 return false 486 }