Skip to content

Commit 6b32c61

Browse files
adonovangopherbot
authored andcommitted
go/types: make typeset return an iterator
typeset(t) now returns a func equivalent to iter.Seq2[Type, Type] for the sequence over (type, underlying) pairs in the typeset of t. underIs was modified to take advantage of the underlying iteration primitive, all, which computes the desired boolean conjunction directly. Change-Id: I3e17d5970fd2908c5dca0754db3e251bf1200af2 Reviewed-on: https://go-review.googlesource.com/c/go/+/688876 Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent fbba930 commit 6b32c61

File tree

12 files changed

+129
-160
lines changed

12 files changed

+129
-160
lines changed

src/cmd/compile/internal/types2/builtins.go

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,17 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
9898
if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
9999
y := args[1]
100100
hasString := false
101-
typeset(y.typ, func(_, u Type) bool {
101+
for _, u := range typeset(y.typ) {
102102
if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
103-
return true
104-
}
105-
if isString(u) {
103+
// typeset ⊇ {[]byte}
104+
} else if isString(u) {
105+
// typeset ⊇ {string}
106106
hasString = true
107-
return true
107+
} else {
108+
y = nil
109+
break
108110
}
109-
y = nil
110-
return false
111-
})
111+
}
112112
if y != nil && hasString {
113113
// setting the signature also signals that we're done
114114
sig = makeSig(x.typ, x.typ, y.typ)
@@ -368,16 +368,16 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
368368
var special bool
369369
if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
370370
special = true
371-
typeset(y.typ, func(_, u Type) bool {
371+
for _, u := range typeset(y.typ) {
372372
if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
373-
return true
374-
}
375-
if isString(u) {
376-
return true
373+
// typeset ⊇ {[]byte}
374+
} else if isString(u) {
375+
// typeset ⊇ {string}
376+
} else {
377+
special = false
378+
break
377379
}
378-
special = false
379-
return false
380-
})
380+
}
381381
}
382382

