Skip to content

Commit

Permalink
Unsuffixed effectul function warning
Browse files Browse the repository at this point in the history
  • Loading branch information
agu-z committed Oct 16, 2024
1 parent b55c8d2 commit 949c54b
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 6 deletions.
70 changes: 66 additions & 4 deletions crates/compiler/load/tests/test_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3804,7 +3804,7 @@ mod test_reporting {
10│ y = { Test.example & age: 3 }
^^^^^^^^^^^^
Only variables can be updated with record update syntax.
Only variables can be updated with record update syntax.
"
);

Expand Down Expand Up @@ -4339,7 +4339,7 @@ mod test_reporting {
like `return 4` in other programming languages. To me, it seems like
you did `return 4` followed by more code in the lines after, that code
would never be executed!
Tip: If you are working with `Task`, this error can happen if you
forgot a `!` somewhere.
"###
Expand Down Expand Up @@ -14391,11 +14391,11 @@ All branches in an `if` must have the same type!
leftover_statement,
indoc!(
r#"
app [main] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
import pf.Effect
main = \{} ->
main! = \{} ->
identity {}
Effect.putLine! "hello"
Expand All @@ -14417,4 +14417,66 @@ All branches in an `if` must have the same type!
Did you forget to use its result? If not, feel free to remove it.
"###
);

test_report!(
function_def_fx_no_bang,
indoc!(
r#"
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
import pf.Effect
main! = \{} ->
printHello {}
printHello = \{} ->
Effect.putLine! "hello"
"#
),
@r###"
── MISSING EXCLAMATION in /code/proj/Main.roc ──────────────────────────────────
This function is effectful, but its name does not indicate so:
8│ printHello = \{} ->
^^^^^^^^^^
Add an exclamation mark at the end of its name, like:
printHello!
This will help readers identify it as a source of effects.
"###
);

test_report!(
nested_function_def_fx_no_bang,
indoc!(
r#"
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
import pf.Effect
main! = \{} ->
printHello = \{} ->
Effect.putLine! "hello"
printHello {}
"#
),
@r###"
── MISSING EXCLAMATION in /code/proj/Main.roc ──────────────────────────────────
This function is effectful, but its name does not indicate so:
6│ printHello = \{} ->
^^^^^^^^^^
Add an exclamation mark at the end of its name, like:
printHello!
This will help readers identify it as a source of effects.
"###
);
}
3 changes: 2 additions & 1 deletion crates/compiler/lower_params/src/type_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ pub fn remove_module_param_arguments(
| TypeError::UnexpectedModuleParams(_, _)
| TypeError::MissingModuleParams(_, _, _)
| TypeError::ModuleParamsMismatch(_, _, _, _)
| TypeError::PureStmt(_) => {}
| TypeError::PureStmt(_)
| TypeError::UnsuffixedEffectfulFunction(_, _) => {}
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions crates/compiler/solve/src/solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use roc_debug_flags::dbg_do;
#[cfg(debug_assertions)]
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
use roc_error_macros::internal_error;
use roc_module::ident::IdentSuffix;
use roc_module::symbol::{ModuleId, Symbol};
use roc_problem::can::CycleEntry;
use roc_region::all::Loc;
Expand Down Expand Up @@ -448,6 +449,8 @@ fn solve(
);

new_scope.insert_symbol_var_if_vacant(*symbol, loc_var.value);

check_symbol_suffix(env, problems, *symbol, *loc_var);
}

// Note that this vars_by_symbol is the one returned by the
Expand Down Expand Up @@ -1512,6 +1515,31 @@ fn solve(
state
}

fn check_symbol_suffix(
env: &mut InferenceEnv<'_>,
problems: &mut Vec<TypeError>,
symbol: Symbol,
loc_var: Loc<Variable>,
) {
match symbol.suffix() {
IdentSuffix::None => {
if let Content::Structure(FlatType::Func(_, _, _, fx)) =
env.subs.get_content_without_compacting(loc_var.value)
{
if let Content::Effectful = env.subs.get_content_without_compacting(*fx) {
problems.push(TypeError::UnsuffixedEffectfulFunction(
loc_var.region,
symbol,
));
}
}
}
IdentSuffix::Bang => {
// [purity-inference] TODO
}
}
}

fn chase_alias_content(subs: &Subs, mut var: Variable) -> (Variable, &Content) {
loop {
match subs.get_content_without_compacting(var) {
Expand Down
5 changes: 4 additions & 1 deletion crates/compiler/solve_problem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub enum TypeError {
MissingModuleParams(Region, ModuleId, ErrorType),
ModuleParamsMismatch(Region, ModuleId, ErrorType, ErrorType),
PureStmt(Region),
UnsuffixedEffectfulFunction(Region, Symbol),
}

impl TypeError {
Expand All @@ -65,6 +66,7 @@ impl TypeError {
TypeError::IngestedFileBadUtf8(..) => Fatal,
TypeError::IngestedFileUnsupportedType(..) => Fatal,
TypeError::PureStmt(..) => Warning,
TypeError::UnsuffixedEffectfulFunction(_, _) => Warning,
}
}

Expand All @@ -81,7 +83,8 @@ impl TypeError {
| TypeError::UnexpectedModuleParams(region, ..)
| TypeError::MissingModuleParams(region, ..)
| TypeError::ModuleParamsMismatch(region, ..)
| TypeError::PureStmt(region) => Some(*region),
| TypeError::PureStmt(region)
| TypeError::UnsuffixedEffectfulFunction(region, _) => Some(*region),
TypeError::UnfulfilledAbility(ab, ..) => ab.region(),
TypeError::Exhaustive(e) => Some(e.region()),
TypeError::CircularDef(c) => c.first().map(|ce| ce.symbol_region),
Expand Down
17 changes: 17 additions & 0 deletions crates/reporting/src/error/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,23 @@ pub fn type_problem<'b>(
severity,
})
}
UnsuffixedEffectfulFunction(region, symbol) => {
let stack = [
alloc.reflow("This function is effectful, but its name does not indicate so:"),
alloc.region(lines.convert_region(region), severity),
alloc.reflow("Add an exclamation mark at the end of its name, like:"),
alloc
.string(format!("{}!", symbol.as_str(alloc.interns)))
.indent(4),
alloc.reflow("This will help readers identify it as a source of effects."),
];
Some(Report {
title: "MISSING EXCLAMATION".to_string(),
filename,
doc: alloc.stack(stack),
severity,
})
}
}
}

Expand Down

0 comments on commit 949c54b

Please sign in to comment.