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 // If t is not a type parameter, coreType returns the underlying type. 44 // If t is a type parameter, coreType returns the single underlying 45 // type of all types in its type set if it exists, or nil otherwise. If the 46 // type set contains only unrestricted and restricted channel types (with 47 // identical element types), the single underlying type is the restricted 48 // channel type if the restrictions are always the same, or nil otherwise. 49 func coreType(t Type) Type { 50 var su Type 51 typeset(t, func(_, u Type) bool { 52 if u == nil { 53 return false 54 } 55 if su != nil { 56 u = match(su, u) 57 if u == nil { 58 su = nil 59 return false 60 } 61 } 62 // su == nil || match(su, u) != nil 63 su = u 64 return true 65 }) 66 return su 67 } 68 69 // coreString is like coreType but also considers []byte 70 // and strings as identical. In this case, if successful and we saw 71 // a string, the result is of type (possibly untyped) string. 72 func coreString(t Type) Type { 73 // This explicit case is needed because otherwise the 74 // result would be string if t is an untyped string. 75 if !isTypeParam(t) { 76 return under(t) // untyped string remains untyped 77 } 78 79 var su Type 80 hasString := false 81 typeset(t, func(_, u Type) bool { 82 if u == nil { 83 return false 84 } 85 if isString(u) { 86 u = NewSlice(universeByte) 87 hasString = true 88 } 89 if su != nil { 90 u = match(su, u) 91 if u == nil { 92 su = nil 93 hasString = false 94 return false 95 } 96 } 97 // su == nil || match(su, u) != nil 98 su = u 99 return true 100 }) 101 if hasString { 102 return Typ[String] 103 } 104 return su 105 } 106 107 // If x and y are identical, match returns x. 108 // If x and y are identical channels but for their direction 109 // and one of them is unrestricted, match returns the channel 110 // with the restricted direction. 111 // In all other cases, match returns nil. 112 func match(x, y Type) Type { 113 // Common case: we don't have channels. 114 if Identical(x, y) { 115 return x 116 } 117 118 // We may have channels that differ in direction only. 119 if x, _ := x.(*Chan); x != nil { 120 if y, _ := y.(*Chan); y != nil && Identical(x.elem, y.elem) { 121 // We have channels that differ in direction only. 122 // If there's an unrestricted channel, select the restricted one. 123 switch { 124 case x.dir == SendRecv: 125 return y 126 case y.dir == SendRecv: 127 return x 128 } 129 } 130 } 131 132 // types are different 133 return nil 134 } 135