1
2
3
4
5 package types2
6
7 import (
8 "cmd/compile/internal/syntax"
9 . "internal/types/errors"
10 )
11
12
13
14
15
16 type Union struct {
17 terms []*Term
18 }
19
20
21
22 func NewUnion(terms []*Term) *Union {
23 if len(terms) == 0 {
24 panic("empty union")
25 }
26 return &Union{terms}
27 }
28
29 func (u *Union) Len() int { return len(u.terms) }
30 func (u *Union) Term(i int) *Term { return u.terms[i] }
31
32 func (u *Union) Underlying() Type { return u }
33 func (u *Union) String() string { return TypeString(u, nil) }
34
35
36 type Term term
37
38
39 func NewTerm(tilde bool, typ Type) *Term { return &Term{tilde, typ} }
40
41 func (t *Term) Tilde() bool { return t.tilde }
42 func (t *Term) Type() Type { return t.typ }
43 func (t *Term) String() string { return (*term)(t).String() }
44
45
46
47
48
49 const maxTermCount = 100
50
51
52
53 func parseUnion(check *Checker, uexpr syntax.Expr) Type {
54 blist, tlist := flattenUnion(nil, uexpr)
55 assert(len(blist) == len(tlist)-1)
56
57 var terms []*Term
58
59 var u Type
60 for i, x := range tlist {
61 term := parseTilde(check, x)
62 if len(tlist) == 1 && !term.tilde {
63
64
65
66 return term.typ
67 }
68 if len(terms) >= maxTermCount {
69 if isValid(u) {
70 check.errorf(x, InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
71 u = Typ[Invalid]
72 }
73 } else {
74 terms = append(terms, term)
75 u = &Union{terms}
76 }
77
78 if i > 0 {
79 check.recordTypeAndValue(blist[i-1], typexpr, u, nil)
80 }
81 }
82
83 if !isValid(u) {
84 return u
85 }
86
87
88
89
90 check.later(func() {
91 for i, t := range terms {
92 if !isValid(t.typ) {
93 continue
94 }
95
96 u := under(t.typ)
97 f, _ := u.(*Interface)
98 if t.tilde {
99 if f != nil {
100 check.errorf(tlist[i], InvalidUnion, "invalid use of ~ (%s is an interface)", t.typ)
101 continue
102 }
103
104 if !Identical(u, t.typ) {
105 check.errorf(tlist[i], InvalidUnion, "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
106 continue
107 }
108 }
109
110
111
112
113
114 if f != nil {
115 tset := f.typeSet()
116 switch {
117 case tset.NumMethods() != 0:
118 check.errorf(tlist[i], InvalidUnion, "cannot use %s in union (%s contains methods)", t, t)
119 case t.typ == universeComparable.Type():
120 check.error(tlist[i], InvalidUnion, "cannot use comparable in union")
121 case tset.comparable:
122 check.errorf(tlist[i], InvalidUnion, "cannot use %s in union (%s embeds comparable)", t, t)
123 }
124 continue
125 }
126
127
128
129 if j := overlappingTerm(terms[:i], t); j >= 0 {
130 check.softErrorf(tlist[i], InvalidUnion, "overlapping terms %s and %s", t, terms[j])
131 }
132 }
133 }).describef(uexpr, "check term validity %s", uexpr)
134
135 return u
136 }
137
138 func parseTilde(check *Checker, tx syntax.Expr) *Term {
139 x := tx
140 var tilde bool
141 if op, _ := x.(*syntax.Operation); op != nil && op.Op == syntax.Tilde {
142 x = op.X
143 tilde = true
144 }
145 typ := check.typ(x)
146
147
148
149
150
151 if isTypeParam(typ) {
152 if tilde {
153 check.errorf(x, MisplacedTypeParam, "type in term %s cannot be a type parameter", tx)
154 } else {
155 check.error(x, MisplacedTypeParam, "term cannot be a type parameter")
156 }
157 typ = Typ[Invalid]
158 }
159 term := NewTerm(tilde, typ)
160 if tilde {
161 check.recordTypeAndValue(tx, typexpr, &Union{[]*Term{term}}, nil)
162 }
163 return term
164 }
165
166
167
168
169
170 func overlappingTerm(terms []*Term, y *Term) int {
171 assert(!IsInterface(y.typ))
172 for i, x := range terms {
173 if IsInterface(x.typ) {
174 continue
175 }
176
177
178 if debug {
179 if x == nil || x.typ == nil || y == nil || y.typ == nil {
180 panic("empty or top union term")
181 }
182 }
183 if !(*term)(x).disjoint((*term)(y)) {
184 return i
185 }
186 }
187 return -1
188 }
189
190
191
192 func flattenUnion(list []syntax.Expr, x syntax.Expr) (blist, tlist []syntax.Expr) {
193 if o, _ := x.(*syntax.Operation); o != nil && o.Op == syntax.Or {
194 blist, tlist = flattenUnion(list, o.X)
195 blist = append(blist, o)
196 x = o.Y
197 }
198 return blist, append(tlist, x)
199 }
200
View as plain text