Source file src/cmd/compile/internal/types2/under.go
1 // Copyright 2011 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 "iter" 8 9 // If typ is a type parameter, underIs returns the result of typ.underIs(f). 10 // Otherwise, underIs returns the result of f(typ.Underlying()). 11 func underIs(typ Type, f func(Type) bool) bool { 12 return all(typ, func(_, u Type) bool { 13 return f(u) 14 }) 15 } 16 17 // all reports whether f(t, u) is true for all (type/underlying type) 18 // pairs in the typeset of t. See [typeset] for details of sequence. 19 func all(t Type, f func(t, u Type) bool) bool { 20 if p, _ := Unalias(t).(*TypeParam); p != nil { 21 return p.typeset(f) 22 } 23 return f(t, t.Underlying()) 24 } 25 26 // typeset is an iterator over the (type/underlying type) pairs of the 27 // specific type terms of the type set implied by t. 28 // If t is a type parameter, the implied type set is the type set of t's constraint. 29 // In that case, if there are no specific terms, typeset calls yield with (nil, nil). 30 // If t is not a type parameter, the implied type set consists of just t. 31 // In any case, typeset is guaranteed to call yield at least once. 32 func typeset(t Type) iter.Seq2[Type, Type] { 33 return func(yield func(t, u Type) bool) { 34 _ = all(t, yield) 35 } 36 } 37 38 // A typeError describes a type error. 39 type typeError struct { 40 format_ string 41 args []any 42 } 43 44 var emptyTypeError typeError 45 46 func typeErrorf(format string, args ...any) *typeError { 47 if format == "" { 48 return &emptyTypeError 49 } 50 return &typeError{format, args} 51 } 52 53 // format formats a type error as a string. 54 // check may be nil. 55 func (err *typeError) format(check *Checker) string { 56 return check.sprintf(err.format_, err.args...) 57 } 58 59 // If t is a type parameter, cond is nil, and t's type set contains no channel types, 60 // commonUnder returns the common underlying type of all types in t's type set if 61 // it exists, or nil and a type error otherwise. 62 // 63 // If t is a type parameter, cond is nil, and there are channel types, t's type set 64 // must only contain channel types, they must all have the same element types, 65 // channel directions must not conflict, and commonUnder returns one of the most 66 // restricted channels. Otherwise, the function returns nil and a type error. 67 // 68 // If cond != nil, each pair (t, u) of type and underlying type in t's type set 69 // must satisfy the condition expressed by cond. If the result of cond is != nil, 70 // commonUnder returns nil and the type error reported by cond. 71 // Note that cond is called before any other conditions are checked; specifically 72 // cond may be called with (nil, nil) if the type set contains no specific types. 73 // 74 // If t is not a type parameter, commonUnder behaves as if t was a type parameter 75 // with the single type t in its type set. 76 func commonUnder(t Type, cond func(t, u Type) *typeError) (Type, *typeError) { 77 var ct, cu Type // type and respective common underlying type 78 for t, u := range typeset(t) { 79 if cond != nil { 80 if err := cond(t, u); err != nil { 81 return nil, err 82 } 83 } 84 85 if u == nil { 86 return nil, typeErrorf("no specific type") 87 } 88 89 // If this is the first type we're seeing, we're done. 90 if cu == nil { 91 ct, cu = t, u 92 continue 93 } 94 95 // If we've seen a channel before, and we have a channel now, they must be compatible. 96 if chu, _ := cu.(*Chan); chu != nil { 97 if ch, _ := u.(*Chan); ch != nil { 98 if !Identical(chu.elem, ch.elem) { 99 return nil, typeErrorf("channels %s and %s have different element types", ct, t) 100 } 101 // If we have different channel directions, keep the restricted one 102 // and complain if they conflict. 103 switch { 104 case chu.dir == ch.dir: 105 // nothing to do 106 case chu.dir == SendRecv: 107 ct, cu = t, u // switch to restricted channel 108 case ch.dir != SendRecv: 109 return nil, typeErrorf("channels %s and %s have conflicting directions", ct, t) 110 } 111 continue 112 } 113 } 114 115 // Otherwise, the current type must have the same underlying type as all previous types. 116 if !Identical(cu, u) { 117 return nil, typeErrorf("%s and %s have different underlying types", ct, t) 118 } 119 } 120 return cu, nil 121 } 122