mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
handle AnnotatedBody everywhere. It compiles now!
This commit is contained in:
parent
d2d3681d7e
commit
014131dabe
6 changed files with 108 additions and 81 deletions
|
@ -139,77 +139,37 @@ pub fn canonicalize_defs<'a>(
|
||||||
let mut refs_by_symbol = MutMap::default();
|
let mut refs_by_symbol = MutMap::default();
|
||||||
let mut can_defs_by_symbol = HashMap::with_capacity_and_hasher(num_defs, default_hasher());
|
let mut can_defs_by_symbol = HashMap::with_capacity_and_hasher(num_defs, default_hasher());
|
||||||
let mut pending = Vec::with_capacity(num_defs); // TODO bump allocate this!
|
let mut pending = Vec::with_capacity(num_defs); // TODO bump allocate this!
|
||||||
let mut iter = loc_defs.iter().peekable();
|
|
||||||
|
|
||||||
// Canonicalize all the patterns, record shadowing problems, and store
|
// Canonicalize all the patterns, record shadowing problems, and store
|
||||||
// the ast::Expr values in pending_exprs for further canonicalization
|
// the ast::Expr values in pending_exprs for further canonicalization
|
||||||
// once we've finished assembling the entire scope.
|
// once we've finished assembling the entire scope.
|
||||||
while let Some(loc_def) = iter.next() {
|
for loc_def in loc_defs {
|
||||||
// Any time we have an Annotation followed immediately by a Body,
|
match to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type) {
|
||||||
// check to see if their patterns are equivalent. If they are,
|
None => (),
|
||||||
// turn it into a TypedBody. Otherwise, give an error.
|
Some((new_output, pending_def)) => {
|
||||||
let (new_output, pending_def) = match &loc_def.value {
|
// store the top-level defs, used to ensure that closures won't capture them
|
||||||
Annotation(pattern, annotation) | Nested(Annotation(pattern, annotation)) => {
|
if let PatternType::TopLevelDef = pattern_type {
|
||||||
match iter.peek() {
|
match &pending_def {
|
||||||
Some(Located {
|
PendingDef::AnnotationOnly(_, loc_can_pattern, _)
|
||||||
value: Body(body_pattern, body_expr),
|
| PendingDef::Body(_, loc_can_pattern, _)
|
||||||
region: body_region,
|
| PendingDef::TypedBody(_, loc_can_pattern, _, _) => {
|
||||||
}) => {
|
env.top_level_symbols.extend(
|
||||||
if pattern.value.equivalent(&body_pattern.value) {
|
bindings_from_patterns(std::iter::once(loc_can_pattern))
|
||||||
iter.next();
|
.iter()
|
||||||
|
.map(|t| t.0),
|
||||||
pending_typed_body(
|
|
||||||
env,
|
|
||||||
body_pattern,
|
|
||||||
annotation,
|
|
||||||
body_expr,
|
|
||||||
var_store,
|
|
||||||
&mut scope,
|
|
||||||
pattern_type,
|
|
||||||
)
|
)
|
||||||
} else if loc_def.region.lines_between(body_region) > 1 {
|
|
||||||
// there is a line of whitespace between the annotation and the body
|
|
||||||
// treat annotation and body separately
|
|
||||||
to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type)
|
|
||||||
} else {
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
PendingDef::Alias { .. } | PendingDef::InvalidAlias => {}
|
||||||
}
|
}
|
||||||
_ => to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type),
|
|
||||||
}
|
}
|
||||||
}
|
// Record the ast::Expr for later. We'll do another pass through these
|
||||||
_ => to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type),
|
// once we have the entire scope assembled. If we were to canonicalize
|
||||||
};
|
// the exprs right now, they wouldn't have symbols in scope from defs
|
||||||
|
// that get would have gotten added later in the defs list!
|
||||||
output.union(new_output);
|
pending.push(pending_def);
|
||||||
|
output.union(new_output);
|
||||||
// store the top-level defs, used to ensure that closures won't capture them
|
|
||||||
if let PatternType::TopLevelDef = pattern_type {
|
|
||||||
match &pending_def {
|
|
||||||
PendingDef::AnnotationOnly(_, loc_can_pattern, _)
|
|
||||||
| PendingDef::Body(_, loc_can_pattern, _)
|
|
||||||
| PendingDef::TypedBody(_, loc_can_pattern, _, _) => env.top_level_symbols.extend(
|
|
||||||
bindings_from_patterns(std::iter::once(loc_can_pattern))
|
|
||||||
.iter()
|
|
||||||
.map(|t| t.0),
|
|
||||||
),
|
|
||||||
PendingDef::Alias { .. } | PendingDef::InvalidAlias => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the ast::Expr for later. We'll do another pass through these
|
|
||||||
// once we have the entire scope assembled. If we were to canonicalize
|
|
||||||
// the exprs right now, they wouldn't have symbols in scope from defs
|
|
||||||
// that get would have gotten added later in the defs list!
|
|
||||||
pending.push(pending_def);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
|
@ -1344,7 +1304,7 @@ fn to_pending_def<'a>(
|
||||||
def: &'a ast::Def<'a>,
|
def: &'a ast::Def<'a>,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
) -> (Output, PendingDef<'a>) {
|
) -> Option<(Output, PendingDef<'a>)> {
|
||||||
use roc_parse::ast::Def::*;
|
use roc_parse::ast::Def::*;
|
||||||
|
|
||||||
match def {
|
match def {
|
||||||
|
@ -1359,10 +1319,10 @@ fn to_pending_def<'a>(
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
Some((
|
||||||
output,
|
output,
|
||||||
PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann),
|
PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
Body(loc_pattern, loc_expr) => {
|
Body(loc_pattern, loc_expr) => {
|
||||||
// This takes care of checking for shadowing and adding idents to scope.
|
// This takes care of checking for shadowing and adding idents to scope.
|
||||||
|
@ -1375,10 +1335,41 @@ fn to_pending_def<'a>(
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
Some((
|
||||||
output,
|
output,
|
||||||
PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr),
|
PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr),
|
||||||
)
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotatedBody {
|
||||||
|
ann_pattern,
|
||||||
|
ann_type,
|
||||||
|
comment: _,
|
||||||
|
body_pattern,
|
||||||
|
body_expr,
|
||||||
|
} => {
|
||||||
|
if ann_pattern.value.equivalent(&body_pattern.value) {
|
||||||
|
Some(pending_typed_body(
|
||||||
|
env,
|
||||||
|
ann_pattern,
|
||||||
|
ann_type,
|
||||||
|
body_expr,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
pattern_type,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
// the pattern of the annotation does not match the pattern of the body direc
|
||||||
|
env.problems.push(Problem::SignatureDefMismatch {
|
||||||
|
annotation_pattern: ann_pattern.region,
|
||||||
|
def_pattern: body_pattern.region,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Should we instead build some PendingDef::InvalidAnnotatedBody ? This would
|
||||||
|
// remove the `Option` on this function (and be probably more reliable for further
|
||||||
|
// problem/error reporting)
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Alias { name, vars, ann } => {
|
Alias { name, vars, ann } => {
|
||||||
|
@ -1411,12 +1402,12 @@ fn to_pending_def<'a>(
|
||||||
region: loc_var.region,
|
region: loc_var.region,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (Output::default(), PendingDef::InvalidAlias);
|
return Some((Output::default(), PendingDef::InvalidAlias));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
Some((
|
||||||
Output::default(),
|
Output::default(),
|
||||||
PendingDef::Alias {
|
PendingDef::Alias {
|
||||||
name: Located {
|
name: Located {
|
||||||
|
@ -1426,7 +1417,7 @@ fn to_pending_def<'a>(
|
||||||
vars: can_rigids,
|
vars: can_rigids,
|
||||||
ann,
|
ann,
|
||||||
},
|
},
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
Err((original_region, loc_shadowed_symbol)) => {
|
Err((original_region, loc_shadowed_symbol)) => {
|
||||||
|
@ -1435,7 +1426,7 @@ fn to_pending_def<'a>(
|
||||||
shadow: loc_shadowed_symbol,
|
shadow: loc_shadowed_symbol,
|
||||||
});
|
});
|
||||||
|
|
||||||
(Output::default(), PendingDef::InvalidAlias)
|
Some((Output::default(), PendingDef::InvalidAlias))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> {
|
||||||
Nested(alias @ Alias { .. }) => Nested(alias),
|
Nested(alias @ Alias { .. }) => Nested(alias),
|
||||||
ann @ Annotation(_, _) => Nested(ann),
|
ann @ Annotation(_, _) => Nested(ann),
|
||||||
Nested(ann @ Annotation(_, _)) => Nested(ann),
|
Nested(ann @ Annotation(_, _)) => Nested(ann),
|
||||||
|
ann_body @ AnnotatedBody { .. } => Nested(ann_body),
|
||||||
|
Nested(ann_body @ AnnotatedBody { .. }) => Nested(ann_body),
|
||||||
Nested(NotYetImplemented(s)) => todo!("{}", s),
|
Nested(NotYetImplemented(s)) => todo!("{}", s),
|
||||||
NotYetImplemented(s) => todo!("{}", s),
|
NotYetImplemented(s) => todo!("{}", s),
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ impl<'a> Formattable<'a> for Def<'a> {
|
||||||
loc_pattern.is_multiline() || loc_annotation.is_multiline()
|
loc_pattern.is_multiline() || loc_annotation.is_multiline()
|
||||||
}
|
}
|
||||||
Body(loc_pattern, loc_expr) => loc_pattern.is_multiline() || loc_expr.is_multiline(),
|
Body(loc_pattern, loc_expr) => loc_pattern.is_multiline() || loc_expr.is_multiline(),
|
||||||
|
AnnotatedBody { .. } => true, // Sebbes: not really sure here...
|
||||||
SpaceBefore(sub_def, spaces) | SpaceAfter(sub_def, spaces) => {
|
SpaceBefore(sub_def, spaces) | SpaceAfter(sub_def, spaces) => {
|
||||||
spaces.iter().any(|s| is_comment(s)) || sub_def.is_multiline()
|
spaces.iter().any(|s| is_comment(s)) || sub_def.is_multiline()
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,24 @@ impl<'a> Formattable<'a> for Def<'a> {
|
||||||
Body(loc_pattern, loc_expr) => {
|
Body(loc_pattern, loc_expr) => {
|
||||||
fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent);
|
fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent);
|
||||||
}
|
}
|
||||||
|
AnnotatedBody {
|
||||||
|
ann_pattern,
|
||||||
|
ann_type,
|
||||||
|
comment,
|
||||||
|
body_pattern,
|
||||||
|
body_expr,
|
||||||
|
} => {
|
||||||
|
ann_pattern.format(buf, indent);
|
||||||
|
buf.push_str(" : ");
|
||||||
|
ann_type.format(buf, indent);
|
||||||
|
if let Some(comment_str) = comment {
|
||||||
|
buf.push_str(" # ");
|
||||||
|
buf.push_str(comment_str.trim());
|
||||||
|
}
|
||||||
|
buf.push_str("\n");
|
||||||
|
fmt_body(buf, &body_pattern.value, &body_expr.value, indent);
|
||||||
|
}
|
||||||
|
|
||||||
SpaceBefore(sub_def, spaces) => {
|
SpaceBefore(sub_def, spaces) => {
|
||||||
fmt_spaces(buf, spaces.iter(), indent);
|
fmt_spaces(buf, spaces.iter(), indent);
|
||||||
sub_def.format(buf, indent);
|
sub_def.format(buf, indent);
|
||||||
|
|
|
@ -92,6 +92,25 @@ fn generate_module_doc<'a>(
|
||||||
_ => (acc, None),
|
_ => (acc, None),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
AnnotatedBody{ ann_pattern, .. } => match ann_pattern.value {
|
||||||
|
Pattern::Identifier(identifier) => {
|
||||||
|
// Check if the definition is exposed
|
||||||
|
if exposed_ident_ids
|
||||||
|
.get_id(&InlinableString::from(identifier))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
let entry = DocEntry {
|
||||||
|
name: identifier.to_string(),
|
||||||
|
docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs),
|
||||||
|
};
|
||||||
|
acc.push(entry);
|
||||||
|
}
|
||||||
|
(acc, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (acc, None),
|
||||||
|
},
|
||||||
|
|
||||||
Alias {
|
Alias {
|
||||||
name: _,
|
name: _,
|
||||||
vars: _,
|
vars: _,
|
||||||
|
|
|
@ -281,8 +281,8 @@ pub enum Def<'a> {
|
||||||
ann_pattern: Loc<Pattern<'a>>,
|
ann_pattern: Loc<Pattern<'a>>,
|
||||||
ann_type: Loc<TypeAnnotation<'a>>,
|
ann_type: Loc<TypeAnnotation<'a>>,
|
||||||
comment: Option<&'a str>,
|
comment: Option<&'a str>,
|
||||||
body_pattern: Loc<Pattern<'a>>,
|
body_pattern: &'a Loc<Pattern<'a>>,
|
||||||
body_expr: Loc<Expr<'a>>,
|
body_expr: &'a Loc<Expr<'a>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Blank Space (e.g. comments, spaces, newlines) before or after a def.
|
// Blank Space (e.g. comments, spaces, newlines) before or after a def.
|
||||||
|
|
|
@ -509,12 +509,9 @@ fn to_def<'a>(
|
||||||
Either::First((body_pattern, body_expr)) => {
|
Either::First((body_pattern, body_expr)) => {
|
||||||
Def::Body(arena.alloc(body_pattern), arena.alloc(body_expr))
|
Def::Body(arena.alloc(body_pattern), arena.alloc(body_expr))
|
||||||
}
|
}
|
||||||
Either::Second(((ann_pattern, ann_type), None)) => annotation_or_alias(
|
Either::Second(((ann_pattern, ann_type), None)) => {
|
||||||
arena,
|
annotation_or_alias(arena, &ann_pattern.value, ann_pattern.region, ann_type)
|
||||||
&ann_pattern.value,
|
}
|
||||||
ann_pattern.region,
|
|
||||||
ann_type,
|
|
||||||
),
|
|
||||||
Either::Second((
|
Either::Second((
|
||||||
(ann_pattern, ann_type),
|
(ann_pattern, ann_type),
|
||||||
Some((opt_comment, (body_pattern, body_expr))),
|
Some((opt_comment, (body_pattern, body_expr))),
|
||||||
|
@ -522,8 +519,8 @@ fn to_def<'a>(
|
||||||
ann_pattern: ann_pattern,
|
ann_pattern: ann_pattern,
|
||||||
ann_type: ann_type,
|
ann_type: ann_type,
|
||||||
comment: opt_comment,
|
comment: opt_comment,
|
||||||
body_pattern: body_pattern,
|
body_pattern: arena.alloc(body_pattern),
|
||||||
body_expr: body_expr,
|
body_expr: arena.alloc(body_expr),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue