aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/dcl.go
blob: 1c23c5a92f635efa0523728b7a5347784adbcb55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gc

import (
	"bytes"
	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/src"
	"fmt"
	"strings"
)

// Declaration stack & operations

var externdcl []ir.Node

func testdclstack() {
	if !types.IsDclstackValid() {
		base.Fatalf("mark left on the dclstack")
	}
}

// redeclare emits a diagnostic about symbol s being redeclared at pos.
func redeclare(pos src.XPos, s *types.Sym, where string) {
	if !s.Lastlineno.IsKnown() {
		pkg := s.Origpkg
		if pkg == nil {
			pkg = s.Pkg
		}
		base.ErrorfAt(pos, "%v redeclared %s\n"+
			"\tprevious declaration during import %q", s, where, pkg.Path)
	} else {
		prevPos := s.Lastlineno

		// When an import and a declaration collide in separate files,
		// present the import as the "redeclared", because the declaration
		// is visible where the import is, but not vice versa.
		// See issue 4510.
		if s.Def == nil {
			pos, prevPos = prevPos, pos
		}

		base.ErrorfAt(pos, "%v redeclared %s\n"+
			"\tprevious declaration at %v", s, where, base.FmtPos(prevPos))
	}
}

var vargen int

// declare individual names - var, typ, const

var declare_typegen int

// declare records that Node n declares symbol n.Sym in the specified
// declaration context.
func declare(n *ir.Name, ctxt ir.Class) {
	if ir.IsBlank(n) {
		return
	}

	s := n.Sym()

	// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
	if !inimport && !typecheckok && s.Pkg != types.LocalPkg {
		base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
	}

	gen := 0
	if ctxt == ir.PEXTERN {
		if s.Name == "init" {
			base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
		}
		if s.Name == "main" && s.Pkg.Name == "main" {
			base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
		}
		externdcl = append(externdcl, n)
	} else {
		if Curfn == nil && ctxt == ir.PAUTO {
			base.Pos = n.Pos()
			base.Fatalf("automatic outside function")
		}
		if Curfn != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
			Curfn.Dcl = append(Curfn.Dcl, n)
		}
		if n.Op() == ir.OTYPE {
			declare_typegen++
			gen = declare_typegen
		} else if n.Op() == ir.ONAME && ctxt == ir.PAUTO && !strings.Contains(s.Name, "·") {
			vargen++
			gen = vargen
		}
		types.Pushdcl(s)
		n.Curfn = Curfn
	}

	if ctxt == ir.PAUTO {
		n.SetOffset(0)
	}

	if s.Block == types.Block {
		// functype will print errors about duplicate function arguments.
		// Don't repeat the error here.
		if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
			redeclare(n.Pos(), s, "in this block")
		}
	}

	s.Block = types.Block
	s.Lastlineno = base.Pos
	s.Def = n
	n.Vargen = int32(gen)
	n.SetClass(ctxt)
	if ctxt == ir.PFUNC {
		n.Sym().SetFunc(true)
	}

	autoexport(n, ctxt)
}

// declare variables from grammar
// new_name_list (type | [type] = expr_list)
func variter(vl []ir.Node, t ir.Ntype, el []ir.Node) []ir.Node {
	var init []ir.Node
	doexpr := len(el) > 0

	if len(el) == 1 && len(vl) > 1 {
		e := el[0]
		as2 := ir.Nod(ir.OAS2, nil, nil)
		as2.PtrList().Set(vl)
		as2.PtrRlist().Set1(e)
		for _, v := range vl {
			v := v.(*ir.Name)
			v.SetOp(ir.ONAME)
			declare(v, dclcontext)
			v.Ntype = t
			v.Defn = as2
			if Curfn != nil {
				init = append(init, ir.Nod(ir.ODCL, v, nil))
			}
		}

		return append(init, as2)
	}

	nel := len(el)
	for _, v := range vl {
		v := v.(*ir.Name)
		var e ir.Node
		if doexpr {
			if len(el) == 0 {
				base.Errorf("assignment mismatch: %d variables but %d values", len(vl), nel)
				break
			}
			e = el[0]
			el = el[1:]
		}

		v.SetOp(ir.ONAME)
		declare(v, dclcontext)
		v.Ntype = t

		if e != nil || Curfn != nil || ir.IsBlank(v) {
			if Curfn != nil {
				init = append(init, ir.Nod(ir.ODCL, v, nil))
			}
			e = ir.Nod(ir.OAS, v, e)
			init = append(init, e)
			if e.Right() != nil {
				v.Defn = e
			}
		}
	}

	if len(el) != 0 {
		base.Errorf("assignment mismatch: %d variables but %d values", len(vl), nel)
	}
	return init
}

// newFuncNameAt generates a new name node for a function or method.
func newFuncNameAt(pos src.XPos, s *types.Sym, fn *ir.Func) *ir.Name {
	if fn.Nname != nil {
		base.Fatalf("newFuncName - already have name")
	}
	n := ir.NewNameAt(pos, s)
	n.SetFunc(fn)
	fn.Nname = n
	return n
}

func anonfield(typ *types.Type) *ir.Field {
	return symfield(nil, typ)
}

func namedfield(s string, typ *types.Type) *ir.Field {
	return symfield(lookup(s), typ)
}

func symfield(s *types.Sym, typ *types.Type) *ir.Field {
	return ir.NewField(base.Pos, s, nil, typ)
}

// oldname returns the Node that declares symbol s in the current scope.
// If no such Node currently exists, an ONONAME Node is returned instead.
// Automatically creates a new closure variable if the referenced symbol was
// declared in a different (containing) function.
func oldname(s *types.Sym) ir.Node {
	n := ir.AsNode(s.Def)
	if n == nil {
		// Maybe a top-level declaration will come along later to
		// define s. resolve will check s.Def again once all input
		// source has been processed.
		return ir.NewDeclNameAt(base.Pos, s)
	}

	if Curfn != nil && n.Op() == ir.ONAME && n.Name().Curfn != nil && n.Name().Curfn != Curfn {
		// Inner func is referring to var in outer func.
		//
		// TODO(rsc): If there is an outer variable x and we
		// are parsing x := 5 inside the closure, until we get to
		// the := it looks like a reference to the outer x so we'll
		// make x a closure variable unnecessarily.
		c := n.Name().Innermost
		if c == nil || c.Curfn != Curfn {
			// Do not have a closure var for the active closure yet; make one.
			c = NewName(s)
			c.SetClass(ir.PAUTOHEAP)
			c.SetIsClosureVar(true)
			c.SetIsDDD(n.IsDDD())
			c.Defn = n

			// Link into list of active closure variables.
			// Popped from list in func funcLit.
			c.Outer = n.Name().Innermost
			n.Name().Innermost = c

			Curfn.ClosureVars = append(Curfn.ClosureVars, c)
		}

		// return ref to closure var, not original
		return c
	}

	return n
}

// importName is like oldname,
// but it reports an error if sym is from another package and not exported.
func importName(sym *types.Sym) ir.Node {
	n := oldname(sym)
	if !types.IsExported(sym.Name) && sym.Pkg != types.LocalPkg {
		n.SetDiag(true)
		base.Errorf("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name)
	}
	return n
}

// := declarations
func colasname(n ir.Node) bool {
	switch n.Op() {
	case ir.ONAME,
		ir.ONONAME,
		ir.OPACK,
		ir.OTYPE,
		ir.OLITERAL:
		return n.Sym() != nil
	}

	return false
}

func colasdefn(left []ir.Node, defn ir.Node) {
	for _, n := range left {
		if n.Sym() != nil {
			n.Sym().SetUniq(true)
		}
	}

	var nnew, nerr int
	for i, n := range left {
		if ir.IsBlank(n) {
			continue
		}
		if !colasname(n) {
			base.ErrorfAt(defn.Pos(), "non-name %v on left side of :=", n)
			nerr++
			continue
		}

		if !n.Sym().Uniq() {
			base.ErrorfAt(defn.Pos(), "%v repeated on left side of :=", n.Sym())
			n.SetDiag(true)
			nerr++
			continue
		}

		n.Sym().SetUniq(false)
		if n.Sym().Block == types.Block {
			continue
		}

		nnew++
		n := NewName(n.Sym())
		declare(n, dclcontext)
		n.Defn = defn
		defn.PtrInit().Append(ir.Nod(ir.ODCL, n, nil))
		left[i] = n
	}

	if nnew == 0 && nerr == 0 {
		base.ErrorfAt(defn.Pos(), "no new variables on left side of :=")
	}
}

// declare the function proper
// and declare the arguments.
// called in extern-declaration context
// returns in auto-declaration context.
func funchdr(fn *ir.Func) {
	// change the declaration context from extern to auto
	funcStack = append(funcStack, funcStackEnt{Curfn, dclcontext})
	Curfn = fn
	dclcontext = ir.PAUTO

	types.Markdcl()

	if fn.Nname.Ntype != nil {
		funcargs(fn.Nname.Ntype.(*ir.FuncType))
	} else {
		funcargs2(fn.Type())
	}
}

func funcargs(nt *ir.FuncType) {
	if nt.Op() != ir.OTFUNC {
		base.Fatalf("funcargs %v", nt.Op())
	}

	// re-start the variable generation number
	// we want to use small numbers for the return variables,
	// so let them have the chunk starting at 1.
	//
	// TODO(mdempsky): This is ugly, and only necessary because
	// esc.go uses Vargen to figure out result parameters' index
	// within the result tuple.
	vargen = len(nt.Results)

	// declare the receiver and in arguments.
	if nt.Recv != nil {
		funcarg(nt.Recv, ir.PPARAM)
	}
	for _, n := range nt.Params {
		funcarg(n, ir.PPARAM)
	}

	oldvargen := vargen
	vargen = 0

	// declare the out arguments.
	gen := len(nt.Params)
	for _, n := range nt.Results {
		if n.Sym == nil {
			// Name so that escape analysis can track it. ~r stands for 'result'.
			n.Sym = lookupN("~r", gen)
			gen++
		}
		if n.Sym.IsBlank() {
			// Give it a name so we can assign to it during return. ~b stands for 'blank'.
			// The name must be different from ~r above because if you have
			//	func f() (_ int)
			//	func g() int
			// f is allowed to use a plain 'return' with no arguments, while g is not.
			// So the two cases must be distinguished.
			n.Sym = lookupN("~b", gen)
			gen++
		}

		funcarg(n, ir.PPARAMOUT)
	}

	vargen = oldvargen
}

func funcarg(n *ir.Field, ctxt ir.Class) {
	if n.Sym == nil {
		return
	}

	name := ir.NewNameAt(n.Pos, n.Sym)
	n.Decl = name
	name.Ntype = n.Ntype
	name.SetIsDDD(n.IsDDD)
	declare(name, ctxt)

	vargen++
	n.Decl.Vargen = int32(vargen)
}

// Same as funcargs, except run over an already constructed TFUNC.
// This happens during import, where the hidden_fndcl rule has
// used functype directly to parse the function's type.
func funcargs2(t *types.Type) {
	if t.Kind() != types.TFUNC {
		base.Fatalf("funcargs2 %v", t)
	}

	for _, f := range t.Recvs().Fields().Slice() {
		funcarg2(f, ir.PPARAM)
	}
	for _, f := range t.Params().Fields().Slice() {
		funcarg2(f, ir.PPARAM)
	}
	for _, f := range t.Results().Fields().Slice() {
		funcarg2(f, ir.PPARAMOUT)
	}
}

func funcarg2(f *types.Field, ctxt ir.Class) {
	if f.Sym == nil {
		return
	}
	n := ir.NewNameAt(f.Pos, f.Sym)
	f.Nname = n
	n.SetType(f.Type)
	n.SetIsDDD(f.IsDDD())
	declare(n, ctxt)
}

var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext

type funcStackEnt struct {
	curfn      *ir.Func
	dclcontext ir.Class
}

// finish the body.
// called in auto-declaration context.
// returns in extern-declaration context.
func funcbody() {
	// change the declaration context from auto to previous context
	types.Popdcl()
	var e funcStackEnt
	funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
	Curfn, dclcontext = e.curfn, e.dclcontext
}

// structs, functions, and methods.
// they don't belong here, but where do they belong?
func checkembeddedtype(t *types.Type) {
	if t == nil {
		return
	}

	if t.Sym() == nil && t.IsPtr() {
		t = t.Elem()
		if t.IsInterface() {
			base.Errorf("embedded type cannot be a pointer to interface")
		}
	}

	if t.IsPtr() || t.IsUnsafePtr() {
		base.Errorf("embedded type cannot be a pointer")
	} else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
		t.ForwardType().Embedlineno = base.Pos
	}
}

// checkdupfields emits errors for duplicately named fields or methods in
// a list of struct or interface types.
func checkdupfields(what string, fss ...[]*types.Field) {
	seen := make(map[*types.Sym]bool)
	for _, fs := range fss {
		for _, f := range fs {
			if f.Sym == nil || f.Sym.IsBlank() {
				continue
			}
			if seen[f.Sym] {
				base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
				continue
			}
			seen[f.Sym] = true
		}
	}
}

// convert a parsed id/type list into
// a type for struct/interface/arglist
func tostruct(l []*ir.Field) *types.Type {
	lno := base.Pos

	fields := make([]*types.Field, len(l))
	for i, n := range l {
		base.Pos = n.Pos

		if n.Ntype != nil {
			n.Type = typecheckNtype(n.Ntype).Type()
			n.Ntype = nil
		}
		f := types.NewField(n.Pos, n.Sym, n.Type)
		if n.Embedded {
			checkembeddedtype(n.Type)
			f.Embedded = 1
		}
		f.Note = n.Note
		fields[i] = f
	}
	checkdupfields("field", fields)

	base.Pos = lno
	return types.NewStruct(types.LocalPkg, fields)
}

func tointerface(nmethods []*ir.Field) *types.Type {
	if len(nmethods) == 0 {
		return types.Types[types.TINTER]
	}

	lno := base.Pos

	methods := make([]*types.Field, len(nmethods))
	for i, n := range nmethods {
		base.Pos = n.Pos
		if n.Ntype != nil {
			n.Type = typecheckNtype(n.Ntype).Type()
			n.Ntype = nil
		}
		methods[i] = types.NewField(n.Pos, n.Sym, n.Type)
	}

	base.Pos = lno
	return types.NewInterface(types.LocalPkg, methods)
}

func fakeRecv() *ir.Field {
	return anonfield(types.FakeRecvType())
}

func fakeRecvField() *types.Field {
	return types.NewField(src.NoXPos, nil, types.FakeRecvType())
}

// isifacemethod reports whether (field) m is
// an interface method. Such methods have the
// special receiver type types.FakeRecvType().
func isifacemethod(f *types.Type) bool {
	return f.Recv().Type == types.FakeRecvType()
}

// turn a parsed function declaration into a type
func functype(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
	funarg := func(n *ir.Field) *types.Field {
		lno := base.Pos
		base.Pos = n.Pos

		if n.Ntype != nil {
			n.Type = typecheckNtype(n.Ntype).Type()
			n.Ntype = nil
		}

		f := types.NewField(n.Pos, n.Sym, n.Type)
		f.SetIsDDD(n.IsDDD)
		if n.Decl != nil {
			n.Decl.SetType(f.Type)
			f.Nname = n.Decl
		}

		base.Pos = lno
		return f
	}
	funargs := func(nn []*ir.Field) []*types.Field {
		res := make([]*types.Field, len(nn))
		for i, n := range nn {
			res[i] = funarg(n)
		}
		return res
	}

	var recv *types.Field
	if nrecv != nil {
		recv = funarg(nrecv)
	}

	t := types.NewSignature(types.LocalPkg, recv, funargs(nparams), funargs(nresults))
	checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
	return t
}

func hasNamedResults(fn *ir.Func) bool {
	typ := fn.Type()
	return typ.NumResults() > 0 && types.OrigSym(typ.Results().Field(0).Sym) != nil
}

// methodSym returns the method symbol representing a method name
// associated with a specific receiver type.
//
// Method symbols can be used to distinguish the same method appearing
// in different method sets. For example, T.M and (*T).M have distinct
// method symbols.
//
// The returned symbol will be marked as a function.
func methodSym(recv *types.Type, msym *types.Sym) *types.Sym {
	sym := methodSymSuffix(recv, msym, "")
	sym.SetFunc(true)
	return sym
}

