mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
feat: Tuple shape narrowing
This commit is contained in:
parent
5835adbf7a
commit
bdfa424545
@ -306,8 +306,7 @@ impl Shape {
|
||||
self.narrow_list_shapes(left_slist, right_slist, right)
|
||||
}
|
||||
(Shape::Tuple(left_slist), Shape::Tuple(right_slist)) => {
|
||||
// TODO
|
||||
unimplemented!("Can't merge these yet.");
|
||||
self.narrow_tuple_shapes(left_slist, right_slist, right)
|
||||
}
|
||||
(Shape::Func(left_opshape), Shape::Func(right_opshape)) => {
|
||||
// TODO
|
||||
@ -328,6 +327,18 @@ impl Shape {
|
||||
}
|
||||
}
|
||||
|
||||
fn narrow_tuple_shapes(&self, left_slist: &PositionedItem<Vec<(Token, Shape)>>, right_slist: &PositionedItem<Vec<(Token, Shape)>>, right: &Shape) -> Shape {
|
||||
let left_iter = left_slist.val.iter();
|
||||
let right_iter = right_slist.val.iter();
|
||||
if is_tuple_subset(left_iter, right_slist) {
|
||||
self.clone()
|
||||
} else if is_tuple_subset(right_iter, left_slist) {
|
||||
right.clone()
|
||||
} else {
|
||||
Shape::TypeErr(right.pos().clone(), "Incompatible Tuple Shapes".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
fn narrow_list_shapes(
|
||||
&self,
|
||||
left_slist: &NarrowedShape,
|
||||
@ -336,9 +347,9 @@ impl Shape {
|
||||
) -> Shape {
|
||||
let left_iter = left_slist.types.iter();
|
||||
let right_iter = right_slist.types.iter();
|
||||
if is_shape_subset(left_iter, right_slist) {
|
||||
if is_list_subset(left_iter, right_slist) {
|
||||
self.clone()
|
||||
} else if is_shape_subset(right_iter, left_slist) {
|
||||
} else if is_list_subset(right_iter, left_slist) {
|
||||
right.clone()
|
||||
} else {
|
||||
Shape::TypeErr(right.pos().clone(), "Incompatible List Shapes".to_owned())
|
||||
@ -406,7 +417,34 @@ impl Shape {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_shape_subset(mut right_iter: std::slice::Iter<Shape>, left_slist: &NarrowedShape) -> bool {
|
||||
fn is_tuple_subset(
|
||||
mut left_iter: std::slice::Iter<(Token, Shape)>,
|
||||
right_slist: &PositionedItem<Vec<(Token, Shape)>>,
|
||||
) -> bool {
|
||||
return loop {
|
||||
if let Some((lt, ls)) = left_iter.next() {
|
||||
let mut matched = false;
|
||||
for (rt, rs) in right_slist.val.iter() {
|
||||
if rt.fragment == lt.fragment {
|
||||
if let Shape::TypeErr(_, _) = ls.narrow(rs) {
|
||||
// noop
|
||||
} else {
|
||||
matched = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
break false;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break true;
|
||||
};
|
||||
}
|
||||
|
||||
fn is_list_subset(mut right_iter: std::slice::Iter<Shape>, left_slist: &NarrowedShape) -> bool {
|
||||
let right_subset = loop {
|
||||
let mut matches = false;
|
||||
let ls = if let Some(ls) = right_iter.next() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::convert::Into;
|
||||
|
||||
use crate::ast::{Token, TokenType};
|
||||
use crate::ast::walk::Walker;
|
||||
use crate::ast::{Position, PositionedItem};
|
||||
use crate::parse;
|
||||
@ -54,6 +55,21 @@ fn simple_binary_typecheck() {
|
||||
"[] + [];",
|
||||
Shape::List(crate::ast::NarrowedShape::new(vec![], 1, 1, 0))
|
||||
);
|
||||
assert_type_success!(
|
||||
"{} + {};",
|
||||
Shape::Tuple(PositionedItem::new(vec![], Position::new(1, 1, 0)))
|
||||
);
|
||||
// TODO(jwall): + isn't valid for tuples.
|
||||
assert_type_success!(
|
||||
"{foo = 1} + {foo = 1};",
|
||||
Shape::Tuple(PositionedItem::new(
|
||||
vec![
|
||||
(Token { typ: TokenType::BAREWORD, fragment: "foo".to_owned(), pos: Position::new(1, 2, 1)},
|
||||
Shape::Int(PositionedItem::new_with_pos(1, Position::new(1, 8, 7)))),
|
||||
],
|
||||
Position::new(1, 1, 0)
|
||||
))
|
||||
);
|
||||
assert_type_success!(
|
||||
"[1] + [2];",
|
||||
Shape::List(crate::ast::NarrowedShape::new(
|
||||
@ -70,14 +86,8 @@ fn simple_binary_typecheck() {
|
||||
"[1, 1.0] + [1, 2.0];",
|
||||
Shape::List(crate::ast::NarrowedShape::new(
|
||||
vec![
|
||||
Shape::Int(PositionedItem::new_with_pos(
|
||||
1,
|
||||
Position::new(1, 1, 0)
|
||||
)),
|
||||
Shape::Float(PositionedItem::new_with_pos(
|
||||
1.0,
|
||||
Position::new(1, 1, 0)
|
||||
)),
|
||||
Shape::Int(PositionedItem::new_with_pos(1, Position::new(1, 1, 0))),
|
||||
Shape::Float(PositionedItem::new_with_pos(1.0, Position::new(1, 1, 0))),
|
||||
],
|
||||
1,
|
||||
1,
|
||||
@ -114,6 +124,17 @@ fn simple_binary_typefail() {
|
||||
"Incompatible List Shapes",
|
||||
Position::new(1, 7, 6)
|
||||
);
|
||||
// TODO(jwall): + isn't valid for tuples.
|
||||
assert_type_fail!(
|
||||
"{foo = 1} + {foo = 1.0};",
|
||||
"Incompatible Tuple Shapes",
|
||||
Position::new(1, 13, 12)
|
||||
);
|
||||
assert_type_fail!(
|
||||
"{foo = 1} + {bar = 1};",
|
||||
"Incompatible Tuple Shapes",
|
||||
Position::new(1, 13, 12)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
x
Reference in New Issue
Block a user