func (this DepthWalker) Visit(node ast.Node) ast.Visitor { if node == nil { return this + 1 } buffer := "" for i := 0; i < int(this); i++ { buffer += " " } fmt.Printf("%sPos: %d %s\n", buffer, node.Pos(), AllSources.Position(node.Pos())) fmt.Printf("%sEnd: %d %s\n", buffer, node.End(), AllSources.Position(node.End())) fmt.Printf("%s%T\n", buffer, node) fmt.Printf("%s%v\n", buffer, node) if e, ok := node.(ast.Expr); ok { obj, typ := types.ExprType(e, LocalImporter) fmt.Printf("%s%v\n", buffer, obj) fmt.Printf("%s%v\n", buffer, typ) } fmt.Println() switch n := node.(type) { } return this + 1 }
func exprType(n ast.Node, expectTuple bool, pkg string, importer Importer) (xobj *ast.Object, typ Type) { debugp("exprType tuple:%v pkg:%s %T %v [", expectTuple, pkg, n, pretty{n}) defer func() { debugp("] -> %p, %v", xobj, typ) }() switch n := n.(type) { case nil: case *ast.Ident: obj := n.Obj if obj == nil || obj.Kind == ast.Bad { break } // A type object represents itself. if obj.Kind == ast.Typ { // Objects in the universal scope don't live // in any package. if parser.Universe.Lookup(obj.Name) == obj { pkg = "" } return obj, Type{n, obj.Kind, pkg} } expr, typ := splitDecl(obj, n) switch { case typ != nil: _, t := exprType(typ, false, pkg, importer) if t.Kind != ast.Bad { t.Kind = obj.Kind } return obj, t case expr != nil: _, t := exprType(expr, false, pkg, importer) if t.Kind == ast.Typ { debugp("expected value, got type %v", t) t = badType } return obj, t default: switch n.Obj { case falseIdent.Obj, trueIdent.Obj: return obj, Type{boolIdent, ast.Con, ""} case iotaIdent.Obj: return obj, Type{intIdent, ast.Con, ""} default: return obj, Type{} } } case *ast.LabeledStmt: return n.Label.Obj, Type{n, ast.Lbl, pkg} case *ast.ImportSpec: return nil, Type{n, ast.Pkg, ""} case *ast.ParenExpr: return exprType(n.X, expectTuple, pkg, importer) case *ast.CompositeLit: return nil, certify(n.Type, ast.Var, pkg, importer) case *ast.FuncLit: return nil, certify(n.Type, ast.Var, pkg, importer) case *ast.SelectorExpr: _, t := exprType(n.X, false, pkg, importer) // TODO: method expressions. when t.Kind == ast.Typ, // mutate a method declaration into a function with // the receiver as first argument if t.Kind == ast.Bad { break } obj := t.Member(n.Sel.Name, importer) if obj == nil { return nil, badType } if t.Kind == ast.Pkg { eobj, et := exprType(&ast.Ident{Name: obj.Name, Obj: obj}, false, t.Pkg, importer) et.Pkg = litToString(t.Node.(*ast.ImportSpec).Path) return eobj, et } // a method turns into a function type; // the number of formal arguments depends // on the class of the receiver expression. if fd, ismethod := obj.Decl.(*ast.FuncDecl); ismethod { if t.Kind == ast.Typ { return obj, certify(methodExpr(fd), ast.Fun, t.Pkg, importer) } return obj, certify(fd.Type, ast.Fun, t.Pkg, importer) } else if obj.Kind == ast.Typ { return obj, certify(&ast.Ident{Name: obj.Name, Obj: obj}, ast.Typ, t.Pkg, importer) } _, typ := splitDecl(obj, nil) return obj, certify(typ, obj.Kind, t.Pkg, importer) case *ast.FuncDecl: return nil, certify(methodExpr(n), ast.Fun, pkg, importer) case *ast.IndexExpr: _, t0 := exprType(n.X, false, pkg, importer) t := t0.Underlying(true, importer) switch n := t.Node.(type) { case *ast.ArrayType: return nil, certify(n.Elt, ast.Var, t.Pkg, importer) case *ast.MapType: t := certify(n.Value, ast.Var, t.Pkg, importer) if expectTuple { return nil, Type{MultiValue{[]ast.Expr{t.Node.(ast.Expr), predecl("bool")}}, ast.Var, t.Pkg} } return nil, t } case *ast.SliceExpr: _, typ := exprType(n.X, false, pkg, importer) return nil, typ case *ast.CallExpr: switch exprName(n.Fun) { case makeIdent.Obj: if len(n.Args) > 0 { return nil, certify(n.Args[0], ast.Var, pkg, importer) } case newIdent.Obj: if len(n.Args) > 0 { t := certify(n.Args[0], ast.Var, pkg, importer) if t.Kind != ast.Bad { return nil, Type{&ast.StarExpr{n.Pos(), t.Node.(ast.Expr)}, ast.Var, t.Pkg} } } default: if _, fntype := exprType(n.Fun, false, pkg, importer); fntype.Kind != ast.Bad { // A type cast transforms a type expression // into a value expression. if fntype.Kind == ast.Typ { fntype.Kind = ast.Var // Preserve constness if underlying expr is constant. if len(n.Args) == 1 { _, argtype := exprType(n.Args[0], false, pkg, importer) if argtype.Kind == ast.Con { fntype.Kind = ast.Con } } return nil, fntype } // A function call operates on the underlying type, t := fntype.Underlying(true, importer) if fn, ok := t.Node.(*ast.FuncType); ok { return nil, certify(fields2type(fn.Results), ast.Var, t.Pkg, importer) } } } case *ast.StarExpr: if _, t := exprType(n.X, false, pkg, importer); t.Kind != ast.Bad { if t.Kind == ast.Typ { return nil, Type{&ast.StarExpr{n.Pos(), t.Node.(ast.Expr)}, ast.Typ, t.Pkg} } if n, ok := t.Node.(*ast.StarExpr); ok { return nil, certify(n.X, ast.Var, t.Pkg, importer) } } case *ast.TypeAssertExpr: t := certify(n.Type, ast.Var, pkg, importer) if expectTuple && t.Kind != ast.Bad { return nil, Type{MultiValue{[]ast.Expr{t.Node.(ast.Expr), predecl("bool")}}, ast.Var, t.Pkg} } return nil, t case *ast.UnaryExpr: if _, t := exprType(n.X, false, pkg, importer); t.Kind != ast.Bad { u := t.Underlying(true, importer) switch n.Op { case token.ARROW: if ct, ok := u.Node.(*ast.ChanType); ok { t := certify(ct.Value, ast.Var, u.Pkg, importer) if expectTuple && t.Kind != ast.Bad { return nil, Type{MultiValue{[]ast.Expr{t.Node.(ast.Expr), predecl("bool")}}, ast.Var, t.Pkg} } return nil, certify(ct.Value, ast.Var, u.Pkg, importer) } case token.RANGE: switch n := u.Node.(type) { case *ast.ArrayType: if expectTuple { return nil, Type{MultiValue{[]ast.Expr{predecl("int"), n.Elt}}, ast.Var, u.Pkg} } return nil, Type{predecl("bool"), ast.Var, ""} case *ast.MapType: if expectTuple { return nil, Type{MultiValue{[]ast.Expr{n.Key, n.Value}}, ast.Var, u.Pkg} } return nil, certify(n.Key, ast.Var, u.Pkg, importer) case *ast.ChanType: return nil, certify(n.Value, ast.Var, u.Pkg, importer) } case token.AND: if t.Kind == ast.Var { return nil, Type{&ast.StarExpr{n.Pos(), t.Node.(ast.Expr)}, ast.Var, t.Pkg} } case token.NOT: return nil, Type{predecl("bool"), t.Kind, ""} default: return nil, t } } case *ast.BinaryExpr: switch n.Op { case token.LSS, token.EQL, token.GTR, token.NEQ, token.LEQ, token.GEQ, token.ARROW, token.LOR, token.LAND: _, t := exprType(n.X, false, pkg, importer) if t.Kind == ast.Con { _, t = exprType(n.Y, false, pkg, importer) } return nil, Type{predecl("bool"), t.Kind, ""} case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.AND_NOT, token.XOR: _, tx := exprType(n.X, false, pkg, importer) _, ty := exprType(n.Y, false, pkg, importer) switch { case tx.Kind == ast.Bad || ty.Kind == ast.Bad: case !isNamedType(tx, importer): return nil, ty case !isNamedType(ty, importer): return nil, tx } // could check type equality return nil, tx case token.SHL, token.SHR: _, typ := exprType(n.X, false, pkg, importer) return nil, typ } case *ast.BasicLit: var id *ast.Ident switch n.Kind { case token.STRING: id = stringIdent case token.INT, token.CHAR: id = intIdent case token.FLOAT: id = floatIdent default: debugp("unknown constant type %v", n.Kind) } if id != nil { return nil, Type{id, ast.Con, ""} } case *ast.StructType, *ast.ChanType, *ast.MapType, *ast.ArrayType, *ast.InterfaceType, *ast.FuncType: return nil, Type{n.(ast.Node), ast.Typ, pkg} case MultiValue: return nil, Type{n, ast.Typ, pkg} case *exprIndex: _, t := exprType(n.x, true, pkg, importer) if t.Kind != ast.Bad { if ts, ok := t.Node.(MultiValue); ok { if n.i < len(ts.Types) { return nil, certify(ts.Types[n.i], ast.Var, t.Pkg, importer) } } } case *ast.Ellipsis: t := certify(n.Elt, ast.Var, pkg, importer) if t.Kind != ast.Bad { return nil, Type{&ast.ArrayType{n.Pos(), nil, t.Node.(ast.Expr)}, ast.Var, t.Pkg} } default: panic(fmt.Sprintf("unknown type %T", n)) } return nil, badType }