// 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 gcimporter

import (
	
	
	
	
	
	
)

// A pkgReader holds the shared state for reading a unified IR package
// description.
type pkgReader struct {
	pkgbits.PkgDecoder

	fake fakeFileSet

	ctxt    *types.Context
	imports map[string]*types.Package // previously imported packages, indexed by path

	// lazily initialized arrays corresponding to the unified IR
	// PosBase, Pkg, and Type sections, respectively.
	posBases []string // position bases (i.e., file names)
	pkgs     []*types.Package
	typs     []types.Type

	// laterFns holds functions that need to be invoked at the end of
	// import reading.
	laterFns []func()

	// ifaces holds a list of constructed Interfaces, which need to have
	// Complete called after importing is done.
	ifaces []*types.Interface
}

// later adds a function to be invoked at the end of import reading.
func ( *pkgReader) ( func()) {
	.laterFns = append(.laterFns, )
}

// readUnifiedPackage reads a package description from the given
// unified IR export data decoder.
func readUnifiedPackage( *token.FileSet,  *types.Context,  map[string]*types.Package,  pkgbits.PkgDecoder) *types.Package {
	 := pkgReader{
		PkgDecoder: ,

		fake: fakeFileSet{
			fset:  ,
			files: make(map[string]*fileInfo),
		},

		ctxt:    ,
		imports: ,

		posBases: make([]string, .NumElems(pkgbits.RelocPosBase)),
		pkgs:     make([]*types.Package, .NumElems(pkgbits.RelocPkg)),
		typs:     make([]types.Type, .NumElems(pkgbits.RelocType)),
	}
	defer .fake.setLines()

	 := .newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
	 := .pkg()
	.Bool() // TODO(mdempsky): Remove; was "has init"

	for ,  := 0, .Len();  < ; ++ {
		// As if r.obj(), but avoiding the Scope.Lookup call,
		// to avoid eager loading of imports.
		.Sync(pkgbits.SyncObject)
		assert(!.Bool())
		.p.objIdx(.Reloc(pkgbits.RelocObj))
		assert(.Len() == 0)
	}

	.Sync(pkgbits.SyncEOF)

	for ,  := range .laterFns {
		()
	}

	for ,  := range .ifaces {
		.Complete()
	}

	// Imports() of pkg are all of the transitive packages that were loaded.
	var  []*types.Package
	for ,  := range .pkgs {
		if  != nil &&  !=  {
			 = append(, )
		}
	}
	slices.SortFunc(, func(,  *types.Package) int {
		return strings.Compare(.Path(), .Path())
	})
	.SetImports()

	.MarkComplete()
	return 
}

// A reader holds the state for reading a single unified IR element
// within a package.
type reader struct {
	pkgbits.Decoder

	p *pkgReader

	dict *readerDict
}

// A readerDict holds the state for type parameters that parameterize
// the current unified IR element.
type readerDict struct {
	// bounds is a slice of typeInfos corresponding to the underlying
	// bounds of the element's type parameters.
	bounds []typeInfo

	// tparams is a slice of the constructed TypeParams for the element.
	tparams []*types.TypeParam

	// derived is a slice of types derived from tparams, which may be
	// instantiated while reading the current element.
	derived      []derivedInfo
	derivedTypes []types.Type // lazily instantiated from derived
}

func ( *pkgReader) ( pkgbits.RelocKind,  pkgbits.Index,  pkgbits.SyncMarker) *reader {
	return &reader{
		Decoder: .NewDecoder(, , ),
		p:       ,
	}
}

func ( *pkgReader) ( pkgbits.RelocKind,  pkgbits.Index,  pkgbits.SyncMarker) *reader {
	return &reader{
		Decoder: .TempDecoder(, , ),
		p:       ,
	}
}

func ( *pkgReader) ( *reader) {
	.RetireDecoder(&.Decoder)
}

// @@@ Positions

func ( *reader) () token.Pos {
	.Sync(pkgbits.SyncPos)
	if !.Bool() {
		return token.NoPos
	}

	// TODO(mdempsky): Delta encoding.
	 := .posBase()
	 := .Uint()
	 := .Uint()
	return .p.fake.pos(, int(), int())
}

func ( *reader) () string {
	return .p.posBaseIdx(.Reloc(pkgbits.RelocPosBase))
}

func ( *pkgReader) ( pkgbits.Index) string {
	if  := .posBases[];  != "" {
		return 
	}

	var  string
	{
		 := .tempReader(pkgbits.RelocPosBase, , pkgbits.SyncPosBase)

		// Within types2, position bases have a lot more details (e.g.,
		// keeping track of where //line directives appeared exactly).
		//
		// For go/types, we just track the file name.

		 = .String()

		if .Bool() { // file base
			// Was: "b = token.NewTrimmedFileBase(filename, true)"
		} else { // line base
			 := .pos()
			 := .Uint()
			 := .Uint()

			// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
			_, _, _ = , , 
		}
		.retireReader()
	}
	 := 
	.posBases[] = 
	return 
}

// @@@ Packages

func ( *reader) () *types.Package {
	.Sync(pkgbits.SyncPkg)
	return .p.pkgIdx(.Reloc(pkgbits.RelocPkg))
}

func ( *pkgReader) ( pkgbits.Index) *types.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  := .pkgs[];  != nil {
		return 
	}

	 := .newReader(pkgbits.RelocPkg, , pkgbits.SyncPkgDef).doPkg()
	.pkgs[] = 
	return 
}

func ( *reader) () *types.Package {
	 := .String()
	switch  {
	case "":
		 = .p.PkgPath()
	case "builtin":
		return nil // universe
	case "unsafe":
		return types.Unsafe
	}

	if  := .p.imports[];  != nil {
		return 
	}

	 := .String()

	 := types.NewPackage(, )
	.p.imports[] = 

	return 
}

// @@@ Types

func ( *reader) () types.Type {
	return .p.typIdx(.typInfo(), .dict)
}

func ( *reader) () typeInfo {
	.Sync(pkgbits.SyncType)
	if .Bool() {
		return typeInfo{idx: pkgbits.Index(.Len()), derived: true}
	}
	return typeInfo{idx: .Reloc(pkgbits.RelocType), derived: false}
}

func ( *pkgReader) ( typeInfo,  *readerDict) types.Type {
	 := .idx
	var  *types.Type
	if .derived {
		 = &.derivedTypes[]
		 = .derived[].idx
	} else {
		 = &.typs[]
	}

	if  := *;  != nil {
		return 
	}

	var  types.Type
	{
		 := .tempReader(pkgbits.RelocType, , pkgbits.SyncTypeIdx)
		.dict = 

		 = .doTyp()
		assert( != nil)
		.retireReader()
	}
	// See comment in pkgReader.typIdx explaining how this happens.
	if  := *;  != nil {
		return 
	}

	* = 
	return 
}

func ( *reader) () ( types.Type) {
	switch  := pkgbits.CodeType(.Code(pkgbits.SyncType));  {
	default:
		errorf("unhandled type tag: %v", )
		panic("unreachable")

	case pkgbits.TypeBasic:
		return types.Typ[.Len()]

	case pkgbits.TypeNamed:
		,  := .obj()
		 := .(*types.TypeName)
		if len() != 0 {
			,  := types.Instantiate(.p.ctxt, .Type(), , false)
			return 
		}
		return .Type()

	case pkgbits.TypeTypeParam:
		return .dict.tparams[.Len()]

	case pkgbits.TypeArray:
		 := int64(.Uint64())
		return types.NewArray(.typ(), )
	case pkgbits.TypeChan:
		 := types.ChanDir(.Len())
		return types.NewChan(, .typ())
	case pkgbits.TypeMap:
		return types.NewMap(.typ(), .typ())
	case pkgbits.TypePointer:
		return types.NewPointer(.typ())
	case pkgbits.TypeSignature:
		return .signature(nil, nil, nil)
	case pkgbits.TypeSlice:
		return types.NewSlice(.typ())
	case pkgbits.TypeStruct:
		return .structType()
	case pkgbits.TypeInterface:
		return .interfaceType()
	case pkgbits.TypeUnion:
		return .unionType()
	}
}

func ( *reader) () *types.Struct {
	 := make([]*types.Var, .Len())
	var  []string
	for  := range  {
		 := .pos()
		,  := .selector()
		 := .typ()
		 := .String()
		 := .Bool()

		[] = types.NewField(, , , , )
		if  != "" {
			for len() <  {
				 = append(, "")
			}
			 = append(, )
		}
	}
	return types.NewStruct(, )
}

func ( *reader) () *types.Union {
	 := make([]*types.Term, .Len())
	for  := range  {
		[] = types.NewTerm(.Bool(), .typ())
	}
	return types.NewUnion()
}

func ( *reader) () *types.Interface {
	 := make([]*types.Func, .Len())
	 := make([]types.Type, .Len())
	 := len() == 0 && len() == 1 && .Bool()

	for  := range  {
		 := .pos()
		,  := .selector()
		 := .signature(nil, nil, nil)
		[] = types.NewFunc(, , , )
	}

	for  := range  {
		[] = .typ()
	}

	 := types.NewInterfaceType(, )
	if  {
		.MarkImplicit()
	}

	// We need to call iface.Complete(), but if there are any embedded
	// defined types, then we may not have set their underlying
	// interface type yet. So we need to defer calling Complete until
	// after we've called SetUnderlying everywhere.
	//
	// TODO(mdempsky): After CL 424876 lands, it should be safe to call
	// iface.Complete() immediately.
	.p.ifaces = append(.p.ifaces, )

	return 
}

func ( *reader) ( *types.Var, ,  []*types.TypeParam) *types.Signature {
	.Sync(pkgbits.SyncSignature)

	 := .params()
	 := .params()
	 := .Bool()

	return types.NewSignatureType(, , , , , )
}

func ( *reader) () *types.Tuple {
	.Sync(pkgbits.SyncParams)

	 := make([]*types.Var, .Len())
	for  := range  {
		[] = .param()
	}

	return types.NewTuple(...)
}

func ( *reader) () *types.Var {
	.Sync(pkgbits.SyncParam)

	 := .pos()
	,  := .localIdent()
	 := .typ()

	return types.NewParam(, , , )
}

// @@@ Objects

func ( *reader) () (types.Object, []types.Type) {
	.Sync(pkgbits.SyncObject)

	assert(!.Bool())

	,  := .p.objIdx(.Reloc(pkgbits.RelocObj))
	 := pkgScope().Lookup()

	 := make([]types.Type, .Len())
	for  := range  {
		[] = .typ()
	}

	return , 
}

func ( *pkgReader) ( pkgbits.Index) (*types.Package, string) {

	var  *types.Package
	var  string
	var  pkgbits.CodeObj
	{
		 := .tempReader(pkgbits.RelocName, , pkgbits.SyncObject1)

		,  = .qualifiedIdent()
		assert( != "")

		 = pkgbits.CodeObj(.Code(pkgbits.SyncCodeObj))
		.retireReader()
	}

	if  == pkgbits.ObjStub {
		assert( == nil ||  == types.Unsafe)
		return , 
	}

	// Ignore local types promoted to global scope (#55110).
	if ,  := splitVargenSuffix();  != "" {
		return , 
	}

	if .Scope().Lookup() == nil {
		 := .objDictIdx()

		 := .newReader(pkgbits.RelocObj, , pkgbits.SyncObject1)
		.dict = 

		 := func( types.Object) {
			.Scope().Insert()
		}

		switch  {
		default:
			panic("weird")

		case pkgbits.ObjAlias:
			 := .pos()
			 := .typ()
			(newAliasTypeName(, , , ))

		case pkgbits.ObjConst:
			 := .pos()
			 := .typ()
			 := .Value()
			(types.NewConst(, , , , ))

		case pkgbits.ObjFunc:
			 := .pos()
			 := .typeParamNames()
			 := .signature(nil, nil, )
			(types.NewFunc(, , , ))

		case pkgbits.ObjType:
			 := .pos()

			 := types.NewTypeName(, , , nil)
			 := types.NewNamed(, nil, nil)
			()

			.SetTypeParams(.typeParamNames())

			 := .typ().Underlying()

			// If the underlying type is an interface, we need to
			// duplicate its methods so we can replace the receiver
			// parameter's type (#49906).
			if ,  := .(*types.Interface);  && .NumExplicitMethods() != 0 {
				 := make([]*types.Func, .NumExplicitMethods())
				for  := range  {
					 := .ExplicitMethod()
					 := .Type().(*types.Signature)

					 := types.NewVar(.Pos(), .Pkg(), "", )
					[] = types.NewFunc(.Pos(), .Pkg(), .Name(), types.NewSignature(, .Params(), .Results(), .Variadic()))
				}

				 := make([]types.Type, .NumEmbeddeds())
				for  := range  {
					[] = .EmbeddedType()
				}

				 := types.NewInterfaceType(, )
				.p.ifaces = append(.p.ifaces, )
				 = 
			}

			.SetUnderlying()

			for ,  := 0, .Len();  < ; ++ {
				.AddMethod(.method())
			}

		case pkgbits.ObjVar:
			 := .pos()
			 := .typ()
			(types.NewVar(, , , ))
		}
	}

	return , 
}

