mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
code gen Accessor
This commit is contained in:
parent
bb6f36ad28
commit
c8e5acf142
6 changed files with 96 additions and 27 deletions
|
@ -126,6 +126,7 @@ pub enum Expr {
|
||||||
},
|
},
|
||||||
/// field accessor as a function, e.g. (.foo) expr
|
/// field accessor as a function, e.g. (.foo) expr
|
||||||
Accessor {
|
Accessor {
|
||||||
|
function_var: Variable,
|
||||||
record_var: Variable,
|
record_var: Variable,
|
||||||
closure_var: Variable,
|
closure_var: Variable,
|
||||||
ext_var: Variable,
|
ext_var: Variable,
|
||||||
|
@ -550,6 +551,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
}
|
}
|
||||||
ast::Expr::AccessorFunction(field) => (
|
ast::Expr::AccessorFunction(field) => (
|
||||||
Accessor {
|
Accessor {
|
||||||
|
function_var: var_store.fresh(),
|
||||||
record_var: var_store.fresh(),
|
record_var: var_store.fresh(),
|
||||||
ext_var: var_store.fresh(),
|
ext_var: var_store.fresh(),
|
||||||
closure_var: var_store.fresh(),
|
closure_var: var_store.fresh(),
|
||||||
|
|
|
@ -675,6 +675,7 @@ pub fn constrain_expr(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Accessor {
|
Accessor {
|
||||||
|
function_var,
|
||||||
field,
|
field,
|
||||||
record_var,
|
record_var,
|
||||||
closure_var,
|
closure_var,
|
||||||
|
@ -701,16 +702,19 @@ pub fn constrain_expr(
|
||||||
region,
|
region,
|
||||||
);
|
);
|
||||||
|
|
||||||
exists(
|
let function_type = Type::Function(
|
||||||
vec![*record_var, *closure_var, field_var, ext_var],
|
|
||||||
And(vec![
|
|
||||||
Eq(
|
|
||||||
Type::Function(
|
|
||||||
vec![record_type],
|
vec![record_type],
|
||||||
Box::new(Type::Variable(*closure_var)),
|
Box::new(Type::Variable(*closure_var)),
|
||||||
Box::new(field_type),
|
Box::new(field_type),
|
||||||
),
|
);
|
||||||
expected,
|
|
||||||
|
exists(
|
||||||
|
vec![*record_var, *function_var, *closure_var, field_var, ext_var],
|
||||||
|
And(vec![
|
||||||
|
Eq(function_type.clone(), expected, category.clone(), region),
|
||||||
|
Eq(
|
||||||
|
function_type,
|
||||||
|
NoExpectation(Variable(*function_var)),
|
||||||
category,
|
category,
|
||||||
region,
|
region,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1445,6 +1445,7 @@ pub fn constrain_expr(
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessor {
|
Accessor {
|
||||||
|
function_var,
|
||||||
field,
|
field,
|
||||||
record_var,
|
record_var,
|
||||||
closure_var,
|
closure_var,
|
||||||
|
@ -1490,6 +1491,7 @@ pub fn constrain_expr(
|
||||||
exists(
|
exists(
|
||||||
vec![
|
vec![
|
||||||
*record_var,
|
*record_var,
|
||||||
|
*function_var,
|
||||||
*closure_var,
|
*closure_var,
|
||||||
*field_var,
|
*field_var,
|
||||||
*ext_var,
|
*ext_var,
|
||||||
|
@ -1497,7 +1499,16 @@ pub fn constrain_expr(
|
||||||
field_uniq_var,
|
field_uniq_var,
|
||||||
record_uniq_var,
|
record_uniq_var,
|
||||||
],
|
],
|
||||||
And(vec![Eq(fn_type, expected, category, region), record_con]),
|
And(vec![
|
||||||
|
Eq(fn_type.clone(), expected, category.clone(), region),
|
||||||
|
Eq(
|
||||||
|
fn_type,
|
||||||
|
Expected::NoExpectation(Variable(*function_var)),
|
||||||
|
category,
|
||||||
|
region,
|
||||||
|
),
|
||||||
|
record_con,
|
||||||
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
RuntimeError(_) => True,
|
RuntimeError(_) => True,
|
||||||
|
|
|
@ -678,15 +678,15 @@ mod gen_records {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn just_to_be_sure() {
|
fn accessor() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
{ a: 1, b : 2, c : 3 }
|
.foo { foo: 4 } + .foo { bar: 6.28, foo: 3 }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
[1, 2, 3],
|
7,
|
||||||
[i64; 3]
|
i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1959,7 +1959,65 @@ pub fn with_hole<'a>(
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
Accessor { .. } | Update { .. } => todo!("record access/accessor/update"),
|
Accessor {
|
||||||
|
function_var,
|
||||||
|
record_var,
|
||||||
|
closure_var: _,
|
||||||
|
ext_var,
|
||||||
|
field_var,
|
||||||
|
field,
|
||||||
|
} => {
|
||||||
|
// IDEA: convert accessor fromt
|
||||||
|
//
|
||||||
|
// .foo
|
||||||
|
//
|
||||||
|
// into
|
||||||
|
//
|
||||||
|
// (\r -> r.foo)
|
||||||
|
let record_symbol = env.unique_symbol();
|
||||||
|
let body = roc_can::expr::Expr::Access {
|
||||||
|
record_var,
|
||||||
|
ext_var,
|
||||||
|
field_var,
|
||||||
|
loc_expr: Box::new(Located::at_zero(roc_can::expr::Expr::Var(record_symbol))),
|
||||||
|
field: field.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let loc_body = Located::at_zero(body);
|
||||||
|
|
||||||
|
let name = env.unique_symbol();
|
||||||
|
|
||||||
|
let arguments = vec![(
|
||||||
|
record_var,
|
||||||
|
Located::at_zero(roc_can::pattern::Pattern::Identifier(record_symbol)),
|
||||||
|
)];
|
||||||
|
|
||||||
|
match procs.insert_anonymous(
|
||||||
|
env,
|
||||||
|
name,
|
||||||
|
function_var,
|
||||||
|
arguments,
|
||||||
|
loc_body,
|
||||||
|
field_var,
|
||||||
|
layout_cache,
|
||||||
|
) {
|
||||||
|
Ok(layout) => {
|
||||||
|
// TODO should the let have layout Pointer?
|
||||||
|
Stmt::Let(
|
||||||
|
assigned,
|
||||||
|
Expr::FunctionPointer(name, layout.clone()),
|
||||||
|
layout,
|
||||||
|
hole,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(_error) => Stmt::RuntimeError(
|
||||||
|
"TODO convert anonymous function error to a RuntimeError string",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Update { .. } => todo!("record access/accessor/update"),
|
||||||
|
|
||||||
Closure {
|
Closure {
|
||||||
function_type,
|
function_type,
|
||||||
|
|
|
@ -406,15 +406,19 @@ fn layout_from_flat_type<'a>(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_record(subs, ext_var));
|
|
||||||
|
|
||||||
// Sort the fields by label
|
// Sort the fields by label
|
||||||
let mut sorted_fields = Vec::with_capacity_in(fields.len(), arena);
|
let mut sorted_fields = Vec::with_capacity_in(fields.len(), arena);
|
||||||
|
sorted_fields.extend(fields.into_iter());
|
||||||
|
|
||||||
for tuple in fields {
|
// extract any values from the ext_var
|
||||||
sorted_fields.push(tuple);
|
let mut fields_map = MutMap::default();
|
||||||
|
match roc_types::pretty_print::chase_ext_record(subs, ext_var, &mut fields_map) {
|
||||||
|
Ok(()) | Err((_, Content::FlexVar(_))) => {}
|
||||||
|
Err(_) => unreachable!("this would have been a type error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sorted_fields.extend(fields_map.into_iter());
|
||||||
|
|
||||||
sorted_fields.sort_by(|(label1, _), (label2, _)| label1.cmp(label2));
|
sorted_fields.sort_by(|(label1, _), (label2, _)| label1.cmp(label2));
|
||||||
|
|
||||||
// Determine the layouts of the fields, maintaining sort order
|
// Determine the layouts of the fields, maintaining sort order
|
||||||
|
@ -781,16 +785,6 @@ fn ext_var_is_empty_tag_union(_: &Subs, _: Variable) -> bool {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
fn ext_var_is_empty_record(subs: &Subs, ext_var: Variable) -> bool {
|
|
||||||
// the ext_var is empty
|
|
||||||
let mut ext_fields = MutMap::default();
|
|
||||||
match roc_types::pretty_print::chase_ext_record(subs, ext_var, &mut ext_fields) {
|
|
||||||
Ok(()) | Err((_, Content::FlexVar(_))) => ext_fields.is_empty(),
|
|
||||||
Err((_, content)) => panic!("invalid content in ext_var: {:?}", content),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
fn ext_var_is_empty_record(_: &Subs, _: Variable) -> bool {
|
fn ext_var_is_empty_record(_: &Subs, _: Variable) -> bool {
|
||||||
// This should only ever be used in debug_assert! macros
|
// This should only ever be used in debug_assert! macros
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue