errors for patterns

This commit is contained in:
Folkert 2020-04-12 16:39:54 +02:00
parent 97c10e1211
commit c326b09964
5 changed files with 367 additions and 44 deletions

View file

@ -148,34 +148,145 @@ pub fn mono_problem<'b>(
problem: roc_mono::expr::MonoProblem,
) -> Report<'b> {
use roc_mono::expr::MonoProblem::*;
use roc_mono::pattern::Context::*;
use roc_mono::pattern::Error::*;
//#[derive(Clone, Debug, PartialEq)]
//pub enum Error {
// Incomplete(Region, Context, Vec<Pattern>),
// Redundant(Region, Region, usize),
//}
//
//pub enum Context {
// BadArg,
// BadDestruct,
// BadCase,
//}
//
//#[derive(Clone, Debug, PartialEq)]
//pub enum Guard {
// HasGuard,
// NoGuard,
//}
//
match problem {
PatternProblem(Incomplete(region, context, missing)) => todo!("incomplete"),
PatternProblem(Incomplete(region, context, missing)) => match context {
BadArg => {
let doc = alloc.stack(vec![
alloc.reflow("This pattern does not cover all the possibilities"),
alloc.region(region),
alloc.reflow("Other possibilities include:"),
unhandled_patterns_to_doc_block(alloc, missing),
alloc.concat(vec![
alloc.reflow(
"I would have to crash if I saw one of those! \
So rather than pattern matching in function arguments, put a ",
),
alloc.keyword("when"),
alloc.reflow(" in the function body to account for all possibilities."),
]),
]);
Report {
filename,
title: "UNSAFE PATTERN".to_string(),
doc,
}
}
BadDestruct => {
let doc = alloc.stack(vec![
alloc.reflow("This pattern does not cover all the possibilities"),
alloc.region(region),
alloc.reflow("Other possibilities include:"),
unhandled_patterns_to_doc_block(alloc, missing),
alloc.concat(vec![
alloc.reflow(
"I would have to crash if I saw one of those! \
You can use a binding to deconstruct a value if there is only ONE possibility. \
Use a "
),
alloc.keyword("when"),
alloc.reflow(" to account for all possibilities."),
]),
]);
Report {
filename,
title: "UNSAFE PATTERN".to_string(),
doc,
}
}
BadCase => {
let doc = alloc.stack(vec![
alloc.concat(vec![
alloc.reflow("This "),
alloc.keyword("when"),
alloc.reflow(" does not cover all the possibilities"),
]),
alloc.region(region),
alloc.reflow("Other possibilities include:"),
unhandled_patterns_to_doc_block(alloc, missing),
alloc.reflow(
"I would have to crash if I saw one of those! \
Add branches for them!",
),
// alloc.hint().append(alloc.reflow("or use a hole.")),
]);
Report {
filename,
title: "UNSAFE PATTERN".to_string(),
doc,
}
}
},
PatternProblem(Redundant {
overall_region,
branch_region,
index,
}) => todo!("redundant"),
}) => {
let doc = alloc.stack(vec![
alloc.concat(vec![
alloc.reflow("The "),
alloc.string(index.ordinal()),
alloc.reflow(" pattern is redundant:"),
]),
alloc.region(branch_region),
alloc.reflow(
"Any value of this shape will be handled by \
a previous pattern, so this one should be removed.",
),
]);
Report {
filename,
title: "REDUNDANT PATTERN".to_string(),
doc,
}
}
}
}
pub fn unhandled_patterns_to_doc_block<'b>(
alloc: &'b RocDocAllocator<'b>,
patterns: Vec<roc_mono::pattern::Pattern>,
) -> RocDocBuilder<'b> {
use roc_mono::pattern::Pattern::*;
alloc
.vcat(patterns.into_iter().map(|v| pattern_to_doc(alloc, v)))
.indent(4)
.annotate(Annotation::TypeBlock)
}
fn pattern_to_doc<'b>(
alloc: &'b RocDocAllocator<'b>,
pattern: roc_mono::pattern::Pattern,
) -> RocDocBuilder<'b> {
use roc_mono::pattern::Literal::*;
use roc_mono::pattern::Pattern::*;
// Anything,
// Literal(Literal),
// Ctor(Union, TagName, std::vec::Vec<Pattern>),
match pattern {
Anything => alloc.text("_"),
Literal(l) => match l {
Int(i) => alloc.text(i.to_string()),
Bit(true) => alloc.text("True"),
Bit(false) => alloc.text("False"),
Byte(b) => alloc.text(b.to_string()),
Float(f) => alloc.text(f.to_string()),
Str(s) => alloc.string(s.into()),
},
Ctor(_, tag_name, args) => {
let arg_docs = args.into_iter().map(|v| pattern_to_doc(alloc, v));
let docs = std::iter::once(alloc.tag_name(tag_name)).chain(arg_docs);
alloc.intersperse(docs, alloc.space())
}
}
}
@ -641,18 +752,18 @@ impl<'a> RocDocAllocator<'a> {
.append(self.text("").annotate(Annotation::GutterBar))
.append(rest_of_line);
let highlight_text = "^".repeat((region.end_col - region.start_col) as usize);
let highlight_line = self
.line()
.append(self.text(" ".repeat(max_line_number_length)))
.append(self.text("").annotate(Annotation::GutterBar))
.append(
.append(if highlight_text.is_empty() {
self.nil()
} else {
self.text(" ".repeat(region.start_col as usize))
.indent(indent),
)
.append(
self.text("^".repeat((region.end_col - region.start_col) as usize))
.annotate(Annotation::Error),
);
.indent(indent)
.append(self.text(highlight_text).annotate(Annotation::Error))
});
source_line.append(highlight_line)
} else {