func ( *pkgReader) ( pkgbits.Index) *readerDict {

	var  readerDict

	{
		 := .tempReader(pkgbits.RelocObjDict, , pkgbits.SyncObject1)
		if  := .Len();  != 0 {
			errorf("unexpected object with %v implicit type parameter(s)", )
		}

		.bounds = make([]typeInfo, .Len())
		for  := range .bounds {
			.bounds[] = .typInfo()
		}

		.derived = make([]derivedInfo, .Len())
		.derivedTypes = make([]types.Type, len(.derived))
		for  := range .derived {
			.derived[] = derivedInfo{.Reloc(pkgbits.RelocType), .Bool()}
		}

		.retireReader()
	}
	// function references follow, but reader doesn't need those

	return &
}

func ( *reader) () []*types.TypeParam {
	.Sync(pkgbits.SyncTypeParamNames)

	// Note: This code assumes it only processes objects without
	// implement type parameters. This is currently fine, because
	// reader is only used to read in exported declarations, which are
	// always package scoped.

	if len(.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.

	.dict.tparams = make([]*types.TypeParam, len(.dict.bounds))
	for  := range .dict.bounds {
		 := .pos()
		,  := .localIdent()

		 := types.NewTypeName(, , , nil)
		.dict.tparams[] = types.NewTypeParam(, nil)
	}

	 := make([]types.Type, len(.dict.bounds))
	for ,  := range .dict.bounds {
		[] = .p.typIdx(, .dict)
	}

	// TODO(mdempsky): This is subtle, elaborate further.
	//
	// We have to save tparams outside of the closure, because
	// typeParamNames() can be called multiple times with the same
	// dictionary instance.
	//
	// Also, this needs to happen later to make sure SetUnderlying has
	// been called.
	//
	// TODO(mdempsky): Is it safe to have a single "later" slice or do
	// we need to have multiple passes? See comments on CL 386002 and
	// go.dev/issue/52104.
	 := .dict.tparams
	.p.later(func() {
		for ,  := range  {
			[].SetConstraint()
		}
	})

	return .dict.tparams
}

func ( *reader) () *types.Func {
	.Sync(pkgbits.SyncMethod)
	 := .pos()
	,  := .selector()

	 := .typeParamNames()
	 := .signature(.param(), , nil)

	_ = .pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
	return types.NewFunc(, , , )
}

func ( *reader) () (*types.Package, string) { return .ident(pkgbits.SyncSym) }
func ( *reader) () (*types.Package, string)     { return .ident(pkgbits.SyncLocalIdent) }
func ( *reader) () (*types.Package, string)       { return .ident(pkgbits.SyncSelector) }

func ( *reader) ( pkgbits.SyncMarker) (*types.Package, string) {
	.Sync()
	return .pkg(), .String()
}

// pkgScope returns pkg.Scope().
// If pkg is nil, it returns types.Universe instead.
//
// TODO(mdempsky): Remove after x/tools can depend on Go 1.19.
func pkgScope( *types.Package) *types.Scope {
	if  != nil {
		return .Scope()
	}
	return types.Universe
}

// newAliasTypeName returns a new TypeName, with a materialized *types.Alias if supported.
func newAliasTypeName( token.Pos,  *types.Package,  string,  types.Type) *types.TypeName {
	// When GODEBUG=gotypesalias=1 or unset, the Type() of the return value is a
	// *types.Alias. Copied from x/tools/internal/aliases.NewAlias.
	switch godebug.New("gotypesalias").Value() {
	case "", "1":
		 := types.NewTypeName(, , , nil)
		_ = types.NewAlias(, ) // form TypeName -> Alias cycle
		return 
	}
	return types.NewTypeName(, , , )
}