Source file 
src/go/types/union.go
     1  
     2  
     3  
     4  
     5  package types
     6  
     7  import (
     8  	"go/ast"
     9  	"go/token"
    10  	. "internal/types/errors"
    11  )
    12  
    13  
    14  
    15  
    16  
    17  type Union struct {
    18  	terms []*Term 
    19  }
    20  
    21  
    22  
    23  func NewUnion(terms []*Term) *Union {
    24  	if len(terms) == 0 {
    25  		panic("empty union")
    26  	}
    27  	return &Union{terms}
    28  }
    29  
    30  func (u *Union) Len() int         { return len(u.terms) }
    31  func (u *Union) Term(i int) *Term { return u.terms[i] }
    32  
    33  func (u *Union) Underlying() Type { return u }
    34  func (u *Union) String() string   { return TypeString(u, nil) }
    35  
    36  
    37  type Term term
    38  
    39  
    40  func NewTerm(tilde bool, typ Type) *Term { return &Term{tilde, typ} }
    41  
    42  func (t *Term) Tilde() bool    { return t.tilde }
    43  func (t *Term) Type() Type     { return t.typ }
    44  func (t *Term) String() string { return (*term)(t).String() }
    45  
    46  
    47  
    48  
    49  
    50  const maxTermCount = 100
    51  
    52  
    53  
    54  func parseUnion(check *Checker, uexpr ast.Expr) Type {
    55  	blist, tlist := flattenUnion(nil, uexpr)
    56  	assert(len(blist) == len(tlist)-1)
    57  
    58  	var terms []*Term
    59  
    60  	var u Type
    61  	for i, x := range tlist {
    62  		term := parseTilde(check, x)
    63  		if len(tlist) == 1 && !term.tilde {
    64  			
    65  			
    66  			
    67  			return term.typ 
    68  		}
    69  		if len(terms) >= maxTermCount {
    70  			if isValid(u) {
    71  				check.errorf(x, InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
    72  				u = Typ[Invalid]
    73  			}
    74  		} else {
    75  			terms = append(terms, term)
    76  			u = &Union{terms}
    77  		}
    78  
    79  		if i > 0 {
    80  			check.recordTypeAndValue(blist[i-1], typexpr, u, nil)
    81  		}
    82  	}
    83  
    84  	if !isValid(u) {
    85  		return u
    86  	}
    87  
    88  	
    89  	
    90  	
    91  	check.later(func() {
    92  		for i, t := range terms {
    93  			if !isValid(t.typ) {
    94  				continue
    95  			}
    96  
    97  			u := under(t.typ)
    98  			f, _ := u.(*Interface)
    99  			if t.tilde {
   100  				if f != nil {
   101  					check.errorf(tlist[i], InvalidUnion, "invalid use of ~ (%s is an interface)", t.typ)
   102  					continue 
   103  				}
   104  
   105  				if !Identical(u, t.typ) {
   106  					check.errorf(tlist[i], InvalidUnion, "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
   107  					continue
   108  				}
   109  			}
   110  
   111  			
   112  			
   113  			
   114  			
   115  			if f != nil {
   116  				tset := f.typeSet()
   117  				switch {
   118  				case tset.NumMethods() != 0:
   119  					check.errorf(tlist[i], InvalidUnion, "cannot use %s in union (%s contains methods)", t, t)
   120  				case t.typ == universeComparable.Type():
   121  					check.error(tlist[i], InvalidUnion, "cannot use comparable in union")
   122  				case tset.comparable:
   123  					check.errorf(tlist[i], InvalidUnion, "cannot use %s in union (%s embeds comparable)", t, t)
   124  				}
   125  				continue 
   126  			}
   127  
   128  			
   129  			
   130  			if j := overlappingTerm(terms[:i], t); j >= 0 {
   131  				check.softErrorf(tlist[i], InvalidUnion, "overlapping terms %s and %s", t, terms[j])
   132  			}
   133  		}
   134  	}).describef(uexpr, "check term validity %s", uexpr)
   135  
   136  	return u
   137  }
   138  
   139  func parseTilde(check *Checker, tx ast.Expr) *Term {
   140  	x := tx
   141  	var tilde bool
   142  	if op, _ := x.(*ast.UnaryExpr); op != nil && op.Op == token.TILDE {
   143  		x = op.X
   144  		tilde = true
   145  	}
   146  	typ := check.typ(x)
   147  	
   148  	
   149  	
   150  	
   151  	
   152  	if isTypeParam(typ) {
   153  		if tilde {
   154  			check.errorf(x, MisplacedTypeParam, "type in term %s cannot be a type parameter", tx)
   155  		} else {
   156  			check.error(x, MisplacedTypeParam, "term cannot be a type parameter")
   157  		}
   158  		typ = Typ[Invalid]
   159  	}
   160  	term := NewTerm(tilde, typ)
   161  	if tilde {
   162  		check.recordTypeAndValue(tx, typexpr, &Union{[]*Term{term}}, nil)
   163  	}
   164  	return term
   165  }
   166  
   167  
   168  
   169  
   170  
   171  func overlappingTerm(terms []*Term, y *Term) int {
   172  	assert(!IsInterface(y.typ))
   173  	for i, x := range terms {
   174  		if IsInterface(x.typ) {
   175  			continue
   176  		}
   177  		
   178  		
   179  		if debug {
   180  			if x == nil || x.typ == nil || y == nil || y.typ == nil {
   181  				panic("empty or top union term")
   182  			}
   183  		}
   184  		if !(*term)(x).disjoint((*term)(y)) {
   185  			return i
   186  		}
   187  	}
   188  	return -1
   189  }
   190  
   191  
   192  
   193  func flattenUnion(list []ast.Expr, x ast.Expr) (blist, tlist []ast.Expr) {
   194  	if o, _ := x.(*ast.BinaryExpr); o != nil && o.Op == token.OR {
   195  		blist, tlist = flattenUnion(list, o.X)
   196  		blist = append(blist, o)
   197  		x = o.Y
   198  	}
   199  	return blist, append(tlist, x)
   200  }
   201  
View as plain text