1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package typecheck 6 7import ( 8 "fmt" 9 "sync" 10 11 "cmd/compile/internal/base" 12 "cmd/compile/internal/ir" 13 "cmd/compile/internal/types" 14 "cmd/internal/src" 15) 16 17var funcStack []*ir.Func // stack of previous values of ir.CurFunc 18 19// DeclFunc declares the parameters for fn and adds it to 20// Target.Funcs. 21// 22// Before returning, it sets CurFunc to fn. When the caller is done 23// constructing fn, it must call FinishFuncBody to restore CurFunc. 24func DeclFunc(fn *ir.Func) { 25 fn.DeclareParams(true) 26 fn.Nname.Defn = fn 27 Target.Funcs = append(Target.Funcs, fn) 28 29 funcStack = append(funcStack, ir.CurFunc) 30 ir.CurFunc = fn 31} 32 33// FinishFuncBody restores ir.CurFunc to its state before the last 34// call to DeclFunc. 35func FinishFuncBody() { 36 funcStack, ir.CurFunc = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1] 37} 38 39func CheckFuncStack() { 40 if len(funcStack) != 0 { 41 base.Fatalf("funcStack is non-empty: %v", len(funcStack)) 42 } 43} 44 45// make a new Node off the books. 46func TempAt(pos src.XPos, curfn *ir.Func, typ *types.Type) *ir.Name { 47 if curfn == nil { 48 base.FatalfAt(pos, "no curfn for TempAt") 49 } 50 if typ == nil { 51 base.FatalfAt(pos, "TempAt called with nil type") 52 } 53 if typ.Kind() == types.TFUNC && typ.Recv() != nil { 54 base.FatalfAt(pos, "misuse of method type: %v", typ) 55 } 56 types.CalcSize(typ) 57 58 sym := &types.Sym{ 59 Name: autotmpname(len(curfn.Dcl)), 60 Pkg: types.LocalPkg, 61 } 62 name := curfn.NewLocal(pos, sym, typ) 63 name.SetEsc(ir.EscNever) 64 name.SetUsed(true) 65 name.SetAutoTemp(true) 66 67 return name 68} 69 70var ( 71 autotmpnamesmu sync.Mutex 72 autotmpnames []string 73) 74 75// autotmpname returns the name for an autotmp variable numbered n. 76func autotmpname(n int) string { 77 autotmpnamesmu.Lock() 78 defer autotmpnamesmu.Unlock() 79 80 // Grow autotmpnames, if needed. 81 if n >= len(autotmpnames) { 82 autotmpnames = append(autotmpnames, make([]string, n+1-len(autotmpnames))...) 83 autotmpnames = autotmpnames[:cap(autotmpnames)] 84 } 85 86 s := autotmpnames[n] 87 if s == "" { 88 // Give each tmp a different name so that they can be registerized. 89 // Add a preceding . to avoid clashing with legal names. 90 prefix := ".autotmp_%d" 91 92 s = fmt.Sprintf(prefix, n) 93 autotmpnames[n] = s 94 } 95 return s 96} 97 98// f is method type, with receiver. 99// return function type, receiver as first argument (or not). 100func NewMethodType(sig *types.Type, recv *types.Type) *types.Type { 101 nrecvs := 0 102 if recv != nil { 103 nrecvs++ 104 } 105 106 // TODO(mdempsky): Move this function to types. 107 // TODO(mdempsky): Preserve positions, names, and package from sig+recv. 108 109 params := make([]*types.Field, nrecvs+sig.NumParams()) 110 if recv != nil { 111 params[0] = types.NewField(base.Pos, nil, recv) 112 } 113 for i, param := range sig.Params() { 114 d := types.NewField(base.Pos, nil, param.Type) 115 d.SetIsDDD(param.IsDDD()) 116 params[nrecvs+i] = d 117 } 118 119 results := make([]*types.Field, sig.NumResults()) 120 for i, t := range sig.Results() { 121 results[i] = types.NewField(base.Pos, nil, t.Type) 122 } 123 124 return types.NewSignature(nil, params, results) 125} 126