// methodSymSuffix is like methodsym, but allows attaching a
// distinguisher suffix. To avoid collisions, the suffix must not
// start with a letter, number, or period.
func methodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sym {
	if msym.IsBlank() {
		base.Fatalf("blank method name")
	}

	rsym := recv.Sym()
	if recv.IsPtr() {
		if rsym != nil {
			base.Fatalf("declared pointer receiver type: %v", recv)
		}
		rsym = recv.Elem().Sym()
	}

	// Find the package the receiver type appeared in. For
	// anonymous receiver types (i.e., anonymous structs with
	// embedded fields), use the "go" pseudo-package instead.
	rpkg := gopkg
	if rsym != nil {
		rpkg = rsym.Pkg
	}

	var b bytes.Buffer
	if recv.IsPtr() {
		// The parentheses aren't really necessary, but
		// they're pretty traditional at this point.
		fmt.Fprintf(&b, "(%-S)", recv)
	} else {
		fmt.Fprintf(&b, "%-S", recv)
	}

	// A particular receiver type may have multiple non-exported
	// methods with the same name. To disambiguate them, include a
	// package qualifier for names that came from a different
	// package than the receiver type.
	if !types.IsExported(msym.Name) && msym.Pkg != rpkg {
		b.WriteString(".")
		b.WriteString(msym.Pkg.Prefix)
	}

	b.WriteString(".")
	b.WriteString(msym.Name)
	b.WriteString(suffix)

	return rpkg.LookupBytes(b.Bytes())
}

// Add a method, declared as a function.
// - msym is the method symbol
// - t is function type (with receiver)
// Returns a pointer to the existing or added Field; or nil if there's an error.
func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
	if msym == nil {
		base.Fatalf("no method symbol")
	}

	// get parent type sym
	rf := t.Recv() // ptr to this structure
	if rf == nil {
		base.Errorf("missing receiver")
		return nil
	}

	mt := methtype(rf.Type)
	if mt == nil || mt.Sym() == nil {
		pa := rf.Type
		t := pa
		if t != nil && t.IsPtr() {
			if t.Sym() != nil {
				base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
				return nil
			}
			t = t.Elem()
		}

		switch {
		case t == nil || t.Broke():
			// rely on typecheck having complained before
		case t.Sym() == nil:
			base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
		case t.IsPtr():
			base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
		case t.IsInterface():
			base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
		default:
			// Should have picked off all the reasons above,
			// but just in case, fall back to generic error.
			base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
		}
		return nil
	}

	if local && mt.Sym().Pkg != types.LocalPkg {
		base.Errorf("cannot define new methods on non-local type %v", mt)
		return nil
	}

	if msym.IsBlank() {
		return nil
	}

	if mt.IsStruct() {
		for _, f := range mt.Fields().Slice() {
			if f.Sym == msym {
				base.Errorf("type %v has both field and method named %v", mt, msym)
				f.SetBroke(true)
				return nil
			}
		}
	}

	for _, f := range mt.Methods().Slice() {
		if msym.Name != f.Sym.Name {
			continue
		}
		// types.Identical only checks that incoming and result parameters match,
		// so explicitly check that the receiver parameters match too.
		if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
			base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
		}
		return f
	}

	f := types.NewField(base.Pos, msym, t)
	f.Nname = n.Nname
	f.SetNointerface(nointerface)

	mt.Methods().Append(f)
	return f
}

func funcsymname(s *types.Sym) string {
	return s.Name + "·f"
}

