]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: implement Alias proposal (export API)
authorRobert Griesemer <gri@golang.org>
Sat, 11 Nov 2023 02:11:15 +0000 (18:11 -0800)
committerGopher Robot <gobot@golang.org>
Mon, 13 Nov 2023 20:18:45 +0000 (20:18 +0000)
This CL exports the previously unexported Alias type and
corresponding functions and methods per issue #63223.

Whether Alias types are used or not is controlled by
the gotypesalias setting with the GODEBUG environment
variable. Setting gotypesalias to "1" enables the Alias
types:

GODEBUG=gotypesalias=1

By default, gotypesalias is not set.

Adjust test cases that enable/disable the use of Alias
types to use -gotypesalias=1 or -gotypesalias=0 rather
than -alias and -alias=false for consistency and to
avoid confusion.

For #63223.

Change-Id: I51308cad3320981afac97dd8c6f6a416fdb0be55
Reviewed-on: https://go-review.googlesource.com/c/go/+/541737
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
46 files changed:
api/next/63223.txt [new file with mode: 0644]
doc/godebug.md
src/cmd/compile/internal/types2/alias.go
src/cmd/compile/internal/types2/api.go
src/cmd/compile/internal/types2/check.go
src/cmd/compile/internal/types2/check_test.go
src/cmd/compile/internal/types2/decl.go
src/cmd/compile/internal/types2/infer.go
src/cmd/compile/internal/types2/issues_test.go
src/cmd/compile/internal/types2/lookup.go
src/cmd/compile/internal/types2/mono.go
src/cmd/compile/internal/types2/named.go
src/cmd/compile/internal/types2/object.go
src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/resolver.go
src/cmd/compile/internal/types2/signature.go
src/cmd/compile/internal/types2/typestring.go
src/cmd/compile/internal/types2/typexpr.go
src/cmd/compile/internal/types2/unify.go
src/cmd/compile/internal/types2/validtype.go
src/go/types/alias.go
src/go/types/api.go
src/go/types/check.go
src/go/types/check_test.go
src/go/types/decl.go
src/go/types/infer.go
src/go/types/issues_test.go
src/go/types/lookup.go
src/go/types/mono.go
src/go/types/named.go
src/go/types/object.go
src/go/types/predicates.go
src/go/types/resolver.go
src/go/types/signature.go
src/go/types/typestring.go
src/go/types/typexpr.go
src/go/types/unify.go
src/go/types/validtype.go
src/internal/godebugs/table.go
src/internal/types/testdata/check/cycles5.go
src/internal/types/testdata/check/cycles5a.go
src/internal/types/testdata/fixedbugs/issue46461.go
src/internal/types/testdata/fixedbugs/issue46461a.go
src/internal/types/testdata/fixedbugs/issue50779.go
src/internal/types/testdata/fixedbugs/issue50779a.go
src/runtime/metrics/doc.go

