From 0cfb16c7d52175f14e435ecf4cf928c38543b081 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 2 Jul 2020 23:24:10 +0200 Subject: [PATCH] implement canonicalization error when signature pattern does not match definition pattern. --- compiler/can/src/def.rs | 10 ++++++- compiler/problem/src/can.rs | 4 +++ compiler/reporting/src/error/canonicalize.rs | 14 ++++++++++ compiler/reporting/tests/test_reporting.rs | 28 ++++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index 392974852b..d8194bef68 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -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), diff --git a/compiler/problem/src/can.rs b/compiler/problem/src/can.rs index 5f83be28b0..3b37e40645 100644 --- a/compiler/problem/src/can.rs +++ b/compiler/problem/src/can.rs @@ -46,6 +46,10 @@ pub enum Problem { replaced_region: Region, }, RuntimeError(RuntimeError), + SignatureDefMismatch { + annotation_pattern: Region, + def_pattern: Region, + }, } #[derive(Clone, Debug, PartialEq)] diff --git a/compiler/reporting/src/error/canonicalize.rs b/compiler/reporting/src/error/canonicalize.rs index 9710ab32d5..4a97ec2e66 100644 --- a/compiler/reporting/src/error/canonicalize.rs +++ b/compiler/reporting/src/error/canonicalize.rs @@ -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,19 @@ 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."), + // TODO add link to this guide section + // alloc.hint().append(alloc.reflow( + // "If you want an unused type parameter (a so-called \"phantom type\"), \ + // read the guide section on phantom data.", + // )), + ]), Problem::RuntimeError(runtime_error) => pretty_runtime_error(alloc, runtime_error), }; diff --git a/compiler/reporting/tests/test_reporting.rs b/compiler/reporting/tests/test_reporting.rs index 90f7959672..2fb67fc285 100644 --- a/compiler/reporting/tests/test_reporting.rs +++ b/compiler/reporting/tests/test_reporting.rs @@ -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(