// Copyright 2018 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.

// Indexed package import.
// See cmd/compile/internal/gc/iexport.go for the export data format.

// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go.

package gcimporter

import (
	
	
	
	
	
	
	
	
	
	

	
)

type intReader struct {
	*bytes.Reader
	path string
}

func ( *intReader) () int64 {
	,  := binary.ReadVarint(.Reader)
	if  != nil {
		errorf("import %q: read varint error: %v", .path, )
	}
	return 
}

func ( *intReader) () uint64 {
	,  := binary.ReadUvarint(.Reader)
	if  != nil {
		errorf("import %q: read varint error: %v", .path, )
	}
	return 
}

// Keep this in sync with constants in iexport.go.
const (
	iexportVersionGo1_11   = 0
	iexportVersionPosCol   = 1
	iexportVersionGo1_18   = 2
	iexportVersionGenerics = 2

	iexportVersionCurrent = 2
)

type ident struct {
	pkg  *types.Package
	name string
}

const predeclReserved = 32

type itag uint64

const (
	// Types
	definedType itag = iota
	pointerType
	sliceType
	arrayType
	chanType
	mapType
	signatureType
	structType
	interfaceType
	typeParamType
	instanceType
	unionType
)

// IImportData imports a package from the serialized package data
// and returns 0 and a reference to the package.
// If the export data version is not recognized or the format is otherwise
// compromised, an error is returned.
func ( *token.FileSet,  map[string]*types.Package,  []byte,  string) (int, *types.Package, error) {
	,  := iimportCommon(, , , false, , nil)
	if  != nil {
		return 0, nil, 
	}
	return 0, [0], nil
}

// IImportBundle imports a set of packages from the serialized package bundle.
func ( *token.FileSet,  map[string]*types.Package,  []byte) ([]*types.Package, error) {
	return iimportCommon(, , , true, "", nil)
}

func ( *token.FileSet,  map[string]*types.Package,  []byte,  bool,  string,  InsertType) ( []*types.Package,  error) {
	const  = iexportVersionCurrent
	 := int64(-1)
	if !debug {
		defer func() {
			if  := recover();  != nil {
				if  {
					 = fmt.Errorf("%v", )
				} else if  >  {
					 = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", , )
				} else {
					 = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", , )
				}
			}
		}()
	}

	 := &intReader{bytes.NewReader(), }

	if  {
		 := .uint64()
		switch  {
		case :
		default:
			errorf("unknown bundle format version %d", )
		}
	}

	 = int64(.uint64())
	switch  {
	case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
	default:
		if  > iexportVersionGo1_18 {
			errorf("unstable iexport format version %d, just rebuild compiler and std library", )
		} else {
			errorf("unknown iexport format version %d", )
		}
	}

	 := int64(.uint64())
	var  int64
	var  []uint64
	if  != nil {
		// Shallow mode uses a different position encoding.
		 = int64(.uint64())
		 = make([]uint64, .uint64())
		for  := range  {
			[] = .uint64()
		}
	}
	 := int64(.uint64())

	,  := .Seek(0, io.SeekCurrent)
	 := [ : +]
	 := [+ : ++]
	 := [++ : +++]
	.Seek(++, io.SeekCurrent)

	 := iimporter{
		version: int(),
		ipath:   ,
		insert:  ,

		stringData:  ,
		stringCache: make(map[uint64]string),
		fileOffset:  ,
		fileData:    ,
		fileCache:   make([]*token.File, len()),
		pkgCache:    make(map[uint64]*types.Package),

		declData: ,
		pkgIndex: make(map[*types.Package]map[string]uint64),
		typCache: make(map[uint64]types.Type),
		// Separate map for typeparams, keyed by their package and unique
		// name.
		tparamIndex: make(map[ident]types.Type),

		fake: fakeFileSet{
			fset:  ,
			files: make(map[string]*fileInfo),
		},
	}
	defer .fake.setLines() // set lines for files in fset

	for ,  := range predeclared() {
		.typCache[uint64()] = 
	}

	 := make([]*types.Package, .uint64())
	for  := range  {
		 := .uint64()
		 := .stringAt()
		 := .stringAt(.uint64())
		_ = .uint64() // package height; unused by go/types

		if  == "" {
			 = 
		}
		 := []
		if  == nil {
			 = types.NewPackage(, )
			[] = 
		} else if .Name() !=  {
			errorf("conflicting names %s and %s for package %q", .Name(), , )
		}
		if  == 0 && ! {
			.localpkg = 
		}

		.pkgCache[] = 

		// Read index for package.
		 := make(map[string]uint64)
		 := .uint64()
		// In shallow mode we don't expect an index for other packages.
		assert( == 0 || .localpkg ==  || .insert == nil)
		for ;  > 0; -- {
			 := .stringAt(.uint64())
			[] = .uint64()
		}

		.pkgIndex[] = 
		[] = 
	}

	if  {
		 = make([]*types.Package, .uint64())
		for  := range  {
			 := .pkgAt(.uint64())
			 := make([]*types.Package, .uint64())
			for  := range  {
				[] = .pkgAt(.uint64())
			}
			.SetImports()
			[] = 
		}
	} else {
		if len() == 0 {
			errorf("no packages found for %s", )
			panic("unreachable")
		}
		 = [:1]

		// record all referenced packages as imports
		 := append(([]*types.Package)(nil), [1:]...)
		sort.Sort(byPath())
		[0].SetImports()
	}

	for ,  := range  {
		if .Complete() {
			continue
		}

		 := make([]string, 0, len(.pkgIndex[]))
		for  := range .pkgIndex[] {
			 = append(, )
		}
		sort.Strings()
		for ,  := range  {
			.doDecl(, )
		}

		// package was imported completely and without errors
		.MarkComplete()
	}

	// SetConstraint can't be called if the constraint type is not yet complete.
	// When type params are created in the 'P' case of (*importReader).obj(),
	// the associated constraint type may not be complete due to recursion.
	// Therefore, we defer calling SetConstraint there, and call it here instead
	// after all types are complete.
	for ,  := range .later {
		typeparams.SetTypeParamConstraint(.t, .constraint)
	}

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

	return , nil
}

type setConstraintArgs struct {
	t          *typeparams.TypeParam
	constraint types.Type
}

type iimporter struct {
	version int
	ipath   string

	localpkg *types.Package
	insert   func(pkg *types.Package, name string) // "shallow" mode only

	stringData  []byte
	stringCache map[uint64]string
	fileOffset  []uint64 // fileOffset[i] is offset in fileData for info about file encoded as i
	fileData    []byte
	fileCache   []*token.File // memoized decoding of file encoded as i
	pkgCache    map[uint64]*types.Package

	declData    []byte
	pkgIndex    map[*types.Package]map[string]uint64
	typCache    map[uint64]types.Type
	tparamIndex map[ident]types.Type

	fake          fakeFileSet
	interfaceList []*types.Interface

	// Arguments for calls to SetConstraint that are deferred due to recursive types
	later []setConstraintArgs

	indent int // for tracing support
}

func ( *iimporter) ( string,  ...interface{}) {
	if !trace {
		// Call sites should also be guarded, but having this check here allows
		// easily enabling/disabling debug trace statements.
		return
	}
	fmt.Printf(strings.Repeat("..", .indent)++"\n", ...)
}

func ( *iimporter) ( *types.Package,  string) {
	if debug {
		.trace("import decl %s", )
		.indent++
		defer func() {
			.indent--
			.trace("=> %s", )
		}()
	}
	// See if we've already imported this declaration.
	if  := .Scope().Lookup();  != nil {
		return
	}

	,  := .pkgIndex[][]
	if ! {
		// In "shallow" mode, call back to the application to
		// find the object and insert it into the package scope.
		if .insert != nil {
			assert( != .localpkg)
			.insert(, ) // "can't fail"
			return
		}
		errorf("%v.%v not in index", , )
	}

	 := &importReader{p: , currPkg: }
	.declReader.Reset(.declData[:])

	.obj()
}

func ( *iimporter) ( uint64) string {
	if ,  := .stringCache[];  {
		return 
	}

	,  := binary.Uvarint(.stringData[:])
	if  <= 0 {
		errorf("varint failed")
	}
	 :=  + uint64()
	 := string(.stringData[ : +])
	.stringCache[] = 
	return 
}

func ( *iimporter) ( uint64) *token.File {
	 := .fileCache[]
	if  == nil {
		 := .fileOffset[]
		 = .decodeFile(intReader{bytes.NewReader(.fileData[:]), .ipath})
		.fileCache[] = 
	}
	return 
}

func ( *iimporter) ( intReader) *token.File {
	 := .stringAt(.uint64())
	 := int(.uint64())
	 := .fake.fset.AddFile(, -1, )

	// SetLines requires a nondecreasing sequence.
	// Because it is common for clients to derive the interval
	// [start, start+len(name)] from a start position, and we
	// want to ensure that the end offset is on the same line,
	// we fill in the gaps of the sparse encoding with values
	// that strictly increase by the largest possible amount.
	// This allows us to avoid having to record the actual end
	// offset of each needed line.

	 := make([]int, int(.uint64()))
	var ,  int
	for ,  := 0, int(.uint64());  < ; ++ {
		 += int(.uint64())
		 += int(.uint64())
		[] = 

		// Ensure monotonicity between points.
		for  :=  - 1;  > 0 && [] == 0; -- {
			[] = [+1] - 1
		}
	}

	// Ensure monotonicity after last point.
	for  := len() - 1;  > 0 && [] == 0; -- {
		--
		[] = 
	}

	if !.SetLines() {
		errorf("SetLines failed: %d", ) // can't happen
	}
	return 
}

func ( *iimporter) ( uint64) *types.Package {
	if ,  := .pkgCache[];  {
		return 
	}
	 := .stringAt()
	errorf("missing package %q in %q", , .ipath)
	return nil
}

func ( *iimporter) ( uint64,  *types.Named) types.Type {
	if ,  := .typCache[];  && canReuse(, ) {
		return 
	}

	if  < predeclReserved {
		errorf("predeclared type missing from cache: %v", )
	}

	 := &importReader{p: }
	.declReader.Reset(.declData[-predeclReserved:])
	 := .doType()

	if canReuse(, ) {
		.typCache[] = 
	}
	return 
}

// canReuse reports whether the type rhs on the RHS of the declaration for def
// may be re-used.
//
// Specifically, if def is non-nil and rhs is an interface type with methods, it
// may not be re-used because we have a convention of setting the receiver type
// for interface methods to def.
func ( *types.Named,  types.Type) bool {
	if  == nil {
		return true
	}
	,  := .(*types.Interface)
	if  == nil {
		return true
	}
	// Don't use iface.Empty() here as iface may not be complete.
	return .NumEmbeddeds() == 0 && .NumExplicitMethods() == 0
}

type importReader struct {
	p          *iimporter
	declReader bytes.Reader
	currPkg    *types.Package
	prevFile   string
	prevLine   int64
	prevColumn int64
}

