diff --git a/builtin_test.go b/builtin_test.go index c240a380..c2278806 100644 --- a/builtin_test.go +++ b/builtin_test.go @@ -44,6 +44,14 @@ func getConf() *Config { return &Config{Fset: fset, Importer: imp} } +func TestSetTypeParams(t *testing.T) { + pkg := types.NewPackage("", "") + tn := types.NewTypeName(0, pkg, "foo__1", nil) + named := types.NewNamed(tn, TyByte, nil) + + setTypeParams(nil, named, &ast.TypeSpec{}, nil) +} + func TestOverloadNameds(t *testing.T) { pkg := types.NewPackage("", "") tn := types.NewTypeName(0, pkg, "foo__1", nil) diff --git a/type_var_and_const.go b/type_var_and_const.go index 4bd001b4..4329f2c6 100644 --- a/type_var_and_const.go +++ b/type_var_and_const.go @@ -103,7 +103,9 @@ func (p *TypeDecl) InitType(pkg *Package, typ types.Type, tparams ...*TypeParam) } else { p.typ.SetUnderlying(typ) } - setTypeParams(pkg, p.typ, spec, tparams) + if tparams != nil { + setTypeParams(pkg, p.typ, spec, tparams) + } spec.Type = toType(pkg, typ) return p.typ } diff --git a/typeparams.go b/typeparams.go index 589570fd..b08671f8 100644 --- a/typeparams.go +++ b/typeparams.go @@ -445,14 +445,29 @@ func interfaceIsImplicit(t *types.Interface) bool { func (p *Package) Instantiate(orig types.Type, targs []types.Type, src ...ast.Node) types.Type { p.cb.ensureLoaded(orig) + for _, targ := range targs { + p.cb.ensureLoaded(targ) + } + ctxt := p.cb.ctxt + if on, ok := orig.(*TyOverloadNamed); ok { + var first error + for _, t := range on.Types { + ret, err := types.Instantiate(ctxt, t, targs, true) + if err == nil { + return ret + } + if first == nil { + first = err + } + } + p.cb.handleCodeError(getPos(src), first.Error()) + return types.Typ[types.Invalid] + } if !isGenericType(orig) { p.cb.handleCodeErrorf(getPos(src), "%v is not a generic type", orig) return types.Typ[types.Invalid] } - for _, targ := range targs { - p.cb.ensureLoaded(targ) - } - ret, err := types.Instantiate(p.cb.ctxt, orig, targs, true) + ret, err := types.Instantiate(ctxt, orig, targs, true) if err != nil { p.cb.handleCodeError(getPos(src), err.Error()) } diff --git a/typeparams_test.go b/typeparams_test.go index 671d224c..be2d30f0 100644 --- a/typeparams_test.go +++ b/typeparams_test.go @@ -31,6 +31,8 @@ func TestOverloadNamed(t *testing.T) { const GopPackage = true +type M = map[string]any + type basetype interface { string | int | bool | float64 } @@ -38,6 +40,10 @@ type basetype interface { type Var__0[T basetype] struct { val T } + +type Var__1[T map[string]any] struct { + val T +} ` gt := newGoxTest() _, err := gt.LoadGoPackage("foo", "foo.go", src) @@ -56,6 +62,29 @@ type Var__0[T basetype] struct { if on.Types[0].TypeParams() == nil { t.Fatal("TestOverloadNamed: not generic") } + + tyInt := types.Typ[types.Int] + tyM := pkgRef.Ref("M").Type() + ty1 := pkg.Instantiate(on, []types.Type{tyInt}) + ty2 := pkg.Instantiate(on, []types.Type{tyM}) + pkg.NewTypeDefs().NewType("t1").InitType(pkg, ty1) + pkg.NewTypeDefs().NewType("t2").InitType(pkg, ty2) + + domTest(t, pkg, `package main + +import "foo" + +type t1 foo.Var__0[int] +type t2 foo.Var__1[map[string]any] +`) + + defer func() { + if e := recover(); e == nil { + t.Fatal("TestOverloadNamed failed: no error?") + } + }() + ty3 := pkg.Instantiate(on, []types.Type{gox.TyByte}) + pkg.NewTypeDefs().NewType("t3").InitType(pkg, ty3) } func TestInstantiate(t *testing.T) {