[meta] Make TypeVar shareable and mutable;

... since its type set can change over time during type inference. Use a
Rc<RefCell> to achieve this.
This commit is contained in:
Benjamin Bouvier
2019-04-18 18:38:11 +02:00
parent b85146e945
commit dfb27c3402

View File

@@ -30,25 +30,25 @@ pub struct TypeVarContent {
/// Type set associated to the type variable.
/// This field must remain private; use `get_typeset()` or `get_raw_typeset()` to get the
/// information you want.
type_set: Rc<TypeSet>,
type_set: TypeSet,
pub base: Option<TypeVarParent>,
}
#[derive(Clone, Debug)]
pub struct TypeVar {
content: Rc<TypeVarContent>,
content: Rc<RefCell<TypeVarContent>>,
}
impl TypeVar {
pub fn new(name: impl Into<String>, doc: impl Into<String>, type_set: TypeSet) -> Self {
Self {
content: Rc::new(TypeVarContent {
content: Rc::new(RefCell::new(TypeVarContent {
name: name.into(),
doc: doc.into(),
type_set: Rc::new(type_set),
type_set,
base: None,
}),
})),
}
}
@@ -89,20 +89,37 @@ impl TypeVar {
TypeVar::new(name, doc, builder.finish())
}
/// Returns this typevar's type set, maybe computing it from the parent.
fn get_typeset(&self) -> Rc<TypeSet> {
// TODO Can this be done in a non-lazy way in derived() and we can remove this function and
// the one below?
match &self.content.base {
Some(base) => Rc::new(base.type_var.get_typeset().image(base.derived_func)),
None => self.content.type_set.clone(),
/// Get a fresh copy of self, named after `name`. Can only be called on non-derived typevars.
pub fn copy_from(other: &TypeVar, name: String) -> TypeVar {
assert!(
other.base.is_none(),
"copy_from() can only be called on non-derived type variables"
);
TypeVar {
content: Rc::new(RefCell::new(TypeVarContent {
name,
doc: "".into(),
type_set: other.type_set.clone(),
base: None,
})),
}
}
/// Returns the typeset for this TV. If the TV is derived, computes it recursively from the
/// derived function and the base's typeset.
/// Note this can't be done non-lazily in the constructor, because the TypeSet of the base may
/// change over time.
pub fn get_typeset(&self) -> TypeSet {
match &self.base {
Some(base) => base.type_var.get_typeset().image(base.derived_func),
None => self.type_set.clone(),
}
}
/// Returns this typevar's type set, assuming this type var has no parent.
pub fn get_raw_typeset(&self) -> &TypeSet {
assert_eq!(self.content.type_set, self.get_typeset());
&*self.content.type_set
assert_eq!(self.type_set, self.get_typeset());
&self.type_set
}
/// If the associated typeset has a single type return it. Otherwise return None.
@@ -117,7 +134,7 @@ impl TypeVar {
/// Get the free type variable controlling this one.
pub fn free_typevar(&self) -> Option<TypeVar> {
match &self.content.base {
match &self.base {
Some(base) => base.type_var.free_typevar(),
None => {
match self.singleton_type() {
@@ -130,7 +147,7 @@ impl TypeVar {
}
/// Create a type variable that is a function of another.
fn derived(&self, derived_func: DerivedFunc) -> TypeVar {
pub fn derived(&self, derived_func: DerivedFunc) -> TypeVar {
let ts = self.get_typeset();
// Safety checks to avoid over/underflows.
@@ -182,7 +199,7 @@ impl TypeVar {
}
return TypeVar {
content: Rc::new(TypeVarContent {
content: Rc::new(RefCell::new(TypeVarContent {
name: format!("{}({})", derived_func.name(), self.name),
doc: "".into(),
type_set: ts,
@@ -190,7 +207,7 @@ impl TypeVar {
type_var: self.clone(),
derived_func,
}),
}),
})),
};
}
@@ -215,6 +232,52 @@ impl TypeVar {
pub fn to_bitvec(&self) -> TypeVar {
return self.derived(DerivedFunc::ToBitVec);
}
/// Constrain the range of types this variable can assume to a subset of those in the typeset
/// ts.
/// May mutate itself if it's not derived, or its parent if it is.
pub fn constrain_types_by_ts(&self, type_set: TypeSet) {
match &self.base {
Some(base) => {
base.type_var
.constrain_types_by_ts(type_set.preimage(base.derived_func));
}
None => {
self.content
.borrow_mut()
.type_set
.inplace_intersect_with(&type_set);
}
}
}
/// Constrain the range of types this variable can assume to a subset of those `other` can
/// assume.
/// May mutate itself if it's not derived, or its parent if it is.
pub fn constrain_types(&self, other: TypeVar) {
if self == &other {
return;
}
self.constrain_types_by_ts(other.get_typeset());
}
/// Get a Rust expression that computes the type of this type variable.
pub fn to_rust_code(&self) -> String {
match &self.base {
Some(base) => format!(
"{}.{}()",
base.type_var.to_rust_code(),
base.derived_func.name()
),
None => {
if let Some(singleton) = self.singleton_type() {
singleton.rust_name()
} else {
self.name.clone()
}
}
}
}
}
impl Into<TypeVar> for &TypeVar {
@@ -228,24 +291,46 @@ impl Into<TypeVar> for ValueType {
}
}
// Hash TypeVars by pointers.
// There might be a better way to do this, but since TypeVar's content (namely TypeSet) can be
// mutated, it makes sense to use pointer equality/hashing here.
impl hash::Hash for TypeVar {
fn hash<H: hash::Hasher>(&self, h: &mut H) {
match &self.base {
Some(base) => {
base.type_var.hash(h);
base.derived_func.hash(h);
}
None => {
(&**self as *const TypeVarContent).hash(h);
}
}
}
}
impl PartialEq for TypeVar {
fn eq(&self, other: &TypeVar) -> bool {
match (&self.content.base, &other.content.base) {
(Some(base1), Some(base2)) => base1.type_var.eq(&base2.type_var),
match (&self.base, &other.base) {
(Some(base1), Some(base2)) => {
base1.type_var.eq(&base2.type_var) && base1.derived_func == base2.derived_func
}
(None, None) => Rc::ptr_eq(&self.content, &other.content),
_ => false,
}
}
}
// Allow TypeVar as map keys, based on pointer equality (see also above PartialEq impl).
impl Eq for TypeVar {}
impl ops::Deref for TypeVar {
type Target = TypeVarContent;
fn deref(&self) -> &Self::Target {
&*self.content
unsafe { self.content.as_ptr().as_ref().unwrap() }
}
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Hash, PartialEq)]
pub enum DerivedFunc {
LaneOf,
AsBool,
@@ -268,9 +353,20 @@ impl DerivedFunc {
DerivedFunc::ToBitVec => "to_bitvec",
}
}
/// Returns the inverse function of this one, if it is a bijection.
pub fn inverse(&self) -> Option<DerivedFunc> {
match self {
DerivedFunc::HalfWidth => Some(DerivedFunc::DoubleWidth),
DerivedFunc::DoubleWidth => Some(DerivedFunc::HalfWidth),
DerivedFunc::HalfVector => Some(DerivedFunc::DoubleVector),
DerivedFunc::DoubleVector => Some(DerivedFunc::HalfVector),
_ => None,
}
}
}
#[derive(Debug)]
#[derive(Debug, Hash)]
pub struct TypeVarParent {
pub type_var: TypeVar,
pub derived_func: DerivedFunc,
@@ -735,6 +831,18 @@ impl TypeSetBuilder {
self.specials,
)
}
pub fn all() -> TypeSet {
TypeSetBuilder::new()
.ints(Interval::All)
.floats(Interval::All)
.bools(Interval::All)
.simd_lanes(Interval::All)
.bitvecs(Interval::All)
.specials(ValueType::all_special_types().collect())
.includes_scalars(true)
.finish()
}
}
#[derive(PartialEq)]