Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Old Record Builder Syntax #7110

Merged
merged 2 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 4 additions & 134 deletions crates/compiler/can/src/desugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use roc_module::called_via::{BinOp, CalledVia};
use roc_module::ident::ModuleName;
use roc_parse::ast::Expr::{self, *};
use roc_parse::ast::{
AssignedField, Collection, Defs, ModuleImportParams, OldRecordBuilderField, Pattern,
StrLiteral, StrSegment, TypeAnnotation, ValueDef, WhenBranch,
AssignedField, Collection, Defs, ModuleImportParams, Pattern, StrLiteral, StrSegment,
TypeAnnotation, ValueDef, WhenBranch,
};
use roc_problem::can::Problem;
use roc_region::all::{Loc, Region};
Expand Down Expand Up @@ -321,8 +321,6 @@ pub fn desugar_expr<'a>(
| MalformedClosure
| MalformedSuffixed(..)
| PrecedenceConflict { .. }
| MultipleOldRecordBuilders(_)
| UnappliedOldRecordBuilder(_)
| EmptyRecordBuilder(_)
| SingleFieldRecordBuilder(_)
| OptionalFieldInRecordBuilder { .. }
Expand Down Expand Up @@ -555,10 +553,6 @@ pub fn desugar_expr<'a>(
}
}
}
OldRecordBuilder(_) => env.arena.alloc(Loc {
value: UnappliedOldRecordBuilder(loc_expr),
region: loc_expr.region,
}),
RecordBuilder { mapper, fields } => {
// NOTE the `mapper` is always a `Var { .. }`, we only desugar it to get rid of
// any spaces before/after
Expand Down Expand Up @@ -853,25 +847,11 @@ pub fn desugar_expr<'a>(
}
Apply(loc_fn, loc_args, called_via) => {
let mut desugared_args = Vec::with_capacity_in(loc_args.len(), env.arena);
let mut builder_apply_exprs = None;

for loc_arg in loc_args.iter() {
let mut current = loc_arg.value;
let arg = loop {
match current {
OldRecordBuilder(fields) => {
if builder_apply_exprs.is_some() {
return env.arena.alloc(Loc {
value: MultipleOldRecordBuilders(loc_expr),
region: loc_expr.region,
});
}

let builder_arg = old_record_builder_arg(env, loc_arg.region, fields);
builder_apply_exprs = Some(builder_arg.apply_exprs);

break builder_arg.closure;
}
SpaceBefore(expr, _) | SpaceAfter(expr, _) => {
current = *expr;
}
Expand All @@ -884,33 +864,14 @@ pub fn desugar_expr<'a>(

let desugared_args = desugared_args.into_bump_slice();

let mut apply: &Loc<Expr> = env.arena.alloc(Loc {
env.arena.alloc(Loc {
value: Apply(
desugar_expr(env, scope, loc_fn),
desugared_args,
*called_via,
),
region: loc_expr.region,
});

match builder_apply_exprs {
None => {}

Some(apply_exprs) => {
for expr in apply_exprs {
let desugared_expr = desugar_expr(env, scope, expr);

let args = std::slice::from_ref(env.arena.alloc(apply));

apply = env.arena.alloc(Loc {
value: Apply(desugared_expr, args, CalledVia::OldRecordBuilder),
region: loc_expr.region,
});
}
}
}

apply
})
}
When(loc_cond_expr, branches) => {
let loc_desugared_cond = &*env.arena.alloc(desugar_expr(env, scope, loc_cond_expr));
Expand Down Expand Up @@ -1390,97 +1351,6 @@ fn desugar_dbg_stmt<'a>(
))
}

struct OldRecordBuilderArg<'a> {
closure: &'a Loc<Expr<'a>>,
apply_exprs: Vec<'a, &'a Loc<Expr<'a>>>,
}

fn old_record_builder_arg<'a>(
env: &mut Env<'a>,
region: Region,
fields: Collection<'a, Loc<OldRecordBuilderField<'a>>>,
) -> OldRecordBuilderArg<'a> {
let mut record_fields = Vec::with_capacity_in(fields.len(), env.arena);
let mut apply_exprs = Vec::with_capacity_in(fields.len(), env.arena);
let mut apply_field_names = Vec::with_capacity_in(fields.len(), env.arena);

// Build the record that the closure will return and gather apply expressions