diff --git a/api/next/63223.txt b/api/next/63223.txt
new file mode 100644 (file)
index 0000000..2dcafb8
--- /dev/null
@@ -0,0 +1,6 @@
+pkg go/types, func NewAlias(*TypeName, Type) *Alias #63223
+pkg go/types, func Unalias(Type) Type #63223
+pkg go/types, method (*Alias) Obj() *TypeName #63223
+pkg go/types, method (*Alias) String() string #63223
+pkg go/types, method (*Alias) Underlying() Type #63223
+pkg go/types, type Alias struct #63223
index 380107cf66f4897ca845cad7f7709ff3412736c5..e4978b9d26334e3279db1715ed99ed3797b2092f 100644 (file)
@@ -143,6 +143,13 @@ patterns and unescape both patterns and request paths by segment.
 This behavior can be controlled by the
 [`httpmuxgo121` setting](/pkg/net/http/#ServeMux).
 
+Go 1.22 added the [Alias type](/pkg/go/types#Alias) to [go/types](/pkg/go/types)
+for the explicit representation of [type aliases](/ref/spec#Type_declarations).
+Whether the type checker produces `Alias` types or not is controlled by the
+[`gotypesalias` setting](/pkg/go/types#Alias).
+For Go 1.22 it defaults to `gotypesalias=0`.
+For Go 1.23, `gotypealias=1` will become the default.
+This setting will be removed in a future release, Go 1.24 at the earliest.
 
 ### Go 1.21
 
index c0e646eb1c07bd39bbfe472d45c34bb6f2a6a7e3..2cc57721f9ddab02057354d626db5ffe9c367616 100644 (file)
@@ -6,39 +6,42 @@ package types2
 
 import "fmt"
 
-// Names starting with a _ are intended to be exported eventually
-// (go.dev/issue/63223).
-
-// An _Alias represents an alias type.
-type _Alias struct {
+// An Alias represents an alias type.
+// Whether or not Alias types are created is controlled by the
+// gotypesalias setting with the GODEBUG environment variable.
+// For gotypesalias=1, alias declarations produce an Alias type.
+// Otherwise, the alias information is only in the type name,
+// which points directly to the actual (aliased) type.
+type Alias struct {
        obj     *TypeName // corresponding declared alias object
        fromRHS Type      // RHS of type alias declaration; may be an alias
        actual  Type      // actual (aliased) type; never an alias
 }
 
-// _NewAlias creates a new Alias type with the given type name and rhs.
+// NewAlias creates a new Alias type with the given type name and rhs.
 // rhs must not be nil.
-func _NewAlias(obj *TypeName, rhs Type) *_Alias {
+func NewAlias(obj *TypeName, rhs Type) *Alias {
        return (*Checker)(nil).newAlias(obj, rhs)
 }
 
-func (a *_Alias) Underlying() Type { return a.actual.Underlying() }
-func (a *_Alias) String() string   { return TypeString(a, nil) }
+func (a *Alias) Obj() *TypeName   { return a.obj }
+func (a *Alias) Underlying() Type { return a.actual.Underlying() }
+func (a *Alias) String() string   { return TypeString(a, nil) }
 
 // Type accessors
 
-// _Unalias returns t if it is not an alias type;
+// Unalias returns t if it is not an alias type;
 // otherwise it follows t's alias chain until it
 // reaches a non-alias type which is then returned.
 // Consequently, the result is never an alias type.
-func _Unalias(t Type) Type {
-       if a0, _ := t.(*_Alias); a0 != nil {
+func Unalias(t Type) Type {
+       if a0, _ := t.(*Alias); a0 != nil {
                if a0.actual != nil {
                        return a0.actual
                }
                for a := a0; ; {
                        t = a.fromRHS
-                       a, _ = t.(*_Alias)
+                       a, _ = t.(*Alias)
                        if a == nil {
                                break
                        }
@@ -54,15 +57,15 @@ func _Unalias(t Type) Type {
 // asNamed returns t as *Named if that is t's
 // actual type. It returns nil otherwise.
 func asNamed(t Type) *Named {
-       n, _ := _Unalias(t).(*Named)
+       n, _ := Unalias(t).(*Named)
        return n
 }
 
 // newAlias creates a new Alias type with the given type name and rhs.
 // rhs must not be nil.
-func (check *Checker) newAlias(obj *TypeName, rhs Type) *_Alias {
+func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
        assert(rhs != nil)
-       a := &_Alias{obj, rhs, nil}
+       a := &Alias{obj, rhs, nil}
        if obj.typ == nil {
                obj.typ = a
        }
@@ -75,6 +78,6 @@ func (check *Checker) newAlias(obj *TypeName, rhs Type) *_Alias {
        return a
 }
 
-func (a *_Alias) cleanup() {
-       _Unalias(a)
+func (a *Alias) cleanup() {
+       Unalias(a)
 }
index 2093ceb817a01bd0532ed2be61c14353501ea9b0..ca42c394336e94df7a61044a7af1e0da927d179c 100644 (file)
@@ -170,11 +170,6 @@ type Config struct {
        // for unused imports.
        DisableUnusedImportCheck bool
 
-       // If EnableAlias is set, alias declarations produce an _Alias type.
-       // Otherwise the alias information is only in the type name, which
-       // points directly to the actual (aliased) type.
-       _EnableAlias bool
-
        // If a non-empty ErrorURL format string is provided, it is used
        // to format an error URL link that is appended to the first line
        // of an error message. ErrorURL must be a format string containing
index 60422d8dd9e297a5e95a721a66652242f5ca70cf..e8aed5d56e5249e8825c84e32d86f2e56d1fcd4b 100644 (file)
@@ -11,6 +11,7 @@ import (
        "errors"
        "fmt"
        "go/constant"
+       "internal/godebug"
        "internal/goversion"
        . "internal/types/errors"
 )
@@ -21,6 +22,9 @@ var nopos syntax.Pos
 // debugging/development support
 const debug = false // leave on during development
 
+// gotypesalias controls the use of Alias types.
+var gotypesalias = godebug.New("gotypesalias")
+
 // exprInfo stores information about an untyped expression.
 type exprInfo struct {
        isLhs bool // expression is lhs operand of a shift with delayed type-check
@@ -93,6 +97,12 @@ type actionDesc struct {
 type Checker struct {
        // package information
        // (initialized by NewChecker, valid for the life-time of checker)
+
+       // If enableAlias is set, alias declarations produce an Alias type.
+       // Otherwise the alias information is only in the type name, which
+       // points directly to the actual (aliased) type.
+       enableAlias bool
+
        conf *Config
        ctxt *Context // context for de-duplicating instances
        pkg  *Package
@@ -153,13 +163,13 @@ func (check *Checker) addDeclDep(to Object) {
 }
 
 // Note: The following three alias-related functions are only used
-//       when _Alias types are not enabled.
+//       when Alias types are not enabled.
 
 // brokenAlias records that alias doesn't have a determined type yet.
 // It also sets alias.typ to Typ[Invalid].
-// Not used if check.conf._EnableAlias is set.
+// Not used if check.enableAlias is set.
 func (check *Checker) brokenAlias(alias *TypeName) {
-       assert(!check.conf._EnableAlias)
+       assert(!check.enableAlias)
        if check.brokenAliases == nil {
                check.brokenAliases = make(map[*TypeName]bool)
        }
@@ -169,14 +179,14 @@ func (check *Checker) brokenAlias(alias *TypeName) {
 
 // validAlias records that alias has the valid type typ (possibly Typ[Invalid]).
 func (check *Checker) validAlias(alias *TypeName, typ Type) {
-       assert(!check.conf._EnableAlias)
+       assert(!check.enableAlias)
        delete(check.brokenAliases, alias)
        alias.typ = typ
 }
 
 // isBrokenAlias reports whether alias doesn't have a determined type yet.
 func (check *Checker) isBrokenAlias(alias *TypeName) bool {
-       assert(!check.conf._EnableAlias)
+       assert(!check.enableAlias)
        return check.brokenAliases[alias]
 }
 
@@ -246,12 +256,13 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
        // (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
 
        return &Checker{
-               conf:   conf,
-               ctxt:   conf.Context,
-               pkg:    pkg,
-               Info:   info,
-               objMap: make(map[Object]*declInfo),
-               impMap: make(map[importKey]*Package),
+               enableAlias: gotypesalias.Value() == "1",
+               conf:        conf,
+               ctxt:        conf.Context,
+               pkg:         pkg,
+               Info:        info,
+               objMap:      make(map[Object]*declInfo),
+               impMap:      make(map[importKey]*Package),
        }
 }
 
index 2aac95d842bb8942f04dcb1c0671ab9814c14acf..f5c41033596d32ea377c65925a7b864404b24715 100644 (file)
@@ -113,7 +113,7 @@ func parseFlags(src []byte, flags *flag.FlagSet) error {
 // testFiles type-checks the package consisting of the given files, and
 // compares the resulting errors with the ERROR annotations in the source.
 // Except for manual tests, each package is type-checked twice, once without
-// use of _Alias types, and once with _Alias types.
+// use of Alias types, and once with Alias types.
 //
 // The srcs slice contains the file content for the files named in the
 // filenames slice. The colDelta parameter specifies the tolerance for position
@@ -122,9 +122,11 @@ func parseFlags(src []byte, flags *flag.FlagSet) error {
 //
 // If provided, opts may be used to mutate the Config before type-checking.
 func testFiles(t *testing.T, filenames []string, srcs [][]byte, colDelta uint, manual bool, opts ...func(*Config)) {
+       // Alias types are disabled by default
        testFilesImpl(t, filenames, srcs, colDelta, manual, opts...)
        if !manual {
-               testFilesImpl(t, filenames, srcs, colDelta, manual, append(opts, func(conf *Config) { *boolFieldAddr(conf, "_EnableAlias") = true })...)
+               t.Setenv("GODEBUG", "gotypesalias=1")
+               testFilesImpl(t, filenames, srcs, colDelta, manual, opts...)
        }
 }
 
@@ -168,15 +170,16 @@ func testFilesImpl(t *testing.T, filenames []string, srcs [][]byte, colDelta uin
        }
 
        // apply flag setting (overrides custom configuration)
-       var goexperiment string
+       var goexperiment, gotypesalias string
        flags := flag.NewFlagSet("", flag.PanicOnError)
        flags.StringVar(&conf.GoVersion, "lang", "", "")
        flags.StringVar(&goexperiment, "goexperiment", "", "")
        flags.BoolVar(&conf.FakeImportC, "fakeImportC", false, "")
-       flags.BoolVar(boolFieldAddr(&conf, "_EnableAlias"), "alias", false, "")
+       flags.StringVar(&gotypesalias, "gotypesalias", "", "")
        if err := parseFlags(srcs[0], flags); err != nil {
                t.Fatal(err)
        }
+
        exp, err := buildcfg.ParseGOEXPERIMENT(runtime.GOOS, runtime.GOARCH, goexperiment)
        if err != nil {
                t.Fatal(err)
@@ -187,6 +190,11 @@ func testFilesImpl(t *testing.T, filenames []string, srcs [][]byte, colDelta uin
        }()
        buildcfg.Experiment = *exp
 
+       // By default, gotypesalias is not set.
+       if gotypesalias != "" {
+               t.Setenv("GODEBUG", "gotypesalias="+gotypesalias)
+       }
+
        // Provide Config.Info with all maps so that info recording is tested.
        info := Info{
                Types:      make(map[syntax.Expr]TypeAndValue),
index 6fd2c2cad8f112e1bd1fed4ed4b31520c33805cd..3abde44c7171c9a2ea3d75b27272895454182151 100644 (file)
@@ -251,7 +251,7 @@ loop:
                        // the syntactic information. We should consider storing
                        // this information explicitly in the object.
                        var alias bool
-                       if check.conf._EnableAlias {
+                       if check.enableAlias {
                                alias = obj.IsAlias()
                        } else {
                                if d := check.objMap[obj]; d != nil {
@@ -328,7 +328,7 @@ func (check *Checker) cycleError(cycle []Object) {
        if tname != nil && tname.IsAlias() {
                // If we use Alias nodes, it is initialized with Typ[Invalid].
                // TODO(gri) Adjust this code if we initialize with nil.
-               if !check.conf._EnableAlias {
+               if !check.enableAlias {
                        check.validAlias(tname, Typ[Invalid])
                }
        }
@@ -514,7 +514,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *TypeN
        // alias declaration
        if aliasDecl {
                check.verifyVersionf(tdecl, go1_9, "type aliases")
-               if check.conf._EnableAlias {
+               if check.enableAlias {
                        // TODO(gri) Should be able to use nil instead of Typ[Invalid] to mark
                        //           the alias as incomplete. Currently this causes problems
                        //           with certain cycles. Investigate.
@@ -523,7 +523,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *TypeN
                        rhs = check.definedType(tdecl.Type, obj)
                        assert(rhs != nil)
                        alias.fromRHS = rhs
-                       _Unalias(alias) // resolve alias.actual
+                       Unalias(alias) // resolve alias.actual
                } else {
                        check.brokenAlias(obj)
                        rhs = check.typ(tdecl.Type)
index 49d4ed7fe81c47a859d8ed565656274e7fb0b74e..c186d70d95e1e48b6759dfe5cdb9f9f95905c821 100644 (file)
@@ -542,8 +542,8 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
        case *Basic:
                // nothing to do
 
-       case *_Alias:
-               return w.isParameterized(_Unalias(t))
+       case *Alias:
+               return w.isParameterized(Unalias(t))
 
        case *Array:
                return w.isParameterized(t.elem)
@@ -696,8 +696,8 @@ func (w *cycleFinder) typ(typ Type) {
        case *Basic:
                // nothing to do
 
-       case *_Alias:
-               w.typ(_Unalias(t))
+       case *Alias:
+               w.typ(Unalias(t))
 
        case *Array:
                w.typ(t.elem)
index a66e8eab929ea936efbd432dfab571929ca6ef4a..95b9f940784da4481680009b31c24c45e42ae7e2 100644 (file)
@@ -989,9 +989,8 @@ type A = []int
 type S struct{ A }
 `
 
-       var conf Config
-       *boolFieldAddr(&conf, "_EnableAlias") = true
-       pkg := mustTypecheck(src, &conf, nil)
+       t.Setenv("GODEBUG", "gotypesalias=1")
+       pkg := mustTypecheck(src, nil, nil)
 
        S := pkg.Scope().Lookup("S")
        if S == nil {
index b8926250cf2a4a98b8bbe91912256f55d69c284a..893cdb157dff2cc5d9b93c49f4e0fb7adf305794 100644 (file)
@@ -527,7 +527,7 @@ func (check *Checker) newAssertableTo(pos syntax.Pos, V, T Type, cause *string)
 // with an underlying pointer type!) and returns its base and true.
 // Otherwise it returns (typ, false).
 func deref(typ Type) (Type, bool) {
-       if p, _ := _Unalias(typ).(*Pointer); p != nil {
+       if p, _ := Unalias(typ).(*Pointer); p != nil {
                // p.base should never be nil, but be conservative
                if p.base == nil {
                        if debug {
index 497276083abeda374c46c56ccb156f612acdfe6a..dae9230252692726a9907ab20d07a9b1928761d2 100644 (file)
@@ -208,7 +208,7 @@ func (w *monoGraph) assign(pkg *Package, pos syntax.Pos, tpar *TypeParam, targ T
        // type parameters.
        var do func(typ Type)
        do = func(typ Type) {
-               switch typ := _Unalias(typ).(type) {
+               switch typ := Unalias(typ).(type) {
                default:
                        panic("unexpected type")
 
index dcfb20592ca302f3e22cbf1be2b05fb614b3d0a2..893247de35b671e063990fb70586ca9db7447d01 100644 (file)
@@ -453,8 +453,8 @@ func (t *Named) AddMethod(m *Func) {
        }
 }
 
-// TODO(gri) Investigate if _Unalias can be moved to where underlying is set.
-func (t *Named) Underlying() Type { return _Unalias(t.resolve().underlying) }
+// TODO(gri) Investigate if Unalias can be moved to where underlying is set.
+func (t *Named) Underlying() Type { return Unalias(t.resolve().underlying) }
 func (t *Named) String() string   { return TypeString(t, nil) }
 
 // ----------------------------------------------------------------------------
index 23387a1c21f8dabce472a2fa4f914c2c7b7b1772..251587224b825451499be0849a96037a5b68e526 100644 (file)
@@ -285,7 +285,7 @@ func (obj *TypeName) IsAlias() bool {
        switch t := obj.typ.(type) {
        case nil:
                return false
-       // case *_Alias:
+       // case *Alias:
        //      handled by default case
        case *Basic:
                // unsafe.Pointer is not an alias.
index 9ec7d58d6fbab69a18fbf509e0fff95b867dfecf..7a096e3d97c0e436902c5645bbb0ab6178d4b3dd 100644 (file)
@@ -7,7 +7,7 @@
 package types2
 
 // isValid reports whether t is a valid type.
-func isValid(t Type) bool { return _Unalias(t) != Typ[Invalid] }
+func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
 
 // The isX predicates below report whether t is an X.
 // If t is a type parameter the result is false; i.e.,
@@ -50,7 +50,7 @@ func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
 // for all specific types of the type parameter's type set.
 // allBasic(t, info) is an optimized version of isBasic(coreType(t), info).
 func allBasic(t Type, info BasicInfo) bool {
-       if tpar, _ := _Unalias(t).(*TypeParam); tpar != nil {
+       if tpar, _ := Unalias(t).(*TypeParam); tpar != nil {
                return tpar.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
        }
        return isBasic(t, info)
@@ -60,7 +60,7 @@ func allBasic(t Type, info BasicInfo) bool {
 // predeclared types, defined types, and type parameters.
 // hasName may be called with types that are not fully set up.
 func hasName(t Type) bool {
-       switch _Unalias(t).(type) {
+       switch Unalias(t).(type) {
        case *Basic, *Named, *TypeParam:
                return true
        }
@@ -71,7 +71,7 @@ func hasName(t Type) bool {
 // This includes all non-defined types, but also basic types.
 // isTypeLit may be called with types that are not fully set up.
 func isTypeLit(t Type) bool {
-       switch _Unalias(t).(type) {
+       switch Unalias(t).(type) {
        case *Named, *TypeParam:
                return false
        }
@@ -83,7 +83,7 @@ func isTypeLit(t Type) bool {
 // are not fully set up.
 func isTyped(t Type) bool {
        // Alias or Named types cannot denote untyped types,
-       // thus we don't need to call _Unalias or under
+       // thus we don't need to call Unalias or under
        // (which would be unsafe to do for types that are
        // not fully set up).
        b, _ := t.(*Basic)
@@ -108,7 +108,7 @@ func isNonTypeParamInterface(t Type) bool {
 
 // isTypeParam reports whether t is a type parameter.
 func isTypeParam(t Type) bool {
-       _, ok := _Unalias(t).(*TypeParam)
+       _, ok := Unalias(t).(*TypeParam)
        return ok
 }
 
@@ -117,7 +117,7 @@ func isTypeParam(t Type) bool {
 // use anywhere, but it may report a false negative if the type set has not been
 // computed yet.
 func hasEmptyTypeset(t Type) bool {
-       if tpar, _ := _Unalias(t).(*TypeParam); tpar != nil && tpar.bound != nil {
+       if tpar, _ := Unalias(t).(*TypeParam); tpar != nil && tpar.bound != nil {
                iface, _ := safeUnderlying(tpar.bound).(*Interface)
                return iface != nil && iface.tset != nil && iface.tset.IsEmpty()
        }
@@ -223,8 +223,8 @@ type comparer struct {
 
 // For changes to this code the corresponding changes should be made to unifier.nify.
 func (c *comparer) identical(x, y Type, p *ifacePair) bool {
-       x = _Unalias(x)
-       y = _Unalias(y)
+       x = Unalias(x)
+       y = Unalias(y)
 
        if x == y {
                return true
@@ -500,7 +500,7 @@ func identicalInstance(xorig Type, xargs []Type, yorig Type, yargs []Type) bool
 // it returns the incoming type for all other types. The default type
 // for untyped nil is untyped nil.
 func Default(t Type) Type {
-       if t, ok := _Unalias(t).(*Basic); ok {
+       if t, ok := Unalias(t).(*Basic); ok {
                switch t.kind {
                case UntypedBool:
                        return Typ[Bool]
index e074b7548c05c0a5ac8bcdb48b88ffe445bfaa0b..0cf7c9142e4c4e746030c60fe2d8306967ba712f 100644 (file)
@@ -677,13 +677,13 @@ func (check *Checker) packageObjects() {
                }
        }
 
-       if check.conf._EnableAlias {
-               // With _Alias nodes we can process declarations in any order.
+       if check.enableAlias {
+               // With Alias nodes we can process declarations in any order.
                for _, obj := range objList {
                        check.objDecl(obj, nil)
                }
        } else {
-               // Without _Alias nodes, we process non-alias type declarations first, followed by
+               // Without Alias nodes, we process non-alias type declarations first, followed by
                // alias declarations, and then everything else. This appears to avoid most situations
                // where the type of an alias is needed before it is available.
                // There may still be cases where this is not good enough (see also go.dev/issue/25838).
index f876b16c8f6b4c47a3c0195b0a80d32c7e5084c3..8b896f7a907a1b77144e3427de1826d9efc2cda9 100644 (file)
@@ -208,7 +208,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
                check.later(func() {
                        // spec: "The receiver type must be of the form T or *T where T is a type name."
                        rtyp, _ := deref(recv.typ)
-                       atyp := _Unalias(rtyp)
+                       atyp := Unalias(rtyp)
                        if !isValid(atyp) {
                                return // error was reported before
                        }
index 3c2150273ee85c54276cea8d1af37c9b710afb35..0e0da0f7f69f1d3c3a0344043577a3e711e06994 100644 (file)
@@ -326,13 +326,13 @@ func (w *typeWriter) typ(typ Type) {
                        }
                }
 
-       case *_Alias:
+       case *Alias:
                w.typeName(t.obj)
                if w.ctxt != nil {
                        // TODO(gri) do we need to print the alias type name, too?
-                       w.typ(_Unalias(t.obj.typ))
+                       w.typ(Unalias(t.obj.typ))
                } else {
-                       w.string(fmt.Sprintf(" /* = %s */", _Unalias(t.obj.typ)))
+                       w.string(fmt.Sprintf(" /* = %s */", Unalias(t.obj.typ)))
                }
 
        default:
index cabf4eb856a0d5b5ba96e03ee2b0d54cca029688..0ee92be6ee5cd23fecb12c8b5b3a5e8c8626cf4e 100644 (file)
@@ -94,7 +94,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
                x.mode = constant_
 
        case *TypeName:
-               if !check.conf._EnableAlias && check.isBrokenAlias(obj) {
+               if !check.enableAlias && check.isBrokenAlias(obj) {
                        check.errorf(e, InvalidDeclCycle, "invalid use of type alias %s in recursive type (see go.dev/issue/50729)", obj.name)
                        return
                }
@@ -403,7 +403,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) {
 func setDefType(def *TypeName, typ Type) {
        if def != nil {
                switch t := def.typ.(type) {
-               case *_Alias:
+               case *Alias:
                        // t.fromRHS should always be set, either to an invalid type
                        // in the beginning, or to typ in certain cyclic declarations.
                        if t.fromRHS != Typ[Invalid] && t.fromRHS != typ {
index 000321e4eae2f992c5458ebdd6ed279dec688cc3..8218939b6834771987ef77e2eaa5c7e82c662f66 100644 (file)
@@ -291,8 +291,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
                u.depth--
        }()
 
-       x = _Unalias(x)
-       y = _Unalias(y)
+       x = Unalias(x)
+       y = Unalias(y)
 
        // nothing to do if x == y
        if x == y {
index 07a291b4351faa3108b25fec3dc9209afabee6e4..a880a3d93320123f3e62b9569c57990dad80f022 100644 (file)
@@ -23,7 +23,7 @@ func (check *Checker) validType(typ *Named) {
 // (say S->F->S) we have an invalid recursive type. The path list is the full
 // path of named types in a cycle, it is only needed for error reporting.
 func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
-       switch t := _Unalias(typ).(type) {
+       switch t := Unalias(typ).(type) {
        case nil:
                // We should never see a nil type but be conservative and panic
                // only in debug mode.
index f79d5eaf3a46e7e9d96244ca6ba51c2c6499ea95..8333a4d9c9cbc2cad76eaf59bdf2c819b6efd0fa 100644 (file)
@@ -8,39 +8,42 @@ package types
 
 import "fmt"
 
-// Names starting with a _ are intended to be exported eventually
-// (go.dev/issue/63223).
-
-// An _Alias represents an alias type.
-type _Alias struct {
+// An Alias represents an alias type.
+// Whether or not Alias types are created is controlled by the
+// gotypesalias setting with the GODEBUG environment variable.
+// For gotypesalias=1, alias declarations produce an Alias type.
+// Otherwise, the alias information is only in the type name,
+// which points directly to the actual (aliased) type.
+type Alias struct {
        obj     *TypeName // corresponding declared alias object
        fromRHS Type      // RHS of type alias declaration; may be an alias
        actual  Type      // actual (aliased) type; never an alias
 }
 
-// _NewAlias creates a new Alias type with the given type name and rhs.
+// NewAlias creates a new Alias type with the given type name and rhs.
 // rhs must not be nil.
-func _NewAlias(obj *TypeName, rhs Type) *_Alias {
+func NewAlias(obj *TypeName, rhs Type) *Alias {
        return (*Checker)(nil).newAlias(obj, rhs)
 }
 
-func (a *_Alias) Underlying() Type { return a.actual.Underlying() }
-func (a *_Alias) String() string   { return TypeString(a, nil) }
+func (a *Alias) Obj() *TypeName   { return a.obj }
+func (a *Alias) Underlying() Type { return a.actual.Underlying() }
+func (a *Alias) String() string   { return TypeString(a, nil) }
 
 // Type accessors
 
-// _Unalias returns t if it is not an alias type;
+// Unalias returns t if it is not an alias type;
 // otherwise it follows t's alias chain until it
 // reaches a non-alias type which is then returned.
 // Consequently, the result is never an alias type.
-func _Unalias(t Type) Type {
-       if a0, _ := t.(*_Alias); a0 != nil {
+func Unalias(t Type) Type {
+       if a0, _ := t.(*Alias); a0 != nil {
                if a0.actual != nil {
                        return a0.actual
                }
                for a := a0; ; {
                        t = a.fromRHS
-                       a, _ = t.(*_Alias)
+                       a, _ = t.(*Alias)
                        if a == nil {
                                break
                        }
@@ -56,15 +59,15 @@ func _Unalias(t Type) Type {
 // asNamed returns t as *Named if that is t's
 // actual type. It returns nil otherwise.
 func asNamed(t Type) *Named {
-       n, _ := _Unalias(t).(*Named)
+       n, _ := Unalias(t).(*Named)
        return n
 }
 
 // newAlias creates a new Alias type with the given type name and rhs.
 // rhs must not be nil.
-func (check *Checker) newAlias(obj *TypeName, rhs Type) *_Alias {
+func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
        assert(rhs != nil)
-       a := &_Alias{obj, rhs, nil}
+       a := &Alias{obj, rhs, nil}
        if obj.typ == nil {
                obj.typ = a
        }
@@ -77,6 +80,6 @@ func (check *Checker) newAlias(obj *TypeName, rhs Type) *_Alias {
        return a
 }
 
-func (a *_Alias) cleanup() {
-       _Unalias(a)
+func (a *Alias) cleanup() {
+       Unalias(a)
 }
index 0dc06af53843361a813a1fbe92614f4b4461e904..6635253fdfdd37f07a5f97293be36bad2b282bd8 100644 (file)
@@ -171,11 +171,6 @@ type Config struct {
        // for unused imports.
        DisableUnusedImportCheck bool
 
-       // If EnableAlias is set, alias declarations produce an _Alias type.
-       // Otherwise the alias information is only in the type name, which
-       // points directly to the actual (aliased) type.
-       _EnableAlias bool
-
        // If a non-empty _ErrorURL format string is provided, it is used
        // to format an error URL link that is appended to the first line
        // of an error message. ErrorURL must be a format string containing
index 1fddb450ea47a635edb1b2c40c6505f15e06bcb0..0feea6dfeba678815a8559497e643152439a79a1 100644 (file)
@@ -12,6 +12,7 @@ import (
        "go/ast"
        "go/constant"
        "go/token"
+       "internal/godebug"
        "internal/goversion"
        . "internal/types/errors"
 )
@@ -22,6 +23,9 @@ var nopos token.Pos
 // debugging/development support
 const debug = false // leave on during development
 
+// gotypesalias controls the use of Alias types
+var gotypesalias = godebug.New("gotypesalias")
+
 // exprInfo stores information about an untyped expression.
 type exprInfo struct {
        isLhs bool // expression is lhs operand of a shift with delayed type-check
@@ -94,6 +98,12 @@ type actionDesc struct {
 type Checker struct {
        // package information
        // (initialized by NewChecker, valid for the life-time of checker)
+
+       // If EnableAlias is set, alias declarations produce an Alias type.
+       // Otherwise the alias information is only in the type name, which
+       // points directly to the actual (aliased) type.
+       enableAlias bool
+
        conf *Config
        ctxt *Context // context for de-duplicating instances
        fset *token.FileSet
@@ -155,13 +165,13 @@ func (check *Checker) addDeclDep(to Object) {
 }
 
 // Note: The following three alias-related functions are only used
-//       when _Alias types are not enabled.
+//       when Alias types are not enabled.
 
 // brokenAlias records that alias doesn't have a determined type yet.
 // It also sets alias.typ to Typ[Invalid].
-// Not used if check.conf._EnableAlias is set.
+// Not used if check.enableAlias is set.
 func (check *Checker) brokenAlias(alias *TypeName) {
-       assert(!check.conf._EnableAlias)
+       assert(!check.enableAlias)
        if check.brokenAliases == nil {
                check.brokenAliases = make(map[*TypeName]bool)
        }
@@ -171,14 +181,14 @@ func (check *Checker) brokenAlias(alias *TypeName) {
 
 // validAlias records that alias has the valid type typ (possibly Typ[Invalid]).
 func (check *Checker) validAlias(alias *TypeName, typ Type) {
-       assert(!check.conf._EnableAlias)
+       assert(!check.enableAlias)
        delete(check.brokenAliases, alias)
        alias.typ = typ
 }
 
 // isBrokenAlias reports whether alias doesn't have a determined type yet.
 func (check *Checker) isBrokenAlias(alias *TypeName) bool {
-       assert(!check.conf._EnableAlias)
+       assert(!check.enableAlias)
        return check.brokenAliases[alias]
 }
 
@@ -248,13 +258,14 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
        // (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
 
        return &Checker{
-               conf:   conf,
-               ctxt:   conf.Context,
-               fset:   fset,
-               pkg:    pkg,
-               Info:   info,
-               objMap: make(map[Object]*declInfo),
-               impMap: make(map[importKey]*Package),
+               enableAlias: gotypesalias.Value() == "1",
+               conf:        conf,
+               ctxt:        conf.Context,
+               fset:        fset,
+               pkg:         pkg,
+               Info:        info,
+               objMap:      make(map[Object]*declInfo),
+               impMap:      make(map[importKey]*Package),
        }
 }
 
index e99cb2e374723fc39cb39c0229c2d84d53b6b29b..b0fa131e5da493bfc63f5a9806fc7c3c7500c210 100644 (file)
@@ -125,7 +125,7 @@ func parseFlags(src []byte, flags *flag.FlagSet) error {
 // testFiles type-checks the package consisting of the given files, and
 // compares the resulting errors with the ERROR annotations in the source.
 // Except for manual tests, each package is type-checked twice, once without
-// use of _Alias types, and once with _Alias types.
+// use of Alias types, and once with Alias types.
 //
 // The srcs slice contains the file content for the files named in the
 // filenames slice. The colDelta parameter specifies the tolerance for position
@@ -134,9 +134,11 @@ func parseFlags(src []byte, flags *flag.FlagSet) error {
 //
 // If provided, opts may be used to mutate the Config before type-checking.
 func testFiles(t *testing.T, filenames []string, srcs [][]byte, manual bool, opts ...func(*Config)) {
+       // Alias types are disabled by default
        testFilesImpl(t, filenames, srcs, manual, opts...)
        if !manual {
-               testFilesImpl(t, filenames, srcs, manual, append(opts, func(conf *Config) { *boolFieldAddr(conf, "_EnableAlias") = true })...)
+               t.Setenv("GODEBUG", "gotypesalias=1")
+               testFilesImpl(t, filenames, srcs, manual, opts...)
        }
 }
 
@@ -184,15 +186,16 @@ func testFilesImpl(t *testing.T, filenames []string, srcs [][]byte, manual bool,
        }
 
        // apply flag setting (overrides custom configuration)
-       var goexperiment string
+       var goexperiment, gotypesalias string
        flags := flag.NewFlagSet("", flag.PanicOnError)
        flags.StringVar(&conf.GoVersion, "lang", "", "")
        flags.StringVar(&goexperiment, "goexperiment", "", "")
        flags.BoolVar(&conf.FakeImportC, "fakeImportC", false, "")
-       flags.BoolVar(boolFieldAddr(&conf, "_EnableAlias"), "alias", false, "")
+       flags.StringVar(&gotypesalias, "gotypesalias", "", "")
        if err := parseFlags(srcs[0], flags); err != nil {
                t.Fatal(err)
        }
+
        exp, err := buildcfg.ParseGOEXPERIMENT(runtime.GOOS, runtime.GOARCH, goexperiment)
        if err != nil {
                t.Fatal(err)
@@ -203,6 +206,11 @@ func testFilesImpl(t *testing.T, filenames []string, srcs [][]byte, manual bool,
        }()
        buildcfg.Experiment = *exp
 
+       // By default, gotypesalias is not set.
+       if gotypesalias != "" {
+               t.Setenv("GODEBUG", "gotypesalias="+gotypesalias)
+       }
+
        // Provide Config.Info with all maps so that info recording is tested.
        info := Info{
                Types:      make(map[ast.Expr]TypeAndValue),
index 16f250aee2c602a7aa8487f34a972f9dfb2d2d28..c8716bd74fe580049614ccc2d4e5a33d8a56b70e 100644 (file)
@@ -249,7 +249,7 @@ loop:
                        // the syntactic information. We should consider storing
                        // this information explicitly in the object.
                        var alias bool
-                       if check.conf._EnableAlias {
+                       if check.enableAlias {
                                alias = obj.IsAlias()
                        } else {
                                if d := check.objMap[obj]; d != nil {
@@ -326,7 +326,7 @@ func (check *Checker) cycleError(cycle []Object) {
        if tname != nil && tname.IsAlias() {
                // If we use Alias nodes, it is initialized with Typ[Invalid].
                // TODO(gri) Adjust this code if we initialize with nil.
-               if !check.conf._EnableAlias {
+               if !check.enableAlias {
                        check.validAlias(tname, Typ[Invalid])
                }
        }
@@ -583,7 +583,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *TypeName
        // alias declaration
        if aliasDecl {
                check.verifyVersionf(atPos(tdecl.Assign), go1_9, "type aliases")
-               if check.conf._EnableAlias {
+               if check.enableAlias {
                        // TODO(gri) Should be able to use nil instead of Typ[Invalid] to mark
                        //           the alias as incomplete. Currently this causes problems
                        //           with certain cycles. Investigate.
@@ -592,7 +592,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *TypeName
                        rhs = check.definedType(tdecl.Type, obj)
                        assert(rhs != nil)
                        alias.fromRHS = rhs
-                       _Unalias(alias) // resolve alias.actual
+                       Unalias(alias) // resolve alias.actual
                } else {
                        check.brokenAlias(obj)
                        rhs = check.typ(tdecl.Type)
index 962548a9b0f3064555acc1fc539a984784538020..b804b0eb080283fd6b472a56192c14fd52e688aa 100644 (file)
@@ -544,8 +544,8 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
        case *Basic:
                // nothing to do
 
-       case *_Alias:
-               return w.isParameterized(_Unalias(t))
+       case *Alias:
+               return w.isParameterized(Unalias(t))
 
        case *Array:
                return w.isParameterized(t.elem)
@@ -698,8 +698,8 @@ func (w *cycleFinder) typ(typ Type) {
        case *Basic:
                // nothing to do
 
-       case *_Alias:
-               w.typ(_Unalias(t))
+       case *Alias:
+               w.typ(Unalias(t))
 
        case *Array:
                w.typ(t.elem)
index 01d739878840a18fd4951ffa42a87fc7acb01d87..c38459e488a6f1628ed3461ce9f35335ea946681 100644 (file)
@@ -999,9 +999,8 @@ type A = []int
 type S struct{ A }
 `
 
-       var conf Config
-       *boolFieldAddr(&conf, "_EnableAlias") = true
-       pkg := mustTypecheck(src, &conf, nil)
+       t.Setenv("GODEBUG", "gotypesalias=1")
+       pkg := mustTypecheck(src, nil, nil)
 
        S := pkg.Scope().Lookup("S")
        if S == nil {
index e6ad72843743ab2a856006e36bedf34904cb1fbf..2857ba358c19eb3283cb32a01fab4334943216c0 100644 (file)
@@ -529,7 +529,7 @@ func (check *Checker) newAssertableTo(pos token.Pos, V, T Type, cause *string) b
 // with an underlying pointer type!) and returns its base and true.
 // Otherwise it returns (typ, false).
 func deref(typ Type) (Type, bool) {
-       if p, _ := _Unalias(typ).(*Pointer); p != nil {
+       if p, _ := Unalias(typ).(*Pointer); p != nil {
                // p.base should never be nil, but be conservative
                if p.base == nil {
                        if debug {
index ee01435e77275e57a2cf94f067c38a27703408a9..74113392149fbdc1362af3d085496b8daf907b12 100644 (file)
@@ -206,7 +206,7 @@ func (w *monoGraph) assign(pkg *Package, pos token.Pos, tpar *TypeParam, targ Ty
        // type parameters.
        var do func(typ Type)
        do = func(typ Type) {
-               switch typ := _Unalias(typ).(type) {
+               switch typ := Unalias(typ).(type) {
                default:
                        panic("unexpected type")
 
index fed114edc054a564743bf4b48a6d2d077ceb9a18..21c0de255dedba8db35edd79192f509d90ec6ee4 100644 (file)
@@ -455,8 +455,8 @@ func (t *Named) AddMethod(m *Func) {
        }
 }
 
-// TODO(gri) Investigate if _Unalias can be moved to where underlying is set.
-func (t *Named) Underlying() Type { return _Unalias(t.resolve().underlying) }
+// TODO(gri) Investigate if Unalias can be moved to where underlying is set.
+func (t *Named) Underlying() Type { return Unalias(t.resolve().underlying) }
 func (t *Named) String() string   { return TypeString(t, nil) }
 
 // ----------------------------------------------------------------------------
index ef20de4b51b126db8704bd5534060a759f36a045..51b3886716f6b2dcbcea59666a89c7f8213133a9 100644 (file)
@@ -287,7 +287,7 @@ func (obj *TypeName) IsAlias() bool {
        switch t := obj.typ.(type) {
        case nil:
                return false
-       // case *_Alias:
+       // case *Alias:
        //      handled by default case
        case *Basic:
                // unsafe.Pointer is not an alias.
index 5dc775af8d4c33332a46e7b4365ee0e9bed3b80a..cac2b3c75fa09d8f65183c6c261edda5636689de 100644 (file)
@@ -9,7 +9,7 @@
 package types
 
 // isValid reports whether t is a valid type.
-func isValid(t Type) bool { return _Unalias(t) != Typ[Invalid] }
+func isValid(t Type) bool { return Unalias(t) != Typ[Invalid] }
 
 // The isX predicates below report whether t is an X.
 // If t is a type parameter the result is false; i.e.,
@@ -52,7 +52,7 @@ func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
 // for all specific types of the type parameter's type set.
 // allBasic(t, info) is an optimized version of isBasic(coreType(t), info).
 func allBasic(t Type, info BasicInfo) bool {
-       if tpar, _ := _Unalias(t).(*TypeParam); tpar != nil {
+       if tpar, _ := Unalias(t).(*TypeParam); tpar != nil {
                return tpar.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
        }
        return isBasic(t, info)
@@ -62,7 +62,7 @@ func allBasic(t Type, info BasicInfo) bool {
 // predeclared types, defined types, and type parameters.
 // hasName may be called with types that are not fully set up.
 func hasName(t Type) bool {
-       switch _Unalias(t).(type) {
+       switch Unalias(t).(type) {
        case *Basic, *Named, *TypeParam:
                return true
        }
@@ -73,7 +73,7 @@ func hasName(t Type) bool {
 // This includes all non-defined types, but also basic types.
 // isTypeLit may be called with types that are not fully set up.
 func isTypeLit(t Type) bool {
-       switch _Unalias(t).(type) {
+       switch Unalias(t).(type) {
        case *Named, *TypeParam:
                return false
        }
@@ -85,7 +85,7 @@ func isTypeLit(t Type) bool {
 // are not fully set up.
 func isTyped(t Type) bool {
        // Alias or Named types cannot denote untyped types,
-       // thus we don't need to call _Unalias or under
+       // thus we don't need to call Unalias or under
        // (which would be unsafe to do for types that are
        // not fully set up).
        b, _ := t.(*Basic)
@@ -110,7 +110,7 @@ func isNonTypeParamInterface(t Type) bool {
 
 // isTypeParam reports whether t is a type parameter.
 func isTypeParam(t Type) bool {
-       _, ok := _Unalias(t).(*TypeParam)
+       _, ok := Unalias(t).(*TypeParam)
        return ok
 }
 
@@ -119,7 +119,7 @@ func isTypeParam(t Type) bool {
 // use anywhere, but it may report a false negative if the type set has not been
 // computed yet.
 func hasEmptyTypeset(t Type) bool {
-       if tpar, _ := _Unalias(t).(*TypeParam); tpar != nil && tpar.bound != nil {
+       if tpar, _ := Unalias(t).(*TypeParam); tpar != nil && tpar.bound != nil {
                iface, _ := safeUnderlying(tpar.bound).(*Interface)
                return iface != nil && iface.tset != nil && iface.tset.IsEmpty()
        }
@@ -225,8 +225,8 @@ type comparer struct {
 
 // For changes to this code the corresponding changes should be made to unifier.nify.
 func (c *comparer) identical(x, y Type, p *ifacePair) bool {
-       x = _Unalias(x)
-       y = _Unalias(y)
+       x = Unalias(x)
+       y = Unalias(y)
 
        if x == y {
                return true
@@ -502,7 +502,7 @@ func identicalInstance(xorig Type, xargs []Type, yorig Type, yargs []Type) bool
 // it returns the incoming type for all other types. The default type
 // for untyped nil is untyped nil.
 func Default(t Type) Type {
-       if t, ok := _Unalias(t).(*Basic); ok {
+       if t, ok := Unalias(t).(*Basic); ok {
                switch t.kind {
                case UntypedBool:
                        return Typ[Bool]
index 8b6a1b4b79e0717021a114ab7484aaf021817acd..f828344749b08d73dfd89b7a2d5bfedd686f96cb 100644 (file)
@@ -659,13 +659,13 @@ func (check *Checker) packageObjects() {
                }
        }
 
-       if check.conf._EnableAlias {
-               // With _Alias nodes we can process declarations in any order.
+       if check.enableAlias {
+               // With Alias nodes we can process declarations in any order.
                for _, obj := range objList {
                        check.objDecl(obj, nil)
                }
        } else {
-               // Without _Alias nodes, we process non-alias type declarations first, followed by
+               // Without Alias nodes, we process non-alias type declarations first, followed by
                // alias declarations, and then everything else. This appears to avoid most situations
                // where the type of an alias is needed before it is available.
                // There may still be cases where this is not good enough (see also go.dev/issue/25838).
index e7a348d8510ee713a7bf7ff77046dcb2d45a9ea1..ed9fcfe58ef31f8ec1d1b6096bcdb399511530a1 100644 (file)
@@ -211,7 +211,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                check.later(func() {
                        // spec: "The receiver type must be of the form T or *T where T is a type name."
                        rtyp, _ := deref(recv.typ)
-                       atyp := _Unalias(rtyp)
+                       atyp := Unalias(rtyp)
                        if !isValid(atyp) {
                                return // error was reported before
                        }
index 6eee1af2a81c00c333bd722416035c8123d13ec3..d5623d3d86a0d984aea02797f1f155645267af2a 100644 (file)
@@ -329,13 +329,13 @@ func (w *typeWriter) typ(typ Type) {
                        }
                }
 
-       case *_Alias:
+       case *Alias:
                w.typeName(t.obj)
                if w.ctxt != nil {
                        // TODO(gri) do we need to print the alias type name, too?
-                       w.typ(_Unalias(t.obj.typ))
+                       w.typ(Unalias(t.obj.typ))
                } else {
-                       w.string(fmt.Sprintf(" /* = %s */", _Unalias(t.obj.typ)))
+                       w.string(fmt.Sprintf(" /* = %s */", Unalias(t.obj.typ)))
                }
 
        default:
index 5bc5a1f3ac72565c0e590f34391ecc87fd62ea74..2835958d9842c8bffe10501f1bc512d0ae2ce180 100644 (file)
@@ -95,7 +95,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo
                x.mode = constant_
 
        case *TypeName:
-               if !check.conf._EnableAlias && check.isBrokenAlias(obj) {
+               if !check.enableAlias && check.isBrokenAlias(obj) {
                        check.errorf(e, InvalidDeclCycle, "invalid use of type alias %s in recursive type (see go.dev/issue/50729)", obj.name)
                        return
                }
@@ -394,7 +394,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *TypeName) (T Type) {
 func setDefType(def *TypeName, typ Type) {
        if def != nil {
                switch t := def.typ.(type) {
-               case *_Alias:
+               case *Alias:
                        // t.fromRHS should always be set, either to an invalid type
                        // in the beginning, or to typ in certain cyclic declarations.
                        if t.fromRHS != Typ[Invalid] && t.fromRHS != typ {
index 7f08d9f579c0606cfa5dbf3c5082f178787c8977..d4889b93d972de0807ba2a1f0b33df892b04d654 100644 (file)
@@ -293,8 +293,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
                u.depth--
        }()
 
-       x = _Unalias(x)
-       y = _Unalias(y)
+       x = Unalias(x)
+       y = Unalias(y)
 
        // nothing to do if x == y
        if x == y {
index dde5cb039d212d083c5a580a5b828c227aba0a14..063871485732eb1ba67e0f22b8dacfc24e612e39 100644 (file)
@@ -25,7 +25,7 @@ func (check *Checker) validType(typ *Named) {
 // (say S->F->S) we have an invalid recursive type. The path list is the full
 // path of named types in a cycle, it is only needed for error reporting.
 func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
-       switch t := _Unalias(typ).(type) {
+       switch t := Unalias(typ).(type) {
        case nil:
                // We should never see a nil type but be conservative and panic
                // only in debug mode.
index 2f6d7133630f023910db8a97b478293623e8d201..fb5de8a21e63ca5ca206267719a03e1279a5bd3e 100644 (file)
@@ -29,6 +29,7 @@ var All = []Info{
        {Name: "gocachehash", Package: "cmd/go"},
        {Name: "gocachetest", Package: "cmd/go"},
        {Name: "gocacheverify", Package: "cmd/go"},
+       {Name: "gotypesalias", Package: "go/types"},
        {Name: "http2client", Package: "net/http"},
        {Name: "http2debug", Package: "net/http", Opaque: true},
        {Name: "http2server", Package: "net/http"},
index f854de0fda0ec4d924bc06eee36822dd27a24a16..a6145058bba9a2a72083c6f7e6e742315a174fc7 100644 (file)
@@ -1,4 +1,4 @@
-// -alias=false
+// -gotypesalias=0
 
 // Copyright 2017 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 96234bf1b9f4bb9e02f02b2e80807cd776ee6298..ed5853e3f239321581375d7bf315b7968a021e10 100644 (file)
@@ -1,4 +1,4 @@
-// -alias
+// -gotypesalias=1
 
 // Copyright 2017 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index c42b81d0a00b0bbe7596177053eebea63f9cb5f3..e823013f9951676daabe94e76ed63db2b9c5482a 100644 (file)
@@ -1,4 +1,4 @@
-// -alias=false
+// -gotypesalias=0
 
 // Copyright 2021 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index f1df59b7bd3bf4414da87def5c94189992836fad..e4b8e1a240a973f62ed89669f3b1a8babe9376c0 100644 (file)
@@ -1,4 +1,4 @@
-// -alias
+// -gotypesalias=1
 
 // Copyright 2021 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 21f0c09b777593195676189fff95a48816ffe2d9..59c0f2d6a015750eb73237450dcf459c06374c27 100644 (file)
@@ -1,4 +1,4 @@
-// -alias=false
+// -gotypesalias=0
 
 // Copyright 2022 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 37217887bf3fb1b4f48c241b02a9fa7067408b8b..d0e99058b7ede98bdf6a3d5d0d6252290b2ee4eb 100644 (file)
@@ -1,4 +1,4 @@
-// -alias
+// -gotypesalias=1
 
 // Copyright 2022 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 5895404217c80ef6b8f1474300695797160725a4..6b614184f39b292543200669ea0302dcd85db7e1 100644 (file)
@@ -246,6 +246,10 @@ Below is the full list of supported metrics, ordered lexicographically.
                The number of non-default behaviors executed by the cmd/go
                package due to a non-default GODEBUG=gocacheverify=... setting.
 
+       /godebug/non-default-behavior/gotypesalias:events
+               The number of non-default behaviors executed by the go/types
+               package due to a non-default GODEBUG=gotypesalias=... setting.
+
        /godebug/non-default-behavior/http2client:events
                The number of non-default behaviors executed by the net/http
                package due to a non-default GODEBUG=http2client=... setting.