"strings"
)
+// To enable tracing support (-t flag), set enableTrace to true.
+const enableTrace = false
+
+var trace bool
+var traceIndent []byte
+
+func tracePrint(title string, n *Node) func(np **Node) {
+ indent := traceIndent
+
+ // guard against nil
+ var pos, op string
+ var tc uint8
+ if n != nil {
+ pos = linestr(n.Pos)
+ op = n.Op.String()
+ tc = n.Typecheck()
+ }
+
+ 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) {
+ traceIndent = traceIndent[:len(traceIndent)-2]
+
+ // if we have a result, use that
+ if np != nil {
+ n = *np
+ }
+
+ // guard against nil
+ // use outer pos, op so we don't get empty pos/op if n == nil (nicer output)
+ var tc uint8
+ var typ *types.Type
+ if n != nil {
+ pos = linestr(n.Pos)
+ op = n.Op.String()
+ tc = n.Typecheck()
+ typ = n.Type
+ }
+
+ fmt.Printf("%s: %s=> %p %s %v tc=%d type=%#L\n", pos, indent, n, op, n, tc, typ)
+ }
+}
+
const (
Etop = 1 << iota // evaluated at statement level
Erv // evaluated in value context
var typecheckdefstack []*Node
// resolve ONONAME to definition, if any.
-func resolve(n *Node) *Node {
+func resolve(n *Node) (res *Node) {
if n == nil || n.Op != ONONAME {
return n
}
+ // only trace if there's work to do
+ if enableTrace && trace {
+ defer tracePrint("resolve", n)(&res)
+ }
+
if n.Sym.Pkg != localpkg {
if inimport {
Fatalf("recursive inimport")
// 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) *Node {
+func typecheck(n *Node, top int) (res *Node) {
// cannot type check until all the source has been parsed
if !typecheckok {
Fatalf("early typecheck")
return nil
}
+ // only trace if there's work to do
+ if enableTrace && trace {
+ defer tracePrint("typecheck", n)(&res)
+ }
+
lno := setlineno(n)
// Skip over parens.
// The result of typecheck1 MUST be assigned back to n, e.g.
// n.Left = typecheck1(n.Left, top)
-func typecheck1(n *Node, top int) *Node {
+func typecheck1(n *Node, top int) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheck1", n)(&res)
+ }
+
switch n.Op {
case OLITERAL, ONAME, ONONAME, OTYPE:
if n.Sym == nil {
// typecheckMethodExpr checks selector expressions (ODOT) where the
// base expression is a type expression (OTYPE).
-func typecheckMethodExpr(n *Node) *Node {
+func typecheckMethodExpr(n *Node) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckMethodExpr", n)(&res)
+ }
+
t := n.Left.Type
// Compute the method set for t.
// The result of typecheckcomplit MUST be assigned back to n, e.g.
// n.Left = typecheckcomplit(n.Left)
-func typecheckcomplit(n *Node) *Node {
+func typecheckcomplit(n *Node) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckcomplit", n)(&res)
+ }
+
lno := lineno
defer func() {
lineno = lno
// 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 {
+ defer tracePrint("typecheckas", n)(nil)
+ }
+
// delicate little dance.
// the definition of n may refer to this assignment
// as its definition, in which case it will call typecheckas.
}
func typecheckas2(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckas2", n)(nil)
+ }
+
ls := n.List.Slice()
for i1, n1 := range ls {
// delicate little dance.
// type check function definition
func typecheckfunc(n *Node) {
+ if enableTrace && trace {
+ 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
}
func typecheckdeftype(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckdeftype", n)(nil)
+ }
+
n.Type.Sym = n.Sym
n.SetTypecheck(1)
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
}
func typecheckdef(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckdef", n)(nil)
+ }
+
lno := setlineno(n)
if n.Op == ONONAME {