383383
// general case
@@ -980,29 +980,22 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
980980
// or a type error if x is not a slice (or a type set of slices).
981981
func sliceElem(x *operand) (Type, *typeError) {
982982
var E Type
983-
var err *typeError
984-
typeset(x.typ, func(_, u Type) bool {
983+
for _, u := range typeset(x.typ) {
985984
s, _ := u.(*Slice)
986985
if s == nil {
987986
if x.isNil() {
988987
// Printing x in this case would just print "nil".
989988
// Special case this so we can emphasize "untyped".
990-
err = typeErrorf("argument must be a slice; have untyped nil")
989+
return nil, typeErrorf("argument must be a slice; have untyped nil")
991990
} else {
992-
err = typeErrorf("argument must be a slice; have %s", x)
991+
return nil, typeErrorf("argument must be a slice; have %s", x)
993992
}
994-
return false
995993
}
996994
if E == nil {
997995
E = s.elem
998996
} else if !Identical(E, s.elem) {
999-
err = typeErrorf("mismatched slice element types %s and %s in %s", E, s.elem, x)
1000-
return false
997+
return nil, typeErrorf("mismatched slice element types %s and %s in %s", E, s.elem, x)
1001998
}
1002-
return true
1003-
})
1004-
if err != nil {
1005-
return nil, err
1006999
}
10071000
return E, nil
10081001
}

src/cmd/compile/internal/types2/index.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,11 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
216216
// determine common underlying type cu
217217
var ct, cu Type // type and respective common underlying type
218218
var hasString bool
219-
typeset(x.typ, func(t, u Type) bool {
219+
for t, u := range typeset(x.typ) {
220220
if u == nil {
221221
check.errorf(x, NonSliceableOperand, "cannot slice %s: no specific type in %s", x, x.typ)
222222
cu = nil
223-
return false
223+
break
224224
}
225225

226226
// Treat strings like byte slices but remember that we saw a string.
@@ -232,18 +232,16 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
232232
// If this is the first type we're seeing, we're done.
233233
if cu == nil {
234234
ct, cu = t, u
235-
return true
235+
continue
236236
}
237237

238238
// Otherwise, the current type must have the same underlying type as all previous types.
239239
if !Identical(cu, u) {
240240
check.errorf(x, NonSliceableOperand, "cannot slice %s: %s and %s have different underlying types", x, ct, t)
241241
cu = nil
242-
return false
242+
break
243243
}
244-
245-
return true
246-
})
244+
}
247245
if hasString {
248246
// If we saw a string, proceed with string type,
249247
// but don't go from untyped string to string.

src/cmd/compile/internal/types2/signature.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params
4949
}
5050
last := params.At(n - 1).typ
5151
var S *Slice
52-
typeset(last, func(t, _ Type) bool {
52+
for t := range typeset(last) {
5353
var s *Slice
5454
if isString(t) {
5555
s = NewSlice(universeByte)
@@ -60,10 +60,9 @@ func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params
6060
S = s
6161
} else if !Identical(S, s) {
6262
S = nil
63-
return false
63+
break
6464
}
65-
return true
66-
})
65+
}
6766
if S == nil {
6867
panic(fmt.Sprintf("got %s, want variadic parameter of unnamed slice or string type", last))
6968
}

src/cmd/compile/internal/types2/typeparam.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ func (t *TypeParam) is(f func(*term) bool) bool {
155155
return t.iface().typeSet().is(f)
156156
}
157157

158-
// typeset is an iterator over the (type/underlying type) pairs of the
158+
// typeset reports whether f(t, y) is true for all (type/underlying type) pairs of the
159159
// specific type terms of t's constraint.
160-
// If there are no specific terms, typeset calls yield with (nil, nil).
161-
// In any case, typeset is guaranteed to call yield at least once.
162-
func (t *TypeParam) typeset(yield func(t, u Type) bool) {
163-
t.iface().typeSet().typeset(yield)
160+
// If there are no specific terms, typeset returns f(nil, nil).
161+
// In any case, typeset is guaranteed to call f at least once.
162+
func (t *TypeParam) typeset(f func(t, u Type) bool) bool {
163+
return t.iface().typeSet().all(f)
164164
}

src/cmd/compile/internal/types2/typeset.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,12 @@ func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll
104104
// subsetOf reports whether s1 ⊆ s2.
105105
func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
106106

107-
// typeset is an iterator over the (type/underlying type) pairs in s.
108-
// If s has no specific terms, typeset calls yield with (nil, nil).
109-
// In any case, typeset is guaranteed to call yield at least once.
110-
func (s *_TypeSet) typeset(yield func(t, u Type) bool) {
107+
// all reports whether f(t, u) is true for each (type/underlying type) pairs in s.
108+
// If s has no specific terms, all calls f(nil, nil).
109+
// In any case, all is guaranteed to call f at least once.
110+
func (s *_TypeSet) all(f func(t, u Type) bool) bool {
111111
if !s.hasTerms() {
112-
yield(nil, nil)
113-
return
112+
return f(nil, nil)
114113
}
115114

116115
for _, t := range s.terms {
@@ -123,10 +122,11 @@ func (s *_TypeSet) typeset(yield func(t, u Type) bool) {
123122
if debug {
124123
assert(Identical(u, under(u)))
125124
}
126-
if !yield(t.typ, u) {
127-
break
125+
if !f(t.typ, u) {
126+
return false
128127
}
129128
}
129+
return true
130130
}
131131

132132
// is calls f with the specific type terms of s and reports whether

src/cmd/compile/internal/types2/under.go

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package types2
66

7+
import "iter"
8+
79
// under returns the true expanded underlying type.
810
// If it doesn't exist, the result is Typ[Invalid].
911
// under must only be called when a type is known
@@ -18,12 +20,18 @@ func under(t Type) Type {
1820
// If typ is a type parameter, underIs returns the result of typ.underIs(f).
1921
// Otherwise, underIs returns the result of f(under(typ)).
2022
func underIs(typ Type, f func(Type) bool) bool {
21-
var ok bool
22-
typeset(typ, func(_, u Type) bool {
23-
ok = f(u)
24-
return ok
23+
return all(typ, func(_, u Type) bool {
24+
return f(u)
2525
})
26-
return ok
26+
}
27+
28+
// all reports whether f(t, u) is true for all (type/underlying type)
29+
// pairs in the typeset of t. See [typeset] for details of sequence.
30+
func all(t Type, f func(t, u Type) bool) bool {
31+
if p, _ := Unalias(t).(*TypeParam); p != nil {
32+
return p.typeset(f)
33+
}
34+
return f(t, under(t))
2735
}
2836

2937
// typeset is an iterator over the (type/underlying type) pairs of the
@@ -32,12 +40,10 @@ func underIs(typ Type, f func(Type) bool) bool {
3240
// In that case, if there are no specific terms, typeset calls yield with (nil, nil).
3341
// If t is not a type parameter, the implied type set consists of just t.
3442
// In any case, typeset is guaranteed to call yield at least once.
35-
func typeset(t Type, yield func(t, u Type) bool) {
36-
if p, _ := Unalias(t).(*TypeParam); p != nil {
37-
p.typeset(yield)
38-
return
43+
func typeset(t Type) iter.Seq2[Type, Type] {
44+
return func(yield func(t, u Type) bool) {
45+
_ = all(t, yield)
3946
}
40-
yield(t, under(t))
4147
}
4248

4349
// A typeError describes a type error.
@@ -80,35 +86,28 @@ func (err *typeError) format(check *Checker) string {
8086
// with the single type t in its type set.
8187
func commonUnder(t Type, cond func(t, u Type) *typeError) (Type, *typeError) {
8288
var ct, cu Type // type and respective common underlying type
83-
var err *typeError
84-
85-
bad := func(format string, args ...any) bool {
86-
err = typeErrorf(format, args...)
87-
return false
88-
}
89-
90-
typeset(t, func(t, u Type) bool {
89+
for t, u := range typeset(t) {
9190
if cond != nil {
92-
if err = cond(t, u); err != nil {
93-
return false
91+
if err := cond(t, u); err != nil {
92+
return nil, err
9493
}
9594
}
9695

9796
if u == nil {
98-
return bad("no specific type")
97+
return nil, typeErrorf("no specific type")
9998
}
10099

101100
// If this is the first type we're seeing, we're done.
102101
if cu == nil {
103102
ct, cu = t, u
104-
return true
103+
continue
105104
}
106105

107106
// If we've seen a channel before, and we have a channel now, they must be compatible.
108107
if chu, _ := cu.(*Chan); chu != nil {
109108
if ch, _ := u.(*Chan); ch != nil {
110109
if !Identical(chu.elem, ch.elem) {
111-
return bad("channels %s and %s have different element types", ct, t)
110+
return nil, typeErrorf("channels %s and %s have different element types", ct, t)
112111
}
113112
// If we have different channel directions, keep the restricted one
114113
// and complain if they conflict.
@@ -118,22 +117,16 @@ func commonUnder(t Type, cond func(t, u Type) *typeError) (Type, *typeError) {
118117
case chu.dir == SendRecv:
119118
ct, cu = t, u // switch to restricted channel
120119
case ch.dir != SendRecv:
121-
return bad("channels %s and %s have conflicting directions", ct, t)
120+
return nil, typeErrorf("channels %s and %s have conflicting directions", ct, t)
122121
}
123-
return true
122+
continue
124123
}
125124
}
126125

127126
// Otherwise, the current type must have the same underlying type as all previous types.
128127
if !Identical(cu, u) {
129-
return bad("%s and %s have different underlying types", ct, t)
128+
return nil, typeErrorf("%s and %s have different underlying types", ct, t)
130129
}
131-
132-
return true
133-
})
134-
135-
if err != nil {
136-
return nil, err
137130
}
138131
return cu, nil
139132
}

src/go/types/builtins.go

Lines changed: 20 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)