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