Unsuffixed effectul function warning

This commit is contained in:
Agus Zubiaga 2024-10-16 16:08:33 -03:00
parent 75856ae804
commit 1da8af390b
No known key found for this signature in database
5 changed files with 115 additions and 4 deletions

View file

@ -14547,11 +14547,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"
@ -14689,4 +14689,66 @@ All branches in an `if` must have the same type!
Num *
"###
);
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.
"###
);
}

View file

@ -100,7 +100,8 @@ pub fn remove_module_param_arguments(
| TypeError::UnexpectedModuleParams(_, _)
| TypeError::MissingModuleParams(_, _, _)
| TypeError::ModuleParamsMismatch(_, _, _, _)
| TypeError::PureStmt(_) => {}
| TypeError::PureStmt(_)
| TypeError::UnsuffixedEffectfulFunction(_, _) => {}
}
}
}

View file

@ -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;
@ -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
@ -1520,6 +1523,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) {

View file

@ -40,6 +40,7 @@ pub enum TypeError {
MissingModuleParams(Region, ModuleId, ErrorType),
ModuleParamsMismatch(Region, ModuleId, ErrorType, ErrorType),
PureStmt(Region),
UnsuffixedEffectfulFunction(Region, Symbol),
}
impl TypeError {
@ -65,6 +66,7 @@ impl TypeError {
TypeError::IngestedFileBadUtf8(..) => Fatal,
TypeError::IngestedFileUnsupportedType(..) => Fatal,
TypeError::PureStmt(..) => Warning,
TypeError::UnsuffixedEffectfulFunction(_, _) => Warning,
}
}
@ -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),

View file

@ -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,
})
}
}
}