mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +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
|
@ -448,7 +448,7 @@ pub fn find_type_def_symbols(
|
|||
As(actual, _, _) => {
|
||||
stack.push(&actual.value);
|
||||
}
|
||||
Tuple { fields: _, ext: _ } => {
|
||||
Tuple { elems: _, ext: _ } => {
|
||||
todo!("find_type_def_symbols: Tuple");
|
||||
}
|
||||
Record { fields, ext } => {
|
||||
|
@ -872,8 +872,41 @@ fn can_annotation_help(
|
|||
}
|
||||
}
|
||||
|
||||
Tuple { fields: _, ext: _ } => {
|
||||
todo!("tuple");
|
||||
Tuple { elems, ext } => {
|
||||
let (ext_type, is_implicit_openness) = can_extension_type(
|
||||
env,
|
||||
pol,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
local_aliases,
|
||||
references,
|
||||
ext,
|
||||
roc_problem::can::ExtensionTypeKind::Record,
|
||||
);
|
||||
|
||||
debug_assert!(
|
||||
matches!(is_implicit_openness, ExtImplicitOpenness::No),
|
||||
"tuples should never be implicitly inferred open"
|
||||
);
|
||||
|
||||
debug_assert!(!elems.is_empty()); // We don't allow empty tuples
|
||||
|
||||
let elem_types = can_assigned_tuple_elems(
|
||||
env,
|
||||
pol,
|
||||
&elems.items,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
local_aliases,
|
||||
references,
|
||||
);
|
||||
|
||||
Type::Tuple(
|
||||
elem_types,
|
||||
TypeExtension::from_type(ext_type, is_implicit_openness),
|
||||
)
|
||||
}
|
||||
Record { fields, ext } => {
|
||||
let (ext_type, is_implicit_openness) = can_extension_type(
|
||||
|
@ -1440,6 +1473,39 @@ fn can_assigned_fields<'a>(
|
|||
field_types
|
||||
}
|
||||
|
||||
// TODO trim down these arguments!
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn can_assigned_tuple_elems<'a>(
|
||||
env: &mut Env,
|
||||
pol: CanPolarity,
|
||||
elems: &&[Loc<TypeAnnotation<'a>>],
|
||||
scope: &mut Scope,
|
||||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
local_aliases: &mut VecMap<Symbol, Alias>,
|
||||
references: &mut VecSet<Symbol>,
|
||||
) -> VecMap<usize, Type> {
|
||||
let mut elem_types = VecMap::with_capacity(elems.len());
|
||||
|
||||
for (index, loc_elem) in elems.iter().enumerate() {
|
||||
let elem_type = can_annotation_help(
|
||||
env,
|
||||
pol,
|
||||
&loc_elem.value,
|
||||
loc_elem.region,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
local_aliases,
|
||||
references,
|
||||
);
|
||||
|
||||
elem_types.insert(index, elem_type);
|
||||
}
|
||||
|
||||
elem_types
|
||||
}
|
||||
|
||||
// TODO trim down these arguments!
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn can_tags<'a>(
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::{
|
||||
def::Def,
|
||||
expr::{
|
||||
ClosureData, Expr, Field, OpaqueWrapFunctionData, RecordAccessorData, TupleAccessorData,
|
||||
WhenBranchPattern,
|
||||
ClosureData, Expr, Field, OpaqueWrapFunctionData, StructAccessorData, WhenBranchPattern,
|
||||
},
|
||||
pattern::{DestructType, ListPatterns, Pattern, RecordDestruct},
|
||||
pattern::{DestructType, ListPatterns, Pattern, RecordDestruct, TupleDestruct},
|
||||
};
|
||||
use roc_module::{
|
||||
ident::{Lowercase, TagName},
|
||||
|
@ -513,7 +512,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
field: field.clone(),
|
||||
},
|
||||
|
||||
RecordAccessor(RecordAccessorData {
|
||||
RecordAccessor(StructAccessorData {
|
||||
name,
|
||||
function_var,
|
||||
record_var,
|
||||
|
@ -521,7 +520,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
ext_var,
|
||||
field_var,
|
||||
field,
|
||||
}) => RecordAccessor(RecordAccessorData {
|
||||
}) => RecordAccessor(StructAccessorData {
|
||||
name: *name,
|
||||
function_var: sub!(*function_var),
|
||||
record_var: sub!(*record_var),
|
||||
|
@ -545,24 +544,6 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
index: *index,
|
||||
},
|
||||
|
||||
TupleAccessor(TupleAccessorData {
|
||||
name,
|
||||
function_var,
|
||||
tuple_var: record_var,
|
||||
closure_var,
|
||||
ext_var,
|
||||
elem_var: field_var,
|
||||
index,
|
||||
}) => TupleAccessor(TupleAccessorData {
|
||||
name: *name,
|
||||
function_var: sub!(*function_var),
|
||||
tuple_var: sub!(*record_var),
|
||||
closure_var: sub!(*closure_var),
|
||||
ext_var: sub!(*ext_var),
|
||||
elem_var: sub!(*field_var),
|
||||
index: *index,
|
||||
}),
|
||||
|
||||
RecordUpdate {
|
||||
record_var,
|
||||
ext_var,
|
||||
|
@ -794,6 +775,30 @@ fn deep_copy_pattern_help<C: CopyEnv>(
|
|||
})
|
||||
.collect(),
|
||||
},
|
||||
TupleDestructure {
|
||||
whole_var,
|
||||
ext_var,
|
||||
destructs,
|
||||
} => TupleDestructure {
|
||||
whole_var: sub!(*whole_var),
|
||||
ext_var: sub!(*ext_var),
|
||||
destructs: destructs
|
||||
.iter()
|
||||
.map(|lrd| {
|
||||
lrd.map(
|
||||
|TupleDestruct {
|
||||
destruct_index: index,
|
||||
var,
|
||||
typ: (tyvar, pat),
|
||||
}: &crate::pattern::TupleDestruct| TupleDestruct {
|
||||
destruct_index: *index,
|
||||
var: sub!(*var),
|
||||
typ: (sub!(*tyvar), pat.map(|p| go_help!(p))),
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
List {
|
||||
list_var,
|
||||
elem_var,
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::expr::Expr::{self, *};
|
|||
use crate::expr::{
|
||||
ClosureData, DeclarationTag, Declarations, FunctionDef, OpaqueWrapFunctionData, WhenBranch,
|
||||
};
|
||||
use crate::pattern::{Pattern, RecordDestruct};
|
||||
use crate::pattern::{Pattern, RecordDestruct, TupleDestruct};
|
||||
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
|
||||
|
@ -335,7 +335,6 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
|||
f.text(format!("@{}", opaque_name.as_str(c.interns)))
|
||||
}
|
||||
RecordAccessor(_) => todo!(),
|
||||
TupleAccessor(_) => todo!(),
|
||||
RecordUpdate {
|
||||
symbol, updates, ..
|
||||
} => f
|
||||
|
@ -505,6 +504,19 @@ fn pattern<'a>(
|
|||
)
|
||||
.append(f.text("}"))
|
||||
.group(),
|
||||
TupleDestructure { destructs, .. } => f
|
||||
.text("(")
|
||||
.append(
|
||||
f.intersperse(
|
||||
destructs
|
||||
.iter()
|
||||
.map(|l| &l.value)
|
||||
.map(|TupleDestruct { typ: (_, p), .. }| pattern(c, Free, f, &p.value)),
|
||||
f.text(", "),
|
||||
),
|
||||
)
|
||||
.append(f.text(")"))
|
||||
.group(),
|
||||
List { .. } => todo!(),
|
||||
NumLiteral(_, n, _, _) | IntLiteral(_, _, n, _, _) | FloatLiteral(_, _, n, _, _) => {
|
||||
f.text(&**n)
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::expr::AnnotatedMark;
|
|||
use crate::expr::ClosureData;
|
||||
use crate::expr::Declarations;
|
||||
use crate::expr::Expr::{self, *};
|
||||
use crate::expr::RecordAccessorData;
|
||||
use crate::expr::StructAccessorData;
|
||||
use crate::expr::{canonicalize_expr, Output, Recursive};
|
||||
use crate::pattern::{canonicalize_def_header_pattern, BindingsFromPattern, Pattern};
|
||||
use crate::procedure::References;
|
||||
|
@ -36,6 +36,7 @@ use roc_parse::ast::AssignedField;
|
|||
use roc_parse::ast::Defs;
|
||||
use roc_parse::ast::ExtractSpaces;
|
||||
use roc_parse::ast::TypeHeader;
|
||||
use roc_parse::ident::Accessor;
|
||||
use roc_parse::pattern::PatternType;
|
||||
use roc_problem::can::ShadowKind;
|
||||
use roc_problem::can::{CycleEntry, Problem, RuntimeError};
|
||||
|
@ -45,6 +46,7 @@ use roc_types::subs::{VarStore, Variable};
|
|||
use roc_types::types::AliasCommon;
|
||||
use roc_types::types::AliasKind;
|
||||
use roc_types::types::AliasVar;
|
||||
use roc_types::types::IndexOrField;
|
||||
use roc_types::types::LambdaSet;
|
||||
use roc_types::types::MemberImpl;
|
||||
use roc_types::types::OptAbleType;
|
||||
|
@ -1995,6 +1997,16 @@ fn pattern_to_vars_by_symbol(
|
|||
vars_by_symbol.insert(*opaque, expr_var);
|
||||
}
|
||||
|
||||
TupleDestructure { destructs, .. } => {
|
||||
for destruct in destructs {
|
||||
pattern_to_vars_by_symbol(
|
||||
vars_by_symbol,
|
||||
&destruct.value.typ.1.value,
|
||||
destruct.value.typ.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RecordDestructure { destructs, .. } => {
|
||||
for destruct in destructs {
|
||||
vars_by_symbol.insert(destruct.value.symbol, destruct.value.var);
|
||||
|
@ -2316,19 +2328,23 @@ fn canonicalize_pending_body<'a>(
|
|||
ident: defined_symbol,
|
||||
..
|
||||
},
|
||||
ast::Expr::RecordAccessorFunction(field),
|
||||
ast::Expr::AccessorFunction(field),
|
||||
) => {
|
||||
let field = match field {
|
||||
Accessor::RecordField(field) => IndexOrField::Field((*field).into()),
|
||||
Accessor::TupleIndex(index) => IndexOrField::Index(index.parse().unwrap()),
|
||||
};
|
||||
let (loc_can_expr, can_output) = (
|
||||
Loc::at(
|
||||
loc_expr.region,
|
||||
RecordAccessor(RecordAccessorData {
|
||||
RecordAccessor(StructAccessorData {
|
||||
name: *defined_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,
|
||||
}),
|
||||
),
|
||||
Output::default(),
|
||||
|
|
|
@ -81,6 +81,8 @@ enum IndexCtor<'a> {
|
|||
Opaque,
|
||||
/// Index a record type. The arguments are the types of the record fields.
|
||||
Record(&'a [Lowercase]),
|
||||
/// Index a tuple type.
|
||||
Tuple,
|
||||
/// Index a guard constructor. The arguments are a faux guard pattern, and then the real
|
||||
/// pattern being guarded. E.g. `A B if g` becomes Guard { [True, (A B)] }.
|
||||
Guard,
|
||||
|
@ -113,6 +115,7 @@ impl<'a> IndexCtor<'a> {
|
|||
}
|
||||
RenderAs::Opaque => Self::Opaque,
|
||||
RenderAs::Record(fields) => Self::Record(fields),
|
||||
RenderAs::Tuple => Self::Tuple,
|
||||
RenderAs::Guard => Self::Guard,
|
||||
}
|
||||
}
|
||||
|
@ -366,6 +369,30 @@ fn sketch_pattern(pattern: &crate::pattern::Pattern) -> SketchedPattern {
|
|||
SP::KnownCtor(union, tag_id, patterns)
|
||||
}
|
||||
|
||||
TupleDestructure { destructs, .. } => {
|
||||
let tag_id = TagId(0);
|
||||
let mut patterns = std::vec::Vec::with_capacity(destructs.len());
|
||||
|
||||
for Loc {
|
||||
value: destruct,
|
||||
region: _,
|
||||
} in destructs
|
||||
{
|
||||
patterns.push(sketch_pattern(&destruct.typ.1.value));
|
||||
}
|
||||
|
||||
let union = Union {
|
||||
render_as: RenderAs::Tuple,
|
||||
alternatives: vec![Ctor {
|
||||
name: CtorName::Tag(TagName("#Record".into())),
|
||||
tag_id,
|
||||
arity: destructs.len(),
|
||||
}],
|
||||
};
|
||||
|
||||
SP::KnownCtor(union, tag_id, patterns)
|
||||
}
|
||||
|
||||
List {
|
||||
patterns,
|
||||
list_var: _,
|
||||
|
|
|
@ -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(_)
|
||||
|
|
|
@ -918,6 +918,15 @@ fn fix_values_captured_in_closure_pattern(
|
|||
}
|
||||
}
|
||||
}
|
||||
TupleDestructure { destructs, .. } => {
|
||||
for loc_destruct in destructs.iter_mut() {
|
||||
fix_values_captured_in_closure_pattern(
|
||||
&mut loc_destruct.value.typ.1.value,
|
||||
no_capture_symbols,
|
||||
closure_captures,
|
||||
)
|
||||
}
|
||||
}
|
||||
List { patterns, .. } => {
|
||||
for loc_pat in patterns.patterns.iter_mut() {
|
||||
fix_values_captured_in_closure_pattern(
|
||||
|
@ -1087,8 +1096,7 @@ fn fix_values_captured_in_closure_expr(
|
|||
| TypedHole { .. }
|
||||
| RuntimeError(_)
|
||||
| ZeroArgumentTag { .. }
|
||||
| RecordAccessor { .. }
|
||||
| TupleAccessor { .. } => {}
|
||||
| RecordAccessor { .. } => {}
|
||||
|
||||
List { loc_elems, .. } => {
|
||||
for elem in loc_elems.iter_mut() {
|
||||
|
|
|
@ -130,8 +130,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc<Expr<'a>>) -> &'a Loc
|
|||
| NonBase10Int { .. }
|
||||
| Str(_)
|
||||
| SingleQuote(_)
|
||||
| RecordAccessorFunction(_)
|
||||
| TupleAccessorFunction(_)
|
||||
| AccessorFunction(_)
|
||||
| Var { .. }
|
||||
| Underscore { .. }
|
||||
| MalformedIdent(_, _)
|
||||
|
|
|
@ -58,6 +58,11 @@ pub enum Pattern {
|
|||
ext_var: Variable,
|
||||
destructs: Vec<Loc<RecordDestruct>>,
|
||||
},
|
||||
TupleDestructure {
|
||||
whole_var: Variable,
|
||||
ext_var: Variable,
|
||||
destructs: Vec<Loc<TupleDestruct>>,
|
||||
},
|
||||
List {
|
||||
list_var: Variable,
|
||||
elem_var: Variable,
|
||||
|
@ -100,6 +105,7 @@ impl Pattern {
|
|||
AppliedTag { whole_var, .. } => Some(*whole_var),
|
||||
UnwrappedOpaque { whole_var, .. } => Some(*whole_var),
|
||||
RecordDestructure { whole_var, .. } => Some(*whole_var),
|
||||
TupleDestructure { whole_var, .. } => Some(*whole_var),
|
||||
List {
|
||||
list_var: whole_var,
|
||||
..
|
||||
|
@ -130,7 +136,21 @@ impl Pattern {
|
|||
| UnsupportedPattern(..)
|
||||
| MalformedPattern(..)
|
||||
| AbilityMemberSpecialization { .. } => true,
|
||||
RecordDestructure { destructs, .. } => destructs.is_empty(),
|
||||
|
||||
RecordDestructure { destructs, .. } => {
|
||||
// If all destructs are surely exhaustive, then this is surely exhaustive.
|
||||
destructs.iter().all(|d| match &d.value.typ {
|
||||
DestructType::Required | DestructType::Optional(_, _) => false,
|
||||
DestructType::Guard(_, pat) => pat.value.surely_exhaustive(),
|
||||
})
|
||||
}
|
||||
TupleDestructure { destructs, .. } => {
|
||||
// If all destructs are surely exhaustive, then this is surely exhaustive.
|
||||
destructs
|
||||
.iter()
|
||||
.all(|d| d.value.typ.1.value.surely_exhaustive())
|
||||
}
|
||||
|
||||
As(pattern, _identifier) => pattern.value.surely_exhaustive(),
|
||||
List { patterns, .. } => patterns.surely_exhaustive(),
|
||||
AppliedTag { .. }
|
||||
|
@ -160,6 +180,7 @@ impl Pattern {
|
|||
UnwrappedOpaque { opaque, .. } => C::Opaque(*opaque),
|
||||
RecordDestructure { destructs, .. } if destructs.is_empty() => C::EmptyRecord,
|
||||
RecordDestructure { .. } => C::Record,
|
||||
TupleDestructure { .. } => C::Tuple,
|
||||
List { .. } => C::List,
|
||||
NumLiteral(..) => C::Num,
|
||||
IntLiteral(..) => C::Int,
|
||||
|
@ -215,6 +236,13 @@ pub struct RecordDestruct {
|
|||
pub typ: DestructType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TupleDestruct {
|
||||
pub var: Variable,
|
||||
pub destruct_index: usize,
|
||||
pub typ: (Variable, Loc<Pattern>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum DestructType {
|
||||
Required,
|
||||
|
@ -554,8 +582,38 @@ pub fn canonicalize_pattern<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
Tuple(_patterns) => {
|
||||
todo!("canonicalize_pattern: Tuple")
|
||||
Tuple(patterns) => {
|
||||
let ext_var = var_store.fresh();
|
||||
let whole_var = var_store.fresh();
|
||||
let mut destructs = Vec::with_capacity(patterns.len());
|
||||
|
||||
for (i, loc_pattern) in patterns.iter().enumerate() {
|
||||
let can_guard = canonicalize_pattern(
|
||||
env,
|
||||
var_store,
|
||||
scope,
|
||||
output,
|
||||
pattern_type,
|
||||
&loc_pattern.value,
|
||||
loc_pattern.region,
|
||||
permit_shadows,
|
||||
);
|
||||
|
||||
destructs.push(Loc {
|
||||
region: loc_pattern.region,
|
||||
value: TupleDestruct {
|
||||
destruct_index: i,
|
||||
var: var_store.fresh(),
|
||||
typ: (var_store.fresh(), can_guard),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Pattern::TupleDestructure {
|
||||
whole_var,
|
||||
ext_var,
|
||||
destructs,
|
||||
}
|
||||
}
|
||||
|
||||
RecordDestructure(patterns) => {
|
||||
|
@ -861,7 +919,8 @@ pub enum BindingsFromPattern<'a> {
|
|||
|
||||
pub enum BindingsFromPatternWork<'a> {
|
||||
Pattern(&'a Loc<Pattern>),
|
||||
Destruct(&'a Loc<RecordDestruct>),
|
||||
RecordDestruct(&'a Loc<RecordDestruct>),
|
||||
TupleDestruct(&'a Loc<TupleDestruct>),
|
||||
}
|
||||
|
||||
impl<'a> BindingsFromPattern<'a> {
|
||||
|
@ -911,8 +970,12 @@ impl<'a> BindingsFromPattern<'a> {
|
|||
let (_, loc_arg) = &**argument;
|
||||
stack.push(Pattern(loc_arg));
|
||||
}
|
||||
TupleDestructure { destructs, .. } => {
|
||||
let it = destructs.iter().rev().map(TupleDestruct);
|
||||
stack.extend(it);
|
||||
}
|
||||
RecordDestructure { destructs, .. } => {
|
||||
let it = destructs.iter().rev().map(Destruct);
|
||||
let it = destructs.iter().rev().map(RecordDestruct);
|
||||
stack.extend(it);
|
||||
}
|
||||
NumLiteral(..)
|
||||
|
@ -930,7 +993,7 @@ impl<'a> BindingsFromPattern<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
BindingsFromPatternWork::Destruct(loc_destruct) => {
|
||||
BindingsFromPatternWork::RecordDestruct(loc_destruct) => {
|
||||
match &loc_destruct.value.typ {
|
||||
DestructType::Required | DestructType::Optional(_, _) => {
|
||||
return Some((loc_destruct.value.symbol, loc_destruct.region));
|
||||
|
@ -941,6 +1004,10 @@ impl<'a> BindingsFromPattern<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
BindingsFromPatternWork::TupleDestruct(loc_destruct) => {
|
||||
let inner = &loc_destruct.value.typ.1;
|
||||
stack.push(BindingsFromPatternWork::Pattern(inner))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ use crate::{
|
|||
def::{Annotation, Declaration, Def},
|
||||
expr::{
|
||||
self, AnnotatedMark, ClosureData, Declarations, Expr, Field, OpaqueWrapFunctionData,
|
||||
RecordAccessorData, TupleAccessorData,
|
||||
StructAccessorData,
|
||||
},
|
||||
pattern::{DestructType, Pattern, RecordDestruct},
|
||||
pattern::{DestructType, Pattern, RecordDestruct, TupleDestruct},
|
||||
};
|
||||
|
||||
macro_rules! visit_list {
|
||||
|
@ -242,7 +242,7 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr, var: Variable) {
|
|||
record_var: _,
|
||||
ext_var: _,
|
||||
} => visitor.visit_expr(&loc_expr.value, loc_expr.region, *field_var),
|
||||
Expr::RecordAccessor(RecordAccessorData { .. }) => { /* terminal */ }
|
||||
Expr::RecordAccessor(StructAccessorData { .. }) => { /* terminal */ }
|
||||
Expr::TupleAccess {
|
||||
elem_var,
|
||||
loc_expr,
|
||||
|
@ -250,7 +250,6 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr, var: Variable) {
|
|||
tuple_var: _,
|
||||
ext_var: _,
|
||||
} => visitor.visit_expr(&loc_expr.value, loc_expr.region, *elem_var),
|
||||
Expr::TupleAccessor(TupleAccessorData { .. }) => { /* terminal */ }
|
||||
Expr::OpaqueWrapFunction(OpaqueWrapFunctionData { .. }) => { /* terminal */ }
|
||||
Expr::RecordUpdate {
|
||||
record_var: _,
|
||||
|
@ -483,6 +482,16 @@ pub trait Visitor: Sized {
|
|||
walk_record_destruct(self, destruct);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_tuple_destruct(&mut self, destruct: &TupleDestruct, region: Region) {
|
||||
if self.should_visit(region) {
|
||||
self.visit_pattern(
|
||||
&destruct.typ.1.value,
|
||||
destruct.typ.1.region,
|
||||
Some(destruct.typ.0),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_pattern<V: Visitor>(visitor: &mut V, pattern: &Pattern) {
|
||||
|
@ -503,6 +512,9 @@ pub fn walk_pattern<V: Visitor>(visitor: &mut V, pattern: &Pattern) {
|
|||
RecordDestructure { destructs, .. } => destructs
|
||||
.iter()
|
||||
.for_each(|d| visitor.visit_record_destruct(&d.value, d.region)),
|
||||
TupleDestructure { destructs, .. } => destructs
|
||||
.iter()
|
||||
.for_each(|d| visitor.visit_tuple_destruct(&d.value, d.region)),
|
||||
List {
|
||||
patterns, elem_var, ..
|
||||
} => patterns
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue