| // Copyright 2021 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package types |
| |
| // A term describes elementary type sets: |
| // |
| // β
: (*term)(nil) == β
// set of no types (empty set) |
| // π€: &term{} == π€ // set of all types (π€niverse) |
| // T: &term{false, T} == {T} // set of type T |
| // ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t |
| // |
| type term struct { |
| tilde bool // valid if typ != nil |
| typ Type |
| } |
| |
| func (x *term) String() string { |
| switch { |
| case x == nil: |
| return "β
" |
| case x.typ == nil: |
| return "π€" |
| case x.tilde: |
| return "~" + x.typ.String() |
| default: |
| return x.typ.String() |
| } |
| } |
| |
| // equal reports whether x and y represent the same type set. |
| func (x *term) equal(y *term) bool { |
| // easy cases |
| switch { |
| case x == nil || y == nil: |
| return x == y |
| case x.typ == nil || y.typ == nil: |
| return x.typ == y.typ |
| } |
| // β
β x, y β π€ |
| |
| return x.tilde == y.tilde && Identical(x.typ, y.typ) |
| } |
| |
| // union returns the union x βͺ y: zero, one, or two non-nil terms. |
| func (x *term) union(y *term) (_, _ *term) { |
| // easy cases |
| switch { |
| case x == nil && y == nil: |
| return nil, nil // β
βͺ β
== β
|
| case x == nil: |
| return y, nil // β
βͺ y == y |
| case y == nil: |
| return x, nil // x βͺ β
== x |
| case x.typ == nil: |
| return x, nil // π€ βͺ y == π€ |
| case y.typ == nil: |
| return y, nil // x βͺ π€ == π€ |
| } |
| // β
β x, y β π€ |
| |
| if x.disjoint(y) { |
| return x, y // x βͺ y == (x, y) if x β© y == β
|
| } |
| // x.typ == y.typ |
| |
| // ~t βͺ ~t == ~t |
| // ~t βͺ T == ~t |
| // T βͺ ~t == ~t |
| // T βͺ T == T |
| if x.tilde || !y.tilde { |
| return x, nil |
| } |
| return y, nil |
| } |
| |
| // intersect returns the intersection x β© y. |
| func (x *term) intersect(y *term) *term { |
| // easy cases |
| switch { |
| case x == nil || y == nil: |
| return nil // β
β© y == β
and β© β
== β
|
| case x.typ == nil: |
| return y // π€ β© y == y |
| case y.typ == nil: |
| return x // x β© π€ == x |
| } |
| // β
β x, y β π€ |
| |
| if x.disjoint(y) { |
| return nil // x β© y == β
if x β© y == β
|
| } |
| // x.typ == y.typ |
| |
| // ~t β© ~t == ~t |
| // ~t β© T == T |
| // T β© ~t == T |
| // T β© T == T |
| if !x.tilde || y.tilde { |
| return x |
| } |
| return y |
| } |
| |
| // includes reports whether t β x. |
| func (x *term) includes(t Type) bool { |
| // easy cases |
| switch { |
| case x == nil: |
| return false // t β β
== false |
| case x.typ == nil: |
| return true // t β π€ == true |
| } |
| // β
β x β π€ |
| |
| u := t |
| if x.tilde { |
| u = under(u) |
| } |
| return Identical(x.typ, u) |
| } |
| |
| // subsetOf reports whether x β y. |
| func (x *term) subsetOf(y *term) bool { |
| // easy cases |
| switch { |
| case x == nil: |
| return true // β
β y == true |
| case y == nil: |
| return false // x β β
== false since x != β
|
| case y.typ == nil: |
| return true // x β π€ == true |
| case x.typ == nil: |
| return false // π€ β y == false since y != π€ |
| } |
| // β
β x, y β π€ |
| |
| if x.disjoint(y) { |
| return false // x β y == false if x β© y == β
|
| } |
| // x.typ == y.typ |
| |
| // ~t β ~t == true |
| // ~t β T == false |
| // T β ~t == true |
| // T β T == true |
| return !x.tilde || y.tilde |
| } |
| |
| // disjoint reports whether x β© y == β
. |
| // x.typ and y.typ must not be nil. |
| func (x *term) disjoint(y *term) bool { |
| if debug && (x.typ == nil || y.typ == nil) { |
| panic("invalid argument(s)") |
| } |
| ux := x.typ |
| if y.tilde { |
| ux = under(ux) |
| } |
| uy := y.typ |
| if x.tilde { |
| uy = under(uy) |
| } |
| return !Identical(ux, uy) |
| } |