Monomorphize optional fields

This commit is contained in:
Richard Feldman 2020-07-18 20:16:36 -04:00
parent 28a2f9656e
commit 2f50c0494b
5 changed files with 86 additions and 40 deletions

View File

@ -162,6 +162,7 @@ pub fn build(
let mut layout_ids = LayoutIds::default();
let mut procs = Procs::default();
let mut mono_problems = std::vec::Vec::new();
let mut layout_cache = LayoutCache::default();
let mut mono_env = Env {
arena,
subs: &mut subs,
@ -191,6 +192,7 @@ pub fn build(
procs.insert_named(
&mut mono_env,
&mut layout_cache,
symbol,
annotation,
loc_args,
@ -235,7 +237,6 @@ pub fn build(
Vec::with_capacity(num_headers)
};
let mut layout_cache = LayoutCache::default();
let mut procs = roc_mono::expr::specialize_all(&mut mono_env, procs, &mut layout_cache);
assert_eq!(

View File

@ -1,8 +1,5 @@
use crate::expr::Env;
use crate::expr::Expr;
use crate::expr::Pattern;
use crate::layout::Builtin;
use crate::layout::Layout;
use crate::expr::{DestructType, Env, Expr, Pattern};
use crate::layout::{Builtin, Layout};
use crate::pattern::{Ctor, RenderAs, TagId, Union};
use bumpalo::Bump;
use roc_collections::all::{MutMap, MutSet};
@ -393,10 +390,16 @@ fn test_at_path<'a>(selected_path: &Path, branch: Branch<'a>, all_tests: &mut Ve
let mut arguments = std::vec::Vec::new();
for destruct in destructs {
if let Some(guard) = &destruct.guard {
arguments.push((guard.clone(), destruct.layout.clone()));
} else {
arguments.push((Pattern::Underscore, destruct.layout.clone()));
match &destruct.typ {
DestructType::Guard(guard) => {
arguments.push((guard.clone(), destruct.layout.clone()));
}
DestructType::Required => {
arguments.push((Pattern::Underscore, destruct.layout.clone()));
}
DestructType::Optional(_expr) => {
todo!("test_at_type for optional destruct");
}
}
}
@ -524,10 +527,12 @@ fn to_relevant_branch_help<'a>(
} => {
debug_assert!(test_name == &TagName::Global("#Record".into()));
let sub_positions = destructs.into_iter().enumerate().map(|(index, destruct)| {
let pattern = if let Some(guard) = destruct.guard {
guard.clone()
} else {
Pattern::Underscore
let pattern = match destruct.typ {
DestructType::Guard(guard) => guard.clone(),
DestructType::Required => Pattern::Underscore,
DestructType::Optional(_expr) => {
todo!("TODO decision tree for optional field branch");
}
};
(

View File

@ -11,7 +11,6 @@ use roc_problem::can::RuntimeError;
use roc_region::all::{Located, Region};
use roc_types::subs::{Content, FlatType, Subs, Variable};
use std::collections::HashMap;
use std::hash::Hash;
#[derive(Clone, Debug, PartialEq)]
pub struct PartialProc<'a> {
@ -56,13 +55,14 @@ impl<'a> Procs<'a> {
pub fn insert_named(
&mut self,
env: &mut Env<'a, '_>,
layout_cache: &mut LayoutCache<'a>,
name: Symbol,
annotation: Variable,
loc_args: std::vec::Vec<(Variable, Located<roc_can::pattern::Pattern>)>,
loc_body: Located<roc_can::expr::Expr>,
ret_var: Variable,
) {
match patterns_to_when(env, loc_args, ret_var, loc_body) {
match patterns_to_when(env, self, layout_cache, loc_args, ret_var, loc_body) {
Ok((_, pattern_symbols, body)) => {
// a named closure. Since these aren't specialized by the surrounding
// context, we can't add pending specializations for them yet.
@ -106,7 +106,7 @@ impl<'a> Procs<'a> {
ret_var: Variable,
layout_cache: &mut LayoutCache<'a>,
) -> Result<Layout<'a>, RuntimeError> {
match patterns_to_when(env, loc_args, ret_var, loc_body) {
match patterns_to_when(env, self, layout_cache, loc_args, ret_var, loc_body) {
Ok((pattern_vars, pattern_symbols, body)) => {
// an anonymous closure. These will always be specialized already
// by the surrounding context, so we can add pending specializations
@ -418,6 +418,8 @@ fn num_argument_to_int_or_float(subs: &Subs, var: Variable) -> IntOrFloat {
#[allow(clippy::type_complexity)]
fn patterns_to_when<'a>(
env: &mut Env<'a, '_>,
procs: &mut Procs<'a>,
layout_cache: &mut LayoutCache<'a>,
patterns: std::vec::Vec<(Variable, Located<roc_can::pattern::Pattern>)>,
body_var: Variable,
body: Located<roc_can::expr::Expr>,
@ -438,7 +440,7 @@ fn patterns_to_when<'a>(
// are only stores anyway, no branches.
for (pattern_var, pattern) in patterns.into_iter() {
let context = crate::pattern::Context::BadArg;
let mono_pattern = from_can_pattern(env, &pattern.value);
let mono_pattern = from_can_pattern(env, procs, layout_cache, &pattern.value);
match crate::pattern::check(
pattern.region,
@ -1023,11 +1025,14 @@ fn store_record_destruct<'a>(
is_unwrapped: true,
};
match &destruct.guard {
None => {
match &destruct.typ {
DestructType::Required => {
stored.push((destruct.symbol, destruct.layout.clone(), load));
}
Some(guard_pattern) => match &guard_pattern {
DestructType::Optional(_expr) => {
todo!("TODO monomorphize optional field destructure's default expr");
}
DestructType::Guard(guard_pattern) => match &guard_pattern {
Identifier(symbol) => {
stored.push((*symbol, destruct.layout.clone(), load));
}
@ -1097,7 +1102,15 @@ fn from_can_defs<'a>(
let (loc_body, ret_var) = *boxed_body;
procs.insert_named(env, *symbol, ann, loc_args, loc_body, ret_var);
procs.insert_named(
env,
layout_cache,
*symbol,
ann,
loc_args,
loc_body,
ret_var,
);
continue;
}
@ -1107,7 +1120,7 @@ fn from_can_defs<'a>(
}
// If it wasn't specifically an Identifier & Closure, proceed as normal.
let mono_pattern = from_can_pattern(env, &loc_pattern.value);
let mono_pattern = from_can_pattern(env, procs, layout_cache, &loc_pattern.value);
let layout = layout_cache
.from_var(env.arena, def.expr_var, env.subs, env.pointer_size)
@ -1195,7 +1208,7 @@ fn from_can_when<'a>(
let loc_when_pattern = &first.patterns[0];
let mono_pattern = from_can_pattern(env, &loc_when_pattern.value);
let mono_pattern = from_can_pattern(env, procs, layout_cache, &loc_when_pattern.value);
// record pattern matches can have 1 branch and typecheck, but may still not be exhaustive
let guard = if first.guard.is_some() {
@ -1259,7 +1272,7 @@ fn from_can_when<'a>(
};
for loc_pattern in when_branch.patterns {
let mono_pattern = from_can_pattern(env, &loc_pattern.value);
let mono_pattern = from_can_pattern(env, procs, layout_cache, &loc_pattern.value);
loc_branches.push((
Located::at(loc_pattern.region, mono_pattern.clone()),
@ -1632,7 +1645,7 @@ fn specialize<'a>(
/// A pattern, including possible problems (e.g. shadowing) so that
/// codegen can generate a runtime error if this pattern is reached.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq)]
pub enum Pattern<'a> {
Identifier(Symbol),
Underscore,
@ -1666,12 +1679,19 @@ pub enum Pattern<'a> {
UnsupportedPattern(Region),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq)]
pub struct RecordDestruct<'a> {
pub label: Lowercase,
pub layout: Layout<'a>,
pub symbol: Symbol,
pub guard: Option<Pattern<'a>>,
pub typ: DestructType<'a>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum DestructType<'a> {
Required,
Optional(Expr<'a>),
Guard(Pattern<'a>),
}
#[derive(Clone, Debug, PartialEq)]
@ -1683,6 +1703,8 @@ pub struct WhenBranch<'a> {
fn from_can_pattern<'a>(
env: &mut Env<'a, '_>,
procs: &mut Procs<'a>,
layout_cache: &mut LayoutCache<'a>,
can_pattern: &roc_can::pattern::Pattern,
) -> Pattern<'a> {
use roc_can::pattern::Pattern::*;
@ -1786,7 +1808,10 @@ fn from_can_pattern<'a>(
let mut mono_args = Vec::with_capacity_in(arguments.len(), env.arena);
for ((_, loc_pat), layout) in arguments.iter().zip(field_layouts.iter()) {
mono_args.push((from_can_pattern(env, &loc_pat.value), layout.clone()));
mono_args.push((
from_can_pattern(env, procs, layout_cache, &loc_pat.value),
layout.clone(),
));
}
let layout = Layout::Struct(field_layouts.into_bump_slice());
@ -1825,7 +1850,10 @@ fn from_can_pattern<'a>(
// disregard the tag discriminant layout
let it = argument_layouts[1..].iter();
for ((_, loc_pat), layout) in arguments.iter().zip(it) {
mono_args.push((from_can_pattern(env, &loc_pat.value), layout.clone()));
mono_args.push((
from_can_pattern(env, procs, layout_cache, &loc_pat.value),
layout.clone(),
));
}
let mut layouts: Vec<&'a [Layout<'a>]> =
@ -1876,6 +1904,8 @@ fn from_can_pattern<'a>(
mono_destructs.push(from_can_record_destruct(
env,
procs,
layout_cache,
&destruct.value,
field_layout.clone(),
));
@ -1885,7 +1915,7 @@ fn from_can_pattern<'a>(
label: label.clone(),
symbol: env.unique_symbol(),
layout: field_layout.clone(),
guard: Some(Pattern::Underscore),
typ: DestructType::Guard(Pattern::Underscore),
});
}
} else {
@ -1894,7 +1924,7 @@ fn from_can_pattern<'a>(
label: label.clone(),
symbol: env.unique_symbol(),
layout: field_layout.clone(),
guard: Some(Pattern::Underscore),
typ: DestructType::Guard(Pattern::Underscore),
});
}
field_layouts.push(field_layout);
@ -1910,6 +1940,8 @@ fn from_can_pattern<'a>(
fn from_can_record_destruct<'a>(
env: &mut Env<'a, '_>,
procs: &mut Procs<'a>,
layout_cache: &mut LayoutCache<'a>,
can_rd: &roc_can::pattern::RecordDestruct,
field_layout: Layout<'a>,
) -> RecordDestruct<'a> {
@ -1917,9 +1949,14 @@ fn from_can_record_destruct<'a>(
label: can_rd.label.clone(),
symbol: can_rd.symbol,
layout: field_layout,
guard: match &can_rd.guard {
None => None,
Some((_, loc_pattern)) => Some(from_can_pattern(env, &loc_pattern.value)),
typ: match &can_rd.typ {
roc_can::pattern::DestructType::Required => DestructType::Required,
roc_can::pattern::DestructType::Optional(_, loc_expr) => {
DestructType::Optional(from_can(env, loc_expr.value.clone(), procs, layout_cache))
}
roc_can::pattern::DestructType::Guard(_, loc_pattern) => DestructType::Guard(
from_can_pattern(env, procs, layout_cache, &loc_pattern.value),
),
},
}
}

View File

@ -313,9 +313,10 @@ fn layout_from_flat_type<'a>(
// Determine the layouts of the fields, maintaining sort order
let mut layouts = Vec::with_capacity_in(sorted_fields.len(), arena);
for (_, field_var) in sorted_fields {
for (_, field) in sorted_fields {
use LayoutProblem::*;
let field_var = field.into_inner();
let field_content = subs.get_without_compacting(field_var).content;
match Layout::new(arena, field_content, subs, pointer_size) {
@ -372,7 +373,8 @@ pub fn sort_record_fields<'a>(
// Sort the fields by label
let mut sorted_fields = Vec::with_capacity_in(fields_map.len(), arena);
for (label, var) in fields_map {
for (label, field) in fields_map {
let var = field.into_inner();
let layout = Layout::from_var(arena, var, subs, pointer_size)
.expect("invalid layout from var");

View File

@ -1,3 +1,4 @@
use crate::expr::DestructType;
use roc_collections::all::{Index, MutMap};
use roc_module::ident::{Lowercase, TagName};
use roc_region::all::{Located, Region};
@ -66,9 +67,9 @@ fn simplify<'a>(pattern: &crate::expr::Pattern<'a>) -> Pattern {
for destruct in destructures {
field_names.push(destruct.label.clone());
match &destruct.guard {
None => patterns.push(Anything),
Some(guard) => patterns.push(simplify(guard)),
match &destruct.typ {
DestructType::Required | DestructType::Optional(_) => patterns.push(Anything),
DestructType::Guard(guard) => patterns.push(simplify(guard)),
}
}