mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-18 19:31:26 +00:00
Unsuffixed effectul function warning
This commit is contained in:
parent
75856ae804
commit
1da8af390b
5 changed files with 115 additions and 4 deletions
|
|
@ -14547,11 +14547,11 @@ All branches in an `if` must have the same type!
|
||||||
leftover_statement,
|
leftover_statement,
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app [main] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
|
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
|
||||||
|
|
||||||
import pf.Effect
|
import pf.Effect
|
||||||
|
|
||||||
main = \{} ->
|
main! = \{} ->
|
||||||
identity {}
|
identity {}
|
||||||
|
|
||||||
Effect.putLine! "hello"
|
Effect.putLine! "hello"
|
||||||
|
|
@ -14689,4 +14689,66 @@ All branches in an `if` must have the same type!
|
||||||
Num *
|
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.
|
||||||
|
"###
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,8 @@ pub fn remove_module_param_arguments(
|
||||||
| TypeError::UnexpectedModuleParams(_, _)
|
| TypeError::UnexpectedModuleParams(_, _)
|
||||||
| TypeError::MissingModuleParams(_, _, _)
|
| TypeError::MissingModuleParams(_, _, _)
|
||||||
| TypeError::ModuleParamsMismatch(_, _, _, _)
|
| TypeError::ModuleParamsMismatch(_, _, _, _)
|
||||||
| TypeError::PureStmt(_) => {}
|
| TypeError::PureStmt(_)
|
||||||
|
| TypeError::UnsuffixedEffectfulFunction(_, _) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use roc_debug_flags::dbg_do;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
|
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
|
use roc_module::ident::IdentSuffix;
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
use roc_problem::can::CycleEntry;
|
use roc_problem::can::CycleEntry;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
@ -448,6 +449,8 @@ fn solve(
|
||||||
);
|
);
|
||||||
|
|
||||||
new_scope.insert_symbol_var_if_vacant(*symbol, loc_var.value);
|
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
|
// Note that this vars_by_symbol is the one returned by the
|
||||||
|
|
@ -1520,6 +1523,31 @@ fn solve(
|
||||||
state
|
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) {
|
fn chase_alias_content(subs: &Subs, mut var: Variable) -> (Variable, &Content) {
|
||||||
loop {
|
loop {
|
||||||
match subs.get_content_without_compacting(var) {
|
match subs.get_content_without_compacting(var) {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ pub enum TypeError {
|
||||||
MissingModuleParams(Region, ModuleId, ErrorType),
|
MissingModuleParams(Region, ModuleId, ErrorType),
|
||||||
ModuleParamsMismatch(Region, ModuleId, ErrorType, ErrorType),
|
ModuleParamsMismatch(Region, ModuleId, ErrorType, ErrorType),
|
||||||
PureStmt(Region),
|
PureStmt(Region),
|
||||||
|
UnsuffixedEffectfulFunction(Region, Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeError {
|
impl TypeError {
|
||||||
|
|
@ -65,6 +66,7 @@ impl TypeError {
|
||||||
TypeError::IngestedFileBadUtf8(..) => Fatal,
|
TypeError::IngestedFileBadUtf8(..) => Fatal,
|
||||||
TypeError::IngestedFileUnsupportedType(..) => Fatal,
|
TypeError::IngestedFileUnsupportedType(..) => Fatal,
|
||||||
TypeError::PureStmt(..) => Warning,
|
TypeError::PureStmt(..) => Warning,
|
||||||
|
TypeError::UnsuffixedEffectfulFunction(_, _) => Warning,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +83,8 @@ impl TypeError {
|
||||||
| TypeError::UnexpectedModuleParams(region, ..)
|
| TypeError::UnexpectedModuleParams(region, ..)
|
||||||
| TypeError::MissingModuleParams(region, ..)
|
| TypeError::MissingModuleParams(region, ..)
|
||||||
| TypeError::ModuleParamsMismatch(region, ..)
|
| TypeError::ModuleParamsMismatch(region, ..)
|
||||||
| TypeError::PureStmt(region) => Some(*region),
|
| TypeError::PureStmt(region)
|
||||||
|
| TypeError::UnsuffixedEffectfulFunction(region, _) => Some(*region),
|
||||||
TypeError::UnfulfilledAbility(ab, ..) => ab.region(),
|
TypeError::UnfulfilledAbility(ab, ..) => ab.region(),
|
||||||
TypeError::Exhaustive(e) => Some(e.region()),
|
TypeError::Exhaustive(e) => Some(e.region()),
|
||||||
TypeError::CircularDef(c) => c.first().map(|ce| ce.symbol_region),
|
TypeError::CircularDef(c) => c.first().map(|ce| ce.symbol_region),
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,23 @@ pub fn type_problem<'b>(
|
||||||
severity,
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue