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  import "iter"
     8  
     9  // If typ is a type parameter, underIs returns the result of typ.underIs(f).
    10  // Otherwise, underIs returns the result of f(typ.Underlying()).
    11  func underIs(typ Type, f func(Type) bool) bool {
    12  	return all(typ, func(_, u Type) bool {
    13  		return f(u)
    14  	})
    15  }
    16  
    17  // all reports whether f(t, u) is true for all (type/underlying type)
    18  // pairs in the typeset of t. See [typeset] for details of sequence.
    19  func all(t Type, f func(t, u Type) bool) bool {
    20  	if p, _ := Unalias(t).(*TypeParam); p != nil {
    21  		return p.typeset(f)
    22  	}
    23  	return f(t, t.Underlying())
    24  }
    25  
    26  // typeset is an iterator over the (type/underlying type) pairs of the
    27  // specific type terms of the type set implied by t.
    28  // If t is a type parameter, the implied type set is the type set of t's constraint.
    29  // In that case, if there are no specific terms, typeset calls yield with (nil, nil).
    30  // If t is not a type parameter, the implied type set consists of just t.
    31  // In any case, typeset is guaranteed to call yield at least once.
    32  func typeset(t Type) iter.Seq2[Type, Type] {
    33  	return func(yield func(t, u Type) bool) {
    34  		_ = all(t, yield)
    35  	}
    36  }
    37  
    38  // A typeError describes a type error.
    39  type typeError struct {
    40  	format_ string
    41  	args    []any
    42  }
    43  
    44  var emptyTypeError typeError
    45  
    46  func typeErrorf(format string, args ...any) *typeError {
    47  	if format == "" {
    48  		return &emptyTypeError
    49  	}
    50  	return &typeError{format, args}
    51  }
    52  
    53  // format formats a type error as a string.
    54  // check may be nil.
    55  func (err *typeError) format(check *Checker) string {
    56  	return check.sprintf(err.format_, err.args...)
    57  }
    58  
    59  // If t is a type parameter, cond is nil, and t's type set contains no channel types,
    60  // commonUnder returns the common underlying type of all types in t's type set if
    61  // it exists, or nil and a type error otherwise.
    62  //
    63  // If t is a type parameter, cond is nil, and there are channel types, t's type set
    64  // must only contain channel types, they must all have the same element types,
    65  // channel directions must not conflict, and commonUnder returns one of the most
    66  // restricted channels. Otherwise, the function returns nil and a type error.
    67  //
    68  // If cond != nil, each pair (t, u) of type and underlying type in t's type set
    69  // must satisfy the condition expressed by cond. If the result of cond is != nil,
    70  // commonUnder returns nil and the type error reported by cond.
    71  // Note that cond is called before any other conditions are checked; specifically
    72  // cond may be called with (nil, nil) if the type set contains no specific types.
    73  //
    74  // If t is not a type parameter, commonUnder behaves as if t was a type parameter
    75  // with the single type t in its type set.
    76  func commonUnder(t Type, cond func(t, u Type) *typeError) (Type, *typeError) {
    77  	var ct, cu Type // type and respective common underlying type
    78  	for t, u := range typeset(t) {
    79  		if cond != nil {
    80  			if err := cond(t, u); err != nil {
    81  				return nil, err
    82  			}
    83  		}
    84  
    85  		if u == nil {
    86  			return nil, typeErrorf("no specific type")
    87  		}
    88  
    89  		// If this is the first type we're seeing, we're done.
    90  		if cu == nil {
    91  			ct, cu = t, u
    92  			continue
    93  		}
    94  
    95  		// If we've seen a channel before, and we have a channel now, they must be compatible.
    96  		if chu, _ := cu.(*Chan); chu != nil {
    97  			if ch, _ := u.(*Chan); ch != nil {
    98  				if !Identical(chu.elem, ch.elem) {
    99  					return nil, typeErrorf("channels %s and %s have different element types", ct, t)
   100  				}
   101  				// If we have different channel directions, keep the restricted one
   102  				// and complain if they conflict.
   103  				switch {
   104  				case chu.dir == ch.dir:
   105  					// nothing to do
   106  				case chu.dir == SendRecv:
   107  					ct, cu = t, u // switch to restricted channel
   108  				case ch.dir != SendRecv:
   109  					return nil, typeErrorf("channels %s and %s have conflicting directions", ct, t)
   110  				}
   111  				continue
   112  			}
   113  		}
   114  
   115  		// Otherwise, the current type must have the same underlying type as all previous types.
   116  		if !Identical(cu, u) {
   117  			return nil, typeErrorf("%s and %s have different underlying types", ct, t)
   118  		}
   119  	}
   120  	return cu, nil
   121  }
   122  

View as plain text