Merge pull request #339 from rtfeldman/mono-module

code gen top-level module declarations
This commit is contained in:
Richard Feldman 2020-05-01 22:24:46 -04:00 committed by GitHub
commit e3ec087657
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 280 additions and 169 deletions

View file

@ -16,7 +16,7 @@ use roc_gen::llvm::build::{
use roc_gen::llvm::convert::basic_type_from_layout; use roc_gen::llvm::convert::basic_type_from_layout;
use roc_load::file::{LoadedModule, LoadingProblem}; use roc_load::file::{LoadedModule, LoadingProblem};
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::expr::{Expr, Procs}; use roc_mono::expr::{Env, Expr, PartialProc, Procs};
use roc_mono::layout::Layout; use roc_mono::layout::Layout;
use std::time::SystemTime; use std::time::SystemTime;
@ -220,6 +220,8 @@ async fn build_file(
Ok(binary_path) Ok(binary_path)
} }
// TODO this should probably use more helper functions
#[allow(clippy::cognitive_complexity)]
fn gen( fn gen(
arena: &Bump, arena: &Bump,
loaded: LoadedModule, loaded: LoadedModule,
@ -275,17 +277,22 @@ fn gen(
} }
} }
let mut decls_by_id = loaded.declarations_by_id;
let home_decls = decls_by_id
.remove(&loaded.module_id)
.expect("Root module ID not found in loaded declarations_by_id");
// We use a loop label here so we can break all the way out of a nested // We use a loop label here so we can break all the way out of a nested
// loop inside DeclareRec if we find the expr there. // loop inside DeclareRec if we find the expr there.
// //
// https://doc.rust-lang.org/1.30.0/book/first-edition/loops.html#loop-labels // https://doc.rust-lang.org/1.30.0/book/first-edition/loops.html#loop-labels
'find_expr: for decl in loaded.declarations { 'find_expr: for decl in home_decls.iter() {
use roc_can::def::Declaration::*; use roc_can::def::Declaration::*;
match decl { match decl {
Declare(def) => { Declare(def) => {
if def.pattern_vars.contains_key(&main_symbol) { if def.pattern_vars.contains_key(&main_symbol) {
main_expr = Some(def.loc_expr); main_expr = Some(def.loc_expr.clone());
break 'find_expr; break 'find_expr;
} }
@ -294,7 +301,7 @@ fn gen(
DeclareRec(defs) => { DeclareRec(defs) => {
for def in defs { for def in defs {
if def.pattern_vars.contains_key(&main_symbol) { if def.pattern_vars.contains_key(&main_symbol) {
main_expr = Some(def.loc_expr); main_expr = Some(def.loc_expr.clone());
break 'find_expr; break 'find_expr;
} }
@ -347,20 +354,74 @@ fn gen(
ptr_bytes, ptr_bytes,
}; };
let mut procs = Procs::default(); let mut procs = Procs::default();
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
// Populate Procs and get the low-level Expr from the canonical Expr
let mut mono_problems = std::vec::Vec::new(); let mut mono_problems = std::vec::Vec::new();
let main_body = Expr::new( let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
&arena, let mut mono_env = Env {
&mut subs, arena,
&mut mono_problems, subs: &mut subs,
loc_expr.value, problems: &mut mono_problems,
&mut procs,
home, home,
&mut ident_ids, ident_ids: &mut ident_ids,
ptr_bytes, pointer_size: ptr_bytes,
symbol_counter: 0,
jump_counter: arena.alloc(0),
};
// Add modules' decls to Procs
for (_, mut decls) in decls_by_id
.drain()
.chain(std::iter::once((loaded.module_id, home_decls)))
{
for decl in decls.drain(..) {
use roc_can::def::Declaration::*;
use roc_can::expr::Expr::*;
use roc_can::pattern::Pattern::*;
match decl {
Declare(def) => match def.loc_pattern.value {
Identifier(symbol) => {
match def.loc_expr.value {
Closure(annotation, _, _, loc_args, boxed_body) => {
let (loc_body, ret_var) = *boxed_body;
procs.insert_closure(
&mut mono_env,
Some(symbol),
annotation,
loc_args,
loc_body,
ret_var,
); );
}
body => {
let proc = PartialProc {
annotation: def.expr_var,
// This is a 0-arity thunk, so it has no arguments.
patterns: bumpalo::collections::Vec::new_in(arena),
body,
};
procs.user_defined.insert(symbol, proc);
procs.module_thunks.insert(symbol);
}
};
}
other => {
todo!("TODO gracefully handle Declare({:?})", other);
}
},
DeclareRec(_defs) => {
todo!("TODO support DeclareRec");
}
InvalidCycle(_loc_idents, _regions) => {
todo!("TODO handle InvalidCycle");
}
}
}
}
// Populate Procs further and get the low-level Expr from the canonical Expr
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
// Put this module's ident_ids back in the interns, so we can use them in env. // Put this module's ident_ids back in the interns, so we can use them in env.
env.interns.all_ident_ids.insert(home, ident_ids); env.interns.all_ident_ids.insert(home, ident_ids);

View file

@ -246,16 +246,17 @@ pub fn gen(src: &str, target: Triple, opt_level: OptLevel) -> Result<(String, St
// Populate Procs and get the low-level Expr from the canonical Expr // Populate Procs and get the low-level Expr from the canonical Expr
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
let main_body = roc_mono::expr::Expr::new( let mut mono_env = roc_mono::expr::Env {
&arena, arena: &arena,
&mut subs, subs: &mut subs,
&mut mono_problems, problems: &mut mono_problems,
loc_expr.value,
&mut procs,
home, home,
&mut ident_ids, ident_ids: &mut ident_ids,
ptr_bytes, pointer_size: ptr_bytes,
); symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let main_body = roc_mono::expr::Expr::new(&mut mono_env, loc_expr.value, &mut procs);
// Put this module's ident_ids back in the interns, so we can use them in Env. // Put this module's ident_ids back in the interns, so we can use them in Env.
env.interns.all_ident_ids.insert(home, ident_ids); env.interns.all_ident_ids.insert(home, ident_ids);

View file

@ -35,8 +35,7 @@ pub fn standard_stdlib() -> StdLib {
} }
} }
/// Keep this up to date by hand! /// Keep this up to date by hand! It's the number of builtin aliases that are imported by default.
///
const NUM_BUILTIN_IMPORTS: usize = 7; const NUM_BUILTIN_IMPORTS: usize = 7;
/// These can be shared between definitions, they will get instantiated when converted to Type /// These can be shared between definitions, they will get instantiated when converted to Type

View file

@ -3,8 +3,8 @@ use crate::expr::Expr;
use crate::expr::Recursive; use crate::expr::Recursive;
use roc_collections::all::SendMap; use roc_collections::all::SendMap;
use roc_module::ident::TagName; use roc_module::ident::TagName;
use roc_module::operator::CalledVia;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_parse::operator::CalledVia;
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
use roc_types::subs::{VarStore, Variable}; use roc_types::subs::{VarStore, Variable};

View file

@ -10,9 +10,9 @@ use crate::procedure::References;
use crate::scope::Scope; use crate::scope::Scope;
use roc_collections::all::{ImSet, MutMap, MutSet, SendMap}; use roc_collections::all::{ImSet, MutMap, MutSet, SendMap};
use roc_module::ident::{Lowercase, TagName}; use roc_module::ident::{Lowercase, TagName};
use roc_module::operator::CalledVia;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_parse::ast; use roc_parse::ast;
use roc_parse::operator::CalledVia;
use roc_parse::pattern::PatternType::*; use roc_parse::pattern::PatternType::*;
use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError}; use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};

View file

@ -1,10 +1,10 @@
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_module::ident::ModuleName; use roc_module::ident::ModuleName;
use roc_module::operator::BinOp::Pizza;
use roc_module::operator::{BinOp, CalledVia};
use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::Expr::{self, *};
use roc_parse::ast::{AssignedField, Def, Pattern, WhenBranch}; use roc_parse::ast::{AssignedField, Def, Pattern, WhenBranch};
use roc_parse::operator::BinOp::Pizza;
use roc_parse::operator::{BinOp, CalledVia};
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
// BinOp precedence logic adapted from Gluon by Markus Westerlind, MIT licensed // BinOp precedence logic adapted from Gluon by Markus Westerlind, MIT licensed
@ -201,7 +201,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
}) })
} }
UnaryOp(loc_arg, loc_op) | Nested(UnaryOp(loc_arg, loc_op)) => { UnaryOp(loc_arg, loc_op) | Nested(UnaryOp(loc_arg, loc_op)) => {
use roc_parse::operator::UnaryOp::*; use roc_module::operator::UnaryOp::*;
let region = loc_op.region; let region = loc_op.region;
let op = loc_op.value; let op = loc_op.value;
@ -327,7 +327,7 @@ fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
} }
fn desugar_bin_op<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'_>>) -> &'a Located<Expr<'a>> { fn desugar_bin_op<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'_>>) -> &'a Located<Expr<'a>> {
use roc_parse::operator::Associativity::*; use roc_module::operator::Associativity::*;
use std::cmp::Ordering; use std::cmp::Ordering;
let mut infixes = Infixes::new(loc_expr); let mut infixes = Infixes::new(loc_expr);

View file

@ -4,9 +4,8 @@ use crate::spaces::{
add_spaces, fmt_comments_only, fmt_condition_spaces, fmt_spaces, is_comment, newline, INDENT, add_spaces, fmt_comments_only, fmt_condition_spaces, fmt_spaces, is_comment, newline, INDENT,
}; };
use bumpalo::collections::{String, Vec}; use bumpalo::collections::{String, Vec};
use roc_module::operator::{self, BinOp};
use roc_parse::ast::{AssignedField, Base, CommentOrNewline, Expr, Pattern, WhenBranch}; use roc_parse::ast::{AssignedField, Base, CommentOrNewline, Expr, Pattern, WhenBranch};
use roc_parse::operator;
use roc_parse::operator::BinOp;
use roc_region::all::Located; use roc_region::all::Located;
pub fn fmt_expr<'a>( pub fn fmt_expr<'a>(

View file

@ -63,7 +63,17 @@ macro_rules! assert_llvm_evals_to {
// Populate Procs and get the low-level Expr from the canonical Expr // Populate Procs and get the low-level Expr from the canonical Expr
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
let main_body = Expr::new(&arena, &mut subs, &mut mono_problems, loc_expr.value, &mut procs, home, &mut ident_ids, ptr_bytes); let mut mono_env = roc_mono::expr::Env {
arena: &arena,
subs: &mut subs,
problems: &mut mono_problems,
home,
ident_ids: &mut ident_ids,
pointer_size: ptr_bytes,
symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
// Put this module's ident_ids back in the interns, so we can use them in Env. // Put this module's ident_ids back in the interns, so we can use them in Env.
env.interns.all_ident_ids.insert(home, ident_ids); env.interns.all_ident_ids.insert(home, ident_ids);
@ -215,7 +225,17 @@ macro_rules! assert_opt_evals_to {
// Populate Procs and get the low-level Expr from the canonical Expr // Populate Procs and get the low-level Expr from the canonical Expr
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
let main_body = Expr::new(&arena, &mut subs, &mut mono_problems, loc_expr.value, &mut procs, home, &mut ident_ids, ptr_bytes); let mut mono_env = roc_mono::expr::Env {
arena: &arena,
subs: &mut subs,
problems: &mut mono_problems,
home,
ident_ids: &mut ident_ids,
pointer_size: ptr_bytes,
symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
// Put this module's ident_ids back in the interns, so we can use them in Env. // Put this module's ident_ids back in the interns, so we can use them in Env.
env.interns.all_ident_ids.insert(home, ident_ids); env.interns.all_ident_ids.insert(home, ident_ids);
@ -361,7 +381,17 @@ macro_rules! emit_expr {
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap(); let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
// Populate Procs and get the low-level Expr from the canonical Expr // Populate Procs and get the low-level Expr from the canonical Expr
let main_body = Expr::new(&arena, &mut subs, loc_expr.value, &mut procs, home, &mut ident_ids, $crate::helpers::eval::POINTER_SIZE); let mut mono_env = roc_mono::expr::Env {
arena: &arena,
subs: &mut subs,
problems: &mut mono_problems,
home,
ident_ids: &mut ident_ids,
pointer_size: ptr_bytes,
symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
// Put this module's ident_ids back in the interns, so we can use them in Env. // Put this module's ident_ids back in the interns, so we can use them in Env.
env.interns.all_ident_ids.insert(home, ident_ids); env.interns.all_ident_ids.insert(home, ident_ids);

View file

@ -282,7 +282,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
}) })
.collect(); .collect();
//load builtin values // load builtin values
let (_introduced_rigids, constraint) = let (_introduced_rigids, constraint) =
constrain_imported_values(imports, constraint, &var_store); constrain_imported_values(imports, constraint, &var_store);

View file

@ -53,7 +53,7 @@ pub struct LoadedModule {
pub solved: Solved<Subs>, pub solved: Solved<Subs>,
pub can_problems: Vec<roc_problem::can::Problem>, pub can_problems: Vec<roc_problem::can::Problem>,
pub type_problems: Vec<solve::TypeError>, pub type_problems: Vec<solve::TypeError>,
pub declarations: Vec<Declaration>, pub declarations_by_id: MutMap<ModuleId, Vec<Declaration>>,
pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>, pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
pub src: Box<str>, pub src: Box<str>,
} }
@ -417,10 +417,6 @@ pub async fn load<'a>(
.into_inner() .into_inner()
.expect("Unwrapping mutex for module_ids"); .expect("Unwrapping mutex for module_ids");
let declarations = declarations_by_id
.remove(&module_id)
.expect("declarations_by_id was missing root module_id entry");
let interns = Interns { let interns = Interns {
module_ids, module_ids,
all_ident_ids: constrained_ident_ids, all_ident_ids: constrained_ident_ids,
@ -432,7 +428,7 @@ pub async fn load<'a>(
solved, solved,
can_problems, can_problems,
type_problems, type_problems,
declarations, declarations_by_id,
exposed_vars_by_symbol, exposed_vars_by_symbol,
src, src,
}); });

