remove EmptyDefsFinal

This commit is contained in:
Kiryl Dziamura 2024-06-28 20:54:28 +02:00
parent 05ab018380
commit de9ed734c5
No known key found for this signature in database
GPG Key ID: FB539501A4561ACF
7 changed files with 49 additions and 204 deletions

View File

@ -755,28 +755,6 @@ pub fn desugar_expr<'a>(
})
}
// Replace an empty final def with a `Task.ok {}`
EmptyDefsFinal => {
let mut apply_args: Vec<&'a Loc<Expr<'a>>> = Vec::new_in(arena);
apply_args
.push(arena.alloc(Loc::at(loc_expr.region, Expr::Record(Collection::empty()))));
arena.alloc(Loc::at(
loc_expr.region,
Expr::Apply(
arena.alloc(Loc::at(
loc_expr.region,
Expr::Var {
module_name: ModuleName::TASK,
ident: "ok",
},
)),
arena.alloc(apply_args),
CalledVia::BangSuffix,
),
))
}
// note this only exists after desugaring
LowLevelDbg(_, _, _) => loc_expr,
}

View File

@ -621,9 +621,6 @@ pub fn canonicalize_expr<'a>(
use Expr::*;
let (expr, output) = match expr {
&ast::Expr::EmptyDefsFinal => {
internal_error!("EmptyDefsFinal should have been desugared")
}
&ast::Expr::Num(str) => {
let answer = num_expr_from_result(var_store, finish_parsing_num(str), region, env);
@ -2392,8 +2389,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::Expr::Backpassing(_, _, _)
| ast::Expr::SpaceBefore(_, _)
| ast::Expr::Str(StrLiteral::Block(_))
| ast::Expr::SpaceAfter(_, _)
| ast::Expr::EmptyDefsFinal => false,
| ast::Expr::SpaceAfter(_, _) => false,
// These can contain subexpressions, so we need to recursively check those
ast::Expr::Str(StrLiteral::Line(segments)) => {
segments.iter().all(|segment| match segment {

View File

@ -45,7 +45,6 @@ impl<'a> Formattable for Expr<'a> {
| MalformedClosure
| Tag(_)
| OpaqueRef(_)
| EmptyDefsFinal
| Crash => false,
RecordAccess(inner, _) | TupleAccess(inner, _) | TaskAwaitBang(inner) => {
@ -420,9 +419,6 @@ impl<'a> Formattable for Expr<'a> {
indent,
);
}
EmptyDefsFinal => {
// no need to print anything
}
_ => {
buf.ensure_ends_with_newline();
buf.indent(indent);
@ -439,9 +435,6 @@ impl<'a> Formattable for Expr<'a> {
buf.push(')');
}
}
EmptyDefsFinal => {
// no need to print anything
}
Expect(condition, continuation) => {
fmt_expect(buf, condition, continuation, self.is_multiline(), indent);
}

View File

@ -768,7 +768,6 @@ impl<'a> RemoveSpaces<'a> for StrSegment<'a> {
impl<'a> RemoveSpaces<'a> for Expr<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self {
match *self {
Expr::EmptyDefsFinal => Expr::EmptyDefsFinal,
Expr::Float(a) => Expr::Float(a),
Expr::Num(a) => Expr::Num(a),
Expr::NonBase10Int {

View File

@ -462,10 +462,6 @@ pub enum Expr<'a> {
/// Multiple defs in a row
Defs(&'a Defs<'a>, &'a Loc<Expr<'a>>),
/// Used in place of an expression when the final expression is empty
/// This may happen if the final expression is actually a suffixed statement
EmptyDefsFinal,
Backpassing(&'a [Loc<Pattern<'a>>], &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
Expect(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
Dbg(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
@ -613,7 +609,6 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
Expr::Crash => false,
Expr::Tag(_) => false,
Expr::OpaqueRef(_) => false,
Expr::EmptyDefsFinal => false,
Expr::Backpassing(_, _, _) => false, // TODO: we might want to check this?
Expr::Expect(a, b) | Expr::Dbg(a, b) => {
is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value)
@ -975,8 +970,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
| MalformedIdent(_, _)
| MalformedClosure
| PrecedenceConflict(_)
| MalformedSuffixed(_)
| EmptyDefsFinal => { /* terminal */ }
| MalformedSuffixed(_) => { /* terminal */ }
}
}
}
@ -1183,51 +1177,43 @@ impl<'a> Defs<'a> {
})
}
// We could have a type annotation as the last tag,
// this helper ensures we refer to the last value_def
// and that we remove the correct tag
pub fn last_value_suffixed(&self) -> Option<(Self, &'a Loc<Expr<'a>>)> {
let value_indexes =
self.tags
.clone()
.into_iter()
.enumerate()
.filter_map(|(tag_index, tag)| match tag.split() {
Ok(_) => None,
Err(value_index) => Some((tag_index, value_index.index())),
});
pub fn last_value_suffixed(&mut self) -> Option<&'a Loc<Expr<'a>>> {
let last_value_suffix = self
.tags
.iter()
.enumerate()
.rev()
.find_map(|(tag_index, tag)| match tag.split() {
Ok(_) => None,
Err(value_index) => match self.value_defs[value_index.index()] {
ValueDef::Body(
Loc {
value: Pattern::RecordDestructure(collection),
..
},
loc_expr,
) if collection.is_empty() && is_expr_suffixed(&loc_expr.value) => {
Some((tag_index, loc_expr))
}
ValueDef::Stmt(loc_expr) if is_expr_suffixed(&loc_expr.value) => {
Some((tag_index, loc_expr))
}
_ => None,
},
});
if let Some((tag_index, value_index)) = value_indexes.last() {
match self.value_defs[value_index] {
ValueDef::Body(
Loc {
value: Pattern::RecordDestructure(collection),
..
},
loc_expr,
) if collection.is_empty() && is_expr_suffixed(&loc_expr.value) => {
let mut new_defs = self.clone();
new_defs.remove_value_def(tag_index);
return Some((new_defs, loc_expr));
}
ValueDef::Stmt(loc_expr) if is_expr_suffixed(&loc_expr.value) => {
let mut new_defs = self.clone();
new_defs.remove_value_def(tag_index);
return Some((new_defs, loc_expr));
}
_ => {}
}
if let Some((tag_index, loc_expr)) = last_value_suffix {
self.remove_tag(tag_index);
Some(loc_expr)
} else {
None
}
None
}
pub fn remove_value_def(&mut self, index: usize) {
pub fn remove_tag(&mut self, tag_index: usize) {
match self
.tags
.get(index)
.get(tag_index)
.expect("got an invalid index for Defs")
.split()
{
@ -1260,10 +1246,10 @@ impl<'a> Defs<'a> {
}
}
}
self.tags.remove(index);
self.regions.remove(index);
self.space_after.remove(index);
self.space_before.remove(index);
self.tags.remove(tag_index);
self.regions.remove(tag_index);
self.space_after.remove(tag_index);
self.space_before.remove(tag_index);
}
/// NOTE assumes the def itself is pushed already!
@ -2394,7 +2380,6 @@ impl<'a> Malformed for Expr<'a> {
Tag(_) |
OpaqueRef(_) |
SingleQuote(_) | // This is just a &str - not a bunch of segments
EmptyDefsFinal |
Crash => false,
Str(inner) => inner.is_malformed(),

View File

@ -372,31 +372,14 @@ fn expr_operator_chain<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a
end,
};
match parse_expr_end(
parse_expr_end(
new_min_indent,
options,
expr_state,
arena,
state,
initial_state,
) {
Err(err) => Err(err),
Ok((progress, expr, new_state)) => {
// We need to check if we have just parsed a suffixed statement,
// if so, this is a defs node.
if is_expr_suffixed(&expr) {
let def_region = Region::new(end, new_state.pos());
let value_def = ValueDef::Stmt(arena.alloc(Loc::at(def_region, expr)));
let mut defs = Defs::default();
defs.push_value_def(value_def, def_region, &[], &[]);
return parse_defs_expr(options, min_indent, defs, arena, new_state);
} else {
Ok((progress, expr, new_state))
}
}
}
)
}
}
})
@ -1151,69 +1134,6 @@ pub fn parse_single_def_assignment<'a>(
parse_def_expr.parse(arena, initial_state, min_indent)?;
let region = Region::span_across(&def_loc_pattern.region, &first_loc_expr.region);
// If the expression is actually a suffixed statement, then we need to continue
// to parse the rest of the expression
if crate::ast::is_expr_suffixed(&first_loc_expr.value) {
let mut defs = Defs::default();
// Take the suffixed value and make it a e.g. Body(`{}=`, Apply(Var(...)))
// we will keep the pattern `def_loc_pattern` for the new Defs
defs.push_value_def(
ValueDef::Stmt(arena.alloc(first_loc_expr)),
Region::span_across(&def_loc_pattern.region, &first_loc_expr.region),
spaces_before_current,
&[],
);
// Try to parse the rest of the expression as multiple defs, which may contain sub-assignments
match parse_defs_expr(
options,
min_indent,
defs.clone(),
arena,
state_after_first_expression.clone(),
) {
Ok((progress_after_rest_of_def, expr, state_after_rest_of_def)) => {
let final_loc_expr = arena.alloc(Loc::at(region, expr));
let value_def = ValueDef::Body(arena.alloc(def_loc_pattern), final_loc_expr);
return Ok((
progress_after_rest_of_def,
Some(SingleDef {
type_or_value: Either::Second(value_def),
region,
spaces_before: spaces_before_current,
spaces_after: &[],
}),
state_after_rest_of_def,
));
}
Err(_) => {
// Unable to parse more defs, continue and return the first parsed expression as a stement
let empty_return =
arena.alloc(Loc::at(first_loc_expr.region, Expr::EmptyDefsFinal));
let value_def = ValueDef::Body(
arena.alloc(def_loc_pattern),
arena.alloc(Loc::at(
first_loc_expr.region,
Expr::Defs(arena.alloc(defs), empty_return),
)),
);
return Ok((
progress_after_first,
Some(SingleDef {
type_or_value: Either::Second(value_def),
region,
spaces_before: spaces_before_current,
spaces_after: &[],
}),
state_after_first_expression,
));
}
}
}
let value_def = ValueDef::Body(arena.alloc(def_loc_pattern), arena.alloc(first_loc_expr));
Ok((
@ -1458,7 +1378,7 @@ fn parse_defs_expr<'a>(
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
match parse_defs_end(options, min_indent, defs, arena, state) {
Err(bad) => Err(bad),
Ok((_, def_state, state)) => {
Ok((_, mut def_state, state)) => {
// this is no def, because there is no `=` or `:`; parse as an expr
let parse_final_expr = space0_before_e(expr_start(options), EExpr::IndentEnd);
@ -1467,41 +1387,17 @@ fn parse_defs_expr<'a>(
// If the last def was a suffixed statement, assume this was
// intentional by the application author instead of giving
// an error.
if let Some((new_defs, loc_ret)) = def_state.last_value_suffixed() {
// note we check the tags here and not value_defs, as there may be redundant defs in Defs
let mut local_defs = new_defs.clone();
let last_stmt = ValueDef::Stmt(loc_ret);
local_defs.push_value_def(last_stmt, loc_ret.region, &[], &[]);
//check the length of the defs we would return, if we only have one
// we can just return the expression
// note we use tags here, as we may have redundant defs in Defs
if local_defs
.tags
.iter()
.filter(|tag| tag.split().is_err())
.count()
== 1
{
return Ok((MadeProgress, loc_ret.value, state));
}
return Ok((
match def_state.last_value_suffixed() {
Some(loc_ret) => Ok((
MadeProgress,
Expr::Defs(
arena.alloc(local_defs),
arena.alloc(Loc::at_zero(Expr::EmptyDefsFinal)),
),
Expr::Defs(arena.alloc(def_state), arena.alloc(loc_ret)),
state,
));
)),
_ => Err((
MadeProgress,
EExpr::DefMissingFinalExpr2(arena.alloc(fail), state.pos()),
)),
}
Err((
MadeProgress,
EExpr::DefMissingFinalExpr2(arena.alloc(fail), state.pos()),
))
}
Ok((_, loc_ret, state)) => Ok((
MadeProgress,
@ -2408,8 +2304,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
Expr::SpaceBefore(..)
| Expr::SpaceAfter(..)
| Expr::ParensAround(..)
| Expr::RecordBuilder(..)
| Expr::EmptyDefsFinal => unreachable!(),
| Expr::RecordBuilder(..) => unreachable!(),
Expr::Record(fields) => {
let patterns = fields.map_items_result(arena, |loc_assigned_field| {

View File

@ -732,7 +732,6 @@ impl IterTokens for Loc<Expr<'_>> {
Expr::MalformedIdent(_, _)
| Expr::MalformedClosure
| Expr::PrecedenceConflict(_)
| Expr::EmptyDefsFinal
| Expr::MalformedSuffixed(_) => {
bumpvec![in arena;]
}