typeparams: simplify now that minimum required Go is 1.25.0 This module has a go directive set to 1.25.0. Some of the files have build constraints that will therefore never be satisfied, such as the '//go:build !go1.18' constraint in the typeparams_go117.go file. Simplify the code accordingly. This includes deleting TestAPIConsistency because it has outlived its purpose. It's no longer possible to make the API of this package at Go 1.17 inconsistent with that of Go 1.18+ since this package cannot be compiled with Go 1.17 (not in any supported way). Its Go 1.18+ API may still evolve in a backwards compatible way via the Go proposal process. For golang/go#50447. For golang/go#79683. Change-Id: I7f9923625cfe54ca2031e996ffa2cc7e26d83eea Reviewed-on: https://go-review.googlesource.com/c/exp/+/783440 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/typeparams/common.go b/typeparams/common.go index 820ca7b..c64e4f0 100644 --- a/typeparams/common.go +++ b/typeparams/common.go
@@ -8,10 +8,7 @@ // Many of the types and functions in this package are proxies for the new APIs // introduced in the standard library with Go 1.18. For example, the // typeparams.Union type is an alias for go/types.Union, and the ForTypeSpec -// function returns the value of the go/ast.TypeSpec.TypeParams field. At Go -// versions older than 1.18 these helpers are implemented as stubs, allowing -// users of this package to write code that handles generic constructs inline, -// even if the Go version being used to compile does not support generics. +// function returns the value of the go/ast.TypeSpec.TypeParams field. // // Additionally, this package contains common utilities for working with the // new generic constructs, to supplement the standard library APIs. Notably, @@ -29,7 +26,7 @@ // Enabled reports whether type parameters are enabled in the current build // environment. func Enabled() bool { - return enabled + return true } // UnpackIndexExpr extracts data from AST nodes that represent index
diff --git a/typeparams/common_test.go b/typeparams/common_test.go index 5dd5c3f..c3d78a9 100644 --- a/typeparams/common_test.go +++ b/typeparams/common_test.go
@@ -39,15 +39,7 @@ } } -func SkipIfNotEnabled(t *testing.T) { - if !Enabled() { - t.Skip("type parameters are not enabled") - } -} - func TestOriginMethodRecursive(t *testing.T) { - SkipIfNotEnabled(t) - src := `package p type N[A any] int @@ -119,8 +111,6 @@ } func TestOriginMethodUses(t *testing.T) { - SkipIfNotEnabled(t) - tests := []string{ `type T interface { m() }; func _(t T) { t.m() }`, `type T[P any] interface { m() P }; func _[A any](t T[A]) { t.m() }`, @@ -165,8 +155,6 @@ } func TestGenericAssignableTo(t *testing.T) { - SkipIfNotEnabled(t) - tests := []struct { src string want bool
diff --git a/typeparams/normalize_test.go b/typeparams/normalize_test.go index 98f7ec4..207c044 100644 --- a/typeparams/normalize_test.go +++ b/typeparams/normalize_test.go
@@ -17,10 +17,6 @@ ) func TestNormalTerms(t *testing.T) { - if !Enabled() { - t.Skip("typeparams are not enabled") - } - // In the following tests, src must define a type T with (at least) one type // parameter. We will compute the normal terms of the first type parameter. tests := []struct {
diff --git a/typeparams/typeparams_go118.go b/typeparams/typeparams.go similarity index 98% rename from typeparams/typeparams_go118.go rename to typeparams/typeparams.go index 0b35449..73a62a7 100644 --- a/typeparams/typeparams_go118.go +++ b/typeparams/typeparams.go
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.18 - package typeparams import ( @@ -11,8 +9,6 @@ "go/types" ) -const enabled = true - // IndexListExpr is an alias for ast.IndexListExpr. type IndexListExpr = ast.IndexListExpr
diff --git a/typeparams/typeparams_go117.go b/typeparams/typeparams_go117.go deleted file mode 100644 index c1da793..0000000 --- a/typeparams/typeparams_go117.go +++ /dev/null
@@ -1,201 +0,0 @@ -// 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. - -//go:build !go1.18 - -package typeparams - -import ( - "go/ast" - "go/token" - "go/types" -) - -const enabled = false - -func unsupported() { - panic("type parameters are unsupported at this go version") -} - -// IndexListExpr is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type IndexListExpr struct { - ast.Expr - X ast.Expr // expression - Lbrack token.Pos // position of "[" - Indices []ast.Expr // index expressions - Rbrack token.Pos // position of "]" -} - -func (*IndexListExpr) Pos() token.Pos { unsupported(); return token.NoPos } -func (*IndexListExpr) End() token.Pos { unsupported(); return token.NoPos } - -// ForTypeSpec returns an empty field list, as type parameters on not supported -// at this Go version. -func ForTypeSpec(*ast.TypeSpec) *ast.FieldList { - return nil -} - -// ForFuncType returns an empty field list, as type parameters are not -// supported at this Go version. -func ForFuncType(*ast.FuncType) *ast.FieldList { - return nil -} - -// TypeParam is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type TypeParam struct{ types.Type } - -func (*TypeParam) String() string { unsupported(); return "" } -func (*TypeParam) Underlying() types.Type { unsupported(); return nil } -func (*TypeParam) Index() int { unsupported(); return 0 } -func (*TypeParam) Constraint() types.Type { unsupported(); return nil } -func (*TypeParam) SetConstraint(types.Type) { unsupported() } -func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil } - -// TypeParamList is a placeholder for an empty type parameter list. -type TypeParamList struct{} - -func (*TypeParamList) Len() int { return 0 } -func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil } - -// TypeList is a placeholder for an empty type list. -type TypeList struct{} - -func (*TypeList) Len() int { return 0 } -func (*TypeList) At(int) types.Type { unsupported(); return nil } - -// NewTypeParam is unsupported at this Go version, and panics. -func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { - unsupported() - return nil -} - -// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or -// typeParams is non-empty. -func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { - if len(recvTypeParams) != 0 || len(typeParams) != 0 { - unsupported() - } - return types.NewSignature(recv, params, results, variadic) -} - -// ForSignature returns an empty slice. -func ForSignature(*types.Signature) *TypeParamList { - return nil -} - -// RecvTypeParams returns a nil slice. -func RecvTypeParams(sig *types.Signature) *TypeParamList { - return nil -} - -// IsComparable returns false, as no interfaces are type-restricted at this Go -// version. -func IsComparable(*types.Interface) bool { - return false -} - -// IsMethodSet returns true, as no interfaces are type-restricted at this Go -// version. -func IsMethodSet(*types.Interface) bool { - return true -} - -// IsImplicit returns false, as no interfaces are implicit at this Go version. -func IsImplicit(*types.Interface) bool { - return false -} - -// MarkImplicit does nothing, because this Go version does not have implicit -// interfaces. -func MarkImplicit(*types.Interface) {} - -// ForNamed returns an empty type parameter list, as type parameters are not -// supported at this Go version. -func ForNamed(*types.Named) *TypeParamList { - return nil -} - -// SetForNamed panics if tparams is non-empty. -func SetForNamed(_ *types.Named, tparams []*TypeParam) { - if len(tparams) > 0 { - unsupported() - } -} - -// NamedTypeArgs returns nil. -func NamedTypeArgs(*types.Named) *TypeList { - return nil -} - -// NamedTypeOrigin is the identity method at this Go version. -func NamedTypeOrigin(named *types.Named) types.Type { - return named -} - -// Term holds information about a structural type restriction. -type Term struct { - tilde bool - typ types.Type -} - -func (m *Term) Tilde() bool { return m.tilde } -func (m *Term) Type() types.Type { return m.typ } -func (m *Term) String() string { - pre := "" - if m.tilde { - pre = "~" - } - return pre + m.typ.String() -} - -// NewTerm creates a new placeholder term type. -func NewTerm(tilde bool, typ types.Type) *Term { - return &Term{tilde, typ} -} - -// Union is a placeholder type, as type parameters are not supported at this Go -// version. Its methods panic on use. -type Union struct{ types.Type } - -func (*Union) String() string { unsupported(); return "" } -func (*Union) Underlying() types.Type { unsupported(); return nil } -func (*Union) Len() int { return 0 } -func (*Union) Term(i int) *Term { unsupported(); return nil } - -// NewUnion is unsupported at this Go version, and panics. -func NewUnion(terms []*Term) *Union { - unsupported() - return nil -} - -// InitInstances is a noop at this Go version. -func InitInstances(*types.Info) {} - -// Instance is a placeholder type, as type parameters are not supported at this -// Go version. -type Instance struct { - TypeArgs *TypeList - Type types.Type -} - -// GetInstances returns a nil map, as type parameters are not supported at this -// Go version. -func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil } - -// Context is a placeholder type, as type parameters are not supported at -// this Go version. -type Context struct{} - -// NewContext returns a placeholder Context instance. -func NewContext() *Context { - return &Context{} -} - -// Instantiate is unsupported on this Go version, and panics. -func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { - unsupported() - return nil, nil -}
diff --git a/typeparams/typeparams_test.go b/typeparams/typeparams_test.go deleted file mode 100644 index 9f7b55f..0000000 --- a/typeparams/typeparams_test.go +++ /dev/null
@@ -1,160 +0,0 @@ -// 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. - -//go:build go1.18 - -package typeparams_test - -import ( - "bytes" - "go/ast" - "go/build" - "go/importer" - "go/parser" - "go/token" - "go/types" - "testing" -) - -// TestAPIConsistency verifies that exported APIs match at Go 1.17 and Go -// 1.18+. -// -// It relies on the convention that the names of type aliases in the typeparams -// package match the names of the types they are aliasing. -// -// This test could be made more precise. -func TestAPIConsistency(t *testing.T) { - api118 := getAPI(buildPackage(t, true)) - api117 := getAPI(buildPackage(t, false)) - - knownMissing := map[string]string{ - // Go 1.23 has iterator methods that return Seq. - // These methods can't be supported at 1.17. - "*TypeList.Types": "func()(Seq[Type])", - "*TypeParamList.TypeParams": "func()(Seq[*TypeParam])", - "*Union.Terms": "func()(Seq[*Term])", - - // Go 1.27 added String methods to some types (proposal go.dev/issue/79287). - // These could be supported at 1.17 (easily) and at 1.27 (already are). - // However, supporting them at 1.26/1.25 is annoying - it would require - // replacing type aliases in typeparams_go118.go with copies of the - // implementation from 1.26/1.25. - "Instance.String": "func()(string)", - "*Instance.String": "func()(string)", - "*TypeList.String": "func()(string)", - "*TypeParamList.String": "func()(string)", - } - - for name, api := range api117 { - if api != api118[name] { - t.Errorf("%q: got %q at 1.17, but %q at 1.18+", name, api, api118[name]) - } - delete(api118, name) - } - for name, api := range api118 { - if api117[name] == "" && knownMissing[name] == api { - t.Logf("%q: got %q at 1.18+; known to be missing at 1.17", name, api) - continue - } - - if api != api117[name] { - t.Errorf("%q: got %q at 1.18+, but %q at 1.17", name, api, api117[name]) - } - } -} - -func getAPI(pkg *types.Package) map[string]string { - api := make(map[string]string) - for _, name := range pkg.Scope().Names() { - if !token.IsExported(name) { - continue - } - api[name] = name - obj := pkg.Scope().Lookup(name) - if f, ok := obj.(*types.Func); ok { - api[name] = formatSignature(f.Type().(*types.Signature)) - } - typ := pkg.Scope().Lookup(name).Type() - // Consider method sets of pointer and non-pointer receivers. - msets := map[string]*types.MethodSet{ - name: types.NewMethodSet(typ), - "*" + name: types.NewMethodSet(types.NewPointer(typ)), - } - for name, mset := range msets { - for i := 0; i < mset.Len(); i++ { - f := mset.At(i).Obj().(*types.Func) - mname := f.Name() - if token.IsExported(mname) { - api[name+"."+mname] = formatSignature(f.Type().(*types.Signature)) - } - } - } - } - return api -} - -func formatSignature(sig *types.Signature) string { - var b bytes.Buffer - b.WriteString("func") - writeTuple(&b, sig.Params()) - writeTuple(&b, sig.Results()) - return b.String() -} - -func writeTuple(buf *bytes.Buffer, t *types.Tuple) { - buf.WriteRune('(') - - // The API at Go 1.18 uses aliases for types in go/types. These types are - // _actually_ in the go/types package, and therefore would be formatted as - // e.g. *types.TypeParam, which would not match *typeparams.TypeParam -- - // go/types does not track aliases. As we use the same name for all aliases, - // we can make the formatted signatures match by dropping the package - // qualifier. - qf := func(*types.Package) string { return "" } - - for i := 0; i < t.Len(); i++ { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(types.TypeString(t.At(i).Type(), qf)) - } - buf.WriteRune(')') -} - -func buildPackage(t *testing.T, go118 bool) *types.Package { - ctxt := build.Default - if !go118 { - for i, tag := range ctxt.ReleaseTags { - if tag == "go1.18" { - ctxt.ReleaseTags = ctxt.ReleaseTags[:i] - break - } - } - } - bpkg, err := ctxt.ImportDir(".", 0) - if err != nil { - t.Fatal(err) - } - return typeCheck(t, bpkg.GoFiles) -} - -func typeCheck(t *testing.T, filenames []string) *types.Package { - fset := token.NewFileSet() - var files []*ast.File - for _, name := range filenames { - f, err := parser.ParseFile(fset, name, nil, 0) - if err != nil { - t.Fatal(err) - } - files = append(files, f) - } - conf := types.Config{ - Importer: importer.Default(), - } - pkg, err := conf.Check("", fset, files, nil) - if err != nil { - t.Fatal(err) - } - return pkg -}