Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/compile/internal/typecheck

     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  	"strconv"
    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  // TODO(mdempsky): Move to package types.
   318  func FakeRecv() *types.Field {
   319  	return types.NewField(src.NoXPos, nil, types.FakeRecvType())
   320  }
   321  
   322  var fakeRecvField = FakeRecv
   323  
   324  var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext
   325  
   326  type funcStackEnt struct {
   327  	curfn      *ir.Func
   328  	dclcontext ir.Class
   329  }
   330  
   331  func funcarg(n *ir.Field, ctxt ir.Class) {
   332  	if n.Sym == nil {
   333  		return
   334  	}
   335  
   336  	name := ir.NewNameAt(n.Pos, n.Sym)
   337  	n.Decl = name
   338  	name.Ntype = n.Ntype
   339  	Declare(name, ctxt)
   340  }
   341  
   342  func funcarg2(f *types.Field, ctxt ir.Class) {
   343  	if f.Sym == nil {
   344  		return
   345  	}
   346  	n := ir.NewNameAt(f.Pos, f.Sym)
   347  	f.Nname = n
   348  	n.SetType(f.Type)
   349  	Declare(n, ctxt)
   350  }
   351  
   352  func funcargs(nt *ir.FuncType) {
   353  	if nt.Op() != ir.OTFUNC {
   354  		base.Fatalf("funcargs %v", nt.Op())
   355  	}
   356  
   357  	// declare the receiver and in arguments.
   358  	if nt.Recv != nil {
   359  		funcarg(nt.Recv, ir.PPARAM)
   360  	}
   361  	for _, n := range nt.Params {
   362  		funcarg(n, ir.PPARAM)
   363  	}
   364  
   365  	// declare the out arguments.
   366  	gen := len(nt.Params)
   367  	for _, n := range nt.Results {
   368  		if n.Sym == nil {
   369  			// Name so that escape analysis can track it. ~r stands for 'result'.
   370  			n.Sym = LookupNum("~r", gen)
   371  			gen++
   372  		}
   373  		if n.Sym.IsBlank() {
   374  			// Give it a name so we can assign to it during return. ~b stands for 'blank'.
   375  			// The name must be different from ~r above because if you have
   376  			//	func f() (_ int)
   377  			//	func g() int
   378  			// f is allowed to use a plain 'return' with no arguments, while g is not.
   379  			// So the two cases must be distinguished.
   380  			n.Sym = LookupNum("~b", gen)
   381  			gen++
   382  		}
   383  
   384  		funcarg(n, ir.PPARAMOUT)
   385  	}
   386  }
   387  
   388  // Same as funcargs, except run over an already constructed TFUNC.
   389  // This happens during import, where the hidden_fndcl rule has
   390  // used functype directly to parse the function's type.
   391  func funcargs2(t *types.Type) {
   392  	if t.Kind() != types.TFUNC {
   393  		base.Fatalf("funcargs2 %v", t)
   394  	}
   395  
   396  	for _, f := range t.Recvs().Fields().Slice() {
   397  		funcarg2(f, ir.PPARAM)
   398  	}
   399  	for _, f := range t.Params().Fields().Slice() {
   400  		funcarg2(f, ir.PPARAM)
   401  	}
   402  	for _, f := range t.Results().Fields().Slice() {
   403  		funcarg2(f, ir.PPARAMOUT)
   404  	}
   405  }
   406  
   407  func Temp(t *types.Type) *ir.Name {
   408  	return TempAt(base.Pos, ir.CurFunc, t)
   409  }
   410  
   411  // make a new Node off the books
   412  func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
   413  	if curfn == nil {
   414  		base.Fatalf("no curfn for TempAt")
   415  	}
   416  	if curfn.Op() == ir.OCLOSURE {
   417  		ir.Dump("TempAt", curfn)
   418  		base.Fatalf("adding TempAt to wrong closure function")
   419  	}
   420  	if t == nil {
   421  		base.Fatalf("TempAt called with nil type")
   422  	}
   423  	if t.Kind() == types.TFUNC && t.Recv() != nil {
   424  		base.Fatalf("misuse of method type: %v", t)
   425  	}
   426  
   427  	s := &types.Sym{
   428  		Name: autotmpname(len(curfn.Dcl)),
   429  		Pkg:  types.LocalPkg,
   430  	}
   431  	n := ir.NewNameAt(pos, s)
   432  	s.Def = n
   433  	n.SetType(t)
   434  	n.Class = ir.PAUTO
   435  	n.SetEsc(ir.EscNever)
   436  	n.Curfn = curfn
   437  	n.SetUsed(true)
   438  	n.SetAutoTemp(true)
   439  	curfn.Dcl = append(curfn.Dcl, n)
   440  
   441  	types.CalcSize(t)
   442  
   443  	return n
   444  }
   445  
   446  // autotmpname returns the name for an autotmp variable numbered n.
   447  func autotmpname(n int) string {
   448  	// Give each tmp a different name so that they can be registerized.
   449  	// Add a preceding . to avoid clashing with legal names.
   450  	const prefix = ".autotmp_"
   451  	// Start with a buffer big enough to hold a large n.
   452  	b := []byte(prefix + "      ")[:len(prefix)]
   453  	b = strconv.AppendInt(b, int64(n), 10)
   454  	return types.InternString(b)
   455  }
   456  
   457  // f is method type, with receiver.
   458  // return function type, receiver as first argument (or not).
   459  func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
   460  	nrecvs := 0
   461  	if recv != nil {
   462  		nrecvs++
   463  	}
   464  
   465  	// TODO(mdempsky): Move this function to types.
   466  	// TODO(mdempsky): Preserve positions, names, and package from sig+recv.
   467  
   468  	params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
   469  	if recv != nil {
   470  		params[0] = types.NewField(base.Pos, nil, recv)
   471  	}
   472  	for i, param := range sig.Params().Fields().Slice() {
   473  		d := types.NewField(base.Pos, nil, param.Type)
   474  		d.SetIsDDD(param.IsDDD())
   475  		params[nrecvs+i] = d
   476  	}
   477  
   478  	results := make([]*types.Field, sig.Results().Fields().Len())
   479  	for i, t := range sig.Results().Fields().Slice() {
   480  		results[i] = types.NewField(base.Pos, nil, t.Type)
   481  	}
   482  
   483  	return types.NewSignature(types.LocalPkg, nil, nil, params, results)
   484  }
   485  

View as plain text