Correct instantiation of delayed opaques

I didn't realize that delayed instantiation of aliases instantiates
their real var, not the whole alias type. So prior to this, we were
wrapping all opaques in a structural `Alias(..)`. Which is okay from a
typechecking perspective because Aliases are transparent, but is
wasteful.
This commit is contained in:
Ayaz Hafiz 2022-05-07 16:46:37 -04:00
parent e2383fec50
commit af3a677f12
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58

View file

@ -17,8 +17,8 @@ use roc_types::subs::{
}; };
use roc_types::types::Type::{self, *}; use roc_types::types::Type::{self, *};
use roc_types::types::{ use roc_types::types::{
gather_fields_unsorted_iter, AliasCommon, AliasKind, Category, ErrorType, LambdaSet, gather_fields_unsorted_iter, AliasCommon, AliasKind, Category, ErrorType, PatternCategory,
PatternCategory, Reason, TypeExtension, Reason, TypeExtension,
}; };
use roc_unify::unify::{unify, Mode, Unified::*}; use roc_unify::unify::{unify, Mode, Unified::*};
@ -215,30 +215,24 @@ impl Aliases {
register(subs, rank, pools, content) register(subs, rank, pools, content)
} }
fn instantiate_builtin_aliases( fn instantiate_builtin_aliases_real_var(
&mut self, &mut self,
subs: &mut Subs, subs: &mut Subs,
rank: Rank, rank: Rank,
pools: &mut Pools, pools: &mut Pools,
symbol: Symbol, symbol: Symbol,
alias_variables: AliasVariables, alias_variables: AliasVariables,
) -> Option<Variable> { ) -> Option<(Variable, AliasKind)> {
match symbol { match symbol {
Symbol::RESULT_RESULT => { Symbol::RESULT_RESULT => {
let var = Self::instantiate_result_result(subs, rank, pools, alias_variables); let var = Self::instantiate_result_result(subs, rank, pools, alias_variables);
Some(var) Some((var, AliasKind::Structural))
} }
Symbol::NUM_NUM | Symbol::NUM_INTEGER | Symbol::NUM_FLOATINGPOINT => { Symbol::NUM_NUM | Symbol::NUM_INTEGER | Symbol::NUM_FLOATINGPOINT => {
// Num range := range | Integer range := range | FloatingPoint range := range // Num range := range | Integer range := range | FloatingPoint range := range
Self::build_num_opaque( let range_var = subs.variables[alias_variables.variables_start as usize];
subs, Some((range_var, AliasKind::Opaque))
rank,
pools,
symbol,
subs.variables[alias_variables.variables_start as usize],
)
.into()
} }
Symbol::NUM_INT => { Symbol::NUM_INT => {
// Int range : Num (Integer range) // Int range : Num (Integer range)
@ -256,7 +250,7 @@ impl Aliases {
let num_content_var = let num_content_var =
Self::build_num_opaque(subs, rank, pools, Symbol::NUM_NUM, integer_content_var); Self::build_num_opaque(subs, rank, pools, Symbol::NUM_NUM, integer_content_var);
Some(num_content_var) Some((num_content_var, AliasKind::Structural))
} }
Symbol::NUM_FLOAT => { Symbol::NUM_FLOAT => {
// Float range : Num (FloatingPoint range) // Float range : Num (FloatingPoint range)
@ -274,13 +268,13 @@ impl Aliases {
let num_content_var = let num_content_var =
Self::build_num_opaque(subs, rank, pools, Symbol::NUM_NUM, fpoint_content_var); Self::build_num_opaque(subs, rank, pools, Symbol::NUM_NUM, fpoint_content_var);
Some(num_content_var) Some((num_content_var, AliasKind::Structural))
} }
_ => None, _ => None,
} }
} }
fn instantiate( fn instantiate_real_var(
&mut self, &mut self,
subs: &mut Subs, subs: &mut Subs,
rank: Rank, rank: Rank,
@ -288,15 +282,20 @@ impl Aliases {
arena: &bumpalo::Bump, arena: &bumpalo::Bump,
symbol: Symbol, symbol: Symbol,
alias_variables: AliasVariables, alias_variables: AliasVariables,
) -> Result<Variable, ()> { ) -> Result<(Variable, AliasKind), ()> {
// hardcoded instantiations for builtin aliases // hardcoded instantiations for builtin aliases
if let Some(var) = if let Some((var, kind)) = Self::instantiate_builtin_aliases_real_var(
Self::instantiate_builtin_aliases(self, subs, rank, pools, symbol, alias_variables) self,
{ subs,
return Ok(var); rank,
pools,
symbol,
alias_variables,
) {
return Ok((var, kind));
} }
let (typ, delayed_variables, kind) = let (typ, delayed_variables, &mut kind) =
match self.aliases.iter_mut().find(|(s, _, _, _)| *s == symbol) { match self.aliases.iter_mut().find(|(s, _, _, _)| *s == symbol) {
None => return Err(()), None => return Err(()),
Some((_, typ, delayed_variables, kind)) => (typ, delayed_variables, kind), Some((_, typ, delayed_variables, kind)) => (typ, delayed_variables, kind),
@ -344,10 +343,6 @@ impl Aliases {
typ.substitute_variables(&substitutions); typ.substitute_variables(&substitutions);
} }
let alias_variable = match kind {
AliasKind::Structural => {
// We can replace structural aliases wholly with the type on the
// RHS of their definition.
let mut t = Type::EmptyRec; let mut t = Type::EmptyRec;
std::mem::swap(typ, &mut t); std::mem::swap(typ, &mut t);
@ -367,37 +362,7 @@ impl Aliases {
} }
} }
alias_variable Ok((alias_variable, kind))
}
AliasKind::Opaque => {
// For opaques, the instantiation must be to an opaque type rather than just what's
// on the RHS.
let lambda_set_variables = new_lambda_set_variables
.iter()
.copied()
.map(Type::Variable)
.map(LambdaSet)
.collect();
let type_arguments = new_type_variables
.iter()
.copied()
.map(Type::Variable)
.collect();
let opaq = Type::Alias {
symbol,
kind: *kind,
lambda_set_variables,
type_arguments,
actual: Box::new(typ.clone()),
};
type_to_variable(subs, rank, pools, arena, self, &opaq)
}
};
Ok(alias_variable)
} }
} }
@ -1919,8 +1884,6 @@ fn type_to_variable<'a>(
type_arguments, type_arguments,
lambda_set_variables, lambda_set_variables,
}) => { }) => {
let kind = AliasKind::Structural;
let alias_variables = { let alias_variables = {
let length = type_arguments.len() + lambda_set_variables.len(); let length = type_arguments.len() + lambda_set_variables.len();
let new_variables = VariableSubsSlice::reserve_into_subs(subs, length); let new_variables = VariableSubsSlice::reserve_into_subs(subs, length);
@ -1944,13 +1907,17 @@ fn type_to_variable<'a>(
} }
}; };
let instantiated = let instantiated = aliases.instantiate_real_var(
aliases.instantiate(subs, rank, pools, arena, *symbol, alias_variables); subs,
rank,
pools,
arena,
*symbol,
alias_variables,
);
let alias_variable = match instantiated { let (alias_variable, kind) = instantiated
Err(_) => unreachable!("Alias {:?} is not available", symbol), .unwrap_or_else(|_| unreachable!("Alias {:?} is not available", symbol));
Ok(alias_variable) => alias_variable,
};
let content = Content::Alias(*symbol, alias_variables, alias_variable, kind); let content = Content::Alias(*symbol, alias_variables, alias_variable, kind);