mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Prevent record builder field names from shadowing other symbols
This commit is contained in:
parent
232f5fd84c
commit
c43ff03e41
2 changed files with 57 additions and 8 deletions
|
@ -503,11 +503,19 @@ fn record_builder_arg<'a>(
|
|||
RecordBuilderField::Value(label, spaces, expr) => {
|
||||
break AssignedField::RequiredValue(label, spaces, expr)
|
||||
}
|
||||
RecordBuilderField::ApplyValue(label, _spaces, expr) => {
|
||||
RecordBuilderField::ApplyValue(label, spaces, expr) => {
|
||||
apply_field_names.push(label);
|
||||
apply_exprs.push(expr);
|
||||
|
||||
break AssignedField::LabelOnly(label);
|
||||
let var = arena.alloc(Loc {
|
||||
region: label.region,
|
||||
value: Expr::Var {
|
||||
module_name: "",
|
||||
ident: arena.alloc("#".to_owned() + label.value),
|
||||
},
|
||||
});
|
||||
|
||||
break AssignedField::RequiredValue(label, spaces, var);
|
||||
}
|
||||
RecordBuilderField::LabelOnly(label) => break AssignedField::LabelOnly(label),
|
||||
RecordBuilderField::SpaceBefore(sub_field, _) => {
|
||||
|
@ -537,16 +545,17 @@ fn record_builder_arg<'a>(
|
|||
|
||||
// Construct the builder's closure
|
||||
//
|
||||
// { x, y, z: 3 }
|
||||
// \y -> { x, y, z: 3 }
|
||||
// \x -> \y -> { x, y, z: 3 }
|
||||
// { x: #x, y: #y, z: 3 }
|
||||
// \#y -> { x: #x, y: #y, z: 3 }
|
||||
// \#x -> \#y -> { x: #x, y: #y, z: 3 }
|
||||
|
||||
for name in apply_field_names.iter().rev() {
|
||||
let ident = roc_parse::ast::Pattern::Identifier(name.value);
|
||||
for label in apply_field_names.iter().rev() {
|
||||
let name = arena.alloc("#".to_owned() + label.value);
|
||||
let ident = roc_parse::ast::Pattern::Identifier(name);
|
||||
|
||||
let arg_pattern = arena.alloc(Loc {
|
||||
value: ident,
|
||||
region: name.region,
|
||||
region: label.region,
|
||||
});
|
||||
|
||||
body = arena.alloc(Loc {
|
||||
|
|
|
@ -773,6 +773,46 @@ mod test_can {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_builder_field_names_do_not_shadow() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
succeed = \_ -> crash "succeed"
|
||||
parse = \_ -> crash "parse"
|
||||
|
||||
number = "42"
|
||||
|
||||
succeed {
|
||||
number <- parse number,
|
||||
raw: number,
|
||||
}
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems.len(), 0);
|
||||
|
||||
let (_, number_to_succeed) = simplify_curried_call(&out.loc_expr.value);
|
||||
let (_, number_closure) = simplify_curried_call(number_to_succeed);
|
||||
let (apply_number_sym, record) = simplify_builder_closure(number_closure);
|
||||
|
||||
match record {
|
||||
Record { fields, .. } => {
|
||||
assert_eq!(get_field_var_sym(fields, "number"), apply_number_sym);
|
||||
|
||||
match get_field_expr(fields, "raw") {
|
||||
Var(number_sym, _) => {
|
||||
assert_ne!(number_sym.ident_id(), apply_number_sym.ident_id());
|
||||
assert_eq!(number_sym.as_str(&out.interns), "number")
|
||||
}
|
||||
expr => panic!("a is not a Num: {:?}", expr),
|
||||
}
|
||||
}
|
||||
_ => panic!("Closure body wasn't a Record: {:?}", record),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_record_builders_error() {
|
||||
let src = indoc!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue