CTCPLX
CTSTR
CTBOOL
- CTNIL
)
type Val struct {
// *Mpflt float when Ctype() == CTFLT
// *Mpcplx pair of floats when Ctype() == CTCPLX
// string string when Ctype() == CTSTR
- // *Nilval when Ctype() == CTNIL
U interface{}
}
panic("unreachable")
case nil:
return CTxxx
- case *NilVal:
- return CTNIL
case bool:
return CTBOOL
case *Mpint:
default:
Fatalf("unexpected Ctype for %T", a.U)
panic("unreachable")
- case *NilVal:
- return true
case bool:
y := b.U.(bool)
return x == y
default:
Fatalf("unexpected Interface for %T", v.U)
panic("unreachable")
- case *NilVal:
- return nil
case bool, string:
return x
case *Mpint:
}
}
-type NilVal struct{}
-
// Int64Val returns n as an int64.
// n must be an integer or rune constant.
func (n *Node) Int64Val() int64 {
return n
}
- if n.Op == OLITERAL {
+ if n.Op == OLITERAL || n.Op == ONIL {
// Can't always set n.Type directly on OLITERAL nodes.
// See discussion on CL 20813.
n = n.rawcopy()
// Nil is technically not a constant, so handle it specially.
if n.Type.Etype == TNIL {
+ if n.Op != ONIL {
+ Fatalf("unexpected op: %v (%v)", n, n.Op)
+ }
if t == nil {
yyerror("use of untyped nil")
n.SetDiag(true)
return types.UntypedFloat
case CTCPLX:
return types.UntypedComplex
- case CTNIL:
- return types.Types[TNIL]
}
Fatalf("unexpected Ctype: %v", ct)
return nil
// Expressions derived from nil, like string([]byte(nil)), while they
// may be known at compile time, are not Go language constants.
func (n *Node) isGoConst() bool {
- return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
+ return n.Op == OLITERAL
}
func hascallchan(n *Node) bool {
// We're ignoring things like division by zero, index out of range,
// and nil pointer dereference here.
switch n.Op {
- case ONAME, OCLOSUREVAR, OLITERAL:
+ case ONAME, OCLOSUREVAR, OLITERAL, ONIL:
return false
// Left+Right group.
default:
Fatalf("unexpected expr: %v", n)
- case OLITERAL, OGETG, OCLOSUREVAR, OTYPE:
+ case OLITERAL, ONIL, OGETG, OCLOSUREVAR, OTYPE:
// nop
case ONAME:
case bool:
fmt.Fprint(s, u)
- case *NilVal:
- fmt.Fprint(s, "nil")
-
default:
fmt.Fprintf(s, "<ctype=%d>", v.Ctype())
}
OMAPLIT: 8,
ONAME: 8,
ONEW: 8,
+ ONIL: 8,
ONONAME: 8,
OOFFSETOF: 8,
OPACK: 8,
case OPAREN:
mode.Fprintf(s, "(%v)", n.Left)
+ case ONIL:
+ fmt.Fprint(s, "nil")
+
case OLITERAL: // this is a bit of a mess
if mode == FErr {
if n.Orig != nil && n.Orig != n {
return
}
}
- if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
- n.Orig.exprfmt(s, prec, mode)
- return
- }
+
if n.Type != nil && !n.Type.IsUntyped() {
// Need parens when type begins with what might
// be misinterpreted as a unary operator: * or <-.
}
switch typ.Etype {
- case TCHAN, TFUNC, TMAP, TNIL, TINTER, TPTR, TSLICE, TUNSAFEPTR:
- return CTNIL
case TBOOL:
return CTBOOL
case TSTRING:
// and provides a useful consistency check.
switch constTypeOf(typ) {
- case CTNIL:
- // Only one value; nothing to encode.
- _ = v.U.(*NilVal)
case CTBOOL:
w.bool(v.U.(bool))
case CTSTR:
switch op := n.Op; op {
// expressions
// (somewhat closely following the structure of exprfmt in fmt.go)
- case OLITERAL:
- if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
+ case ONIL:
+ if !n.Type.HasNil() {
+ Fatalf("unexpected type for nil: %v", n.Type)
+ }
+ if n.Orig != nil && n.Orig != n {
w.expr(n.Orig)
break
}
+ w.op(OLITERAL)
+ w.pos(n.Pos)
+ w.typ(n.Type)
+
+ case OLITERAL:
w.op(OLITERAL)
w.pos(n.Pos)
w.value(n.Type, n.Val())
importalias(r.p.ipkg, pos, n.Sym, typ)
case 'C':
- typ, val := r.value()
+ typ := r.typ()
+ val := r.value(typ)
importconst(r.p.ipkg, pos, n.Sym, typ, val)
}
}
-func (p *importReader) value() (typ *types.Type, v Val) {
- typ = p.typ()
-
+func (p *importReader) value(typ *types.Type) (v Val) {
switch constTypeOf(typ) {
- case CTNIL:
- v.U = &NilVal{}
case CTBOOL:
v.U = p.bool()
case CTSTR:
// case OPAREN:
// unreachable - unpacked by exporter
+ // case ONIL:
+ // unreachable - mapped to OLITERAL
+
case OLITERAL:
pos := r.pos()
- typ, val := r.value()
+ typ := r.typ()
- n := npos(pos, nodlit(val))
+ var n *Node
+ if typ.HasNil() {
+ n = nodnil()
+ } else {
+ n = nodlit(r.value(typ))
+ }
+ n = npos(pos, n)
n.Type = typ
return n
}
switch n.Op {
- case ONAME, OTYPE, OLITERAL:
+ case ONAME, OTYPE, OLITERAL, ONIL:
return n
}
}
return n
- case OLITERAL, OTYPE:
+ case OLITERAL, ONIL, OTYPE:
// If n is a named constant or type, we can continue
// using it in the inline copy. Otherwise, make a copy
// so we can update the line number.
if n.Op != ONAME {
Fatalf("litsym n op %v", n.Op)
}
- if c.Op != OLITERAL {
- Fatalf("litsym c op %v", c.Op)
- }
if n.Sym == nil {
Fatalf("litsym nil n sym")
}
+ if c.Op == ONIL {
+ return
+ }
+ if c.Op != OLITERAL {
+ Fatalf("litsym c op %v", c.Op)
+ }
s := n.Sym.Linksym()
switch u := c.Val().U.(type) {
case bool:
}
switch n.Op {
- case ONAME, OLITERAL:
+ case ONAME, OLITERAL, ONIL:
return n
case OLEN, OCAP:
l := o.cheapExpr(n.Left)
// The intended use is to apply to x when rewriting x += y into x = x + y.
func (o *Order) safeExpr(n *Node) *Node {
switch n.Op {
- case ONAME, OLITERAL:
+ case ONAME, OLITERAL, ONIL:
return n
case ODOT, OLEN, OCAP:
// The result of addrTemp MUST be assigned back to n, e.g.
// n.Left = o.addrTemp(n.Left)
func (o *Order) addrTemp(n *Node) *Node {
- if consttype(n) != CTxxx {
+ if n.Op == OLITERAL || n.Op == ONIL {
// TODO: expand this to all static composite literal nodes?
n = defaultlit(n, nil)
dowidth(n.Type)
s.append(nod(OAS, l, conv(r, l.Type)))
return true
+ case ONIL:
+ return true
+
case OLITERAL:
if isZero(r) {
return true
e := &p.E[i]
n.Xoffset = l.Xoffset + e.Xoffset
n.Type = e.Expr.Type
- if e.Expr.Op == OLITERAL {
+ if e.Expr.Op == OLITERAL || e.Expr.Op == ONIL {
litsym(n, e.Expr, int(n.Type.Width))
continue
}
case ONAME:
return s.staticcopy(l, r)
+ case ONIL:
+ return true
+
case OLITERAL:
if isZero(r) {
return true
e := &p.E[i]
n.Xoffset = l.Xoffset + e.Xoffset
n.Type = e.Expr.Type
- if e.Expr.Op == OLITERAL {
+ if e.Expr.Op == OLITERAL || e.Expr.Op == ONIL {
litsym(n, e.Expr, int(n.Type.Width))
continue
}
for val.Op == OCONVIFACE {
val = val.Left
}
+
if val.Type.IsInterface() {
// val is an interface type.
// If val is nil, we can statically initialize l;
// both words are zero and so there no work to do, so report success.
// If val is non-nil, we have no concrete type to record,
// and we won't be able to statically initialize its value, so report failure.
- return Isconst(val, CTNIL)
+ return val.Op == ONIL
}
markTypeUsedInInterface(val.Type, l.Sym.Linksym())
// Emit data.
if isdirectiface(val.Type) {
- if Isconst(val, CTNIL) {
+ if val.Op == ONIL {
// Nil is zero, nothing to do.
return true
}
}
}
return true
- case OLITERAL:
+ case OLITERAL, ONIL:
return true
case OCONVIFACE:
// See staticassign's OCONVIFACE case for comments.
val = val.Left
}
if val.Type.IsInterface() {
- return Isconst(val, CTNIL)
+ return val.Op == ONIL
}
- if isdirectiface(val.Type) && Isconst(val, CTNIL) {
+ if isdirectiface(val.Type) && val.Op == ONIL {
return true
}
return isStaticCompositeLiteral(val)
func isZero(n *Node) bool {
switch n.Op {
+ case ONIL:
+ return true
+
case OLITERAL:
switch u := n.Val().U.(type) {
default:
Dump("unexpected literal", n)
Fatalf("isZero")
- case *NilVal:
- return true
case string:
return u == ""
case bool:
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
func (s *state) expr(n *Node) *ssa.Value {
- if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
+ if hasUniquePos(n) {
// ONAMEs and named OLITERALs have the line number
// of the decl, not the use. See issue 14742.
s.pushLine(n.Pos)
case OCLOSUREVAR:
addr := s.addr(n)
return s.load(n.Type, addr)
+ case ONIL:
+ t := n.Type
+ switch {
+ case t.IsSlice():
+ return s.constSlice(t)
+ case t.IsInterface():
+ return s.constInterface(t)
+ default:
+ return s.constNil(t)
+ }
case OLITERAL:
switch u := n.Val().U.(type) {
case *Mpint:
return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
case bool:
return s.constBool(u)
- case *NilVal:
- t := n.Type
- switch {
- case t.IsSlice():
- return s.constSlice(t)
- case t.IsInterface():
- return s.constInterface(t)
- default:
- return s.constNil(t)
- }
case *Mpflt:
switch n.Type.Size() {
case 4:
switch n.Op {
case ONAME, OPACK:
return false
- case OLITERAL, OTYPE:
+ case OLITERAL, ONIL, OTYPE:
if n.Sym != nil {
return false
}
}
func nodnil() *Node {
- return nodlit(Val{new(NilVal)})
+ n := nod(ONIL, nil, nil)
+ n.Type = types.Types[TNIL]
+ return n
}
func nodbool(b bool) *Node {
// crashing (golang.org/issue/11361).
fallthrough
- case ONAME, ONONAME, OLITERAL, OTYPE:
+ case ONAME, ONONAME, OLITERAL, ONIL, OTYPE:
return n
}
func (n *Node) isNil() bool {
// Check n.Orig because constant propagation may produce typed nil constants,
// which don't exist in the Go spec.
- return Isconst(n.Orig, CTNIL)
+ return n.Orig.Op == ONIL
}
func isptrto(t *types.Type, et types.EType) bool {
}
switch n.Op {
- case OLITERAL, ONAME, OTYPE:
+ case OLITERAL, ONIL, ONAME, OTYPE:
if n.HasCall() {
Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n)
}
}
switch n.Op {
- case ONAME, OLITERAL:
+ case ONAME, OLITERAL, ONIL:
return n
case ODOT, OLEN, OCAP:
// result may not be assignable.
func cheapexpr(n *Node, init *Nodes) *Node {
switch n.Op {
- case ONAME, OLITERAL:
+ case ONAME, OLITERAL, ONIL:
return n
}
}
cond = walkexpr(cond, &sw.Ninit)
- if cond.Op != OLITERAL {
+ if cond.Op != OLITERAL && cond.Op != ONIL {
cond = copyexpr(cond, cond.Type, &sw.Nbody)
}
// Extra care must be taken when mutating such a node.
func (n *Node) mayBeShared() bool {
switch n.Op {
- case ONAME, OLITERAL, OTYPE:
+ case ONAME, OLITERAL, ONIL, OTYPE:
return true
}
return false
n.Type = types.UntypedString
}
- case ONONAME:
+ case ONIL, ONONAME:
ok |= ctxExpr
case ONAME:
n.Type = t
if !t.IsSlice() {
- if Isconst(args.First(), CTNIL) {
+ if args.First().isNil() {
yyerror("first argument to append must be typed slice; have untyped nil")
n.Type = nil
return n
case OLITERAL:
return eqval(l.Val(), r.Val())
+
+ case ONIL:
+ return true
}
return false
}
if !e.isGoConst() {
if !e.Diag() {
- if Isconst(e, CTNIL) {
+ if e.Op == ONIL {
yyerrorl(n.Pos, "const initializer cannot be nil")
} else {
yyerrorl(n.Pos, "const initializer %v is not a constant", e)
types.Types[TNIL] = types.New(TNIL)
s = builtinpkg.Lookup("nil")
- var v Val
- v.U = new(NilVal)
- s.Def = asTypesNode(nodlit(v))
+ s.Def = asTypesNode(nodnil())
asNode(s.Def).Sym = s
asNode(s.Def).Name = new(Name)
case ONONAME, OEMPTY, OGETG, ONEWOBJ:
- case OTYPE, ONAME, OLITERAL:
+ case OTYPE, ONAME, OLITERAL, ONIL:
// TODO(mdempsky): Just return n; see discussion on CL 38655.
// Perhaps refactor to use Node.mayBeShared for these instead.
// If these return early, make sure to still call
}
switch n.Op {
- case OLITERAL:
+ case OLITERAL, ONIL:
return true
case ONAME:
case ONAME:
return l == r
- case OLITERAL:
+ case OLITERAL, ONIL:
return false
}
return vmatch2(l, r)
- case OLITERAL:
+ case OLITERAL, ONIL:
return false
}
// The result of walkcompare MUST be assigned back to n, e.g.
// n.Left = walkcompare(n.Left, init)
func walkcompare(n *Node, init *Nodes) *Node {
- if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != OLITERAL && n.Right.Op != OLITERAL {
+ if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != ONIL && n.Right.Op != ONIL {
return walkcompareInterface(n, init)
}
OTYPE,
OPACK,
OLITERAL,
+ ONIL,
OADD,
OSUB,
OOR,
// HasNil reports whether the set of values determined by t includes nil.
func (t *Type) HasNil() bool {
switch t.Etype {
- case TCHAN, TFUNC, TINTER, TMAP, TPTR, TSLICE, TUNSAFEPTR:
+ case TCHAN, TFUNC, TINTER, TMAP, TNIL, TPTR, TSLICE, TUNSAFEPTR:
return true
}
return false