Skip to content

Commit

Permalink
Merge pull request #328 from KisaragiEffective/fix/avoid-recursion
Browse files Browse the repository at this point in the history
  • Loading branch information
KisaragiEffective authored Dec 19, 2023
2 parents cd262b9 + 325392b commit 2bce8dc
Showing 1 changed file with 107 additions and 101 deletions.
208 changes: 107 additions & 101 deletions package/origlang-compiler/src/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,123 +259,129 @@ fn handle_atomic_pattern(
}

fn desugar(
outer_destruction: Cow<'_, [AtomicPattern]>, rhs: TypedExpression, checker: &TypeChecker,
outer_destruction: Cow<'_, [AtomicPattern]>, mut rhs: TypedExpression, checker: &TypeChecker,
) -> Result<Vec<TypedStatement>, TypeCheckError> {
debug!("check: {outer_destruction:?} = {rhs:?}");

match rhs {
TypedExpression::Variable { ident, tp } => {
match tp {
Type::Tuple(tuple_element_types) => {
let tuple_element_types = tuple_element_types.0;
if outer_destruction.len() == tuple_element_types.len() {
desugar(outer_destruction, TypedExpression::Tuple {
expressions: tuple_element_types.iter().enumerate().map(|(i, _)| TypedExpression::ExtractTuple {
expr: Box::new(
TypedExpression::Variable { ident: ident.clone(), tp: Type::tuple(tuple_element_types.clone()) }
),
index: i,
}).collect(),
}, checker)
} else {
debug!("tuple arity mismatch");
Err(TypeCheckError::UnsatisfiablePattern {
// this is intentionally written in loop way because deep recursion causes stack-overflow during type-checking.
loop {
debug!("check: {outer_destruction:?} = {rhs:?}");

match rhs {
TypedExpression::Variable { ident, tp } => {
match tp {
Type::Tuple(tuple_element_types) => {
let tuple_element_types = tuple_element_types.0;
if outer_destruction.len() == tuple_element_types.len() {
rhs = TypedExpression::Tuple {
expressions: tuple_element_types.iter().enumerate().map(|(i, _)| TypedExpression::ExtractTuple {
expr: Box::new(
TypedExpression::Variable { ident: ident.clone(), tp: Type::tuple(tuple_element_types.clone()) }
),
index: i,
}).collect(),
};
continue
} else {
debug!("tuple arity mismatch");
break Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
expression: TypedExpression::Variable { ident, tp: Type::tuple(tuple_element_types.clone()) },
expr_type: Type::tuple(tuple_element_types),
})
}
}
other => {
debug!("non-tuple expression");
break Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
expression: TypedExpression::Variable { ident, tp: Type::tuple(tuple_element_types.clone()) },
expr_type: Type::tuple(tuple_element_types),
expression: TypedExpression::Variable { ident, tp: other.clone() },
expr_type: other,
})
}
}
other => {
debug!("non-tuple expression");
Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
expression: TypedExpression::Variable { ident, tp: other.clone() },
expr_type: other,
})
}
}
}
TypedExpression::Block { inner: _, final_expression, return_type: _ } => {
// TODO: how can we handle inner statement?
desugar(outer_destruction, *final_expression, checker)
}
TypedExpression::Tuple { expressions } => {
let m = outer_destruction.iter().zip(expressions).enumerate().map(|(_i, (element_binding, expression))| {
handle_atomic_pattern(expression, element_binding, checker)
}).collect::<Vec<_>>();
TypedExpression::Block { inner: _, final_expression, return_type: _ } => {
// TODO: how can we handle inner statement?
rhs = *final_expression;
continue;
}
TypedExpression::Tuple { expressions } => {
let m = outer_destruction.iter().zip(expressions).enumerate().map(|(_i, (element_binding, expression))| {
handle_atomic_pattern(expression, element_binding, checker)
}).collect::<Vec<_>>();

let mut k = vec![];
let mut k = vec![];

for mx in m {
match mx {
Ok(y) => {
k.extend(y);
for mx in m {
match mx {
Ok(y) => {
k.extend(y);
}
Err(x) => return Err(x)
}
Err(x) => return Err(x)
}
}

Ok(k)
}
TypedExpression::ExtractTuple { expr, index } => {
let expr = *expr;

enum RecursionStrategy {
Simple(TypedExpression),
InsertTemporary(TypedExpression),
break Ok(k)
}
let expr = match expr {
TypedExpression::If { condition, then, els, return_type } => {
RecursionStrategy::Simple(TypedExpression::If { condition, then, els, return_type: return_type.as_tuple().expect("oops 15").0[index].clone() })
}
TypedExpression::Block { inner, final_expression, return_type } => {
RecursionStrategy::Simple(TypedExpression::Block { inner, final_expression, return_type: return_type.as_tuple().expect("oops 4").0[index].clone() })
}
TypedExpression::Tuple { expressions } => {
RecursionStrategy::Simple(expressions[index].clone())
}
TypedExpression::Variable { .. } => {
RecursionStrategy::InsertTemporary(expr)
}
other => RecursionStrategy::Simple(other),
};
TypedExpression::ExtractTuple { expr, index } => {
let expr = *expr;

match expr {
RecursionStrategy::Simple(expr) => {
debug!("recurse");
desugar(outer_destruction, expr, checker)
enum RecursionStrategy {
Simple(TypedExpression),
InsertTemporary(TypedExpression),
}
RecursionStrategy::InsertTemporary(expr) => {
let new_ident = checker.make_fresh_identifier();
let tp = expr.actual_type().as_tuple().expect("oh").0[index].clone();
let v = TypedExpression::Variable {
ident: new_ident.clone(), tp: tp.clone()
};

checker.ctx.borrow_mut().add_known_variable(new_ident.clone(), tp);
let v = desugar(outer_destruction, v, checker)?;
let mut r = VecDeque::from(v);

r.push_front(TypedStatement::VariableDeclaration {
identifier: new_ident,
expression: TypedExpression::ExtractTuple {
expr: Box::new(expr),
index
},
});

Ok(r.into_iter().collect::<Vec<_>>())
let expr = match expr {
TypedExpression::If { condition, then, els, return_type } => {
RecursionStrategy::Simple(TypedExpression::If { condition, then, els, return_type: return_type.as_tuple().expect("oops 15").0[index].clone() })
}
TypedExpression::Block { inner, final_expression, return_type } => {
RecursionStrategy::Simple(TypedExpression::Block { inner, final_expression, return_type: return_type.as_tuple().expect("oops 4").0[index].clone() })
}
TypedExpression::Tuple { expressions } => {
RecursionStrategy::Simple(expressions[index].clone())
}
TypedExpression::Variable { .. } => {
RecursionStrategy::InsertTemporary(expr)
}
other => RecursionStrategy::Simple(other),
};

match expr {
RecursionStrategy::Simple(expr) => {
debug!("recurse");
rhs = expr;
continue;
}
RecursionStrategy::InsertTemporary(expr) => {
let new_ident = checker.make_fresh_identifier();
let tp = expr.actual_type().as_tuple().expect("oh").0[index].clone();
let v = TypedExpression::Variable {
ident: new_ident.clone(), tp: tp.clone()
};

checker.ctx.borrow_mut().add_known_variable(new_ident.clone(), tp);
let v = desugar(outer_destruction, v, checker)?;
let mut r = VecDeque::from(v);

r.push_front(TypedStatement::VariableDeclaration {
identifier: new_ident,
expression: TypedExpression::ExtractTuple {
expr: Box::new(expr),
index
},
});

break Ok(r.into_iter().collect::<Vec<_>>())
}
}
}
}
other => {
debug!("unsupported expression");
Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
expr_type: other.actual_type(),
expression: other,
})
other => {
debug!("unsupported expression");
break Err(TypeCheckError::UnsatisfiablePattern {
pattern: AtomicPattern::Tuple(outer_destruction.to_vec()),
expr_type: other.actual_type(),
expression: other,
})
}
}
}
}
Expand Down

0 comments on commit 2bce8dc

Please sign in to comment.