mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Merge pull request #394 from rtfeldman/annotation-def-match
Report when annotation pattern does not match definition pattern
This commit is contained in:
commit
39b70232de
5 changed files with 54 additions and 7 deletions
|
@ -168,7 +168,15 @@ pub fn canonicalize_defs<'a>(
|
|||
pattern_type,
|
||||
)
|
||||
} else {
|
||||
panic!("TODO gracefully handle the case where a type annotation appears immediately before a body def, but the patterns are different. This should be an error; put a newline or comment between them!");
|
||||
// the pattern of the annotation does not match the pattern of the body directly below it
|
||||
env.problems.push(Problem::SignatureDefMismatch {
|
||||
annotation_pattern: pattern.region,
|
||||
def_pattern: body_pattern.region,
|
||||
});
|
||||
|
||||
// both the annotation and definition are skipped!
|
||||
iter.next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type),
|
||||
|
|
|
@ -46,6 +46,10 @@ pub enum Problem {
|
|||
replaced_region: Region,
|
||||
},
|
||||
RuntimeError(RuntimeError),
|
||||
SignatureDefMismatch {
|
||||
annotation_pattern: Region,
|
||||
def_pattern: Region,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use roc_collections::all::MutSet;
|
||||
use roc_problem::can::PrecedenceProblem::BothNonAssociative;
|
||||
use roc_problem::can::{Problem, RuntimeError};
|
||||
use roc_region::all::Region;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::report::{Annotation, Report, RocDocAllocator, RocDocBuilder};
|
||||
|
@ -238,6 +239,14 @@ pub fn can_problem<'b>(
|
|||
alloc.reflow(" definitions from this tag union type."),
|
||||
]),
|
||||
]),
|
||||
Problem::SignatureDefMismatch {
|
||||
ref annotation_pattern,
|
||||
ref def_pattern,
|
||||
} => alloc.stack(vec![
|
||||
alloc.reflow("This annotation does not match the definition immediately following it:"),
|
||||
alloc.region(Region::span_across(annotation_pattern, def_pattern)),
|
||||
alloc.reflow("Is it a typo? If not, put either a newline or comment between them."),
|
||||
]),
|
||||
Problem::RuntimeError(runtime_error) => pretty_runtime_error(alloc, runtime_error),
|
||||
};
|
||||
|
||||
|
|
|
@ -2684,6 +2684,34 @@ mod test_reporting {
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn annotation_definition_mismatch() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
bar : Int
|
||||
foo = \x -> x
|
||||
|
||||
# NOTE: neither bar or foo are defined at this point
|
||||
4
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
-- SYNTAX PROBLEM --------------------------------------------------------------
|
||||
|
||||
This annotation does not match the definition immediately following
|
||||
it:
|
||||
|
||||
1 ┆> bar : Int
|
||||
2 ┆> foo = \x -> x
|
||||
|
||||
Is it a typo? If not, put either a newline or comment between them.
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_num() {
|
||||
report_problem_as(
|
||||
|
|
|
@ -212,7 +212,7 @@ pub fn name_all_type_vars(variable: Variable, subs: &mut Subs) {
|
|||
|
||||
for root in roots {
|
||||
// show the type variable number instead of `*`. useful for debugging
|
||||
// set_root_name(root, &(format!("<{:?}>", root).into()), subs);
|
||||
// set_root_name(root, (format!("<{:?}>", root).into()), subs);
|
||||
if let Some(Appearances::Multiple) = appearances.get(&root) {
|
||||
letters_used = name_root(letters_used, root, subs, &mut taken);
|
||||
}
|
||||
|
@ -227,21 +227,19 @@ fn name_root(
|
|||
) -> u32 {
|
||||
let (generated_name, new_letters_used) = name_type_var(letters_used, taken);
|
||||
|
||||
set_root_name(root, &generated_name, subs);
|
||||
set_root_name(root, generated_name, subs);
|
||||
|
||||
new_letters_used
|
||||
}
|
||||
|
||||
fn set_root_name(root: Variable, name: &Lowercase, subs: &mut Subs) {
|
||||
fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) {
|
||||
use crate::subs::Content::*;
|
||||
|
||||
let mut descriptor = subs.get_without_compacting(root);
|
||||
|
||||
match descriptor.content {
|
||||
FlexVar(None) => {
|
||||
descriptor.content = FlexVar(Some(name.clone()));
|
||||
|
||||
// TODO is this necessary, or was mutating descriptor in place sufficient?
|
||||
descriptor.content = FlexVar(Some(name));
|
||||
subs.set(root, descriptor);
|
||||
}
|
||||
FlexVar(Some(_existing)) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue