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.
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/types"
17 var DeclContext ir.Class = ir.PEXTERN // PEXTERN/PAUTO
19 func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
20 if tfn.Op() != ir.OTFUNC {
21 base.Fatalf("expected OTFUNC node, got %v", tfn)
24 fn := ir.NewFunc(base.Pos)
25 fn.Nname = ir.NewNameAt(base.Pos, sym)
31 fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
35 // Declare records that Node n declares symbol n.Sym in the specified
36 // declaration context.
37 func Declare(n *ir.Name, ctxt ir.Class) {
44 // kludgy: TypecheckAllowed means we're past parsing. Eg reflectdata.methodWrapper may declare out of package names later.
45 if !inimport && !TypecheckAllowed && s.Pkg != types.LocalPkg {
46 base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
49 if ctxt == ir.PEXTERN {
51 base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
53 if s.Name == "main" && s.Pkg.Name == "main" {
54 base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
56 Target.Externs = append(Target.Externs, n)
58 if ir.CurFunc == nil && ctxt == ir.PAUTO {
60 base.Fatalf("automatic outside function")
62 if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
63 ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
73 if s.Block == types.Block {
74 // functype will print errors about duplicate function arguments.
75 // Don't repeat the error here.
76 if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
77 Redeclared(n.Pos(), s, "in this block")
82 s.Lastlineno = base.Pos
92 // Export marks n for export (or reexport).
93 func Export(n *ir.Name) {
94 if n.Sym().OnExportList() {
97 n.Sym().SetOnExportList(true)
100 fmt.Printf("export symbol %v\n", n.Sym())
103 Target.Exports = append(Target.Exports, n)
106 // Redeclared emits a diagnostic about symbol s being redeclared at pos.
107 func Redeclared(pos src.XPos, s *types.Sym, where string) {
108 if !s.Lastlineno.IsKnown() {
109 pkgName := DotImportRefs[s.Def.(*ir.Ident)]
110 base.ErrorfAt(pos, "%v redeclared %s\n"+
111 "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
113 prevPos := s.Lastlineno
115 // When an import and a declaration collide in separate files,
116 // present the import as the "redeclared", because the declaration
117 // is visible where the import is, but not vice versa.
120 pos, prevPos = prevPos, pos
123 base.ErrorfAt(pos, "%v redeclared %s\n"+
124 "\t%v: previous declaration", s, where, base.FmtPos(prevPos))
128 // declare the function proper
129 // and declare the arguments.
130 // called in extern-declaration context
131 // returns in auto-declaration context.
132 func StartFuncBody(fn *ir.Func) {
133 // change the declaration context from extern to auto
134 funcStack = append(funcStack, funcStackEnt{ir.CurFunc, DeclContext})
136 DeclContext = ir.PAUTO
140 if fn.Nname.Ntype != nil {
141 funcargs(fn.Nname.Ntype.(*ir.FuncType))
148 // called in auto-declaration context.
149 // returns in extern-declaration context.
150 func FinishFuncBody() {
151 // change the declaration context from auto to previous context
154 funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
155 ir.CurFunc, DeclContext = e.curfn, e.dclcontext
158 func CheckFuncStack() {
159 if len(funcStack) != 0 {
160 base.Fatalf("funcStack is non-empty: %v", len(funcStack))
164 // Add a method, declared as a function.
165 // - msym is the method symbol
166 // - t is function type (with receiver)
167 // Returns a pointer to the existing or added Field; or nil if there's an error.
168 func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
170 base.Fatalf("no method symbol")
173 // get parent type sym
174 rf := t.Recv() // ptr to this structure
176 base.Errorf("missing receiver")
180 mt := types.ReceiverBaseType(rf.Type)
181 if mt == nil || mt.Sym() == nil {
184 if t != nil && t.IsPtr() {
186 base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
193 case t == nil || t.Broke():
194 // rely on typecheck having complained before
196 base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
198 base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
199 case t.IsInterface():
200 base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
202 // Should have picked off all the reasons above,
203 // but just in case, fall back to generic error.
204 base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
209 if local && mt.Sym().Pkg != types.LocalPkg {
210 base.Errorf("cannot define new methods on non-local type %v", mt)
219 for _, f := range mt.Fields().Slice() {
221 base.Errorf("type %v has both field and method named %v", mt, msym)
228 for _, f := range mt.Methods().Slice() {
229 if msym.Name != f.Sym.Name {
232 // types.Identical only checks that incoming and result parameters match,
233 // so explicitly check that the receiver parameters match too.
234 if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
235 base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
240 f := types.NewField(base.Pos, msym, t)
242 f.SetNointerface(nointerface)
244 mt.Methods().Append(f)
248 func autoexport(n *ir.Name, ctxt ir.Class) {
249 if n.Sym().Pkg != types.LocalPkg {
252 if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || DeclContext != ir.PEXTERN {
255 if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) {
259 if types.IsExported(n.Sym().Name) || n.Sym().Name == "init" {
262 if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
264 Target.Asms = append(Target.Asms, n)
268 // checkdupfields emits errors for duplicately named fields or methods in
269 // a list of struct or interface types.
270 func checkdupfields(what string, fss ...[]*types.Field) {
271 seen := make(map[*types.Sym]bool)
272 for _, fs := range fss {
273 for _, f := range fs {
274 if f.Sym == nil || f.Sym.IsBlank() {
278 base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
286 // structs, functions, and methods.
287 // they don't belong here, but where do they belong?
288 func checkembeddedtype(t *types.Type) {
293 if t.Sym() == nil && t.IsPtr() {
296 base.Errorf("embedded type cannot be a pointer to interface")
300 if t.IsPtr() || t.IsUnsafePtr() {
301 base.Errorf("embedded type cannot be a pointer")
302 } else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
303 t.ForwardType().Embedlineno = base.Pos
307 func fakeRecvField() *types.Field {
308 return types.NewField(src.NoXPos, nil, types.FakeRecvType())
311 var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext
313 type funcStackEnt struct {
318 func funcarg(n *ir.Field, ctxt ir.Class) {
323 name := ir.NewNameAt(n.Pos, n.Sym)
329 func funcarg2(f *types.Field, ctxt ir.Class) {
333 n := ir.NewNameAt(f.Pos, f.Sym)
339 func funcargs(nt *ir.FuncType) {
340 if nt.Op() != ir.OTFUNC {
341 base.Fatalf("funcargs %v", nt.Op())
344 // declare the receiver and in arguments.
346 funcarg(nt.Recv, ir.PPARAM)
348 for _, n := range nt.Params {
349 funcarg(n, ir.PPARAM)
352 // declare the out arguments.
353 gen := len(nt.Params)
354 for _, n := range nt.Results {
356 // Name so that escape analysis can track it. ~r stands for 'result'.
357 n.Sym = LookupNum("~r", gen)
361 // Give it a name so we can assign to it during return. ~b stands for 'blank'.
362 // The name must be different from ~r above because if you have
365 // f is allowed to use a plain 'return' with no arguments, while g is not.
366 // So the two cases must be distinguished.
367 n.Sym = LookupNum("~b", gen)
371 funcarg(n, ir.PPARAMOUT)
375 // Same as funcargs, except run over an already constructed TFUNC.
376 // This happens during import, where the hidden_fndcl rule has
377 // used functype directly to parse the function's type.
378 func funcargs2(t *types.Type) {
379 if t.Kind() != types.TFUNC {
380 base.Fatalf("funcargs2 %v", t)
383 for _, f := range t.Recvs().Fields().Slice() {
384 funcarg2(f, ir.PPARAM)
386 for _, f := range t.Params().Fields().Slice() {
387 funcarg2(f, ir.PPARAM)
389 for _, f := range t.Results().Fields().Slice() {
390 funcarg2(f, ir.PPARAMOUT)
394 func Temp(t *types.Type) *ir.Name {
395 return TempAt(base.Pos, ir.CurFunc, t)
398 // make a new Node off the books
399 func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
401 base.Fatalf("no curfn for TempAt")
403 if curfn.Op() == ir.OCLOSURE {
404 ir.Dump("TempAt", curfn)
405 base.Fatalf("adding TempAt to wrong closure function")
408 base.Fatalf("TempAt called with nil type")
410 if t.Kind() == types.TFUNC && t.Recv() != nil {
411 base.Fatalf("misuse of method type: %v", t)
415 Name: autotmpname(len(curfn.Dcl)),
418 n := ir.NewNameAt(pos, s)
422 n.SetEsc(ir.EscNever)
426 curfn.Dcl = append(curfn.Dcl, n)
433 // autotmpname returns the name for an autotmp variable numbered n.
434 func autotmpname(n int) string {
435 // Give each tmp a different name so that they can be registerized.
436 // Add a preceding . to avoid clashing with legal names.
437 const prefix = ".autotmp_"
438 // Start with a buffer big enough to hold a large n.
439 b := []byte(prefix + " ")[:len(prefix)]
440 b = strconv.AppendInt(b, int64(n), 10)
441 return types.InternString(b)
444 // f is method type, with receiver.
445 // return function type, receiver as first argument (or not).
446 func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
452 // TODO(mdempsky): Move this function to types.
453 // TODO(mdempsky): Preserve positions, names, and package from sig+recv.
455 params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
457 params[0] = types.NewField(base.Pos, nil, recv)
459 for i, param := range sig.Params().Fields().Slice() {
460 d := types.NewField(base.Pos, nil, param.Type)
461 d.SetIsDDD(param.IsDDD())
465 results := make([]*types.Field, sig.Results().Fields().Len())
466 for i, t := range sig.Results().Fields().Slice() {
467 results[i] = types.NewField(base.Pos, nil, t.Type)
470 return types.NewSignature(types.LocalPkg, nil, params, results)