1// UNREVIEWED
2
3// Copyright 2021 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7package noder
8
9import (
10	"cmd/compile/internal/base"
11	"cmd/compile/internal/syntax"
12	"cmd/compile/internal/types2"
13	"cmd/internal/src"
14)
15
16type pkgReader2 struct {
17	pkgDecoder
18
19	ctxt    *types2.Context
20	imports map[string]*types2.Package
21
22	posBases []*syntax.PosBase
23	pkgs     []*types2.Package
24	typs     []types2.Type
25}
26
27func readPackage2(ctxt *types2.Context, imports map[string]*types2.Package, input pkgDecoder) *types2.Package {
28	pr := pkgReader2{
29		pkgDecoder: input,
30
31		ctxt:    ctxt,
32		imports: imports,
33
34		posBases: make([]*syntax.PosBase, input.numElems(relocPosBase)),
35		pkgs:     make([]*types2.Package, input.numElems(relocPkg)),
36		typs:     make([]types2.Type, input.numElems(relocType)),
37	}
38
39	r := pr.newReader(relocMeta, publicRootIdx, syncPublic)
40	pkg := r.pkg()
41	r.bool() // has init
42
43	for i, n := 0, r.len(); i < n; i++ {
44		// As if r.obj(), but avoiding the Scope.Lookup call,
45		// to avoid eager loading of imports.
46		r.sync(syncObject)
47		assert(!r.bool())
48		r.p.objIdx(r.reloc(relocObj))
49		assert(r.len() == 0)
50	}
51
52	r.sync(syncEOF)
53
54	pkg.MarkComplete()
55	return pkg
56}
57
58type reader2 struct {
59	decoder
60
61	p *pkgReader2
62
63	dict *reader2Dict
64}
65
66type reader2Dict struct {
67	bounds []typeInfo
68
69	tparams []*types2.TypeParam
70
71	derived      []derivedInfo
72	derivedTypes []types2.Type
73}
74
75type reader2TypeBound struct {
76	derived  bool
77	boundIdx int
78}
79
80func (pr *pkgReader2) newReader(k reloc, idx int, marker syncMarker) *reader2 {
81	return &reader2{
82		decoder: pr.newDecoder(k, idx, marker),
83		p:       pr,
84	}
85}
86
87// @@@ Positions
88
89func (r *reader2) pos() syntax.Pos {
90	r.sync(syncPos)
91	if !r.bool() {
92		return syntax.Pos{}
93	}
94
95	// TODO(mdempsky): Delta encoding.
96	posBase := r.posBase()
97	line := r.uint()
98	col := r.uint()
99	return syntax.MakePos(posBase, line, col)
100}
101
102func (r *reader2) posBase() *syntax.PosBase {
103	return r.p.posBaseIdx(r.reloc(relocPosBase))
104}
105
106func (pr *pkgReader2) posBaseIdx(idx int) *syntax.PosBase {
107	if b := pr.posBases[idx]; b != nil {
108		return b
109	}
110
111	r := pr.newReader(relocPosBase, idx, syncPosBase)
112	var b *syntax.PosBase
113
114	filename := r.string()
115
116	if r.bool() {
117		b = syntax.NewTrimmedFileBase(filename, true)
118	} else {
119		pos := r.pos()
120		line := r.uint()
121		col := r.uint()
122		b = syntax.NewLineBase(pos, filename, true, line, col)
123	}
124
125	pr.posBases[idx] = b
126	return b
127}
128
129// @@@ Packages
130
131func (r *reader2) pkg() *types2.Package {
132	r.sync(syncPkg)
133	return r.p.pkgIdx(r.reloc(relocPkg))
134}
135
136func (pr *pkgReader2) pkgIdx(idx int) *types2.Package {
137	// TODO(mdempsky): Consider using some non-nil pointer to indicate
138	// the universe scope, so we don't need to keep re-reading it.
139	if pkg := pr.pkgs[idx]; pkg != nil {
140		return pkg
141	}
142
143	pkg := pr.newReader(relocPkg, idx, syncPkgDef).doPkg()
144	pr.pkgs[idx] = pkg
145	return pkg
146}
147
148func (r *reader2) doPkg() *types2.Package {
149	path := r.string()
150	if path == "builtin" {
151		return nil // universe
152	}
153	if path == "" {
154		path = r.p.pkgPath
155	}
156
157	if pkg := r.p.imports[path]; pkg != nil {
158		return pkg
159	}
160
161	name := r.string()
162	height := r.len()
163
164	pkg := types2.NewPackageHeight(path, name, height)
165	r.p.imports[path] = pkg
166
167	// TODO(mdempsky): The list of imported packages is important for
168	// go/types, but we could probably skip populating it for types2.
169	imports := make([]*types2.Package, r.len())
170	for i := range imports {
171		imports[i] = r.pkg()
172	}
173	pkg.SetImports(imports)
174
175	return pkg
176}
177
178// @@@ Types
179
180func (r *reader2) typ() types2.Type {
181	return r.p.typIdx(r.typInfo(), r.dict)
182}
183
184func (r *reader2) typInfo() typeInfo {
185	r.sync(syncType)
186	if r.bool() {
187		return typeInfo{idx: r.len(), derived: true}
188	}
189	return typeInfo{idx: r.reloc(relocType), derived: false}
190}
191
192func (pr *pkgReader2) typIdx(info typeInfo, dict *reader2Dict) types2.Type {
193	idx := info.idx
194	var where *types2.Type
195	if info.derived {
196		where = &dict.derivedTypes[idx]
197		idx = dict.derived[idx].idx
198	} else {
199		where = &pr.typs[idx]
200	}
201
202	if typ := *where; typ != nil {
203		return typ
204	}
205
206	r := pr.newReader(relocType, idx, syncTypeIdx)
207	r.dict = dict
208
209	typ := r.doTyp()
210	assert(typ != nil)
211
212	// See comment in pkgReader.typIdx explaining how this happens.
213	if prev := *where; prev != nil {
214		return prev
215	}
216
217	*where = typ
218	return typ
219}
220
221func (r *reader2) doTyp() (res types2.Type) {
222	switch tag := codeType(r.code(syncType)); tag {
223	default:
224		base.FatalfAt(src.NoXPos, "unhandled type tag: %v", tag)
225		panic("unreachable")
226
227	case typeBasic:
228		return types2.Typ[r.len()]
229
230	case typeNamed:
231		obj, targs := r.obj()
232		name := obj.(*types2.TypeName)
233		if len(targs) != 0 {
234			t, _ := types2.Instantiate(r.p.ctxt, name.Type(), targs, false)
235			return t
236		}
237		return name.Type()
238
239	case typeTypeParam:
240		return r.dict.tparams[r.len()]
241
242	case typeArray:
243		len := int64(r.uint64())
244		return types2.NewArray(r.typ(), len)
245	case typeChan:
246		dir := types2.ChanDir(r.len())
247		return types2.NewChan(dir, r.typ())
248	case typeMap:
249		return types2.NewMap(r.typ(), r.typ())
250	case typePointer:
251		return types2.NewPointer(r.typ())
252	case typeSignature:
253		return r.signature(nil)
254	case typeSlice:
255		return types2.NewSlice(r.typ())
256	case typeStruct:
257		return r.structType()
258	case typeInterface:
259		return r.interfaceType()
260	case typeUnion:
261		return r.unionType()
262	}
263}
264
265func (r *reader2) structType() *types2.Struct {
266	fields := make([]*types2.Var, r.len())
267	var tags []string
268	for i := range fields {
269		pos := r.pos()
270		pkg, name := r.selector()
271		ftyp := r.typ()
272		tag := r.string()
273		embedded := r.bool()
274
275		fields[i] = types2.NewField(pos, pkg, name, ftyp, embedded)
276		if tag != "" {
277			for len(tags) < i {
278				tags = append(tags, "")
279			}
280			tags = append(tags, tag)
281		}
282	}
283	return types2.NewStruct(fields, tags)
284}
285
286func (r *reader2) unionType() *types2.Union {
287	terms := make([]*types2.Term, r.len())
288	for i := range terms {
289		terms[i] = types2.NewTerm(r.bool(), r.typ())
290	}
291	return types2.NewUnion(terms)
292}
293
294func (r *reader2) interfaceType() *types2.Interface {
295	methods := make([]*types2.Func, r.len())
296	embeddeds := make([]types2.Type, r.len())
297
298	for i := range methods {
299		pos := r.pos()
300		pkg, name := r.selector()
301		mtyp := r.signature(nil)
302		methods[i] = types2.NewFunc(pos, pkg, name, mtyp)
303	}
304
305	for i := range embeddeds {
306		embeddeds[i] = r.typ()
307	}
308
309	return types2.NewInterfaceType(methods, embeddeds)
310}
311
312func (r *reader2) signature(recv *types2.Var) *types2.Signature {
313	r.sync(syncSignature)
314
315	params := r.params()
316	results := r.params()
317	variadic := r.bool()
318
319	return types2.NewSignatureType(recv, nil, nil, params, results, variadic)
320}
321
322func (r *reader2) params() *types2.Tuple {
323	r.sync(syncParams)
324	params := make([]*types2.Var, r.len())
325	for i := range params {
326		params[i] = r.param()
327	}
328	return types2.NewTuple(params...)
329}
330
331func (r *reader2) param() *types2.Var {
332	r.sync(syncParam)
333
334	pos := r.pos()
335	pkg, name := r.localIdent()
336	typ := r.typ()
337
338	return types2.NewParam(pos, pkg, name, typ)
339}
340
341// @@@ Objects
342
343func (r *reader2) obj() (types2.Object, []types2.Type) {
344	r.sync(syncObject)
345
346	assert(!r.bool())
347
348	pkg, name := r.p.objIdx(r.reloc(relocObj))
349	obj := pkg.Scope().Lookup(name)
350
351	targs := make([]types2.Type, r.len())
352	for i := range targs {
353		targs[i] = r.typ()
354	}
355
356	return obj, targs
357}
358
359func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
360	rname := pr.newReader(relocName, idx, syncObject1)
361
362	objPkg, objName := rname.qualifiedIdent()
363	assert(objName != "")
364
365	tag := codeObj(rname.code(syncCodeObj))
366
367	if tag == objStub {
368		assert(objPkg == nil || objPkg == types2.Unsafe)
369		return objPkg, objName
370	}
371
372	dict := pr.objDictIdx(idx)
373
374	r := pr.newReader(relocObj, idx, syncObject1)
375	r.dict = dict
376
377	objPkg.Scope().InsertLazy(objName, func() types2.Object {
378		switch tag {
379		default:
380			panic("weird")
381
382		case objAlias:
383			pos := r.pos()
384			typ := r.typ()
385			return types2.NewTypeName(pos, objPkg, objName, typ)
386
387		case objConst:
388			pos := r.pos()
389			typ := r.typ()
390			val := r.value()
391			return types2.NewConst(pos, objPkg, objName, typ, val)
392
393		case objFunc:
394			pos := r.pos()
395			tparams := r.typeParamNames()
396			sig := r.signature(nil)
397			sig.SetTypeParams(tparams)
398			return types2.NewFunc(pos, objPkg, objName, sig)
399
400		case objType:
401			pos := r.pos()
402
403			return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeParam, underlying types2.Type, methods []*types2.Func) {
404				tparams = r.typeParamNames()
405
406				// TODO(mdempsky): Rewrite receiver types to underlying is an
407				// Interface? The go/types importer does this (I think because
408				// unit tests expected that), but cmd/compile doesn't care
409				// about it, so maybe we can avoid worrying about that here.
410				underlying = r.typ().Underlying()
411
412				methods = make([]*types2.Func, r.len())
413				for i := range methods {
414					methods[i] = r.method()
415				}
416
417				return
418			})
419
420		case objVar:
421			pos := r.pos()
422			typ := r.typ()
423			return types2.NewVar(pos, objPkg, objName, typ)
424		}
425	})
426
427	return objPkg, objName
428}
429
430func (pr *pkgReader2) objDictIdx(idx int) *reader2Dict {
431	r := pr.newReader(relocObjDict, idx, syncObject1)
432
433	var dict reader2Dict
434
435	if implicits := r.len(); implicits != 0 {
436		base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits)
437	}
438
439	dict.bounds = make([]typeInfo, r.len())
440	for i := range dict.bounds {
441		dict.bounds[i] = r.typInfo()
442	}
443
444	dict.derived = make([]derivedInfo, r.len())
445	dict.derivedTypes = make([]types2.Type, len(dict.derived))
446	for i := range dict.derived {
447		dict.derived[i] = derivedInfo{r.reloc(relocType), r.bool()}
448	}
449
450	// function references follow, but reader2 doesn't need those
451
452	return &dict
453}
454
455func (r *reader2) typeParamNames() []*types2.TypeParam {
456	r.sync(syncTypeParamNames)
457
458	// Note: This code assumes it only processes objects without
459	// implement type parameters. This is currently fine, because
460	// reader2 is only used to read in exported declarations, which are
461	// always package scoped.
462
463	if len(r.dict.bounds) == 0 {
464		return nil
465	}
466
467	// Careful: Type parameter lists may have cycles. To allow for this,
468	// we construct the type parameter list in two passes: first we
469	// create all the TypeNames and TypeParams, then we construct and
470	// set the bound type.
471
472	r.dict.tparams = make([]*types2.TypeParam, len(r.dict.bounds))
473	for i := range r.dict.bounds {
474		pos := r.pos()
475		pkg, name := r.localIdent()
476
477		tname := types2.NewTypeName(pos, pkg, name, nil)
478		r.dict.tparams[i] = types2.NewTypeParam(tname, nil)
479	}
480
481	for i, bound := range r.dict.bounds {
482		r.dict.tparams[i].SetConstraint(r.p.typIdx(bound, r.dict))
483	}
484
485	return r.dict.tparams
486}
487
488func (r *reader2) method() *types2.Func {
489	r.sync(syncMethod)
490	pos := r.pos()
491	pkg, name := r.selector()
492
493	rparams := r.typeParamNames()
494	sig := r.signature(r.param())
495	sig.SetRecvTypeParams(rparams)
496
497	_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
498	return types2.NewFunc(pos, pkg, name, sig)
499}
500
501func (r *reader2) qualifiedIdent() (*types2.Package, string) { return r.ident(syncSym) }
502func (r *reader2) localIdent() (*types2.Package, string)     { return r.ident(syncLocalIdent) }
503func (r *reader2) selector() (*types2.Package, string)       { return r.ident(syncSelector) }
504
505func (r *reader2) ident(marker syncMarker) (*types2.Package, string) {
506	r.sync(marker)
507	return r.pkg(), r.string()
508}
509