Repository: goplus/gop
Pull request #2208 (2025-03-27 07:29:48)

support gotypesalias
- cl enable gotypesalias by check `builtin/ng.Gop_ninteger` not *types.Basic (*types.Alias)
- cl record alias type
- x/typesutil support alias type
- workflows: TestTypeAlias ( Go1.23/Go1.24 and golang.org/x/tools v0.30 )

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/goplus/gop/pull/2208?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 93.14%. Comparing base [(`931d4e3`)](https://app.codecov.io/gh/goplus/gop/commit/931d4e3ecce1396c5bd9a51d24778ad9b3ac82a0?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus) to head [(`6162ce1`)](https://app.codecov.io/gh/goplus/gop/commit/6162ce1d3e33ff74dd00ee2a971490cc3032fb66?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).
> Report is 2 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #2208      +/-   ##
==========================================
- Coverage   93.14%   93.14%   -0.01%     
==========================================
  Files          34       33       -1     
  Lines       11100    11098       -2     
==========================================
- Hits        10339    10337       -2     
  Misses        605      605              
  Partials      156      156              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/goplus/gop/pull/2208?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index da72df3b..074b7b7c 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -52,3 +52,41 @@ jobs:
       uses: codecov/codecov-action@v5
       with:
         slug: goplus/gop
+
+  TestTypeAlias:
+    strategy:
+      matrix:
+        os:
+        - ubuntu-latest
+        - windows-latest
+        - macos-latest
+        go:
+        - 1.23.x
+        - 1.24.x
+    runs-on: ${{ matrix.os }}
+    steps:
+    - uses: actions/checkout@v4
+
+    - name: Set up Go
+      uses: actions/setup-go@v5
+      with:
+        go-version: ${{ matrix.go }}
+
+    - name: Update golang.org/x/tools
+      run: |
+        go work init .
+        go work edit -replace golang.org/x/tools=golang.org/x/tools@v0.30
+
+    - name: Test Go+ installer
+      run: |
+        git config --global user.email "build-robot@goplus.org"
+        git config --global user.name "build robot"
+        go test -v cmd/make_test.go
+
+    - name: Run testcases
+      run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
+
+    - name: Codecov
+      uses: codecov/codecov-action@v5
+      with:
+        slug: goplus/gop
diff --git a/cl/builtin.go b/cl/builtin.go
index 93445a39..6becb512 100644
--- a/cl/builtin.go
+++ b/cl/builtin.go
@@ -91,6 +91,11 @@ func newBuiltinDefault(pkg *gogen.Package, conf *gogen.Config) *types.Package {
 	pkg.TryImport("strings")
 	if ng.Types != nil {
 		initMathBig(pkg, conf, ng)
+		if obj := ng.Types.Scope().Lookup("Gop_ninteger"); obj != nil {
+			if _, ok := obj.Type().(*types.Basic); !ok {
+				conf.EnableTypesalias = true
+			}
+		}
 	}
 	initBuiltin(pkg, builtin, os, fmt, ng, iox, buil, reflect)
 	gogen.InitBuiltin(pkg, builtin, conf)
diff --git a/cl/compile.go b/cl/compile.go
index 09f3acb2..cc2794fa 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -1040,7 +1040,12 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
 								if debugLoad {
 									log.Println("==> Load > AliasType", name)
 								}
-								defs.AliasType(name, toType(ctx, t.Type), tName)
+								typ := defs.AliasType(name, toType(ctx, t.Type), tName)
+								if rec := ctx.recorder(); rec != nil {
+									if obj, ok := typ.(interface{ Obj() *types.TypeName }); ok {
+										rec.Def(tName, obj.Obj())
+									}
+								}
 								return
 							}
 							if debugLoad {


Test patch:
diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go
index aff9a1b1..7de3a3de 100644
--- a/cl/cltest/cltest.go
+++ b/cl/cltest/cltest.go
@@ -18,6 +18,10 @@ package cltest
 
 import (
 	"bytes"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/types"
 	"io/fs"
 	"log"
 	"os"
@@ -25,6 +29,8 @@ import (
 	"strings"
 	"testing"
 
+	goparser "go/parser"
+
 	"github.com/goplus/gogen"
 	"github.com/goplus/gop/cl"
 	"github.com/goplus/gop/parser"
@@ -205,4 +211,31 @@ func testFrom(t *testing.T, pkgDir, sel string) {
 	DoFS(t, conf, fsx.Local, pkgDir, filter, "main", expected)
 }
 
+func Go1Point() int {
+	for i := len(build.Default.ReleaseTags) - 1; i >= 0; i-- {
+		var version int
+		if _, err := fmt.Sscanf(build.Default.ReleaseTags[i], "go1.%d", &version); err != nil {
+			continue
+		}
+		return version
+	}
+	panic("bad release tags")
+}
+
+func EnableTypesalias() bool {
+	ver := Go1Point()
+	if ver < 22 {
+		return false
+	} else if ver > 22 {
+		_, ok := types.Universe.Lookup("any").Type().(*types.Interface)
+		return !ok
+	} else {
+		fset := token.NewFileSet()
+		f, _ := goparser.ParseFile(fset, "a.go", "package p; type A = int", goparser.SkipObjectResolution)
+		pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil)
+		_, ok := pkg.Scope().Lookup("A").Type().(*types.Basic)
+		return !ok
+	}
+}
+
 // -----------------------------------------------------------------------------
diff --git a/cl/compile_gop_test.go b/cl/compile_gop_test.go
index d6fa13e0..3a799df7 100644
--- a/cl/compile_gop_test.go
+++ b/cl/compile_gop_test.go
@@ -933,14 +933,22 @@ func main() {
 }
 
 func TestOverloadNamed(t *testing.T) {
-	gopClTest(t, `
+	var excepted string
+	if gotypesalias {
+		excepted = `package main
+
 import "github.com/goplus/gop/cl/internal/overload/bar"
 
-var a bar.Var[int]
-var b bar.Var[bar.M]
-c := bar.Var(string)
-d := bar.Var(bar.M)
-`, `package main
+var a bar.Var__0[int]
+var b bar.Var__1[bar.M]
+
+func main() {
+	c := bar.Gopx_Var_Cast__0[string]()
+	d := bar.Gopx_Var_Cast__1[bar.M]()
+}
+`
+	} else {
+		excepted = `package main
 
 import "github.com/goplus/gop/cl/internal/overload/bar"
 
@@ -951,7 +959,16 @@ func main() {
 	c := bar.Gopx_Var_Cast__0[string]()
 	d := bar.Gopx_Var_Cast__1[map[string]any]()
 }
-`)
+`
+	}
+	gopClTest(t, `
+import "github.com/goplus/gop/cl/internal/overload/bar"
+
+var a bar.Var[int]
+var b bar.Var[bar.M]
+c := bar.Var(string)
+d := bar.Var(bar.M)
+`, excepted)
 }
 
 func TestMixedOverloadNamed(t *testing.T) {
diff --git a/cl/compile_test.go b/cl/compile_test.go
index 88521d52..89e0476b 100644
--- a/cl/compile_test.go
+++ b/cl/compile_test.go
@@ -31,7 +31,8 @@ const (
 )
 
 var (
-	gblConfLine *cl.Config
+	gblConfLine  *cl.Config
+	gotypesalias bool
 )
 
 func init() {
@@ -45,6 +46,7 @@ func init() {
 		NoFileLine:    false,
 		NoAutoGenMain: true,
 	}
+	gotypesalias = cltest.EnableTypesalias()
 }
 
 func gopClNamedTest(t *testing.T, name string, gopcode, expected string) {
@@ -1955,13 +1957,15 @@ func main() {
 }
 
 func TestStructType(t *testing.T) {
-	gopClTest(t, `
-type bar = foo
+	var expect string
+	if gotypesalias {
+		expect = `package main
 
+type bar = foo
 type foo struct {
 	p *bar
 	A int
-	B string "tag1:123"
+	B string ` + "`tag1:123`" + `
 }
 
 func main() {
@@ -1970,13 +1974,15 @@ func main() {
 	}
 	type b = a
 }
-`, `package main
+`
+	} else {
+		expect = `package main
 
 type bar = foo
 type foo struct {
 	p *foo
 	A int
-	B string `+"`tag1:123`"+`
+	B string ` + "`tag1:123`" + `
 }
 
 func main() {
@@ -1985,7 +1991,24 @@ func main() {
 	}
 	type b = a
 }
-`)
+`
+	}
+	gopClTest(t, `
+type bar = foo
+
+type foo struct {
+	p *bar
+	A int
+	B string "tag1:123"
+}
+
+func main() {
+	type a struct {
+		p *a
+	}
+	type b = a
+}
+`, expect)
 }
 
 func TestDeferGo(t *testing.T) {
diff --git a/cl/typeparams_test.go b/cl/typeparams_test.go
index b1a679e0..c2da0777 100644
--- a/cl/typeparams_test.go
+++ b/cl/typeparams_test.go
@@ -136,6 +136,56 @@ func main() {
 }
 
 func TestTypeParamsType(t *testing.T) {
+	var expect string
+	if gotypesalias {
+		expect = `package main
+
+import "fmt"
+
+type DataString = Data[string]
+type SliceString = Slice[[]string, string]
+
+func main() {
+	fmt.Println(Data[int]{1}.v)
+	fmt.Println(DataString{"hello"}.v)
+	fmt.Println(Data[int]{100}.v)
+	fmt.Println(Data[string]{"hello"}.v)
+	fmt.Println(Data[struct {
+		X int
+		Y int
+	}]{}.v.X)
+	v1 := Slice[[]int, int]{}
+	v2 := SliceString{}
+	v3 := Slice[[]int, int]{}
+	v3.Append([]int{1, 2, 3, 4}...)
+	v3.Append2([]int{1, 2, 3, 4}...)
+}
+`
+	} else {
+		expect = `package main
+
+import "fmt"
+
+type DataString = Data[string]
+type SliceString = Slice[[]string, string]
+
+func main() {
+	fmt.Println(Data[int]{1}.v)
+	fmt.Println(Data[string]{"hello"}.v)
+	fmt.Println(Data[int]{100}.v)
+	fmt.Println(Data[string]{"hello"}.v)
+	fmt.Println(Data[struct {
+		X int
+		Y int
+	}]{}.v.X)
+	v1 := Slice[[]int, int]{}
+	v2 := Slice[[]string, string]{}
+	v3 := Slice[[]int, int]{}
+	v3.Append([]int{1, 2, 3, 4}...)
+	v3.Append2([]int{1, 2, 3, 4}...)
+}
+`
+	}
 	gopMixedClTest(t, "main", `package main
 type Data[T any] struct {
 	v T
@@ -178,29 +228,7 @@ v2 := SliceString{}
 v3 := Slice[[]int,int]{}
 v3.Append([1,2,3,4]...)
 v3.Append2([1,2,3,4]...)
-`, `package main
-
-import "fmt"
-
-type DataString = Data[string]
-type SliceString = Slice[[]string, string]
-
-func main() {
-	fmt.Println(Data[int]{1}.v)
-	fmt.Println(Data[string]{"hello"}.v)
-	fmt.Println(Data[int]{100}.v)
-	fmt.Println(Data[string]{"hello"}.v)
-	fmt.Println(Data[struct {
-		X int
-		Y int
-	}]{}.v.X)
-	v1 := Slice[[]int, int]{}
-	v2 := Slice[[]string, string]{}
-	v3 := Slice[[]int, int]{}
-	v3.Append([]int{1, 2, 3, 4}...)
-	v3.Append2([]int{1, 2, 3, 4}...)
-}
-`)
+`, expect)
 }
 
 func TestTypeParamsComparable(t *testing.T) {
@@ -314,7 +342,13 @@ _ = At[int]
 }
 
 func TestTypeParamsErrInferFunc(t *testing.T) {
-	mixedErrorTest(t, `b.gop:2:5: cannot infer T2 (/foo/a.go:4:21)`, `
+	var expect string
+	if cltest.Go1Point() == 24 {
+		expect = `b.gop:2:5: cannot infer T2 (declared at /foo/a.go:4:21)`
+	} else {
+		expect = `b.gop:2:5: cannot infer T2 (/foo/a.go:4:21)`
+	}
+	mixedErrorTest(t, expect, `
 package main
 
 func Loader[T1 any, T2 any](p1 T1, p2 T2) T1 {
diff --git a/x/typesutil/info_test.go b/x/typesutil/info_test.go
index 1cede6fa..ffcce113 100644
--- a/x/typesutil/info_test.go
+++ b/x/typesutil/info_test.go
@@ -17,6 +17,7 @@ import (
 
 	"github.com/goplus/gogen"
 	"github.com/goplus/gop/ast"
+	"github.com/goplus/gop/cl/cltest"
 	"github.com/goplus/gop/format"
 	"github.com/goplus/gop/parser"
 	"github.com/goplus/gop/token"
@@ -34,11 +35,13 @@ var spxProject = &modfile.Project{
 	PkgPaths: []string{"github.com/goplus/gop/cl/internal/spx", "math"}}
 
 var spxMod *gopmod.Module
+var gotypesalias bool
 
 func init() {
 	spxMod = gopmod.New(modload.Default)
 	spxMod.Opt.Projects = append(spxMod.Opt.Projects, spxProject)
 	spxMod.ImportClasses()
+	gotypesalias = cltest.EnableTypesalias()
 }
 
 func lookupClass(ext string) (c *modfile.Project, ok bool) {
@@ -105,7 +108,6 @@ func parseMixedSource(mod *gopmod.Module, fset *token.FileSet, name, src string,
 	err = check.Files(gofiles, []*ast.File{f})
 	return chkOpts.Types, info, ginfo, err
 }
-
 func parseSource(fset *token.FileSet, filename string, src any, mode parser.Mode) (*types.Package, *typesutil.Info, error) {
 	f, err := parser.ParseEntry(fset, filename, src, parser.Config{
 		Mode: mode,
@@ -116,7 +118,8 @@ func parseSource(fset *token.FileSet, filename string, src any, mode parser.Mode
 
 	pkg := types.NewPackage("", f.Name.Name)
 	conf := &types.Config{}
-	conf.Importer = importer.Default()
+	Gop := &env.Gop{Version: "1.0"}
+	conf.Importer = tool.NewImporter(nil, Gop, fset)
 	chkOpts := &typesutil.Config{
 		Types: pkg,
 		Fset:  fset,
@@ -1484,14 +1487,49 @@ func (p *N) Test__1(n int) {
 }
 
 func TestOverloadNamed(t *testing.T) {
-	testGopInfo(t, `
-import "github.com/goplus/gop/cl/internal/overload/bar"
-
-var a bar.Var[int]
-var b bar.Var[bar.M]
-c := bar.Var(string)
-d := bar.Var(bar.M)
-`, ``, `== types ==
+	var expect string
+	if gotypesalias {
+		expect = `== types ==
+000:  4: 7 | bar.Var             *ast.SelectorExpr              | type    : github.com/goplus/gop/cl/internal/overload/bar.Var__0[int] | type
+001:  4: 7 | bar.Var[int]        *ast.IndexExpr                 | type    : github.com/goplus/gop/cl/internal/overload/bar.Var__0[int] | type
+002:  4:15 | int                 *ast.Ident                     | type    : int | type
+003:  5: 7 | bar.Var             *ast.SelectorExpr              | type    : github.com/goplus/gop/cl/internal/overload/bar.Var__1[github.com/goplus/gop/cl/internal/overload/bar.M] | type
+004:  5: 7 | bar.Var[bar.M]      *ast.IndexExpr                 | type    : github.com/goplus/gop/cl/internal/overload/bar.Var__1[github.com/goplus/gop/cl/internal/overload/bar.M] | type
+005:  5:15 | bar.M               *ast.SelectorExpr              | type    : github.com/goplus/gop/cl/internal/overload/bar.M | type
+006:  6: 6 | bar.Var             *ast.SelectorExpr              | value   : func[T github.com/goplus/gop/cl/internal/overload/bar.basetype]() *github.com/goplus/gop/cl/internal/overload/bar.Var__0[T] | value
+007:  6: 6 | bar.Var(string)     *ast.CallExpr                  | value   : *github.com/goplus/gop/cl/internal/overload/bar.Var__0[string] | value
+008:  6:14 | string              *ast.Ident                     | type    : string | type
+009:  7: 6 | bar.Var             *ast.SelectorExpr              | value   : func[T map[string]any]() *github.com/goplus/gop/cl/internal/overload/bar.Var__1[T] | value
+010:  7: 6 | bar.Var(bar.M)      *ast.CallExpr                  | value   : *github.com/goplus/gop/cl/internal/overload/bar.Var__1[github.com/goplus/gop/cl/internal/overload/bar.M] | value
+011:  7:14 | bar.M               *ast.SelectorExpr              | var     : github.com/goplus/gop/cl/internal/overload/bar.M | variable
+== defs ==
+000:  4: 5 | a                   | var main.a github.com/goplus/gop/cl/internal/overload/bar.Var__0[int]
+001:  5: 5 | b                   | var main.b github.com/goplus/gop/cl/internal/overload/bar.Var__1[github.com/goplus/gop/cl/internal/overload/bar.M]
+002:  6: 1 | c                   | var c *github.com/goplus/gop/cl/internal/overload/bar.Var__0[string]
+003:  6: 1 | main                | func main.main()
+004:  7: 1 | d                   | var d *github.com/goplus/gop/cl/internal/overload/bar.Var__1[github.com/goplus/gop/cl/internal/overload/bar.M]
+== uses ==
+000:  4: 7 | bar                 | package bar ("github.com/goplus/gop/cl/internal/overload/bar")
+001:  4:11 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var__0[T github.com/goplus/gop/cl/internal/overload/bar.basetype] struct{val T}
+002:  4:15 | int                 | type int
+003:  5: 7 | bar                 | package bar ("github.com/goplus/gop/cl/internal/overload/bar")
+004:  5:11 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var__1[T map[string]any] struct{val T}
+005:  5:15 | bar                 | package bar ("github.com/goplus/gop/cl/internal/overload/bar")
+006:  5:19 | M                   | type github.com/goplus/gop/cl/internal/overload/bar.M = map[string]any
+007:  6: 6 | bar                 | package bar ("github.com/goplus/gop/cl/internal/overload/bar")
+008:  6:10 | Var                 | func github.com/goplus/gop/cl/internal/overload/bar.Gopx_Var_Cast__0[T github.com/goplus/gop/cl/internal/overload/bar.basetype]() *github.com/goplus/gop/cl/internal/overload/bar.Var__0[T]
+009:  6:14 | string              | type string
+010:  7: 6 | bar                 | package bar ("github.com/goplus/gop/cl/internal/overload/bar")
+011:  7:10 | Var                 | func github.com/goplus/gop/cl/internal/overload/bar.Gopx_Var_Cast__1[T map[string]any]() *github.com/goplus/gop/cl/internal/overload/bar.Var__1[T]
+012:  7:14 | bar                 | package bar ("github.com/goplus/gop/cl/internal/overload/bar")
+013:  7:18 | M                   | type github.com/goplus/gop/cl/internal/overload/bar.M = map[string]any
+== overloads ==
+000:  4:11 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})
+001:  5:11 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})
+002:  6:10 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})
+003:  7:10 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})`
+	} else {
+		expect = `== types ==
 000:  4: 7 | bar.Var             *ast.SelectorExpr              | type    : github.com/goplus/gop/cl/internal/overload/bar.Var__0[int] | type
 001:  4: 7 | bar.Var[int]        *ast.IndexExpr                 | type    : github.com/goplus/gop/cl/internal/overload/bar.Var__0[int] | type
 002:  4:15 | int                 *ast.Ident                     | type    : int | type
@@ -1529,7 +1567,16 @@ d := bar.Var(bar.M)
 000:  4:11 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})
 001:  5:11 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})
 002:  6:10 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})
-003:  7:10 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})`)
+003:  7:10 | Var                 | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})`
+	}
+	testGopInfo(t, `
+import "github.com/goplus/gop/cl/internal/overload/bar"
+
+var a bar.Var[int]
+var b bar.Var[bar.M]
+c := bar.Var(string)
+d := bar.Var(bar.M)
+`, ``, expect)
 }
 
 func TestMixedOverloadNamed(t *testing.T) {
@@ -2444,3 +2491,18 @@ func add = (
 013: 13:14 | b                   | var b float64
 014: 15: 2 | addString           | func (*main.Rect).addString(a string, b string) string`)
 }
+
+func TestTypesAlias(t *testing.T) {
+	testInfo(t, `package main
+import "fmt"
+
+type T = int
+var v T
+func demo(v T) {
+	fmt.Println(v)
+}
+func main() {
+	demo(100)
+}
+`)
+}