mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
feat: modules: Handle module args in let.
This commit is contained in:
parent
ce928b7bd2
commit
337b7c7203
151
src/ast/mod.rs
151
src/ast/mod.rs
@ -259,10 +259,16 @@ pub enum ImportShape {
|
||||
Unresolved(PositionedItem<Rc<str>>),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum NarrowingShape {
|
||||
Narrowed(Vec<Shape>),
|
||||
Any,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct NarrowedShape {
|
||||
pub pos: Position,
|
||||
pub types: Vec<Shape>,
|
||||
pub types: NarrowingShape,
|
||||
}
|
||||
|
||||
impl NarrowedShape {
|
||||
@ -271,7 +277,10 @@ impl NarrowedShape {
|
||||
}
|
||||
|
||||
pub fn new_with_pos(types: Vec<Shape>, pos: Position) -> Self {
|
||||
Self { pos, types }
|
||||
Self {
|
||||
pos,
|
||||
types: NarrowingShape::Narrowed(types),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_pos(mut self, pos: Position) -> Self {
|
||||
@ -280,12 +289,19 @@ impl NarrowedShape {
|
||||
}
|
||||
|
||||
pub fn merge_in_shape(&mut self, shape: Shape, symbol_table: &mut BTreeMap<Rc<str>, Shape>) {
|
||||
for s in self.types.iter() {
|
||||
if s.equivalent(&shape, symbol_table) {
|
||||
return;
|
||||
match &mut self.types {
|
||||
NarrowingShape::Narrowed(ref mut types) => {
|
||||
for s in types.iter() {
|
||||
if s.equivalent(&shape, symbol_table) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
types.push(shape);
|
||||
}
|
||||
NarrowingShape::Any => {
|
||||
self.types = NarrowingShape::Narrowed(vec![shape]);
|
||||
}
|
||||
}
|
||||
self.types.push(shape)
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,11 +331,49 @@ impl Shape {
|
||||
| (Shape::Int(_), Shape::Int(_))
|
||||
| (Shape::Hole(_), Shape::Hole(_))
|
||||
| (Shape::Float(_), Shape::Float(_)) => true,
|
||||
(Shape::Narrowed(left_slist), Shape::Narrowed(right_slist))
|
||||
| (Shape::List(left_slist), Shape::List(right_slist)) => {
|
||||
for ls in left_slist.types.iter() {
|
||||
(
|
||||
Shape::List(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
Shape::List(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
)
|
||||
| (
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
) => true,
|
||||
(
|
||||
Shape::List(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Narrowed(left_slist),
|
||||
}),
|
||||
Shape::List(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Narrowed(right_slist),
|
||||
}),
|
||||
)
|
||||
| (
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Narrowed(left_slist),
|
||||
}),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Narrowed(right_slist),
|
||||
}),
|
||||
) => {
|
||||
for ls in left_slist.iter() {
|
||||
let mut found = false;
|
||||
for rs in right_slist.types.iter() {
|
||||
for rs in right_slist.iter() {
|
||||
if ls.equivalent(rs, symbol_table) {
|
||||
found = true;
|
||||
break;
|
||||
@ -331,6 +385,46 @@ impl Shape {
|
||||
}
|
||||
true
|
||||
}
|
||||
(
|
||||
Shape::List(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
Shape::List(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Narrowed(right_slist),
|
||||
}),
|
||||
)
|
||||
| (
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Narrowed(right_slist),
|
||||
}),
|
||||
) => true,
|
||||
(
|
||||
Shape::List(NarrowedShape {
|
||||
pos,
|
||||
types: NarrowingShape::Narrowed(left_slist),
|
||||
}),
|
||||
Shape::List(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
)
|
||||
| (
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos,
|
||||
types: NarrowingShape::Narrowed(left_slist),
|
||||
}),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
) => true,
|
||||
(Shape::Tuple(left_slist), Shape::Tuple(right_slist)) => {
|
||||
for (lt, ls) in left_slist.val.iter() {
|
||||
let mut found = false;
|
||||
@ -433,14 +527,24 @@ impl Shape {
|
||||
right: &Shape,
|
||||
symbol_table: &mut BTreeMap<Rc<str>, Shape>,
|
||||
) -> Shape {
|
||||
let left_iter = left_slist.types.iter();
|
||||
let right_iter = right_slist.types.iter();
|
||||
if is_list_subset(left_iter, right_slist, symbol_table) {
|
||||
self.clone()
|
||||
} else if is_list_subset(right_iter, left_slist, symbol_table) {
|
||||
right.clone()
|
||||
} else {
|
||||
Shape::TypeErr(right.pos().clone(), "Incompatible List Shapes".to_owned())
|
||||
match (&left_slist.types, &right_slist.types) {
|
||||
(
|
||||
NarrowingShape::Narrowed(ref left_types),
|
||||
NarrowingShape::Narrowed(ref right_types),
|
||||
) => {
|
||||
let left_iter = left_types.iter();
|
||||
let right_iter = right_types.iter();
|
||||
if is_list_subset(left_iter, right_slist, symbol_table) {
|
||||
self.clone()
|
||||
} else if is_list_subset(right_iter, left_slist, symbol_table) {
|
||||
right.clone()
|
||||
} else {
|
||||
Shape::TypeErr(right.pos().clone(), "Incompatible List Shapes".to_owned())
|
||||
}
|
||||
}
|
||||
(NarrowingShape::Narrowed(_), NarrowingShape::Any)
|
||||
| (NarrowingShape::Any, NarrowingShape::Any) => self.clone(),
|
||||
(NarrowingShape::Any, NarrowingShape::Narrowed(_)) => right.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,10 +590,11 @@ impl Shape {
|
||||
Shape::Int(_) => Shape::Int(pos.clone()),
|
||||
Shape::Float(_) => Shape::Float(pos.clone()),
|
||||
Shape::Boolean(_) => Shape::Boolean(pos.clone()),
|
||||
Shape::List(lst) => Shape::List(NarrowedShape::new_with_pos(lst.types, pos)),
|
||||
Shape::List(NarrowedShape { pos: _, types: NarrowingShape::Narrowed(lst) }) => Shape::List(NarrowedShape::new_with_pos(lst, pos)),
|
||||
Shape::List(NarrowedShape { pos: _, types: NarrowingShape::Any }) => Shape::List(NarrowedShape {pos, types: NarrowingShape::Any}),
|
||||
Shape::Tuple(flds) => Shape::Tuple(PositionedItem::new(flds.val, pos)),
|
||||
Shape::Func(_) | Shape::Module(_) => self.clone(),
|
||||
Shape::Narrowed(pi) => Shape::Narrowed(pi.with_pos(pos)),
|
||||
Shape::Narrowed(narrowed_shape) => Shape::Narrowed(narrowed_shape.with_pos(pos)),
|
||||
Shape::Hole(pi) => Shape::Hole(pi.with_pos(pos)),
|
||||
Shape::Import(ImportShape::Resolved(_, s)) => {
|
||||
Shape::Import(ImportShape::Resolved(pos, s))
|
||||
@ -535,6 +640,10 @@ fn is_list_subset(
|
||||
left_slist: &NarrowedShape,
|
||||
symbol_table: &mut BTreeMap<Rc<str>, Shape>,
|
||||
) -> bool {
|
||||
let left_slist = match &left_slist.types {
|
||||
NarrowingShape::Any => return true,
|
||||
NarrowingShape::Narrowed(ref list) => list,
|
||||
};
|
||||
let right_subset = loop {
|
||||
let mut matches = false;
|
||||
let ls = if let Some(ls) = right_iter.next() {
|
||||
@ -542,7 +651,7 @@ fn is_list_subset(
|
||||
} else {
|
||||
break true;
|
||||
};
|
||||
for rs in left_slist.types.iter() {
|
||||
for rs in left_slist.iter() {
|
||||
let s = ls.narrow(rs, symbol_table);
|
||||
if let Shape::TypeErr(_, _) = s {
|
||||
// noop
|
||||
|
5
src/ast/typecheck/complex_module.ucg
Normal file
5
src/ast/typecheck/complex_module.ucg
Normal file
@ -0,0 +1,5 @@
|
||||
module{
|
||||
arg=0,
|
||||
} => (foo) {
|
||||
let foo = mod.arg;
|
||||
};
|
5
src/ast/typecheck/infer_module_arg.ucg
Normal file
5
src/ast/typecheck/infer_module_arg.ucg
Normal file
@ -0,0 +1,5 @@
|
||||
module{
|
||||
arg={},
|
||||
} => (foo) {
|
||||
let foo = mod.arg.bar + 1;
|
||||
};
|
@ -24,7 +24,7 @@ use crate::error::{BuildError, ErrorType};
|
||||
|
||||
use super::{
|
||||
BinaryExprType, BinaryOpDef, CastType, CopyDef, FuncDef, ImportShape, ModuleDef, ModuleShape,
|
||||
NarrowedShape, NotDef, Position, PositionedItem, SelectDef,
|
||||
NarrowedShape, NarrowingShape, NotDef, Position, PositionedItem, SelectDef, TupleShape,
|
||||
};
|
||||
|
||||
/// Trait for shape derivation.
|
||||
@ -69,41 +69,35 @@ impl DeriveShape for FuncDef {
|
||||
|
||||
impl DeriveShape for ModuleDef {
|
||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
||||
let sym_table: BTreeMap<Rc<str>, Shape> = self
|
||||
.arg_set
|
||||
.iter()
|
||||
.map(|(tok, expr)| (tok.fragment.clone(), expr.derive_shape(symbol_table)))
|
||||
.collect();
|
||||
let sym_positions: BTreeSet<PositionedItem<Rc<str>>> =
|
||||
self.arg_set.iter().map(|(tok, _)| tok.into()).collect();
|
||||
let mut sym_table: BTreeMap<Rc<str>, Shape> = BTreeMap::new();
|
||||
let mod_key: Rc<str> = "mod".into();
|
||||
let mut mod_shape: TupleShape = Vec::new();
|
||||
if let Some(pos) = self.arg_set.first().map(|(t, _)| t.pos.clone()) {
|
||||
mod_shape = self
|
||||
.arg_set
|
||||
.iter()
|
||||
.map(|(tok, expr)| (tok.into(), expr.derive_shape(symbol_table)))
|
||||
.collect();
|
||||
sym_table.insert(
|
||||
mod_key.clone(),
|
||||
Shape::Tuple(PositionedItem::new(mod_shape.clone(), pos)),
|
||||
);
|
||||
}
|
||||
// TODO(jwall): We should modify the shape_list when we can continue narrowing a type.
|
||||
let mut checker = Checker::new().with_symbol_table(sym_table);
|
||||
checker.walk_statement_list(self.statements.clone().iter_mut().collect());
|
||||
if let Some(mut expr) = self.out_expr.clone() {
|
||||
checker.walk_expression(&mut expr);
|
||||
} else {
|
||||
// TODO(jwall): We need to construct a tuple from the let statements here.
|
||||
// TODO(jwall): Remove this when we require out expressions.
|
||||
}
|
||||
let ret = Box::new(
|
||||
checker
|
||||
.pop_shape()
|
||||
.expect("There should always be a return type here"),
|
||||
);
|
||||
let mut items = Vec::new();
|
||||
let sym_table = checker
|
||||
.result()
|
||||
.expect("There should aways be a symbol_table here");
|
||||
for pos_key in sym_positions {
|
||||
let key = pos_key.val.clone();
|
||||
items.push((
|
||||
pos_key,
|
||||
sym_table
|
||||
.get(&key)
|
||||
.expect("This should always have a valid shape")
|
||||
.clone(),
|
||||
));
|
||||
}
|
||||
Shape::Module(ModuleShape {
|
||||
items,
|
||||
items: dbg!(mod_shape),
|
||||
ret,
|
||||
})
|
||||
}
|
||||
@ -117,10 +111,8 @@ impl DeriveShape for SelectDef {
|
||||
tuple,
|
||||
pos: _,
|
||||
} = self;
|
||||
let mut narrowed_shape = NarrowedShape {
|
||||
pos: self.pos.clone(),
|
||||
types: Vec::with_capacity(tuple.len()),
|
||||
};
|
||||
let mut narrowed_shape =
|
||||
NarrowedShape::new_with_pos(Vec::with_capacity(tuple.len()), self.pos.clone());
|
||||
for (_, expr) in tuple {
|
||||
let shape = expr.derive_shape(symbol_table);
|
||||
narrowed_shape.merge_in_shape(shape, symbol_table);
|
||||
@ -147,24 +139,40 @@ fn derive_include_shape(
|
||||
|
||||
fn derive_not_shape(def: &NotDef, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
||||
let shape = def.expr.as_ref().derive_shape(symbol_table);
|
||||
if let Shape::Boolean(_) = &shape {
|
||||
return Shape::Boolean(def.pos.clone());
|
||||
} else if let Shape::Hole(_) = &shape {
|
||||
return Shape::Boolean(def.pos.clone());
|
||||
} else if let Shape::Narrowed(shape_list) = &shape {
|
||||
for s in shape_list.types.iter() {
|
||||
if let Shape::Boolean(_) = s {
|
||||
return Shape::Boolean(def.pos.clone());
|
||||
match &shape {
|
||||
Shape::Boolean(_) => {
|
||||
return Shape::Boolean(def.pos.clone());
|
||||
}
|
||||
Shape::Hole(_) => {
|
||||
return Shape::Boolean(def.pos.clone());
|
||||
}
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Any,
|
||||
}) => {
|
||||
return Shape::Boolean(def.pos.clone());
|
||||
}
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: _,
|
||||
types: NarrowingShape::Narrowed(shape_list),
|
||||
}) => {
|
||||
for s in shape_list.iter() {
|
||||
if let Shape::Boolean(_) = s {
|
||||
return Shape::Boolean(def.pos.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Shape::TypeErr(
|
||||
_ => {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
return Shape::TypeErr(
|
||||
def.pos.clone(),
|
||||
format!(
|
||||
"Expected Boolean value in Not expression but got: {:?}",
|
||||
shape
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn derive_copy_shape(def: &CopyDef, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
||||
@ -187,19 +195,40 @@ fn derive_copy_shape(def: &CopyDef, symbol_table: &mut BTreeMap<Rc<str>, Shape>)
|
||||
Shape::Tuple(PositionedItem::new(vec![], pi.pos.clone())),
|
||||
Shape::Module(ModuleShape {
|
||||
items: vec![],
|
||||
ret: Box::new(Shape::Narrowed(NarrowedShape {
|
||||
pos: pi.pos.clone(),
|
||||
types: vec![],
|
||||
})),
|
||||
ret: Box::new(Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![],
|
||||
pi.pos.clone(),
|
||||
))),
|
||||
}),
|
||||
Shape::Import(ImportShape::Unresolved(pi.clone())),
|
||||
],
|
||||
pi.pos.clone(),
|
||||
)),
|
||||
Shape::Narrowed(potentials) => {
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos,
|
||||
types: NarrowingShape::Any,
|
||||
}) => Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![
|
||||
Shape::Tuple(PositionedItem {
|
||||
pos: def.pos.clone(),
|
||||
val: Vec::new(),
|
||||
}),
|
||||
Shape::Module(ModuleShape {
|
||||
items: vec![],
|
||||
ret: Box::new(Shape::Narrowed(NarrowedShape {
|
||||
pos: def.pos.clone(),
|
||||
types: NarrowingShape::Any,
|
||||
})),
|
||||
}),
|
||||
],
|
||||
def.pos.clone(),
|
||||
)),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos,
|
||||
types: NarrowingShape::Narrowed(potentials),
|
||||
}) => {
|
||||
// 1. Do the possible shapes include tuple, module, or import?
|
||||
let filtered = potentials
|
||||
.types
|
||||
.iter()
|
||||
.filter_map(|v| match v {
|
||||
Shape::Tuple(_) | Shape::Module(_) | Shape::Import(_) | Shape::Hole(_) => {
|
||||
@ -284,48 +313,20 @@ impl DeriveShape for Expression {
|
||||
def.path.pos.clone(),
|
||||
))),
|
||||
Expression::Binary(def) => {
|
||||
dbg!(&def);
|
||||
let left_shape = def.left.derive_shape(symbol_table);
|
||||
let right_shape = def.right.derive_shape(symbol_table);
|
||||
// We need to do somethig different if it's a ShapeKind::DOT
|
||||
// We need to do somethig different if it's a BinaryExprType::DOT
|
||||
if def.kind == BinaryExprType::DOT {
|
||||
dbg!(&def);
|
||||
// left_shape can be assumed to be of type tuple.
|
||||
// If left_shape is not known it can be inferred to be a tuple with right
|
||||
// shapes symbol as a field name.
|
||||
if let Shape::Hole(p) = left_shape {
|
||||
dbg!(&p);
|
||||
if let Shape::Hole(pi) = right_shape {
|
||||
dbg!(&pi);
|
||||
let derived_shape = Shape::Tuple(PositionedItem::new(
|
||||
// TODO(jeremy): This needs to be a token...
|
||||
vec![(
|
||||
pi.into(),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: p.pos.clone(),
|
||||
types: Vec::new(),
|
||||
}),
|
||||
)],
|
||||
p.pos.clone(),
|
||||
));
|
||||
symbol_table.insert(p.val.clone(), derived_shape);
|
||||
return Shape::Narrowed(NarrowedShape {
|
||||
pos: p.pos.clone(),
|
||||
types: Vec::new(),
|
||||
});
|
||||
}
|
||||
} else if let Shape::Tuple(fields_pi) = left_shape {
|
||||
dbg!(&fields_pi);
|
||||
if let Shape::Hole(pi) = right_shape {
|
||||
dbg!(&pi);
|
||||
for (sym, shape) in fields_pi.val {
|
||||
if pi.val == sym.val {
|
||||
return shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(jwall): We should update the symbol table with the new
|
||||
// left shape type if it was a symbol
|
||||
let shape =
|
||||
derive_dot_expression(&def.pos, &left_shape, &def.right, symbol_table);
|
||||
if let Expression::Simple(Value::Symbol(pi)) = def.left.as_ref() {
|
||||
symbol_table.insert(pi.val.clone(), shape.clone());
|
||||
}
|
||||
Shape::TypeErr(def.pos.clone(), "Invalid Tuple field selector".to_owned())
|
||||
shape
|
||||
} else {
|
||||
let right_shape = def.right.derive_shape(symbol_table);
|
||||
left_shape.narrow(&right_shape, symbol_table)
|
||||
}
|
||||
}
|
||||
@ -342,6 +343,125 @@ impl DeriveShape for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_dot_expression(
|
||||
pos: &Position,
|
||||
left_shape: &Shape,
|
||||
right_expr: &Expression,
|
||||
symbol_table: &mut BTreeMap<Rc<str>, Shape>,
|
||||
) -> Shape {
|
||||
// left shape is symbol or tuple or array.
|
||||
// right shape is symbol, str, number, grouped expression
|
||||
// left_shape can be assumed to be of type tuple.
|
||||
// If left_shape is not known it can be inferred to be a tuple with right
|
||||
// shapes symbol as a field name.
|
||||
match (left_shape, right_expr) {
|
||||
// These all recurse down the dot chain
|
||||
(
|
||||
Shape::Tuple(tshape),
|
||||
Expression::Binary(BinaryOpDef {
|
||||
kind: BinaryExprType::DOT,
|
||||
left,
|
||||
right,
|
||||
pos,
|
||||
}),
|
||||
) => {
|
||||
let next_left_shape = left.derive_shape(symbol_table);
|
||||
let mut tshape = tshape.clone();
|
||||
if let Shape::Hole(pi) = next_left_shape {
|
||||
tshape.val.push((
|
||||
pi.clone(),
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(vec![], pos.clone())),
|
||||
));
|
||||
}
|
||||
return Shape::Tuple(tshape);
|
||||
}
|
||||
(
|
||||
Shape::List(lshape),
|
||||
Expression::Binary(BinaryOpDef {
|
||||
kind: BinaryExprType::DOT,
|
||||
left,
|
||||
right,
|
||||
pos,
|
||||
}),
|
||||
) => {
|
||||
let next_left_shape = left.derive_shape(symbol_table);
|
||||
if let Shape::Int(_) = next_left_shape {
|
||||
return Shape::List(lshape.clone());
|
||||
};
|
||||
if let Shape::Hole(pi) = next_left_shape {
|
||||
return Shape::Tuple(PositionedItem {
|
||||
pos: pi.pos.clone(),
|
||||
val: vec![(
|
||||
pi.clone(),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: pi.pos.clone(),
|
||||
types: NarrowingShape::Any,
|
||||
}),
|
||||
)],
|
||||
});
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
}
|
||||
(
|
||||
Shape::Narrowed(narrowed_shape),
|
||||
Expression::Binary(BinaryOpDef {
|
||||
kind: BinaryExprType::DOT,
|
||||
left,
|
||||
right,
|
||||
pos,
|
||||
}),
|
||||
) => {
|
||||
let next_left_shape = left.derive_shape(symbol_table);
|
||||
let types = match &narrowed_shape.types {
|
||||
NarrowingShape::Any => todo!(),
|
||||
NarrowingShape::Narrowed(ref types) => types,
|
||||
};
|
||||
match next_left_shape {
|
||||
Shape::Hole(_) | Shape::Int(_) | Shape::Str(_) => {
|
||||
if types
|
||||
.iter()
|
||||
.any(|s| s.type_name() == "tuple" || s.type_name() == "list")
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
_ => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
(
|
||||
Shape::Hole(_),
|
||||
Expression::Binary(BinaryOpDef {
|
||||
kind: BinaryExprType::DOT,
|
||||
left,
|
||||
right,
|
||||
pos,
|
||||
}),
|
||||
) => {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// These do not recurse down the dot chain
|
||||
(Shape::Tuple(_), Expression::Simple(Value::Str(pi)))
|
||||
| (Shape::Tuple(_), Expression::Simple(Value::Symbol(pi))) => todo!(),
|
||||
(Shape::List(_), Expression::Simple(Value::Symbol(pi))) => todo!(),
|
||||
(Shape::List(_), Expression::Simple(Value::Int(pi))) => todo!(),
|
||||
(Shape::Hole(_), Expression::Simple(Value::Str(pi))) => todo!(),
|
||||
(Shape::Hole(_), Expression::Simple(Value::Symbol(pi))) => todo!(),
|
||||
(Shape::Hole(_), Expression::Simple(Value::Int(pi))) => todo!(),
|
||||
(Shape::Narrowed(_), Expression::Simple(Value::Symbol(pi))) => todo!(),
|
||||
(Shape::Narrowed(_), Expression::Simple(Value::Str(pi))) => todo!(),
|
||||
(Shape::Narrowed(_), Expression::Simple(Value::Int(pi))) => todo!(),
|
||||
(_, Expression::Grouped(expr, _)) => {
|
||||
return derive_dot_expression(pos, left_shape, expr.as_ref(), symbol_table)
|
||||
}
|
||||
(_, _) => return Shape::TypeErr(pos.clone(), "Invalid Tuple field selector".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
impl DeriveShape for Value {
|
||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
||||
match self {
|
||||
|
@ -32,7 +32,11 @@ macro_rules! assert_type_success {
|
||||
checker.walk_statement_list(expr.iter_mut().collect());
|
||||
let maybe_shape = checker.pop_shape();
|
||||
let result = checker.result();
|
||||
assert!(result.is_ok(), "We expect this to typecheck successfully.");
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"We expect this to typecheck successfully. {:?}",
|
||||
result
|
||||
);
|
||||
assert!(maybe_shape.is_some(), "We got a shape out of it");
|
||||
assert_eq!(maybe_shape.unwrap(), $shape);
|
||||
}};
|
||||
@ -205,10 +209,10 @@ fn infer_symbol_type_test() {
|
||||
Shape::Tuple(PositionedItem::new(
|
||||
vec![(
|
||||
PositionedItem::new(foo.clone(), Position::new(1, 5, 4)),
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: Position::new(0, 0, 0),
|
||||
types: Vec::new(),
|
||||
}),
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
Vec::new(),
|
||||
Position::new(0, 0, 0),
|
||||
)),
|
||||
)],
|
||||
Position::new(0, 0, 0),
|
||||
)),
|
||||
@ -289,29 +293,23 @@ fn infer_func_type_test() {
|
||||
fn infer_select_shape() {
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = "foo", false = 1 };"#,
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: Position {
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![
|
||||
Shape::Str(Position::new(1, 26, 25)),
|
||||
Shape::Int(Position::new(1, 41, 40)),
|
||||
],
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0
|
||||
},
|
||||
types: vec![
|
||||
Shape::Str(Position::new(1, 26, 25)),
|
||||
Shape::Int(Position::new(1, 41, 40)),
|
||||
]
|
||||
})
|
||||
))
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = "foo", false = { } };"#,
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0
|
||||
},
|
||||
types: vec![
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![
|
||||
Shape::Str(Position::new(1, 26, 25)),
|
||||
Shape::Tuple(PositionedItem {
|
||||
pos: Position {
|
||||
@ -323,18 +321,18 @@ fn infer_select_shape() {
|
||||
val: vec![],
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = { }, false = { } };"#,
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: Position {
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0
|
||||
},
|
||||
types: vec![Shape::Tuple(PositionedItem {
|
||||
))
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = { }, false = { } };"#,
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![Shape::Tuple(PositionedItem {
|
||||
pos: Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
@ -343,18 +341,18 @@ fn infer_select_shape() {
|
||||
},
|
||||
val: vec![],
|
||||
}),],
|
||||
})
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = { foo = 1, }, false = { bar = "foo" } };"#,
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: Position {
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0
|
||||
},
|
||||
types: vec![
|
||||
))
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = { foo = 1, }, false = { bar = "foo" } };"#,
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![
|
||||
Shape::Tuple(PositionedItem {
|
||||
pos: Position {
|
||||
file: None,
|
||||
@ -405,19 +403,19 @@ fn infer_select_shape() {
|
||||
})
|
||||
)]
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = { foo = 1, bar = "quux" }, false = { bar = "foo" } };"#,
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: Position {
|
||||
],
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0
|
||||
},
|
||||
types: vec![
|
||||
))
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = { foo = 1, bar = "quux" }, false = { bar = "foo" } };"#,
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![
|
||||
Shape::Tuple(PositionedItem {
|
||||
pos: Position {
|
||||
file: None,
|
||||
@ -487,49 +485,55 @@ fn infer_select_shape() {
|
||||
})
|
||||
)]
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = [ "quux" ], false = [ 1 ] };"#,
|
||||
Shape::Narrowed(NarrowedShape {
|
||||
pos: Position {
|
||||
],
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0
|
||||
},
|
||||
types: vec![
|
||||
Shape::List(NarrowedShape {
|
||||
pos: Position {
|
||||
))
|
||||
);
|
||||
assert_type_success!(
|
||||
r#"select (foo) => { true = [ "quux" ], false = [ 1 ] };"#,
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![
|
||||
Shape::List(NarrowedShape::new_with_pos(
|
||||
vec![Shape::Str(Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 28,
|
||||
offset: 27
|
||||
})],
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 26,
|
||||
offset: 25
|
||||
},
|
||||
types: vec![Shape::Str(Position {
|
||||
)),
|
||||
Shape::List(NarrowedShape::new_with_pos(
|
||||
vec![Shape::Int(Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 28,
|
||||
offset: 27
|
||||
})]
|
||||
}),
|
||||
Shape::List(NarrowedShape {
|
||||
pos: Position {
|
||||
column: 48,
|
||||
offset: 47
|
||||
})],
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 46,
|
||||
offset: 45
|
||||
},
|
||||
types: vec![Shape::Int(Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 48,
|
||||
offset: 47
|
||||
})]
|
||||
})
|
||||
]
|
||||
})
|
||||
))
|
||||
],
|
||||
Position {
|
||||
file: None,
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0
|
||||
},
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
@ -589,5 +593,66 @@ fn test_module_inference() {
|
||||
offset: 14
|
||||
}))
|
||||
})
|
||||
)
|
||||
);
|
||||
let complex_mod_stmt = include_str!("complex_module.ucg");
|
||||
assert_type_success!(
|
||||
complex_mod_stmt,
|
||||
Shape::Module(ModuleShape {
|
||||
items: vec![(
|
||||
PositionedItem {
|
||||
pos: Position {
|
||||
file: None,
|
||||
line: 2,
|
||||
column: 3,
|
||||
offset: 10
|
||||
},
|
||||
val: "arg".into()
|
||||
},
|
||||
Shape::Int(Position {
|
||||
file: None,
|
||||
line: 2,
|
||||
column: 7,
|
||||
offset: 14
|
||||
})
|
||||
)],
|
||||
ret: Box::new(Shape::Int(Position {
|
||||
file: None,
|
||||
line: 2,
|
||||
column: 7,
|
||||
offset: 14
|
||||
}))
|
||||
})
|
||||
);
|
||||
let infer_mod_arg_stmt = include_str!("infer_module_arg.ucg");
|
||||
assert_type_success!(
|
||||
infer_mod_arg_stmt,
|
||||
Shape::Module(ModuleShape {
|
||||
items: vec![(
|
||||
PositionedItem {
|
||||
pos: Position {
|
||||
file: None,
|
||||
line: 2,
|
||||
column: 3,
|
||||
offset: 10
|
||||
},
|
||||
val: "arg".into()
|
||||
},
|
||||
Shape::Narrowed(NarrowedShape::new_with_pos(
|
||||
vec![],
|
||||
Position {
|
||||
file: None,
|
||||
line: 2,
|
||||
column: 3,
|
||||
offset: 10
|
||||
},
|
||||
))
|
||||
)],
|
||||
ret: Box::new(Shape::Int(Position {
|
||||
file: None,
|
||||
line: 2,
|
||||
column: 7,
|
||||
offset: 14
|
||||
}))
|
||||
})
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user