Source file src/cmd/compile/internal/types2/alias.go
1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types2 6 7 import ( 8 "cmd/compile/internal/syntax" 9 "fmt" 10 ) 11 12 // An Alias represents an alias type. 13 // 14 // Alias types are created by alias declarations such as: 15 // 16 // type A = int 17 // 18 // The type on the right-hand side of the declaration can be accessed 19 // using [Alias.Rhs]. This type may itself be an alias. 20 // Call [Unalias] to obtain the first non-alias type in a chain of 21 // alias type declarations. 22 // 23 // Like a defined ([Named]) type, an alias type has a name. 24 // Use the [Alias.Obj] method to access its [TypeName] object. 25 // 26 // Historically, Alias types were not materialized so that, in the example 27 // above, A's type was represented by a Basic (int), not an Alias 28 // whose [Alias.Rhs] is int. But Go 1.24 allows you to declare an 29 // alias type with type parameters or arguments: 30 // 31 // type Set[K comparable] = map[K]bool 32 // s := make(Set[String]) 33 // 34 // and this requires that Alias types be materialized. Use the 35 // [Alias.TypeParams] and [Alias.TypeArgs] methods to access them. 36 // 37 // To ease the transition, the Alias type was introduced in go1.22, 38 // but the type-checker would not construct values of this type unless 39 // the GODEBUG=gotypesalias=1 environment variable was provided. 40 // Starting in go1.23, this variable is enabled by default. 41 // This setting also causes the predeclared type "any" to be 42 // represented as an Alias, not a bare [Interface]. 43 type Alias struct { 44 obj *TypeName // corresponding declared alias object 45 orig *Alias // original, uninstantiated alias 46 tparams *TypeParamList // type parameters, or nil 47 targs *TypeList // type arguments, or nil 48 fromRHS Type // RHS of type alias declaration; may be an alias 49 actual Type // actual (aliased) type; never an alias 50 } 51 52 // NewAlias creates a new Alias type with the given type name and rhs. 53 // rhs must not be nil. 54 func NewAlias(obj *TypeName, rhs Type) *Alias { 55 alias := (*Checker)(nil).newAlias(obj, rhs) 56 // Ensure that alias.actual is set (#65455). 57 alias.cleanup() 58 return alias 59 } 60 61 // Obj returns the type name for the declaration defining the alias type a. 62 // For instantiated types, this is same as the type name of the origin type. 63 func (a *Alias) Obj() *TypeName { return a.orig.obj } 64 65 func (a *Alias) String() string { return TypeString(a, nil) } 66 67 // Underlying returns the [underlying type] of the alias type a, which is the 68 // underlying type of the aliased type. Underlying types are never Named, 69 // TypeParam, or Alias types. 70 // 71 // [underlying type]: https://go.dev/ref/spec#Underlying_types. 72 func (a *Alias) Underlying() Type { return unalias(a).Underlying() } 73 74 // Origin returns the generic Alias type of which a is an instance. 75 // If a is not an instance of a generic alias, Origin returns a. 76 func (a *Alias) Origin() *Alias { return a.orig } 77 78 // TypeParams returns the type parameters of the alias type a, or nil. 79 // A generic Alias and its instances have the same type parameters. 80 func (a *Alias) TypeParams() *TypeParamList { return a.tparams } 81 82 // SetTypeParams sets the type parameters of the alias type a. 83 // The alias a must not have type arguments. 84 func (a *Alias) SetTypeParams(tparams []*TypeParam) { 85 assert(a.targs == nil) 86 a.tparams = bindTParams(tparams) 87 } 88 89 // TypeArgs returns the type arguments used to instantiate the Alias type. 90 // If a is not an instance of a generic alias, the result is nil. 91 func (a *Alias) TypeArgs() *TypeList { return a.targs } 92 93 // Rhs returns the type R on the right-hand side of an alias 94 // declaration "type A = R", which may be another alias. 95 func (a *Alias) Rhs() Type { return a.fromRHS } 96 97 // Unalias returns t if it is not an alias type; 98 // otherwise it follows t's alias chain until it 99 // reaches a non-alias type which is then returned. 100 // Consequently, the result is never an alias type. 101 func Unalias(t Type) Type { 102 if a0, _ := t.(*Alias); a0 != nil { 103 return unalias(a0) 104 } 105 return t 106 } 107 108 func unalias(a0 *Alias) Type { 109 if a0.actual != nil { 110 return a0.actual 111 } 112 var t Type 113 for a := a0; a != nil; a, _ = t.(*Alias) { 114 t = a.fromRHS 115 } 116 if t == nil { 117 panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name)) 118 } 119 120 // Memoize the type only if valid. 121 // In the presence of unfinished cyclic declarations, Unalias 122 // would otherwise latch the invalid value (#66704). 123 // TODO(adonovan): rethink, along with checker.typeDecl's use 124 // of Invalid to mark unfinished aliases. 125 if t != Typ[Invalid] { 126 a0.actual = t 127 } 128 129 return t 130 } 131 132 // asNamed returns t as *Named if that is t's 133 // actual type. It returns nil otherwise. 134 func asNamed(t Type) *Named { 135 n, _ := Unalias(t).(*Named) 136 return n 137 } 138 139 // newAlias creates a new Alias type with the given type name and rhs. 140 // rhs must not be nil. 141 func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias { 142 assert(rhs != nil) 143 a := new(Alias) 144 a.obj = obj 145 a.orig = a 146 a.fromRHS = rhs 147 if obj.typ == nil { 148 obj.typ = a 149 } 150 151 // Ensure that a.actual is set at the end of type checking. 152 if check != nil { 153 check.needsCleanup(a) 154 } 155 156 return a 157 } 158 159 // newAliasInstance creates a new alias instance for the given origin and type 160 // arguments, recording pos as the position of its synthetic object (for error 161 // reporting). 162 func (check *Checker) newAliasInstance(pos syntax.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias { 163 assert(len(targs) > 0) 164 obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil) 165 rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt) 166 res := check.newAlias(obj, rhs) 167 res.orig = orig 168 res.tparams = orig.tparams 169 res.targs = newTypeList(targs) 170 return res 171 } 172 173 func (a *Alias) cleanup() { 174 // Ensure a.actual is set before types are published, 175 // so Unalias is a pure "getter", not a "setter". 176 actual := Unalias(a) 177 178 if actual == Typ[Invalid] { 179 // We don't set a.actual to Typ[Invalid] during type checking, 180 // as it may indicate that the RHS is not fully set up. 181 a.actual = actual 182 } 183 } 184