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