mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Unify variables directly when possible
instead of going through a solved type
This commit is contained in:
parent
1348ec433b
commit
ecba687243
3 changed files with 141 additions and 49 deletions
|
@ -694,10 +694,8 @@ impl<'a> Procs<'a> {
|
|||
layout: ProcLayout<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
) {
|
||||
let tuple = (name, layout);
|
||||
|
||||
// If we've already specialized this one, no further work is needed.
|
||||
if self.specialized.contains_key(&tuple) {
|
||||
if self.specialized.contains_key(&(name, layout)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -707,15 +705,12 @@ impl<'a> Procs<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
// We're done with that tuple, so move layout back out to avoid cloning it.
|
||||
let (name, layout) = tuple;
|
||||
|
||||
let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var);
|
||||
|
||||
// This should only be called when pending_specializations is Some.
|
||||
// Otherwise, it's being called in the wrong pass!
|
||||
match &mut self.pending_specializations {
|
||||
Some(pending_specializations) => {
|
||||
let pending = PendingSpecialization::from_var(env.arena, env.subs, fn_var);
|
||||
|
||||
// register the pending specialization, so this gets code genned later
|
||||
if self.module_thunks.contains(&name) {
|
||||
debug_assert!(layout.arguments.is_empty());
|
||||
|
@ -736,7 +731,26 @@ impl<'a> Procs<'a> {
|
|||
// (We had a bug around this before this system existed!)
|
||||
self.specialized.insert((symbol, layout), InProgress);
|
||||
|
||||
match specialize(env, self, symbol, layout_cache, pending, partial_proc) {
|
||||
// See https://github.com/rtfeldman/roc/issues/1600
|
||||
//
|
||||
// The annotation variable is the generic/lifted/top-level annotation.
|
||||
// It is connected to the variables of the function's body
|
||||
//
|
||||
// fn_var is the variable representing the type that we actually need for the
|
||||
// function right here.
|
||||
//
|
||||
// For some reason, it matters that we unify with the original variable. Extracting
|
||||
// that variable into a SolvedType and then introducing it again severs some
|
||||
// connection that turns out to be important
|
||||
match specialize_variable(
|
||||
env,
|
||||
self,
|
||||
symbol,
|
||||
layout_cache,
|
||||
fn_var,
|
||||
Default::default(),
|
||||
partial_proc,
|
||||
) {
|
||||
Ok((proc, _ignore_layout)) => {
|
||||
// the `layout` is a function pointer, while `_ignore_layout` can be a
|
||||
// closure. We only specialize functions, storing this value with a closure
|
||||
|
@ -2448,13 +2462,57 @@ fn specialize_solved_type<'a>(
|
|||
host_exposed_aliases: BumpMap<Symbol, SolvedType>,
|
||||
partial_proc: PartialProc<'a>,
|
||||
) -> Result<SpecializeSuccess<'a>, SpecializeFailure<'a>> {
|
||||
specialize_variable_help(
|
||||
env,
|
||||
procs,
|
||||
proc_name,
|
||||
layout_cache,
|
||||
|env| introduce_solved_type_to_subs(env, &solved_type),
|
||||
host_exposed_aliases,
|
||||
partial_proc,
|
||||
)
|
||||
}
|
||||
|
||||
fn specialize_variable<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
proc_name: Symbol,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
fn_var: Variable,
|
||||
host_exposed_aliases: BumpMap<Symbol, SolvedType>,
|
||||
partial_proc: PartialProc<'a>,
|
||||
) -> Result<SpecializeSuccess<'a>, SpecializeFailure<'a>> {
|
||||
specialize_variable_help(
|
||||
env,
|
||||
procs,
|
||||
proc_name,
|
||||
layout_cache,
|
||||
|_| fn_var,
|
||||
host_exposed_aliases,
|
||||
partial_proc,
|
||||
)
|
||||
}
|
||||
|
||||
fn specialize_variable_help<'a, F>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
proc_name: Symbol,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
fn_var_thunk: F,
|
||||
host_exposed_aliases: BumpMap<Symbol, SolvedType>,
|
||||
partial_proc: PartialProc<'a>,
|
||||
) -> Result<SpecializeSuccess<'a>, SpecializeFailure<'a>>
|
||||
where
|
||||
F: FnOnce(&mut Env<'a, '_>) -> Variable,
|
||||
{
|
||||
// add the specializations that other modules require of us
|
||||
use roc_solve::solve::instantiate_rigids;
|
||||
|
||||
let snapshot = env.subs.snapshot();
|
||||
let cache_snapshot = layout_cache.snapshot();
|
||||
|
||||
let fn_var = introduce_solved_type_to_subs(env, &solved_type);
|
||||
// important: evaluate after the snapshot has been created!
|
||||
let fn_var = fn_var_thunk(env);
|
||||
|
||||
// for debugging only
|
||||
let raw = layout_cache
|
||||
|
@ -2723,32 +2781,36 @@ pub fn with_hole<'a>(
|
|||
hole,
|
||||
),
|
||||
|
||||
Num(var, num) => match num_argument_to_int_or_float(env.subs, env.ptr_bytes, var, false) {
|
||||
IntOrFloat::SignedIntType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(num.into())),
|
||||
Layout::Builtin(int_precision_to_builtin(precision)),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(num.into())),
|
||||
Layout::Builtin(int_precision_to_builtin(precision)),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Float(num as f64)),
|
||||
Layout::Builtin(float_precision_to_builtin(precision)),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::DecimalFloatType => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Float(num as f64)),
|
||||
Layout::Builtin(Builtin::Decimal),
|
||||
hole,
|
||||
),
|
||||
},
|
||||
Num(var, num) => {
|
||||
// first figure out what kind of number this is
|
||||
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, var, false) {
|
||||
IntOrFloat::SignedIntType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(num.into())),
|
||||
Layout::Builtin(int_precision_to_builtin(precision)),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(num.into())),
|
||||
Layout::Builtin(int_precision_to_builtin(precision)),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Float(num as f64)),
|
||||
Layout::Builtin(float_precision_to_builtin(precision)),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::DecimalFloatType => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Float(num as f64)),
|
||||
Layout::Builtin(Builtin::Decimal),
|
||||
hole,
|
||||
),
|
||||
}
|
||||
}
|
||||
LetNonRec(def, cont, _) => {
|
||||
if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value {
|
||||
if let Closure {
|
||||
|
@ -7865,6 +7927,12 @@ fn union_lambda_set_to_switch<'a>(
|
|||
assigned: Symbol,
|
||||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
// NOTE this can happen if there is a type error somewhere. Since the lambda set is empty,
|
||||
// there is really nothing we can do here, so we just proceed with the hole itself and
|
||||
// hope that the type error is communicated in a clear way elsewhere.
|
||||
if lambda_set.is_empty() {
|
||||
return hole.clone();
|
||||
}
|
||||
debug_assert!(!lambda_set.is_empty());
|
||||
|
||||
let join_point_id = JoinPointId(env.unique_symbol());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue