Report effectful statement in pure function

This commit is contained in:
Agus Zubiaga 2024-10-16 19:05:26 -03:00
parent fd2493ee51
commit b62665e49e
No known key found for this signature in database
3 changed files with 69 additions and 35 deletions

View file

@ -601,24 +601,6 @@ pub fn constrain_expr(
let category = Category::CallResult(opt_symbol, *called_via);
let fx_expected_type = match env.enclosing_fx {
Some(enclosing_fn) => {
let enclosing_fx_index = constraints.push_variable(enclosing_fn.fx_var);
constraints.push_expected_type(ForReason(
Reason::CallInFunction(enclosing_fn.ann_region),
enclosing_fx_index,
region,
))
}
None => constraints.push_expected_type(ForReason(
Reason::CallInTopLevelDef,
// top-level defs are only allowed to call pure functions
constraints.push_variable(Variable::PURE),
region,
)),
};
let and_cons = [
fn_con,
constraints.equal_types_var(*fn_var, expected_fn_type, category.clone(), fn_region),
@ -629,7 +611,7 @@ pub fn constrain_expr(
category.clone(),
region,
),
constraints.equal_types_var(*fx_var, fx_expected_type, category, region),
constrain_call_fx(env, constraints, region, *fx_var, category),
];
let and_constraint = constraints.and_constraint(and_cons);
@ -1891,6 +1873,34 @@ pub fn constrain_expr(
}
}
fn constrain_call_fx(
env: &mut Env,
constraints: &mut Constraints,
region: Region,
fx_var: Variable,
category: Category,
) -> Constraint {
let fx_expected_type = match env.enclosing_fx {
Some(enclosing_fn) => {
let enclosing_fx_index = constraints.push_variable(enclosing_fn.fx_var);
constraints.push_expected_type(ForReason(
Reason::CallInFunction(enclosing_fn.ann_region),
enclosing_fx_index,
region,
))
}
None => constraints.push_expected_type(ForReason(
Reason::CallInTopLevelDef,
// top-level defs are only allowed to call pure functions
constraints.push_variable(Variable::PURE),
region,
)),
};
constraints.equal_types_var(fx_var, fx_expected_type, category, region)
}
fn constrain_function_def(
types: &mut Types,
constraints: &mut Constraints,
@ -3517,21 +3527,8 @@ fn constrain_stmt_def(
// We have to unify the stmt fx with the enclosing fx
// since we used the former to constrain the expr.
let enclosing_fx_index = match env.enclosing_fx {
Some(enclosing_fn) => {
let enclosing_fx_index = constraints.push_variable(enclosing_fn.fx_var);
constraints.push_expected_type(ForReason(Reason::Stmt, enclosing_fx_index, region))
}
None => constraints.push_expected_type(ForReason(
// Statements are not allowed in top-level defs
Reason::Stmt,
constraints.push_variable(Variable::PURE),
region,
)),
};
let enclosing_fx_constraint =
constraints.equal_types_var(fx_var, enclosing_fx_index, Category::Unknown, region);
constrain_call_fx(env, constraints, region, fx_var, Category::Unknown);
constraints.and_constraint([body_con, effectful_constraint, enclosing_fx_constraint])
}

View file

@ -14716,7 +14716,7 @@ All branches in an `if` must have the same type!
10 name = Effect.getLine! {}
^^^^^^^^^^^^^^^^^^
However, the type of the enclosing function indicates it must be pure:
However, the type of the enclosing function requires that it's pure:
8 getCheer : Str -> Str
^^^^^^^^^^
@ -14728,6 +14728,43 @@ All branches in an `if` must have the same type!
"###
);
test_report!(
fx_fn_annotated_as_pure_stmt,
indoc!(
r#"
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
import pf.Effect
main! = \{} ->
trim "hello "
trim : Str -> Str
trim = \msg ->
Effect.putLine! "Trimming $(msg)"
Str.trim msg
"#
),
@r###"
EFFECT IN PURE FUNCTION in /code/proj/Main.roc
This expression calls an effectful function:
10 Effect.putLine! "Trimming $(msg)"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
However, the type of the enclosing function requires that it's pure:
8 trim : Str -> Str
^^^^^^^^^^
Tip: Replace `->` with `=>` to annotate it as effectful.
You can still run the program with this error, which can be helpful
when you're debugging.
"###
);
test_report!(
nested_function_def_fx_no_bang,
indoc!(

View file

@ -1737,7 +1737,7 @@ fn to_expr_report<'b>(
match ann_region {
Some(ann_region) => alloc.stack([
alloc.reflow(
"However, the type of the enclosing function indicates it must be pure:",
"However, the type of the enclosing function requires that it's pure:",
),
alloc.region(lines.convert_region(ann_region), Severity::Warning),
alloc.concat([