tc_const.mx raw

   1  package types
   2  
   3  import (
   4  	"git.smesh.lol/moxie/pkg/mxutil"
   5  	"git.smesh.lol/moxie/pkg/syntax"
   6  	"git.smesh.lol/moxie/pkg/token"
   7  )
   8  
   9  func (c *Checker) checkConstGroup(decls []*syntax.ConstDecl) {
  10  	var prevType syntax.Expr
  11  	var prevValues syntax.Expr
  12  	for i, d := range decls {
  13  		typ := d.Type
  14  		vals := d.Values
  15  		if vals == nil {
  16  			typ = prevType
  17  			vals = prevValues
  18  		} else {
  19  			prevType = typ
  20  			prevValues = vals
  21  		}
  22  		c.checkConstDeclAt(d, typ, vals, int64(i))
  23  	}
  24  }
  25  
  26  func (c *Checker) checkConstDeclAt(d *syntax.ConstDecl, typExpr syntax.Expr, valExpr syntax.Expr, iotaVal int64) {
  27  	var typ Type
  28  	if typExpr != nil {
  29  		typ = c.resolveTypeExpr(typExpr)
  30  	}
  31  
  32  	var vals []ConstVal
  33  	if valExpr != nil {
  34  		vals = c.evalConstExprList(valExpr, iotaVal)
  35  	}
  36  
  37  	// When no explicit type and the value is a type conversion (CallExpr
  38  	// with a type name as Fun), infer the type from the conversion target.
  39  	// e.g. const EOF = errors.Const("EOF") -> type is errors.Const
  40  	var inferredTypes []Type
  41  	if typ == nil && valExpr != nil {
  42  		inferredTypes = c.inferConstTypeList(valExpr)
  43  	}
  44  
  45  	for i, name := range d.NameList {
  46  		if name.Value == "_" {
  47  			continue
  48  		}
  49  		obj, ok := c.pkg.Scope.Lookup(name.Value).(*TCConst)
  50  		if !ok {
  51  			continue
  52  		}
  53  		var cv ConstVal
  54  		if i < len(vals) {
  55  			cv = vals[i]
  56  		}
  57  		obj.Val = cv
  58  		if typ != nil {
  59  			obj.Typ = typ
  60  		} else if i < len(inferredTypes) && inferredTypes[i] != nil {
  61  			obj.Typ = inferredTypes[i]
  62  		} else if cv != nil {
  63  			obj.Typ = UntypedTypeOfCV(cv)
  64  		}
  65  		if c.info != nil {
  66  			c.info.Defs[name] = obj
  67  		}
  68  	}
  69  }
  70  
  71  func (c *Checker) inferConstTypeList(e syntax.Expr) (ts []Type) {
  72  	if l, ok := e.(*syntax.ListExpr); ok {
  73  		var out []Type
  74  		for _, el := range l.ElemList {
  75  			push(out, c.inferConstType(el))
  76  		}
  77  		return out
  78  	}
  79  	return []Type{c.inferConstType(e)}
  80  }
  81  
  82  func (c *Checker) inferConstType(e syntax.Expr) (t Type) {
  83  	if e == nil {
  84  		return nil
  85  	}
  86  	ce, ok := e.(*syntax.CallExpr)
  87  	if !ok {
  88  		return nil
  89  	}
  90  	if len(ce.ArgList) != 1 {
  91  		return nil
  92  	}
  93  	return c.resolveTypeExpr(ce.Fun)
  94  }
  95  
  96  func (c *Checker) evalConstExprList(e syntax.Expr, iotaVal int64) (cs []ConstVal) {
  97  	if l, ok := e.(*syntax.ListExpr); ok {
  98  		var out []ConstVal
  99  		for _, el := range l.ElemList {
 100  			cv := c.evalConst(el, iotaVal)
 101  			push(out, cv)
 102  		}
 103  		return out
 104  	}
 105  	v := c.evalConst(e, iotaVal)
 106  	return []ConstVal{v}
 107  }
 108  
 109  func (c *Checker) evalConst(e syntax.Expr, iotaVal int64) (cv ConstVal) {
 110  	if e == nil {
 111  		return nil
 112  	}
 113  	switch ex := e.(type) {
 114  	case *syntax.BasicLit:
 115  		return EvalBasicLitLocal(ex)
 116  	case *syntax.Name:
 117  		if ex.Value == "iota" {
 118  			return &ConstInt{V:iotaVal}
 119  		}
 120  		var obj Object
 121  		if c.localScope != nil {
 122  			_, obj = c.localScope.LookupParent(ex.Value)
 123  		}
 124  		if obj == nil {
 125  			_, obj = c.lookup(ex.Value, c.pkg.Scope)
 126  		}
 127  		if obj == nil {
 128  			mxutil.WriteStr(2, "  CONST-LOOKUP-FAIL name=" | ex.Value | " pkg=" | c.pkg.Path | "\n")
 129  			return nil
 130  		}
 131  		if k, matched := obj.(*TCConst); matched {
 132  			if k.Val == nil {
 133  				mxutil.WriteStr(2, "  CONST-REF-NIL name=" | ex.Value | " pkg=" | c.pkg.Path | "\n")
 134  			}
 135  			return k.Val
 136  		}
 137  		return nil
 138  	case *syntax.SelectorExpr:
 139  		if pkgName, matched := ex.X.(*syntax.Name); matched {
 140  			if _, imp := c.lookupType(pkgName.Value); imp != nil {
 141  				if pn, ok2 := imp.(*PkgName); ok2 && pn.Imported != nil {
 142  					if obj := pn.Imported.Scope.Lookup(ex.Sel.Value); obj != nil {
 143  						if k, ok3 := obj.(*TCConst); ok3 {
 144  							return k.Val
 145  						}
 146  					}
 147  				}
 148  			}
 149  		}
 150  		return nil
 151  	case *syntax.Operation:
 152  		return c.evalConstOp(ex, iotaVal)
 153  	case *syntax.ParenExpr:
 154  		return c.evalConst(ex.X, iotaVal)
 155  	case *syntax.CallExpr:
 156  		if id, matched := ex.Fun.(*syntax.Name); matched && id.Value == "len" && len(ex.ArgList) == 1 {
 157  			if lit, matched2 := ex.ArgList[0].(*syntax.BasicLit); matched2 && lit.Kind == token.StringLit {
 158  				lv := EvalBasicLitLocal(lit)
 159  				if cs2, matched3 := lv.(*ConstStr); matched3 {
 160  					return &ConstInt{V:int64(len(cs2.S))}
 161  				}
 162  			}
 163  			lenArg := c.evalConst(ex.ArgList[0], iotaVal)
 164  			if cs2, matched2 := lenArg.(*ConstStr); matched2 {
 165  				return &ConstInt{V:int64(len(cs2.S))}
 166  			}
 167  		}
 168  		if sel, matched := ex.Fun.(*syntax.SelectorExpr); matched {
 169  			if pkg, matched2 := sel.X.(*syntax.Name); matched2 && pkg.Value == "unsafe" {
 170  				switch sel.Sel.Value {
 171  				case "Sizeof", "Alignof", "Offsetof":
 172  					return &ConstInt{V:8}
 173  				}
 174  			}
 175  		}
 176  		if len(ex.ArgList) != 1 {
 177  			return nil
 178  		}
 179  		arg := c.evalConst(ex.ArgList[0], iotaVal)
 180  		if arg == nil {
 181  			return nil
 182  		}
 183  		targetType := c.resolveTypeExpr(ex.Fun)
 184  		if targetType == nil {
 185  			funName := "?"
 186  			if id, ok2 := ex.Fun.(*syntax.Name); ok2 {
 187  				funName = id.Value
 188  			}
 189  			mxutil.WriteStr(2, "  CONST-CONV-FAIL fun=" | funName | " pkg=" | c.pkg.Path | "\n")
 190  			return nil
 191  		}
 192  		return ConvertConstLocal(arg, targetType)
 193  	}
 194  	return nil
 195  }
 196  
 197  func EvalBasicLitLocal(e *syntax.BasicLit) (c ConstVal) {
 198  	switch e.Kind {
 199  	case token.IntLit:
 200  		n := ParseIntLocal(e.Value)
 201  		return &ConstInt{V:n}
 202  	case token.FloatLit:
 203  		f := parseFloatLocal(e.Value)
 204  		return &ConstFloat{V:f, Lit:e.Value}
 205  	case token.StringLit:
 206  		s := interpStringLocal(e.Value)
 207  		return &ConstStr{S:s}
 208  	case token.RuneLit:
 209  		s := interpStringLocal(e.Value)
 210  		if len(s) > 0 {
 211  			return &ConstInt{V:int64(decodeFirstRune(s))}
 212  		}
 213  		return &ConstInt{V:0}
 214  	}
 215  	return nil
 216  }
 217  
 218  func ParseIntLocal(s string) (n int64) {
 219  	if len(s) == 0 {
 220  		return 0
 221  	}
 222  	neg := false
 223  	i := 0
 224  	if s[0] == '-' {
 225  		neg = true
 226  		i = 1
 227  	} else if s[0] == '+' {
 228  		i = 1
 229  	}
 230  	base := int64(10)
 231  	if i < len(s)-1 && s[i] == '0' {
 232  		c := s[i+1]
 233  		if c == 'x' || c == 'X' {
 234  			base = 16
 235  			i += 2
 236  		} else if c == 'o' || c == 'O' {
 237  			base = 8
 238  			i += 2
 239  		} else if c == 'b' || c == 'B' {
 240  			base = 2
 241  			i += 2
 242  		} else if c >= '0' && c <= '7' {
 243  			base = 8
 244  			i += 1
 245  		}
 246  	}
 247  	for ; i < len(s); i++ {
 248  		ch := s[i]
 249  		if ch == '_' {
 250  			continue
 251  		}
 252  		var d int64
 253  		if ch >= '0' && ch <= '9' {
 254  			d = int64(ch - '0')
 255  		} else if ch >= 'a' && ch <= 'f' {
 256  			d = int64(ch-'a') + 10
 257  		} else if ch >= 'A' && ch <= 'F' {
 258  			d = int64(ch-'A') + 10
 259  		} else {
 260  			break
 261  		}
 262  		n = n*base + d
 263  	}
 264  	if neg {
 265  		return -n
 266  	}
 267  	return n
 268  }
 269  
 270  func parseFloatLocal(s string) (f float64) {
 271  	if len(s) == 0 {
 272  		return 0.0
 273  	}
 274  	neg := false
 275  	i := 0
 276  	if s[0] == '-' {
 277  		neg = true
 278  		i = 1
 279  	} else if s[0] == '+' {
 280  		i = 1
 281  	}
 282  	var intPart float64
 283  	for ; i < len(s); i++ {
 284  		ch := s[i]
 285  		if ch == '_' {
 286  			continue
 287  		}
 288  		if ch < '0' || ch > '9' {
 289  			break
 290  		}
 291  		intPart = intPart*10.0 + float64(ch-'0')
 292  	}
 293  	var fracPart float64
 294  	if i < len(s) && s[i] == '.' {
 295  		i++
 296  		divisor := 10.0
 297  		for ; i < len(s); i++ {
 298  			ch := s[i]
 299  			if ch == '_' {
 300  				continue
 301  			}
 302  			if ch < '0' || ch > '9' {
 303  				break
 304  			}
 305  			fracPart = fracPart + float64(ch-'0')/divisor
 306  			divisor = divisor * 10.0
 307  		}
 308  	}
 309  	result := intPart + fracPart
 310  	if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
 311  		i++
 312  		expNeg := false
 313  		if i < len(s) && s[i] == '-' {
 314  			expNeg = true
 315  			i++
 316  		} else if i < len(s) && s[i] == '+' {
 317  			i++
 318  		}
 319  		var exp int32
 320  		for ; i < len(s); i++ {
 321  			ch := s[i]
 322  			if ch < '0' || ch > '9' {
 323  				break
 324  			}
 325  			exp = exp*10 + int32(ch-'0')
 326  		}
 327  		mul := 1.0
 328  		for j := 0; j < exp; j++ {
 329  			mul = mul * 10.0
 330  		}
 331  		if expNeg {
 332  			result = result / mul
 333  		} else {
 334  			result = result * mul
 335  		}
 336  	}
 337  	if neg {
 338  		return -result
 339  	}
 340  	return result
 341  }
 342  
 343  func interpStringLocal(s string) (sv string) {
 344  	if len(s) < 2 {
 345  		return s
 346  	}
 347  	if s[0] == '`' {
 348  		return s[1 : len(s)-1]
 349  	}
 350  	quote := s[0]
 351  	if quote != '"' && quote != '\'' {
 352  		return s
 353  	}
 354  	s = s[1 : len(s)-1]
 355  	hasEsc := false
 356  	for i := 0; i < len(s); i++ {
 357  		if s[i] == '\\' {
 358  			hasEsc = true
 359  			break
 360  		}
 361  	}
 362  	if !hasEsc {
 363  		return s
 364  	}
 365  	var buf []byte
 366  	for i := 0; i < len(s); i++ {
 367  		if s[i] != '\\' {
 368  			push(buf, s[i])
 369  			continue
 370  		}
 371  		i++
 372  		if i >= len(s) {
 373  			break
 374  		}
 375  		switch s[i] {
 376  		case 'n':
 377  			push(buf, '\n')
 378  		case 't':
 379  			push(buf, '\t')
 380  		case 'r':
 381  			push(buf, '\r')
 382  		case '\\':
 383  			push(buf, '\\')
 384  		case '\'':
 385  			push(buf, '\'')
 386  		case '"':
 387  			push(buf, '"')
 388  		case '0':
 389  			push(buf, 0)
 390  		case 'a':
 391  			push(buf, '\a')
 392  		case 'b':
 393  			push(buf, '\b')
 394  		case 'f':
 395  			push(buf, '\f')
 396  		case 'v':
 397  			push(buf, '\v')
 398  		case 'x':
 399  			if i+2 < len(s) {
 400  				h := hexDigit(s[i+1])*16 + hexDigit(s[i+2])
 401  				push(buf, byte(h))
 402  				i += 2
 403  			}
 404  		case 'u':
 405  			if i+4 < len(s) {
 406  				r := rune(hexDigit(s[i+1]))*4096 + rune(hexDigit(s[i+2]))*256 + rune(hexDigit(s[i+3]))*16 + rune(hexDigit(s[i+4]))
 407  				buf = appendRuneUTF8(buf, r)
 408  				i += 4
 409  			}
 410  		case 'U':
 411  			if i+8 < len(s) {
 412  				var r rune
 413  				for j := 1; j <= 8; j++ {
 414  					r = r*16 + rune(hexDigit(s[i+j]))
 415  				}
 416  				buf = appendRuneUTF8(buf, r)
 417  				i += 8
 418  			}
 419  		default:
 420  			if s[i] >= '0' && s[i] <= '7' {
 421  				v := int32(s[i] - '0')
 422  				if i+1 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' {
 423  					v = v*8 + int32(s[i+1]-'0')
 424  					i++
 425  					if i+1 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' {
 426  						v = v*8 + int32(s[i+1]-'0')
 427  						i++
 428  					}
 429  				}
 430  				push(buf, byte(v))
 431  			} else {
 432  				push(buf, s[i])
 433  			}
 434  		}
 435  	}
 436  	return string(buf)
 437  }
 438  
 439  func hexDigit(c byte) (n int32) {
 440  	if c >= '0' && c <= '9' {
 441  		return int32(c - '0')
 442  	}
 443  	if c >= 'a' && c <= 'f' {
 444  		return int32(c-'a') + 10
 445  	}
 446  	if c >= 'A' && c <= 'F' {
 447  		return int32(c-'A') + 10
 448  	}
 449  	return 0
 450  }
 451  
 452  func appendRuneUTF8(buf []byte, r rune) (buf2 []byte) {
 453  	if r < 0x80 {
 454  		push(buf, byte(r))
 455  		return buf
 456  	}
 457  	if r < 0x800 {
 458  		push(buf, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F)))
 459  		return buf
 460  	}
 461  	if r < 0x10000 {
 462  		push(buf, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
 463  		return buf
 464  	}
 465  	push(buf, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
 466  	return buf
 467  }
 468  
 469  func (c *Checker) evalConstOp(e *syntax.Operation, iotaVal int64) (cv ConstVal) {
 470  	if e.Y == nil {
 471  		xu := c.evalConst(e.X, iotaVal)
 472  		if xu == nil {
 473  			mxutil.WriteStr(2, "  CONSTOP-UNARY-NIL-X pkg=" | c.pkg.Path | "\n")
 474  			return nil
 475  		}
 476  		r := EvalUnaryLocal(e.Op, xu)
 477  		if r == nil {
 478  			mxutil.WriteStr(2, "  CONSTOP-UNARY-NIL-R pkg=" | c.pkg.Path | " x=" | xu.String() | "\n")
 479  		}
 480  		// ^x on a typed operand must be masked to the operand's width: the
 481  		// arbitrary-precision result (-x-1) is only correct for untyped
 482  		// constants.  Without this, uint64(^someUint32Const) sign-extends
 483  		// the stored negative value to 0xffffffffXXXXXXXX.
 484  		if r != nil && e.Op == token.Xor {
 485  			if b := c.constExprBasic(e.X); b != nil {
 486  				r = MaskConstToBasic(r, b)
 487  			}
 488  		}
 489  		return r
 490  	}
 491  	x := c.evalConst(e.X, iotaVal)
 492  	y := c.evalConst(e.Y, iotaVal)
 493  	if x == nil || y == nil {
 494  		return nil
 495  	}
 496  	return EvalBinaryLocal(e.Op, x, y)
 497  }
 498  
 499  func EvalUnaryLocal(op token.Operator, x ConstVal) (c ConstVal) {
 500  	switch op {
 501  	case token.Add:
 502  		return x
 503  	case token.Sub:
 504  		if ci, ok := x.(*ConstInt); ok {
 505  			return &ConstInt{V:-ci.V}
 506  		}
 507  		if cf, ok := x.(*ConstFloat); ok {
 508  			neg := ""
 509  			if cf.Lit != "" {
 510  				neg = "-" | cf.Lit
 511  			}
 512  			return &ConstFloat{V:-cf.V, Lit:neg}
 513  		}
 514  	case token.Xor:
 515  		if ci, ok := x.(*ConstInt); ok {
 516  			return &ConstInt{V:^ci.V}
 517  		}
 518  	case token.Not:
 519  		if cb, ok := x.(*ConstBool); ok {
 520  			return &ConstBool{V:!cb.V}
 521  		}
 522  	}
 523  	return nil
 524  }
 525  
 526  func EvalBinaryLocal(op token.Operator, x ConstVal, y ConstVal) (c ConstVal) {
 527  	switch op {
 528  	case token.Add:
 529  		if xi, ok := x.(*ConstInt); ok {
 530  			return &ConstInt{V:xi.V + cvInt(y)}
 531  		}
 532  		if xf, ok := x.(*ConstFloat); ok {
 533  			return &ConstFloat{V:xf.V + cvFloat(y)}
 534  		}
 535  		if xs, ok := x.(*ConstStr); ok {
 536  			return &ConstStr{S:xs.S | cvStr(y)}
 537  		}
 538  	case token.Sub:
 539  		if xi, ok := x.(*ConstInt); ok {
 540  			return &ConstInt{V:xi.V - cvInt(y)}
 541  		}
 542  		if xf, ok := x.(*ConstFloat); ok {
 543  			return &ConstFloat{V:xf.V - cvFloat(y)}
 544  		}
 545  	case token.Mul:
 546  		if xi, ok := x.(*ConstInt); ok {
 547  			return &ConstInt{V:xi.V * cvInt(y)}
 548  		}
 549  		if xf, ok := x.(*ConstFloat); ok {
 550  			return &ConstFloat{V:xf.V * cvFloat(y)}
 551  		}
 552  	case token.Div:
 553  		if xi, ok := x.(*ConstInt); ok {
 554  			d := cvInt(y)
 555  			if d == 0 {
 556  				return &ConstInt{V:0}
 557  			}
 558  			return &ConstInt{V:xi.V / d}
 559  		}
 560  		if xf, ok := x.(*ConstFloat); ok {
 561  			d := cvFloat(y)
 562  			if d == 0.0 {
 563  				return &ConstFloat{V:0.0}
 564  			}
 565  			return &ConstFloat{V:xf.V / d}
 566  		}
 567  	case token.Rem:
 568  		if xi, ok := x.(*ConstInt); ok {
 569  			d := cvInt(y)
 570  			if d == 0 {
 571  				return &ConstInt{V:0}
 572  			}
 573  			return &ConstInt{V:xi.V % d}
 574  		}
 575  	case token.And:
 576  		if xi, ok := x.(*ConstInt); ok {
 577  			return &ConstInt{V:xi.V & cvInt(y)}
 578  		}
 579  	case token.Or:
 580  		if xi, ok := x.(*ConstInt); ok {
 581  			return &ConstInt{V:xi.V | cvInt(y)}
 582  		}
 583  		if xs, ok := x.(*ConstStr); ok {
 584  			return &ConstStr{S:xs.S | cvStr(y)}
 585  		}
 586  	case token.Xor:
 587  		if xi, ok := x.(*ConstInt); ok {
 588  			return &ConstInt{V:xi.V ^ cvInt(y)}
 589  		}
 590  	case token.Shl:
 591  		if xi, ok := x.(*ConstInt); ok {
 592  			shift := uint32(cvInt(y))
 593  			return &ConstInt{V:xi.V << shift}
 594  		}
 595  	case token.Shr:
 596  		if xi, ok := x.(*ConstInt); ok {
 597  			shift := uint32(cvInt(y))
 598  			return &ConstInt{V:xi.V >> shift}
 599  		}
 600  	case token.AndNot:
 601  		if xi, ok := x.(*ConstInt); ok {
 602  			return &ConstInt{V:xi.V &^ cvInt(y)}
 603  		}
 604  	case token.Eql:
 605  		return &ConstBool{V:constEqual(x, y)}
 606  	case token.Neq:
 607  		return &ConstBool{V:!constEqual(x, y)}
 608  	case token.Lss:
 609  		return &ConstBool{V:constLess(x, y)}
 610  	case token.Leq:
 611  		return &ConstBool{V:constLess(x, y) || constEqual(x, y)}
 612  	case token.Gtr:
 613  		return &ConstBool{V:constLess(y, x)}
 614  	case token.Geq:
 615  		return &ConstBool{V:constLess(y, x) || constEqual(x, y)}
 616  	case token.OrOr:
 617  		xb, xok := x.(*ConstBool)
 618  		yb, yok := y.(*ConstBool)
 619  		if xok && yok {
 620  			return &ConstBool{V:xb.V || yb.V}
 621  		}
 622  	case token.AndAnd:
 623  		xb, xok := x.(*ConstBool)
 624  		yb, yok := y.(*ConstBool)
 625  		if xok && yok {
 626  			return &ConstBool{V:xb.V && yb.V}
 627  		}
 628  	}
 629  	return nil
 630  }
 631  
 632  func constEqual(x ConstVal, y ConstVal) (eq bool) {
 633  	if xi, matched := x.(*ConstInt); matched {
 634  		return xi.V == cvInt(y)
 635  	}
 636  	if xf, matched := x.(*ConstFloat); matched {
 637  		return xf.V == cvFloat(y)
 638  	}
 639  	if xs, matched := x.(*ConstStr); matched {
 640  		return xs.S == cvStr(y)
 641  	}
 642  	if xb, matched := x.(*ConstBool); matched {
 643  		if yb, matched2 := y.(*ConstBool); matched2 {
 644  			return xb.V == yb.V
 645  		}
 646  	}
 647  	return false
 648  }
 649  
 650  func constLess(x ConstVal, y ConstVal) (lt bool) {
 651  	if xi, matched := x.(*ConstInt); matched {
 652  		return xi.V < cvInt(y)
 653  	}
 654  	if xf, matched := x.(*ConstFloat); matched {
 655  		return xf.V < cvFloat(y)
 656  	}
 657  	if xs, matched := x.(*ConstStr); matched {
 658  		return xs.S < cvStr(y)
 659  	}
 660  	return false
 661  }
 662  
 663  func ConvertConstLocal(v ConstVal, target Type) (c ConstVal) {
 664  	b, isBasic := SafeUnderlying(target).(*Basic)
 665  	if !isBasic {
 666  		return v
 667  	}
 668  	switch {
 669  	case b.Info&IsInteger != 0:
 670  		iv := cvInt(v)
 671  		return MaskConstToBasic(&ConstInt{V:iv}, b)
 672  	case b.Info&IsFloat != 0:
 673  		fv := cvFloat(v)
 674  		if cf, matched := v.(*ConstFloat); matched {
 675  			return &ConstFloat{V:fv, Lit:cf.Lit}
 676  		}
 677  		return &ConstFloat{V:fv}
 678  	case b.Info&IsString != 0:
 679  		if cvKind(v) == 3 {
 680  			n := cvInt(v)
 681  			return &ConstStr{S:runeToStr(rune(n))}
 682  		}
 683  		return v
 684  	}
 685  	return v
 686  }
 687  
 688  // MaskConstToBasic truncates a ConstInt to the width and signedness of the
 689  // given sized basic integer type.  Untyped and non-integer types pass
 690  // through unchanged.
 691  func MaskConstToBasic(v ConstVal, b *Basic) (c ConstVal) {
 692  	ci, ok := v.(*ConstInt)
 693  	if !ok || b == nil || b.Info&IsInteger == 0 || b.Info&IsUntyped != 0 {
 694  		return v
 695  	}
 696  	n := ci.V
 697  	switch b.Kind {
 698  	case Int8:
 699  		n = int64(int8(n))
 700  	case Int16:
 701  		n = int64(int16(n))
 702  	case Int32:
 703  		n = int64(int32(n))
 704  	case Uint8:
 705  		n = int64(uint8(n))
 706  	case Uint16:
 707  		n = int64(uint16(n))
 708  	case Uint32:
 709  		n = int64(uint32(n))
 710  	case Int64, Uint64:
 711  		// 64-bit: int64 bit pattern is already exact.
 712  	default:
 713  		return v
 714  	}
 715  	return &ConstInt{V:n}
 716  }
 717  
 718  // constExprBasic resolves the basic type of a constant expression, used to
 719  // apply width masking to typed constant operations.  Returns nil when the
 720  // type cannot be determined (untyped literals and untracked forms).
 721  func (c *Checker) constExprBasic(e syntax.Expr) (b *Basic) {
 722  	switch ex := e.(type) {
 723  	case *syntax.Name:
 724  		var obj Object
 725  		if c.localScope != nil {
 726  			_, obj = c.localScope.LookupParent(ex.Value)
 727  		}
 728  		if obj == nil {
 729  			_, obj = c.lookup(ex.Value, c.pkg.Scope)
 730  		}
 731  		if k, matched := obj.(*TCConst); matched && k.Typ != nil {
 732  			if bb, matched2 := SafeUnderlying(k.Typ).(*Basic); matched2 {
 733  				return bb
 734  			}
 735  		}
 736  	case *syntax.SelectorExpr:
 737  		if pkgName, matched := ex.X.(*syntax.Name); matched {
 738  			if _, imp := c.lookupType(pkgName.Value); imp != nil {
 739  				if pn, matched2 := imp.(*PkgName); matched2 && pn.Imported != nil {
 740  					if obj := pn.Imported.Scope.Lookup(ex.Sel.Value); obj != nil {
 741  						if k, matched3 := obj.(*TCConst); matched3 && k.Typ != nil {
 742  							if bb, matched4 := SafeUnderlying(k.Typ).(*Basic); matched4 {
 743  								return bb
 744  							}
 745  						}
 746  					}
 747  				}
 748  			}
 749  		}
 750  	case *syntax.ParenExpr:
 751  		return c.constExprBasic(ex.X)
 752  	case *syntax.CallExpr:
 753  		if t := c.resolveTypeExpr(ex.Fun); t != nil {
 754  			if bb, matched := SafeUnderlying(t).(*Basic); matched {
 755  				return bb
 756  			}
 757  		}
 758  	case *syntax.Operation:
 759  		if bb := c.constExprBasic(ex.X); bb != nil && bb.Info&IsUntyped == 0 {
 760  			return bb
 761  		}
 762  		if ex.Y != nil {
 763  			return c.constExprBasic(ex.Y)
 764  		}
 765  	}
 766  	return nil
 767  }
 768  
 769  func UntypedTypeOfCV(v ConstVal) (t Type) {
 770  	switch cvKind(v) {
 771  	case 1:
 772  		return Typ[UntypedBool]
 773  	case 3:
 774  		return Typ[UntypedInt]
 775  	case 4:
 776  		return Typ[UntypedFloat]
 777  	case 2:
 778  		return Typ[UntypedString]
 779  	}
 780  	return nil
 781  }
 782  
 783  func cvKind(val ConstVal) (n int32) {
 784  	switch val.(type) {
 785  	case *ConstBool:
 786  		return 1
 787  	case *ConstStr:
 788  		return 2
 789  	case *ConstInt:
 790  		return 3
 791  	case *ConstFloat:
 792  		return 4
 793  	case *ConstNil:
 794  		return 0
 795  	}
 796  	return 0
 797  }
 798  
 799  func constInt64CV(v ConstVal) (n int64, valid bool) {
 800  	if v == nil || cvKind(v) != 3 {
 801  		return 0, false
 802  	}
 803  	if ci, matched := v.(*ConstInt); matched {
 804  		return ci.V, true
 805  	}
 806  	return 0, false
 807  }
 808  
 809  func (c *Checker) IsConstExpr(e syntax.Expr) (ok bool) {
 810  	return c.evalConst(e, 0) != nil
 811  }
 812  
 813  func (c *Checker) evalArrayLen(e syntax.Expr) (n int64) {
 814  	v := c.evalConst(e, 0)
 815  	if v == nil {
 816  		return 0
 817  	}
 818  	n, _ = constInt64CV(v)
 819  	return n
 820  }
 821  
 822  func cvInt(v ConstVal) (n int64) {
 823  	if ci, ok := v.(*ConstInt); ok {
 824  		return ci.V
 825  	}
 826  	if cf, ok := v.(*ConstFloat); ok {
 827  		return int64(cf.V)
 828  	}
 829  	return 0
 830  }
 831  
 832  func cvFloat(v ConstVal) (f float64) {
 833  	if cf, ok := v.(*ConstFloat); ok {
 834  		return cf.V
 835  	}
 836  	if ci, ok := v.(*ConstInt); ok {
 837  		return float64(ci.V)
 838  	}
 839  	return 0
 840  }
 841  
 842  func cvStr(v ConstVal) (s string) {
 843  	if cs, ok := v.(*ConstStr); ok {
 844  		return cs.S
 845  	}
 846  	return ""
 847  }
 848  
 849  func decodeFirstRune(s string) (n int32) {
 850  	b := s[0]
 851  	if b < 0x80 {
 852  		return int32(b)
 853  	}
 854  	if b < 0xC0 {
 855  		return int32(b)
 856  	}
 857  	if b < 0xE0 && len(s) >= 2 {
 858  		return int32(b&0x1F)<<6 | int32(s[1]&0x3F)
 859  	}
 860  	if b < 0xF0 && len(s) >= 3 {
 861  		return int32(b&0x0F)<<12 | int32(s[1]&0x3F)<<6 | int32(s[2]&0x3F)
 862  	}
 863  	if len(s) >= 4 {
 864  		return int32(b&0x07)<<18 | int32(s[1]&0x3F)<<12 | int32(s[2]&0x3F)<<6 | int32(s[3]&0x3F)
 865  	}
 866  	return int32(b)
 867  }
 868  
 869  func runeToStr(r rune) (s string) {
 870  	if r < 0 || r > 0x10FFFF {
 871  		r = 0xFFFD
 872  	}
 873  	var out []byte
 874  	if r <= 0x7F {
 875  		push(out, byte(r))
 876  	} else if r <= 0x7FF {
 877  		push(out, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F)))
 878  	} else if r <= 0xFFFF {
 879  		push(out, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
 880  	} else {
 881  		push(out, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
 882  	}
 883  	return string(out)
 884  }
 885