func ( *importReader) ( string) {
	 := .byte()
	 := .pos()

	switch  {
	case 'A':
		 := .typ()

		.declare(types.NewTypeName(, .currPkg, , ))

	case 'C':
		,  := .value()

		.declare(types.NewConst(, .currPkg, , , ))

	case 'F', 'G':
		var  []*typeparams.TypeParam
		if  == 'G' {
			 = .tparamList()
		}
		 := .signature(nil, nil, )
		.declare(types.NewFunc(, .currPkg, , ))

	case 'T', 'U':
		// Types can be recursive. We need to setup a stub
		// declaration before recursing.
		 := types.NewTypeName(, .currPkg, , nil)
		 := types.NewNamed(, nil, nil)
		// Declare obj before calling r.tparamList, so the new type name is recognized
		// if used in the constraint of one of its own typeparams (see #48280).
		.declare()
		if  == 'U' {
			 := .tparamList()
			typeparams.SetForNamed(, )
		}

		 := .p.typAt(.uint64(), ).Underlying()
		.SetUnderlying()

		if !isInterface() {
			for  := .uint64();  > 0; -- {
				 := .pos()
				 := .ident()
				 := .param()

				// If the receiver has any targs, set those as the
				// rparams of the method (since those are the
				// typeparams being used in the method sig/body).
				 := baseType(.Type())
				assert( != nil)
				 := typeparams.NamedTypeArgs()
				var  []*typeparams.TypeParam
				if .Len() > 0 {
					 = make([]*typeparams.TypeParam, .Len())
					for  := range  {
						[] = .At().(*typeparams.TypeParam)
					}
				}
				 := .signature(, , nil)

				.AddMethod(types.NewFunc(, .currPkg, , ))
			}
		}

	case 'P':
		// We need to "declare" a typeparam in order to have a name that
		// can be referenced recursively (if needed) in the type param's
		// bound.
		if .p.version < iexportVersionGenerics {
			errorf("unexpected type param type")
		}
		 := tparamName()
		 := types.NewTypeName(, .currPkg, , nil)
		 := typeparams.NewTypeParam(, nil)

		// To handle recursive references to the typeparam within its
		// bound, save the partial type in tparamIndex before reading the bounds.
		 := ident{.currPkg, }
		.p.tparamIndex[] = 
		var  bool
		if .p.version >= iexportVersionGo1_18 {
			 = .bool()
		}
		 := .typ()
		if  {
			,  := .(*types.Interface)
			if  == nil {
				errorf("non-interface constraint marked implicit")
			}
			typeparams.MarkImplicit()
		}
		// The constraint type may not be complete, if we
		// are in the middle of a type recursion involving type
		// constraints. So, we defer SetConstraint until we have
		// completely set up all types in ImportData.
		.p.later = append(.p.later, setConstraintArgs{t: , constraint: })

	case 'V':
		 := .typ()

		.declare(types.NewVar(, .currPkg, , ))

	default:
		errorf("unexpected tag: %v", )
	}
}

func ( *importReader) ( types.Object) {
	.Pkg().Scope().Insert()
}

func ( *importReader) () ( types.Type,  constant.Value) {
	 = .typ()
	if .p.version >= iexportVersionGo1_18 {
		// TODO: add support for using the kind.
		_ = constant.Kind(.int64())
	}

	switch  := .Underlying().(*types.Basic); .Info() & types.IsConstType {
	case types.IsBoolean:
		 = constant.MakeBool(.bool())

	case types.IsString:
		 = constant.MakeString(.string())

	case types.IsInteger:
		var  big.Int
		.mpint(&, )
		 = constant.Make(&)

	case types.IsFloat:
		 = .mpfloat()

	case types.IsComplex:
		 := .mpfloat()
		 := .mpfloat()
		 = constant.BinaryOp(, token.ADD, constant.MakeImag())

	default:
		if .Kind() == types.Invalid {
			 = constant.MakeUnknown()
			return
		}
		errorf("unexpected type %v", ) // panics
		panic("unreachable")
	}

	return
}

func ( *types.Basic) ( bool,  uint) {
	if (.Info() & types.IsUntyped) != 0 {
		return true, 64
	}

	switch .Kind() {
	case types.Float32, types.Complex64:
		return true, 3
	case types.Float64, types.Complex128:
		return true, 7
	}

	 = (.Info() & types.IsUnsigned) == 0
	switch .Kind() {
	case types.Int8, types.Uint8:
		 = 1
	case types.Int16, types.Uint16:
		 = 2
	case types.Int32, types.Uint32:
		 = 4
	default:
		 = 8
	}

	return
}

func ( *importReader) ( *big.Int,  *types.Basic) {
	,  := intSize()

	 := 256 - 
	if  {
		 = 256 - 2*
	}
	if  == 1 {
		 = 256
	}

	,  := .declReader.ReadByte()
	if uint() <  {
		 := int64()
		if  {
			 >>= 1
			if &1 != 0 {
				 = ^
			}
		}
		.SetInt64()
		return
	}

	 := -
	if  {
		 = -( &^ 1) >> 1
	}
	if  < 1 || uint() >  {
		errorf("weird decoding: %v, %v => %v", , , )
	}
	 := make([]byte, )
	io.ReadFull(&.declReader, )
	.SetBytes()
	if  && &1 != 0 {
		.Neg()
	}
}

func ( *importReader) ( *types.Basic) constant.Value {
	var  big.Int
	.mpint(&, )
	var  big.Float
	.SetInt(&)
	if .Sign() != 0 {
		.SetMantExp(&, int(.int64()))
	}
	return constant.Make(&)
}

func ( *importReader) () string {
	return .string()
}

func ( *importReader) () (*types.Package, string) {
	 := .string()
	 := .pkg()
	return , 
}

func ( *importReader) () token.Pos {
	if .p.insert != nil { // shallow mode
		return .posv2()
	}
	if .p.version >= iexportVersionPosCol {
		.posv1()
	} else {
		.posv0()
	}

	if .prevFile == "" && .prevLine == 0 && .prevColumn == 0 {
		return token.NoPos
	}
	return .p.fake.pos(.prevFile, int(.prevLine), int(.prevColumn))
}

func ( *importReader) () {
	 := .int64()
	if  != deltaNewFile {
		.prevLine += 
	} else if  := .int64();  == -1 {
		.prevLine += deltaNewFile
	} else {
		.prevFile = .string()
		.prevLine = 
	}
}

func ( *importReader) () {
	 := .int64()
	.prevColumn +=  >> 1
	if &1 != 0 {
		 = .int64()
		.prevLine +=  >> 1
		if &1 != 0 {
			.prevFile = .string()
		}
	}
}

func ( *importReader) () token.Pos {
	 := .uint64()
	if  == 0 {
		return token.NoPos
	}
	 := .p.fileAt( - 1)
	return .Pos(int(.uint64()))
}

func ( *importReader) () types.Type {
	return .p.typAt(.uint64(), nil)
}

func ( types.Type) bool {
	,  := .(*types.Interface)
	return 
}

func ( *importReader) () *types.Package { return .p.pkgAt(.uint64()) }
func ( *importReader) () string      { return .p.stringAt(.uint64()) }

func ( *importReader) ( *types.Named) ( types.Type) {
	 := .kind()
	if debug {
		.p.trace("importing type %d (base: %s)", , )
		.p.indent++
		defer func() {
			.p.indent--
			.p.trace("=> %s", )
		}()
	}
	switch  {
	default:
		errorf("unexpected kind tag in %q: %v", .p.ipath, )
		return nil

	case definedType:
		,  := .qualifiedIdent()
		.p.doDecl(, )
		return .Scope().Lookup().(*types.TypeName).Type()
	case pointerType:
		return types.NewPointer(.typ())
	case sliceType:
		return types.NewSlice(.typ())
	case arrayType:
		 := .uint64()
		return types.NewArray(.typ(), int64())
	case chanType:
		 := chanDir(int(.uint64()))
		return types.NewChan(, .typ())
	case mapType:
		return types.NewMap(.typ(), .typ())
	case signatureType:
		.currPkg = .pkg()
		return .signature(nil, nil, nil)

	case structType:
		.currPkg = .pkg()

		 := make([]*types.Var, .uint64())
		 := make([]string, len())
		for  := range  {
			 := .pos()
			 := .ident()
			 := .typ()
			 := .bool()
			 := .string()

			[] = types.NewField(, .currPkg, , , )
			[] = 
		}
		return types.NewStruct(, )

	case interfaceType:
		.currPkg = .pkg()

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

		 := make([]*types.Func, .uint64())
		for  := range  {
			 := .pos()
			 := .ident()

			// TODO(mdempsky): Matches bimport.go, but I
			// don't agree with this.
			var  *types.Var
			if  != nil {
				 = types.NewVar(token.NoPos, .currPkg, "", )
			}

			 := .signature(, nil, nil)
			[] = types.NewFunc(, .currPkg, , )
		}

		 := newInterface(, )
		.p.interfaceList = append(.p.interfaceList, )
		return 

	case typeParamType:
		if .p.version < iexportVersionGenerics {
			errorf("unexpected type param type")
		}
		,  := .qualifiedIdent()
		 := ident{, }
		if ,  := .p.tparamIndex[];  {
			// We're already in the process of importing this typeparam.
			return 
		}
		// Otherwise, import the definition of the typeparam now.
		.p.doDecl(, )
		return .p.tparamIndex[]

	case instanceType:
		if .p.version < iexportVersionGenerics {
			errorf("unexpected instantiation type")
		}
		// pos does not matter for instances: they are positioned on the original
		// type.
		_ = .pos()
		 := .uint64()
		 := make([]types.Type, )
		for  := range  {
			[] = .typ()
		}
		 := .typ()
		// The imported instantiated type doesn't include any methods, so
		// we must always use the methods of the base (orig) type.
		// TODO provide a non-nil *Environment
		,  := typeparams.Instantiate(nil, , , false)
		return 

	case unionType:
		if .p.version < iexportVersionGenerics {
			errorf("unexpected instantiation type")
		}
		 := make([]*typeparams.Term, .uint64())
		for  := range  {
			[] = typeparams.NewTerm(.bool(), .typ())
		}
		return typeparams.NewUnion()
	}
}

func ( *importReader) () itag {
	return itag(.uint64())
}

func ( *importReader) ( *types.Var,  []*typeparams.TypeParam,  []*typeparams.TypeParam) *types.Signature {
	 := .paramList()
	 := .paramList()
	 := .Len() > 0 && .bool()
	return typeparams.NewSignatureType(, , , , , )
}

func ( *importReader) () []*typeparams.TypeParam {
	 := .uint64()
	if  == 0 {
		return nil
	}
	 := make([]*typeparams.TypeParam, )
	for  := range  {
		// Note: the standard library importer is tolerant of nil types here,
		// though would panic in SetTypeParams.
		[] = .typ().(*typeparams.TypeParam)
	}
	return 
}

func ( *importReader) () *types.Tuple {
	 := make([]*types.Var, .uint64())
	for  := range  {
		[] = .param()
	}
	return types.NewTuple(...)
}

func ( *importReader) () *types.Var {
	 := .pos()
	 := .ident()
	 := .typ()
	return types.NewParam(, .currPkg, , )
}

func ( *importReader) () bool {
	return .uint64() != 0
}

func ( *importReader) () int64 {
	,  := binary.ReadVarint(&.declReader)
	if  != nil {
		errorf("readVarint: %v", )
	}
	return 
}

func ( *importReader) () uint64 {
	,  := binary.ReadUvarint(&.declReader)
	if  != nil {
		errorf("readUvarint: %v", )
	}
	return 
}

func ( *importReader) () byte {
	,  := .declReader.ReadByte()
	if  != nil {
		errorf("declReader.ReadByte: %v", )
	}
	return 
}

func ( types.Type) *types.Named {
	// pointer receivers are never types.Named types
	if ,  := .(*types.Pointer);  != nil {
		 = .Elem()
	}
	// receiver base types are always (possibly generic) types.Named types
	,  := .(*types.Named)
	return 
}