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  

View as plain text