mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 23:37:56 +03:00
highlight code snippets better
This commit is contained in:
parent
c326b09964
commit
7632a4b484
@ -22,14 +22,21 @@ use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use ven_graph::{strongly_connected_components, topological_sort_into_groups};
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Def {
|
||||
pub loc_pattern: Located<Pattern>,
|
||||
pub loc_expr: Located<Expr>,
|
||||
pub expr_var: Variable,
|
||||
pub pattern_vars: SendMap<Symbol, Variable>,
|
||||
pub annotation: Option<(Type, IntroducedVariables, SendMap<Symbol, Alias>)>,
|
||||
pub annotation: Option<Annotation>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Annotation {
|
||||
pub signature: Type,
|
||||
pub introduced_variables: IntroducedVariables,
|
||||
pub aliases: SendMap<Symbol, Alias>,
|
||||
pub region: Region,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -794,11 +801,12 @@ fn canonicalize_pending_def<'a>(
|
||||
value: loc_can_expr.value.clone(),
|
||||
},
|
||||
pattern_vars: im::HashMap::clone(&vars_by_symbol),
|
||||
annotation: Some((
|
||||
typ.clone(),
|
||||
output.introduced_variables.clone(),
|
||||
ann.aliases.clone(),
|
||||
)),
|
||||
annotation: Some(Annotation {
|
||||
signature: typ.clone(),
|
||||
introduced_variables: output.introduced_variables.clone(),
|
||||
aliases: ann.aliases.clone(),
|
||||
region: loc_ann.region,
|
||||
}),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -996,11 +1004,12 @@ fn canonicalize_pending_def<'a>(
|
||||
value: loc_can_expr.value.clone(),
|
||||
},
|
||||
pattern_vars: im::HashMap::clone(&vars_by_symbol),
|
||||
annotation: Some((
|
||||
typ.clone(),
|
||||
output.introduced_variables.clone(),
|
||||
ann.aliases.clone(),
|
||||
)),
|
||||
annotation: Some(Annotation {
|
||||
signature: typ.clone(),
|
||||
introduced_variables: output.introduced_variables.clone(),
|
||||
aliases: ann.aliases.clone(),
|
||||
region: loc_ann.region,
|
||||
}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ pub enum Expr {
|
||||
When {
|
||||
cond_var: Variable,
|
||||
expr_var: Variable,
|
||||
region: Region,
|
||||
loc_cond: Box<Located<Expr>>,
|
||||
branches: Vec<WhenBranch>,
|
||||
},
|
||||
@ -464,7 +465,7 @@ pub fn canonicalize_expr<'a>(
|
||||
// Infer the condition expression's type.
|
||||
let cond_var = var_store.fresh();
|
||||
let (can_cond, mut output) =
|
||||
canonicalize_expr(env, var_store, scope, region, &loc_cond.value);
|
||||
canonicalize_expr(env, var_store, scope, loc_cond.region, &loc_cond.value);
|
||||
|
||||
// the condition can never be a tail-call
|
||||
output.tail_call = None;
|
||||
@ -491,6 +492,7 @@ pub fn canonicalize_expr<'a>(
|
||||
let expr = When {
|
||||
expr_var: var_store.fresh(),
|
||||
cond_var,
|
||||
region,
|
||||
loc_cond: Box::new(can_cond),
|
||||
branches: can_branches,
|
||||
};
|
||||
|
@ -149,8 +149,13 @@ pub fn constrain_expr(
|
||||
let mut vars = Vec::with_capacity(updates.len() + 2);
|
||||
let mut cons = Vec::with_capacity(updates.len() + 1);
|
||||
for (field_name, Field { var, loc_expr, .. }) in updates.clone() {
|
||||
let (var, tipe, con) =
|
||||
constrain_field_update(env, var, region, field_name.clone(), &loc_expr);
|
||||
let (var, tipe, con) = constrain_field_update(
|
||||
env,
|
||||
var,
|
||||
loc_expr.region,
|
||||
field_name.clone(),
|
||||
&loc_expr,
|
||||
);
|
||||
fields.insert(field_name, tipe);
|
||||
vars.push(var);
|
||||
cons.push(con);
|
||||
@ -498,6 +503,7 @@ pub fn constrain_expr(
|
||||
expr_var,
|
||||
loc_cond,
|
||||
branches,
|
||||
..
|
||||
} => {
|
||||
// Infer the condition expression's type.
|
||||
let cond_var = *cond_var;
|
||||
@ -935,16 +941,16 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
|
||||
let mut new_rigids = Vec::new();
|
||||
|
||||
let expr_con = match &def.annotation {
|
||||
Some((annotation, introduced_vars, ann_def_aliases)) => {
|
||||
def_aliases = ann_def_aliases.clone();
|
||||
Some(annotation) => {
|
||||
def_aliases = annotation.aliases.clone();
|
||||
|
||||
let arity = annotation.arity();
|
||||
let arity = annotation.signature.arity();
|
||||
let rigids = &env.rigids;
|
||||
let mut ftv = rigids.clone();
|
||||
|
||||
let annotation = instantiate_rigids(
|
||||
annotation,
|
||||
&introduced_vars,
|
||||
let signature = instantiate_rigids(
|
||||
&annotation.signature,
|
||||
&annotation.introduced_variables,
|
||||
&mut new_rigids,
|
||||
&mut ftv,
|
||||
&def.loc_pattern,
|
||||
@ -954,8 +960,10 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
|
||||
let annotation_expected = FromAnnotation(
|
||||
def.loc_pattern.clone(),
|
||||
arity,
|
||||
AnnotationSource::TypedBody,
|
||||
annotation,
|
||||
AnnotationSource::TypedBody {
|
||||
region: annotation.region,
|
||||
},
|
||||
signature,
|
||||
);
|
||||
|
||||
pattern_state.constraints.push(Eq(
|
||||
@ -1106,17 +1114,17 @@ pub fn rec_defs_help(
|
||||
flex_info.def_types.extend(pattern_state.headers);
|
||||
}
|
||||
|
||||
Some((annotation, introduced_vars, ann_def_aliases)) => {
|
||||
for (symbol, alias) in ann_def_aliases.clone() {
|
||||
Some(annotation) => {
|
||||
for (symbol, alias) in annotation.aliases.clone() {
|
||||
def_aliases.insert(symbol, alias);
|
||||
}
|
||||
|
||||
let arity = annotation.arity();
|
||||
let arity = annotation.signature.arity();
|
||||
let mut ftv = env.rigids.clone();
|
||||
|
||||
let annotation = instantiate_rigids(
|
||||
annotation,
|
||||
&introduced_vars,
|
||||
let signature = instantiate_rigids(
|
||||
&annotation.signature,
|
||||
&annotation.introduced_variables,
|
||||
&mut new_rigids,
|
||||
&mut ftv,
|
||||
&def.loc_pattern,
|
||||
@ -1126,8 +1134,10 @@ pub fn rec_defs_help(
|
||||
let annotation_expected = FromAnnotation(
|
||||
def.loc_pattern.clone(),
|
||||
arity,
|
||||
AnnotationSource::TypedBody,
|
||||
annotation.clone(),
|
||||
AnnotationSource::TypedBody {
|
||||
region: annotation.region,
|
||||
},
|
||||
signature.clone(),
|
||||
);
|
||||
let expr_con = constrain_expr(
|
||||
&Env {
|
||||
|
@ -1059,6 +1059,7 @@ pub fn constrain_expr(
|
||||
expr_var,
|
||||
loc_cond,
|
||||
branches,
|
||||
..
|
||||
} => {
|
||||
let cond_var = *cond_var;
|
||||
let cond_type = Variable(cond_var);
|
||||
@ -1897,15 +1898,15 @@ fn constrain_def(
|
||||
let mut new_rigids = Vec::new();
|
||||
|
||||
let expr_con = match &def.annotation {
|
||||
Some((annotation, introduced_vars, ann_def_aliases)) => {
|
||||
def_aliases = ann_def_aliases.clone();
|
||||
let arity = annotation.arity();
|
||||
Some(annotation) => {
|
||||
def_aliases = annotation.aliases.clone();
|
||||
let arity = annotation.signature.arity();
|
||||
let mut ftv = env.rigids.clone();
|
||||
|
||||
let annotation = instantiate_rigids(
|
||||
let signature = instantiate_rigids(
|
||||
var_store,
|
||||
annotation,
|
||||
&introduced_vars,
|
||||
&annotation.signature,
|
||||
&annotation.introduced_variables,
|
||||
&mut new_rigids,
|
||||
&mut ftv,
|
||||
&def.loc_pattern,
|
||||
@ -1915,8 +1916,10 @@ fn constrain_def(
|
||||
let annotation_expected = Expected::FromAnnotation(
|
||||
def.loc_pattern.clone(),
|
||||
arity,
|
||||
AnnotationSource::TypedBody,
|
||||
annotation,
|
||||
AnnotationSource::TypedBody {
|
||||
region: annotation.region,
|
||||
},
|
||||
signature,
|
||||
);
|
||||
|
||||
pattern_state.constraints.push(Eq(
|
||||
@ -2119,16 +2122,16 @@ pub fn rec_defs_help(
|
||||
flex_info.def_types.extend(pattern_state.headers);
|
||||
}
|
||||
|
||||
Some((annotation, introduced_vars, ann_def_aliases)) => {
|
||||
for (symbol, alias) in ann_def_aliases.clone() {
|
||||
Some(annotation) => {
|
||||
for (symbol, alias) in annotation.aliases.clone() {
|
||||
def_aliases.insert(symbol, alias);
|
||||
}
|
||||
let arity = annotation.arity();
|
||||
let arity = annotation.signature.arity();
|
||||
let mut ftv = env.rigids.clone();
|
||||
let annotation = instantiate_rigids(
|
||||
let signature = instantiate_rigids(
|
||||
var_store,
|
||||
annotation,
|
||||
&introduced_vars,
|
||||
&annotation.signature,
|
||||
&annotation.introduced_variables,
|
||||
&mut new_rigids,
|
||||
&mut ftv,
|
||||
&def.loc_pattern,
|
||||
@ -2137,8 +2140,10 @@ pub fn rec_defs_help(
|
||||
let annotation_expected = Expected::FromAnnotation(
|
||||
def.loc_pattern.clone(),
|
||||
arity,
|
||||
AnnotationSource::TypedBody,
|
||||
annotation.clone(),
|
||||
AnnotationSource::TypedBody {
|
||||
region: annotation.region,
|
||||
},
|
||||
signature.clone(),
|
||||
);
|
||||
let expr_con = constrain_expr(
|
||||
&Env {
|
||||
|
@ -393,6 +393,7 @@ fn pattern_to_when<'a>(
|
||||
let wrapped_body = When {
|
||||
cond_var: pattern_var,
|
||||
expr_var: body_var,
|
||||
region: Region::zero(),
|
||||
loc_cond: Box::new(Located::at_zero(Var(symbol))),
|
||||
branches: vec![WhenBranch {
|
||||
patterns: vec![pattern],
|
||||
@ -613,9 +614,10 @@ fn from_can<'a>(
|
||||
When {
|
||||
cond_var,
|
||||
expr_var,
|
||||
region,
|
||||
loc_cond,
|
||||
branches,
|
||||
} => from_can_when(env, cond_var, expr_var, *loc_cond, branches, procs),
|
||||
} => from_can_when(env, cond_var, expr_var, region, *loc_cond, branches, procs),
|
||||
|
||||
If {
|
||||
cond_var,
|
||||
@ -1077,6 +1079,7 @@ fn from_can_when<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
cond_var: Variable,
|
||||
expr_var: Variable,
|
||||
region: Region,
|
||||
loc_cond: Located<roc_can::expr::Expr>,
|
||||
mut branches: std::vec::Vec<roc_can::expr::WhenBranch>,
|
||||
procs: &mut Procs<'a>,
|
||||
@ -1106,7 +1109,7 @@ fn from_can_when<'a>(
|
||||
|
||||
let context = crate::pattern::Context::BadCase;
|
||||
match crate::pattern::check(
|
||||
loc_when_pattern.region,
|
||||
region,
|
||||
&[(
|
||||
Located::at(loc_when_pattern.region, mono_pattern.clone()),
|
||||
guard,
|
||||
@ -1225,7 +1228,7 @@ fn from_can_when<'a>(
|
||||
}
|
||||
|
||||
let context = crate::pattern::Context::BadCase;
|
||||
match crate::pattern::check(loc_cond.region, &loc_branches, context) {
|
||||
match crate::pattern::check(region, &loc_branches, context) {
|
||||
Ok(_) => {}
|
||||
Err(errors) => {
|
||||
use crate::pattern::Error::*;
|
||||
|
@ -30,6 +30,23 @@ impl Region {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, other: &Self) -> bool {
|
||||
use std::cmp::Ordering::*;
|
||||
match self.start_line.cmp(&other.start_line) {
|
||||
Greater => false,
|
||||
Equal => match self.end_line.cmp(&other.end_line) {
|
||||
Less => false,
|
||||
Equal => self.start_col <= other.start_col && self.end_col >= other.end_col,
|
||||
Greater => self.start_col >= other.start_col,
|
||||
},
|
||||
Less => match self.end_line.cmp(&other.end_line) {
|
||||
Less => false,
|
||||
Equal => self.end_col >= other.end_col,
|
||||
Greater => true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_across(start: &Region, end: &Region) -> Self {
|
||||
Region {
|
||||
start_line: start.start_line,
|
||||
|
@ -233,7 +233,7 @@ pub fn mono_problem<'b>(
|
||||
alloc.string(index.ordinal()),
|
||||
alloc.reflow(" pattern is redundant:"),
|
||||
]),
|
||||
alloc.region(branch_region),
|
||||
alloc.region_with_subregion(overall_region, branch_region),
|
||||
alloc.reflow(
|
||||
"Any value of this shape will be handled by \
|
||||
a previous pattern, so this one should be removed.",
|
||||
@ -253,8 +253,6 @@ 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)
|
||||
@ -726,33 +724,68 @@ impl<'a> RocDocAllocator<'a> {
|
||||
.annotate(Annotation::Hint)
|
||||
}
|
||||
|
||||
pub fn region(&'a self, region: roc_region::all::Region) -> DocBuilder<'a, Self, Annotation> {
|
||||
pub fn region_with_subregion(
|
||||
&'a self,
|
||||
region: roc_region::all::Region,
|
||||
sub_region: roc_region::all::Region,
|
||||
) -> DocBuilder<'a, Self, Annotation> {
|
||||
debug_assert!(region.contains(&sub_region));
|
||||
|
||||
// if true, the final line of the snippet will be some ^^^ that point to the region where
|
||||
// the problem is. Otherwise, the snippet will have a > on the lines that are in the regon
|
||||
// where the problem is.
|
||||
let error_highlight_line = sub_region.start_line == region.end_line;
|
||||
|
||||
let max_line_number_length = (region.end_line + 1).to_string().len();
|
||||
let indent = 2;
|
||||
|
||||
if region.start_line == region.end_line {
|
||||
let i = region.start_line;
|
||||
|
||||
let mut result = self.nil();
|
||||
for i in region.start_line..=region.end_line {
|
||||
let line_number_string = (i + 1).to_string();
|
||||
let line_number = line_number_string;
|
||||
let this_line_number_length = line_number.len();
|
||||
|
||||
let line = self.src_lines[i as usize];
|
||||
let rest_of_line = if line.trim().is_empty() {
|
||||
self.nil()
|
||||
|
||||
let rest_of_line = if !line.trim().is_empty() {
|
||||
self.text(line)
|
||||
.annotate(Annotation::CodeBlock)
|
||||
.indent(indent)
|
||||
} else {
|
||||
self.nil()
|
||||
.append(self.text(line).indent(2))
|
||||
.annotate(Annotation::CodeBlock)
|
||||
};
|
||||
|
||||
let source_line = self
|
||||
.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
.append(self.text(line_number).annotate(Annotation::LineNumber))
|
||||
.append(self.text(" ┆").annotate(Annotation::GutterBar))
|
||||
.append(rest_of_line);
|
||||
let source_line = if !error_highlight_line
|
||||
&& i >= sub_region.start_line
|
||||
&& i <= sub_region.end_line
|
||||
{
|
||||
self.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
.append(self.text(line_number).annotate(Annotation::LineNumber))
|
||||
.append(self.text(" ┆").annotate(Annotation::GutterBar))
|
||||
.append(self.text(">").annotate(Annotation::Error))
|
||||
.append(rest_of_line)
|
||||
} else if error_highlight_line {
|
||||
self.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
.append(self.text(line_number).annotate(Annotation::LineNumber))
|
||||
.append(self.text(" ┆").annotate(Annotation::GutterBar))
|
||||
.append(rest_of_line)
|
||||
} else {
|
||||
self.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
.append(self.text(line_number).annotate(Annotation::LineNumber))
|
||||
.append(self.text(" ┆").annotate(Annotation::GutterBar))
|
||||
.append(self.text(" "))
|
||||
.append(rest_of_line)
|
||||
};
|
||||
|
||||
let highlight_text = "^".repeat((region.end_col - region.start_col) as usize);
|
||||
result = result.append(source_line);
|
||||
|
||||
if i != region.end_line {
|
||||
result = result.append(self.line())
|
||||
}
|
||||
}
|
||||
|
||||
if error_highlight_line {
|
||||
let highlight_text = "^".repeat((sub_region.end_col - sub_region.start_col) as usize);
|
||||
let highlight_line = self
|
||||
.line()
|
||||
.append(self.text(" ".repeat(max_line_number_length)))
|
||||
@ -760,44 +793,19 @@ impl<'a> RocDocAllocator<'a> {
|
||||
.append(if highlight_text.is_empty() {
|
||||
self.nil()
|
||||
} else {
|
||||
self.text(" ".repeat(region.start_col as usize))
|
||||
self.text(" ".repeat(sub_region.start_col as usize))
|
||||
.indent(indent)
|
||||
.append(self.text(highlight_text).annotate(Annotation::Error))
|
||||
});
|
||||
|
||||
source_line.append(highlight_line)
|
||||
} else {
|
||||
let mut result = self.nil();
|
||||
for i in region.start_line..=region.end_line {
|
||||
let line_number_string = (i + 1).to_string();
|
||||
let line_number = line_number_string;
|
||||
let this_line_number_length = line_number.len();
|
||||
|
||||
let line = self.src_lines[i as usize];
|
||||
let rest_of_line = if !line.trim().is_empty() {
|
||||
self.text(line)
|
||||
.annotate(Annotation::CodeBlock)
|
||||
.indent(indent)
|
||||
} else {
|
||||
self.nil()
|
||||
};
|
||||
|
||||
let source_line = self
|
||||
.text(" ".repeat(max_line_number_length - this_line_number_length))
|
||||
.append(self.text(line_number).annotate(Annotation::LineNumber))
|
||||
.append(self.text(" ┆").annotate(Annotation::GutterBar))
|
||||
.append(self.text(">").annotate(Annotation::Error))
|
||||
.append(rest_of_line);
|
||||
|
||||
result = result.append(source_line);
|
||||
|
||||
if i != region.end_line {
|
||||
result = result.append(self.line())
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
result = result.append(highlight_line);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn region(&'a self, region: roc_region::all::Region) -> DocBuilder<'a, Self, Annotation> {
|
||||
self.region_with_subregion(region, region)
|
||||
}
|
||||
|
||||
pub fn ident(&'a self, ident: Ident) -> DocBuilder<'a, Self, Annotation> {
|
||||
|
@ -40,15 +40,20 @@ fn report_mismatch<'b>(
|
||||
found: ErrorType,
|
||||
expected_type: ErrorType,
|
||||
region: roc_region::all::Region,
|
||||
_opt_highlight: Option<roc_region::all::Region>,
|
||||
opt_highlight: Option<roc_region::all::Region>,
|
||||
problem: RocDocBuilder<'b>,
|
||||
this_is: RocDocBuilder<'b>,
|
||||
instead_of: RocDocBuilder<'b>,
|
||||
further_details: Option<RocDocBuilder<'b>>,
|
||||
) -> Report<'b> {
|
||||
let snippet = if let Some(highlight) = opt_highlight {
|
||||
alloc.region_with_subregion(highlight, region)
|
||||
} else {
|
||||
alloc.region(region)
|
||||
};
|
||||
let lines = vec![
|
||||
problem,
|
||||
alloc.region(region),
|
||||
snippet,
|
||||
type_comparison(
|
||||
alloc,
|
||||
found,
|
||||
@ -74,14 +79,19 @@ fn report_bad_type<'b>(
|
||||
found: ErrorType,
|
||||
expected_type: ErrorType,
|
||||
region: roc_region::all::Region,
|
||||
_opt_highlight: Option<roc_region::all::Region>,
|
||||
opt_highlight: Option<roc_region::all::Region>,
|
||||
problem: RocDocBuilder<'b>,
|
||||
this_is: RocDocBuilder<'b>,
|
||||
further_details: RocDocBuilder<'b>,
|
||||
) -> Report<'b> {
|
||||
let snippet = if let Some(highlight) = opt_highlight {
|
||||
alloc.region_with_subregion(highlight, region)
|
||||
} else {
|
||||
alloc.region(region)
|
||||
};
|
||||
let lines = vec![
|
||||
problem,
|
||||
alloc.region(region),
|
||||
snippet,
|
||||
lone_type(
|
||||
alloc,
|
||||
found,
|
||||
@ -150,6 +160,8 @@ fn to_expr_report<'b>(
|
||||
None => (alloc.text("this"), alloc.nil()),
|
||||
};
|
||||
|
||||
let mut region = None;
|
||||
|
||||
let thing = match annotation_source {
|
||||
TypedIfBranch {
|
||||
index,
|
||||
@ -176,17 +188,20 @@ fn to_expr_report<'b>(
|
||||
alloc.keyword("when"),
|
||||
alloc.text(" expression:"),
|
||||
]),
|
||||
TypedBody => alloc.concat(vec![
|
||||
alloc.text("body of "),
|
||||
the_name_text,
|
||||
alloc.text(" definition:"),
|
||||
]),
|
||||
TypedBody { region: ann_region } => {
|
||||
region = Some(ann_region);
|
||||
alloc.concat(vec![
|
||||
alloc.text("body of "),
|
||||
the_name_text,
|
||||
alloc.text(" definition:"),
|
||||
])
|
||||
}
|
||||
};
|
||||
|
||||
let it_is = match annotation_source {
|
||||
TypedIfBranch { index, .. } => format!("The {} branch is", index.ordinal()),
|
||||
TypedWhenBranch { index, .. } => format!("The {} branch is", index.ordinal()),
|
||||
TypedBody => "The body is".into(),
|
||||
TypedBody { .. } => "The body is".into(),
|
||||
};
|
||||
|
||||
let comparison = type_comparison(
|
||||
@ -207,7 +222,14 @@ fn to_expr_report<'b>(
|
||||
filename,
|
||||
doc: alloc.stack(vec![
|
||||
alloc.text("Something is off with the ").append(thing),
|
||||
alloc.region(expr_region),
|
||||
match region {
|
||||
None => alloc.region(expr_region),
|
||||
Some(ann_region) => {
|
||||
let joined =
|
||||
roc_region::all::Region::span_across(&ann_region, &expr_region);
|
||||
alloc.region_with_subregion(joined, expr_region)
|
||||
}
|
||||
},
|
||||
comparison,
|
||||
]),
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||
&mut env,
|
||||
&var_store,
|
||||
&mut scope,
|
||||
Region::zero(),
|
||||
loc_expr.region,
|
||||
&loc_expr.value,
|
||||
);
|
||||
|
||||
|
@ -23,10 +23,8 @@ mod test_reporting {
|
||||
use std::path::PathBuf;
|
||||
// use roc_region::all;
|
||||
use crate::helpers::{can_expr, infer_expr, CanExprOut};
|
||||
use roc_reporting::report;
|
||||
use roc_reporting::report::{RocDocAllocator, RocDocBuilder};
|
||||
use roc_solve::solve;
|
||||
use std::fmt::Write;
|
||||
|
||||
fn filename_from_string(str: &str) -> PathBuf {
|
||||
let mut filename = PathBuf::new();
|
||||
@ -89,7 +87,7 @@ mod test_reporting {
|
||||
let pointer_size = std::mem::size_of::<u64>() as u32;
|
||||
|
||||
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
||||
let mono_expr = Expr::new(
|
||||
let _mono_expr = Expr::new(
|
||||
&arena,
|
||||
&mut subs,
|
||||
&mut mono_problems,
|
||||
@ -556,7 +554,7 @@ mod test_reporting {
|
||||
|
||||
I cannot find a `theAdmin` value
|
||||
|
||||
<cyan>3<reset><magenta> ┆<reset><white> theAdmin<reset>
|
||||
<cyan>3<reset><magenta> ┆<reset> <white>theAdmin<reset>
|
||||
<magenta> ┆<reset> <red>^^^^^^^^<reset>
|
||||
|
||||
these names seem close though:
|
||||
@ -660,8 +658,9 @@ mod test_reporting {
|
||||
|
||||
This `if` guard condition needs to be a Bool:
|
||||
|
||||
2 ┆ 2 if 1 -> 0x0
|
||||
┆ ^
|
||||
1 ┆ when 1 is
|
||||
2 ┆> 2 if 1 -> 0x0
|
||||
3 ┆ _ -> 0x1
|
||||
|
||||
Right now it’s a number of type:
|
||||
|
||||
@ -751,6 +750,8 @@ mod test_reporting {
|
||||
|
||||
The 2nd branch of this `when` does not match all the previous branches:
|
||||
|
||||
1 ┆ when 1 is
|
||||
2 ┆ 2 -> "foo"
|
||||
3 ┆ 3 -> {}
|
||||
┆ ^^
|
||||
|
||||
@ -817,7 +818,7 @@ mod test_reporting {
|
||||
I cannot update the `.foo` field like this:
|
||||
|
||||
4 ┆ { x & foo: "bar" }
|
||||
┆ ^^^^^^^^^^^^^^^^^^
|
||||
┆ ^^^^^
|
||||
|
||||
You are trying to update `.foo` to be a string of type:
|
||||
|
||||
@ -834,67 +835,6 @@ mod test_reporting {
|
||||
)
|
||||
}
|
||||
|
||||
// needs a bit more infrastructure re. diffing records
|
||||
// #[test]
|
||||
// fn record_update_keys() {
|
||||
// report_problem_as(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// x : { foo : {} }
|
||||
// x = { foo: {} }
|
||||
//
|
||||
// { x & baz: "bar" }
|
||||
// "#
|
||||
// ),
|
||||
// indoc!(
|
||||
// r#"
|
||||
// The `x` record does not have a `baz` field:
|
||||
//
|
||||
// 4 ┆ { x & baz: "bar" }
|
||||
// ┆ ^^^
|
||||
//
|
||||
// This is usually a typo. Here are the `x` fields that are most similar:
|
||||
//
|
||||
// { foo : {}
|
||||
// }
|
||||
//
|
||||
// So maybe `baz` should be `foo`?
|
||||
// "#
|
||||
// ),
|
||||
// )
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn num_literal() {
|
||||
// report_problem_as(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// x : Str
|
||||
// x = 4
|
||||
//
|
||||
// x
|
||||
// "#
|
||||
// ),
|
||||
// indoc!(
|
||||
// r#"
|
||||
// Something is off with the body of the `x` definition:
|
||||
//
|
||||
// 4 ┆ x = 4
|
||||
// ┆ ^
|
||||
//
|
||||
// The body is a number of type:
|
||||
//
|
||||
// Num a
|
||||
//
|
||||
// But the type annotation on `x` says that it should be:
|
||||
//
|
||||
// Str
|
||||
//
|
||||
// "#
|
||||
// ),
|
||||
// )
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn circular_type() {
|
||||
report_problem_as(
|
||||
@ -1156,6 +1096,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `x` definition:
|
||||
|
||||
1 ┆ x : Int -> Int
|
||||
2 ┆ x = \_ -> 3.14
|
||||
┆ ^^^^^^^^^^
|
||||
|
||||
@ -1488,6 +1429,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of this definition:
|
||||
|
||||
1 ┆ { x } : { x : Int }
|
||||
2 ┆ { x } = { x: 4.0 }
|
||||
┆ ^^^^^^^^^^
|
||||
|
||||
@ -1522,6 +1464,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `x` definition:
|
||||
|
||||
1 ┆ x : { a : Int, b : Float, c : Bool }
|
||||
2 ┆ x = { b: 4.0 }
|
||||
┆ ^^^^^^^^^^
|
||||
|
||||
@ -1556,6 +1499,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1 ┆ f : a, b -> a
|
||||
2 ┆ f = \x, y -> if True then x else y
|
||||
┆ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -1593,6 +1537,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1 ┆ f : Bool -> msg
|
||||
2 ┆ f = \_ -> Foo
|
||||
┆ ^^^^^^^^^
|
||||
|
||||
@ -1631,6 +1576,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1 ┆ f : msg
|
||||
2 ┆ f = 0x3
|
||||
┆ ^^^
|
||||
|
||||
@ -1715,6 +1661,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1 ┆ f : Bool -> Int
|
||||
2 ┆> f = \_ ->
|
||||
3 ┆> ok = 3
|
||||
4 ┆>
|
||||
@ -1865,6 +1812,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1 ┆ f : { fo: Int }ext -> Int
|
||||
2 ┆> f = \r ->
|
||||
3 ┆> r2 = { r & foo: r.fo }
|
||||
4 ┆>
|
||||
@ -2001,6 +1949,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1 ┆ f : [ A ] -> [ A, B ]
|
||||
2 ┆ f = \a -> a
|
||||
┆ ^^^^^^^
|
||||
|
||||
@ -2038,6 +1987,7 @@ mod test_reporting {
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1 ┆ f : [ A ] -> [ A, B, C ]
|
||||
2 ┆ f = \a -> a
|
||||
┆ ^^^^^^^
|
||||
|
||||
@ -2162,8 +2112,8 @@ mod test_reporting {
|
||||
|
||||
This `when` does not cover all the possibilities
|
||||
|
||||
2 ┆ 2 -> 0x3
|
||||
┆ ^
|
||||
1 ┆> when 0x1 is
|
||||
2 ┆> 2 -> 0x3
|
||||
|
||||
Other possibilities include:
|
||||
|
||||
@ -2181,9 +2131,9 @@ mod test_reporting {
|
||||
indoc!(
|
||||
r#"
|
||||
when 0x1 is
|
||||
2 -> 0x3
|
||||
2 -> 0x4
|
||||
_ -> 0x5
|
||||
2 -> 3
|
||||
2 -> 4
|
||||
_ -> 5
|
||||
"#
|
||||
),
|
||||
// should not give errors
|
||||
@ -2193,8 +2143,10 @@ mod test_reporting {
|
||||
|
||||
The 2nd pattern is redundant:
|
||||
|
||||
3 ┆ 2 -> 0x4
|
||||
┆ ^
|
||||
1 ┆ when 0x1 is
|
||||
2 ┆ 2 -> 3
|
||||
3 ┆> 2 -> 4
|
||||
4 ┆ _ -> 5
|
||||
|
||||
Any value of this shape will be handled by a previous pattern, so this
|
||||
one should be removed.
|
||||
|
@ -606,7 +606,7 @@ pub enum PReason {
|
||||
pub enum AnnotationSource {
|
||||
TypedIfBranch { index: Index, num_branches: usize },
|
||||
TypedWhenBranch { index: Index },
|
||||
TypedBody,
|
||||
TypedBody { region: Region },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
Loading…
Reference in New Issue
Block a user