mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Deal with equivalence in the presence of unresolved recursive pointers
This commit is contained in:
parent
9eb1c170f3
commit
564d9f795a
1 changed files with 68 additions and 19 deletions
|
@ -65,24 +65,45 @@ impl Types {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_equivalent(&self, a: &RocType, b: &RocType) -> bool {
|
pub fn is_equivalent(&self, a: &RocType, b: &RocType) -> bool {
|
||||||
|
self.is_equivalent_help(RocTypeOrPending::Type(a), RocTypeOrPending::Type(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_equivalent_help(&self, a: RocTypeOrPending, b: RocTypeOrPending) -> bool {
|
||||||
use RocType::*;
|
use RocType::*;
|
||||||
|
|
||||||
|
let (a, b) = match (a, b) {
|
||||||
|
(RocTypeOrPending::Type(a), RocTypeOrPending::Type(b)) => (a, b),
|
||||||
|
(RocTypeOrPending::Pending, RocTypeOrPending::Pending) => return true,
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(RocStr, RocStr) | (Bool, Bool) | (EmptyTagUnion, EmptyTagUnion) | (Unit, Unit) => true,
|
(RocStr, RocStr) | (Bool, Bool) | (EmptyTagUnion, EmptyTagUnion) | (Unit, Unit) => true,
|
||||||
(RocResult(ok_a, err_a), RocResult(ok_b, err_b)) => {
|
(RocResult(ok_a, err_a), RocResult(ok_b, err_b)) => {
|
||||||
self.is_equivalent(self.get_type(*ok_a), self.get_type(*ok_b))
|
self.is_equivalent_help(
|
||||||
&& self.is_equivalent(self.get_type(*err_a), self.get_type(*err_b))
|
self.get_type_or_pending(*ok_a),
|
||||||
|
self.get_type_or_pending(*ok_b),
|
||||||
|
) && self.is_equivalent_help(
|
||||||
|
self.get_type_or_pending(*err_a),
|
||||||
|
self.get_type_or_pending(*err_b),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(Num(num_a), Num(num_b)) => num_a == num_b,
|
(Num(num_a), Num(num_b)) => num_a == num_b,
|
||||||
(RocList(elem_a), RocList(elem_b))
|
(RocList(elem_a), RocList(elem_b))
|
||||||
| (RocSet(elem_a), RocSet(elem_b))
|
| (RocSet(elem_a), RocSet(elem_b))
|
||||||
| (RocBox(elem_a), RocBox(elem_b))
|
| (RocBox(elem_a), RocBox(elem_b))
|
||||||
| (RecursivePointer(elem_a), RecursivePointer(elem_b)) => {
|
| (RecursivePointer(elem_a), RecursivePointer(elem_b)) => self.is_equivalent_help(
|
||||||
self.is_equivalent(self.get_type(*elem_a), self.get_type(*elem_b))
|
self.get_type_or_pending(*elem_a),
|
||||||
}
|
self.get_type_or_pending(*elem_b),
|
||||||
|
),
|
||||||
(RocDict(key_a, val_a), RocDict(key_b, val_b)) => {
|
(RocDict(key_a, val_a), RocDict(key_b, val_b)) => {
|
||||||
self.is_equivalent(self.get_type(*key_a), self.get_type(*key_b))
|
self.is_equivalent_help(
|
||||||
&& self.is_equivalent(self.get_type(*val_a), self.get_type(*val_b))
|
self.get_type_or_pending(*key_a),
|
||||||
|
self.get_type_or_pending(*key_b),
|
||||||
|
) && self.is_equivalent_help(
|
||||||
|
self.get_type_or_pending(*val_a),
|
||||||
|
self.get_type_or_pending(*val_b),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(TagUnion(union_a), TagUnion(union_b)) => {
|
(TagUnion(union_a), TagUnion(union_b)) => {
|
||||||
use RocTagUnion::*;
|
use RocTagUnion::*;
|
||||||
|
@ -113,8 +134,10 @@ impl Types {
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
tag_name_a == tag_name_b
|
tag_name_a == tag_name_b
|
||||||
&& self
|
&& self.is_equivalent_help(
|
||||||
.is_equivalent(self.get_type(*payload_a), self.get_type(*payload_b))
|
self.get_type_or_pending(*payload_a),
|
||||||
|
self.get_type_or_pending(*payload_b),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(Enumeration { tags: tags_a, .. }, Enumeration { tags: tags_b, .. }) => {
|
(Enumeration { tags: tags_a, .. }, Enumeration { tags: tags_b, .. }) => {
|
||||||
tags_a == tags_b
|
tags_a == tags_b
|
||||||
|
@ -157,9 +180,9 @@ impl Types {
|
||||||
|((name_a, opt_id_a), (name_b, opt_id_b))| {
|
|((name_a, opt_id_a), (name_b, opt_id_b))| {
|
||||||
name_a == name_b
|
name_a == name_b
|
||||||
&& match (opt_id_a, opt_id_b) {
|
&& match (opt_id_a, opt_id_b) {
|
||||||
(Some(id_a), Some(id_b)) => self.is_equivalent(
|
(Some(id_a), Some(id_b)) => self.is_equivalent_help(
|
||||||
self.get_type(*id_a),
|
self.get_type_or_pending(*id_a),
|
||||||
self.get_type(*id_b),
|
self.get_type_or_pending(*id_b),
|
||||||
),
|
),
|
||||||
(None, None) => true,
|
(None, None) => true,
|
||||||
(None, Some(_)) | (Some(_), None) => false,
|
(None, Some(_)) | (Some(_), None) => false,
|
||||||
|
@ -179,9 +202,9 @@ impl Types {
|
||||||
|((name_a, opt_id_a), (name_b, opt_id_b))| {
|
|((name_a, opt_id_a), (name_b, opt_id_b))| {
|
||||||
name_a == name_b
|
name_a == name_b
|
||||||
&& match (opt_id_a, opt_id_b) {
|
&& match (opt_id_a, opt_id_b) {
|
||||||
(Some(id_a), Some(id_b)) => self.is_equivalent(
|
(Some(id_a), Some(id_b)) => self.is_equivalent_help(
|
||||||
self.get_type(*id_a),
|
self.get_type_or_pending(*id_a),
|
||||||
self.get_type(*id_b),
|
self.get_type_or_pending(*id_b),
|
||||||
),
|
),
|
||||||
(None, None) => true,
|
(None, None) => true,
|
||||||
(None, Some(_)) | (Some(_), None) => false,
|
(None, Some(_)) | (Some(_), None) => false,
|
||||||
|
@ -241,7 +264,10 @@ impl Types {
|
||||||
.zip(fields_b.iter())
|
.zip(fields_b.iter())
|
||||||
.all(|((name_a, id_a), (name_b, id_b))| {
|
.all(|((name_a, id_a), (name_b, id_b))| {
|
||||||
name_a == name_b
|
name_a == name_b
|
||||||
&& self.is_equivalent(self.get_type(*id_a), self.get_type(*id_b))
|
&& self.is_equivalent_help(
|
||||||
|
self.get_type_or_pending(*id_a),
|
||||||
|
self.get_type_or_pending(*id_b),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -261,7 +287,10 @@ impl Types {
|
||||||
.zip(fields_b.iter())
|
.zip(fields_b.iter())
|
||||||
.all(|((name_a, id_a), (name_b, id_b))| {
|
.all(|((name_a, id_a), (name_b, id_b))| {
|
||||||
name_a == name_b
|
name_a == name_b
|
||||||
&& self.is_equivalent(self.get_type(*id_a), self.get_type(*id_b))
|
&& self.is_equivalent_help(
|
||||||
|
self.get_type_or_pending(*id_a),
|
||||||
|
self.get_type_or_pending(*id_b),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -283,10 +312,16 @@ impl Types {
|
||||||
// with the same type could have completely different implementations!
|
// with the same type could have completely different implementations!
|
||||||
if name_a == name_b
|
if name_a == name_b
|
||||||
&& args_a.len() == args_b.len()
|
&& args_a.len() == args_b.len()
|
||||||
&& self.is_equivalent(self.get_type(*ret_a), self.get_type(*ret_b))
|
&& self.is_equivalent_help(
|
||||||
|
self.get_type_or_pending(*ret_a),
|
||||||
|
self.get_type_or_pending(*ret_b),
|
||||||
|
)
|
||||||
{
|
{
|
||||||
args_a.iter().zip(args_b.iter()).all(|(id_a, id_b)| {
|
args_a.iter().zip(args_b.iter()).all(|(id_a, id_b)| {
|
||||||
self.is_equivalent(self.get_type(*id_a), self.get_type(*id_b))
|
self.is_equivalent_help(
|
||||||
|
self.get_type_or_pending(*id_a),
|
||||||
|
self.get_type_or_pending(*id_b),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -389,6 +424,14 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_type_or_pending(&self, id: TypeId) -> RocTypeOrPending {
|
||||||
|
match self.types.get(id.0) {
|
||||||
|
Some(typ) => RocTypeOrPending::Type(typ),
|
||||||
|
None if id == TypeId::PENDING => RocTypeOrPending::Pending,
|
||||||
|
None => unreachable!("{:?}", id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Contrast this with the size_ignoring_alignment method
|
/// Contrast this with the size_ignoring_alignment method
|
||||||
pub fn size_rounded_to_alignment(&self, id: TypeId) -> u32 {
|
pub fn size_rounded_to_alignment(&self, id: TypeId) -> u32 {
|
||||||
let size_ignoring_alignment = self.size_ignoring_alignment(id);
|
let size_ignoring_alignment = self.size_ignoring_alignment(id);
|
||||||
|
@ -448,6 +491,12 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum RocTypeOrPending<'a> {
|
||||||
|
Type(&'a RocType),
|
||||||
|
/// A pending recursive pointer
|
||||||
|
Pending,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum RocType {
|
pub enum RocType {
|
||||||
RocStr,
|
RocStr,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue