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  

View as plain text