| // UNREVIEWED | |
| // Copyright 2021 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 noder | |
| import ( | |
| "go/constant" | |
| "cmd/compile/internal/base" | |
| "cmd/compile/internal/syntax" | |
| "cmd/compile/internal/types2" | |
| "cmd/internal/src" | |
| ) | |
| type pkgReader2 struct { | |
| pkgDecoder | |
| check *types2.Checker | |
| imports map[string]*types2.Package | |
| posBases []*syntax.PosBase | |
| pkgs []*types2.Package | |
| typs []types2.Type | |
| } | |
| func readPackage2(check *types2.Checker, imports map[string]*types2.Package, input pkgDecoder) *types2.Package { | |
| pr := pkgReader2{ | |
| pkgDecoder: input, | |
| check: check, | |
| imports: imports, | |
| posBases: make([]*syntax.PosBase, input.numElems(relocPosBase)), | |
| pkgs: make([]*types2.Package, input.numElems(relocPkg)), | |
| typs: make([]types2.Type, input.numElems(relocType)), | |
| } | |
| r := pr.newReader(relocMeta, publicRootIdx, syncPublic) | |
| pkg := r.pkg() | |
| r.bool() // has init | |
| for i, n := 0, r.len(); i < n; i++ { | |
| r.obj() | |
| } | |
| r.sync(syncEOF) | |
| pkg.MarkComplete() | |
| return pkg | |
| } | |
| type reader2 struct { | |
| decoder | |
| p *pkgReader2 | |
| dict *reader2Dict | |
| } | |
| type reader2Dict struct { | |
| bounds []typeInfo | |
| tparams []*types2.TypeParam | |
| derived []derivedInfo | |
| derivedTypes []types2.Type | |
| } | |
| type reader2TypeBound struct { | |
| derived bool | |
| boundIdx int | |
| } | |
| func (pr *pkgReader2) newReader(k reloc, idx int, marker syncMarker) *reader2 { | |
| return &reader2{ | |
| decoder: pr.newDecoder(k, idx, marker), | |
| p: pr, | |
| } | |
| } | |
| // @@@ Positions | |
| func (r *reader2) pos() syntax.Pos { | |
| r.sync(syncPos) | |
| if !r.bool() { | |
| return syntax.Pos{} | |
| } | |
| // TODO(mdempsky): Delta encoding. | |
| posBase := r.posBase() | |
| line := r.uint() | |
| col := r.uint() | |
| return syntax.MakePos(posBase, line, col) | |
| } | |
| func (r *reader2) posBase() *syntax.PosBase { | |
| return r.p.posBaseIdx(r.reloc(relocPosBase)) | |
| } | |
| func (pr *pkgReader2) posBaseIdx(idx int) *syntax.PosBase { | |
| if b := pr.posBases[idx]; b != nil { | |
| return b | |
| } | |
| r := pr.newReader(relocPosBase, idx, syncPosBase) | |
| var b *syntax.PosBase | |
| filename := r.string() | |
| _ = r.string() // absolute file name | |
| if r.bool() { | |
| b = syntax.NewFileBase(filename) | |
| } else { | |
| pos := r.pos() | |
| line := r.uint() | |
| col := r.uint() | |
| b = syntax.NewLineBase(pos, filename, line, col) | |
| } | |
| pr.posBases[idx] = b | |
| return b | |
| } | |
| // @@@ Packages | |
| func (r *reader2) pkg() *types2.Package { | |
| r.sync(syncPkg) | |
| return r.p.pkgIdx(r.reloc(relocPkg)) | |
| } | |
| func (pr *pkgReader2) pkgIdx(idx int) *types2.Package { | |
| // TODO(mdempsky): Consider using some non-nil pointer to indicate | |
| // the universe scope, so we don't need to keep re-reading it. | |
| if pkg := pr.pkgs[idx]; pkg != nil { | |
| return pkg | |
| } | |
| pkg := pr.newReader(relocPkg, idx, syncPkgDef).doPkg() | |
| pr.pkgs[idx] = pkg | |
| return pkg | |
| } | |
| func (r *reader2) doPkg() *types2.Package { | |
| path := r.string() | |
| if path == "builtin" { | |
| return nil // universe | |
| } | |
| if path == "" { | |
| path = r.p.pkgPath | |
| } | |
| if pkg := r.p.imports[path]; pkg != nil { | |
| return pkg | |
| } | |
| name := r.string() | |
| height := r.len() | |
| pkg := types2.NewPackageHeight(path, name, height) | |
| r.p.imports[path] = pkg | |
| // TODO(mdempsky): The list of imported packages is important for | |
| // go/types, but we could probably skip populating it for types2. | |
| imports := make([]*types2.Package, r.len()) | |
| for i := range imports { | |
| imports[i] = r.pkg() | |
| } | |
| pkg.SetImports(imports) | |
| return pkg | |
| } | |
| // @@@ Types | |
| func (r *reader2) typ() types2.Type { | |
| return r.p.typIdx(r.typInfo(), r.dict) | |
| } | |
| func (r *reader2) typInfo() typeInfo { | |
| r.sync(syncType) | |
| if r.bool() { | |
| return typeInfo{idx: r.len(), derived: true} | |
| } | |
| return typeInfo{idx: r.reloc(relocType), derived: false} | |
| } | |
| func (pr *pkgReader2) typIdx(info typeInfo, dict *reader2Dict) types2.Type { | |
| idx := info.idx | |
| var where *types2.Type | |
| if info.derived { | |
| where = &dict.derivedTypes[idx] | |
| idx = dict.derived[idx].idx | |
| } else { | |
| where = &pr.typs[idx] | |
| } | |
| if typ := *where; typ != nil { | |
| return typ | |
| } | |
| r := pr.newReader(relocType, idx, syncTypeIdx) | |
| r.dict = dict | |
| typ := r.doTyp() | |
| assert(typ != nil) | |
| // See comment in pkgReader.typIdx explaining how this happens. | |
| if prev := *where; prev != nil { | |
| return prev | |
| } | |
| *where = typ | |
| return typ | |
| } | |
| func (r *reader2) doTyp() (res types2.Type) { | |
| switch tag := codeType(r.code(syncType)); tag { | |
| default: | |
| base.FatalfAt(src.NoXPos, "unhandled type tag: %v", tag) | |
| panic("unreachable") | |
| case typeBasic: | |
| return types2.Typ[r.len()] | |
| case typeNamed: | |
| obj, targs := r.obj() | |
| name := obj.(*types2.TypeName) | |
| if len(targs) != 0 { | |
| return r.p.check.Instantiate(syntax.Pos{}, name.Type(), targs, nil, false) | |
| } | |
| return name.Type() | |
| case typeTypeParam: | |
| return r.dict.tparams[r.len()] | |
| case typeArray: | |
| len := int64(r.uint64()) | |
| return types2.NewArray(r.typ(), len) | |
| case typeChan: | |
| dir := types2.ChanDir(r.len()) | |
| return types2.NewChan(dir, r.typ()) | |
| case typeMap: | |
| return types2.NewMap(r.typ(), r.typ()) | |
| case typePointer: | |
| return types2.NewPointer(r.typ()) | |
| case typeSignature: | |
| return r.signature(nil) | |
| case typeSlice: | |
| return types2.NewSlice(r.typ()) | |
| case typeStruct: | |
| return r.structType() | |
| case typeInterface: | |
| return r.interfaceType() | |
| case typeUnion: | |
| return r.unionType() | |
| } | |
| } | |
| func (r *reader2) structType() *types2.Struct { | |
| fields := make([]*types2.Var, r.len()) | |
| var tags []string | |
| for i := range fields { | |
| pos := r.pos() | |
| pkg, name := r.selector() | |
| ftyp := r.typ() | |
| tag := r.string() | |
| embedded := r.bool() | |
| fields[i] = types2.NewField(pos, pkg, name, ftyp, embedded) | |
| if tag != "" { | |
| for len(tags) < i { | |
| tags = append(tags, "") | |
| } | |
| tags = append(tags, tag) | |
| } | |
| } | |
| return types2.NewStruct(fields, tags) | |
| } | |
| func (r *reader2) unionType() *types2.Union { | |
| terms := make([]*types2.Term, r.len()) | |
| for i := range terms { | |
| terms[i] = types2.NewTerm(r.bool(), r.typ()) | |
| } | |
| return types2.NewUnion(terms) | |
| } | |
| func (r *reader2) interfaceType() *types2.Interface { | |
| methods := make([]*types2.Func, r.len()) | |
| embeddeds := make([]types2.Type, r.len()) | |
| for i := range methods { | |
| pos := r.pos() | |
| pkg, name := r.selector() | |
| mtyp := r.signature(nil) | |
| methods[i] = types2.NewFunc(pos, pkg, name, mtyp) | |
| } | |
| for i := range embeddeds { | |
| embeddeds[i] = r.typ() | |
| } | |
| return types2.NewInterfaceType(methods, embeddeds) | |
| } | |
| func (r *reader2) signature(recv *types2.Var) *types2.Signature { | |
| r.sync(syncSignature) | |
| params := r.params() | |
| results := r.params() | |
| variadic := r.bool() | |
| return types2.NewSignature(recv, params, results, variadic) | |
| } | |
| func (r *reader2) params() *types2.Tuple { | |
| r.sync(syncParams) | |
| params := make([]*types2.Var, r.len()) | |
| for i := range params { | |
| params[i] = r.param() | |
| } | |
| return types2.NewTuple(params...) | |
| } | |
| func (r *reader2) param() *types2.Var { | |
| r.sync(syncParam) | |
| pos := r.pos() | |
| pkg, name := r.localIdent() | |
| typ := r.typ() | |
| return types2.NewParam(pos, pkg, name, typ) | |
| } | |
| // @@@ Objects | |
| func (r *reader2) obj() (types2.Object, []types2.Type) { | |
| r.sync(syncObject) | |
| assert(!r.bool()) | |
| pkg, name := r.p.objIdx(r.reloc(relocObj)) | |
| obj := pkg.Scope().Lookup(name) | |
| targs := make([]types2.Type, r.len()) | |
| for i := range targs { | |
| targs[i] = r.typ() | |
| } | |
| return obj, targs | |
| } | |
| func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) { | |
| rname := pr.newReader(relocName, idx, syncObject1) | |
| objPkg, objName := rname.qualifiedIdent() | |
| assert(objName != "") | |
| tag := codeObj(rname.code(syncCodeObj)) | |
| if tag == objStub { | |
| assert(objPkg == nil) | |
| return objPkg, objName | |
| } | |
| dict := pr.objDictIdx(idx) | |
| r := pr.newReader(relocObj, idx, syncObject1) | |
| r.dict = dict | |
| objPkg.Scope().InsertLazy(objName, func() types2.Object { | |
| switch tag { | |
| default: | |
| panic("weird") | |
| case objAlias: | |
| pos := r.pos() | |
| typ := r.typ() | |
| return types2.NewTypeName(pos, objPkg, objName, typ) | |
| case objConst: | |
| pos := r.pos() | |
| typ, val := r.value() | |
| return types2.NewConst(pos, objPkg, objName, typ, val) | |
| case objFunc: | |
| pos := r.pos() | |
| tparams := r.typeParamNames() | |
| sig := r.signature(nil) | |
| sig.SetTParams(tparams) | |
| return types2.NewFunc(pos, objPkg, objName, sig) | |
| case objType: | |
| pos := r.pos() | |
| return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeName, underlying types2.Type, methods []*types2.Func) { | |
| tparams = r.typeParamNames() | |
| // TODO(mdempsky): Rewrite receiver types to underlying is an | |
| // Interface? The go/types importer does this (I think because | |
| // unit tests expected that), but cmd/compile doesn't care | |
| // about it, so maybe we can avoid worrying about that here. | |
| underlying = r.typ().Underlying() | |
| methods = make([]*types2.Func, r.len()) | |
| for i := range methods { | |
| methods[i] = r.method() | |
| } | |
| return | |
| }) | |
| case objVar: | |
| pos := r.pos() | |
| typ := r.typ() | |
| return types2.NewVar(pos, objPkg, objName, typ) | |
| } | |
| }) | |
| return objPkg, objName | |
| } | |
| func (r *reader2) value() (types2.Type, constant.Value) { | |
| r.sync(syncValue) | |
| return r.typ(), r.rawValue() | |
| } | |
| func (pr *pkgReader2) objDictIdx(idx int) *reader2Dict { | |
| r := pr.newReader(relocObjDict, idx, syncObject1) | |
| var dict reader2Dict | |
| if implicits := r.len(); implicits != 0 { | |
| base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits) | |
| } | |
| dict.bounds = make([]typeInfo, r.len()) | |
| for i := range dict.bounds { | |
| dict.bounds[i] = r.typInfo() | |
| } | |
| dict.derived = make([]derivedInfo, r.len()) | |
| dict.derivedTypes = make([]types2.Type, len(dict.derived)) | |
| for i := range dict.derived { | |
| dict.derived[i] = derivedInfo{r.reloc(relocType), r.bool()} | |
| } | |
| // function references follow, but reader2 doesn't need those | |
| return &dict | |
| } | |
| func (r *reader2) typeParamNames() []*types2.TypeName { | |
| r.sync(syncTypeParamNames) | |
| // Note: This code assumes it only processes objects without | |
| // implement type parameters. This is currently fine, because | |
| // reader2 is only used to read in exported declarations, which are | |
| // always package scoped. | |
| if len(r.dict.bounds) == 0 { | |
| return nil | |
| } | |
| // Careful: Type parameter lists may have cycles. To allow for this, | |
| // we construct the type parameter list in two passes: first we | |
| // create all the TypeNames and TypeParams, then we construct and | |
| // set the bound type. | |
| names := make([]*types2.TypeName, len(r.dict.bounds)) | |
| r.dict.tparams = make([]*types2.TypeParam, len(r.dict.bounds)) | |
| for i := range r.dict.bounds { | |
| pos := r.pos() | |
| pkg, name := r.localIdent() | |
| names[i] = types2.NewTypeName(pos, pkg, name, nil) | |
| r.dict.tparams[i] = r.p.check.NewTypeParam(names[i], nil) | |
| } | |
| for i, bound := range r.dict.bounds { | |
| r.dict.tparams[i].SetConstraint(r.p.typIdx(bound, r.dict)) | |
| } | |
| return names | |
| } | |
| func (r *reader2) method() *types2.Func { | |
| r.sync(syncMethod) | |
| pos := r.pos() | |
| pkg, name := r.selector() | |
| rparams := r.typeParamNames() | |
| sig := r.signature(r.param()) | |
| sig.SetRParams(rparams) | |
| _ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go. | |
| return types2.NewFunc(pos, pkg, name, sig) | |
| } | |
| func (r *reader2) qualifiedIdent() (*types2.Package, string) { return r.ident(syncSym) } | |
| func (r *reader2) localIdent() (*types2.Package, string) { return r.ident(syncLocalIdent) } | |
| func (r *reader2) selector() (*types2.Package, string) { return r.ident(syncSelector) } | |
| func (r *reader2) ident(marker syncMarker) (*types2.Package, string) { | |
| r.sync(marker) | |
| return r.pkg(), r.string() | |
| } |