package gcimporter
import (
"go/token"
"go/types"
"internal/godebug"
"internal/pkgbits"
"slices"
"strings"
)
type pkgReader struct {
pkgbits .PkgDecoder
fake fakeFileSet
ctxt *types .Context
imports map [string ]*types .Package
posBases []string
pkgs []*types .Package
typs []types .Type
laterFns []func ()
ifaces []*types .Interface
}
func (pr *pkgReader ) later (fn func ()) {
pr .laterFns = append (pr .laterFns , fn )
}
func readUnifiedPackage(fset *token .FileSet , ctxt *types .Context , imports map [string ]*types .Package , input pkgbits .PkgDecoder ) *types .Package {
pr := pkgReader {
PkgDecoder : input ,
fake : fakeFileSet {
fset : fset ,
files : make (map [string ]*fileInfo ),
},
ctxt : ctxt ,
imports : imports ,
posBases : make ([]string , input .NumElems (pkgbits .RelocPosBase )),
pkgs : make ([]*types .Package , input .NumElems (pkgbits .RelocPkg )),
typs : make ([]types .Type , input .NumElems (pkgbits .RelocType )),
}
defer pr .fake .setLines ()
r := pr .newReader (pkgbits .RelocMeta , pkgbits .PublicRootIdx , pkgbits .SyncPublic )
pkg := r .pkg ()
r .Bool ()
for i , n := 0 , r .Len (); i < n ; i ++ {
r .Sync (pkgbits .SyncObject )
assert (!r .Bool ())
r .p .objIdx (r .Reloc (pkgbits .RelocObj ))
assert (r .Len () == 0 )
}
r .Sync (pkgbits .SyncEOF )
for _ , fn := range pr .laterFns {
fn ()
}
for _ , iface := range pr .ifaces {
iface .Complete ()
}
var imps []*types .Package
for _ , imp := range pr .pkgs {
if imp != nil && imp != pkg {
imps = append (imps , imp )
}
}
slices .SortFunc (imps , func (a , b *types .Package ) int {
return strings .Compare (a .Path (), b .Path ())
})
pkg .SetImports (imps )
pkg .MarkComplete ()
return pkg
}
type reader struct {
pkgbits .Decoder
p *pkgReader
dict *readerDict
}
type readerDict struct {
bounds []typeInfo
tparams []*types .TypeParam
derived []derivedInfo
derivedTypes []types .Type
}
func (pr *pkgReader ) newReader (k pkgbits .RelocKind , idx pkgbits .Index , marker pkgbits .SyncMarker ) *reader {
return &reader {
Decoder : pr .NewDecoder (k , idx , marker ),
p : pr ,
}
}
func (pr *pkgReader ) tempReader (k pkgbits .RelocKind , idx pkgbits .Index , marker pkgbits .SyncMarker ) *reader {
return &reader {
Decoder : pr .TempDecoder (k , idx , marker ),
p : pr ,
}
}
func (pr *pkgReader ) retireReader (r *reader ) {
pr .RetireDecoder (&r .Decoder )
}
func (r *reader ) pos () token .Pos {
r .Sync (pkgbits .SyncPos )
if !r .Bool () {
return token .NoPos
}
posBase := r .posBase ()
line := r .Uint ()
col := r .Uint ()
return r .p .fake .pos (posBase , int (line ), int (col ))
}
func (r *reader ) posBase () string {
return r .p .posBaseIdx (r .Reloc (pkgbits .RelocPosBase ))
}
func (pr *pkgReader ) posBaseIdx (idx pkgbits .Index ) string {
if b := pr .posBases [idx ]; b != "" {
return b
}
var filename string
{
r := pr .tempReader (pkgbits .RelocPosBase , idx , pkgbits .SyncPosBase )
filename = r .String ()
if r .Bool () {
} else {
pos := r .pos ()
line := r .Uint ()
col := r .Uint ()
_, _, _ = pos , line , col
}
pr .retireReader (r )
}
b := filename
pr .posBases [idx ] = b
return b
}
func (r *reader ) pkg () *types .Package {
r .Sync (pkgbits .SyncPkg )
return r .p .pkgIdx (r .Reloc (pkgbits .RelocPkg ))
}
func (pr *pkgReader ) pkgIdx (idx pkgbits .Index ) *types .Package {
if pkg := pr .pkgs [idx ]; pkg != nil {
return pkg
}
pkg := pr .newReader (pkgbits .RelocPkg , idx , pkgbits .SyncPkgDef ).doPkg ()
pr .pkgs [idx ] = pkg
return pkg
}
func (r *reader ) doPkg () *types .Package {
path := r .String ()
switch path {
case "" :
path = r .p .PkgPath ()
case "builtin" :
return nil
case "unsafe" :
return types .Unsafe
}
if pkg := r .p .imports [path ]; pkg != nil {
return pkg
}
name := r .String ()
pkg := types .NewPackage (path , name )
r .p .imports [path ] = pkg
return pkg
}
func (r *reader ) typ () types .Type {
return r .p .typIdx (r .typInfo (), r .dict )
}
func (r *reader ) typInfo () typeInfo {
r .Sync (pkgbits .SyncType )
if r .Bool () {
return typeInfo {idx : pkgbits .Index (r .Len ()), derived : true }
}
return typeInfo {idx : r .Reloc (pkgbits .RelocType ), derived : false }
}
func (pr *pkgReader ) typIdx (info typeInfo , dict *readerDict ) types .Type {
idx := info .idx
var where *types .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
}
var typ types .Type
{
r := pr .tempReader (pkgbits .RelocType , idx , pkgbits .SyncTypeIdx )
r .dict = dict
typ = r .doTyp ()
assert (typ != nil )
pr .retireReader (r )
}
if prev := *where ; prev != nil {
return prev
}
*where = typ
return typ
}
func (r *reader ) doTyp () (res types .Type ) {
switch tag := pkgbits .CodeType (r .Code (pkgbits .SyncType )); tag {
default :
errorf ("unhandled type tag: %v" , tag )
panic ("unreachable" )
case pkgbits .TypeBasic :
return types .Typ [r .Len ()]
case pkgbits .TypeNamed :
obj , targs := r .obj ()
name := obj .(*types .TypeName )
if len (targs ) != 0 {
t , _ := types .Instantiate (r .p .ctxt , name .Type (), targs , false )
return t
}
return name .Type ()
case pkgbits .TypeTypeParam :
return r .dict .tparams [r .Len ()]
case pkgbits .TypeArray :
len := int64 (r .Uint64 ())
return types .NewArray (r .typ (), len )
case pkgbits .TypeChan :
dir := types .ChanDir (r .Len ())
return types .NewChan (dir , r .typ ())
case pkgbits .TypeMap :
return types .NewMap (r .typ (), r .typ ())
case pkgbits .TypePointer :
return types .NewPointer (r .typ ())
case pkgbits .TypeSignature :
return r .signature (nil , nil , nil )
case pkgbits .TypeSlice :
return types .NewSlice (r .typ ())
case pkgbits .TypeStruct :
return r .structType ()
case pkgbits .TypeInterface :
return r .interfaceType ()
case pkgbits .TypeUnion :
return r .unionType ()
}
}
func (r *reader ) structType () *types .Struct {
fields := make ([]*types .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 ] = types .NewField (pos , pkg , name , ftyp , embedded )
if tag != "" {
for len (tags ) < i {
tags = append (tags , "" )
}
tags = append (tags , tag )
}
}
return types .NewStruct (fields , tags )
}
func (r *reader ) unionType () *types .Union {
terms := make ([]*types .Term , r .Len ())
for i := range terms {
terms [i ] = types .NewTerm (r .Bool (), r .typ ())
}
return types .NewUnion (terms )
}
func (r *reader ) interfaceType () *types .Interface {
methods := make ([]*types .Func , r .Len ())
embeddeds := make ([]types .Type , r .Len ())
implicit := len (methods ) == 0 && len (embeddeds ) == 1 && r .Bool ()
for i := range methods {
pos := r .pos ()
pkg , name := r .selector ()
mtyp := r .signature (nil , nil , nil )
methods [i ] = types .NewFunc (pos , pkg , name , mtyp )
}
for i := range embeddeds {
embeddeds [i ] = r .typ ()
}
iface := types .NewInterfaceType (methods , embeddeds )
if implicit {
iface .MarkImplicit ()
}
r .p .ifaces = append (r .p .ifaces , iface )
return iface
}
func (r *reader ) signature (recv *types .Var , rtparams , tparams []*types .TypeParam ) *types .Signature {
r .Sync (pkgbits .SyncSignature )
params := r .params ()
results := r .params ()
variadic := r .Bool ()
return types .NewSignatureType (recv , rtparams , tparams , params , results , variadic )
}
func (r *reader ) params () *types .Tuple {
r .Sync (pkgbits .SyncParams )
params := make ([]*types .Var , r .Len ())
for i := range params {
params [i ] = r .param ()
}
return types .NewTuple (params ...)
}
func (r *reader ) param () *types .Var {
r .Sync (pkgbits .SyncParam )
pos := r .pos ()
pkg , name := r .localIdent ()
typ := r .typ ()
return types .NewParam (pos , pkg , name , typ )
}
func (r *reader ) obj () (types .Object , []types .Type ) {
r .Sync (pkgbits .SyncObject )
assert (!r .Bool ())
pkg , name := r .p .objIdx (r .Reloc (pkgbits .RelocObj ))
obj := pkgScope (pkg ).Lookup (name )
targs := make ([]types .Type , r .Len ())
for i := range targs {
targs [i ] = r .typ ()
}
return obj , targs
}
func (pr *pkgReader ) objIdx (idx pkgbits .Index ) (*types .Package , string ) {
var objPkg *types .Package
var objName string
var tag pkgbits .CodeObj
{
rname := pr .tempReader (pkgbits .RelocName , idx , pkgbits .SyncObject1 )
objPkg , objName = rname .qualifiedIdent ()
assert (objName != "" )
tag = pkgbits .CodeObj (rname .Code (pkgbits .SyncCodeObj ))
pr .retireReader (rname )
}
if tag == pkgbits .ObjStub {
assert (objPkg == nil || objPkg == types .Unsafe )
return objPkg , objName
}
if _ , suffix := splitVargenSuffix (objName ); suffix != "" {
return objPkg , objName
}
if objPkg .Scope ().Lookup (objName ) == nil {
dict := pr .objDictIdx (idx )
r := pr .newReader (pkgbits .RelocObj , idx , pkgbits .SyncObject1 )
r .dict = dict
declare := func (obj types .Object ) {
objPkg .Scope ().Insert (obj )
}
switch tag {
default :
panic ("weird" )
case pkgbits .ObjAlias :
pos := r .pos ()
typ := r .typ ()
declare (newAliasTypeName (pos , objPkg , objName , typ ))
case pkgbits .ObjConst :
pos := r .pos ()
typ := r .typ ()
val := r .Value ()
declare (types .NewConst (pos , objPkg , objName , typ , val ))
case pkgbits .ObjFunc :
pos := r .pos ()
tparams := r .typeParamNames ()
sig := r .signature (nil , nil , tparams )
declare (types .NewFunc (pos , objPkg , objName , sig ))
case pkgbits .ObjType :
pos := r .pos ()
obj := types .NewTypeName (pos , objPkg , objName , nil )
named := types .NewNamed (obj , nil , nil )
declare (obj )
named .SetTypeParams (r .typeParamNames ())
underlying := r .typ ().Underlying ()
if iface , ok := underlying .(*types .Interface ); ok && iface .NumExplicitMethods () != 0 {
methods := make ([]*types .Func , iface .NumExplicitMethods ())
for i := range methods {
fn := iface .ExplicitMethod (i )
sig := fn .Type ().(*types .Signature )
recv := types .NewVar (fn .Pos (), fn .Pkg (), "" , named )
methods [i ] = types .NewFunc (fn .Pos (), fn .Pkg (), fn .Name (), types .NewSignature (recv , sig .Params (), sig .Results (), sig .Variadic ()))
}
embeds := make ([]types .Type , iface .NumEmbeddeds ())
for i := range embeds {
embeds [i ] = iface .EmbeddedType (i )
}
newIface := types .NewInterfaceType (methods , embeds )
r .p .ifaces = append (r .p .ifaces , newIface )
underlying = newIface
}
named .SetUnderlying (underlying )
for i , n := 0 , r .Len (); i < n ; i ++ {
named .AddMethod (r .method ())
}
case pkgbits .ObjVar :
pos := r .pos ()
typ := r .typ ()
declare (types .NewVar (pos , objPkg , objName , typ ))
}
}
return objPkg , objName
}
func (pr *pkgReader ) objDictIdx (idx pkgbits .Index ) *readerDict {
var dict readerDict
{
r := pr .tempReader (pkgbits .RelocObjDict , idx , pkgbits .SyncObject1 )
if implicits := r .Len (); implicits != 0 {
errorf ("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 ([]types .Type , len (dict .derived ))
for i := range dict .derived {
dict .derived [i ] = derivedInfo {r .Reloc (pkgbits .RelocType ), r .Bool ()}
}
pr .retireReader (r )
}
return &dict
}
func (r *reader ) typeParamNames () []*types .TypeParam {
r .Sync (pkgbits .SyncTypeParamNames )
if len (r .dict .bounds ) == 0 {
return nil
}
r .dict .tparams = make ([]*types .TypeParam , len (r .dict .bounds ))
for i := range r .dict .bounds {
pos := r .pos ()
pkg , name := r .localIdent ()
tname := types .NewTypeName (pos , pkg , name , nil )
r .dict .tparams [i ] = types .NewTypeParam (tname , nil )
}
typs := make ([]types .Type , len (r .dict .bounds ))
for i , bound := range r .dict .bounds {
typs [i ] = r .p .typIdx (bound , r .dict )
}
tparams := r .dict .tparams
r .p .later (func () {
for i , typ := range typs {
tparams [i ].SetConstraint (typ )
}
})
return r .dict .tparams
}
func (r *reader ) method () *types .Func {
r .Sync (pkgbits .SyncMethod )
pos := r .pos ()
pkg , name := r .selector ()
rparams := r .typeParamNames ()
sig := r .signature (r .param (), rparams , nil )
_ = r .pos ()
return types .NewFunc (pos , pkg , name , sig )
}
func (r *reader ) qualifiedIdent () (*types .Package , string ) { return r .ident (pkgbits .SyncSym ) }
func (r *reader ) localIdent () (*types .Package , string ) { return r .ident (pkgbits .SyncLocalIdent ) }
func (r *reader ) selector () (*types .Package , string ) { return r .ident (pkgbits .SyncSelector ) }
func (r *reader ) ident (marker pkgbits .SyncMarker ) (*types .Package , string ) {
r .Sync (marker )
return r .pkg (), r .String ()
}
func pkgScope(pkg *types .Package ) *types .Scope {
if pkg != nil {
return pkg .Scope ()
}
return types .Universe
}
func newAliasTypeName(pos token .Pos , pkg *types .Package , name string , rhs types .Type ) *types .TypeName {
switch godebug .New ("gotypesalias" ).Value () {
case "" , "1" :
tname := types .NewTypeName (pos , pkg , name , nil )
_ = types .NewAlias (tname , rhs )
return tname
}
return types .NewTypeName (pos , pkg , name , rhs )
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .