github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/types2/under.go (about)

     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 t is not a type parameter, coreType returns the underlying type.
    19  // If t is a type parameter, coreType returns the single underlying
    20  // type of all types in its type set if it exists, or nil otherwise. If the
    21  // type set contains only unrestricted and restricted channel types (with
    22  // identical element types), the single underlying type is the restricted
    23  // channel type if the restrictions are always the same, or nil otherwise.
    24  func coreType(t Type) Type {
    25  	tpar, _ := t.(*TypeParam)
    26  	if tpar == nil {
    27  		return under(t)
    28  	}
    29  
    30  	var su Type
    31  	if tpar.underIs(func(u Type) bool {
    32  		if u == nil {
    33  			return false
    34  		}
    35  		if su != nil {
    36  			u = match(su, u)
    37  			if u == nil {
    38  				return false
    39  			}
    40  		}
    41  		// su == nil || match(su, u) != nil
    42  		su = u
    43  		return true
    44  	}) {
    45  		return su
    46  	}
    47  	return nil
    48  }
    49  
    50  // coreString is like coreType but also considers []byte
    51  // and strings as identical. In this case, if successful and we saw
    52  // a string, the result is of type (possibly untyped) string.
    53  func coreString(t Type) Type {
    54  	tpar, _ := t.(*TypeParam)
    55  	if tpar == nil {
    56  		return under(t) // string or untyped string
    57  	}
    58  
    59  	var su Type
    60  	hasString := false
    61  	if tpar.underIs(func(u Type) bool {
    62  		if u == nil {
    63  			return false
    64  		}
    65  		if isString(u) {
    66  			u = NewSlice(universeByte)
    67  			hasString = true
    68  		}
    69  		if su != nil {
    70  			u = match(su, u)
    71  			if u == nil {
    72  				return false
    73  			}
    74  		}
    75  		// su == nil || match(su, u) != nil
    76  		su = u
    77  		return true
    78  	}) {
    79  		if hasString {
    80  			return Typ[String]
    81  		}
    82  		return su
    83  	}
    84  	return nil
    85  }
    86  
    87  // If x and y are identical, match returns x.
    88  // If x and y are identical channels but for their direction
    89  // and one of them is unrestricted, match returns the channel
    90  // with the restricted direction.
    91  // In all other cases, match returns nil.
    92  func match(x, y Type) Type {
    93  	// Common case: we don't have channels.
    94  	if Identical(x, y) {
    95  		return x
    96  	}
    97  
    98  	// We may have channels that differ in direction only.
    99  	if x, _ := x.(*Chan); x != nil {
   100  		if y, _ := y.(*Chan); y != nil && Identical(x.elem, y.elem) {
   101  			// We have channels that differ in direction only.
   102  			// If there's an unrestricted channel, select the restricted one.
   103  			switch {
   104  			case x.dir == SendRecv:
   105  				return y
   106  			case y.dir == SendRecv:
   107  				return x
   108  			}
   109  		}
   110  	}
   111  
   112  	// types are different
   113  	return nil
   114  }