for field in fields.iter() {
let mut current = field.value;

let new_field = loop {
match current {
OldRecordBuilderField::Value(label, spaces, expr) => {
break AssignedField::RequiredValue(label, spaces, expr)
}
OldRecordBuilderField::ApplyValue(label, _, _, expr) => {
apply_field_names.push(label);
apply_exprs.push(expr);

let var = env.arena.alloc(Loc {
region: label.region,
value: Expr::Var {
module_name: "",
ident: env.arena.alloc("#".to_owned() + label.value),
},
});

break AssignedField::RequiredValue(label, &[], var);
}
OldRecordBuilderField::LabelOnly(label) => break AssignedField::LabelOnly(label),
OldRecordBuilderField::SpaceBefore(sub_field, _) => {
current = *sub_field;
}
OldRecordBuilderField::SpaceAfter(sub_field, _) => {
current = *sub_field;
}
OldRecordBuilderField::Malformed(malformed) => {
break AssignedField::Malformed(malformed)
}
}
};

record_fields.push(Loc {
value: new_field,
region: field.region,
});
}

let record_fields = fields.replace_items(record_fields.into_bump_slice());

let mut body = env.arena.alloc(Loc {
value: Record(record_fields),
region,
});

// Construct the builder's closure
//
// { x: #x, y: #y, z: 3 }
// \#y -> { x: #x, y: #y, z: 3 }
// \#x -> \#y -> { x: #x, y: #y, z: 3 }

for label in apply_field_names.iter().rev() {
let name = env.arena.alloc("#".to_owned() + label.value);
let ident = roc_parse::ast::Pattern::Identifier { ident: name };

let arg_pattern = env.arena.alloc(Loc {
value: ident,
region: label.region,
});

body = env.arena.alloc(Loc {
value: Closure(std::slice::from_ref(arg_pattern), body),
region,
});
}

OldRecordBuilderArg {
closure: body,
apply_exprs,
}
}

// TODO move this desugaring to canonicalization, so we can use Symbols instead of strings
#[inline(always)]
fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
Expand Down
44 changes: 1 addition & 43 deletions crates/compiler/can/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,11 +1013,8 @@ pub fn canonicalize_expr<'a>(
can_defs_with_return(env, var_store, inner_scope, env.arena.alloc(defs), loc_ret)
})
}
ast::Expr::OldRecordBuilder(_) => {
internal_error!("Old record builder should have been desugared by now")
}
ast::Expr::RecordBuilder { .. } => {
internal_error!("New record builder should have been desugared by now")
internal_error!("Record builder should have been desugared by now")
}
ast::Expr::Backpassing(_, _, _) => {
internal_error!("Backpassing should have been desugared by now")
Expand Down Expand Up @@ -1356,22 +1353,6 @@ pub fn canonicalize_expr<'a>(
use roc_problem::can::RuntimeError::*;
(RuntimeError(MalformedSuffixed(region)), Output::default())
}
ast::Expr::MultipleOldRecordBuilders(sub_expr) => {
use roc_problem::can::RuntimeError::*;

let problem = MultipleOldRecordBuilders(sub_expr.region);
env.problem(Problem::RuntimeError(problem.clone()));

(RuntimeError(problem), Output::default())
}
ast::Expr::UnappliedOldRecordBuilder(sub_expr) => {
use roc_problem::can::RuntimeError::*;

let problem = UnappliedOldRecordBuilder(sub_expr.region);
env.problem(Problem::RuntimeError(problem.clone()));

(RuntimeError(problem), Output::default())
}
ast::Expr::EmptyRecordBuilder(sub_expr) => {
use roc_problem::can::RuntimeError::*;

Expand Down Expand Up @@ -2552,8 +2533,6 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
.iter()
.all(|loc_field| is_valid_interpolation(&loc_field.value)),
ast::Expr::MalformedSuffixed(loc_expr)
| ast::Expr::MultipleOldRecordBuilders(loc_expr)
| ast::Expr::UnappliedOldRecordBuilder(loc_expr)
| ast::Expr::EmptyRecordBuilder(loc_expr)
| ast::Expr::SingleFieldRecordBuilder(loc_expr)
| ast::Expr::OptionalFieldInRecordBuilder(_, loc_expr)
Expand Down Expand Up @@ -2603,27 +2582,6 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::AssignedField::SpaceAfter(_, _) => false,
})
}
ast::Expr::OldRecordBuilder(fields) => {
fields.iter().all(|loc_field| match loc_field.value {
ast::OldRecordBuilderField::Value(_label, comments, loc_expr) => {
comments.is_empty() && is_valid_interpolation(&loc_expr.value)
}
ast::OldRecordBuilderField::ApplyValue(
_label,
comments_before,
comments_after,
loc_expr,
) => {
comments_before.is_empty()
&& comments_after.is_empty()
&& is_valid_interpolation(&loc_expr.value)
}
ast::OldRecordBuilderField::Malformed(_)
| ast::OldRecordBuilderField::LabelOnly(_) => true,
ast::OldRecordBuilderField::SpaceBefore(_, _)
| ast::OldRecordBuilderField::SpaceAfter(_, _) => false,
})
}
ast::Expr::RecordBuilder { mapper, fields } => {
is_valid_interpolation(&mapper.value)
&& fields.iter().all(|loc_field| match loc_field.value {
Expand Down
Loading