mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
implement mono / lowering for tuples
This commit is contained in:
parent
65f8bb3d0d
commit
5a6be05ead
42 changed files with 1773 additions and 290 deletions
|
@ -19,12 +19,13 @@ use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
|||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_parse::ast::{self, Defs, StrLiteral};
|
||||
use roc_parse::ident::Accessor;
|
||||
use roc_parse::pattern::PatternType::*;
|
||||
use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::num::SingleQuoteBound;
|
||||
use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, RedundantMark, VarStore, Variable};
|
||||
use roc_types::types::{Alias, Category, LambdaSet, OptAbleVar, Type};
|
||||
use roc_types::types::{Alias, Category, IndexOrField, LambdaSet, OptAbleVar, Type};
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::{char, u32};
|
||||
|
||||
|
@ -186,8 +187,8 @@ pub enum Expr {
|
|||
field: Lowercase,
|
||||
},
|
||||
|
||||
/// field accessor as a function, e.g. (.foo) expr
|
||||
RecordAccessor(RecordAccessorData),
|
||||
/// tuple or field accessor as a function, e.g. (.foo) expr or (.1) expr
|
||||
RecordAccessor(StructAccessorData),
|
||||
|
||||
TupleAccess {
|
||||
tuple_var: Variable,
|
||||
|
@ -197,9 +198,6 @@ pub enum Expr {
|
|||
index: usize,
|
||||
},
|
||||
|
||||
/// tuple accessor as a function, e.g. (.1) expr
|
||||
TupleAccessor(TupleAccessorData),
|
||||
|
||||
RecordUpdate {
|
||||
record_var: Variable,
|
||||
ext_var: Variable,
|
||||
|
@ -315,9 +313,8 @@ impl Expr {
|
|||
Self::Record { .. } => Category::Record,
|
||||
Self::EmptyRecord => Category::Record,
|
||||
Self::RecordAccess { field, .. } => Category::RecordAccess(field.clone()),
|
||||
Self::RecordAccessor(data) => Category::RecordAccessor(data.field.clone()),
|
||||
Self::RecordAccessor(data) => Category::Accessor(data.field.clone()),
|
||||
Self::TupleAccess { index, .. } => Category::TupleAccess(*index),
|
||||
Self::TupleAccessor(data) => Category::TupleAccessor(data.index),
|
||||
Self::RecordUpdate { .. } => Category::Record,
|
||||
Self::Tag {
|
||||
name, arguments, ..
|
||||
|
@ -383,43 +380,30 @@ pub struct ClosureData {
|
|||
pub loc_body: Box<Loc<Expr>>,
|
||||
}
|
||||
|
||||
/// A tuple accessor like `.2`, which is equivalent to `\x -> x.2`
|
||||
/// TupleAccessors are desugared to closures; they need to have a name
|
||||
/// A record or tuple accessor like `.foo` or `.0`, which is equivalent to `\r -> r.foo`
|
||||
/// Struct accessors are desugared to closures; they need to have a name
|
||||
/// so the closure can have a correct lambda set.
|
||||
///
|
||||
/// We distinguish them from closures so we can have better error messages
|
||||
/// during constraint generation.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct TupleAccessorData {
|
||||
pub name: Symbol,
|
||||
pub function_var: Variable,
|
||||
pub tuple_var: Variable,
|
||||
pub closure_var: Variable,
|
||||
pub ext_var: Variable,
|
||||
pub elem_var: Variable,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
/// A record accessor like `.foo`, which is equivalent to `\r -> r.foo`
|
||||
/// RecordAccessors are desugared to closures; they need to have a name
|
||||
/// so the closure can have a correct lambda set.
|
||||
///
|
||||
/// We distinguish them from closures so we can have better error messages
|
||||
/// during constraint generation.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct RecordAccessorData {
|
||||
pub struct StructAccessorData {
|
||||
pub name: Symbol,
|
||||
pub function_var: Variable,
|
||||
pub record_var: Variable,
|
||||
pub closure_var: Variable,
|
||||
pub ext_var: Variable,
|
||||
pub field_var: Variable,
|
||||
pub field: Lowercase,
|
||||
|
||||
/// Note that the `field` field is an `IndexOrField` in order to represent both
|
||||
/// record and tuple accessors. This is different from `TupleAccess` and
|
||||
/// `RecordAccess` (and RecordFields/TupleElems), which share less of their implementation.
|
||||
pub field: IndexOrField,
|
||||
}
|
||||
|
||||
impl RecordAccessorData {
|
||||
impl StructAccessorData {
|
||||
pub fn to_closure_data(self, record_symbol: Symbol) -> ClosureData {
|
||||
let RecordAccessorData {
|
||||
let StructAccessorData {
|
||||
name,
|
||||
function_var,
|
||||
record_var,
|
||||
|
@ -436,12 +420,21 @@ impl RecordAccessorData {
|
|||
// into
|
||||
//
|
||||
// (\r -> r.foo)
|
||||
let body = Expr::RecordAccess {
|
||||
record_var,
|
||||
ext_var,
|
||||
field_var,
|
||||
loc_expr: Box::new(Loc::at_zero(Expr::Var(record_symbol, record_var))),
|
||||
field,
|
||||
let body = match field {
|
||||
IndexOrField::Index(index) => Expr::TupleAccess {
|
||||
tuple_var: record_var,
|
||||
ext_var,
|
||||
elem_var: field_var,
|
||||
loc_expr: Box::new(Loc::at_zero(Expr::Var(record_symbol, record_var))),
|
||||
index,
|
||||
},
|
||||
IndexOrField::Field(field) => Expr::RecordAccess {
|
||||
record_var,
|
||||
ext_var,
|
||||
field_var,
|
||||
loc_expr: Box::new(Loc::at_zero(Expr::Var(record_symbol, record_var))),
|
||||
field,
|
||||
},
|
||||
};
|
||||
|
||||
let loc_body = Loc::at_zero(body);
|
||||
|
@ -1080,15 +1073,18 @@ pub fn canonicalize_expr<'a>(
|
|||
output,
|
||||
)
|
||||
}
|
||||
ast::Expr::RecordAccessorFunction(field) => (
|
||||
RecordAccessor(RecordAccessorData {
|
||||
ast::Expr::AccessorFunction(field) => (
|
||||
RecordAccessor(StructAccessorData {
|
||||
name: scope.gen_unique_symbol(),
|
||||
function_var: var_store.fresh(),
|
||||
record_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
closure_var: var_store.fresh(),
|
||||
field_var: var_store.fresh(),
|
||||
field: (*field).into(),
|
||||
field: match field {
|
||||
Accessor::RecordField(field) => IndexOrField::Field((*field).into()),
|
||||
Accessor::TupleIndex(index) => IndexOrField::Index(index.parse().unwrap()),
|
||||
},
|
||||
}),
|
||||
Output::default(),
|
||||
),
|
||||
|
@ -1106,18 +1102,6 @@ pub fn canonicalize_expr<'a>(
|
|||
output,
|
||||
)
|
||||
}
|
||||
ast::Expr::TupleAccessorFunction(index) => (
|
||||
TupleAccessor(TupleAccessorData {
|
||||
name: scope.gen_unique_symbol(),
|
||||
function_var: var_store.fresh(),
|
||||
tuple_var: var_store.fresh(),
|
||||
ext_var: var_store.fresh(),
|
||||
closure_var: var_store.fresh(),
|
||||
elem_var: var_store.fresh(),
|
||||
index: index.parse().unwrap(),
|
||||
}),
|
||||
Output::default(),
|
||||
),
|
||||
ast::Expr::Tag(tag) => {
|
||||
let variant_var = var_store.fresh();
|
||||
let ext_var = var_store.fresh();
|
||||
|
@ -1874,7 +1858,6 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
| other @ RuntimeError(_)
|
||||
| other @ EmptyRecord
|
||||
| other @ RecordAccessor { .. }
|
||||
| other @ TupleAccessor { .. }
|
||||
| other @ RecordUpdate { .. }
|
||||
| other @ Var(..)
|
||||
| other @ AbilityMember(..)
|
||||
|
@ -3004,7 +2987,6 @@ pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
|||
| Expr::Str(_)
|
||||
| Expr::ZeroArgumentTag { .. }
|
||||
| Expr::RecordAccessor(_)
|
||||
| Expr::TupleAccessor(_)
|
||||
| Expr::SingleQuote(..)
|
||||
| Expr::EmptyRecord
|
||||
| Expr::TypedHole(_)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue