diff --git a/ssa/builder.go b/ssa/builder.go index cd79e543..9c8f3b66 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -49,8 +49,8 @@ type opaqueType struct { func (t *opaqueType) String() string { return t.name } var ( - varOk = types.NewVar(token.NoPos, nil, "ok", tBool) - varIndex = types.NewVar(token.NoPos, nil, "index", tInt) + varOk = newVar("ok", tBool) + varIndex = newVar("index", tInt) // Type constants. tBool = types.Typ[types.Bool] @@ -236,7 +236,7 @@ func (b *builder) exprN(fn *Function, e ast.Expr) Value { tuple.(interface { setType(types.Type) }).setType(types.NewTuple( - types.NewVar(token.NoPos, nil, "value", typ), + newVar("value", typ), varOk, )) return tuple @@ -616,7 +616,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value { // Universal built-in or nil? switch obj := obj.(type) { case *types.Builtin: - return fn.Prog.builtins[obj] + return &Builtin{object: obj, sig: fn.Pkg.typeOf(e).(*types.Signature)} case *types.Nil: return nilConst(fn.Pkg.typeOf(e)) } @@ -756,7 +756,6 @@ func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, se // func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { c.pos = e.Lparen - c.HasEllipsis = e.Ellipsis != 0 // Is this a method call? if selector, ok := unparen(e.Fun).(*ast.SelectorExpr); ok { @@ -1442,7 +1441,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { for _, st := range states { if st.Dir == types.RecvOnly { tElem := st.Chan.Type().Underlying().(*types.Chan).Elem() - vars = append(vars, types.NewVar(token.NoPos, nil, "", tElem)) + vars = append(vars, newVar("", tElem)) } } sel.setType(types.NewTuple(vars...)) @@ -1610,7 +1609,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value } else { // length = len(x). var c Call - c.Call.Value = fn.Prog.builtins[types.Universe.Lookup("len").(*types.Builtin)] + c.Call.Value = makeLen(x.Type()) c.Call.Args = []Value{x} c.setType(tInt) length = fn.emit(&c) @@ -1714,8 +1713,8 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token. } okv.setType(types.NewTuple( varOk, - types.NewVar(token.NoPos, nil, "k", tk), - types.NewVar(token.NoPos, nil, "v", tv), + newVar("k", tk), + newVar("v", tv), )) fn.emit(okv) @@ -1761,7 +1760,7 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) } recv.setPos(pos) recv.setType(types.NewTuple( - types.NewVar(token.NoPos, nil, "k", x.Type().Underlying().(*types.Chan).Elem()), + newVar("k", x.Type().Underlying().(*types.Chan).Elem()), varOk, )) ko := fn.emit(recv) diff --git a/ssa/create.go b/ssa/create.go index 60677514..d8b04838 100644 --- a/ssa/create.go +++ b/ssa/create.go @@ -39,24 +39,14 @@ const ( // mode controls diagnostics and checking during SSA construction. // func NewProgram(fset *token.FileSet, mode BuilderMode) *Program { - prog := &Program{ + return &Program{ Fset: fset, imported: make(map[string]*Package), packages: make(map[*types.Package]*Package), - builtins: make(map[*types.Builtin]*Builtin), boundMethodWrappers: make(map[*types.Func]*Function), ifaceMethodWrappers: make(map[*types.Func]*Function), mode: mode, } - - // Create Values for built-in functions. - for _, name := range types.Universe.Names() { - if obj, ok := types.Universe.Lookup(name).(*types.Builtin); ok { - prog.builtins[obj] = &Builtin{obj} - } - } - - return prog } // memberFromObject populates package pkg with a member for the diff --git a/ssa/emit.go b/ssa/emit.go index 95bf5713..5319064d 100644 --- a/ssa/emit.go +++ b/ssa/emit.go @@ -297,7 +297,7 @@ func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value { } a.setPos(pos) a.setType(types.NewTuple( - types.NewVar(token.NoPos, nil, "value", t), + newVar("value", t), varOk, )) return f.emit(a) diff --git a/ssa/example_test.go b/ssa/example_test.go index 4532d4ca..1a92dfc7 100644 --- a/ssa/example_test.go +++ b/ssa/example_test.go @@ -106,6 +106,6 @@ func main() { // t2 = make interface{} <- string ("Hello, World!":string) interface{} // *t1 = t2 // t3 = slice t0[:] []interface{} - // t4 = fmt.Println(t3) (n int, err error) + // t4 = fmt.Println(t3...) (n int, err error) // return } diff --git a/ssa/print.go b/ssa/print.go index 4738068c..a64f9c93 100644 --- a/ssa/print.go +++ b/ssa/print.go @@ -120,7 +120,7 @@ func printCall(v *CallCommon, prefix string, instr Instruction) string { } b.WriteString(relName(arg, instr)) } - if v.HasEllipsis { + if v.Signature().IsVariadic() { b.WriteString("...") } b.WriteString(")") diff --git a/ssa/promote.go b/ssa/promote.go index 8adb38f2..936ac650 100644 --- a/ssa/promote.go +++ b/ssa/promote.go @@ -216,7 +216,7 @@ func findMethod(prog *Program, meth *types.Selection) *Function { func makeWrapper(prog *Program, typ types.Type, meth *types.Selection) *Function { obj := meth.Obj().(*types.Func) oldsig := obj.Type().(*types.Signature) - recv := types.NewVar(token.NoPos, nil, "recv", typ) + recv := newVar("recv", typ) description := fmt.Sprintf("wrapper for %s", obj) if prog.mode&LogSource != 0 { diff --git a/ssa/sanity.go b/ssa/sanity.go index 21de3d02..5368242d 100644 --- a/ssa/sanity.go +++ b/ssa/sanity.go @@ -179,6 +179,12 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { panic(fmt.Sprintf("Unknown instruction type: %T", instr)) } + if call, ok := instr.(CallInstruction); ok { + if call.Common().Signature() == nil { + s.errorf("nil signature: %s", call) + } + } + // Check that value-defining instructions have valid types. if v, ok := instr.(Value); ok { t := v.Type() diff --git a/ssa/ssa.go b/ssa/ssa.go index a0dfb527..70386946 100644 --- a/ssa/ssa.go +++ b/ssa/ssa.go @@ -25,7 +25,6 @@ type Program struct { Fset *token.FileSet // position information for the files of this Program imported map[string]*Package // all importable Packages, keyed by import path packages map[*types.Package]*Package // all loaded Packages, keyed by object - builtins map[*types.Builtin]*Builtin // all built-in functions, keyed by typechecker objects. mode BuilderMode // set of mode bits for SSA construction methodsMu sync.Mutex // guards the following maps: @@ -413,19 +412,19 @@ type Global struct { Pkg *Package } -// A Builtin represents a built-in function, e.g. len. +// A Builtin represents a specific use of a built-in function, e.g. len. // // Builtins are immutable values. Builtins do not have addresses. // Builtins can only appear in CallCommon.Func. // // Object() returns a *types.Builtin. // -// Type() returns types.Typ[types.Invalid], since built-in functions -// may have polymorphic or variadic types that are not expressible in -// Go's type system. +// Type() returns a *types.Signature representing the effective +// signature of the built-in for this call. // type Builtin struct { object *types.Builtin // canonical types.Universe object for this built-in + sig *types.Signature } // Value-defining instructions ---------------------------------------- @@ -842,7 +841,7 @@ type SelectState struct { DebugNode ast.Node // ast.SendStmt or ast.UnaryExpr(<-) [debug mode] } -// The Select instruction tests whether (or blocks until) one or more +// The Select instruction tests whether (or blocks until) one // of the specified sent or received states is entered. // // Let n be the number of States for which Dir==RECV and T_i (0<=i