--- /dev/null
+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
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
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
}
// 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
}
return a
}
-func (a *_Alias) cleanup() {
- _Unalias(a)
+func (a *Alias) cleanup() {
+ Unalias(a)
}
// 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
"errors"
"fmt"
"go/constant"
+ "internal/godebug"
"internal/goversion"
. "internal/types/errors"
)
// 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
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
}
// 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)
}
// 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]
}
// (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),
}
}
// 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
//
// 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...)
}
}
}
// 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)
}()
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),
// 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 {
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])
}
}
// 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.
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)
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)
case *Basic:
// nothing to do
- case *_Alias:
- w.typ(_Unalias(t))
+ case *Alias:
+ w.typ(Unalias(t))
case *Array:
w.typ(t.elem)
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 {
// 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 {
// 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")
}
}
-// 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) }
// ----------------------------------------------------------------------------
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.
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.,
// 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)
// 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
}
// 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
}
// 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)
// isTypeParam reports whether t is a type parameter.
func isTypeParam(t Type) bool {
- _, ok := _Unalias(t).(*TypeParam)
+ _, ok := Unalias(t).(*TypeParam)
return ok
}
// 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()
}
// 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
// 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]
}
}
- 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).
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
}
}
}
- 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:
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
}
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 {
u.depth--
}()
- x = _Unalias(x)
- y = _Unalias(y)
+ x = Unalias(x)
+ y = Unalias(y)
// nothing to do if x == y
if x == y {
// (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.
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
}
// 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
}
return a
}
-func (a *_Alias) cleanup() {
- _Unalias(a)
+func (a *Alias) cleanup() {
+ Unalias(a)
}
// 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
"go/ast"
"go/constant"
"go/token"
+ "internal/godebug"
"internal/goversion"
. "internal/types/errors"
)
// 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
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
}
// 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)
}
// 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]
}
// (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),
}
}
// 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
//
// 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...)
}
}
}
// 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)
}()
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),
// 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 {
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])
}
}
// 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.
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)
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)
case *Basic:
// nothing to do
- case *_Alias:
- w.typ(_Unalias(t))
+ case *Alias:
+ w.typ(Unalias(t))
case *Array:
w.typ(t.elem)
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 {
// 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 {
// 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")
}
}
-// 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) }
// ----------------------------------------------------------------------------
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.
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.,
// 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)
// 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
}
// 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
}
// 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)
// isTypeParam reports whether t is a type parameter.
func isTypeParam(t Type) bool {
- _, ok := _Unalias(t).(*TypeParam)
+ _, ok := Unalias(t).(*TypeParam)
return ok
}
// 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()
}
// 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
// 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]
}
}
- 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).
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
}
}
}
- 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:
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
}
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 {
u.depth--
}()
- x = _Unalias(x)
- y = _Unalias(y)
+ x = Unalias(x)
+ y = Unalias(y)
// nothing to do if x == y
if x == y {
// (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.
{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"},
-// -alias=false
+// -gotypesalias=0
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// -alias
+// -gotypesalias=1
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// -alias=false
+// -gotypesalias=0
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// -alias
+// -gotypesalias=1
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// -alias=false
+// -gotypesalias=0
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// -alias
+// -gotypesalias=1
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
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.