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 // under returns the true expanded underlying type. 8 // If it doesn't exist, the result is Typ[Invalid]. 9 // under must only be called when a type is known 10 // to be fully set up. 11 func under(t Type) Type { 12 if t := asNamed(t); t != nil { 13 return t.under() 14 } 15 return t.Underlying() 16 } 17 18 // If typ is a type parameter, underIs returns the result of typ.underIs(f). 19 // Otherwise, underIs returns the result of f(under(typ)). 20 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 25 }) 26 return ok 27 } 28 29 // typeset is an iterator over the (type/underlying type) pairs of the 30 // specific type terms of the type set implied by t. 31 // If t is a type parameter, the implied type set is the type set of t's constraint. 32 // In that case, if there are no specific terms, typeset calls yield with (nil, nil). 33 // If t is not a type parameter, the implied type set consists of just t. 34 // 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 39 } 40 yield(t, under(t)) 41 } 42 43 // A typeError describes a type error. 44 type typeError struct { 45 format_ string 46 args []any 47 } 48 49 var emptyTypeError typeError 50 51 func typeErrorf(format string, args ...any) *typeError { 52 if format == "" { 53 return &emptyTypeError 54 } 55 return &typeError{format, args} 56 } 57 58 // format formats a type error as a string. 59 // check may be nil. 60 func (err *typeError) format(check *Checker) string { 61 return check.sprintf(err.format_, err.args...) 62 } 63 64 // If t is a type parameter, cond is nil, and t's type set contains no channel types, 65 // commonUnder returns the common underlying type of all types in t's type set if 66 // it exists, or nil and a type error otherwise. 67 // 68 // If t is a type parameter, cond is nil, and there are channel types, t's type set 69 // must only contain channel types, they must all have the same element types, 70 // channel directions must not conflict, and commonUnder returns one of the most 71 // restricted channels. Otherwise, the function returns nil and a type error. 72 // 73 // If cond != nil, each pair (t, u) of type and underlying type in t's type set 74 // must satisfy the condition expressed by cond. If the result of cond is != nil, 75 // commonUnder returns nil and the type error reported by cond. 76 // Note that cond is called before any other conditions are checked; specifically 77 // cond may be called with (nil, nil) if the type set contains no specific types. 78 // 79 // If t is not a type parameter, commonUnder behaves as if t was a type parameter 80 // with the single type t in its type set. 81 func commonUnder(t Type, cond func(t, u Type) *typeError) (Type, *typeError) { 82 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 { 91 if cond != nil { 92 if err = cond(t, u); err != nil { 93 return false 94 } 95 } 96 97 if u == nil { 98 return bad("no specific type") 99 } 100 101 // If this is the first type we're seeing, we're done. 102 if cu == nil { 103 ct, cu = t, u 104 return true 105 } 106 107 // If we've seen a channel before, and we have a channel now, they must be compatible. 108 if chu, _ := cu.(*Chan); chu != nil { 109 if ch, _ := u.(*Chan); ch != nil { 110 if !Identical(chu.elem, ch.elem) { 111 return bad("channels %s and %s have different element types", ct, t) 112 } 113 // If we have different channel directions, keep the restricted one 114 // and complain if they conflict. 115 switch { 116 case chu.dir == ch.dir: 117 // nothing to do 118 case chu.dir == SendRecv: 119 ct, cu = t, u // switch to restricted channel 120 case ch.dir != SendRecv: 121 return bad("channels %s and %s have conflicting directions", ct, t) 122 } 123 return true 124 } 125 } 126 127 // Otherwise, the current type must have the same underlying type as all previous types. 128 if !Identical(cu, u) { 129 return bad("%s and %s have different underlying types", ct, t) 130 } 131 132 return true 133 }) 134 135 if err != nil { 136 return nil, err 137 } 138 return cu, nil 139 } 140