diff --git a/compiler/problem/src/can.rs b/compiler/problem/src/can.rs index e2ff37a3d8..5ad4ffc80c 100644 --- a/compiler/problem/src/can.rs +++ b/compiler/problem/src/can.rs @@ -25,7 +25,7 @@ pub enum Problem { #[derive(Clone, Debug, PartialEq)] pub enum PrecedenceProblem { - BothNonAssociative(Located, Located), + BothNonAssociative(Symbol, Located, Symbol, Located, Symbol), } #[derive(Clone, Debug, PartialEq)] diff --git a/compiler/reporting/src/report.rs b/compiler/reporting/src/report.rs index a583f75a3d..acfe227109 100644 --- a/compiler/reporting/src/report.rs +++ b/compiler/reporting/src/report.rs @@ -1,5 +1,6 @@ use crate::report::ReportText::{Batch, Module, Region, Value}; use roc_module::symbol::{Interns, ModuleId, Symbol}; +use roc_problem::can::PrecedenceProblem::BothNonAssociative; use roc_problem::can::Problem; use roc_types::pretty_print::content_to_string; use roc_types::subs::{Content, Subs}; @@ -119,6 +120,24 @@ pub fn can_problem(filename: PathBuf, problem: Problem) -> Report { texts.push(Value(argument_symbol)); texts.push(plain_text("\". Adding an underscore at the start of a variable name is a way of saying that the variable is not used.")); } + Problem::PrecedenceProblem(BothNonAssociative( + _left_symbol, + _left_bin_op, + _middle_symbol, + _right_bin_op, + _right_symbol, + )) => panic!("TODO implement precedence problem report"), + Problem::UnsupportedPattern(_pattern_type, _region) => { + panic!("TODO implement unsupported pattern report") + } + Problem::ShadowingInAnnotation { + original_region, + shadow, + } => { + let _a = original_region; + let _b = shadow; + panic!("TODO implement shadow report") + } _ => { panic!("TODO implement others"); } diff --git a/compiler/reporting/tests/test_reporting.rs b/compiler/reporting/tests/test_reporting.rs index 4e12f7f030..800ed2757d 100644 --- a/compiler/reporting/tests/test_reporting.rs +++ b/compiler/reporting/tests/test_reporting.rs @@ -86,6 +86,28 @@ mod test_report { assert_eq!(buf, expected_rendering); } + fn report_problem_as(src: &str, expected_rendering: &str) { + let (_type_problems, can_problems, mut subs, home, interns) = infer_expr_help(src); + + let mut buf: String = String::new(); + let src_lines: Vec<&str> = src.split('\n').collect(); + + match can_problems.first() { + None => {} + Some(problem) => { + let report = can_problem( + filename_from_string(r"\code\proj\Main.roc"), + problem.clone(), + ); + report + .text + .render_ci(&mut buf, &mut subs, home, &src_lines, &interns) + } + } + + assert_eq!(buf, expected_rendering); + } + fn human_readable(str: &str) -> String { return str .replace(RED_CODE, "") @@ -247,35 +269,15 @@ mod test_report { #[test] fn report_unused_def() { - let src: &str = indoc!( - r#" + report_problem_as( + indoc!( + r#" x = 1 y = 2 x "# - ); - - let (_type_problems, can_problems, mut subs, home, interns) = infer_expr_help(src); - - let mut buf: String = String::new(); - let src_lines: Vec<&str> = src.split('\n').collect(); - - match can_problems.first() { - None => {} - Some(problem) => { - let report = can_problem( - filename_from_string(r"\code\proj\Main.roc"), - problem.clone(), - ); - report - .text - .render_ci(&mut buf, &mut subs, home, &src_lines, &interns) - } - } - - assert_eq!( - buf, + ), indoc!( r#" y is not used anywhere in your code. @@ -283,108 +285,125 @@ mod test_report { 2 ┆ y = 2 If you didn't intend on using y then remove it so future readers of your code don't wonder why it is there."# - ) - ); + ), + ) } - #[test] - fn report_unused_argument() { - let src: &str = indoc!( - r#" - y = 9 + // #[test] + // fn report_shadow() { + // report_problem_as( + // indoc!( + // r#" + // i = 1 + // + // s = \i -> + // i + 1 + // + // s i + // "# + // ), + // indoc!(r#" "#), + // ) + // } - box = \class, htmlChildren -> - div [ class ] [] + // #[test] + // fn report_unsupported_top_level_def() { + // report_problem_as( + // indoc!( + // r#" + // x = 1 + // + // 5 = 2 + 1 + // + // x + // "# + // ), + // indoc!(r#" "#), + // ) + // } - div = 4 + // #[test] + // fn report_precedence_problem() { + // report_problem_as( + // indoc!( + // r#" + // x = 1 + // y = + // if 1 == 2 == 3 then + // 4 + // + // else + // 5 + // + // x + // "# + // ), + // indoc!( + // r#" + // Which expression should I evaluate first? "selectedId == thisId" or "thisId == adminsId"? + // + // 3 ┆ if selecteId == thisId == adminsId then + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // + // Please clarify this for me by adding some parentheses. Either "(selectedId == thisId) == adminsId" or "selectedId == (thisId == adminsId)""# + // ), + // ) + // } - box "wizard" [] - "# - ); + // #[test] + // fn report_unused_argument() { + // report_problem_as( + // indoc!(r#" + // y = 9 + // + // box = \class, htmlChildren -> + // div [ class ] [] + // + // div = 4 + // + // box "wizard" [] + // "#), + // indoc!( + // r#" + // box doesn't use htmlChildren. + // + // 3 ┆ box = \class, htmlChildren -> + // + // If you don't need htmlChildren, then you can just remove it. However, if you really do need htmlChildren as an argument of box, prefix it with an underscore, like this: "_htmlChildren". Adding an underscore at the start of a variable name is a way of saying that the variable is not used."# + // ), + // ); + // } - let (_type_problems, can_problems, mut subs, home, interns) = infer_expr_help(src); - - let mut buf: String = String::new(); - let src_lines: Vec<&str> = src.split('\n').collect(); - - match can_problems.first() { - None => {} - Some(problem) => { - let report = can_problem( - filename_from_string(r"\code\proj\Main.roc"), - problem.clone(), - ); - report - .text - .render_ci(&mut buf, &mut subs, home, &src_lines, &interns) - } - } - - assert_eq!( - buf, - indoc!( - r#" - box doesn't use htmlChildren. - - 3 ┆ box = \class, htmlChildren -> - - If you don't need htmlChildren, then you can just remove it. However, if you really do need htmlChildren as an argument of box, prefix it with an underscore, like this: "_htmlChildren". Adding an underscore at the start of a variable name is a way of saying that the variable is not used."# - ) - ); - } - - #[test] - fn report_unused_import() { - let src: &str = indoc!( - r#" - interface Report - exposes [ - plainText, - emText - ] - imports [ - Symbol.{ Interns } - ] - - plainText = \str -> PlainText str - - emText = \str -> EmText str - "# - ); - - let (_type_problems, can_problems, mut subs, home, interns) = infer_expr_help(src); - - let mut buf: String = String::new(); - let src_lines: Vec<&str> = src.split('\n').collect(); - - match can_problems.first() { - None => {} - Some(problem) => { - let report = can_problem( - filename_from_string(r"\code\proj\Main.roc"), - problem.clone(), - ); - report - .text - .render_ci(&mut buf, &mut subs, home, &src_lines, &interns) - } - } - - assert_eq!( - buf, - indoc!( - r#" - Nothing from Symbol is used in this module. - - 6 ┆ imports [ - 7 ┆ Symbol.{ Interns } - ^^^^^^ - 8 ┆ ] - - Since Symbol isn't used, you don't need to import it."# - ) - ); - } + // #[test] + // fn report_unused_import() { + // report_problem_as( + // indoc!(r#" + // interface Report + // exposes [ + // plainText, + // emText + // ] + // imports [ + // Symbol.{ Interns } + // ] + // + // plainText = \str -> PlainText str + // + // emText = \str -> EmText str + // "#), + // indoc!( + // r#" + // Nothing from Symbol is used in this module. + // + // 6 ┆ imports [ + // 7 ┆ Symbol.{ Interns } + // ┆ ^^^^^^ + // 8 ┆ ] + // + // Since Symbol isn't used, you don't need to import it."# + // ), + // ); + // } #[test] fn report_plain_text_color() {