From e62bf150cc0802b3697da315ee41e19c0bbfb7eb Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 13 Nov 2023 16:46:47 -0800 Subject: [PATCH] go/types, types2: move exported predicates into separate file This allows those functions to be generated for go/types. Also, change the generator's renameIdent mechanism so that it can rename multiple identifiers in one pass through the AST instead of requiring multiple passes. No type-checker functionality changes. Change-Id: Ic78d899c6004b6a0692a95902fdc13f8ffb47824 Reviewed-on: https://go-review.googlesource.com/c/go/+/542757 Run-TryBot: Robert Griesemer Reviewed-by: Robert Griesemer TryBot-Result: Gopher Robot Reviewed-by: Robert Findley Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/types2/api.go | 77 ----------------- .../compile/internal/types2/api_predicates.go | 84 ++++++++++++++++++ src/go/types/api.go | 77 ----------------- src/go/types/api_predicates.go | 86 +++++++++++++++++++ src/go/types/generate_test.go | 48 +++++++---- 5 files changed, 199 insertions(+), 173 deletions(-) create mode 100644 src/cmd/compile/internal/types2/api_predicates.go create mode 100644 src/go/types/api_predicates.go diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index ca42c39433..6628174428 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -460,80 +460,3 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa pkg := NewPackage(path, "") return pkg, NewChecker(conf, pkg, info).Files(files) } - -// AssertableTo reports whether a value of type V can be asserted to have type T. -// -// The behavior of AssertableTo is unspecified in three cases: -// - if T is Typ[Invalid] -// - if V is a generalized interface; i.e., an interface that may only be used -// as a type constraint in Go code -// - if T is an uninstantiated generic type -func AssertableTo(V *Interface, T Type) bool { - // Checker.newAssertableTo suppresses errors for invalid types, so we need special - // handling here. - if !isValid(T.Underlying()) { - return false - } - return (*Checker)(nil).newAssertableTo(nopos, V, T, nil) -} - -// AssignableTo reports whether a value of type V is assignable to a variable -// of type T. -// -// The behavior of AssignableTo is unspecified if V or T is Typ[Invalid] or an -// uninstantiated generic type. -func AssignableTo(V, T Type) bool { - x := operand{mode: value, typ: V} - ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x - return ok -} - -// ConvertibleTo reports whether a value of type V is convertible to a value of -// type T. -// -// The behavior of ConvertibleTo is unspecified if V or T is Typ[Invalid] or an -// uninstantiated generic type. -func ConvertibleTo(V, T Type) bool { - x := operand{mode: value, typ: V} - return x.convertibleTo(nil, T, nil) // check not needed for non-constant x -} - -// Implements reports whether type V implements interface T. -// -// The behavior of Implements is unspecified if V is Typ[Invalid] or an uninstantiated -// generic type. -func Implements(V Type, T *Interface) bool { - if T.Empty() { - // All types (even Typ[Invalid]) implement the empty interface. - return true - } - // Checker.implements suppresses errors for invalid types, so we need special - // handling here. - if !isValid(V.Underlying()) { - return false - } - return (*Checker)(nil).implements(nopos, V, T, false, nil) -} - -// Satisfies reports whether type V satisfies the constraint T. -// -// The behavior of Satisfies is unspecified if V is Typ[Invalid] or an uninstantiated -// generic type. -func Satisfies(V Type, T *Interface) bool { - return (*Checker)(nil).implements(nopos, V, T, true, nil) -} - -// Identical reports whether x and y are identical types. -// Receivers of Signature types are ignored. -func Identical(x, y Type) bool { - var c comparer - return c.identical(x, y, nil) -} - -// IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. -// Receivers of Signature types are ignored. -func IdenticalIgnoreTags(x, y Type) bool { - var c comparer - c.ignoreTags = true - return c.identical(x, y, nil) -} diff --git a/src/cmd/compile/internal/types2/api_predicates.go b/src/cmd/compile/internal/types2/api_predicates.go new file mode 100644 index 0000000000..480f71144e --- /dev/null +++ b/src/cmd/compile/internal/types2/api_predicates.go @@ -0,0 +1,84 @@ +// Copyright 2023 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. + +// This file implements exported type predicates. + +package types2 + +// AssertableTo reports whether a value of type V can be asserted to have type T. +// +// The behavior of AssertableTo is unspecified in three cases: +// - if T is Typ[Invalid] +// - if V is a generalized interface; i.e., an interface that may only be used +// as a type constraint in Go code +// - if T is an uninstantiated generic type +func AssertableTo(V *Interface, T Type) bool { + // Checker.newAssertableTo suppresses errors for invalid types, so we need special + // handling here. + if !isValid(T.Underlying()) { + return false + } + return (*Checker)(nil).newAssertableTo(nopos, V, T, nil) +} + +// AssignableTo reports whether a value of type V is assignable to a variable +// of type T. +// +// The behavior of AssignableTo is unspecified if V or T is Typ[Invalid] or an +// uninstantiated generic type. +func AssignableTo(V, T Type) bool { + x := operand{mode: value, typ: V} + ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x + return ok +} + +// ConvertibleTo reports whether a value of type V is convertible to a value of +// type T. +// +// The behavior of ConvertibleTo is unspecified if V or T is Typ[Invalid] or an +// uninstantiated generic type. +func ConvertibleTo(V, T Type) bool { + x := operand{mode: value, typ: V} + return x.convertibleTo(nil, T, nil) // check not needed for non-constant x +} + +// Implements reports whether type V implements interface T. +// +// The behavior of Implements is unspecified if V is Typ[Invalid] or an uninstantiated +// generic type. +func Implements(V Type, T *Interface) bool { + if T.Empty() { + // All types (even Typ[Invalid]) implement the empty interface. + return true + } + // Checker.implements suppresses errors for invalid types, so we need special + // handling here. + if !isValid(V.Underlying()) { + return false + } + return (*Checker)(nil).implements(nopos, V, T, false, nil) +} + +// Satisfies reports whether type V satisfies the constraint T. +// +// The behavior of Satisfies is unspecified if V is Typ[Invalid] or an uninstantiated +// generic type. +func Satisfies(V Type, T *Interface) bool { + return (*Checker)(nil).implements(nopos, V, T, true, nil) +} + +// Identical reports whether x and y are identical types. +// Receivers of [Signature] types are ignored. +func Identical(x, y Type) bool { + var c comparer + return c.identical(x, y, nil) +} + +// IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. +// Receivers of [Signature] types are ignored. +func IdenticalIgnoreTags(x, y Type) bool { + var c comparer + c.ignoreTags = true + return c.identical(x, y, nil) +} diff --git a/src/go/types/api.go b/src/go/types/api.go index 6635253fdf..f729e33dec 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -448,80 +448,3 @@ func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, i pkg := NewPackage(path, "") return pkg, NewChecker(conf, fset, pkg, info).Files(files) } - -// AssertableTo reports whether a value of type V can be asserted to have type T. -// -// The behavior of AssertableTo is unspecified in three cases: -// - if T is Typ[Invalid] -// - if V is a generalized interface; i.e., an interface that may only be used -// as a type constraint in Go code -// - if T is an uninstantiated generic type -func AssertableTo(V *Interface, T Type) bool { - // Checker.newAssertableTo suppresses errors for invalid types, so we need special - // handling here. - if !isValid(T.Underlying()) { - return false - } - return (*Checker)(nil).newAssertableTo(nopos, V, T, nil) -} - -// AssignableTo reports whether a value of type V is assignable to a variable -// of type T. -// -// The behavior of AssignableTo is unspecified if V or T is Typ[Invalid] or an -// uninstantiated generic type. -func AssignableTo(V, T Type) bool { - x := operand{mode: value, typ: V} - ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x - return ok -} - -// ConvertibleTo reports whether a value of type V is convertible to a value of -// type T. -// -// The behavior of ConvertibleTo is unspecified if V or T is Typ[Invalid] or an -// uninstantiated generic type. -func ConvertibleTo(V, T Type) bool { - x := operand{mode: value, typ: V} - return x.convertibleTo(nil, T, nil) // check not needed for non-constant x -} - -// Implements reports whether type V implements interface T. -// -// The behavior of Implements is unspecified if V is Typ[Invalid] or an uninstantiated -// generic type. -func Implements(V Type, T *Interface) bool { - if T.Empty() { - // All types (even Typ[Invalid]) implement the empty interface. - return true - } - // Checker.implements suppresses errors for invalid types, so we need special - // handling here. - if !isValid(V.Underlying()) { - return false - } - return (*Checker)(nil).implements(0, V, T, false, nil) -} - -// Satisfies reports whether type V satisfies the constraint T. -// -// The behavior of Satisfies is unspecified if V is Typ[Invalid] or an uninstantiated -// generic type. -func Satisfies(V Type, T *Interface) bool { - return (*Checker)(nil).implements(0, V, T, true, nil) -} - -// Identical reports whether x and y are identical types. -// Receivers of [Signature] types are ignored. -func Identical(x, y Type) bool { - var c comparer - return c.identical(x, y, nil) -} - -// IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. -// Receivers of [Signature] types are ignored. -func IdenticalIgnoreTags(x, y Type) bool { - var c comparer - c.ignoreTags = true - return c.identical(x, y, nil) -} diff --git a/src/go/types/api_predicates.go b/src/go/types/api_predicates.go new file mode 100644 index 0000000000..d712afe0ff --- /dev/null +++ b/src/go/types/api_predicates.go @@ -0,0 +1,86 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. + +// Copyright 2023 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. + +// This file implements exported type predicates. + +package types + +// AssertableTo reports whether a value of type V can be asserted to have type T. +// +// The behavior of AssertableTo is unspecified in three cases: +// - if T is Typ[Invalid] +// - if V is a generalized interface; i.e., an interface that may only be used +// as a type constraint in Go code +// - if T is an uninstantiated generic type +func AssertableTo(V *Interface, T Type) bool { + // Checker.newAssertableTo suppresses errors for invalid types, so we need special + // handling here. + if !isValid(T.Underlying()) { + return false + } + return (*Checker)(nil).newAssertableTo(nopos, V, T, nil) +} + +// AssignableTo reports whether a value of type V is assignable to a variable +// of type T. +// +// The behavior of AssignableTo is unspecified if V or T is Typ[Invalid] or an +// uninstantiated generic type. +func AssignableTo(V, T Type) bool { + x := operand{mode: value, typ: V} + ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x + return ok +} + +// ConvertibleTo reports whether a value of type V is convertible to a value of +// type T. +// +// The behavior of ConvertibleTo is unspecified if V or T is Typ[Invalid] or an +// uninstantiated generic type. +func ConvertibleTo(V, T Type) bool { + x := operand{mode: value, typ: V} + return x.convertibleTo(nil, T, nil) // check not needed for non-constant x +} + +// Implements reports whether type V implements interface T. +// +// The behavior of Implements is unspecified if V is Typ[Invalid] or an uninstantiated +// generic type. +func Implements(V Type, T *Interface) bool { + if T.Empty() { + // All types (even Typ[Invalid]) implement the empty interface. + return true + } + // Checker.implements suppresses errors for invalid types, so we need special + // handling here. + if !isValid(V.Underlying()) { + return false + } + return (*Checker)(nil).implements(nopos, V, T, false, nil) +} + +// Satisfies reports whether type V satisfies the constraint T. +// +// The behavior of Satisfies is unspecified if V is Typ[Invalid] or an uninstantiated +// generic type. +func Satisfies(V Type, T *Interface) bool { + return (*Checker)(nil).implements(nopos, V, T, true, nil) +} + +// Identical reports whether x and y are identical types. +// Receivers of [Signature] types are ignored. +func Identical(x, y Type) bool { + var c comparer + return c.identical(x, y, nil) +} + +// IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. +// Receivers of [Signature] types are ignored. +func IdenticalIgnoreTags(x, y Type) bool { + var c comparer + c.ignoreTags = true + return c.identical(x, y, nil) +} diff --git a/src/go/types/generate_test.go b/src/go/types/generate_test.go index e74a1e6f25..59c0a97965 100644 --- a/src/go/types/generate_test.go +++ b/src/go/types/generate_test.go @@ -95,16 +95,17 @@ func generate(t *testing.T, filename string, write bool) { type action func(in *ast.File) var filemap = map[string]action{ - "alias.go": nil, - "array.go": nil, - "basic.go": nil, - "chan.go": nil, - "const.go": func(f *ast.File) { fixTokenPos(f) }, - "context.go": nil, - "context_test.go": nil, - "gccgosizes.go": nil, - "gcsizes.go": func(f *ast.File) { renameIdent(f, "IsSyncAtomicAlign64", "_IsSyncAtomicAlign64") }, - "hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) }, + "alias.go": nil, + "array.go": nil, + "api_predicates.go": nil, + "basic.go": nil, + "chan.go": nil, + "const.go": func(f *ast.File) { fixTokenPos(f) }, + "context.go": nil, + "context_test.go": nil, + "gccgosizes.go": nil, + "gcsizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") }, + "hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) }, "infer.go": func(f *ast.File) { fixTokenPos(f) fixInferSig(f) @@ -116,7 +117,7 @@ var filemap = map[string]action{ "main_test.go": nil, "map.go": nil, "named.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) }, - "object.go": func(f *ast.File) { fixTokenPos(f); renameIdent(f, "NewTypeNameLazy", "_NewTypeNameLazy") }, + "object.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "NewTypeNameLazy->_NewTypeNameLazy") }, "object_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) }, "objset.go": nil, "package.go": nil, @@ -124,11 +125,10 @@ var filemap = map[string]action{ "predicates.go": nil, "scope.go": func(f *ast.File) { fixTokenPos(f) - renameIdent(f, "Squash", "squash") - renameIdent(f, "InsertLazy", "_InsertLazy") + renameIdents(f, "Squash->squash", "InsertLazy->_InsertLazy") }, "selection.go": nil, - "sizes.go": func(f *ast.File) { renameIdent(f, "IsSyncAtomicAlign64", "_IsSyncAtomicAlign64") }, + "sizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") }, "slice.go": nil, "subst.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) }, "termlist.go": nil, @@ -148,14 +148,24 @@ var filemap = map[string]action{ // TODO(gri) We should be able to make these rewriters more configurable/composable. // For now this is a good starting point. -// renameIdent renames an identifier. -// Note: This doesn't change the use of the identifier in comments. -func renameIdent(f *ast.File, from, to string) { +// renameIdent renames identifiers: each renames entry is of the form from->to. +// Note: This doesn't change the use of the identifiers in comments. +func renameIdents(f *ast.File, renames ...string) { + var list [][]string + for _, r := range renames { + s := strings.Split(r, "->") + if len(s) != 2 { + panic("invalid rename entry: " + r) + } + list = append(list, s) + } ast.Inspect(f, func(n ast.Node) bool { switch n := n.(type) { case *ast.Ident: - if n.Name == from { - n.Name = to + for _, r := range list { + if n.Name == r[0] { + n.Name = r[1] + } } return false } -- 2.48.1