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