// funcsym returns s·f.
func funcsym(s *types.Sym) *types.Sym {
	// funcsymsmu here serves to protect not just mutations of funcsyms (below),
	// but also the package lookup of the func sym name,
	// since this function gets called concurrently from the backend.
	// There are no other concurrent package lookups in the backend,
	// except for the types package, which is protected separately.
	// Reusing funcsymsmu to also cover this package lookup
	// avoids a general, broader, expensive package lookup mutex.
	// Note makefuncsym also does package look-up of func sym names,
	// but that it is only called serially, from the front end.
	funcsymsmu.Lock()
	sf, existed := s.Pkg.LookupOK(funcsymname(s))
	// Don't export s·f when compiling for dynamic linking.
	// When dynamically linking, the necessary function
	// symbols will be created explicitly with makefuncsym.
	// See the makefuncsym comment for details.
	if !base.Ctxt.Flag_dynlink && !existed {
		funcsyms = append(funcsyms, s)
	}
	funcsymsmu.Unlock()
	return sf
}

// makefuncsym ensures that s·f is exported.
// It is only used with -dynlink.
// When not compiling for dynamic linking,
// the funcsyms are created as needed by
// the packages that use them.
// Normally we emit the s·f stubs as DUPOK syms,
// but DUPOK doesn't work across shared library boundaries.
// So instead, when dynamic linking, we only create
// the s·f stubs in s's package.
func makefuncsym(s *types.Sym) {
	if !base.Ctxt.Flag_dynlink {
		base.Fatalf("makefuncsym dynlink")
	}
	if s.IsBlank() {
		return
	}
	if base.Flag.CompilingRuntime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") {
		// runtime.getg(), getclosureptr(), getcallerpc(), and
		// getcallersp() are not real functions and so do not
		// get funcsyms.
		return
	}
	if _, existed := s.Pkg.LookupOK(funcsymname(s)); !existed {
		funcsyms = append(funcsyms, s)
	}
}

// setNodeNameFunc marks a node as a function.
func setNodeNameFunc(n ir.Node) {
	if n.Op() != ir.ONAME || n.Class() != ir.Pxxx {
		base.Fatalf("expected ONAME/Pxxx node, got %v", n)
	}

	n.SetClass(ir.PFUNC)
	n.Sym().SetFunc(true)
}

func dclfunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
	if tfn.Op() != ir.OTFUNC {
		base.Fatalf("expected OTFUNC node, got %v", tfn)
	}

	fn := ir.NewFunc(base.Pos)
	fn.Nname = newFuncNameAt(base.Pos, sym, fn)
	fn.Nname.Defn = fn
	fn.Nname.Ntype = tfn
	setNodeNameFunc(fn.Nname)
	funchdr(fn)
	fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
	return fn
}

type nowritebarrierrecChecker struct {
	// extraCalls contains extra function calls that may not be
	// visible during later analysis. It maps from the ODCLFUNC of
	// the caller to a list of callees.
	extraCalls map[*ir.Func][]nowritebarrierrecCall

	// curfn is the current function during AST walks.
	curfn *ir.Func
}

type nowritebarrierrecCall struct {
	target *ir.Func // caller or callee
	lineno src.XPos // line of call
}

// newNowritebarrierrecChecker creates a nowritebarrierrecChecker. It
// must be called before transformclosure and walk.
func newNowritebarrierrecChecker() *nowritebarrierrecChecker {
	c := &nowritebarrierrecChecker{
		extraCalls: make(map[*ir.Func][]nowritebarrierrecCall),
	}

	// Find all systemstack calls and record their targets. In
	// general, flow analysis can't see into systemstack, but it's
	// important to handle it for this check, so we model it
	// directly. This has to happen before transformclosure since
	// it's a lot harder to work out the argument after.
	for _, n := range xtop {
		if n.Op() != ir.ODCLFUNC {
			continue
		}
		c.curfn = n.(*ir.Func)
		ir.Inspect(n, c.findExtraCalls)
	}
	c.curfn = nil
	return c
}

func (c *nowritebarrierrecChecker) findExtraCalls(n ir.Node) bool {
	if n.Op() != ir.OCALLFUNC {
		return true
	}
	fn := n.Left()
	if fn == nil || fn.Op() != ir.ONAME || fn.Class() != ir.PFUNC || fn.Name().Defn == nil {
		return true
	}
	if !isRuntimePkg(fn.Sym().Pkg) || fn.Sym().Name != "systemstack" {
		return true
	}

	var callee *ir.Func
	arg := n.List().First()
	switch arg.Op() {
	case ir.ONAME:
		callee = arg.Name().Defn.(*ir.Func)
	case ir.OCLOSURE:
		callee = arg.Func()
	default:
		base.Fatalf("expected ONAME or OCLOSURE node, got %+v", arg)
	}
	if callee.Op() != ir.ODCLFUNC {
		base.Fatalf("expected ODCLFUNC node, got %+v", callee)
	}
	c.extraCalls[c.curfn] = append(c.extraCalls[c.curfn], nowritebarrierrecCall{callee, n.Pos()})
	return true
}

