Allow ignored defs with an effectful RHS

This commit is contained in:
Agus Zubiaga 2024-10-24 00:24:49 -03:00
parent 175a2b5683
commit c9f001b041
No known key found for this signature in database
13 changed files with 136 additions and 126 deletions

View file

@ -663,7 +663,7 @@ impl Constraints {
| Constraint::Store(..)
| Constraint::Lookup(..)
| Constraint::Pattern(..)
| Constraint::EffectfulStmt(..)
| Constraint::ExpectEffectful(..)
| Constraint::FxCall(_)
| Constraint::FxSuffix(_)
| Constraint::FlexToPure(_)
@ -845,8 +845,8 @@ pub enum Constraint {
FxSuffix(Index<FxSuffixConstraint>),
/// Set an fx var as pure if flex (no effectful functions were called)
FlexToPure(Variable),
/// Expect statement to be effectful
EffectfulStmt(Variable, Region),
/// Expect statement or ignored def to be effectful
ExpectEffectful(Variable, ExpectEffectfulReason, Region),
/// Used for things that always unify, e.g. blanks and runtime errors
True,
SaveTheEnvironment,
@ -937,6 +937,7 @@ pub struct FxExpectation {
pub enum FxCallKind {
Call(Option<Symbol>),
Stmt,
Ignored,
}
#[derive(Debug, Clone, Copy)]
@ -962,6 +963,12 @@ impl FxSuffixKind {
}
}
#[derive(Debug, Clone, Copy)]
pub enum ExpectEffectfulReason {
Stmt,
Ignored,
}
/// Custom impl to limit vertical space used by the debug output
impl std::fmt::Debug for Constraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -984,8 +991,8 @@ impl std::fmt::Debug for Constraint {
Self::FxSuffix(arg0) => {
write!(f, "FxSuffix({arg0:?})")
}
Self::EffectfulStmt(arg0, arg1) => {
write!(f, "EffectfulStmt({arg0:?}, {arg1:?})")
Self::ExpectEffectful(arg0, arg1, arg2) => {
write!(f, "EffectfulStmt({arg0:?}, {arg1:?}, {arg2:?})")
}
Self::FlexToPure(arg0) => {
write!(f, "FlexToPure({arg0:?})")

View file

@ -390,6 +390,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
kind: match kind {
DefKind::Let => DefKind::Let,
DefKind::Stmt(v) => DefKind::Stmt(sub!(*v)),
DefKind::Ignored(v) => DefKind::Ignored(sub!(*v)),
},
},
)

View file

@ -112,6 +112,7 @@ fn def<'a>(c: &Ctx, f: &'a Arena<'a>, d: &'a Def) -> DocBuilder<'a, Arena<'a>> {
match kind {
DefKind::Let => def_help(c, f, &loc_pattern.value, &loc_expr.value),
DefKind::Ignored(_) => def_help(c, f, &loc_pattern.value, &loc_expr.value),
DefKind::Stmt(_) => expr(c, EPrec::Free, f, &loc_expr.value),
}
}

View file

@ -97,6 +97,8 @@ pub enum DefKind {
Let,
/// A standalone statement with an fx variable
Stmt(Variable),
/// Ignored result, must be effectful
Ignored(Variable),
}
impl DefKind {
@ -104,6 +106,19 @@ impl DefKind {
match self {
DefKind::Let => DefKind::Let,
DefKind::Stmt(v) => DefKind::Stmt(f(v)),
DefKind::Ignored(v) => DefKind::Ignored(f(v)),
}
}
pub fn from_pattern(var_store: &mut VarStore, pattern: &Loc<Pattern>) -> Self {
if BindingsFromPattern::new(pattern)
.peekable()
.peek()
.is_none()
{
DefKind::Ignored(var_store.fresh())
} else {
DefKind::Let
}
}
}
@ -1212,11 +1227,7 @@ fn canonicalize_value_defs<'a>(
for (def_index, pending_def) in pending_value_defs.iter().enumerate() {
if let Some(loc_pattern) = pending_def.loc_pattern() {
let mut new_bindings = BindingsFromPattern::new(loc_pattern).peekable();
if new_bindings.peek().is_none() {
env.problem(Problem::NoIdentifiersIntroduced(loc_pattern.region));
}
let new_bindings = BindingsFromPattern::new(loc_pattern).peekable();
for (s, r) in new_bindings {
// store the top-level defs, used to ensure that closures won't capture them
@ -2439,6 +2450,8 @@ fn canonicalize_pending_value_def<'a>(
}
Body(loc_can_pattern, loc_expr) => {
//
let def_kind = DefKind::from_pattern(var_store, &loc_can_pattern);
canonicalize_pending_body(
env,
output,
@ -2447,7 +2460,7 @@ fn canonicalize_pending_value_def<'a>(
loc_can_pattern,
loc_expr,
None,
DefKind::Let,
def_kind,
)
}
Stmt(loc_expr) => {