// 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 (
	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/typecheck"
	"cmd/compile/internal/types"
	"cmd/compile/internal/types2"
	"cmd/internal/src"
	"strings"
)

func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
	switch pkg {
	case nil:
		return types.BuiltinPkg
	case g.self:
		return types.LocalPkg
	case types2.Unsafe:
		return types.UnsafePkg
	}
	return types.NewPkg(pkg.Path(), pkg.Name())
}

// typ converts a types2.Type to a types.Type, including caching of previously
// translated types.
func (g *irgen) typ(typ types2.Type) *types.Type {
	// Defer the CheckSize calls until we have fully-defined a
	// (possibly-recursive) top-level type.
	types.DeferCheckSize()
	res := g.typ1(typ)
	types.ResumeCheckSize()

	// Finish up any types on typesToFinalize, now that we are at the top of a
	// fully-defined (possibly recursive) type. fillinMethods could create more
	// types to finalize.
	for len(g.typesToFinalize) > 0 {
		l := len(g.typesToFinalize)
		info := g.typesToFinalize[l-1]
		g.typesToFinalize = g.typesToFinalize[:l-1]
		g.fillinMethods(info.typ, info.ntyp)
	}
	return res
}

// typ1 is like typ, but doesn't call CheckSize, since it may have only
// constructed part of a recursive type. Should not be called from outside this
// file (g.typ is the "external" entry point).
func (g *irgen) typ1(typ types2.Type) *types.Type {
	// Cache type2-to-type mappings. Important so that each defined generic
	// type (instantiated or not) has a single types.Type representation.
	// Also saves a lot of computation and memory by avoiding re-translating
	// types2 types repeatedly.
	res, ok := g.typs[typ]
	if !ok {
		res = g.typ0(typ)
		// Calculate the size for all concrete types seen by the frontend.
		// This is the replacement for the CheckSize() calls in the types1
		// typechecker. These will be deferred until the top-level g.typ().
		if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
			types.CheckSize(res)
		}
		g.typs[typ] = res
	}
	return res
}

// instTypeName2 creates a name for an instantiated type, base on the type args
// (given as types2 types).
func (g *irgen) instTypeName2(name string, targs *types2.TypeList) string {
	rparams := make([]*types.Type, targs.Len())
	for i := range rparams {
		rparams[i] = g.typ(targs.At(i))
	}
	return typecheck.InstTypeName(name, rparams)
}

// typ0 converts a types2.Type to a types.Type, but doesn't do the caching check
// at the top level.
func (g *irgen) typ0(typ types2.Type) *types.Type {
	switch typ := typ.(type) {
	case *types2.Basic:
		return g.basic(typ)
	case *types2.Named:
		// If tparams is set, but targs is not, typ is a base generic
		// type. typ is appearing as part of the source type of an alias,
		// since that is the only use of a generic type that doesn't
		// involve instantiation. We just translate the named type in the
		// normal way below using g.obj().
		if typ.TypeParams() != nil && typ.TypeArgs() != nil {
			// typ is an instantiation of a defined (named) generic type.
			// This instantiation should also be a defined (named) type.
			// types2 gives us the substituted type in t.Underlying()
			// The substituted type may or may not still have type
			// params. We might, for example, be substituting one type
			// param for another type param.
			//
			// When converted to types.Type, typ has a unique name,
			// based on the names of the type arguments.
			instName := g.instTypeName2(typ.Obj().Name(), typ.TypeArgs())
			s := g.pkg(typ.Obj().Pkg()).Lookup(instName)
			if s.Def != nil {
				// We have already encountered this instantiation.
				// Use the type we previously created, since there
				// must be exactly one instance of a defined type.
				return s.Def.Type()
			}

			// Make sure the base generic type exists in type1 (it may
			// not yet if we are referecing an imported generic type, as
			// opposed to a generic type declared in this package).
			_ = g.obj(typ.Orig().Obj())

			// Create a forwarding type first and put it in the g.typs
			// map, in order to deal with recursive generic types
			// (including via method signatures). Set up the extra
			// ntyp information (Def, RParams, which may set
			// HasTParam) before translating the underlying type
			// itself, so we handle recursion correctly.
			ntyp := typecheck.NewIncompleteNamedType(g.pos(typ.Obj().Pos()), s)
			g.typs[typ] = ntyp

			// If ntyp still has type params, then we must be
			// referencing something like 'value[T2]', as when
			// specifying the generic receiver of a method, where
			// value was defined as "type value[T any] ...". Save the
			// type args, which will now be the new typeparams of the
			// current type.
			//
			// If ntyp does not have type params, we are saving the
			// non-generic types used to instantiate this type. We'll
			// use these when instantiating the methods of the
			// instantiated type.
			targs := typ.TypeArgs()
			rparams := make([]*types.Type, targs.Len())
			for i := range rparams {
				rparams[i] = g.typ1(targs.At(i))
			}
			ntyp.SetRParams(rparams)
			//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())

			// Save the symbol for the base generic type.
			ntyp.SetOrigSym(g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name()))
			ntyp.SetUnderlying(g.typ1(typ.Underlying()))
			if typ.NumMethods() != 0 {
				// Save a delayed call to g.fillinMethods() (once
				// potentially recursive types have been fully
				// resolved).
				g.typesToFinalize = append(g.typesToFinalize,
					&typeDelayInfo{
						typ:  typ,
						ntyp: ntyp,
					})
			}
			return ntyp
		}
		obj := g.obj(typ.Obj())
		if obj.Op() != ir.OTYPE {
			base.FatalfAt(obj.Pos(), "expected type: %L", obj)
		}
		return obj.Type()

	case *types2.Array:
		return types.NewArray(g.typ1(typ.Elem()), typ.Len())
	case *types2.Chan:
		return types.NewChan(g.typ1(typ.Elem()), dirs[typ.Dir()])
	case *types2.Map:
		return types.NewMap(g.typ1(typ.Key()), g.typ1(typ.Elem()))
	case *types2.Pointer:
		return types.NewPtr(g.typ1(typ.Elem()))
	case *types2.Signature:
		return g.signature(nil, typ)
	case *types2.Slice:
		return types.NewSlice(g.typ1(typ.Elem()))

	case *types2.Struct:
		fields := make([]*types.Field, typ.NumFields())
		for i := range fields {
			v := typ.Field(i)
			f := types.NewField(g.pos(v), g.selector(v), g.typ1(v.Type()))
			f.Note = typ.Tag(i)
			if v.Embedded() {
				f.Embedded = 1
			}
			fields[i] = f
		}
		return types.NewStruct(g.tpkg(typ), fields)

	case *types2.Interface:
		embeddeds := make([]*types.Field, typ.NumEmbeddeds())
		j := 0
		for i := range embeddeds {
			// TODO(mdempsky): Get embedding position.
			e := typ.EmbeddedType(i)

			// With Go 1.18, an embedded element can be any type, not
			// just an interface.
			embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e))
			j++
		}
		embeddeds = embeddeds[:j]

		methods := make([]*types.Field, typ.NumExplicitMethods())
		for i := range methods {
			m := typ.ExplicitMethod(i)
			mtyp := g.signature(types.FakeRecv(), m.Type().(*types2.Signature))
			methods[i] = types.NewField(g.pos(m), g.selector(m), mtyp)
		}

		return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...))

	case *types2.TypeParam:
		// Save the name of the type parameter in the sym of the type.
		// Include the types2 subscript in the sym name
		pkg := g.tpkg(typ)
		sym := pkg.Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" }))
		if sym.Def != nil {
			// Make sure we use the same type param type for the same
			// name, whether it is created during types1-import or
			// this types2-to-types1 translation.
			return sym.Def.Type()
		}
		tp := types.NewTypeParam(sym, typ.Index())
		nname := ir.NewDeclNameAt(g.pos(typ.Obj().Pos()), ir.OTYPE, sym)
		sym.Def = nname
		nname.SetType(tp)
		tp.SetNod(nname)
		// Set g.typs[typ] in case the bound methods reference typ.
		g.typs[typ] = tp

		bound := g.typ1(typ.Constraint())
		tp.SetBound(bound)
		return tp

	case *types2.Union:
		nt := typ.Len()
		tlist := make([]*types.Type, nt)
		tildes := make([]bool, nt)
		for i := range tlist {
			t := typ.Term(i)
			tlist[i] = g.typ1(t.Type())
			tildes[i] = t.Tilde()
		}
		return types.NewUnion(tlist, tildes)

	case *types2.Tuple:
		// Tuples are used for the type of a function call (i.e. the
		// return value of the function).
		if typ == nil {
			return (*types.Type)(nil)
		}
		fields := make([]*types.Field, typ.Len())
		for i := range fields {
			fields[i] = g.param(typ.At(i))
		}
		t := types.NewStruct(types.LocalPkg, fields)
		t.StructType().Funarg = types.FunargResults
		return t

	default:
		base.FatalfAt(src.NoXPos, "unhandled type: %v (%T)", typ, typ)
		panic("unreachable")
	}
}

// fillinMethods fills in the method name nodes and types for a defined type with at
// least one method. This is needed for later typechecking when looking up methods of
// instantiated types, and for actually generating the methods for instantiated
// types.
func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
	targs2 := typ.TypeArgs()
	targs := make([]*types.Type, targs2.Len())
	for i := range targs {
		targs[i] = g.typ1(targs2.At(i))
	}

	methods := make([]*types.Field, typ.NumMethods())
	for i := range methods {
		m := typ.Method(i)
		recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
		var meth *ir.Name
		if m.Pkg() != g.self {
			// Imported methods cannot be loaded by name (what
			// g.obj() does) - they must be loaded via their
			// type.
			meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
		} else {
			meth = g.obj(m)
		}
		if recvType != types2.Type(typ) {
			// Unfortunately, meth is the type of the method of the
			// generic type, so we have to do a substitution to get
			// the name/type of the method of the instantiated type,
			// using m.Type().RParams() and typ.TArgs()
			inst2 := g.instTypeName2("", typ.TypeArgs())
			name := meth.Sym().Name
			i1 := strings.Index(name, "[")
			i2 := strings.Index(name[i1:], "]")
			assert(i1 >= 0 && i2 >= 0)
			// Generate the name of the instantiated method.
			name = name[0:i1] + inst2 + name[i1+i2+1:]
			newsym := meth.Sym().Pkg.Lookup(name)
			var meth2 *ir.Name
			if newsym.Def != nil {
				meth2 = newsym.Def.(*ir.Name)
			} else {
				meth2 = ir.NewNameAt(meth.Pos(), newsym)
				rparams := types2.AsSignature(m.Type()).RecvTypeParams()
				tparams := make([]*types.Type, rparams.Len())
				for i := range tparams {
					tparams[i] = g.typ1(rparams.At(i))
				}
				assert(len(tparams) == len(targs))
				ts := typecheck.Tsubster{
					Tparams: tparams,
					Targs:   targs,
				}
				// Do the substitution of the type
				meth2.SetType(ts.Typ(meth.Type()))
				newsym.Def = meth2
			}
			meth = meth2
		}
		methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
		methods[i].Nname = meth
	}
	ntyp.Methods().Set(methods)
	if !ntyp.HasTParam() && !ntyp.HasShape() {
		// Generate all the methods for a new fully-instantiated type.
		typecheck.NeedInstType(ntyp)
	}
}

func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {
	tparams2 := sig.TypeParams()
	tparams := make([]*types.Field, tparams2.Len())
	for i := range tparams {
		tp := tparams2.At(i).Obj()
		tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ1(tp.Type()))
	}

	do := func(typ *types2.Tuple) []*types.Field {
		fields := make([]*types.Field, typ.Len())
		for i := range fields {
			fields[i] = g.param(typ.At(i))
		}
		return fields
	}
	params := do(sig.Params())
	results := do(sig.Results())
	if sig.Variadic() {
		params[len(params)-1].SetIsDDD(true)
	}

	return types.NewSignature(g.tpkg(sig), recv, tparams, params, results)
}

func (g *irgen) param(v *types2.Var) *types.Field {
	return types.NewField(g.pos(v), g.sym(v), g.typ1(v.Type()))
}

func (g *irgen) sym(obj types2.Object) *types.Sym {
	if name := obj.Name(); name != "" {
		return g.pkg(obj.Pkg()).Lookup(obj.Name())
	}
	return nil
}

func (g *irgen) selector(obj types2.Object) *types.Sym {
	pkg, name := g.pkg(obj.Pkg()), obj.Name()
	if types.IsExported(name) {
		pkg = types.LocalPkg
	}
	return pkg.Lookup(name)
}

// tpkg returns the package that a function, interface, struct, or typeparam type
// expression appeared in.
//
// Caveat: For the degenerate types "func()", "interface{}", and
// "struct{}", tpkg always returns LocalPkg. However, we only need the
// package information so that go/types can report it via its API, and
// the reason we fail to return the original package for these
// particular types is because go/types does *not* report it for
// them. So in practice this limitation is probably moot.
func (g *irgen) tpkg(typ types2.Type) *types.Pkg {
	if obj := anyObj(typ); obj != nil {
		return g.pkg(obj.Pkg())
	}
	return types.LocalPkg
}

// anyObj returns some object accessible from typ, if any.
func anyObj(typ types2.Type) types2.Object {
	switch typ := typ.(type) {
	case *types2.Signature:
		if recv := typ.Recv(); recv != nil {
			return recv
		}
		if params := typ.Params(); params.Len() > 0 {
			return params.At(0)
		}
		if results := typ.Results(); results.Len() > 0 {
			return results.At(0)
		}
	case *types2.Struct:
		if typ.NumFields() > 0 {
			return typ.Field(0)
		}
	case *types2.Interface:
		if typ.NumExplicitMethods() > 0 {
			return typ.ExplicitMethod(0)
		}
	case *types2.TypeParam:
		return typ.Obj()
	}
	return nil
}

func (g *irgen) basic(typ *types2.Basic) *types.Type {
	switch typ.Name() {
	case "byte":
		return types.ByteType
	case "rune":
		return types.RuneType
	}
	return *basics[typ.Kind()]
}

var basics = [...]**types.Type{
	types2.Invalid:        new(*types.Type),
	types2.Bool:           &types.Types[types.TBOOL],
	types2.Int:            &types.Types[types.TINT],
	types2.Int8:           &types.Types[types.TINT8],
	types2.Int16:          &types.Types[types.TINT16],
	types2.Int32:          &types.Types[types.TINT32],
	types2.Int64:          &types.Types[types.TINT64],
	types2.Uint:           &types.Types[types.TUINT],
	types2.Uint8:          &types.Types[types.TUINT8],
	types2.Uint16:         &types.Types[types.TUINT16],
	types2.Uint32:         &types.Types[types.TUINT32],
	types2.Uint64:         &types.Types[types.TUINT64],
	types2.Uintptr:        &types.Types[types.TUINTPTR],
	types2.Float32:        &types.Types[types.TFLOAT32],
	types2.Float64:        &types.Types[types.TFLOAT64],
	types2.Complex64:      &types.Types[types.TCOMPLEX64],
	types2.Complex128:     &types.Types[types.TCOMPLEX128],
	types2.String:         &types.Types[types.TSTRING],
	types2.UnsafePointer:  &types.Types[types.TUNSAFEPTR],
	types2.UntypedBool:    &types.UntypedBool,
	types2.UntypedInt:     &types.UntypedInt,
	types2.UntypedRune:    &types.UntypedRune,
	types2.UntypedFloat:   &types.UntypedFloat,
	types2.UntypedComplex: &types.UntypedComplex,
	types2.UntypedString:  &types.UntypedString,
	types2.UntypedNil:     &types.Types[types.TNIL],
}

var dirs = [...]types.ChanDir{
	types2.SendRecv: types.Cboth,
	types2.SendOnly: types.Csend,
	types2.RecvOnly: types.Crecv,
}

// deref2 does a single deref of types2 type t, if it is a pointer type.
func deref2(t types2.Type) types2.Type {
	if ptr := types2.AsPointer(t); ptr != nil {
		t = ptr.Elem()
	}
	return t
}