// recordCall records a call from ODCLFUNC node "from", to function
// symbol "to" at position pos.
//
// This should be done as late as possible during compilation to
// capture precise call graphs. The target of the call is an LSym
// because that's all we know after we start SSA.
//
// This can be called concurrently for different from Nodes.
func (c *nowritebarrierrecChecker) recordCall(fn *ir.Func, to *obj.LSym, pos src.XPos) {
	// We record this information on the *Func so this is concurrent-safe.
	if fn.NWBRCalls == nil {
		fn.NWBRCalls = new([]ir.SymAndPos)
	}
	*fn.NWBRCalls = append(*fn.NWBRCalls, ir.SymAndPos{Sym: to, Pos: pos})
}

func (c *nowritebarrierrecChecker) check() {
	// We walk the call graph as late as possible so we can
	// capture all calls created by lowering, but this means we
	// only get to see the obj.LSyms of calls. symToFunc lets us
	// get back to the ODCLFUNCs.
	symToFunc := make(map[*obj.LSym]*ir.Func)
	// funcs records the back-edges of the BFS call graph walk. It
	// maps from the ODCLFUNC of each function that must not have
	// write barriers to the call that inhibits them. Functions
	// that are directly marked go:nowritebarrierrec are in this
	// map with a zero-valued nowritebarrierrecCall. This also
	// acts as the set of marks for the BFS of the call graph.
	funcs := make(map[*ir.Func]nowritebarrierrecCall)
	// q is the queue of ODCLFUNC Nodes to visit in BFS order.
	var q ir.NameQueue

	for _, n := range xtop {
		if n.Op() != ir.ODCLFUNC {
			continue
		}
		fn := n.(*ir.Func)

		symToFunc[fn.LSym] = fn

		// Make nowritebarrierrec functions BFS roots.
		if fn.Pragma&ir.Nowritebarrierrec != 0 {
			funcs[fn] = nowritebarrierrecCall{}
			q.PushRight(fn.Nname)
		}
		// Check go:nowritebarrier functions.
		if fn.Pragma&ir.Nowritebarrier != 0 && fn.WBPos.IsKnown() {
			base.ErrorfAt(fn.WBPos, "write barrier prohibited")
		}
	}

	// Perform a BFS of the call graph from all
	// go:nowritebarrierrec functions.
	enqueue := func(src, target *ir.Func, pos src.XPos) {
		if target.Pragma&ir.Yeswritebarrierrec != 0 {
			// Don't flow into this function.
			return
		}
		if _, ok := funcs[target]; ok {
			// Already found a path to target.
			return
		}

		// Record the path.
		funcs[target] = nowritebarrierrecCall{target: src, lineno: pos}
		q.PushRight(target.Nname)
	}
	for !q.Empty() {
		fn := q.PopLeft().Func()

		// Check fn.
		if fn.WBPos.IsKnown() {
			var err bytes.Buffer
			call := funcs[fn]
			for call.target != nil {
				fmt.Fprintf(&err, "\n\t%v: called by %v", base.FmtPos(call.lineno), call.target.Nname)
				call = funcs[call.target]
			}
			base.ErrorfAt(fn.WBPos, "write barrier prohibited by caller; %v%s", fn.Nname, err.String())
			continue
		}

		// Enqueue fn's calls.
		for _, callee := range c.extraCalls[fn] {
			enqueue(fn, callee.target, callee.lineno)
		}
		if fn.NWBRCalls == nil {
			continue
		}
		for _, callee := range *fn.NWBRCalls {
			target := symToFunc[callee.Sym]
			if target != nil {
				enqueue(fn, target, callee.Pos)
			}
		}
	}
}