View file

@ -81,16 +81,18 @@ mod test_load {
} }
} }
fn expect_types(loaded_module: LoadedModule, expected_types: HashMap<&str, &str>) { fn expect_types(mut loaded_module: LoadedModule, expected_types: HashMap<&str, &str>) {
let home = loaded_module.module_id; let home = loaded_module.module_id;
let mut subs = loaded_module.solved.into_inner(); let mut subs = loaded_module.solved.into_inner();
assert_eq!(loaded_module.can_problems, Vec::new()); assert_eq!(loaded_module.can_problems, Vec::new());
assert_eq!(loaded_module.type_problems, Vec::new()); assert_eq!(loaded_module.type_problems, Vec::new());
let num_decls = loaded_module.declarations.len(); let mut num_decls = 0;
for decl in loaded_module.declarations_by_id.remove(&home).unwrap() {
num_decls += 1;
for decl in loaded_module.declarations {
match decl { match decl {
Declare(def) => expect_def( Declare(def) => expect_def(
&loaded_module.interns, &loaded_module.interns,
@ -135,14 +137,17 @@ mod test_load {
subs_by_module, subs_by_module,
) )
.await; .await;
let loaded_module = loaded.expect("Test module failed to load");
let mut loaded_module = loaded.expect("Test module failed to load");
assert_eq!(loaded_module.can_problems, Vec::new()); assert_eq!(loaded_module.can_problems, Vec::new());
assert_eq!(loaded_module.type_problems, Vec::new()); assert_eq!(loaded_module.type_problems, Vec::new());
let def_count: usize = loaded_module let def_count: usize = loaded_module
.declarations .declarations_by_id
.iter() .remove(&loaded_module.module_id)
.unwrap()
.into_iter()
.map(|decl| decl.def_count()) .map(|decl| decl.def_count())
.sum(); .sum();

View file

@ -76,16 +76,18 @@ mod test_uniq_load {
} }
} }
fn expect_types(loaded_module: LoadedModule, expected_types: HashMap<&str, &str>) { fn expect_types(mut loaded_module: LoadedModule, expected_types: HashMap<&str, &str>) {
let home = loaded_module.module_id; let home = loaded_module.module_id;
let mut subs = loaded_module.solved.into_inner(); let mut subs = loaded_module.solved.into_inner();
assert_eq!(loaded_module.can_problems, Vec::new()); assert_eq!(loaded_module.can_problems, Vec::new());
assert_eq!(loaded_module.type_problems, Vec::new()); assert_eq!(loaded_module.type_problems, Vec::new());
let num_decls = loaded_module.declarations.len(); let mut num_decls = 0;
for decl in loaded_module.declarations_by_id.remove(&home).unwrap() {
num_decls += 1;
for decl in loaded_module.declarations {
match decl { match decl {
Declare(def) => expect_def( Declare(def) => expect_def(
&loaded_module.interns, &loaded_module.interns,
@ -130,14 +132,17 @@ mod test_uniq_load {
subs_by_module, subs_by_module,
) )
.await; .await;
let loaded_module = loaded.expect("Test module failed to load");
let mut loaded_module = loaded.expect("Test module failed to load");
assert_eq!(loaded_module.can_problems, Vec::new()); assert_eq!(loaded_module.can_problems, Vec::new());
assert_eq!(loaded_module.type_problems, Vec::new()); assert_eq!(loaded_module.type_problems, Vec::new());
let def_count: usize = loaded_module let def_count: usize = loaded_module
.declarations .declarations_by_id
.iter() .remove(&loaded_module.module_id)
.unwrap()
.into_iter()
.map(|decl| decl.def_count()) .map(|decl| decl.def_count())
.sum(); .sum();

View file

@ -12,6 +12,7 @@
#![allow(clippy::large_enum_variant)] #![allow(clippy::large_enum_variant)]
pub mod ident; pub mod ident;
pub mod operator;
pub mod symbol; pub mod symbol;
#[macro_use] #[macro_use]

View file

@ -27,7 +27,8 @@ pub struct Proc<'a> {
#[derive(Clone, Debug, PartialEq, Default)] #[derive(Clone, Debug, PartialEq, Default)]
pub struct Procs<'a> { pub struct Procs<'a> {
user_defined: MutMap<Symbol, PartialProc<'a>>, pub user_defined: MutMap<Symbol, PartialProc<'a>>,
pub module_thunks: MutSet<Symbol>,
anonymous: MutMap<Symbol, Option<Proc<'a>>>, anonymous: MutMap<Symbol, Option<Proc<'a>>>,
specializations: MutMap<ContentHash, (Symbol, Option<Proc<'a>>)>, specializations: MutMap<ContentHash, (Symbol, Option<Proc<'a>>)>,
builtin: MutSet<Symbol>, builtin: MutSet<Symbol>,
@ -42,6 +43,66 @@ impl<'a> Procs<'a> {
self.anonymous.insert(symbol, proc); self.anonymous.insert(symbol, proc);
} }
pub fn insert_closure(
&mut self,
env: &mut Env<'a, '_>,
name: Option<Symbol>,
annotation: Variable,
loc_args: std::vec::Vec<(Variable, Located<roc_can::pattern::Pattern>)>,
loc_body: Located<roc_can::expr::Expr>,
ret_var: Variable,
) -> Symbol {
// turn record/tag patterns into a when expression, e.g.
//
// foo = \{ x } -> body
//
// becomes
//
// foo = \r -> when r is { x } -> body
//
// conversion of one-pattern when expressions will do the most optimal thing
let (arg_vars, arg_symbols, body) = patterns_to_when(env, loc_args, ret_var, loc_body);
match name {
Some(symbol) => {
// a named closure
self.insert_user_defined(
symbol,
PartialProc {
annotation,
patterns: arg_symbols,
body: body.value,
},
);
symbol
}
None => {
// an anonymous closure. These will always be specialized already
// by the surrounding context
let symbol = env.fresh_symbol();
let opt_proc = specialize_proc_body(
env,
self,
annotation,
ret_var,
symbol,
&arg_vars,
&arg_symbols,
annotation,
body.value,
)
.ok();
self.insert_anonymous(symbol, opt_proc);
symbol
}
}
}
fn insert_specialization( fn insert_specialization(
&mut self, &mut self,
hash: ContentHash, hash: ContentHash,
@ -96,8 +157,8 @@ pub struct Env<'a, 'i> {
pub home: ModuleId, pub home: ModuleId,
pub ident_ids: &'i mut IdentIds, pub ident_ids: &'i mut IdentIds,
pub pointer_size: u32, pub pointer_size: u32,
symbol_counter: usize,
pub jump_counter: &'a mut u64, pub jump_counter: &'a mut u64,
pub symbol_counter: usize,
} }
impl<'a, 'i> Env<'a, 'i> { impl<'a, 'i> Env<'a, 'i> {
@ -203,27 +264,11 @@ pub enum MonoProblem {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
impl<'a> Expr<'a> { impl<'a> Expr<'a> {
pub fn new( pub fn new(
arena: &'a Bump, env: &mut Env<'a, '_>,
subs: &'a mut Subs,
problems: &mut std::vec::Vec<MonoProblem>,
can_expr: roc_can::expr::Expr, can_expr: roc_can::expr::Expr,
procs: &mut Procs<'a>, procs: &mut Procs<'a>,
home: ModuleId,
ident_ids: &mut IdentIds,
pointer_size: u32,
) -> Self { ) -> Self {
let mut env = Env { from_can(env, can_expr, procs, None)
arena,
subs,
problems,
home,
ident_ids,
pointer_size,
symbol_counter: 0,
jump_counter: arena.alloc(0),
};
from_can(&mut env, can_expr, procs, None)
} }
} }
@ -426,61 +471,24 @@ fn from_can<'a>(
Int(_, num) => Expr::Int(num), Int(_, num) => Expr::Int(num),
Float(_, num) => Expr::Float(num), Float(_, num) => Expr::Float(num),
Str(string) | BlockStr(string) => Expr::Str(env.arena.alloc(string)), Str(string) | BlockStr(string) => Expr::Str(env.arena.alloc(string)),
Var(symbol) => Expr::Load(symbol), Var(symbol) => {
if procs.module_thunks.contains(&symbol) {
let partial_proc = procs.get_user_defined(symbol).unwrap();
let fn_var = partial_proc.annotation;
let ret_var = partial_proc.annotation;
// This is a top-level declaration, which will code gen to a 0-arity thunk.
call_by_name(env, procs, fn_var, ret_var, symbol, std::vec::Vec::new())
} else {
Expr::Load(symbol)
}
}
LetRec(defs, ret_expr, _, _) => from_can_defs(env, defs, *ret_expr, procs), LetRec(defs, ret_expr, _, _) => from_can_defs(env, defs, *ret_expr, procs),
LetNonRec(def, ret_expr, _, _) => from_can_defs(env, vec![*def], *ret_expr, procs), LetNonRec(def, ret_expr, _, _) => from_can_defs(env, vec![*def], *ret_expr, procs),
Closure(annotation, _, _, loc_args, boxed_body) => { Closure(annotation, _, _, loc_args, boxed_body) => {
let (loc_body, ret_var) = *boxed_body; let (loc_body, ret_var) = *boxed_body;
let symbol = procs.insert_closure(env, name, annotation, loc_args, loc_body, ret_var);
// turn record/tag patterns into a when expression, e.g.
//
// foo = \{ x } -> body
//
// becomes
//
// foo = \r -> when r is { x } -> body
//
// conversion of one-pattern when expressions will do the most optimal thing
let (arg_vars, arg_symbols, body) = patterns_to_when(env, loc_args, ret_var, loc_body);
let symbol = match name {
Some(symbol) => {
// a named closure
procs.insert_user_defined(
symbol,
PartialProc {
annotation,
patterns: arg_symbols,
body: body.value,
},
);
symbol
}
None => {
// an anonymous closure. These will always be specialized already
// by the surrounding context
let symbol = env.fresh_symbol();
let opt_proc = specialize_proc_body(
env,
procs,
annotation,
ret_var,
symbol,
&arg_vars,
&arg_symbols,
annotation,
body.value,
)
.ok();
procs.insert_anonymous(symbol, opt_proc);
symbol
}
};
Expr::FunctionPointer(symbol) Expr::FunctionPointer(symbol)
} }

View file

@ -53,16 +53,17 @@ mod test_mono {
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr // Populate Procs and Subs, and get the low-level Expr from the canonical Expr
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
let mono_expr = Expr::new( let mut mono_env = roc_mono::expr::Env {
&arena, arena: &arena,
&mut subs, subs: &mut subs,
&mut mono_problems, problems: &mut mono_problems,
loc_expr.value,
&mut procs,
home, home,
&mut ident_ids, ident_ids: &mut ident_ids,
pointer_size, pointer_size,
); symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let mono_expr = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
// Put this module's ident_ids back in the interns // Put this module's ident_ids back in the interns
interns.all_ident_ids.insert(home, ident_ids); interns.all_ident_ids.insert(home, ident_ids);

View file

@ -42,16 +42,17 @@ mod test_opt {
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr // Populate Procs and Subs, and get the low-level Expr from the canonical Expr
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
let mono_expr = Expr::new( let mut mono_env = roc_mono::expr::Env {
&arena, arena: &arena,
&mut subs, subs: &mut subs,
&mut mono_problems, problems: &mut mono_problems,
loc_expr.value,
&mut procs,
home, home,
&mut ident_ids, ident_ids: &mut ident_ids,
pointer_size, pointer_size,
); symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let mono_expr = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
let unexpected_calls = extract_named_calls(&mono_expr, &mut calls); let unexpected_calls = extract_named_calls(&mono_expr, &mut calls);
let expected = CallProblems::default(); let expected = CallProblems::default();
@ -193,16 +194,17 @@ mod test_opt {
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr // Populate Procs and Subs, and get the low-level Expr from the canonical Expr
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
let mono_expr = Expr::new( let mut mono_env = roc_mono::expr::Env {
&arena, arena: &arena,
&mut subs, subs: &mut subs,
&mut mono_problems, problems: &mut mono_problems,
loc_expr.value,
&mut procs,
home, home,
&mut ident_ids, ident_ids: &mut ident_ids,
pointer_size, pointer_size,
); symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let mono_expr = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
assert_eq!(mono_expr, expected); assert_eq!(mono_expr, expected);
} }

View file

@ -1,10 +1,9 @@
use crate::header::ModuleName; use crate::header::ModuleName;
use crate::ident::Ident; use crate::ident::Ident;
use crate::operator::CalledVia;
use crate::operator::{BinOp, UnaryOp};
use bumpalo::collections::String; use bumpalo::collections::String;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]

View file

@ -7,7 +7,6 @@ use crate::blankspace::{
use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident}; use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
use crate::keyword; use crate::keyword;
use crate::number_literal::number_literal; use crate::number_literal::number_literal;
use crate::operator::{BinOp, CalledVia, UnaryOp};
use crate::parser::{ use crate::parser::{
self, allocated, char, fail, not, not_followed_by, optional, sep_by1, string, then, unexpected, self, allocated, char, fail, not, not_followed_by, optional, sep_by1, string, then, unexpected,
unexpected_eof, Either, Fail, FailReason, ParseResult, Parser, State, unexpected_eof, Either, Fail, FailReason, ParseResult, Parser, State,
@ -16,6 +15,7 @@ use crate::type_annotation;
use bumpalo::collections::string::String; use bumpalo::collections::string::String;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_module::operator::{BinOp, CalledVia, UnaryOp};
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
pub fn expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> { pub fn expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {

View file

@ -21,7 +21,6 @@ pub mod ident;
pub mod keyword; pub mod keyword;
pub mod module; pub mod module;
pub mod number_literal; pub mod number_literal;
pub mod operator;
pub mod pattern; pub mod pattern;
pub mod problems; pub mod problems;
pub mod string_literal; pub mod string_literal;

View file

@ -18,6 +18,8 @@ mod test_parse {
use crate::helpers::parse_with; use crate::helpers::parse_with;
use bumpalo::collections::vec::Vec; use bumpalo::collections::vec::Vec;
use bumpalo::{self, Bump}; use bumpalo::{self, Bump};
use roc_module::operator::BinOp::*;
use roc_module::operator::{CalledVia, UnaryOp};
use roc_parse::ast::AssignedField::*; use roc_parse::ast::AssignedField::*;
use roc_parse::ast::CommentOrNewline::*; use roc_parse::ast::CommentOrNewline::*;
use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::Expr::{self, *};
@ -27,9 +29,6 @@ mod test_parse {
}; };
use roc_parse::header::ModuleName; use roc_parse::header::ModuleName;
use roc_parse::module::{interface_header, module_defs}; use roc_parse::module::{interface_header, module_defs};
use roc_parse::operator::BinOp::*;
use roc_parse::operator::CalledVia;
use roc_parse::operator::UnaryOp;
use roc_parse::parser::{Fail, FailReason, Parser, State}; use roc_parse::parser::{Fail, FailReason, Parser, State};
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
use std::{f64, i64}; use std::{f64, i64};

View file

@ -1,8 +1,8 @@
use inlinable_string::InlinableString; use inlinable_string::InlinableString;
use roc_collections::all::MutSet; use roc_collections::all::MutSet;
use roc_module::ident::{Ident, Lowercase, TagName}; use roc_module::ident::{Ident, Lowercase, TagName};
use roc_module::operator::BinOp;
use roc_module::symbol::{ModuleId, Symbol}; use roc_module::symbol::{ModuleId, Symbol};
use roc_parse::operator::BinOp;
use roc_parse::pattern::PatternType; use roc_parse::pattern::PatternType;
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};

View file

@ -299,7 +299,7 @@ impl<'a> RocDocAllocator<'a> {
pub fn binop( pub fn binop(
&'a self, &'a self,
content: roc_parse::operator::BinOp, content: roc_module::operator::BinOp,
) -> DocBuilder<'a, Self, Annotation> { ) -> DocBuilder<'a, Self, Annotation> {
self.text(content.to_string()).annotate(Annotation::BinOp) self.text(content.to_string()).annotate(Annotation::BinOp)
} }

View file

@ -90,16 +90,17 @@ mod test_reporting {
let pointer_size = std::mem::size_of::<u64>() as u32; let pointer_size = std::mem::size_of::<u64>() as u32;
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr // Populate Procs and Subs, and get the low-level Expr from the canonical Expr
let _mono_expr = Expr::new( let mut mono_env = roc_mono::expr::Env {
&arena, arena: &arena,
&mut subs, subs: &mut subs,
&mut mono_problems, problems: &mut mono_problems,
loc_expr.value,
&mut procs,
home, home,
&mut ident_ids, ident_ids: &mut ident_ids,
pointer_size, pointer_size,
); symbol_counter: 0,
jump_counter: arena.alloc(0),
};
let _mono_expr = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
} }
Ok((unify_problems, can_problems, mono_problems, home, interns)) Ok((unify_problems, can_problems, mono_problems, home, interns))

View file

@ -1,3 +1,8 @@
app Hello provides [ main ] imports [] app Hello provides [ main ] imports []
main = "Hello, World!" greeting =
hi = "Hello, World!"
hi
main = greeting