mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Merge branch 'vecset-references' into builtins-in-roc
This commit is contained in:
commit
8692938fb3
18 changed files with 537 additions and 142 deletions
|
@ -7,6 +7,7 @@ use crate::layout::{
|
|||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::expr::{ClosureData, IntValue};
|
||||
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
||||
use roc_exhaustive::{Ctor, Guard, RenderAs, TagId};
|
||||
|
@ -251,11 +252,22 @@ impl<'a> PartialProc<'a> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum PartialExprLink {
|
||||
Aliases(Symbol),
|
||||
enum PolymorphicExpr {
|
||||
/// A root ability member, which must be specialized at a call site, for example
|
||||
/// "hash" which must be specialized to an exact symbol implementing "hash" for a type.
|
||||
AbilityMember(Symbol),
|
||||
/// A polymorphic expression we inline at the usage site.
|
||||
Expr(roc_can::expr::Expr, Variable),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum PartialExprLink {
|
||||
/// The root polymorphic expression
|
||||
Sink(PolymorphicExpr),
|
||||
/// A hop in a partial expression alias chain
|
||||
Aliases(Symbol),
|
||||
}
|
||||
|
||||
/// A table of symbols to polymorphic expressions. For example, in the program
|
||||
///
|
||||
/// n = 1
|
||||
|
@ -281,8 +293,8 @@ impl PartialExprs {
|
|||
Self(BumpMap::new_in(arena))
|
||||
}
|
||||
|
||||
fn insert(&mut self, symbol: Symbol, expr: roc_can::expr::Expr, expr_var: Variable) {
|
||||
self.0.insert(symbol, PartialExprLink::Expr(expr, expr_var));
|
||||
fn insert(&mut self, symbol: Symbol, expr: PolymorphicExpr) {
|
||||
self.0.insert(symbol, PartialExprLink::Sink(expr));
|
||||
}
|
||||
|
||||
fn insert_alias(&mut self, symbol: Symbol, aliases: Symbol) {
|
||||
|
@ -293,7 +305,7 @@ impl PartialExprs {
|
|||
self.0.contains_key(&symbol)
|
||||
}
|
||||
|
||||
fn get(&mut self, mut symbol: Symbol) -> Option<(&roc_can::expr::Expr, Variable)> {
|
||||
fn get(&mut self, mut symbol: Symbol) -> Option<&PolymorphicExpr> {
|
||||
// In practice the alias chain is very short
|
||||
loop {
|
||||
match self.0.get(&symbol) {
|
||||
|
@ -303,8 +315,8 @@ impl PartialExprs {
|
|||
Some(&PartialExprLink::Aliases(real_symbol)) => {
|
||||
symbol = real_symbol;
|
||||
}
|
||||
Some(PartialExprLink::Expr(expr, var)) => {
|
||||
return Some((expr, *var));
|
||||
Some(PartialExprLink::Sink(expr)) => {
|
||||
return Some(expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1119,6 +1131,7 @@ pub struct Env<'a, 'i> {
|
|||
pub target_info: TargetInfo,
|
||||
pub update_mode_ids: &'i mut UpdateModeIds,
|
||||
pub call_specialization_counter: u32,
|
||||
pub abilities_store: &'i AbilitiesStore,
|
||||
}
|
||||
|
||||
impl<'a, 'i> Env<'a, 'i> {
|
||||
|
@ -4218,10 +4231,14 @@ pub fn with_hole<'a>(
|
|||
// a proc in this module, or an imported symbol
|
||||
procs.partial_procs.contains_key(key)
|
||||
|| (env.is_imported_symbol(key) && !procs.is_imported_module_thunk(key))
|
||||
|| env.abilities_store.is_ability_member_name(key)
|
||||
};
|
||||
|
||||
match loc_expr.value {
|
||||
roc_can::expr::Expr::Var(proc_name) if is_known(proc_name) => {
|
||||
// This might be an ability member - if so, use the appropriate specialization.
|
||||
let proc_name = get_specialization(env, fn_var, proc_name).unwrap_or(proc_name);
|
||||
|
||||
// a call by a known name
|
||||
call_by_name(
|
||||
env,
|
||||
|
@ -4330,47 +4347,68 @@ pub fn with_hole<'a>(
|
|||
unreachable!("calling a non-closure layout")
|
||||
}
|
||||
},
|
||||
UnspecializedExpr(symbol) => match full_layout {
|
||||
RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout) => {
|
||||
let closure_data_symbol = env.unique_symbol();
|
||||
UnspecializedExpr(symbol) => match procs.partial_exprs.get(symbol).unwrap()
|
||||
{
|
||||
&PolymorphicExpr::AbilityMember(member) => {
|
||||
let proc_name = get_specialization(env, fn_var, member).expect("Recorded as an ability member, but it doesn't have a specialization");
|
||||
|
||||
result = match_on_lambda_set(
|
||||
// a call by a known name
|
||||
return call_by_name(
|
||||
env,
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
arg_symbols,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
procs,
|
||||
fn_var,
|
||||
proc_name,
|
||||
loc_args,
|
||||
layout_cache,
|
||||
assigned,
|
||||
hole,
|
||||
);
|
||||
|
||||
let (lambda_expr, lambda_expr_var) =
|
||||
procs.partial_exprs.get(symbol).unwrap();
|
||||
|
||||
let snapshot = env.subs.snapshot();
|
||||
let cache_snapshot = layout_cache.snapshot();
|
||||
let _unified = roc_unify::unify::unify(
|
||||
env.subs,
|
||||
fn_var,
|
||||
lambda_expr_var,
|
||||
roc_unify::unify::Mode::EQ,
|
||||
);
|
||||
|
||||
result = with_hole(
|
||||
env,
|
||||
lambda_expr.clone(),
|
||||
fn_var,
|
||||
procs,
|
||||
layout_cache,
|
||||
closure_data_symbol,
|
||||
env.arena.alloc(result),
|
||||
);
|
||||
env.subs.rollback_to(snapshot);
|
||||
layout_cache.rollback_to(cache_snapshot);
|
||||
}
|
||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||
unreachable!("calling a non-closure layout")
|
||||
PolymorphicExpr::Expr(lambda_expr, lambda_expr_var) => {
|
||||
match full_layout {
|
||||
RawFunctionLayout::Function(
|
||||
arg_layouts,
|
||||
lambda_set,
|
||||
ret_layout,
|
||||
) => {
|
||||
let closure_data_symbol = env.unique_symbol();
|
||||
|
||||
result = match_on_lambda_set(
|
||||
env,
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
arg_symbols,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
assigned,
|
||||
hole,
|
||||
);
|
||||
|
||||
let snapshot = env.subs.snapshot();
|
||||
let cache_snapshot = layout_cache.snapshot();
|
||||
let _unified = roc_unify::unify::unify(
|
||||
env.subs,
|
||||
fn_var,
|
||||
*lambda_expr_var,
|
||||
roc_unify::unify::Mode::EQ,
|
||||
);
|
||||
|
||||
result = with_hole(
|
||||
env,
|
||||
lambda_expr.clone(),
|
||||
fn_var,
|
||||
procs,
|
||||
layout_cache,
|
||||
closure_data_symbol,
|
||||
env.arena.alloc(result),
|
||||
);
|
||||
env.subs.rollback_to(snapshot);
|
||||
layout_cache.rollback_to(cache_snapshot);
|
||||
}
|
||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||
unreachable!("calling a non-closure layout")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
NotASymbol => {
|
||||
|
@ -4705,6 +4743,43 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_specialization<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
symbol_var: Variable,
|
||||
symbol: Symbol,
|
||||
) -> Option<Symbol> {
|
||||
use roc_solve::ability::type_implementing_member;
|
||||
use roc_unify::unify::unify;
|
||||
|
||||
match env.abilities_store.member_def(symbol) {
|
||||
None => {
|
||||
// This is not an ability member, it doesn't need specialization.
|
||||
None
|
||||
}
|
||||
Some(member) => {
|
||||
let snapshot = env.subs.snapshot();
|
||||
let (_, must_implement_ability) = unify(
|
||||
env.subs,
|
||||
symbol_var,
|
||||
member.signature_var,
|
||||
roc_unify::unify::Mode::EQ,
|
||||
)
|
||||
.expect_success("This typechecked previously");
|
||||
env.subs.rollback_to(snapshot);
|
||||
let specializing_type =
|
||||
type_implementing_member(&must_implement_ability, member.parent_ability);
|
||||
|
||||
let specialization = env
|
||||
.abilities_store
|
||||
.get_specialization(symbol, specializing_type)
|
||||
.expect("No specialization is recorded - I thought there would only be a type error here.");
|
||||
|
||||
Some(specialization.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn construct_closure_data<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
|
@ -5621,9 +5696,10 @@ pub fn from_can<'a>(
|
|||
// At the definition site `n = 1` we only know `1` to have the type `[Int *]`,
|
||||
// which won't be refined until the call `asU8 n`. Add it as a partial expression
|
||||
// that will be specialized at each concrete usage site.
|
||||
procs
|
||||
.partial_exprs
|
||||
.insert(*symbol, def.loc_expr.value, def.expr_var);
|
||||
procs.partial_exprs.insert(
|
||||
*symbol,
|
||||
PolymorphicExpr::Expr(def.loc_expr.value, def.expr_var),
|
||||
);
|
||||
|
||||
let result = from_can(env, variable, cont.value, procs, layout_cache);
|
||||
|
||||
|
@ -6329,7 +6405,7 @@ fn store_pattern_help<'a>(
|
|||
|
||||
match can_pat {
|
||||
Identifier(symbol) => {
|
||||
if let Some((_, var)) = procs.partial_exprs.get(outer_symbol) {
|
||||
if let Some(&PolymorphicExpr::Expr(_, var)) = procs.partial_exprs.get(outer_symbol) {
|
||||
// It might be the case that symbol we're storing hasn't been reified to a value
|
||||
// yet, if it's polymorphic. Do that now.
|
||||
stmt = specialize_symbol(
|
||||
|
@ -6739,6 +6815,13 @@ fn handle_variable_aliasing<'a, BuildRest>(
|
|||
where
|
||||
BuildRest: FnOnce(&mut Env<'a, '_>, &mut Procs<'a>, &mut LayoutCache<'a>) -> Stmt<'a>,
|
||||
{
|
||||
if env.abilities_store.is_ability_member_name(right) {
|
||||
procs
|
||||
.partial_exprs
|
||||
.insert(left, PolymorphicExpr::AbilityMember(right));
|
||||
return build_rest(env, procs, layout_cache);
|
||||
}
|
||||
|
||||
if procs.partial_exprs.contains(right) {
|
||||
// If `right` links to a partial expression, make sure we link `left` to it as well, so
|
||||
// that usages of it will be specialized when building the rest of the program.
|
||||
|
@ -6816,7 +6899,7 @@ fn specialize_symbol<'a>(
|
|||
result: Stmt<'a>,
|
||||
original: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
if let Some((expr, expr_var)) = procs.partial_exprs.get(original) {
|
||||
if let Some(PolymorphicExpr::Expr(expr, expr_var)) = procs.partial_exprs.get(original) {
|
||||
// Specialize the expression type now, based off the `arg_var` we've been given.
|
||||
// TODO: cache the specialized result
|
||||
let snapshot = env.subs.snapshot();
|
||||
|
@ -6824,14 +6907,14 @@ fn specialize_symbol<'a>(
|
|||
let _unified = roc_unify::unify::unify(
|
||||
env.subs,
|
||||
arg_var.unwrap(),
|
||||
expr_var,
|
||||
*expr_var,
|
||||
roc_unify::unify::Mode::EQ,
|
||||
);
|
||||
|
||||
let result = with_hole(
|
||||
env,
|
||||
expr.clone(),
|
||||
expr_var,
|
||||
*expr_var,
|
||||
procs,
|
||||
layout_cache,
|
||||
symbol,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue