diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/typecheck.go')
-rw-r--r-- | src/cmd/compile/internal/gc/typecheck.go | 3029 |
1 files changed, 1532 insertions, 1497 deletions
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index c0b05035f0..4e2f205312 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -5,27 +5,30 @@ package gc import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" "cmd/compile/internal/types" "fmt" + "go/constant" + "go/token" "strings" ) // To enable tracing support (-t flag), set enableTrace to true. const enableTrace = false -var trace bool var traceIndent []byte var skipDowidthForTracing bool -func tracePrint(title string, n *Node) func(np **Node) { +func tracePrint(title string, n ir.Node) func(np *ir.Node) { indent := traceIndent // guard against nil var pos, op string var tc uint8 if n != nil { - pos = linestr(n.Pos) - op = n.Op.String() + pos = base.FmtPos(n.Pos()) + op = n.Op().String() tc = n.Typecheck() } @@ -34,7 +37,7 @@ func tracePrint(title string, n *Node) func(np **Node) { fmt.Printf("%s: %s%s %p %s %v tc=%d\n", pos, indent, title, n, op, n, tc) traceIndent = append(traceIndent, ". "...) - return func(np **Node) { + return func(np *ir.Node) { traceIndent = traceIndent[:len(traceIndent)-2] // if we have a result, use that @@ -47,10 +50,10 @@ func tracePrint(title string, n *Node) func(np **Node) { var tc uint8 var typ *types.Type if n != nil { - pos = linestr(n.Pos) - op = n.Op.String() + pos = base.FmtPos(n.Pos()) + op = n.Op().String() tc = n.Typecheck() - typ = n.Type + typ = n.Type() } skipDowidthForTracing = true @@ -74,22 +77,22 @@ const ( // marks variables that escape the local frame. // rewrites n.Op to be more specific in some cases. -var typecheckdefstack []*Node +var typecheckdefstack []ir.Node // resolve ONONAME to definition, if any. -func resolve(n *Node) (res *Node) { - if n == nil || n.Op != ONONAME { +func resolve(n ir.Node) (res ir.Node) { + if n == nil || n.Op() != ir.ONONAME { return n } // only trace if there's work to do - if enableTrace && trace { + if enableTrace && base.Flag.LowerT { defer tracePrint("resolve", n)(&res) } - if n.Sym.Pkg != localpkg { + if n.Sym().Pkg != ir.LocalPkg { if inimport { - Fatalf("recursive inimport") + base.Fatalf("recursive inimport") } inimport = true expandDecl(n) @@ -97,12 +100,12 @@ func resolve(n *Node) (res *Node) { return n } - r := asNode(n.Sym.Def) + r := ir.AsNode(n.Sym().Def) if r == nil { return n } - if r.Op == OIOTA { + if r.Op() == ir.OIOTA { if x := getIotaValue(); x >= 0 { return nodintconst(x) } @@ -112,41 +115,41 @@ func resolve(n *Node) (res *Node) { return r } -func typecheckslice(l []*Node, top int) { +func typecheckslice(l []ir.Node, top int) { for i := range l { l[i] = typecheck(l[i], top) } } var _typekind = []string{ - TINT: "int", - TUINT: "uint", - TINT8: "int8", - TUINT8: "uint8", - TINT16: "int16", - TUINT16: "uint16", - TINT32: "int32", - TUINT32: "uint32", - TINT64: "int64", - TUINT64: "uint64", - TUINTPTR: "uintptr", - TCOMPLEX64: "complex64", - TCOMPLEX128: "complex128", - TFLOAT32: "float32", - TFLOAT64: "float64", - TBOOL: "bool", - TSTRING: "string", - TPTR: "pointer", - TUNSAFEPTR: "unsafe.Pointer", - TSTRUCT: "struct", - TINTER: "interface", - TCHAN: "chan", - TMAP: "map", - TARRAY: "array", - TSLICE: "slice", - TFUNC: "func", - TNIL: "nil", - TIDEAL: "untyped number", + types.TINT: "int", + types.TUINT: "uint", + types.TINT8: "int8", + types.TUINT8: "uint8", + types.TINT16: "int16", + types.TUINT16: "uint16", + types.TINT32: "int32", + types.TUINT32: "uint32", + types.TINT64: "int64", + types.TUINT64: "uint64", + types.TUINTPTR: "uintptr", + types.TCOMPLEX64: "complex64", + types.TCOMPLEX128: "complex128", + types.TFLOAT32: "float32", + types.TFLOAT64: "float64", + types.TBOOL: "bool", + types.TSTRING: "string", + types.TPTR: "pointer", + types.TUNSAFEPTR: "unsafe.Pointer", + types.TSTRUCT: "struct", + types.TINTER: "interface", + types.TCHAN: "chan", + types.TMAP: "map", + types.TARRAY: "array", + types.TSLICE: "slice", + types.TFUNC: "func", + types.TNIL: "nil", + types.TIDEAL: "untyped number", } func typekind(t *types.Type) string { @@ -163,7 +166,7 @@ func typekind(t *types.Type) string { return fmt.Sprintf("etype=%d", et) } -func cycleFor(start *Node) []*Node { +func cycleFor(start ir.Node) []ir.Node { // Find the start node in typecheck_tcstack. // We know that it must exist because each time we mark // a node with n.SetTypecheck(2) we push it on the stack, @@ -176,9 +179,9 @@ func cycleFor(start *Node) []*Node { } // collect all nodes with same Op - var cycle []*Node + var cycle []ir.Node for _, n := range typecheck_tcstack[i:] { - if n.Op == start.Op { + if n.Op() == start.Op() { cycle = append(cycle, n) } } @@ -186,23 +189,23 @@ func cycleFor(start *Node) []*Node { return cycle } -func cycleTrace(cycle []*Node) string { +func cycleTrace(cycle []ir.Node) string { var s string for i, n := range cycle { - s += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cycle[(i+1)%len(cycle)]) + s += fmt.Sprintf("\n\t%v: %v uses %v", ir.Line(n), n, cycle[(i+1)%len(cycle)]) } return s } -var typecheck_tcstack []*Node +var typecheck_tcstack []ir.Node // typecheck type checks node n. // The result of typecheck MUST be assigned back to n, e.g. // n.Left = typecheck(n.Left, top) -func typecheck(n *Node, top int) (res *Node) { +func typecheck(n ir.Node, top int) (res ir.Node) { // cannot type check until all the source has been parsed if !typecheckok { - Fatalf("early typecheck") + base.Fatalf("early typecheck") } if n == nil { @@ -210,15 +213,15 @@ func typecheck(n *Node, top int) (res *Node) { } // only trace if there's work to do - if enableTrace && trace { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheck", n)(&res) } lno := setlineno(n) // Skip over parens. - for n.Op == OPAREN { - n = n.Left + for n.Op() == ir.OPAREN { + n = n.Left() } // Resolve definition of name and value of iota lazily. @@ -227,12 +230,12 @@ func typecheck(n *Node, top int) (res *Node) { // Skip typecheck if already done. // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed. if n.Typecheck() == 1 { - switch n.Op { - case ONAME, OTYPE, OLITERAL, OPACK: + switch n.Op() { + case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.OPACK: break default: - lineno = lno + base.Pos = lno return n } } @@ -240,14 +243,14 @@ func typecheck(n *Node, top int) (res *Node) { if n.Typecheck() == 2 { // Typechecking loop. Trying printing a meaningful message, // otherwise a stack trace of typechecking. - switch n.Op { + switch n.Op() { // We can already diagnose variables used as types. - case ONAME: + case ir.ONAME: if top&(ctxExpr|ctxType) == ctxType { - yyerror("%v is not a type", n) + base.Errorf("%v is not a type", n) } - case OTYPE: + case ir.OTYPE: // Only report a type cycle if we are expecting a type. // Otherwise let other code report an error. if top&ctxType == ctxType { @@ -256,40 +259,40 @@ func typecheck(n *Node, top int) (res *Node) { // are substituted. cycle := cycleFor(n) for _, n1 := range cycle { - if n1.Name != nil && !n1.Name.Param.Alias() { + if n1.Name() != nil && !n1.Name().Param.Alias() { // Cycle is ok. But if n is an alias type and doesn't // have a type yet, we have a recursive type declaration // with aliases that we can't handle properly yet. // Report an error rather than crashing later. - if n.Name != nil && n.Name.Param.Alias() && n.Type == nil { - lineno = n.Pos - Fatalf("cannot handle alias type declaration (issue #25838): %v", n) + if n.Name() != nil && n.Name().Param.Alias() && n.Type() == nil { + base.Pos = n.Pos() + base.Fatalf("cannot handle alias type declaration (issue #25838): %v", n) } - lineno = lno + base.Pos = lno return n } } - yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, cycleTrace(cycle)) + base.ErrorfAt(n.Pos(), "invalid recursive type alias %v%s", n, cycleTrace(cycle)) } - case OLITERAL: + case ir.OLITERAL: if top&(ctxExpr|ctxType) == ctxType { - yyerror("%v is not a type", n) + base.Errorf("%v is not a type", n) break } - yyerrorl(n.Pos, "constant definition loop%s", cycleTrace(cycleFor(n))) + base.ErrorfAt(n.Pos(), "constant definition loop%s", cycleTrace(cycleFor(n))) } - if nsavederrors+nerrors == 0 { + if base.Errors() == 0 { var trace string for i := len(typecheck_tcstack) - 1; i >= 0; i-- { x := typecheck_tcstack[i] - trace += fmt.Sprintf("\n\t%v %v", x.Line(), x) + trace += fmt.Sprintf("\n\t%v %v", ir.Line(x), x) } - yyerror("typechecking loop involving %v%s", n, trace) + base.Errorf("typechecking loop involving %v%s", n, trace) } - lineno = lno + base.Pos = lno return n } @@ -304,7 +307,7 @@ func typecheck(n *Node, top int) (res *Node) { typecheck_tcstack[last] = nil typecheck_tcstack = typecheck_tcstack[:last] - lineno = lno + base.Pos = lno return n } @@ -314,61 +317,61 @@ func typecheck(n *Node, top int) (res *Node) { // value of type int (see also checkmake for comparison). // The result of indexlit MUST be assigned back to n, e.g. // n.Left = indexlit(n.Left) -func indexlit(n *Node) *Node { - if n != nil && n.Type != nil && n.Type.Etype == TIDEAL { - return defaultlit(n, types.Types[TINT]) +func indexlit(n ir.Node) ir.Node { + if n != nil && n.Type() != nil && n.Type().Etype == types.TIDEAL { + return defaultlit(n, types.Types[types.TINT]) } return n } // The result of typecheck1 MUST be assigned back to n, e.g. // n.Left = typecheck1(n.Left, top) -func typecheck1(n *Node, top int) (res *Node) { - if enableTrace && trace { +func typecheck1(n ir.Node, top int) (res ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheck1", n)(&res) } - switch n.Op { - case OLITERAL, ONAME, ONONAME, OTYPE: - if n.Sym == nil { + switch n.Op() { + case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE: + if n.Sym() == nil { break } - if n.Op == ONAME && n.SubOp() != 0 && top&ctxCallee == 0 { - yyerror("use of builtin %v not in function call", n.Sym) - n.Type = nil + if n.Op() == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 { + base.Errorf("use of builtin %v not in function call", n.Sym()) + n.SetType(nil) return n } typecheckdef(n) - if n.Op == ONONAME { - n.Type = nil + if n.Op() == ir.ONONAME { + n.SetType(nil) return n } } ok := 0 - switch n.Op { + switch n.Op() { // until typecheck is complete, do nothing. default: - Dump("typecheck", n) + ir.Dump("typecheck", n) - Fatalf("typecheck %v", n.Op) + base.Fatalf("typecheck %v", n.Op()) // names - case OLITERAL: + case ir.OLITERAL: ok |= ctxExpr - if n.Type == nil && n.Val().Ctype() == CTSTR { - n.Type = types.UntypedString + if n.Type() == nil && n.Val().Kind() == constant.String { + base.Fatalf("string literal missing type") } - case ONONAME: + case ir.ONIL, ir.ONONAME: ok |= ctxExpr - case ONAME: - if n.Name.Decldepth == 0 { - n.Name.Decldepth = decldepth + case ir.ONAME: + if n.Name().Decldepth == 0 { + n.Name().Decldepth = decldepth } if n.SubOp() != 0 { ok |= ctxCallee @@ -377,164 +380,165 @@ func typecheck1(n *Node, top int) (res *Node) { if top&ctxAssign == 0 { // not a write to the variable - if n.isBlank() { - yyerror("cannot use _ as value") - n.Type = nil + if ir.IsBlank(n) { + base.Errorf("cannot use _ as value") + n.SetType(nil) return n } - n.Name.SetUsed(true) + n.Name().SetUsed(true) } ok |= ctxExpr - case OPACK: - yyerror("use of package %v without selector", n.Sym) - n.Type = nil + case ir.OPACK: + base.Errorf("use of package %v without selector", n.Sym()) + n.SetType(nil) return n - case ODDD: + case ir.ODDD: break // types (ODEREF is with exprs) - case OTYPE: + case ir.OTYPE: ok |= ctxType - if n.Type == nil { + if n.Type() == nil { return n } - case OTARRAY: + case ir.OTARRAY: ok |= ctxType - r := typecheck(n.Right, ctxType) - if r.Type == nil { - n.Type = nil + r := typecheck(n.Right(), ctxType) + if r.Type() == nil { + n.SetType(nil) return n } var t *types.Type - if n.Left == nil { - t = types.NewSlice(r.Type) - } else if n.Left.Op == ODDD { + if n.Left() == nil { + t = types.NewSlice(r.Type()) + } else if n.Left().Op() == ir.ODDD { if !n.Diag() { n.SetDiag(true) - yyerror("use of [...] array outside of array literal") + base.Errorf("use of [...] array outside of array literal") } - n.Type = nil + n.SetType(nil) return n } else { - n.Left = indexlit(typecheck(n.Left, ctxExpr)) - l := n.Left - if consttype(l) != CTINT { + n.SetLeft(indexlit(typecheck(n.Left(), ctxExpr))) + l := n.Left() + if ir.ConstType(l) != constant.Int { switch { - case l.Type == nil: + case l.Type() == nil: // Error already reported elsewhere. - case l.Type.IsInteger() && l.Op != OLITERAL: - yyerror("non-constant array bound %v", l) + case l.Type().IsInteger() && l.Op() != ir.OLITERAL: + base.Errorf("non-constant array bound %v", l) default: - yyerror("invalid array bound %v", l) + base.Errorf("invalid array bound %v", l) } - n.Type = nil + n.SetType(nil) return n } v := l.Val() - if doesoverflow(v, types.Types[TINT]) { - yyerror("array bound is too large") - n.Type = nil + if doesoverflow(v, types.Types[types.TINT]) { + base.Errorf("array bound is too large") + n.SetType(nil) return n } - bound := v.U.(*Mpint).Int64() - if bound < 0 { - yyerror("array bound must be non-negative") - n.Type = nil + if constant.Sign(v) < 0 { + base.Errorf("array bound must be non-negative") + n.SetType(nil) return n } - t = types.NewArray(r.Type, bound) + + bound, _ := constant.Int64Val(v) + t = types.NewArray(r.Type(), bound) } setTypeNode(n, t) - n.Left = nil - n.Right = nil + n.SetLeft(nil) + n.SetRight(nil) checkwidth(t) - case OTMAP: + case ir.OTMAP: ok |= ctxType - n.Left = typecheck(n.Left, ctxType) - n.Right = typecheck(n.Right, ctxType) - l := n.Left - r := n.Right - if l.Type == nil || r.Type == nil { - n.Type = nil + n.SetLeft(typecheck(n.Left(), ctxType)) + n.SetRight(typecheck(n.Right(), ctxType)) + l := n.Left() + r := n.Right() + if l.Type() == nil || r.Type() == nil { + n.SetType(nil) return n } - if l.Type.NotInHeap() { - yyerror("incomplete (or unallocatable) map key not allowed") + if l.Type().NotInHeap() { + base.Errorf("incomplete (or unallocatable) map key not allowed") } - if r.Type.NotInHeap() { - yyerror("incomplete (or unallocatable) map value not allowed") + if r.Type().NotInHeap() { + base.Errorf("incomplete (or unallocatable) map value not allowed") } - setTypeNode(n, types.NewMap(l.Type, r.Type)) + setTypeNode(n, types.NewMap(l.Type(), r.Type())) mapqueue = append(mapqueue, n) // check map keys when all types are settled - n.Left = nil - n.Right = nil + n.SetLeft(nil) + n.SetRight(nil) - case OTCHAN: + case ir.OTCHAN: ok |= ctxType - n.Left = typecheck(n.Left, ctxType) - l := n.Left - if l.Type == nil { - n.Type = nil + n.SetLeft(typecheck(n.Left(), ctxType)) + l := n.Left() + if l.Type() == nil { + n.SetType(nil) return n } - if l.Type.NotInHeap() { - yyerror("chan of incomplete (or unallocatable) type not allowed") + if l.Type().NotInHeap() { + base.Errorf("chan of incomplete (or unallocatable) type not allowed") } - setTypeNode(n, types.NewChan(l.Type, n.TChanDir())) - n.Left = nil + setTypeNode(n, types.NewChan(l.Type(), n.TChanDir())) + n.SetLeft(nil) n.ResetAux() - case OTSTRUCT: + case ir.OTSTRUCT: ok |= ctxType - setTypeNode(n, tostruct(n.List.Slice())) - n.List.Set(nil) + setTypeNode(n, tostruct(n.List().Slice())) + n.PtrList().Set(nil) - case OTINTER: + case ir.OTINTER: ok |= ctxType - setTypeNode(n, tointerface(n.List.Slice())) + setTypeNode(n, tointerface(n.List().Slice())) - case OTFUNC: + case ir.OTFUNC: ok |= ctxType - setTypeNode(n, functype(n.Left, n.List.Slice(), n.Rlist.Slice())) - n.Left = nil - n.List.Set(nil) - n.Rlist.Set(nil) + setTypeNode(n, functype(n.Left(), n.List().Slice(), n.Rlist().Slice())) + n.SetLeft(nil) + n.PtrList().Set(nil) + n.PtrRlist().Set(nil) // type or expr - case ODEREF: - n.Left = typecheck(n.Left, ctxExpr|ctxType) - l := n.Left - t := l.Type + case ir.ODEREF: + n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType)) + l := n.Left() + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } - if l.Op == OTYPE { + if l.Op() == ir.OTYPE { ok |= ctxType - setTypeNode(n, types.NewPtr(l.Type)) - n.Left = nil + setTypeNode(n, types.NewPtr(l.Type())) + n.SetLeft(nil) // Ensure l.Type gets dowidth'd for the backend. Issue 20174. - checkwidth(l.Type) + checkwidth(l.Type()) break } if !t.IsPtr() { if top&(ctxExpr|ctxStmt) != 0 { - yyerror("invalid indirect of %L", n.Left) - n.Type = nil + base.Errorf("invalid indirect of %L", n.Left()) + n.SetType(nil) return n } @@ -542,88 +546,88 @@ func typecheck1(n *Node, top int) (res *Node) { } ok |= ctxExpr - n.Type = t.Elem() + n.SetType(t.Elem()) // arithmetic exprs - case OASOP, - OADD, - OAND, - OANDAND, - OANDNOT, - ODIV, - OEQ, - OGE, - OGT, - OLE, - OLT, - OLSH, - ORSH, - OMOD, - OMUL, - ONE, - OOR, - OOROR, - OSUB, - OXOR: - var l *Node - var op Op - var r *Node - if n.Op == OASOP { + case ir.OASOP, + ir.OADD, + ir.OAND, + ir.OANDAND, + ir.OANDNOT, + ir.ODIV, + ir.OEQ, + ir.OGE, + ir.OGT, + ir.OLE, + ir.OLT, + ir.OLSH, + ir.ORSH, + ir.OMOD, + ir.OMUL, + ir.ONE, + ir.OOR, + ir.OOROR, + ir.OSUB, + ir.OXOR: + var l ir.Node + var op ir.Op + var r ir.Node + if n.Op() == ir.OASOP { ok |= ctxStmt - n.Left = typecheck(n.Left, ctxExpr) - n.Right = typecheck(n.Right, ctxExpr) - l = n.Left - r = n.Right - checkassign(n, n.Left) - if l.Type == nil || r.Type == nil { - n.Type = nil + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetRight(typecheck(n.Right(), ctxExpr)) + l = n.Left() + r = n.Right() + checkassign(n, n.Left()) + if l.Type() == nil || r.Type() == nil { + n.SetType(nil) return n } - if n.Implicit() && !okforarith[l.Type.Etype] { - yyerror("invalid operation: %v (non-numeric type %v)", n, l.Type) - n.Type = nil + if n.Implicit() && !okforarith[l.Type().Etype] { + base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type()) + n.SetType(nil) return n } // TODO(marvin): Fix Node.EType type union. op = n.SubOp() } else { ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - n.Right = typecheck(n.Right, ctxExpr) - l = n.Left - r = n.Right - if l.Type == nil || r.Type == nil { - n.Type = nil + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetRight(typecheck(n.Right(), ctxExpr)) + l = n.Left() + r = n.Right() + if l.Type() == nil || r.Type() == nil { + n.SetType(nil) return n } - op = n.Op + op = n.Op() } - if op == OLSH || op == ORSH { - r = defaultlit(r, types.Types[TUINT]) - n.Right = r - t := r.Type + if op == ir.OLSH || op == ir.ORSH { + r = defaultlit(r, types.Types[types.TUINT]) + n.SetRight(r) + t := r.Type() if !t.IsInteger() { - yyerror("invalid operation: %v (shift count type %v, must be integer)", n, r.Type) - n.Type = nil + base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type()) + n.SetType(nil) return n } if t.IsSigned() && !langSupported(1, 13, curpkg()) { - yyerrorv("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type) - n.Type = nil + base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type()) + n.SetType(nil) return n } - t = l.Type - if t != nil && t.Etype != TIDEAL && !t.IsInteger() { - yyerror("invalid operation: %v (shift of type %v)", n, t) - n.Type = nil + t = l.Type() + if t != nil && t.Etype != types.TIDEAL && !t.IsInteger() { + base.Errorf("invalid operation: %v (shift of type %v)", n, t) + n.SetType(nil) return n } // no defaultlit for left // the outer context gives the type - n.Type = l.Type - if (l.Type == types.UntypedFloat || l.Type == types.UntypedComplex) && r.Op == OLITERAL { - n.Type = types.UntypedInt + n.SetType(l.Type()) + if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL { + n.SetType(types.UntypedInt) } break @@ -632,15 +636,15 @@ func typecheck1(n *Node, top int) (res *Node) { // For "x == x && len(s)", it's better to report that "len(s)" (type int) // can't be used with "&&" than to report that "x == x" (type untyped bool) // can't be converted to int (see issue #41500). - if n.Op == OANDAND || n.Op == OOROR { - if !n.Left.Type.IsBoolean() { - yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(n.Left.Type)) - n.Type = nil + if n.Op() == ir.OANDAND || n.Op() == ir.OOROR { + if !n.Left().Type().IsBoolean() { + base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Left().Type())) + n.SetType(nil) return n } - if !n.Right.Type.IsBoolean() { - yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(n.Right.Type)) - n.Type = nil + if !n.Right().Type().IsBoolean() { + base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Right().Type())) + n.SetType(nil) return n } } @@ -648,22 +652,22 @@ func typecheck1(n *Node, top int) (res *Node) { // ideal mixed with non-ideal l, r = defaultlit2(l, r, false) - n.Left = l - n.Right = r - if l.Type == nil || r.Type == nil { - n.Type = nil + n.SetLeft(l) + n.SetRight(r) + if l.Type() == nil || r.Type() == nil { + n.SetType(nil) return n } - t := l.Type - if t.Etype == TIDEAL { - t = r.Type + t := l.Type() + if t.Etype == types.TIDEAL { + t = r.Type() } et := t.Etype - if et == TIDEAL { - et = TINT + if et == types.TIDEAL { + et = types.TINT } - aop := OXXX - if iscmp[n.Op] && t.Etype != TIDEAL && !types.Identical(l.Type, r.Type) { + aop := ir.OXXX + if iscmp[n.Op()] && t.Etype != types.TIDEAL && !types.Identical(l.Type(), r.Type()) { // comparison is okay as long as one side is // assignable to the other. convert so they have // the same type. @@ -672,235 +676,235 @@ func typecheck1(n *Node, top int) (res *Node) { // in that case, check comparability of the concrete type. // The conversion allocates, so only do it if the concrete type is huge. converted := false - if r.Type.Etype != TBLANK { - aop, _ = assignop(l.Type, r.Type) - if aop != OXXX { - if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) { - yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type)) - n.Type = nil + if r.Type().Etype != types.TBLANK { + aop, _ = assignop(l.Type(), r.Type()) + if aop != ir.OXXX { + if r.Type().IsInterface() && !l.Type().IsInterface() && !IsComparable(l.Type()) { + base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type())) + n.SetType(nil) return n } - dowidth(l.Type) - if r.Type.IsInterface() == l.Type.IsInterface() || l.Type.Width >= 1<<16 { - l = nod(aop, l, nil) - l.Type = r.Type + dowidth(l.Type()) + if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 { + l = ir.Nod(aop, l, nil) + l.SetType(r.Type()) l.SetTypecheck(1) - n.Left = l + n.SetLeft(l) } - t = r.Type + t = r.Type() converted = true } } - if !converted && l.Type.Etype != TBLANK { - aop, _ = assignop(r.Type, l.Type) - if aop != OXXX { - if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) { - yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type)) - n.Type = nil + if !converted && l.Type().Etype != types.TBLANK { + aop, _ = assignop(r.Type(), l.Type()) + if aop != ir.OXXX { + if l.Type().IsInterface() && !r.Type().IsInterface() && !IsComparable(r.Type()) { + base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type())) + n.SetType(nil) return n } - dowidth(r.Type) - if r.Type.IsInterface() == l.Type.IsInterface() || r.Type.Width >= 1<<16 { - r = nod(aop, r, nil) - r.Type = l.Type + dowidth(r.Type()) + if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 { + r = ir.Nod(aop, r, nil) + r.SetType(l.Type()) r.SetTypecheck(1) - n.Right = r + n.SetRight(r) } - t = l.Type + t = l.Type() } } et = t.Etype } - if t.Etype != TIDEAL && !types.Identical(l.Type, r.Type) { + if t.Etype != types.TIDEAL && !types.Identical(l.Type(), r.Type()) { l, r = defaultlit2(l, r, true) - if l.Type == nil || r.Type == nil { - n.Type = nil + if l.Type() == nil || r.Type() == nil { + n.SetType(nil) return n } - if l.Type.IsInterface() == r.Type.IsInterface() || aop == 0 { - yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type) - n.Type = nil + if l.Type().IsInterface() == r.Type().IsInterface() || aop == 0 { + base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type()) + n.SetType(nil) return n } } - if t.Etype == TIDEAL { - t = mixUntyped(l.Type, r.Type) + if t.Etype == types.TIDEAL { + t = mixUntyped(l.Type(), r.Type()) } if dt := defaultType(t); !okfor[op][dt.Etype] { - yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t)) - n.Type = nil + base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t)) + n.SetType(nil) return n } // okfor allows any array == array, map == map, func == func. // restrict to slice/map/func == nil and nil == slice/map/func. - if l.Type.IsArray() && !IsComparable(l.Type) { - yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type) - n.Type = nil + if l.Type().IsArray() && !IsComparable(l.Type()) { + base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type()) + n.SetType(nil) return n } - if l.Type.IsSlice() && !l.isNil() && !r.isNil() { - yyerror("invalid operation: %v (slice can only be compared to nil)", n) - n.Type = nil + if l.Type().IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) { + base.Errorf("invalid operation: %v (slice can only be compared to nil)", n) + n.SetType(nil) return n } - if l.Type.IsMap() && !l.isNil() && !r.isNil() { - yyerror("invalid operation: %v (map can only be compared to nil)", n) - n.Type = nil + if l.Type().IsMap() && !ir.IsNil(l) && !ir.IsNil(r) { + base.Errorf("invalid operation: %v (map can only be compared to nil)", n) + n.SetType(nil) return n } - if l.Type.Etype == TFUNC && !l.isNil() && !r.isNil() { - yyerror("invalid operation: %v (func can only be compared to nil)", n) - n.Type = nil + if l.Type().Etype == types.TFUNC && !ir.IsNil(l) && !ir.IsNil(r) { + base.Errorf("invalid operation: %v (func can only be compared to nil)", n) + n.SetType(nil) return n } - if l.Type.IsStruct() { - if f := IncomparableField(l.Type); f != nil { - yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type) - n.Type = nil + if l.Type().IsStruct() { + if f := IncomparableField(l.Type()); f != nil { + base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type) + n.SetType(nil) return n } } - if iscmp[n.Op] { - evconst(n) + if iscmp[n.Op()] { t = types.UntypedBool - if n.Op != OLITERAL { + n.SetType(t) + n = evalConst(n) + if n.Op() != ir.OLITERAL { l, r = defaultlit2(l, r, true) - n.Left = l - n.Right = r + n.SetLeft(l) + n.SetRight(r) } } - if et == TSTRING && n.Op == OADD { - // create OADDSTR node with list of strings in x + y + z + (w + v) + ... - n.Op = OADDSTR - - if l.Op == OADDSTR { - n.List.Set(l.List.Slice()) + if et == types.TSTRING && n.Op() == ir.OADD { + // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ... + if l.Op() == ir.OADDSTR { + orig := n + n = l + n.SetPos(orig.Pos()) } else { - n.List.Set1(l) + n = ir.NodAt(n.Pos(), ir.OADDSTR, nil, nil) + n.PtrList().Set1(l) } - if r.Op == OADDSTR { - n.List.AppendNodes(&r.List) + if r.Op() == ir.OADDSTR { + n.PtrList().AppendNodes(r.PtrList()) } else { - n.List.Append(r) + n.PtrList().Append(r) } - n.Left = nil - n.Right = nil } - if (op == ODIV || op == OMOD) && Isconst(r, CTINT) { - if r.Val().U.(*Mpint).CmpInt64(0) == 0 { - yyerror("division by zero") - n.Type = nil + if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) { + if constant.Sign(r.Val()) == 0 { + base.Errorf("division by zero") + n.SetType(nil) return n } } - n.Type = t + n.SetType(t) - case OBITNOT, ONEG, ONOT, OPLUS: + case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - l := n.Left - t := l.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + l := n.Left() + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } - if !okfor[n.Op][defaultType(t).Etype] { - yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(t)) - n.Type = nil + if !okfor[n.Op()][defaultType(t).Etype] { + base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(t)) + n.SetType(nil) return n } - n.Type = t + n.SetType(t) // exprs - case OADDR: + case ir.OADDR: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - if n.Left.Type == nil { - n.Type = nil + n.SetLeft(typecheck(n.Left(), ctxExpr)) + if n.Left().Type() == nil { + n.SetType(nil) return n } - switch n.Left.Op { - case OARRAYLIT, OMAPLIT, OSLICELIT, OSTRUCTLIT: - n.Op = OPTRLIT + switch n.Left().Op() { + case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT: + n.SetOp(ir.OPTRLIT) default: - checklvalue(n.Left, "take the address of") - r := outervalue(n.Left) - if r.Op == ONAME { - if r.Orig != r { - Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean? + checklvalue(n.Left(), "take the address of") + r := outervalue(n.Left()) + if r.Op() == ir.ONAME { + if r.Orig() != r { + base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean? } - r.Name.SetAddrtaken(true) - if r.Name.IsClosureVar() && !capturevarscomplete { + r.Name().SetAddrtaken(true) + if r.Name().IsClosureVar() && !capturevarscomplete { // Mark the original variable as Addrtaken so that capturevars // knows not to pass it by value. // But if the capturevars phase is complete, don't touch it, // in case l.Name's containing function has not yet been compiled. - r.Name.Defn.Name.SetAddrtaken(true) + r.Name().Defn.Name().SetAddrtaken(true) } } - n.Left = defaultlit(n.Left, nil) - if n.Left.Type == nil { - n.Type = nil + n.SetLeft(defaultlit(n.Left(), nil)) + if n.Left().Type() == nil { + n.SetType(nil) return n } } - n.Type = types.NewPtr(n.Left.Type) + n.SetType(types.NewPtr(n.Left().Type())) - case OCOMPLIT: + case ir.OCOMPLIT: ok |= ctxExpr n = typecheckcomplit(n) - if n.Type == nil { + if n.Type() == nil { return n } - case OXDOT, ODOT: - if n.Op == OXDOT { + case ir.OXDOT, ir.ODOT: + if n.Op() == ir.OXDOT { n = adddot(n) - n.Op = ODOT - if n.Left == nil { - n.Type = nil + n.SetOp(ir.ODOT) + if n.Left() == nil { + n.SetType(nil) return n } } - n.Left = typecheck(n.Left, ctxExpr|ctxType) + n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType)) - n.Left = defaultlit(n.Left, nil) + n.SetLeft(defaultlit(n.Left(), nil)) - t := n.Left.Type + t := n.Left().Type() if t == nil { - adderrorname(n) - n.Type = nil + base.UpdateErrorDot(ir.Line(n), n.Left().String(), n.String()) + n.SetType(nil) return n } - s := n.Sym + s := n.Sym() - if n.Left.Op == OTYPE { + if n.Left().Op() == ir.OTYPE { n = typecheckMethodExpr(n) - if n.Type == nil { + if n.Type() == nil { return n } ok = ctxExpr @@ -910,16 +914,16 @@ func typecheck1(n *Node, top int) (res *Node) { if t.IsPtr() && !t.Elem().IsInterface() { t = t.Elem() if t == nil { - n.Type = nil + n.SetType(nil) return n } - n.Op = ODOTPTR + n.SetOp(ir.ODOTPTR) checkwidth(t) } - if n.Sym.IsBlank() { - yyerror("cannot refer to blank field or method") - n.Type = nil + if n.Sym().IsBlank() { + base.Errorf("cannot refer to blank field or method") + n.SetType(nil) return n } @@ -927,29 +931,29 @@ func typecheck1(n *Node, top int) (res *Node) { // Legitimate field or method lookup failed, try to explain the error switch { case t.IsEmptyInterface(): - yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type) + base.Errorf("%v undefined (type %v is interface with no methods)", n, n.Left().Type()) case t.IsPtr() && t.Elem().IsInterface(): // Pointer to interface is almost always a mistake. - yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type) + base.Errorf("%v undefined (type %v is pointer to interface, not interface)", n, n.Left().Type()) case lookdot(n, t, 1) != nil: // Field or method matches by name, but it is not exported. - yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym) + base.Errorf("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym()) default: if mt := lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // Case-insensitive lookup. - yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym) + base.Errorf("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left().Type(), n.Sym(), mt.Sym) } else { - yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym) + base.Errorf("%v undefined (type %v has no field or method %v)", n, n.Left().Type(), n.Sym()) } } - n.Type = nil + n.SetType(nil) return n } - switch n.Op { - case ODOTINTER, ODOTMETH: + switch n.Op() { + case ir.ODOTINTER, ir.ODOTMETH: if top&ctxCallee != 0 { ok |= ctxCallee } else { @@ -961,76 +965,76 @@ func typecheck1(n *Node, top int) (res *Node) { ok |= ctxExpr } - case ODOTTYPE: + case ir.ODOTTYPE: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - l := n.Left - t := l.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + l := n.Left() + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } if !t.IsInterface() { - yyerror("invalid type assertion: %v (non-interface type %v on left)", n, t) - n.Type = nil + base.Errorf("invalid type assertion: %v (non-interface type %v on left)", n, t) + n.SetType(nil) return n } - if n.Right != nil { - n.Right = typecheck(n.Right, ctxType) - n.Type = n.Right.Type - n.Right = nil - if n.Type == nil { + if n.Right() != nil { + n.SetRight(typecheck(n.Right(), ctxType)) + n.SetType(n.Right().Type()) + n.SetRight(nil) + if n.Type() == nil { return n } } - if n.Type != nil && !n.Type.IsInterface() { + if n.Type() != nil && !n.Type().IsInterface() { var missing, have *types.Field var ptr int - if !implements(n.Type, t, &missing, &have, &ptr) { + if !implements(n.Type(), t, &missing, &have, &ptr) { if have != nil && have.Sym == missing.Sym { - yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+ - "\t\thave %v%0S\n\t\twant %v%0S", n.Type, t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) + base.Errorf("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+ + "\t\thave %v%0S\n\t\twant %v%0S", n.Type(), t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) } else if ptr != 0 { - yyerror("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type, t, missing.Sym) + base.Errorf("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type(), t, missing.Sym) } else if have != nil { - yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+ - "\t\thave %v%0S\n\t\twant %v%0S", n.Type, t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) + base.Errorf("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+ + "\t\thave %v%0S\n\t\twant %v%0S", n.Type(), t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) } else { - yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type, t, missing.Sym) + base.Errorf("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type(), t, missing.Sym) } - n.Type = nil + n.SetType(nil) return n } } - case OINDEX: + case ir.OINDEX: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - n.Left = implicitstar(n.Left) - l := n.Left - n.Right = typecheck(n.Right, ctxExpr) - r := n.Right - t := l.Type - if t == nil || r.Type == nil { - n.Type = nil + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + n.SetLeft(implicitstar(n.Left())) + l := n.Left() + n.SetRight(typecheck(n.Right(), ctxExpr)) + r := n.Right() + t := l.Type() + if t == nil || r.Type() == nil { + n.SetType(nil) return n } switch t.Etype { default: - yyerror("invalid operation: %v (type %v does not support indexing)", n, t) - n.Type = nil + base.Errorf("invalid operation: %v (type %v does not support indexing)", n, t) + n.SetType(nil) return n - case TSTRING, TARRAY, TSLICE: - n.Right = indexlit(n.Right) + case types.TSTRING, types.TARRAY, types.TSLICE: + n.SetRight(indexlit(n.Right())) if t.IsString() { - n.Type = types.Bytetype + n.SetType(types.Bytetype) } else { - n.Type = t.Elem() + n.SetType(t.Elem()) } why := "string" if t.IsArray() { @@ -1039,275 +1043,275 @@ func typecheck1(n *Node, top int) (res *Node) { why = "slice" } - if n.Right.Type != nil && !n.Right.Type.IsInteger() { - yyerror("non-integer %s index %v", why, n.Right) + if n.Right().Type() != nil && !n.Right().Type().IsInteger() { + base.Errorf("non-integer %s index %v", why, n.Right()) break } - if !n.Bounded() && Isconst(n.Right, CTINT) { - x := n.Right.Int64Val() - if x < 0 { - yyerror("invalid %s index %v (index must be non-negative)", why, n.Right) - } else if t.IsArray() && x >= t.NumElem() { - yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem()) - } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.StringVal())) { - yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.StringVal())) - } else if n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { - yyerror("invalid %s index %v (index too large)", why, n.Right) + if !n.Bounded() && ir.IsConst(n.Right(), constant.Int) { + x := n.Right().Val() + if constant.Sign(x) < 0 { + base.Errorf("invalid %s index %v (index must be non-negative)", why, n.Right()) + } else if t.IsArray() && constant.Compare(x, token.GEQ, constant.MakeInt64(t.NumElem())) { + base.Errorf("invalid array index %v (out of bounds for %d-element array)", n.Right(), t.NumElem()) + } else if ir.IsConst(n.Left(), constant.String) && constant.Compare(x, token.GEQ, constant.MakeInt64(int64(len(n.Left().StringVal())))) { + base.Errorf("invalid string index %v (out of bounds for %d-byte string)", n.Right(), len(n.Left().StringVal())) + } else if doesoverflow(x, types.Types[types.TINT]) { + base.Errorf("invalid %s index %v (index too large)", why, n.Right()) } } - case TMAP: - n.Right = assignconv(n.Right, t.Key(), "map index") - n.Type = t.Elem() - n.Op = OINDEXMAP + case types.TMAP: + n.SetRight(assignconv(n.Right(), t.Key(), "map index")) + n.SetType(t.Elem()) + n.SetOp(ir.OINDEXMAP) n.ResetAux() } - case ORECV: + case ir.ORECV: ok |= ctxStmt | ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - l := n.Left - t := l.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + l := n.Left() + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } if !t.IsChan() { - yyerror("invalid operation: %v (receive from non-chan type %v)", n, t) - n.Type = nil + base.Errorf("invalid operation: %v (receive from non-chan type %v)", n, t) + n.SetType(nil) return n } if !t.ChanDir().CanRecv() { - yyerror("invalid operation: %v (receive from send-only type %v)", n, t) - n.Type = nil + base.Errorf("invalid operation: %v (receive from send-only type %v)", n, t) + n.SetType(nil) return n } - n.Type = t.Elem() + n.SetType(t.Elem()) - case OSEND: + case ir.OSEND: ok |= ctxStmt - n.Left = typecheck(n.Left, ctxExpr) - n.Right = typecheck(n.Right, ctxExpr) - n.Left = defaultlit(n.Left, nil) - t := n.Left.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetRight(typecheck(n.Right(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + t := n.Left().Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } if !t.IsChan() { - yyerror("invalid operation: %v (send to non-chan type %v)", n, t) - n.Type = nil + base.Errorf("invalid operation: %v (send to non-chan type %v)", n, t) + n.SetType(nil) return n } if !t.ChanDir().CanSend() { - yyerror("invalid operation: %v (send to receive-only type %v)", n, t) - n.Type = nil + base.Errorf("invalid operation: %v (send to receive-only type %v)", n, t) + n.SetType(nil) return n } - n.Right = assignconv(n.Right, t.Elem(), "send") - if n.Right.Type == nil { - n.Type = nil + n.SetRight(assignconv(n.Right(), t.Elem(), "send")) + if n.Right().Type() == nil { + n.SetType(nil) return n } - n.Type = nil + n.SetType(nil) - case OSLICEHEADER: - // Errors here are Fatalf instead of yyerror because only the compiler + case ir.OSLICEHEADER: + // Errors here are Fatalf instead of Errorf because only the compiler // can construct an OSLICEHEADER node. // Components used in OSLICEHEADER that are supplied by parsed source code // have already been typechecked in e.g. OMAKESLICE earlier. ok |= ctxExpr - t := n.Type + t := n.Type() if t == nil { - Fatalf("no type specified for OSLICEHEADER") + base.Fatalf("no type specified for OSLICEHEADER") } if !t.IsSlice() { - Fatalf("invalid type %v for OSLICEHEADER", n.Type) + base.Fatalf("invalid type %v for OSLICEHEADER", n.Type()) } - if n.Left == nil || n.Left.Type == nil || !n.Left.Type.IsUnsafePtr() { - Fatalf("need unsafe.Pointer for OSLICEHEADER") + if n.Left() == nil || n.Left().Type() == nil || !n.Left().Type().IsUnsafePtr() { + base.Fatalf("need unsafe.Pointer for OSLICEHEADER") } - if x := n.List.Len(); x != 2 { - Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x) + if x := n.List().Len(); x != 2 { + base.Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x) } - n.Left = typecheck(n.Left, ctxExpr) - l := typecheck(n.List.First(), ctxExpr) - c := typecheck(n.List.Second(), ctxExpr) - l = defaultlit(l, types.Types[TINT]) - c = defaultlit(c, types.Types[TINT]) + n.SetLeft(typecheck(n.Left(), ctxExpr)) + l := typecheck(n.List().First(), ctxExpr) + c := typecheck(n.List().Second(), ctxExpr) + l = defaultlit(l, types.Types[types.TINT]) + c = defaultlit(c, types.Types[types.TINT]) - if Isconst(l, CTINT) && l.Int64Val() < 0 { - Fatalf("len for OSLICEHEADER must be non-negative") + if ir.IsConst(l, constant.Int) && l.Int64Val() < 0 { + base.Fatalf("len for OSLICEHEADER must be non-negative") } - if Isconst(c, CTINT) && c.Int64Val() < 0 { - Fatalf("cap for OSLICEHEADER must be non-negative") + if ir.IsConst(c, constant.Int) && c.Int64Val() < 0 { + base.Fatalf("cap for OSLICEHEADER must be non-negative") } - if Isconst(l, CTINT) && Isconst(c, CTINT) && l.Val().U.(*Mpint).Cmp(c.Val().U.(*Mpint)) > 0 { - Fatalf("len larger than cap for OSLICEHEADER") + if ir.IsConst(l, constant.Int) && ir.IsConst(c, constant.Int) && constant.Compare(l.Val(), token.GTR, c.Val()) { + base.Fatalf("len larger than cap for OSLICEHEADER") } - n.List.SetFirst(l) - n.List.SetSecond(c) + n.List().SetFirst(l) + n.List().SetSecond(c) - case OMAKESLICECOPY: - // Errors here are Fatalf instead of yyerror because only the compiler + case ir.OMAKESLICECOPY: + // Errors here are Fatalf instead of Errorf because only the compiler // can construct an OMAKESLICECOPY node. // Components used in OMAKESCLICECOPY that are supplied by parsed source code // have already been typechecked in OMAKE and OCOPY earlier. ok |= ctxExpr - t := n.Type + t := n.Type() if t == nil { - Fatalf("no type specified for OMAKESLICECOPY") + base.Fatalf("no type specified for OMAKESLICECOPY") } if !t.IsSlice() { - Fatalf("invalid type %v for OMAKESLICECOPY", n.Type) + base.Fatalf("invalid type %v for OMAKESLICECOPY", n.Type()) } - if n.Left == nil { - Fatalf("missing len argument for OMAKESLICECOPY") + if n.Left() == nil { + base.Fatalf("missing len argument for OMAKESLICECOPY") } - if n.Right == nil { - Fatalf("missing slice argument to copy for OMAKESLICECOPY") + if n.Right() == nil { + base.Fatalf("missing slice argument to copy for OMAKESLICECOPY") } - n.Left = typecheck(n.Left, ctxExpr) - n.Right = typecheck(n.Right, ctxExpr) + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetRight(typecheck(n.Right(), ctxExpr)) - n.Left = defaultlit(n.Left, types.Types[TINT]) + n.SetLeft(defaultlit(n.Left(), types.Types[types.TINT])) - if !n.Left.Type.IsInteger() && n.Type.Etype != TIDEAL { - yyerror("non-integer len argument in OMAKESLICECOPY") + if !n.Left().Type().IsInteger() && n.Type().Etype != types.TIDEAL { + base.Errorf("non-integer len argument in OMAKESLICECOPY") } - if Isconst(n.Left, CTINT) { - if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { - Fatalf("len for OMAKESLICECOPY too large") + if ir.IsConst(n.Left(), constant.Int) { + if doesoverflow(n.Left().Val(), types.Types[types.TINT]) { + base.Fatalf("len for OMAKESLICECOPY too large") } - if n.Left.Int64Val() < 0 { - Fatalf("len for OMAKESLICECOPY must be non-negative") + if constant.Sign(n.Left().Val()) < 0 { + base.Fatalf("len for OMAKESLICECOPY must be non-negative") } } - case OSLICE, OSLICE3: + case ir.OSLICE, ir.OSLICE3: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) + n.SetLeft(typecheck(n.Left(), ctxExpr)) low, high, max := n.SliceBounds() - hasmax := n.Op.IsSlice3() + hasmax := n.Op().IsSlice3() low = typecheck(low, ctxExpr) high = typecheck(high, ctxExpr) max = typecheck(max, ctxExpr) - n.Left = defaultlit(n.Left, nil) + n.SetLeft(defaultlit(n.Left(), nil)) low = indexlit(low) high = indexlit(high) max = indexlit(max) n.SetSliceBounds(low, high, max) - l := n.Left - if l.Type == nil { - n.Type = nil + l := n.Left() + if l.Type() == nil { + n.SetType(nil) return n } - if l.Type.IsArray() { - if !islvalue(n.Left) { - yyerror("invalid operation %v (slice of unaddressable value)", n) - n.Type = nil + if l.Type().IsArray() { + if !islvalue(n.Left()) { + base.Errorf("invalid operation %v (slice of unaddressable value)", n) + n.SetType(nil) return n } - n.Left = nod(OADDR, n.Left, nil) - n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, ctxExpr) - l = n.Left + n.SetLeft(ir.Nod(ir.OADDR, n.Left(), nil)) + n.Left().SetImplicit(true) + n.SetLeft(typecheck(n.Left(), ctxExpr)) + l = n.Left() } - t := l.Type + t := l.Type() var tp *types.Type if t.IsString() { if hasmax { - yyerror("invalid operation %v (3-index slice of string)", n) - n.Type = nil + base.Errorf("invalid operation %v (3-index slice of string)", n) + n.SetType(nil) return n } - n.Type = t - n.Op = OSLICESTR + n.SetType(t) + n.SetOp(ir.OSLICESTR) } else if t.IsPtr() && t.Elem().IsArray() { tp = t.Elem() - n.Type = types.NewSlice(tp.Elem()) - dowidth(n.Type) + n.SetType(types.NewSlice(tp.Elem())) + dowidth(n.Type()) if hasmax { - n.Op = OSLICE3ARR + n.SetOp(ir.OSLICE3ARR) } else { - n.Op = OSLICEARR + n.SetOp(ir.OSLICEARR) } } else if t.IsSlice() { - n.Type = t + n.SetType(t) } else { - yyerror("cannot slice %v (type %v)", l, t) - n.Type = nil + base.Errorf("cannot slice %v (type %v)", l, t) + n.SetType(nil) return n } if low != nil && !checksliceindex(l, low, tp) { - n.Type = nil + n.SetType(nil) return n } if high != nil && !checksliceindex(l, high, tp) { - n.Type = nil + n.SetType(nil) return n } if max != nil && !checksliceindex(l, max, tp) { - n.Type = nil + n.SetType(nil) return n } if !checksliceconst(low, high) || !checksliceconst(low, max) || !checksliceconst(high, max) { - n.Type = nil + n.SetType(nil) return n } // call and call like - case OCALL: - typecheckslice(n.Ninit.Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907) - n.Left = typecheck(n.Left, ctxExpr|ctxType|ctxCallee) - if n.Left.Diag() { + case ir.OCALL: + typecheckslice(n.Init().Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907) + n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType|ctxCallee)) + if n.Left().Diag() { n.SetDiag(true) } - l := n.Left + l := n.Left() - if l.Op == ONAME && l.SubOp() != 0 { - if n.IsDDD() && l.SubOp() != OAPPEND { - yyerror("invalid use of ... with builtin %v", l) + if l.Op() == ir.ONAME && l.SubOp() != 0 { + if n.IsDDD() && l.SubOp() != ir.OAPPEND { + base.Errorf("invalid use of ... with builtin %v", l) } // builtin: OLEN, OCAP, etc. - n.Op = l.SubOp() - n.Left = n.Right - n.Right = nil + n.SetOp(l.SubOp()) + n.SetLeft(n.Right()) + n.SetRight(nil) n = typecheck1(n, top) return n } - n.Left = defaultlit(n.Left, nil) - l = n.Left - if l.Op == OTYPE { + n.SetLeft(defaultlit(n.Left(), nil)) + l = n.Left() + if l.Op() == ir.OTYPE { if n.IsDDD() { - if !l.Type.Broke() { - yyerror("invalid use of ... in type conversion to %v", l.Type) + if !l.Type().Broke() { + base.Errorf("invalid use of ... in type conversion to %v", l.Type()) } n.SetDiag(true) } @@ -1316,12 +1320,12 @@ func typecheck1(n *Node, top int) (res *Node) { ok |= ctxExpr // turn CALL(type, arg) into CONV(arg) w/ type - n.Left = nil + n.SetLeft(nil) - n.Op = OCONV - n.Type = l.Type - if !onearg(n, "conversion to %v", l.Type) { - n.Type = nil + n.SetOp(ir.OCONV) + n.SetType(l.Type()) + if !onearg(n, "conversion to %v", l.Type()) { + n.SetType(nil) return n } n = typecheck1(n, top) @@ -1329,19 +1333,19 @@ func typecheck1(n *Node, top int) (res *Node) { } typecheckargs(n) - t := l.Type + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } checkwidth(t) - switch l.Op { - case ODOTINTER: - n.Op = OCALLINTER + switch l.Op() { + case ir.ODOTINTER: + n.SetOp(ir.OCALLINTER) - case ODOTMETH: - n.Op = OCALLMETH + case ir.ODOTMETH: + n.SetOp(ir.OCALLMETH) // typecheckaste was used here but there wasn't enough // information further down the call chain to know if we @@ -1349,44 +1353,44 @@ func typecheck1(n *Node, top int) (res *Node) { // It isn't necessary, so just do a sanity check. tp := t.Recv().Type - if l.Left == nil || !types.Identical(l.Left.Type, tp) { - Fatalf("method receiver") + if l.Left() == nil || !types.Identical(l.Left().Type(), tp) { + base.Fatalf("method receiver") } default: - n.Op = OCALLFUNC - if t.Etype != TFUNC { + n.SetOp(ir.OCALLFUNC) + if t.Etype != types.TFUNC { name := l.String() - if isBuiltinFuncName(name) && l.Name.Defn != nil { + if isBuiltinFuncName(name) && l.Name().Defn != nil { // be more specific when the function // name matches a predeclared function - yyerror("cannot call non-function %s (type %v), declared at %s", - name, t, linestr(l.Name.Defn.Pos)) + base.Errorf("cannot call non-function %s (type %v), declared at %s", + name, t, base.FmtPos(l.Name().Defn.Pos())) } else { - yyerror("cannot call non-function %s (type %v)", name, t) + base.Errorf("cannot call non-function %s (type %v)", name, t) } - n.Type = nil + n.SetType(nil) return n } } - typecheckaste(OCALL, n.Left, n.IsDDD(), t.Params(), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) }) + typecheckaste(ir.OCALL, n.Left(), n.IsDDD(), t.Params(), n.List(), func() string { return fmt.Sprintf("argument to %v", n.Left()) }) ok |= ctxStmt if t.NumResults() == 0 { break } ok |= ctxExpr if t.NumResults() == 1 { - n.Type = l.Type.Results().Field(0).Type + n.SetType(l.Type().Results().Field(0).Type) - if n.Op == OCALLFUNC && n.Left.Op == ONAME && isRuntimePkg(n.Left.Sym.Pkg) && n.Left.Sym.Name == "getg" { + if n.Op() == ir.OCALLFUNC && n.Left().Op() == ir.ONAME && isRuntimePkg(n.Left().Sym().Pkg) && n.Left().Sym().Name == "getg" { // Emit code for runtime.getg() directly instead of calling function. // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk, // so that the ordering pass can make sure to preserve the semantics of the original code // (in particular, the exact time of the function call) by introducing temporaries. // In this case, we know getg() always returns the same result within a given function // and we want to avoid the temporaries, so we do the rewrite earlier than is typical. - n.Op = OGETG + n.SetOp(ir.OGETG) } break @@ -1394,228 +1398,228 @@ func typecheck1(n *Node, top int) (res *Node) { // multiple return if top&(ctxMultiOK|ctxStmt) == 0 { - yyerror("multiple-value %v() in single-value context", l) + base.Errorf("multiple-value %v() in single-value context", l) break } - n.Type = l.Type.Results() + n.SetType(l.Type().Results()) - case OALIGNOF, OOFFSETOF, OSIZEOF: + case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: ok |= ctxExpr - if !onearg(n, "%v", n.Op) { - n.Type = nil + if !onearg(n, "%v", n.Op()) { + n.SetType(nil) return n } - n.Type = types.Types[TUINTPTR] + n.SetType(types.Types[types.TUINTPTR]) - case OCAP, OLEN: + case ir.OCAP, ir.OLEN: ok |= ctxExpr - if !onearg(n, "%v", n.Op) { - n.Type = nil + if !onearg(n, "%v", n.Op()) { + n.SetType(nil) return n } - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - n.Left = implicitstar(n.Left) - l := n.Left - t := l.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + n.SetLeft(implicitstar(n.Left())) + l := n.Left() + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } var ok bool - if n.Op == OLEN { + if n.Op() == ir.OLEN { ok = okforlen[t.Etype] } else { ok = okforcap[t.Etype] } if !ok { - yyerror("invalid argument %L for %v", l, n.Op) - n.Type = nil + base.Errorf("invalid argument %L for %v", l, n.Op()) + n.SetType(nil) return n } - n.Type = types.Types[TINT] + n.SetType(types.Types[types.TINT]) - case OREAL, OIMAG: + case ir.OREAL, ir.OIMAG: ok |= ctxExpr - if !onearg(n, "%v", n.Op) { - n.Type = nil + if !onearg(n, "%v", n.Op()) { + n.SetType(nil) return n } - n.Left = typecheck(n.Left, ctxExpr) - l := n.Left - t := l.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + l := n.Left() + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } // Determine result type. switch t.Etype { - case TIDEAL: - n.Type = types.UntypedFloat - case TCOMPLEX64: - n.Type = types.Types[TFLOAT32] - case TCOMPLEX128: - n.Type = types.Types[TFLOAT64] + case types.TIDEAL: + n.SetType(types.UntypedFloat) + case types.TCOMPLEX64: + n.SetType(types.Types[types.TFLOAT32]) + case types.TCOMPLEX128: + n.SetType(types.Types[types.TFLOAT64]) default: - yyerror("invalid argument %L for %v", l, n.Op) - n.Type = nil + base.Errorf("invalid argument %L for %v", l, n.Op()) + n.SetType(nil) return n } - case OCOMPLEX: + case ir.OCOMPLEX: ok |= ctxExpr typecheckargs(n) if !twoarg(n) { - n.Type = nil + n.SetType(nil) return n } - l := n.Left - r := n.Right - if l.Type == nil || r.Type == nil { - n.Type = nil + l := n.Left() + r := n.Right() + if l.Type() == nil || r.Type() == nil { + n.SetType(nil) return n } l, r = defaultlit2(l, r, false) - if l.Type == nil || r.Type == nil { - n.Type = nil + if l.Type() == nil || r.Type() == nil { + n.SetType(nil) return n } - n.Left = l - n.Right = r + n.SetLeft(l) + n.SetRight(r) - if !types.Identical(l.Type, r.Type) { - yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type) - n.Type = nil + if !types.Identical(l.Type(), r.Type()) { + base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type()) + n.SetType(nil) return n } var t *types.Type - switch l.Type.Etype { + switch l.Type().Etype { default: - yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type) - n.Type = nil + base.Errorf("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type()) + n.SetType(nil) return n - case TIDEAL: + case types.TIDEAL: t = types.UntypedComplex - case TFLOAT32: - t = types.Types[TCOMPLEX64] + case types.TFLOAT32: + t = types.Types[types.TCOMPLEX64] - case TFLOAT64: - t = types.Types[TCOMPLEX128] + case types.TFLOAT64: + t = types.Types[types.TCOMPLEX128] } - n.Type = t + n.SetType(t) - case OCLOSE: - if !onearg(n, "%v", n.Op) { - n.Type = nil + case ir.OCLOSE: + if !onearg(n, "%v", n.Op()) { + n.SetType(nil) return n } - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - l := n.Left - t := l.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + l := n.Left() + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } if !t.IsChan() { - yyerror("invalid operation: %v (non-chan type %v)", n, t) - n.Type = nil + base.Errorf("invalid operation: %v (non-chan type %v)", n, t) + n.SetType(nil) return n } if !t.ChanDir().CanSend() { - yyerror("invalid operation: %v (cannot close receive-only channel)", n) - n.Type = nil + base.Errorf("invalid operation: %v (cannot close receive-only channel)", n) + n.SetType(nil) return n } ok |= ctxStmt - case ODELETE: + case ir.ODELETE: ok |= ctxStmt typecheckargs(n) - args := n.List + args := n.List() if args.Len() == 0 { - yyerror("missing arguments to delete") - n.Type = nil + base.Errorf("missing arguments to delete") + n.SetType(nil) return n } if args.Len() == 1 { - yyerror("missing second (key) argument to delete") - n.Type = nil + base.Errorf("missing second (key) argument to delete") + n.SetType(nil) return n } if args.Len() != 2 { - yyerror("too many arguments to delete") - n.Type = nil + base.Errorf("too many arguments to delete") + n.SetType(nil) return n } l := args.First() r := args.Second() - if l.Type != nil && !l.Type.IsMap() { - yyerror("first argument to delete must be map; have %L", l.Type) - n.Type = nil + if l.Type() != nil && !l.Type().IsMap() { + base.Errorf("first argument to delete must be map; have %L", l.Type()) + n.SetType(nil) return n } - args.SetSecond(assignconv(r, l.Type.Key(), "delete")) + args.SetSecond(assignconv(r, l.Type().Key(), "delete")) - case OAPPEND: + case ir.OAPPEND: ok |= ctxExpr typecheckargs(n) - args := n.List + args := n.List() if args.Len() == 0 { - yyerror("missing arguments to append") - n.Type = nil + base.Errorf("missing arguments to append") + n.SetType(nil) return n } - t := args.First().Type + t := args.First().Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } - n.Type = t + n.SetType(t) if !t.IsSlice() { - if Isconst(args.First(), CTNIL) { - yyerror("first argument to append must be typed slice; have untyped nil") - n.Type = nil + if ir.IsNil(args.First()) { + base.Errorf("first argument to append must be typed slice; have untyped nil") + n.SetType(nil) return n } - yyerror("first argument to append must be slice; have %L", t) - n.Type = nil + base.Errorf("first argument to append must be slice; have %L", t) + n.SetType(nil) return n } if n.IsDDD() { if args.Len() == 1 { - yyerror("cannot use ... on first argument to append") - n.Type = nil + base.Errorf("cannot use ... on first argument to append") + n.SetType(nil) return n } if args.Len() != 2 { - yyerror("too many arguments to append") - n.Type = nil + base.Errorf("too many arguments to append") + n.SetType(nil) return n } - if t.Elem().IsKind(TUINT8) && args.Second().Type.IsString() { - args.SetSecond(defaultlit(args.Second(), types.Types[TSTRING])) + if t.Elem().IsKind(types.TUINT8) && args.Second().Type().IsString() { + args.SetSecond(defaultlit(args.Second(), types.Types[types.TSTRING])) break } @@ -1625,464 +1629,464 @@ func typecheck1(n *Node, top int) (res *Node) { as := args.Slice()[1:] for i, n := range as { - if n.Type == nil { + if n.Type() == nil { continue } as[i] = assignconv(n, t.Elem(), "append") - checkwidth(as[i].Type) // ensure width is calculated for backend + checkwidth(as[i].Type()) // ensure width is calculated for backend } - case OCOPY: + case ir.OCOPY: ok |= ctxStmt | ctxExpr typecheckargs(n) if !twoarg(n) { - n.Type = nil + n.SetType(nil) return n } - n.Type = types.Types[TINT] - if n.Left.Type == nil || n.Right.Type == nil { - n.Type = nil + n.SetType(types.Types[types.TINT]) + if n.Left().Type() == nil || n.Right().Type() == nil { + n.SetType(nil) return n } - n.Left = defaultlit(n.Left, nil) - n.Right = defaultlit(n.Right, nil) - if n.Left.Type == nil || n.Right.Type == nil { - n.Type = nil + n.SetLeft(defaultlit(n.Left(), nil)) + n.SetRight(defaultlit(n.Right(), nil)) + if n.Left().Type() == nil || n.Right().Type() == nil { + n.SetType(nil) return n } // copy([]byte, string) - if n.Left.Type.IsSlice() && n.Right.Type.IsString() { - if types.Identical(n.Left.Type.Elem(), types.Bytetype) { + if n.Left().Type().IsSlice() && n.Right().Type().IsString() { + if types.Identical(n.Left().Type().Elem(), types.Bytetype) { break } - yyerror("arguments to copy have different element types: %L and string", n.Left.Type) - n.Type = nil + base.Errorf("arguments to copy have different element types: %L and string", n.Left().Type()) + n.SetType(nil) return n } - if !n.Left.Type.IsSlice() || !n.Right.Type.IsSlice() { - if !n.Left.Type.IsSlice() && !n.Right.Type.IsSlice() { - yyerror("arguments to copy must be slices; have %L, %L", n.Left.Type, n.Right.Type) - } else if !n.Left.Type.IsSlice() { - yyerror("first argument to copy should be slice; have %L", n.Left.Type) + if !n.Left().Type().IsSlice() || !n.Right().Type().IsSlice() { + if !n.Left().Type().IsSlice() && !n.Right().Type().IsSlice() { + base.Errorf("arguments to copy must be slices; have %L, %L", n.Left().Type(), n.Right().Type()) + } else if !n.Left().Type().IsSlice() { + base.Errorf("first argument to copy should be slice; have %L", n.Left().Type()) } else { - yyerror("second argument to copy should be slice or string; have %L", n.Right.Type) + base.Errorf("second argument to copy should be slice or string; have %L", n.Right().Type()) } - n.Type = nil + n.SetType(nil) return n } - if !types.Identical(n.Left.Type.Elem(), n.Right.Type.Elem()) { - yyerror("arguments to copy have different element types: %L and %L", n.Left.Type, n.Right.Type) - n.Type = nil + if !types.Identical(n.Left().Type().Elem(), n.Right().Type().Elem()) { + base.Errorf("arguments to copy have different element types: %L and %L", n.Left().Type(), n.Right().Type()) + n.SetType(nil) return n } - case OCONV: + case ir.OCONV: ok |= ctxExpr - checkwidth(n.Type) // ensure width is calculated for backend - n.Left = typecheck(n.Left, ctxExpr) - n.Left = convlit1(n.Left, n.Type, true, nil) - t := n.Left.Type - if t == nil || n.Type == nil { - n.Type = nil - return n - } - var why string - n.Op, why = convertop(n.Left.Op == OLITERAL, t, n.Type) - if n.Op == OXXX { - if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() { - yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why) + checkwidth(n.Type()) // ensure width is calculated for backend + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(convlit1(n.Left(), n.Type(), true, nil)) + t := n.Left().Type() + if t == nil || n.Type() == nil { + n.SetType(nil) + return n + } + op, why := convertop(n.Left().Op() == ir.OLITERAL, t, n.Type()) + n.SetOp(op) + if n.Op() == ir.OXXX { + if !n.Diag() && !n.Type().Broke() && !n.Left().Diag() { + base.Errorf("cannot convert %L to type %v%s", n.Left(), n.Type(), why) n.SetDiag(true) } - n.Op = OCONV - n.Type = nil + n.SetOp(ir.OCONV) + n.SetType(nil) return n } - switch n.Op { - case OCONVNOP: - if t.Etype == n.Type.Etype { + switch n.Op() { + case ir.OCONVNOP: + if t.Etype == n.Type().Etype { switch t.Etype { - case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128: + case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128: // Floating point casts imply rounding and // so the conversion must be kept. - n.Op = OCONV + n.SetOp(ir.OCONV) } } // do not convert to []byte literal. See CL 125796. // generated code and compiler memory footprint is better without it. - case OSTR2BYTES: + case ir.OSTR2BYTES: break - case OSTR2RUNES: - if n.Left.Op == OLITERAL { + case ir.OSTR2RUNES: + if n.Left().Op() == ir.OLITERAL { n = stringtoruneslit(n) } } - case OMAKE: + case ir.OMAKE: ok |= ctxExpr - args := n.List.Slice() + args := n.List().Slice() if len(args) == 0 { - yyerror("missing argument to make") - n.Type = nil + base.Errorf("missing argument to make") + n.SetType(nil) return n } - n.List.Set(nil) + n.PtrList().Set(nil) l := args[0] l = typecheck(l, ctxType) - t := l.Type + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } i := 1 switch t.Etype { default: - yyerror("cannot make type %v", t) - n.Type = nil + base.Errorf("cannot make type %v", t) + n.SetType(nil) return n - case TSLICE: + case types.TSLICE: if i >= len(args) { - yyerror("missing len argument to make(%v)", t) - n.Type = nil + base.Errorf("missing len argument to make(%v)", t) + n.SetType(nil) return n } l = args[i] i++ l = typecheck(l, ctxExpr) - var r *Node + var r ir.Node if i < len(args) { r = args[i] i++ r = typecheck(r, ctxExpr) } - if l.Type == nil || (r != nil && r.Type == nil) { - n.Type = nil + if l.Type() == nil || (r != nil && r.Type() == nil) { + n.SetType(nil) return n } if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) { - n.Type = nil + n.SetType(nil) return n } - if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && l.Val().U.(*Mpint).Cmp(r.Val().U.(*Mpint)) > 0 { - yyerror("len larger than cap in make(%v)", t) - n.Type = nil + if ir.IsConst(l, constant.Int) && r != nil && ir.IsConst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) { + base.Errorf("len larger than cap in make(%v)", t) + n.SetType(nil) return n } - n.Left = l - n.Right = r - n.Op = OMAKESLICE + n.SetLeft(l) + n.SetRight(r) + n.SetOp(ir.OMAKESLICE) - case TMAP: + case types.TMAP: if i < len(args) { l = args[i] i++ l = typecheck(l, ctxExpr) - l = defaultlit(l, types.Types[TINT]) - if l.Type == nil { - n.Type = nil + l = defaultlit(l, types.Types[types.TINT]) + if l.Type() == nil { + n.SetType(nil) return n } if !checkmake(t, "size", &l) { - n.Type = nil + n.SetType(nil) return n } - n.Left = l + n.SetLeft(l) } else { - n.Left = nodintconst(0) + n.SetLeft(nodintconst(0)) } - n.Op = OMAKEMAP + n.SetOp(ir.OMAKEMAP) - case TCHAN: + case types.TCHAN: l = nil if i < len(args) { l = args[i] i++ l = typecheck(l, ctxExpr) - l = defaultlit(l, types.Types[TINT]) - if l.Type == nil { - n.Type = nil + l = defaultlit(l, types.Types[types.TINT]) + if l.Type() == nil { + n.SetType(nil) return n } if !checkmake(t, "buffer", &l) { - n.Type = nil + n.SetType(nil) return n } - n.Left = l + n.SetLeft(l) } else { - n.Left = nodintconst(0) + n.SetLeft(nodintconst(0)) } - n.Op = OMAKECHAN + n.SetOp(ir.OMAKECHAN) } if i < len(args) { - yyerror("too many arguments to make(%v)", t) - n.Op = OMAKE - n.Type = nil + base.Errorf("too many arguments to make(%v)", t) + n.SetOp(ir.OMAKE) + n.SetType(nil) return n } - n.Type = t + n.SetType(t) - case ONEW: + case ir.ONEW: ok |= ctxExpr - args := n.List + args := n.List() if args.Len() == 0 { - yyerror("missing argument to new") - n.Type = nil + base.Errorf("missing argument to new") + n.SetType(nil) return n } l := args.First() l = typecheck(l, ctxType) - t := l.Type + t := l.Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } if args.Len() > 1 { - yyerror("too many arguments to new(%v)", t) - n.Type = nil + base.Errorf("too many arguments to new(%v)", t) + n.SetType(nil) return n } - n.Left = l - n.Type = types.NewPtr(t) + n.SetLeft(l) + n.SetType(types.NewPtr(t)) - case OPRINT, OPRINTN: + case ir.OPRINT, ir.OPRINTN: ok |= ctxStmt typecheckargs(n) - ls := n.List.Slice() + ls := n.List().Slice() for i1, n1 := range ls { // Special case for print: int constant is int64, not int. - if Isconst(n1, CTINT) { - ls[i1] = defaultlit(ls[i1], types.Types[TINT64]) + if ir.IsConst(n1, constant.Int) { + ls[i1] = defaultlit(ls[i1], types.Types[types.TINT64]) } else { ls[i1] = defaultlit(ls[i1], nil) } } - case OPANIC: + case ir.OPANIC: ok |= ctxStmt if !onearg(n, "panic") { - n.Type = nil + n.SetType(nil) return n } - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, types.Types[TINTER]) - if n.Left.Type == nil { - n.Type = nil + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), types.Types[types.TINTER])) + if n.Left().Type() == nil { + n.SetType(nil) return n } - case ORECOVER: + case ir.ORECOVER: ok |= ctxExpr | ctxStmt - if n.List.Len() != 0 { - yyerror("too many arguments to recover") - n.Type = nil + if n.List().Len() != 0 { + base.Errorf("too many arguments to recover") + n.SetType(nil) return n } - n.Type = types.Types[TINTER] + n.SetType(types.Types[types.TINTER]) - case OCLOSURE: + case ir.OCLOSURE: ok |= ctxExpr typecheckclosure(n, top) - if n.Type == nil { + if n.Type() == nil { return n } - case OITAB: + case ir.OITAB: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - t := n.Left.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + t := n.Left().Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } if !t.IsInterface() { - Fatalf("OITAB of %v", t) + base.Fatalf("OITAB of %v", t) } - n.Type = types.NewPtr(types.Types[TUINTPTR]) + n.SetType(types.NewPtr(types.Types[types.TUINTPTR])) - case OIDATA: + case ir.OIDATA: // Whoever creates the OIDATA node must know a priori the concrete type at that moment, // usually by just having checked the OITAB. - Fatalf("cannot typecheck interface data %v", n) + base.Fatalf("cannot typecheck interface data %v", n) - case OSPTR: + case ir.OSPTR: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - t := n.Left.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + t := n.Left().Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } if !t.IsSlice() && !t.IsString() { - Fatalf("OSPTR of %v", t) + base.Fatalf("OSPTR of %v", t) } if t.IsString() { - n.Type = types.NewPtr(types.Types[TUINT8]) + n.SetType(types.NewPtr(types.Types[types.TUINT8])) } else { - n.Type = types.NewPtr(t.Elem()) + n.SetType(types.NewPtr(t.Elem())) } - case OCLOSUREVAR: + case ir.OCLOSUREVAR: ok |= ctxExpr - case OCFUNC: + case ir.OCFUNC: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) - n.Type = types.Types[TUINTPTR] + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetType(types.Types[types.TUINTPTR]) - case OCONVNOP: + case ir.OCONVNOP: ok |= ctxExpr - n.Left = typecheck(n.Left, ctxExpr) + n.SetLeft(typecheck(n.Left(), ctxExpr)) // statements - case OAS: + case ir.OAS: ok |= ctxStmt typecheckas(n) // Code that creates temps does not bother to set defn, so do it here. - if n.Left.Op == ONAME && n.Left.IsAutoTmp() { - n.Left.Name.Defn = n + if n.Left().Op() == ir.ONAME && ir.IsAutoTmp(n.Left()) { + n.Left().Name().Defn = n } - case OAS2: + case ir.OAS2: ok |= ctxStmt typecheckas2(n) - case OBREAK, - OCONTINUE, - ODCL, - OEMPTY, - OGOTO, - OFALL, - OVARKILL, - OVARLIVE: + case ir.OBREAK, + ir.OCONTINUE, + ir.ODCL, + ir.OEMPTY, + ir.OGOTO, + ir.OFALL, + ir.OVARKILL, + ir.OVARLIVE: ok |= ctxStmt - case OLABEL: + case ir.OLABEL: ok |= ctxStmt decldepth++ - if n.Sym.IsBlank() { + if n.Sym().IsBlank() { // Empty identifier is valid but useless. // Eliminate now to simplify life later. // See issues 7538, 11589, 11593. - n.Op = OEMPTY - n.Left = nil + n.SetOp(ir.OEMPTY) + n.SetLeft(nil) } - case ODEFER: + case ir.ODEFER: ok |= ctxStmt - n.Left = typecheck(n.Left, ctxStmt|ctxExpr) - if !n.Left.Diag() { + n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr)) + if !n.Left().Diag() { checkdefergo(n) } - case OGO: + case ir.OGO: ok |= ctxStmt - n.Left = typecheck(n.Left, ctxStmt|ctxExpr) + n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr)) checkdefergo(n) - case OFOR, OFORUNTIL: + case ir.OFOR, ir.OFORUNTIL: ok |= ctxStmt - typecheckslice(n.Ninit.Slice(), ctxStmt) + typecheckslice(n.Init().Slice(), ctxStmt) decldepth++ - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - if n.Left != nil { - t := n.Left.Type + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + if n.Left() != nil { + t := n.Left().Type() if t != nil && !t.IsBoolean() { - yyerror("non-bool %L used as for condition", n.Left) + base.Errorf("non-bool %L used as for condition", n.Left()) } } - n.Right = typecheck(n.Right, ctxStmt) - if n.Op == OFORUNTIL { - typecheckslice(n.List.Slice(), ctxStmt) + n.SetRight(typecheck(n.Right(), ctxStmt)) + if n.Op() == ir.OFORUNTIL { + typecheckslice(n.List().Slice(), ctxStmt) } - typecheckslice(n.Nbody.Slice(), ctxStmt) + typecheckslice(n.Body().Slice(), ctxStmt) decldepth-- - case OIF: + case ir.OIF: ok |= ctxStmt - typecheckslice(n.Ninit.Slice(), ctxStmt) - n.Left = typecheck(n.Left, ctxExpr) - n.Left = defaultlit(n.Left, nil) - if n.Left != nil { - t := n.Left.Type + typecheckslice(n.Init().Slice(), ctxStmt) + n.SetLeft(typecheck(n.Left(), ctxExpr)) + n.SetLeft(defaultlit(n.Left(), nil)) + if n.Left() != nil { + t := n.Left().Type() if t != nil && !t.IsBoolean() { - yyerror("non-bool %L used as if condition", n.Left) + base.Errorf("non-bool %L used as if condition", n.Left()) } } - typecheckslice(n.Nbody.Slice(), ctxStmt) - typecheckslice(n.Rlist.Slice(), ctxStmt) + typecheckslice(n.Body().Slice(), ctxStmt) + typecheckslice(n.Rlist().Slice(), ctxStmt) - case ORETURN: + case ir.ORETURN: ok |= ctxStmt typecheckargs(n) if Curfn == nil { - yyerror("return outside function") - n.Type = nil + base.Errorf("return outside function") + n.SetType(nil) return n } - if Curfn.Type.FuncType().Outnamed && n.List.Len() == 0 { + if Curfn.Type().FuncType().Outnamed && n.List().Len() == 0 { break } - typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" }) + typecheckaste(ir.ORETURN, nil, false, Curfn.Type().Results(), n.List(), func() string { return "return argument" }) - case ORETJMP: + case ir.ORETJMP: ok |= ctxStmt - case OSELECT: + case ir.OSELECT: ok |= ctxStmt typecheckselect(n) - case OSWITCH: + case ir.OSWITCH: ok |= ctxStmt typecheckswitch(n) - case ORANGE: + case ir.ORANGE: ok |= ctxStmt typecheckrange(n) - case OTYPESW: - yyerror("use of .(type) outside type switch") - n.Type = nil + case ir.OTYPESW: + base.Errorf("use of .(type) outside type switch") + n.SetType(nil) return n - case ODCLFUNC: + case ir.ODCLFUNC: ok |= ctxStmt typecheckfunc(n) - case ODCLCONST: + case ir.ODCLCONST: ok |= ctxStmt - n.Left = typecheck(n.Left, ctxExpr) + n.SetLeft(typecheck(n.Left(), ctxExpr)) - case ODCLTYPE: + case ir.ODCLTYPE: ok |= ctxStmt - n.Left = typecheck(n.Left, ctxType) - checkwidth(n.Left.Type) + n.SetLeft(typecheck(n.Left(), ctxType)) + checkwidth(n.Left().Type()) } - t := n.Type - if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE { + t := n.Type() + if t != nil && !t.IsFuncArgStruct() && n.Op() != ir.OTYPE { switch t.Etype { - case TFUNC, // might have TANY; wait until it's called - TANY, TFORW, TIDEAL, TNIL, TBLANK: + case types.TFUNC, // might have TANY; wait until it's called + types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK: break default: @@ -2090,49 +2094,49 @@ func typecheck1(n *Node, top int) (res *Node) { } } - evconst(n) - if n.Op == OTYPE && top&ctxType == 0 { - if !n.Type.Broke() { - yyerror("type %v is not an expression", n.Type) + n = evalConst(n) + if n.Op() == ir.OTYPE && top&ctxType == 0 { + if !n.Type().Broke() { + base.Errorf("type %v is not an expression", n.Type()) } - n.Type = nil + n.SetType(nil) return n } - if top&(ctxExpr|ctxType) == ctxType && n.Op != OTYPE { - yyerror("%v is not a type", n) - n.Type = nil + if top&(ctxExpr|ctxType) == ctxType && n.Op() != ir.OTYPE { + base.Errorf("%v is not a type", n) + n.SetType(nil) return n } // TODO(rsc): simplify if (top&(ctxCallee|ctxExpr|ctxType) != 0) && top&ctxStmt == 0 && ok&(ctxExpr|ctxType|ctxCallee) == 0 { - yyerror("%v used as value", n) - n.Type = nil + base.Errorf("%v used as value", n) + n.SetType(nil) return n } if (top&ctxStmt != 0) && top&(ctxCallee|ctxExpr|ctxType) == 0 && ok&ctxStmt == 0 { if !n.Diag() { - yyerror("%v evaluated but not used", n) + base.Errorf("%v evaluated but not used", n) n.SetDiag(true) } - n.Type = nil + n.SetType(nil) return n } return n } -func typecheckargs(n *Node) { - if n.List.Len() != 1 || n.IsDDD() { - typecheckslice(n.List.Slice(), ctxExpr) +func typecheckargs(n ir.Node) { + if n.List().Len() != 1 || n.IsDDD() { + typecheckslice(n.List().Slice(), ctxExpr) return } - typecheckslice(n.List.Slice(), ctxExpr|ctxMultiOK) - t := n.List.First().Type + typecheckslice(n.List().Slice(), ctxExpr|ctxMultiOK) + t := n.List().First().Type() if t == nil || !t.IsFuncArgStruct() { return } @@ -2140,58 +2144,59 @@ func typecheckargs(n *Node) { // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...). // Save n as n.Orig for fmt.go. - if n.Orig == n { - n.Orig = n.sepcopy() + if n.Orig() == n { + n.SetOrig(ir.SepCopy(n)) } - as := nod(OAS2, nil, nil) - as.Rlist.AppendNodes(&n.List) + as := ir.Nod(ir.OAS2, nil, nil) + as.PtrRlist().AppendNodes(n.PtrList()) // If we're outside of function context, then this call will // be executed during the generated init function. However, // init.go hasn't yet created it. Instead, associate the - // temporary variables with dummyInitFn for now, and init.go + // temporary variables with initTodo for now, and init.go // will reassociate them later when it's appropriate. static := Curfn == nil if static { - Curfn = dummyInitFn + Curfn = initTodo } for _, f := range t.FieldSlice() { t := temp(f.Type) - as.Ninit.Append(nod(ODCL, t, nil)) - as.List.Append(t) - n.List.Append(t) + as.PtrInit().Append(ir.Nod(ir.ODCL, t, nil)) + as.PtrList().Append(t) + n.PtrList().Append(t) } if static { Curfn = nil } as = typecheck(as, ctxStmt) - n.Ninit.Append(as) + n.PtrInit().Append(as) } -func checksliceindex(l *Node, r *Node, tp *types.Type) bool { - t := r.Type +func checksliceindex(l ir.Node, r ir.Node, tp *types.Type) bool { + t := r.Type() if t == nil { return false } if !t.IsInteger() { - yyerror("invalid slice index %v (type %v)", r, t) + base.Errorf("invalid slice index %v (type %v)", r, t) return false } - if r.Op == OLITERAL { - if r.Int64Val() < 0 { - yyerror("invalid slice index %v (index must be non-negative)", r) + if r.Op() == ir.OLITERAL { + x := r.Val() + if constant.Sign(x) < 0 { + base.Errorf("invalid slice index %v (index must be non-negative)", r) return false - } else if tp != nil && tp.NumElem() >= 0 && r.Int64Val() > tp.NumElem() { - yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem()) + } else if tp != nil && tp.NumElem() >= 0 && constant.Compare(x, token.GTR, constant.MakeInt64(tp.NumElem())) { + base.Errorf("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem()) return false - } else if Isconst(l, CTSTR) && r.Int64Val() > int64(len(l.StringVal())) { - yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal())) + } else if ir.IsConst(l, constant.String) && constant.Compare(x, token.GTR, constant.MakeInt64(int64(len(l.StringVal())))) { + base.Errorf("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal())) return false - } else if r.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { - yyerror("invalid slice index %v (index too large)", r) + } else if doesoverflow(x, types.Types[types.TINT]) { + base.Errorf("invalid slice index %v (index too large)", r) return false } } @@ -2199,57 +2204,57 @@ func checksliceindex(l *Node, r *Node, tp *types.Type) bool { return true } -func checksliceconst(lo *Node, hi *Node) bool { - if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && lo.Val().U.(*Mpint).Cmp(hi.Val().U.(*Mpint)) > 0 { - yyerror("invalid slice index: %v > %v", lo, hi) +func checksliceconst(lo ir.Node, hi ir.Node) bool { + if lo != nil && hi != nil && lo.Op() == ir.OLITERAL && hi.Op() == ir.OLITERAL && constant.Compare(lo.Val(), token.GTR, hi.Val()) { + base.Errorf("invalid slice index: %v > %v", lo, hi) return false } return true } -func checkdefergo(n *Node) { +func checkdefergo(n ir.Node) { what := "defer" - if n.Op == OGO { + if n.Op() == ir.OGO { what = "go" } - switch n.Left.Op { + switch n.Left().Op() { // ok - case OCALLINTER, - OCALLMETH, - OCALLFUNC, - OCLOSE, - OCOPY, - ODELETE, - OPANIC, - OPRINT, - OPRINTN, - ORECOVER: + case ir.OCALLINTER, + ir.OCALLMETH, + ir.OCALLFUNC, + ir.OCLOSE, + ir.OCOPY, + ir.ODELETE, + ir.OPANIC, + ir.OPRINT, + ir.OPRINTN, + ir.ORECOVER: return - case OAPPEND, - OCAP, - OCOMPLEX, - OIMAG, - OLEN, - OMAKE, - OMAKESLICE, - OMAKECHAN, - OMAKEMAP, - ONEW, - OREAL, - OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof - if n.Left.Orig != nil && n.Left.Orig.Op == OCONV { + case ir.OAPPEND, + ir.OCAP, + ir.OCOMPLEX, + ir.OIMAG, + ir.OLEN, + ir.OMAKE, + ir.OMAKESLICE, + ir.OMAKECHAN, + ir.OMAKEMAP, + ir.ONEW, + ir.OREAL, + ir.OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof + if n.Left().Orig() != nil && n.Left().Orig().Op() == ir.OCONV { break } - yyerrorl(n.Pos, "%s discards result of %v", what, n.Left) + base.ErrorfAt(n.Pos(), "%s discards result of %v", what, n.Left()) return } // type is broken or missing, most likely a method call on a broken type // we will warn about the broken type elsewhere. no need to emit a potentially confusing error - if n.Left.Type == nil || n.Left.Type.Broke() { + if n.Left().Type() == nil || n.Left().Type().Broke() { return } @@ -2257,15 +2262,15 @@ func checkdefergo(n *Node) { // The syntax made sure it was a call, so this must be // a conversion. n.SetDiag(true) - yyerrorl(n.Pos, "%s requires function call, not conversion", what) + base.ErrorfAt(n.Pos(), "%s requires function call, not conversion", what) } } // The result of implicitstar MUST be assigned back to n, e.g. // n.Left = implicitstar(n.Left) -func implicitstar(n *Node) *Node { +func implicitstar(n ir.Node) ir.Node { // insert implicit * if needed for fixed array - t := n.Type + t := n.Type() if t == nil || !t.IsPtr() { return n } @@ -2276,54 +2281,54 @@ func implicitstar(n *Node) *Node { if !t.IsArray() { return n } - n = nod(ODEREF, n, nil) + n = ir.Nod(ir.ODEREF, n, nil) n.SetImplicit(true) n = typecheck(n, ctxExpr) return n } -func onearg(n *Node, f string, args ...interface{}) bool { - if n.Left != nil { +func onearg(n ir.Node, f string, args ...interface{}) bool { + if n.Left() != nil { return true } - if n.List.Len() == 0 { + if n.List().Len() == 0 { p := fmt.Sprintf(f, args...) - yyerror("missing argument to %s: %v", p, n) + base.Errorf("missing argument to %s: %v", p, n) return false } - if n.List.Len() > 1 { + if n.List().Len() > 1 { p := fmt.Sprintf(f, args...) - yyerror("too many arguments to %s: %v", p, n) - n.Left = n.List.First() - n.List.Set(nil) + base.Errorf("too many arguments to %s: %v", p, n) + n.SetLeft(n.List().First()) + n.PtrList().Set(nil) return false } - n.Left = n.List.First() - n.List.Set(nil) + n.SetLeft(n.List().First()) + n.PtrList().Set(nil) return true } -func twoarg(n *Node) bool { - if n.Left != nil { +func twoarg(n ir.Node) bool { + if n.Left() != nil { return true } - if n.List.Len() != 2 { - if n.List.Len() < 2 { - yyerror("not enough arguments in call to %v", n) + if n.List().Len() != 2 { + if n.List().Len() < 2 { + base.Errorf("not enough arguments in call to %v", n) } else { - yyerror("too many arguments in call to %v", n) + base.Errorf("too many arguments in call to %v", n) } return false } - n.Left = n.List.First() - n.Right = n.List.Second() - n.List.Set(nil) + n.SetLeft(n.List().First()) + n.SetRight(n.List().Second()) + n.PtrList().Set(nil) return true } -func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field { +func lookdot1(errnode ir.Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field { var r *types.Field for _, f := range fs.Slice() { if dostrcmp != 0 && f.Sym.Name == s.Name { @@ -2337,11 +2342,11 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost } if r != nil { if errnode != nil { - yyerror("ambiguous selector %v", errnode) + base.Errorf("ambiguous selector %v", errnode) } else if t.IsPtr() { - yyerror("ambiguous selector (%v).%v", t, s) + base.Errorf("ambiguous selector (%v).%v", t, s) } else { - yyerror("ambiguous selector %v.%v", t, s) + base.Errorf("ambiguous selector %v.%v", t, s) } break } @@ -2354,12 +2359,12 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost // typecheckMethodExpr checks selector expressions (ODOT) where the // base expression is a type expression (OTYPE). -func typecheckMethodExpr(n *Node) (res *Node) { - if enableTrace && trace { +func typecheckMethodExpr(n ir.Node) (res ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheckMethodExpr", n)(&res) } - t := n.Left.Type + t := n.Left().Type() // Compute the method set for t. var ms *types.Fields @@ -2368,8 +2373,8 @@ func typecheckMethodExpr(n *Node) (res *Node) { } else { mt := methtype(t) if mt == nil { - yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym) - n.Type = nil + base.Errorf("%v undefined (type %v has no method %v)", n, t, n.Sym()) + n.SetType(nil) return n } expandmeth(mt) @@ -2387,40 +2392,41 @@ func typecheckMethodExpr(n *Node) (res *Node) { } } - s := n.Sym + s := n.Sym() m := lookdot1(n, s, t, ms, 0) if m == nil { if lookdot1(n, s, t, ms, 1) != nil { - yyerror("%v undefined (cannot refer to unexported method %v)", n, s) + base.Errorf("%v undefined (cannot refer to unexported method %v)", n, s) } else if _, ambig := dotpath(s, t, nil, false); ambig { - yyerror("%v undefined (ambiguous selector)", n) // method or field + base.Errorf("%v undefined (ambiguous selector)", n) // method or field } else { - yyerror("%v undefined (type %v has no method %v)", n, t, s) + base.Errorf("%v undefined (type %v has no method %v)", n, t, s) } - n.Type = nil + n.SetType(nil) return n } if !isMethodApplicable(t, m) { - yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, s) - n.Type = nil + base.Errorf("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, s) + n.SetType(nil) return n } - n.Op = ONAME - if n.Name == nil { - n.Name = new(Name) + n.SetOp(ir.OMETHEXPR) + if n.Name() == nil { + n.SetName(new(ir.Name)) } - n.Right = newname(n.Sym) - n.Sym = methodSym(t, n.Sym) - n.Type = methodfunc(m.Type, n.Left.Type) - n.Xoffset = 0 - n.SetClass(PFUNC) + n.SetRight(NewName(n.Sym())) + n.SetSym(methodSym(t, n.Sym())) + n.SetType(methodfunc(m.Type, n.Left().Type())) + n.SetOffset(0) + n.SetClass(ir.PFUNC) + n.SetOpt(m) // methodSym already marked n.Sym as a function. // Issue 25065. Make sure that we emit the symbol for a local method. - if Ctxt.Flag_dynlink && !inimport && (t.Sym == nil || t.Sym.Pkg == localpkg) { - makefuncsym(n.Sym) + if base.Ctxt.Flag_dynlink && !inimport && (t.Sym == nil || t.Sym.Pkg == ir.LocalPkg) { + makefuncsym(n.Sym()) } return n @@ -2441,8 +2447,8 @@ func derefall(t *types.Type) *types.Type { return t } -func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { - s := n.Sym +func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field { + s := n.Sym() dowidth(t) var f1 *types.Field @@ -2451,7 +2457,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { } var f2 *types.Field - if n.Left.Type == t || n.Left.Type.Sym == nil { + if n.Left().Type() == t || n.Left().Type().Sym == nil { mt := methtype(t) if mt != nil { f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp) @@ -2464,21 +2470,21 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { return f1 } if f2 != nil { - yyerror("%v is both field and method", n.Sym) + base.Errorf("%v is both field and method", n.Sym()) } - if f1.Offset == BADWIDTH { - Fatalf("lookdot badwidth %v %p", f1, f1) + if f1.Offset == types.BADWIDTH { + base.Fatalf("lookdot badwidth %v %p", f1, f1) } - n.Xoffset = f1.Offset - n.Type = f1.Type + n.SetOffset(f1.Offset) + n.SetType(f1.Type) if t.IsInterface() { - if n.Left.Type.IsPtr() { - n.Left = nod(ODEREF, n.Left, nil) // implicitstar - n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, ctxExpr) + if n.Left().Type().IsPtr() { + n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil)) // implicitstar + n.Left().SetImplicit(true) + n.SetLeft(typecheck(n.Left(), ctxExpr)) } - n.Op = ODOTINTER + n.SetOp(ir.ODOTINTER) } else { n.SetOpt(f1) } @@ -2491,53 +2497,54 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { // Already in the process of diagnosing an error. return f2 } - tt := n.Left.Type + tt := n.Left().Type() dowidth(tt) rcvr := f2.Type.Recv().Type if !types.Identical(rcvr, tt) { if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) { - checklvalue(n.Left, "call pointer method on") - n.Left = nod(OADDR, n.Left, nil) - n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, ctxType|ctxExpr) + checklvalue(n.Left(), "call pointer method on") + n.SetLeft(ir.Nod(ir.OADDR, n.Left(), nil)) + n.Left().SetImplicit(true) + n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr)) } else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) { - n.Left = nod(ODEREF, n.Left, nil) - n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, ctxType|ctxExpr) + n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil)) + n.Left().SetImplicit(true) + n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr)) } else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) { - yyerror("calling method %v with receiver %L requires explicit dereference", n.Sym, n.Left) + base.Errorf("calling method %v with receiver %L requires explicit dereference", n.Sym(), n.Left()) for tt.IsPtr() { // Stop one level early for method with pointer receiver. if rcvr.IsPtr() && !tt.Elem().IsPtr() { break } - n.Left = nod(ODEREF, n.Left, nil) - n.Left.SetImplicit(true) - n.Left = typecheck(n.Left, ctxType|ctxExpr) + n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil)) + n.Left().SetImplicit(true) + n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr)) tt = tt.Elem() } } else { - Fatalf("method mismatch: %v for %v", rcvr, tt) + base.Fatalf("method mismatch: %v for %v", rcvr, tt) } } pll := n - ll := n.Left - for ll.Left != nil && (ll.Op == ODOT || ll.Op == ODOTPTR || ll.Op == ODEREF) { + ll := n.Left() + for ll.Left() != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) { pll = ll - ll = ll.Left + ll = ll.Left() } - if pll.Implicit() && ll.Type.IsPtr() && ll.Type.Sym != nil && asNode(ll.Type.Sym.Def) != nil && asNode(ll.Type.Sym.Def).Op == OTYPE { + if pll.Implicit() && ll.Type().IsPtr() && ll.Type().Sym != nil && ir.AsNode(ll.Type().Sym.Def) != nil && ir.AsNode(ll.Type().Sym.Def).Op() == ir.OTYPE { // It is invalid to automatically dereference a named pointer type when selecting a method. // Make n.Left == ll to clarify error message. - n.Left = ll + n.SetLeft(ll) return nil } - n.Sym = methodSym(n.Left.Type, f2.Sym) - n.Xoffset = f2.Offset - n.Type = f2.Type - n.Op = ODOTMETH + n.SetSym(methodSym(n.Left().Type(), f2.Sym)) + n.SetOffset(f2.Offset) + n.SetType(f2.Type) + n.SetOp(ir.ODOTMETH) + n.SetOpt(f2) return f2 } @@ -2545,9 +2552,9 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { return nil } -func nokeys(l Nodes) bool { +func nokeys(l ir.Nodes) bool { for _, n := range l.Slice() { - if n.Op == OKEY || n.Op == OSTRUCTKEY { + if n.Op() == ir.OKEY || n.Op() == ir.OSTRUCTKEY { return false } } @@ -2565,18 +2572,18 @@ func hasddd(t *types.Type) bool { } // typecheck assignment: type list = expression list -func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) { +func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes, desc func() string) { var t *types.Type var i int - lno := lineno - defer func() { lineno = lno }() + lno := base.Pos + defer func() { base.Pos = lno }() if tstruct.Broke() { return } - var n *Node + var n ir.Node if nl.Len() == 1 { n = nl.First() } @@ -2618,7 +2625,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, } n = nl.Index(i) setlineno(n) - if n.Type != nil { + if n.Type() != nil { nl.SetIndex(i, assignconvfn(n, t, desc)) } return @@ -2628,7 +2635,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, for ; i < nl.Len(); i++ { n = nl.Index(i) setlineno(n) - if n.Type != nil { + if n.Type() != nil { nl.SetIndex(i, assignconvfn(n, t.Elem(), desc)) } } @@ -2640,7 +2647,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, } n = nl.Index(i) setlineno(n) - if n.Type != nil { + if n.Type() != nil { nl.SetIndex(i, assignconvfn(n, t, desc)) } i++ @@ -2651,27 +2658,27 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, } if isddd { if call != nil { - yyerror("invalid use of ... in call to %v", call) + base.Errorf("invalid use of ... in call to %v", call) } else { - yyerror("invalid use of ... in %v", op) + base.Errorf("invalid use of ... in %v", op) } } return notenough: - if n == nil || (!n.Diag() && n.Type != nil) { + if n == nil || (!n.Diag() && n.Type() != nil) { details := errorDetails(nl, tstruct, isddd) if call != nil { // call is the expression being called, not the overall call. // Method expressions have the form T.M, and the compiler has // rewritten those to ONAME nodes but left T in Left. - if call.isMethodExpression() { - yyerror("not enough arguments in call to method expression %v%s", call, details) + if call.Op() == ir.OMETHEXPR { + base.Errorf("not enough arguments in call to method expression %v%s", call, details) } else { - yyerror("not enough arguments in call to %v%s", call, details) + base.Errorf("not enough arguments in call to %v%s", call, details) } } else { - yyerror("not enough arguments to %v%s", op, details) + base.Errorf("not enough arguments to %v%s", op, details) } if n != nil { n.SetDiag(true) @@ -2682,13 +2689,13 @@ notenough: toomany: details := errorDetails(nl, tstruct, isddd) if call != nil { - yyerror("too many arguments in call to %v%s", call, details) + base.Errorf("too many arguments in call to %v%s", call, details) } else { - yyerror("too many arguments to %v%s", op, details) + base.Errorf("too many arguments to %v%s", op, details) } } -func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string { +func errorDetails(nl ir.Nodes, tstruct *types.Type, isddd bool) string { // If we don't know any type at a call site, let's suppress any return // message signatures. See Issue https://golang.org/issues/19012. if tstruct == nil { @@ -2696,11 +2703,11 @@ func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string { } // If any node has an unknown type, suppress it as well for _, n := range nl.Slice() { - if n.Type == nil { + if n.Type() == nil { return "" } } - return fmt.Sprintf("\n\thave %s\n\twant %v", nl.sigerr(isddd), tstruct) + return fmt.Sprintf("\n\thave %s\n\twant %v", fmtSignature(nl, isddd), tstruct) } // sigrepr is a type's representation to the outside world, @@ -2714,7 +2721,7 @@ func sigrepr(t *types.Type, isddd bool) string { return "bool" } - if t.Etype == TIDEAL { + if t.Etype == types.TIDEAL { // "untyped number" is not commonly used // outside of the compiler, so let's use "number". // TODO(mdempsky): Revisit this. @@ -2724,7 +2731,7 @@ func sigrepr(t *types.Type, isddd bool) string { // Turn []T... argument to ...T for clearer error message. if isddd { if !t.IsSlice() { - Fatalf("bad type for ... argument: %v", t) + base.Fatalf("bad type for ... argument: %v", t) } return "..." + t.Elem().String() } @@ -2732,7 +2739,7 @@ func sigrepr(t *types.Type, isddd bool) string { } // sigerr returns the signature of the types at the call or return. -func (nl Nodes) sigerr(isddd bool) string { +func fmtSignature(nl ir.Nodes, isddd bool) string { if nl.Len() < 1 { return "()" } @@ -2740,7 +2747,7 @@ func (nl Nodes) sigerr(isddd bool) string { var typeStrings []string for i, n := range nl.Slice() { isdddArg := isddd && i == nl.Len()-1 - typeStrings = append(typeStrings, sigrepr(n.Type, isdddArg)) + typeStrings = append(typeStrings, sigrepr(n.Type(), isdddArg)) } return fmt.Sprintf("(%s)", strings.Join(typeStrings, ", ")) @@ -2749,7 +2756,7 @@ func (nl Nodes) sigerr(isddd bool) string { // type check composite func fielddup(name string, hash map[string]bool) { if hash[name] { - yyerror("duplicate field name in struct literal: %s", name) + base.Errorf("duplicate field name in struct literal: %s", name) return } hash[name] = true @@ -2758,7 +2765,7 @@ func fielddup(name string, hash map[string]bool) { // iscomptype reports whether type t is a composite literal type. func iscomptype(t *types.Type) bool { switch t.Etype { - case TARRAY, TSLICE, TSTRUCT, TMAP: + case types.TARRAY, types.TSLICE, types.TSTRUCT, types.TMAP: return true default: return false @@ -2767,21 +2774,21 @@ func iscomptype(t *types.Type) bool { // pushtype adds elided type information for composite literals if // appropriate, and returns the resulting expression. -func pushtype(n *Node, t *types.Type) *Node { - if n == nil || n.Op != OCOMPLIT || n.Right != nil { +func pushtype(n ir.Node, t *types.Type) ir.Node { + if n == nil || n.Op() != ir.OCOMPLIT || n.Right() != nil { return n } switch { case iscomptype(t): // For T, return T{...}. - n.Right = typenod(t) + n.SetRight(typenod(t)) case t.IsPtr() && iscomptype(t.Elem()): // For *T, return &T{...}. - n.Right = typenod(t.Elem()) + n.SetRight(typenod(t.Elem())) - n = nodl(n.Pos, OADDR, n, nil) + n = ir.NodAt(n.Pos(), ir.OADDR, n, nil) n.SetImplicit(true) } @@ -2790,107 +2797,107 @@ func pushtype(n *Node, t *types.Type) *Node { // The result of typecheckcomplit MUST be assigned back to n, e.g. // n.Left = typecheckcomplit(n.Left) -func typecheckcomplit(n *Node) (res *Node) { - if enableTrace && trace { +func typecheckcomplit(n ir.Node) (res ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheckcomplit", n)(&res) } - lno := lineno + lno := base.Pos defer func() { - lineno = lno + base.Pos = lno }() - if n.Right == nil { - yyerrorl(n.Pos, "missing type in composite literal") - n.Type = nil + if n.Right() == nil { + base.ErrorfAt(n.Pos(), "missing type in composite literal") + n.SetType(nil) return n } // Save original node (including n.Right) - n.Orig = n.copy() + n.SetOrig(ir.Copy(n)) - setlineno(n.Right) + setlineno(n.Right()) // Need to handle [...]T arrays specially. - if n.Right.Op == OTARRAY && n.Right.Left != nil && n.Right.Left.Op == ODDD { - n.Right.Right = typecheck(n.Right.Right, ctxType) - if n.Right.Right.Type == nil { - n.Type = nil + if n.Right().Op() == ir.OTARRAY && n.Right().Left() != nil && n.Right().Left().Op() == ir.ODDD { + n.Right().SetRight(typecheck(n.Right().Right(), ctxType)) + if n.Right().Right().Type() == nil { + n.SetType(nil) return n } - elemType := n.Right.Right.Type + elemType := n.Right().Right().Type() - length := typecheckarraylit(elemType, -1, n.List.Slice(), "array literal") + length := typecheckarraylit(elemType, -1, n.List().Slice(), "array literal") - n.Op = OARRAYLIT - n.Type = types.NewArray(elemType, length) - n.Right = nil + n.SetOp(ir.OARRAYLIT) + n.SetType(types.NewArray(elemType, length)) + n.SetRight(nil) return n } - n.Right = typecheck(n.Right, ctxType) - t := n.Right.Type + n.SetRight(typecheck(n.Right(), ctxType)) + t := n.Right().Type() if t == nil { - n.Type = nil + n.SetType(nil) return n } - n.Type = t + n.SetType(t) switch t.Etype { default: - yyerror("invalid composite literal type %v", t) - n.Type = nil + base.Errorf("invalid composite literal type %v", t) + n.SetType(nil) - case TARRAY: - typecheckarraylit(t.Elem(), t.NumElem(), n.List.Slice(), "array literal") - n.Op = OARRAYLIT - n.Right = nil + case types.TARRAY: + typecheckarraylit(t.Elem(), t.NumElem(), n.List().Slice(), "array literal") + n.SetOp(ir.OARRAYLIT) + n.SetRight(nil) - case TSLICE: - length := typecheckarraylit(t.Elem(), -1, n.List.Slice(), "slice literal") - n.Op = OSLICELIT - n.Right = nodintconst(length) + case types.TSLICE: + length := typecheckarraylit(t.Elem(), -1, n.List().Slice(), "slice literal") + n.SetOp(ir.OSLICELIT) + n.SetRight(nodintconst(length)) - case TMAP: + case types.TMAP: var cs constSet - for i3, l := range n.List.Slice() { + for i3, l := range n.List().Slice() { setlineno(l) - if l.Op != OKEY { - n.List.SetIndex(i3, typecheck(l, ctxExpr)) - yyerror("missing key in map literal") + if l.Op() != ir.OKEY { + n.List().SetIndex(i3, typecheck(l, ctxExpr)) + base.Errorf("missing key in map literal") continue } - r := l.Left + r := l.Left() r = pushtype(r, t.Key()) r = typecheck(r, ctxExpr) - l.Left = assignconv(r, t.Key(), "map key") - cs.add(lineno, l.Left, "key", "map literal") + l.SetLeft(assignconv(r, t.Key(), "map key")) + cs.add(base.Pos, l.Left(), "key", "map literal") - r = l.Right + r = l.Right() r = pushtype(r, t.Elem()) r = typecheck(r, ctxExpr) - l.Right = assignconv(r, t.Elem(), "map value") + l.SetRight(assignconv(r, t.Elem(), "map value")) } - n.Op = OMAPLIT - n.Right = nil + n.SetOp(ir.OMAPLIT) + n.SetRight(nil) - case TSTRUCT: + case types.TSTRUCT: // Need valid field offsets for Xoffset below. dowidth(t) errored := false - if n.List.Len() != 0 && nokeys(n.List) { + if n.List().Len() != 0 && nokeys(n.List()) { // simple list of variables - ls := n.List.Slice() + ls := n.List().Slice() for i, n1 := range ls { setlineno(n1) n1 = typecheck(n1, ctxExpr) ls[i] = n1 if i >= t.NumFields() { if !errored { - yyerror("too many values in %v", n) + base.Errorf("too many values in %v", n) errored = true } continue @@ -2898,81 +2905,81 @@ func typecheckcomplit(n *Node) (res *Node) { f := t.Field(i) s := f.Sym - if s != nil && !types.IsExported(s.Name) && s.Pkg != localpkg { - yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t) + if s != nil && !types.IsExported(s.Name) && s.Pkg != ir.LocalPkg { + base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t) } // No pushtype allowed here. Must name fields for that. n1 = assignconv(n1, f.Type, "field value") - n1 = nodSym(OSTRUCTKEY, n1, f.Sym) - n1.Xoffset = f.Offset + n1 = nodSym(ir.OSTRUCTKEY, n1, f.Sym) + n1.SetOffset(f.Offset) ls[i] = n1 } if len(ls) < t.NumFields() { - yyerror("too few values in %v", n) + base.Errorf("too few values in %v", n) } } else { hash := make(map[string]bool) // keyed list - ls := n.List.Slice() + ls := n.List().Slice() for i, l := range ls { setlineno(l) - if l.Op == OKEY { - key := l.Left + if l.Op() == ir.OKEY { + key := l.Left() - l.Op = OSTRUCTKEY - l.Left = l.Right - l.Right = nil + l.SetOp(ir.OSTRUCTKEY) + l.SetLeft(l.Right()) + l.SetRight(nil) // An OXDOT uses the Sym field to hold // the field to the right of the dot, // so s will be non-nil, but an OXDOT // is never a valid struct literal key. - if key.Sym == nil || key.Op == OXDOT || key.Sym.IsBlank() { - yyerror("invalid field name %v in struct initializer", key) - l.Left = typecheck(l.Left, ctxExpr) + if key.Sym() == nil || key.Op() == ir.OXDOT || key.Sym().IsBlank() { + base.Errorf("invalid field name %v in struct initializer", key) + l.SetLeft(typecheck(l.Left(), ctxExpr)) continue } // Sym might have resolved to name in other top-level // package, because of import dot. Redirect to correct sym // before we do the lookup. - s := key.Sym - if s.Pkg != localpkg && types.IsExported(s.Name) { + s := key.Sym() + if s.Pkg != ir.LocalPkg && types.IsExported(s.Name) { s1 := lookup(s.Name) if s1.Origpkg == s.Pkg { s = s1 } } - l.Sym = s + l.SetSym(s) } - if l.Op != OSTRUCTKEY { + if l.Op() != ir.OSTRUCTKEY { if !errored { - yyerror("mixture of field:value and value initializers") + base.Errorf("mixture of field:value and value initializers") errored = true } ls[i] = typecheck(ls[i], ctxExpr) continue } - f := lookdot1(nil, l.Sym, t, t.Fields(), 0) + f := lookdot1(nil, l.Sym(), t, t.Fields(), 0) if f == nil { - if ci := lookdot1(nil, l.Sym, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup. + if ci := lookdot1(nil, l.Sym(), t, t.Fields(), 2); ci != nil { // Case-insensitive lookup. if visible(ci.Sym) { - yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, ci.Sym) - } else if nonexported(l.Sym) && l.Sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion. - yyerror("cannot refer to unexported field '%v' in struct literal of type %v", l.Sym, t) + base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym(), t, ci.Sym) + } else if nonexported(l.Sym()) && l.Sym().Name == ci.Sym.Name { // Ensure exactness before the suggestion. + base.Errorf("cannot refer to unexported field '%v' in struct literal of type %v", l.Sym(), t) } else { - yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t) + base.Errorf("unknown field '%v' in struct literal of type %v", l.Sym(), t) } continue } var f *types.Field - p, _ := dotpath(l.Sym, t, &f, true) + p, _ := dotpath(l.Sym(), t, &f, true) if p == nil || f.IsMethod() { - yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t) + base.Errorf("unknown field '%v' in struct literal of type %v", l.Sym(), t) continue } // dotpath returns the parent embedded types in reverse order. @@ -2980,33 +2987,33 @@ func typecheckcomplit(n *Node) (res *Node) { for ei := len(p) - 1; ei >= 0; ei-- { ep = append(ep, p[ei].field.Sym.Name) } - ep = append(ep, l.Sym.Name) - yyerror("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), t) + ep = append(ep, l.Sym().Name) + base.Errorf("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), t) continue } fielddup(f.Sym.Name, hash) - l.Xoffset = f.Offset + l.SetOffset(f.Offset) // No pushtype allowed here. Tried and rejected. - l.Left = typecheck(l.Left, ctxExpr) - l.Left = assignconv(l.Left, f.Type, "field value") + l.SetLeft(typecheck(l.Left(), ctxExpr)) + l.SetLeft(assignconv(l.Left(), f.Type, "field value")) } } - n.Op = OSTRUCTLIT - n.Right = nil + n.SetOp(ir.OSTRUCTLIT) + n.SetRight(nil) } return n } // typecheckarraylit type-checks a sequence of slice/array literal elements. -func typecheckarraylit(elemType *types.Type, bound int64, elts []*Node, ctx string) int64 { +func typecheckarraylit(elemType *types.Type, bound int64, elts []ir.Node, ctx string) int64 { // If there are key/value pairs, create a map to keep seen // keys so we can check for duplicate indices. var indices map[int64]bool for _, elt := range elts { - if elt.Op == OKEY { + if elt.Op() == ir.OKEY { indices = make(map[int64]bool) break } @@ -3015,40 +3022,46 @@ func typecheckarraylit(elemType *types.Type, bound int64, elts []*Node, ctx stri var key, length int64 for i, elt := range elts { setlineno(elt) - vp := &elts[i] - if elt.Op == OKEY { - elt.Left = typecheck(elt.Left, ctxExpr) - key = indexconst(elt.Left) + r := elts[i] + var kv ir.Node + if elt.Op() == ir.OKEY { + elt.SetLeft(typecheck(elt.Left(), ctxExpr)) + key = indexconst(elt.Left()) if key < 0 { - if !elt.Left.Diag() { + if !elt.Left().Diag() { if key == -2 { - yyerror("index too large") + base.Errorf("index too large") } else { - yyerror("index must be non-negative integer constant") + base.Errorf("index must be non-negative integer constant") } - elt.Left.SetDiag(true) + elt.Left().SetDiag(true) } key = -(1 << 30) // stay negative for a while } - vp = &elt.Right + kv = elt + r = elt.Right() } - r := *vp r = pushtype(r, elemType) r = typecheck(r, ctxExpr) - *vp = assignconv(r, elemType, ctx) + r = assignconv(r, elemType, ctx) + if kv != nil { + kv.SetRight(r) + } else { + elts[i] = r + } if key >= 0 { if indices != nil { if indices[key] { - yyerror("duplicate index in %s: %d", ctx, key) + base.Errorf("duplicate index in %s: %d", ctx, key) } else { indices[key] = true } } if bound >= 0 && key >= bound { - yyerror("array index %d out of bounds [0:%d]", key, bound) + base.Errorf("array index %d out of bounds [0:%d]", key, bound) bound = -1 } } @@ -3064,7 +3077,7 @@ func typecheckarraylit(elemType *types.Type, bound int64, elts []*Node, ctx stri // visible reports whether sym is exported or locally defined. func visible(sym *types.Sym) bool { - return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg) + return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == ir.LocalPkg) } // nonexported reports whether sym is an unexported field. @@ -3073,24 +3086,24 @@ func nonexported(sym *types.Sym) bool { } // lvalue etc -func islvalue(n *Node) bool { - switch n.Op { - case OINDEX: - if n.Left.Type != nil && n.Left.Type.IsArray() { - return islvalue(n.Left) +func islvalue(n ir.Node) bool { + switch n.Op() { + case ir.OINDEX: + if n.Left().Type() != nil && n.Left().Type().IsArray() { + return islvalue(n.Left()) } - if n.Left.Type != nil && n.Left.Type.IsString() { + if n.Left().Type() != nil && n.Left().Type().IsString() { return false } fallthrough - case ODEREF, ODOTPTR, OCLOSUREVAR: + case ir.ODEREF, ir.ODOTPTR, ir.OCLOSUREVAR: return true - case ODOT: - return islvalue(n.Left) + case ir.ODOT: + return islvalue(n.Left()) - case ONAME: - if n.Class() == PFUNC { + case ir.ONAME: + if n.Class() == ir.PFUNC { return false } return true @@ -3099,20 +3112,20 @@ func islvalue(n *Node) bool { return false } -func checklvalue(n *Node, verb string) { +func checklvalue(n ir.Node, verb string) { if !islvalue(n) { - yyerror("cannot %s %v", verb, n) + base.Errorf("cannot %s %v", verb, n) } } -func checkassign(stmt *Node, n *Node) { +func checkassign(stmt ir.Node, n ir.Node) { // Variables declared in ORANGE are assigned on every iteration. - if n.Name == nil || n.Name.Defn != stmt || stmt.Op == ORANGE { + if n.Name() == nil || n.Name().Defn != stmt || stmt.Op() == ir.ORANGE { r := outervalue(n) - if r.Op == ONAME { - r.Name.SetAssigned(true) - if r.Name.IsClosureVar() { - r.Name.Defn.Name.SetAssigned(true) + if r.Op() == ir.ONAME { + r.Name().SetAssigned(true) + if r.Name().IsClosureVar() { + r.Name().Defn.Name().SetAssigned(true) } } } @@ -3120,30 +3133,30 @@ func checkassign(stmt *Node, n *Node) { if islvalue(n) { return } - if n.Op == OINDEXMAP { + if n.Op() == ir.OINDEXMAP { n.SetIndexMapLValue(true) return } // have already complained about n being invalid - if n.Type == nil { + if n.Type() == nil { return } switch { - case n.Op == ODOT && n.Left.Op == OINDEXMAP: - yyerror("cannot assign to struct field %v in map", n) - case (n.Op == OINDEX && n.Left.Type.IsString()) || n.Op == OSLICESTR: - yyerror("cannot assign to %v (strings are immutable)", n) - case n.Op == OLITERAL && n.Sym != nil && n.isGoConst(): - yyerror("cannot assign to %v (declared const)", n) + case n.Op() == ir.ODOT && n.Left().Op() == ir.OINDEXMAP: + base.Errorf("cannot assign to struct field %v in map", n) + case (n.Op() == ir.OINDEX && n.Left().Type().IsString()) || n.Op() == ir.OSLICESTR: + base.Errorf("cannot assign to %v (strings are immutable)", n) + case n.Op() == ir.OLITERAL && n.Sym() != nil && isGoConst(n): + base.Errorf("cannot assign to %v (declared const)", n) default: - yyerror("cannot assign to %v", n) + base.Errorf("cannot assign to %v", n) } - n.Type = nil + n.SetType(nil) } -func checkassignlist(stmt *Node, l Nodes) { +func checkassignlist(stmt ir.Node, l ir.Nodes) { for _, n := range l.Slice() { checkassign(stmt, n) } @@ -3164,33 +3177,36 @@ func checkassignlist(stmt *Node, l Nodes) { // currently OK, since the only place samesafeexpr gets used on an // lvalue expression is for OSLICE and OAPPEND optimizations, and it // is correct in those settings. -func samesafeexpr(l *Node, r *Node) bool { - if l.Op != r.Op || !types.Identical(l.Type, r.Type) { +func samesafeexpr(l ir.Node, r ir.Node) bool { + if l.Op() != r.Op() || !types.Identical(l.Type(), r.Type()) { return false } - switch l.Op { - case ONAME, OCLOSUREVAR: + switch l.Op() { + case ir.ONAME, ir.OCLOSUREVAR: return l == r - case ODOT, ODOTPTR: - return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left) + case ir.ODOT, ir.ODOTPTR: + return l.Sym() != nil && r.Sym() != nil && l.Sym() == r.Sym() && samesafeexpr(l.Left(), r.Left()) - case ODEREF, OCONVNOP, - ONOT, OBITNOT, OPLUS, ONEG: - return samesafeexpr(l.Left, r.Left) + case ir.ODEREF, ir.OCONVNOP, + ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG: + return samesafeexpr(l.Left(), r.Left()) - case OCONV: + case ir.OCONV: // Some conversions can't be reused, such as []byte(str). // Allow only numeric-ish types. This is a bit conservative. - return issimple[l.Type.Etype] && samesafeexpr(l.Left, r.Left) + return issimple[l.Type().Etype] && samesafeexpr(l.Left(), r.Left()) + + case ir.OINDEX, ir.OINDEXMAP, + ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD: + return samesafeexpr(l.Left(), r.Left()) && samesafeexpr(l.Right(), r.Right()) - case OINDEX, OINDEXMAP, - OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD: - return samesafeexpr(l.Left, r.Left) && samesafeexpr(l.Right, r.Right) + case ir.OLITERAL: + return constant.Compare(l.Val(), token.EQL, r.Val()) - case OLITERAL: - return eqval(l.Val(), r.Val()) + case ir.ONIL: + return true } return false @@ -3199,8 +3215,8 @@ func samesafeexpr(l *Node, r *Node) bool { // type check assignment. // if this assignment is the definition of a var on the left side, // fill in the var's type. -func typecheckas(n *Node) { - if enableTrace && trace { +func typecheckas(n ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheckas", n)(nil) } @@ -3211,30 +3227,30 @@ func typecheckas(n *Node) { // if the variable has a type (ntype) then typechecking // will not look at defn, so it is okay (and desirable, // so that the conversion below happens). - n.Left = resolve(n.Left) + n.SetLeft(resolve(n.Left())) - if n.Left.Name == nil || n.Left.Name.Defn != n || n.Left.Name.Param.Ntype != nil { - n.Left = typecheck(n.Left, ctxExpr|ctxAssign) + if n.Left().Name() == nil || n.Left().Name().Defn != n || n.Left().Name().Param.Ntype != nil { + n.SetLeft(typecheck(n.Left(), ctxExpr|ctxAssign)) } // Use ctxMultiOK so we can emit an "N variables but M values" error // to be consistent with typecheckas2 (#26616). - n.Right = typecheck(n.Right, ctxExpr|ctxMultiOK) - checkassign(n, n.Left) - if n.Right != nil && n.Right.Type != nil { - if n.Right.Type.IsFuncArgStruct() { - yyerror("assignment mismatch: 1 variable but %v returns %d values", n.Right.Left, n.Right.Type.NumFields()) + n.SetRight(typecheck(n.Right(), ctxExpr|ctxMultiOK)) + checkassign(n, n.Left()) + if n.Right() != nil && n.Right().Type() != nil { + if n.Right().Type().IsFuncArgStruct() { + base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Right().Left(), n.Right().Type().NumFields()) // Multi-value RHS isn't actually valid for OAS; nil out // to indicate failed typechecking. - n.Right.Type = nil - } else if n.Left.Type != nil { - n.Right = assignconv(n.Right, n.Left.Type, "assignment") + n.Right().SetType(nil) + } else if n.Left().Type() != nil { + n.SetRight(assignconv(n.Right(), n.Left().Type(), "assignment")) } } - if n.Left.Name != nil && n.Left.Name.Defn == n && n.Left.Name.Param.Ntype == nil { - n.Right = defaultlit(n.Right, nil) - n.Left.Type = n.Right.Type + if n.Left().Name() != nil && n.Left().Name().Defn == n && n.Left().Name().Param.Ntype == nil { + n.SetRight(defaultlit(n.Right(), nil)) + n.Left().SetType(n.Right().Type()) } // second half of dance. @@ -3242,93 +3258,93 @@ func typecheckas(n *Node) { // just to get it over with. see dance above. n.SetTypecheck(1) - if n.Left.Typecheck() == 0 { - n.Left = typecheck(n.Left, ctxExpr|ctxAssign) + if n.Left().Typecheck() == 0 { + n.SetLeft(typecheck(n.Left(), ctxExpr|ctxAssign)) } - if !n.Left.isBlank() { - checkwidth(n.Left.Type) // ensure width is calculated for backend + if !ir.IsBlank(n.Left()) { + checkwidth(n.Left().Type()) // ensure width is calculated for backend } } -func checkassignto(src *types.Type, dst *Node) { - if op, why := assignop(src, dst.Type); op == OXXX { - yyerror("cannot assign %v to %L in multiple assignment%s", src, dst, why) +func checkassignto(src *types.Type, dst ir.Node) { + if op, why := assignop(src, dst.Type()); op == ir.OXXX { + base.Errorf("cannot assign %v to %L in multiple assignment%s", src, dst, why) return } } -func typecheckas2(n *Node) { - if enableTrace && trace { +func typecheckas2(n ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheckas2", n)(nil) } - ls := n.List.Slice() + ls := n.List().Slice() for i1, n1 := range ls { // delicate little dance. n1 = resolve(n1) ls[i1] = n1 - if n1.Name == nil || n1.Name.Defn != n || n1.Name.Param.Ntype != nil { + if n1.Name() == nil || n1.Name().Defn != n || n1.Name().Param.Ntype != nil { ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign) } } - cl := n.List.Len() - cr := n.Rlist.Len() + cl := n.List().Len() + cr := n.Rlist().Len() if cl > 1 && cr == 1 { - n.Rlist.SetFirst(typecheck(n.Rlist.First(), ctxExpr|ctxMultiOK)) + n.Rlist().SetFirst(typecheck(n.Rlist().First(), ctxExpr|ctxMultiOK)) } else { - typecheckslice(n.Rlist.Slice(), ctxExpr) + typecheckslice(n.Rlist().Slice(), ctxExpr) } - checkassignlist(n, n.List) + checkassignlist(n, n.List()) - var l *Node - var r *Node + var l ir.Node + var r ir.Node if cl == cr { // easy - ls := n.List.Slice() - rs := n.Rlist.Slice() + ls := n.List().Slice() + rs := n.Rlist().Slice() for il, nl := range ls { nr := rs[il] - if nl.Type != nil && nr.Type != nil { - rs[il] = assignconv(nr, nl.Type, "assignment") + if nl.Type() != nil && nr.Type() != nil { + rs[il] = assignconv(nr, nl.Type(), "assignment") } - if nl.Name != nil && nl.Name.Defn == n && nl.Name.Param.Ntype == nil { + if nl.Name() != nil && nl.Name().Defn == n && nl.Name().Param.Ntype == nil { rs[il] = defaultlit(rs[il], nil) - nl.Type = rs[il].Type + nl.SetType(rs[il].Type()) } } goto out } - l = n.List.First() - r = n.Rlist.First() + l = n.List().First() + r = n.Rlist().First() // x,y,z = f() if cr == 1 { - if r.Type == nil { + if r.Type() == nil { goto out } - switch r.Op { - case OCALLMETH, OCALLINTER, OCALLFUNC: - if !r.Type.IsFuncArgStruct() { + switch r.Op() { + case ir.OCALLMETH, ir.OCALLINTER, ir.OCALLFUNC: + if !r.Type().IsFuncArgStruct() { break } - cr = r.Type.NumFields() + cr = r.Type().NumFields() if cr != cl { goto mismatch } - n.Op = OAS2FUNC - n.Right = r - n.Rlist.Set(nil) - for i, l := range n.List.Slice() { - f := r.Type.Field(i) - if f.Type != nil && l.Type != nil { + n.SetOp(ir.OAS2FUNC) + n.SetRight(r) + n.PtrRlist().Set(nil) + for i, l := range n.List().Slice() { + f := r.Type().Field(i) + if f.Type != nil && l.Type() != nil { checkassignto(f.Type, l) } - if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil { - l.Type = f.Type + if l.Name() != nil && l.Name().Defn == n && l.Name().Param.Ntype == nil { + l.SetType(f.Type) } } goto out @@ -3337,51 +3353,51 @@ func typecheckas2(n *Node) { // x, ok = y if cl == 2 && cr == 1 { - if r.Type == nil { + if r.Type() == nil { goto out } - switch r.Op { - case OINDEXMAP, ORECV, ODOTTYPE: - switch r.Op { - case OINDEXMAP: - n.Op = OAS2MAPR - case ORECV: - n.Op = OAS2RECV - case ODOTTYPE: - n.Op = OAS2DOTTYPE - r.Op = ODOTTYPE2 + switch r.Op() { + case ir.OINDEXMAP, ir.ORECV, ir.ODOTTYPE: + switch r.Op() { + case ir.OINDEXMAP: + n.SetOp(ir.OAS2MAPR) + case ir.ORECV: + n.SetOp(ir.OAS2RECV) + case ir.ODOTTYPE: + n.SetOp(ir.OAS2DOTTYPE) + r.SetOp(ir.ODOTTYPE2) } - n.Right = r - n.Rlist.Set(nil) - if l.Type != nil { - checkassignto(r.Type, l) + n.SetRight(r) + n.PtrRlist().Set(nil) + if l.Type() != nil { + checkassignto(r.Type(), l) } - if l.Name != nil && l.Name.Defn == n { - l.Type = r.Type + if l.Name() != nil && l.Name().Defn == n { + l.SetType(r.Type()) } - l := n.List.Second() - if l.Type != nil && !l.Type.IsBoolean() { - checkassignto(types.Types[TBOOL], l) + l := n.List().Second() + if l.Type() != nil && !l.Type().IsBoolean() { + checkassignto(types.Types[types.TBOOL], l) } - if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil { - l.Type = types.Types[TBOOL] + if l.Name() != nil && l.Name().Defn == n && l.Name().Param.Ntype == nil { + l.SetType(types.Types[types.TBOOL]) } goto out } } mismatch: - switch r.Op { + switch r.Op() { default: - yyerror("assignment mismatch: %d variables but %d values", cl, cr) - case OCALLFUNC, OCALLMETH, OCALLINTER: - yyerror("assignment mismatch: %d variables but %v returns %d values", cl, r.Left, cr) + base.Errorf("assignment mismatch: %d variables but %d values", cl, cr) + case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER: + base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.Left(), cr) } // second half of dance out: n.SetTypecheck(1) - ls = n.List.Slice() + ls = n.List().Slice() for i1, n1 := range ls { if n1.Typecheck() == 0 { ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign) @@ -3390,80 +3406,79 @@ out: } // type check function definition -func typecheckfunc(n *Node) { - if enableTrace && trace { +func typecheckfunc(n ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheckfunc", n)(nil) } - for _, ln := range n.Func.Dcl { - if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) { - ln.Name.Decldepth = 1 + for _, ln := range n.Func().Dcl { + if ln.Op() == ir.ONAME && (ln.Class() == ir.PPARAM || ln.Class() == ir.PPARAMOUT) { + ln.Name().Decldepth = 1 } } - n.Func.Nname = typecheck(n.Func.Nname, ctxExpr|ctxAssign) - t := n.Func.Nname.Type + n.Func().Nname = typecheck(n.Func().Nname, ctxExpr|ctxAssign) + t := n.Func().Nname.Type() if t == nil { return } - n.Type = t - t.FuncType().Nname = asTypesNode(n.Func.Nname) + n.SetType(t) rcvr := t.Recv() - if rcvr != nil && n.Func.Shortname != nil { - m := addmethod(n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0) + if rcvr != nil && n.Func().Shortname != nil { + m := addmethod(n, n.Func().Shortname, t, true, n.Func().Pragma&ir.Nointerface != 0) if m == nil { return } - n.Func.Nname.Sym = methodSym(rcvr.Type, n.Func.Shortname) - declare(n.Func.Nname, PFUNC) + n.Func().Nname.SetSym(methodSym(rcvr.Type, n.Func().Shortname)) + declare(n.Func().Nname, ir.PFUNC) } - if Ctxt.Flag_dynlink && !inimport && n.Func.Nname != nil { - makefuncsym(n.Func.Nname.Sym) + if base.Ctxt.Flag_dynlink && !inimport && n.Func().Nname != nil { + makefuncsym(n.Func().Nname.Sym()) } } // The result of stringtoruneslit MUST be assigned back to n, e.g. // n.Left = stringtoruneslit(n.Left) -func stringtoruneslit(n *Node) *Node { - if n.Left.Op != OLITERAL || n.Left.Val().Ctype() != CTSTR { - Fatalf("stringtoarraylit %v", n) +func stringtoruneslit(n ir.Node) ir.Node { + if n.Left().Op() != ir.OLITERAL || n.Left().Val().Kind() != constant.String { + base.Fatalf("stringtoarraylit %v", n) } - var l []*Node + var l []ir.Node i := 0 - for _, r := range n.Left.StringVal() { - l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r)))) + for _, r := range n.Left().StringVal() { + l = append(l, ir.Nod(ir.OKEY, nodintconst(int64(i)), nodintconst(int64(r)))) i++ } - nn := nod(OCOMPLIT, nil, typenod(n.Type)) - nn.List.Set(l) + nn := ir.Nod(ir.OCOMPLIT, nil, typenod(n.Type())) + nn.PtrList().Set(l) nn = typecheck(nn, ctxExpr) return nn } -var mapqueue []*Node +var mapqueue []ir.Node func checkMapKeys() { for _, n := range mapqueue { - k := n.Type.MapType().Key + k := n.Type().MapType().Key if !k.Broke() && !IsComparable(k) { - yyerrorl(n.Pos, "invalid map key type %v", k) + base.ErrorfAt(n.Pos(), "invalid map key type %v", k) } } mapqueue = nil } func setUnderlying(t, underlying *types.Type) { - if underlying.Etype == TFORW { + if underlying.Etype == types.TFORW { // This type isn't computed yet; when it is, update n. underlying.ForwardType().Copyto = append(underlying.ForwardType().Copyto, t) return } - n := asNode(t.Nod) + n := ir.AsNode(t.Nod) ft := t.ForwardType() cache := t.Cache @@ -3471,10 +3486,10 @@ func setUnderlying(t, underlying *types.Type) { *t = *underlying // Restore unnecessarily clobbered attributes. - t.Nod = asTypesNode(n) - t.Sym = n.Sym - if n.Name != nil { - t.Vargen = n.Name.Vargen + t.Nod = n + t.Sym = n.Sym() + if n.Name() != nil { + t.Vargen = n.Name().Vargen } t.Cache = cache t.SetDeferwidth(false) @@ -3488,7 +3503,7 @@ func setUnderlying(t, underlying *types.Type) { } // Propagate go:notinheap pragma from the Name to the Type. - if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma()&NotInHeap != 0 { + if n.Name() != nil && n.Name().Param != nil && n.Name().Param.Pragma()&ir.NotInHeap != 0 { t.SetNotInHeap(true) } @@ -3500,147 +3515,149 @@ func setUnderlying(t, underlying *types.Type) { // Double-check use of type as embedded type. if ft.Embedlineno.IsKnown() { if t.IsPtr() || t.IsUnsafePtr() { - yyerrorl(ft.Embedlineno, "embedded type cannot be a pointer") + base.ErrorfAt(ft.Embedlineno, "embedded type cannot be a pointer") } } } -func typecheckdeftype(n *Node) { - if enableTrace && trace { +func typecheckdeftype(n ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheckdeftype", n)(nil) } n.SetTypecheck(1) - n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType) - t := n.Name.Param.Ntype.Type + n.Name().Param.Ntype = typecheck(n.Name().Param.Ntype, ctxType) + t := n.Name().Param.Ntype.Type() if t == nil { n.SetDiag(true) - n.Type = nil - } else if n.Type == nil { + n.SetType(nil) + } else if n.Type() == nil { n.SetDiag(true) } else { // copy new type and clear fields // that don't come along. - setUnderlying(n.Type, t) + setUnderlying(n.Type(), t) } } -func typecheckdef(n *Node) { - if enableTrace && trace { +func typecheckdef(n ir.Node) { + if enableTrace && base.Flag.LowerT { defer tracePrint("typecheckdef", n)(nil) } lno := setlineno(n) - if n.Op == ONONAME { + if n.Op() == ir.ONONAME { if !n.Diag() { n.SetDiag(true) // Note: adderrorname looks for this string and // adds context about the outer expression - yyerrorl(lineno, "undefined: %v", n.Sym) + base.ErrorfAt(base.Pos, "undefined: %v", n.Sym()) } - lineno = lno + base.Pos = lno return } if n.Walkdef() == 1 { - lineno = lno + base.Pos = lno return } typecheckdefstack = append(typecheckdefstack, n) if n.Walkdef() == 2 { - flusherrors() + base.FlushErrors() fmt.Printf("typecheckdef loop:") for i := len(typecheckdefstack) - 1; i >= 0; i-- { n := typecheckdefstack[i] - fmt.Printf(" %v", n.Sym) + fmt.Printf(" %v", n.Sym()) } fmt.Printf("\n") - Fatalf("typecheckdef loop") + base.Fatalf("typecheckdef loop") } n.SetWalkdef(2) - if n.Type != nil || n.Sym == nil { // builtin or no name + if n.Type() != nil || n.Sym() == nil { // builtin or no name goto ret } - switch n.Op { + switch n.Op() { default: - Fatalf("typecheckdef %v", n.Op) - - case OLITERAL: - if n.Name.Param.Ntype != nil { - n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType) - n.Type = n.Name.Param.Ntype.Type - n.Name.Param.Ntype = nil - if n.Type == nil { + base.Fatalf("typecheckdef %v", n.Op()) + + case ir.OLITERAL: + if n.Name().Param.Ntype != nil { + n.Name().Param.Ntype = typecheck(n.Name().Param.Ntype, ctxType) + n.SetType(n.Name().Param.Ntype.Type()) + n.Name().Param.Ntype = nil + if n.Type() == nil { n.SetDiag(true) goto ret } } - e := n.Name.Defn - n.Name.Defn = nil + e := n.Name().Defn + n.Name().Defn = nil if e == nil { - Dump("typecheckdef nil defn", n) - yyerrorl(n.Pos, "xxx") + ir.Dump("typecheckdef nil defn", n) + base.ErrorfAt(n.Pos(), "xxx") } e = typecheck(e, ctxExpr) - if e.Type == nil { + if e.Type() == nil { goto ret } - if !e.isGoConst() { + if !isGoConst(e) { if !e.Diag() { - if Isconst(e, CTNIL) { - yyerrorl(n.Pos, "const initializer cannot be nil") + if e.Op() == ir.ONIL { + base.ErrorfAt(n.Pos(), "const initializer cannot be nil") } else { - yyerrorl(n.Pos, "const initializer %v is not a constant", e) + base.ErrorfAt(n.Pos(), "const initializer %v is not a constant", e) } e.SetDiag(true) } goto ret } - t := n.Type + t := n.Type() if t != nil { - if !okforconst[t.Etype] { - yyerrorl(n.Pos, "invalid constant type %v", t) + if !ir.OKForConst[t.Etype] { + base.ErrorfAt(n.Pos(), "invalid constant type %v", t) goto ret } - if !e.Type.IsUntyped() && !types.Identical(t, e.Type) { - yyerrorl(n.Pos, "cannot use %L as type %v in const initializer", e, t) + if !e.Type().IsUntyped() && !types.Identical(t, e.Type()) { + base.ErrorfAt(n.Pos(), "cannot use %L as type %v in const initializer", e, t) goto ret } e = convlit(e, t) } - n.SetVal(e.Val()) - n.Type = e.Type + n.SetType(e.Type()) + if n.Type() != nil { + n.SetVal(e.Val()) + } - case ONAME: - if n.Name.Param.Ntype != nil { - n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType) - n.Type = n.Name.Param.Ntype.Type - if n.Type == nil { + case ir.ONAME: + if n.Name().Param.Ntype != nil { + n.Name().Param.Ntype = typecheck(n.Name().Param.Ntype, ctxType) + n.SetType(n.Name().Param.Ntype.Type()) + if n.Type() == nil { n.SetDiag(true) goto ret } } - if n.Type != nil { + if n.Type() != nil { break } - if n.Name.Defn == nil { + if n.Name().Defn == nil { if n.SubOp() != 0 { // like OPRINTN break } - if nsavederrors+nerrors > 0 { + if base.Errors() > 0 { // Can have undefined variables in x := foo // that make x have an n.name.Defn == nil. // If there are other errors anyway, don't @@ -3648,33 +3665,33 @@ func typecheckdef(n *Node) { break } - Fatalf("var without type, init: %v", n.Sym) + base.Fatalf("var without type, init: %v", n.Sym()) } - if n.Name.Defn.Op == ONAME { - n.Name.Defn = typecheck(n.Name.Defn, ctxExpr) - n.Type = n.Name.Defn.Type + if n.Name().Defn.Op() == ir.ONAME { + n.Name().Defn = typecheck(n.Name().Defn, ctxExpr) + n.SetType(n.Name().Defn.Type()) break } - n.Name.Defn = typecheck(n.Name.Defn, ctxStmt) // fills in n.Type + n.Name().Defn = typecheck(n.Name().Defn, ctxStmt) // fills in n.Type - case OTYPE: - if p := n.Name.Param; p.Alias() { + case ir.OTYPE: + if p := n.Name().Param; p.Alias() { // Type alias declaration: Simply use the rhs type - no need // to create a new type. // If we have a syntax error, p.Ntype may be nil. if p.Ntype != nil { p.Ntype = typecheck(p.Ntype, ctxType) - n.Type = p.Ntype.Type - if n.Type == nil { + n.SetType(p.Ntype.Type()) + if n.Type() == nil { n.SetDiag(true) goto ret } // For package-level type aliases, set n.Sym.Def so we can identify // it as a type alias during export. See also #31959. - if n.Name.Curfn == nil { - n.Sym.Def = asTypesNode(p.Ntype) + if n.Name().Curfn == nil { + n.Sym().Def = p.Ntype } } break @@ -3683,51 +3700,50 @@ func typecheckdef(n *Node) { // regular type declaration defercheckwidth() n.SetWalkdef(1) - setTypeNode(n, types.New(TFORW)) - n.Type.Sym = n.Sym - nerrors0 := nerrors + setTypeNode(n, types.New(types.TFORW)) + n.Type().Sym = n.Sym() + errorsBefore := base.Errors() typecheckdeftype(n) - if n.Type.Etype == TFORW && nerrors > nerrors0 { + if n.Type().Etype == types.TFORW && base.Errors() > errorsBefore { // Something went wrong during type-checking, // but it was reported. Silence future errors. - n.Type.SetBroke(true) + n.Type().SetBroke(true) } resumecheckwidth() } ret: - if n.Op != OLITERAL && n.Type != nil && n.Type.IsUntyped() { - Fatalf("got %v for %v", n.Type, n) + if n.Op() != ir.OLITERAL && n.Type() != nil && n.Type().IsUntyped() { + base.Fatalf("got %v for %v", n.Type(), n) } last := len(typecheckdefstack) - 1 if typecheckdefstack[last] != n { - Fatalf("typecheckdefstack mismatch") + base.Fatalf("typecheckdefstack mismatch") } typecheckdefstack[last] = nil typecheckdefstack = typecheckdefstack[:last] - lineno = lno + base.Pos = lno n.SetWalkdef(1) } -func checkmake(t *types.Type, arg string, np **Node) bool { +func checkmake(t *types.Type, arg string, np *ir.Node) bool { n := *np - if !n.Type.IsInteger() && n.Type.Etype != TIDEAL { - yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type) + if !n.Type().IsInteger() && n.Type().Etype != types.TIDEAL { + base.Errorf("non-integer %s argument in make(%v) - %v", arg, t, n.Type()) return false } // Do range checks for constants before defaultlit // to avoid redundant "constant NNN overflows int" errors. - switch consttype(n) { - case CTINT, CTRUNE, CTFLT, CTCPLX: - v := toint(n.Val()).U.(*Mpint) - if v.CmpInt64(0) < 0 { - yyerror("negative %s argument in make(%v)", arg, t) + if n.Op() == ir.OLITERAL { + v := toint(n.Val()) + if constant.Sign(v) < 0 { + base.Errorf("negative %s argument in make(%v)", arg, t) return false } - if v.Cmp(maxintval[TINT]) > 0 { - yyerror("%s argument too large in make(%v)", arg, t) + if doesoverflow(v, types.Types[types.TINT]) { + base.Errorf("%s argument too large in make(%v)", arg, t) return false } } @@ -3737,55 +3753,55 @@ func checkmake(t *types.Type, arg string, np **Node) bool { // are the same as for index expressions. Factor the code better; // for instance, indexlit might be called here and incorporate some // of the bounds checks done for make. - n = defaultlit(n, types.Types[TINT]) + n = defaultlit(n, types.Types[types.TINT]) *np = n return true } -func markbreak(n *Node, implicit *Node) { +func markbreak(n ir.Node, implicit ir.Node) { if n == nil { return } - switch n.Op { - case OBREAK: - if n.Sym == nil { + switch n.Op() { + case ir.OBREAK: + if n.Sym() == nil { if implicit != nil { implicit.SetHasBreak(true) } } else { - lab := asNode(n.Sym.Label) + lab := ir.AsNode(n.Sym().Label) if lab != nil { lab.SetHasBreak(true) } } - case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE: + case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OTYPESW, ir.OSELECT, ir.ORANGE: implicit = n fallthrough default: - markbreak(n.Left, implicit) - markbreak(n.Right, implicit) - markbreaklist(n.Ninit, implicit) - markbreaklist(n.Nbody, implicit) - markbreaklist(n.List, implicit) - markbreaklist(n.Rlist, implicit) + markbreak(n.Left(), implicit) + markbreak(n.Right(), implicit) + markbreaklist(n.Init(), implicit) + markbreaklist(n.Body(), implicit) + markbreaklist(n.List(), implicit) + markbreaklist(n.Rlist(), implicit) } } -func markbreaklist(l Nodes, implicit *Node) { +func markbreaklist(l ir.Nodes, implicit ir.Node) { s := l.Slice() for i := 0; i < len(s); i++ { n := s[i] if n == nil { continue } - if n.Op == OLABEL && i+1 < len(s) && n.Name.Defn == s[i+1] { - switch n.Name.Defn.Op { - case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE: - n.Sym.Label = asTypesNode(n.Name.Defn) - markbreak(n.Name.Defn, n.Name.Defn) - n.Sym.Label = nil + if n.Op() == ir.OLABEL && i+1 < len(s) && n.Name().Defn == s[i+1] { + switch n.Name().Defn.Op() { + case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OTYPESW, ir.OSELECT, ir.ORANGE: + n.Sym().Label = n.Name().Defn + markbreak(n.Name().Defn, n.Name().Defn) + n.Sym().Label = nil i++ continue } @@ -3796,32 +3812,32 @@ func markbreaklist(l Nodes, implicit *Node) { } // isterminating reports whether the Nodes list ends with a terminating statement. -func (l Nodes) isterminating() bool { +func isTermNodes(l ir.Nodes) bool { s := l.Slice() c := len(s) if c == 0 { return false } - return s[c-1].isterminating() + return isTermNode(s[c-1]) } // Isterminating reports whether the node n, the last one in a // statement list, is a terminating statement. -func (n *Node) isterminating() bool { - switch n.Op { +func isTermNode(n ir.Node) bool { + switch n.Op() { // NOTE: OLABEL is treated as a separate statement, // not a separate prefix, so skipping to the last statement // in the block handles the labeled statement case by // skipping over the label. No case OLABEL here. - case OBLOCK: - return n.List.isterminating() + case ir.OBLOCK: + return isTermNodes(n.List()) - case OGOTO, ORETURN, ORETJMP, OPANIC, OFALL: + case ir.OGOTO, ir.ORETURN, ir.ORETJMP, ir.OPANIC, ir.OFALL: return true - case OFOR, OFORUNTIL: - if n.Left != nil { + case ir.OFOR, ir.OFORUNTIL: + if n.Left() != nil { return false } if n.HasBreak() { @@ -3829,24 +3845,24 @@ func (n *Node) isterminating() bool { } return true - case OIF: - return n.Nbody.isterminating() && n.Rlist.isterminating() + case ir.OIF: + return isTermNodes(n.Body()) && isTermNodes(n.Rlist()) - case OSWITCH, OTYPESW, OSELECT: + case ir.OSWITCH, ir.OTYPESW, ir.OSELECT: if n.HasBreak() { return false } def := false - for _, n1 := range n.List.Slice() { - if !n1.Nbody.isterminating() { + for _, n1 := range n.List().Slice() { + if !isTermNodes(n1.Body()) { return false } - if n1.List.Len() == 0 { // default + if n1.List().Len() == 0 { // default def = true } } - if n.Op != OSELECT && !def { + if n.Op() != ir.OSELECT && !def { return false } return true @@ -3856,36 +3872,36 @@ func (n *Node) isterminating() bool { } // checkreturn makes sure that fn terminates appropriately. -func checkreturn(fn *Node) { - if fn.Type.NumResults() != 0 && fn.Nbody.Len() != 0 { - markbreaklist(fn.Nbody, nil) - if !fn.Nbody.isterminating() { - yyerrorl(fn.Func.Endlineno, "missing return at end of function") +func checkreturn(fn ir.Node) { + if fn.Type().NumResults() != 0 && fn.Body().Len() != 0 { + markbreaklist(fn.Body(), nil) + if !isTermNodes(fn.Body()) { + base.ErrorfAt(fn.Func().Endlineno, "missing return at end of function") } } } -func deadcode(fn *Node) { - deadcodeslice(fn.Nbody) +func deadcode(fn ir.Node) { + deadcodeslice(fn.PtrBody()) deadcodefn(fn) } -func deadcodefn(fn *Node) { - if fn.Nbody.Len() == 0 { +func deadcodefn(fn ir.Node) { + if fn.Body().Len() == 0 { return } - for _, n := range fn.Nbody.Slice() { - if n.Ninit.Len() > 0 { + for _, n := range fn.Body().Slice() { + if n.Init().Len() > 0 { return } - switch n.Op { - case OIF: - if !Isconst(n.Left, CTBOOL) || n.Nbody.Len() > 0 || n.Rlist.Len() > 0 { + switch n.Op() { + case ir.OIF: + if !ir.IsConst(n.Left(), constant.Bool) || n.Body().Len() > 0 || n.Rlist().Len() > 0 { return } - case OFOR: - if !Isconst(n.Left, CTBOOL) || n.Left.BoolVal() { + case ir.OFOR: + if !ir.IsConst(n.Left(), constant.Bool) || n.Left().BoolVal() { return } default: @@ -3893,13 +3909,13 @@ func deadcodefn(fn *Node) { } } - fn.Nbody.Set([]*Node{nod(OEMPTY, nil, nil)}) + fn.PtrBody().Set([]ir.Node{ir.Nod(ir.OEMPTY, nil, nil)}) } -func deadcodeslice(nn Nodes) { +func deadcodeslice(nn *ir.Nodes) { var lastLabel = -1 for i, n := range nn.Slice() { - if n != nil && n.Op == OLABEL { + if n != nil && n.Op() == ir.OLABEL { lastLabel = i } } @@ -3911,16 +3927,16 @@ func deadcodeslice(nn Nodes) { if n == nil { continue } - if n.Op == OIF { - n.Left = deadcodeexpr(n.Left) - if Isconst(n.Left, CTBOOL) { - var body Nodes - if n.Left.BoolVal() { - n.Rlist = Nodes{} - body = n.Nbody + if n.Op() == ir.OIF { + n.SetLeft(deadcodeexpr(n.Left())) + if ir.IsConst(n.Left(), constant.Bool) { + var body ir.Nodes + if n.Left().BoolVal() { + n.SetRlist(ir.Nodes{}) + body = n.Body() } else { - n.Nbody = Nodes{} - body = n.Rlist + n.SetBody(ir.Nodes{}) + body = n.Rlist() } // If "then" or "else" branch ends with panic or return statement, // it is safe to remove all statements after this node. @@ -3928,8 +3944,8 @@ func deadcodeslice(nn Nodes) { // We must be careful not to deadcode-remove labels, as they // might be the target of a goto. See issue 28616. if body := body.Slice(); len(body) != 0 { - switch body[(len(body) - 1)].Op { - case ORETURN, ORETJMP, OPANIC: + switch body[(len(body) - 1)].Op() { + case ir.ORETURN, ir.ORETJMP, ir.OPANIC: if i > lastLabel { cut = true } @@ -3938,40 +3954,40 @@ func deadcodeslice(nn Nodes) { } } - deadcodeslice(n.Ninit) - deadcodeslice(n.Nbody) - deadcodeslice(n.List) - deadcodeslice(n.Rlist) + deadcodeslice(n.PtrInit()) + deadcodeslice(n.PtrBody()) + deadcodeslice(n.PtrList()) + deadcodeslice(n.PtrRlist()) if cut { - *nn.slice = nn.Slice()[:i+1] + nn.Set(nn.Slice()[:i+1]) break } } } -func deadcodeexpr(n *Node) *Node { +func deadcodeexpr(n ir.Node) ir.Node { // Perform dead-code elimination on short-circuited boolean // expressions involving constants with the intent of // producing a constant 'if' condition. - switch n.Op { - case OANDAND: - n.Left = deadcodeexpr(n.Left) - n.Right = deadcodeexpr(n.Right) - if Isconst(n.Left, CTBOOL) { - if n.Left.BoolVal() { - return n.Right // true && x => x + switch n.Op() { + case ir.OANDAND: + n.SetLeft(deadcodeexpr(n.Left())) + n.SetRight(deadcodeexpr(n.Right())) + if ir.IsConst(n.Left(), constant.Bool) { + if n.Left().BoolVal() { + return n.Right() // true && x => x } else { - return n.Left // false && x => false + return n.Left() // false && x => false } } - case OOROR: - n.Left = deadcodeexpr(n.Left) - n.Right = deadcodeexpr(n.Right) - if Isconst(n.Left, CTBOOL) { - if n.Left.BoolVal() { - return n.Left // true || x => true + case ir.OOROR: + n.SetLeft(deadcodeexpr(n.Left())) + n.SetRight(deadcodeexpr(n.Right())) + if ir.IsConst(n.Left(), constant.Bool) { + if n.Left().BoolVal() { + return n.Left() // true || x => true } else { - return n.Right // false || x => x + return n.Right() // false || x => x } } } @@ -3979,17 +3995,17 @@ func deadcodeexpr(n *Node) *Node { } // setTypeNode sets n to an OTYPE node representing t. -func setTypeNode(n *Node, t *types.Type) { - n.Op = OTYPE - n.Type = t - n.Type.Nod = asTypesNode(n) +func setTypeNode(n ir.Node, t *types.Type) { + n.SetOp(ir.OTYPE) + n.SetType(t) + n.Type().Nod = n } // getIotaValue returns the current value for "iota", // or -1 if not within a ConstSpec. func getIotaValue() int64 { if i := len(typecheckdefstack); i > 0 { - if x := typecheckdefstack[i-1]; x.Op == OLITERAL { + if x := typecheckdefstack[i-1]; x.Op() == ir.OLITERAL { return x.Iota() } } @@ -4006,14 +4022,33 @@ func curpkg() *types.Pkg { fn := Curfn if fn == nil { // Initialization expressions for package-scope variables. - return localpkg + return ir.LocalPkg } // TODO(mdempsky): Standardize on either ODCLFUNC or ONAME for // Curfn, rather than mixing them. - if fn.Op == ODCLFUNC { - fn = fn.Func.Nname + if fn.Op() == ir.ODCLFUNC { + fn = fn.Func().Nname } return fnpkg(fn) } + +// MethodName returns the ONAME representing the method +// referenced by expression n, which must be a method selector, +// method expression, or method value. +func methodExprName(n ir.Node) ir.Node { + return ir.AsNode(methodExprFunc(n).Nname) +} + +// MethodFunc is like MethodName, but returns the types.Field instead. +func methodExprFunc(n ir.Node) *types.Field { + switch n.Op() { + case ir.ODOTMETH, ir.OMETHEXPR: + return n.Opt().(*types.Field) + case ir.OCALLPART: + return callpartMethod(n) + } + base.Fatalf("unexpected node: %v (%v)", n, n.Op()) + panic("unreachable") +} |