| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package typecheck |
| |
| import ( |
| "fmt" |
| "sync" |
| |
| "cmd/compile/internal/base" |
| "cmd/compile/internal/ir" |
| "cmd/compile/internal/types" |
| "cmd/internal/src" |
| ) |
| |
| var funcStack []*ir.Func // stack of previous values of ir.CurFunc |
| |
| // DeclFunc declares the parameters for fn and adds it to |
| // Target.Funcs. |
| // |
| // Before returning, it sets CurFunc to fn. When the caller is done |
| // constructing fn, it must call FinishFuncBody to restore CurFunc. |
| func DeclFunc(fn *ir.Func) { |
| fn.DeclareParams(true) |
| fn.Nname.Defn = fn |
| Target.Funcs = append(Target.Funcs, fn) |
| |
| funcStack = append(funcStack, ir.CurFunc) |
| ir.CurFunc = fn |
| } |
| |
| // FinishFuncBody restores ir.CurFunc to its state before the last |
| // call to DeclFunc. |
| func FinishFuncBody() { |
| funcStack, ir.CurFunc = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1] |
| } |
| |
| func CheckFuncStack() { |
| if len(funcStack) != 0 { |
| base.Fatalf("funcStack is non-empty: %v", len(funcStack)) |
| } |
| } |
| |
| // make a new Node off the books. |
| func TempAt(pos src.XPos, curfn *ir.Func, typ *types.Type) *ir.Name { |
| if curfn == nil { |
| base.FatalfAt(pos, "no curfn for TempAt") |
| } |
| if typ == nil { |
| base.FatalfAt(pos, "TempAt called with nil type") |
| } |
| if typ.Kind() == types.TFUNC && typ.Recv() != nil { |
| base.FatalfAt(pos, "misuse of method type: %v", typ) |
| } |
| types.CalcSize(typ) |
| |
| sym := &types.Sym{ |
| Name: autotmpname(len(curfn.Dcl)), |
| Pkg: types.LocalPkg, |
| } |
| name := curfn.NewLocal(pos, sym, typ) |
| name.SetEsc(ir.EscNever) |
| name.SetUsed(true) |
| name.SetAutoTemp(true) |
| |
| return name |
| } |
| |
| var ( |
| autotmpnamesmu sync.Mutex |
| autotmpnames []string |
| ) |
| |
| // autotmpname returns the name for an autotmp variable numbered n. |
| func autotmpname(n int) string { |
| autotmpnamesmu.Lock() |
| defer autotmpnamesmu.Unlock() |
| |
| // Grow autotmpnames, if needed. |
| if n >= len(autotmpnames) { |
| autotmpnames = append(autotmpnames, make([]string, n+1-len(autotmpnames))...) |
| autotmpnames = autotmpnames[:cap(autotmpnames)] |
| } |
| |
| s := autotmpnames[n] |
| if s == "" { |
| // Give each tmp a different name so that they can be registerized. |
| // Add a preceding . to avoid clashing with legal names. |
| prefix := ".autotmp_%d" |
| |
| s = fmt.Sprintf(prefix, n) |
| autotmpnames[n] = s |
| } |
| return s |
| } |
| |
| // f is method type, with receiver. |
| // return function type, receiver as first argument (or not). |
| func NewMethodType(sig *types.Type, recv *types.Type) *types.Type { |
| nrecvs := 0 |
| if recv != nil { |
| nrecvs++ |
| } |
| |
| // TODO(mdempsky): Move this function to types. |
| // TODO(mdempsky): Preserve positions, names, and package from sig+recv. |
| |
| params := make([]*types.Field, nrecvs+sig.NumParams()) |
| if recv != nil { |
| params[0] = types.NewField(base.Pos, nil, recv) |
| } |
| for i, param := range sig.Params() { |
| d := types.NewField(base.Pos, nil, param.Type) |
| d.SetIsDDD(param.IsDDD()) |
| params[nrecvs+i] = d |
| } |
| |
| results := make([]*types.Field, sig.NumResults()) |
| for i, t := range sig.Results() { |
| results[i] = types.NewField(base.Pos, nil, t.Type) |
| } |
| |
| return types.NewSignature(nil, params, results) |
| } |