Source file src/cmd/compile/internal/typecheck/dcl.go

     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  
     5  package typecheck
     6  
     7  import (
     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  
    17  var DeclContext ir.Class = ir.PEXTERN // PEXTERN/PAUTO
    18  
    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)
    22  	}
    23  
    24  	fn := ir.NewFunc(base.Pos)
    25  	fn.Nname = ir.NewNameAt(base.Pos, sym)
    26  	fn.Nname.Func = fn
    27  	fn.Nname.Defn = fn
    28  	fn.Nname.Ntype = tfn
    29  	ir.MarkFunc(fn.Nname)
    30  	StartFuncBody(fn)
    31  	fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
    32  	return fn
    33  }
    34  
    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) {
    38  	if ir.IsBlank(n) {
    39  		return
    40  	}
    41  
    42  	s := n.Sym()
    43  
    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)
    47  	}
    48  
    49  	if ctxt == ir.PEXTERN {
    50  		if s.Name == "init" {
    51  			base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
    52  		}
    53  		if s.Name == "main" && s.Pkg.Name == "main" {
    54  			base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
    55  		}
    56  		Target.Externs = append(Target.Externs, n)
    57  	} else {
    58  		if ir.CurFunc == nil && ctxt == ir.PAUTO {
    59  			base.Pos = n.Pos()
    60  			base.Fatalf("automatic outside function")
    61  		}
    62  		if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
    63  			ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
    64  		}
    65  		types.Pushdcl(s)
    66  		n.Curfn = ir.CurFunc
    67  	}
    68  
    69  	if ctxt == ir.PAUTO {
    70  		n.SetFrameOffset(0)
    71  	}
    72  
    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")
    78  		}
    79  	}
    80  
    81  	s.Block = types.Block
    82  	s.Lastlineno = base.Pos
    83  	s.Def = n
    84  	n.Class = ctxt
    85  	if ctxt == ir.PFUNC {
    86  		n.Sym().SetFunc(true)
    87  	}
    88  
    89  	autoexport(n, ctxt)
    90  }
    91  
    92  // Export marks n for export (or reexport).
    93  func Export(n *ir.Name) {
    94  	if n.Sym().OnExportList() {
    95  		return
    96  	}
    97  	n.Sym().SetOnExportList(true)
    98  
    99  	if base.Flag.E != 0 {
   100  		fmt.Printf("export symbol %v\n", n.Sym())
   101  	}
   102  
   103  	Target.Exports = append(Target.Exports, n)
   104  }
   105  
   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  		var pkgName *ir.PkgName
   110  		if s.Def == nil {
   111  			for id, pkg := range DotImportRefs {
   112  				if id.Sym().Name == s.Name {
   113  					pkgName = pkg
   114  					break
   115  				}
   116  			}
   117  		} else {
   118  			pkgName = DotImportRefs[s.Def.(*ir.Ident)]
   119  		}
   120  		base.ErrorfAt(pos, "%v redeclared %s\n"+
   121  			"\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
   122  	} else {
   123  		prevPos := s.Lastlineno
   124  
   125  		// When an import and a declaration collide in separate files,
   126  		// present the import as the "redeclared", because the declaration
   127  		// is visible where the import is, but not vice versa.
   128  		// See issue 4510.
   129  		if s.Def == nil {
   130  			pos, prevPos = prevPos, pos
   131  		}
   132  
   133  		base.ErrorfAt(pos, "%v redeclared %s\n"+
   134  			"\t%v: previous declaration", s, where, base.FmtPos(prevPos))
   135  	}
   136  }
   137  
   138  // declare the function proper
   139  // and declare the arguments.
   140  // called in extern-declaration context
   141  // returns in auto-declaration context.
   142  func StartFuncBody(fn *ir.Func) {
   143  	// change the declaration context from extern to auto
   144  	funcStack = append(funcStack, funcStackEnt{ir.CurFunc, DeclContext})
   145  	ir.CurFunc = fn
   146  	DeclContext = ir.PAUTO
   147  
   148  	types.Markdcl()
   149  
   150  	if fn.Nname.Ntype != nil {
   151  		funcargs(fn.Nname.Ntype.(*ir.FuncType))
   152  	} else {
   153  		funcargs2(fn.Type())
   154  	}
   155  }
   156  
   157  // finish the body.
   158  // called in auto-declaration context.
   159  // returns in extern-declaration context.
   160  func FinishFuncBody() {
   161  	// change the declaration context from auto to previous context
   162  	types.Popdcl()
   163  	var e funcStackEnt
   164  	funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
   165  	ir.CurFunc, DeclContext = e.curfn, e.dclcontext
   166  }
   167  
   168  func CheckFuncStack() {
   169  	if len(funcStack) != 0 {
   170  		base.Fatalf("funcStack is non-empty: %v", len(funcStack))
   171  	}
   172  }
   173  
   174  // Add a method, declared as a function.
   175  // - msym is the method symbol
   176  // - t is function type (with receiver)
   177  // Returns a pointer to the existing or added Field; or nil if there's an error.
   178  func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
   179  	if msym == nil {
   180  		base.Fatalf("no method symbol")
   181  	}
   182  
   183  	// get parent type sym
   184  	rf := t.Recv() // ptr to this structure
   185  	if rf == nil {
   186  		base.Errorf("missing receiver")
   187  		return nil
   188  	}
   189  
   190  	mt := types.ReceiverBaseType(rf.Type)
   191  	if mt == nil || mt.Sym() == nil {
   192  		pa := rf.Type
   193  		t := pa
   194  		if t != nil && t.IsPtr() {
   195  			if t.Sym() != nil {
   196  				base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
   197  				return nil
   198  			}
   199  			t = t.Elem()
   200  		}
   201  
   202  		switch {
   203  		case t == nil || t.Broke():
   204  			// rely on typecheck having complained before
   205  		case t.Sym() == nil:
   206  			base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
   207  		case t.IsPtr():
   208  			base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
   209  		case t.IsInterface():
   210  			base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
   211  		default:
   212  			// Should have picked off all the reasons above,
   213  			// but just in case, fall back to generic error.
   214  			base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
   215  		}
   216  		return nil
   217  	}
   218  
   219  	if local && mt.Sym().Pkg != types.LocalPkg {
   220  		base.Errorf("cannot define new methods on non-local type %v", mt)
   221  		return nil
   222  	}
   223  
   224  	if msym.IsBlank() {
   225  		return nil
   226  	}
   227  
   228  	if mt.IsStruct() {
   229  		for _, f := range mt.Fields().Slice() {
   230  			if f.Sym == msym {
   231  				base.Errorf("type %v has both field and method named %v", mt, msym)
   232  				f.SetBroke(true)
   233  				return nil
   234  			}
   235  		}
   236  	}
   237  
   238  	for _, f := range mt.Methods().Slice() {
   239  		if msym.Name != f.Sym.Name {
   240  			continue
   241  		}
   242  		// types.Identical only checks that incoming and result parameters match,
   243  		// so explicitly check that the receiver parameters match too.
   244  		if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
   245  			base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
   246  		}
   247  		return f
   248  	}
   249  
   250  	f := types.NewField(base.Pos, msym, t)
   251  	f.Nname = n.Nname
   252  	f.SetNointerface(nointerface)
   253  
   254  	mt.Methods().Append(f)
   255  	return f
   256  }
   257  
   258  func autoexport(n *ir.Name, ctxt ir.Class) {
   259  	if n.Sym().Pkg != types.LocalPkg {
   260  		return
   261  	}
   262  	if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || DeclContext != ir.PEXTERN {
   263  		return
   264  	}
   265  	if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) {
   266  		return
   267  	}
   268  
   269  	if types.IsExported(n.Sym().Name) || n.Sym().Name == "init" {
   270  		Export(n)
   271  	}
   272  	if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
   273  		n.Sym().SetAsm(true)
   274  		Target.Asms = append(Target.Asms, n)
   275  	}
   276  }
   277  
   278  // checkdupfields emits errors for duplicately named fields or methods in
   279  // a list of struct or interface types.
   280  func checkdupfields(what string, fss ...[]*types.Field) {
   281  	seen := make(map[*types.Sym]bool)
   282  	for _, fs := range fss {
   283  		for _, f := range fs {
   284  			if f.Sym == nil || f.Sym.IsBlank() {
   285  				continue
   286  			}
   287  			if seen[f.Sym] {
   288  				base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
   289  				continue
   290  			}
   291  			seen[f.Sym] = true
   292  		}
   293  	}
   294  }
   295  
   296  // structs, functions, and methods.
   297  // they don't belong here, but where do they belong?
   298  func checkembeddedtype(t *types.Type) {
   299  	if t == nil {
   300  		return
   301  	}
   302  
   303  	if t.Sym() == nil && t.IsPtr() {
   304  		t = t.Elem()
   305  		if t.IsInterface() {
   306  			base.Errorf("embedded type cannot be a pointer to interface")
   307  		}
   308  	}
   309  
   310  	if t.IsPtr() || t.IsUnsafePtr() {
   311  		base.Errorf("embedded type cannot be a pointer")
   312  	} else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
   313  		t.ForwardType().Embedlineno = base.Pos
   314  	}
   315  }
   316  
   317  var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext
   318  
   319  type funcStackEnt struct {
   320  	curfn      *ir.Func
   321  	dclcontext ir.Class
   322  }
   323  
   324  func funcarg(n *ir.Field, ctxt ir.Class) {
   325  	if n.Sym == nil {
   326  		return
   327  	}
   328  
   329  	name := ir.NewNameAt(n.Pos, n.Sym)
   330  	n.Decl = name
   331  	name.Ntype = n.Ntype
   332  	Declare(name, ctxt)
   333  }
   334  
   335  func funcarg2(f *types.Field, ctxt ir.Class) {
   336  	if f.Sym == nil {
   337  		return
   338  	}
   339  	n := ir.NewNameAt(f.Pos, f.Sym)
   340  	f.Nname = n
   341  	n.SetType(f.Type)
   342  	Declare(n, ctxt)
   343  }
   344  
   345  func funcargs(nt *ir.FuncType) {
   346  	if nt.Op() != ir.OTFUNC {
   347  		base.Fatalf("funcargs %v", nt.Op())
   348  	}
   349  
   350  	// declare the receiver and in arguments.
   351  	if nt.Recv != nil {
   352  		funcarg(nt.Recv, ir.PPARAM)
   353  	}
   354  	for _, n := range nt.Params {
   355  		funcarg(n, ir.PPARAM)
   356  	}
   357  
   358  	// declare the out arguments.
   359  	for i, n := range nt.Results {
   360  		if n.Sym == nil {
   361  			// Name so that escape analysis can track it. ~r stands for 'result'.
   362  			n.Sym = LookupNum("~r", i)
   363  		} else if n.Sym.IsBlank() {
   364  			// Give it a name so we can assign to it during return. ~b stands for 'blank'.
   365  			// The name must be different from ~r above because if you have
   366  			//	func f() (_ int)
   367  			//	func g() int
   368  			// f is allowed to use a plain 'return' with no arguments, while g is not.
   369  			// So the two cases must be distinguished.
   370  			n.Sym = LookupNum("~b", i)
   371  		}
   372  
   373  		funcarg(n, ir.PPARAMOUT)
   374  	}
   375  }
   376  
   377  // Same as funcargs, except run over an already constructed TFUNC.
   378  // This happens during import, where the hidden_fndcl rule has
   379  // used functype directly to parse the function's type.
   380  func funcargs2(t *types.Type) {
   381  	if t.Kind() != types.TFUNC {
   382  		base.Fatalf("funcargs2 %v", t)
   383  	}
   384  
   385  	for _, f := range t.Recvs().Fields().Slice() {
   386  		funcarg2(f, ir.PPARAM)
   387  	}
   388  	for _, f := range t.Params().Fields().Slice() {
   389  		funcarg2(f, ir.PPARAM)
   390  	}
   391  	for _, f := range t.Results().Fields().Slice() {
   392  		funcarg2(f, ir.PPARAMOUT)
   393  	}
   394  }
   395  
   396  func Temp(t *types.Type) *ir.Name {
   397  	return TempAt(base.Pos, ir.CurFunc, t)
   398  }
   399  
   400  // make a new Node off the books
   401  func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
   402  	if curfn == nil {
   403  		base.Fatalf("no curfn for TempAt")
   404  	}
   405  	if curfn.Op() == ir.OCLOSURE {
   406  		ir.Dump("TempAt", curfn)
   407  		base.Fatalf("adding TempAt to wrong closure function")
   408  	}
   409  	if t == nil {
   410  		base.Fatalf("TempAt called with nil type")
   411  	}
   412  	if t.Kind() == types.TFUNC && t.Recv() != nil {
   413  		base.Fatalf("misuse of method type: %v", t)
   414  	}
   415  
   416  	s := &types.Sym{
   417  		Name: autotmpname(len(curfn.Dcl)),
   418  		Pkg:  types.LocalPkg,
   419  	}
   420  	n := ir.NewNameAt(pos, s)
   421  	s.Def = n
   422  	n.SetType(t)
   423  	n.SetTypecheck(1)
   424  	n.Class = ir.PAUTO
   425  	n.SetEsc(ir.EscNever)
   426  	n.Curfn = curfn
   427  	n.SetUsed(true)
   428  	n.SetAutoTemp(true)
   429  	curfn.Dcl = append(curfn.Dcl, n)
   430  
   431  	types.CalcSize(t)
   432  
   433  	return n
   434  }
   435  
   436  var (
   437  	autotmpnamesmu sync.Mutex
   438  	autotmpnames   []string
   439  )
   440  
   441  // autotmpname returns the name for an autotmp variable numbered n.
   442  func autotmpname(n int) string {
   443  	autotmpnamesmu.Lock()
   444  	defer autotmpnamesmu.Unlock()
   445  
   446  	// Grow autotmpnames, if needed.
   447  	if n >= len(autotmpnames) {
   448  		autotmpnames = append(autotmpnames, make([]string, n+1-len(autotmpnames))...)
   449  		autotmpnames = autotmpnames[:cap(autotmpnames)]
   450  	}
   451  
   452  	s := autotmpnames[n]
   453  	if s == "" {
   454  		// Give each tmp a different name so that they can be registerized.
   455  		// Add a preceding . to avoid clashing with legal names.
   456  		prefix := ".autotmp_%d"
   457  
   458  		// In quirks mode, pad out the number to stabilize variable
   459  		// sorting. This ensures autotmps 8 and 9 sort the same way even
   460  		// if they get renumbered to 9 and 10, respectively.
   461  		if base.Debug.UnifiedQuirks != 0 {
   462  			prefix = ".autotmp_%06d"
   463  		}
   464  
   465  		s = fmt.Sprintf(prefix, n)
   466  		autotmpnames[n] = s
   467  	}
   468  	return s
   469  }
   470  
   471  // f is method type, with receiver.
   472  // return function type, receiver as first argument (or not).
   473  func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
   474  	if sig.HasTParam() {
   475  		base.Fatalf("NewMethodType with type parameters in signature %+v", sig)
   476  	}
   477  	if recv != nil && recv.HasTParam() {
   478  		base.Fatalf("NewMethodType with type parameters in receiver %+v", recv)
   479  	}
   480  	nrecvs := 0
   481  	if recv != nil {
   482  		nrecvs++
   483  	}
   484  
   485  	// TODO(mdempsky): Move this function to types.
   486  	// TODO(mdempsky): Preserve positions, names, and package from sig+recv.
   487  
   488  	params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
   489  	if recv != nil {
   490  		params[0] = types.NewField(base.Pos, nil, recv)
   491  	}
   492  	for i, param := range sig.Params().Fields().Slice() {
   493  		d := types.NewField(base.Pos, nil, param.Type)
   494  		d.SetIsDDD(param.IsDDD())
   495  		params[nrecvs+i] = d
   496  	}
   497  
   498  	results := make([]*types.Field, sig.Results().Fields().Len())
   499  	for i, t := range sig.Results().Fields().Slice() {
   500  		results[i] = types.NewField(base.Pos, nil, t.Type)
   501  	}
   502  
   503  	return types.NewSignature(types.LocalPkg, nil, nil, params, results)
   504  }
   505  

View as plain text