mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-02 05:48:17 +00:00
Report effect call in pure function
This commit is contained in:
parent
839078b5d1
commit
fd2493ee51
2 changed files with 88 additions and 43 deletions
|
|
@ -14543,37 +14543,6 @@ All branches in an `if` must have the same type!
|
|||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
leftover_statement,
|
||||
indoc!(
|
||||
r#"
|
||||
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! = \{} ->
|
||||
identity {}
|
||||
|
||||
Effect.putLine! "hello"
|
||||
|
||||
identity = \x -> x
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── LEFTOVER STATEMENT in /code/proj/Main.roc ───────────────────────────────────
|
||||
|
||||
This statement does not produce any effects:
|
||||
|
||||
6│ identity {}
|
||||
^^^^^^^^^^^
|
||||
|
||||
Standalone statements are only useful if they call effectful
|
||||
functions.
|
||||
|
||||
Did you forget to use its result? If not, feel free to remove it.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
return_outside_of_function,
|
||||
indoc!(
|
||||
|
|
@ -14691,7 +14660,7 @@ All branches in an `if` must have the same type!
|
|||
);
|
||||
|
||||
test_report!(
|
||||
function_def_fx_no_bang,
|
||||
leftover_statement,
|
||||
indoc!(
|
||||
r#"
|
||||
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
|
||||
|
|
@ -14699,25 +14668,63 @@ All branches in an `if` must have the same type!
|
|||
import pf.Effect
|
||||
|
||||
main! = \{} ->
|
||||
printHello {}
|
||||
identity {}
|
||||
|
||||
printHello = \{} ->
|
||||
Effect.putLine! "hello"
|
||||
|
||||
identity = \x -> x
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── MISSING EXCLAMATION in /code/proj/Main.roc ──────────────────────────────────
|
||||
── LEFTOVER STATEMENT in /code/proj/Main.roc ───────────────────────────────────
|
||||
|
||||
This function is effectful, but its name does not indicate so:
|
||||
This statement does not produce any effects:
|
||||
|
||||
8│ printHello = \{} ->
|
||||
^^^^^^^^^^
|
||||
6│ identity {}
|
||||
^^^^^^^^^^^
|
||||
|
||||
Add an exclamation mark at the end of its name, like:
|
||||
Standalone statements are only useful if they call effectful
|
||||
functions.
|
||||
|
||||
printHello!
|
||||
Did you forget to use its result? If not, feel free to remove it.
|
||||
"###
|
||||
);
|
||||
|
||||
This will help readers identify it as a source of effects.
|
||||
test_report!(
|
||||
fx_fn_annotated_as_pure,
|
||||
indoc!(
|
||||
r#"
|
||||
app [main!] { pf: platform "../../../../../examples/cli/effects-platform/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! = \{} ->
|
||||
Effect.putLine! (getCheer "hello")
|
||||
|
||||
getCheer : Str -> Str
|
||||
getCheer = \msg ->
|
||||
name = Effect.getLine! {}
|
||||
|
||||
"$(msg), $(name)!"
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── EFFECT IN PURE FUNCTION in /code/proj/Main.roc ──────────────────────────────
|
||||
|
||||
This expression calls an effectful function:
|
||||
|
||||
10│ name = Effect.getLine! {}
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
However, the type of the enclosing function indicates it must be pure:
|
||||
|
||||
8│ getCheer : 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.
|
||||
"###
|
||||
);
|
||||
|
||||
|
|
@ -14809,4 +14816,6 @@ All branches in an `if` must have the same type!
|
|||
This will help readers identify it as a source of effects.
|
||||
"###
|
||||
);
|
||||
|
||||
// [purity-inference] TODO: check ! in records, tuples, tags, opaques, and arguments
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,7 +351,9 @@ pub fn type_problem<'b>(
|
|||
let stack = [
|
||||
alloc.reflow("This function is pure, but its name suggests otherwise:"),
|
||||
alloc.region(lines.convert_region(region), severity),
|
||||
alloc.reflow("Remove the exclamation mark to give an accurate impression of its behavior."),
|
||||
alloc.reflow(
|
||||
"Remove the exclamation mark to give an accurate impression of its behavior.",
|
||||
),
|
||||
];
|
||||
|
||||
Some(Report {
|
||||
|
|
@ -1692,6 +1694,7 @@ fn to_expr_report<'b>(
|
|||
unimplemented!("record default field is not implemented yet")
|
||||
}
|
||||
Reason::ImportParams(_) => unreachable!(),
|
||||
|
||||
Reason::FunctionOutput => {
|
||||
let problem = alloc.concat([
|
||||
alloc.text("This "),
|
||||
|
|
@ -1726,7 +1729,40 @@ fn to_expr_report<'b>(
|
|||
severity,
|
||||
}
|
||||
}
|
||||
Reason::CallInFunction(_) => todo!("[purity-inference] CallInFunction"),
|
||||
|
||||
Reason::CallInFunction(ann_region) => {
|
||||
let lines = [
|
||||
alloc.reflow("This expression calls an effectful function:"),
|
||||
alloc.region(lines.convert_region(region), severity),
|
||||
match ann_region {
|
||||
Some(ann_region) => alloc.stack([
|
||||
alloc.reflow(
|
||||
"However, the type of the enclosing function indicates it must be pure:",
|
||||
),
|
||||
alloc.region(lines.convert_region(ann_region), Severity::Warning),
|
||||
alloc.concat([
|
||||
alloc.tip(),
|
||||
alloc.text("Replace "),
|
||||
alloc.keyword("->"),
|
||||
alloc.text(" with "),
|
||||
alloc.keyword("=>"),
|
||||
alloc.text(" to annotate it as effectful."),
|
||||
]),
|
||||
]),
|
||||
None => {
|
||||
alloc.reflow("However, the enclosing function is required to be pure.")
|
||||
}
|
||||
},
|
||||
alloc.reflow("You can still run the program with this error, which can be helpful when you're debugging."),
|
||||
];
|
||||
|
||||
Report {
|
||||
filename,
|
||||
title: "EFFECT IN PURE FUNCTION".to_string(),
|
||||
doc: alloc.stack(lines),
|
||||
severity,
|
||||
}
|
||||
}
|
||||
Reason::CallInTopLevelDef => todo!("[purity-inference] CallInTopLevelDef"),
|
||||
Reason::Stmt => todo!("[purity-inference] Stmt"),
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue