Merge branch 'delay-instantiating-aliases-fix-limitations' into builtins-in-roc

This commit is contained in:
Folkert 2022-03-19 12:30:03 +01:00
commit 35e5a36ea4
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
6 changed files with 256 additions and 92 deletions

View file

@ -343,12 +343,8 @@ fn can_annotation_help(
return error;
}
// For now, aliases of function types cannot be delayed.
// This is a limitation of the current implementation,
// and this totally should be possible in the future.
let is_import = !symbol.is_builtin() && (env.home != symbol.module_id());
let is_structural = alias.kind == AliasKind::Structural;
if !is_import && is_structural && alias.lambda_set_variables.is_empty() {
if is_structural {
let mut type_var_to_arg = Vec::new();
for (loc_var, arg_ann) in alias.type_variables.iter().zip(args) {
@ -357,10 +353,21 @@ fn can_annotation_help(
type_var_to_arg.push((name, arg_ann));
}
let mut lambda_set_variables =
Vec::with_capacity(alias.lambda_set_variables.len());
for _ in 0..alias.lambda_set_variables.len() {
let lvar = var_store.fresh();
introduced_variables.insert_lambda_set(lvar);
lambda_set_variables.push(LambdaSet(Type::Variable(lvar)));
}
Type::DelayedAlias(AliasCommon {
symbol,
type_arguments: type_var_to_arg,
lambda_set_variables: alias.lambda_set_variables.clone(),
lambda_set_variables,
})
} else {
let (type_arguments, lambda_set_variables, actual) =

View file

@ -22,6 +22,7 @@ use roc_problem::can::{CycleEntry, Problem, RuntimeError};
use roc_region::all::{Loc, Region};
use roc_types::subs::{VarStore, Variable};
use roc_types::types::AliasKind;
use roc_types::types::LambdaSet;
use roc_types::types::{Alias, Type};
use std::collections::HashMap;
use std::fmt::Debug;
@ -1703,12 +1704,21 @@ fn correct_mutual_recursive_type_alias<'a>(
let alias = pending_aliases.get_mut(&rec).unwrap();
// Don't try to instantiate the alias itself in its definition.
let original_alias_def = to_instantiate.remove(&rec).unwrap();
let mut new_lambda_sets = ImSet::default();
alias.typ.instantiate_aliases(
alias.region,
&to_instantiate,
var_store,
&mut ImSet::default(),
&mut new_lambda_sets,
);
for lambda_set_var in new_lambda_sets {
alias
.lambda_set_variables
.push(LambdaSet(Type::Variable(lambda_set_var)));
}
to_instantiate.insert(rec, original_alias_def);
// Now mark the alias recursive, if it needs to be.

View file

@ -548,7 +548,7 @@ pub fn canonicalize_module_defs<'a>(
}
}
Ok(ModuleOutput {
let output = ModuleOutput {
scope,
aliases,
rigid_variables,
@ -559,7 +559,9 @@ pub fn canonicalize_module_defs<'a>(
problems: env.problems,
lookups,
ident_ids: env.ident_ids,
})
};
Ok(output)
}
(Err(runtime_error), _) => Err(runtime_error),
}

View file

@ -4577,6 +4577,8 @@ fn canonicalize_and_constrain<'a>(
..
} = parsed;
let before = roc_types::types::get_type_clone_count();
let mut var_store = VarStore::default();
let canonicalized = canonicalize_module_defs(
arena,
@ -4592,6 +4594,16 @@ fn canonicalize_and_constrain<'a>(
&mut var_store,
);
let after = roc_types::types::get_type_clone_count();
log!(
"canonicalize of {:?} cloned Type {} times ({} -> {})",
module_id,
after - before,
before,
after
);
let canonicalize_end = SystemTime::now();
module_timing.canonicalize = canonicalize_end.duration_since(canonicalize_start).unwrap();
@ -4605,7 +4617,7 @@ fn canonicalize_and_constrain<'a>(
ModuleNameEnum::App(_) => None,
ModuleNameEnum::Interface(name) | ModuleNameEnum::Hosted(name) => {
let docs = crate::docs::generate_module_docs(
module_output.scope,
module_output.scope.clone(),
name.as_str().into(),
&module_output.ident_ids,
parsed_defs,
@ -4615,17 +4627,46 @@ fn canonicalize_and_constrain<'a>(
}
};
let before = roc_types::types::get_type_clone_count();
let mut constraints = Constraints::new();
let constraint =
constrain_module(&mut constraints, &module_output.declarations, module_id);
let after = roc_types::types::get_type_clone_count();
log!(
"constraint gen of {:?} cloned Type {} times ({} -> {})",
module_id,
after - before,
before,
after
);
// scope has imported aliases, but misses aliases from inner scopes
// module_output.aliases does have those aliases, so we combine them
let mut aliases = module_output.aliases;
for (name, alias) in module_output.scope.aliases {
match aliases.entry(name) {
Occupied(_) => {
// do nothing
}
Vacant(vacant) => {
if !name.is_builtin() {
vacant.insert(alias);
}
}
}
}
let module = Module {
module_id,
exposed_imports: module_output.exposed_imports,
exposed_symbols,
referenced_values: module_output.referenced_values,
referenced_types: module_output.referenced_types,
aliases: module_output.aliases,
aliases,
rigid_variables: module_output.rigid_variables,
};

View file

@ -1908,6 +1908,35 @@ fn wildcard_rigid() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn alias_of_alias_with_type_arguments() {
assert_non_opt_evals_to!(
indoc!(
r#"
app "test" provides [ main ] to "./platform"
Effect a : [ @Effect a ]
Task a err : Effect (Result a err)
always : a -> Task a *
always = \x ->
inner = (Ok x)
@Effect inner
main : Task {} (Float *)
main = always {}
"#
),
0,
i64,
|_| 0
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[ignore]

View file

@ -886,7 +886,11 @@ impl Type {
TypeExtension::Closed => Ok(()),
}
}
DelayedAlias(AliasCommon { type_arguments, .. }) => {
DelayedAlias(AliasCommon {
type_arguments,
lambda_set_variables: _no_aliases_in_lambda_sets,
..
}) => {
for (_, ta) in type_arguments {
ta.substitute_alias(rep_symbol, rep_args, actual)?;
}
@ -966,12 +970,16 @@ impl Type {
DelayedAlias(AliasCommon {
symbol,
type_arguments,
lambda_set_variables,
..
}) => {
symbol == &rep_symbol
|| type_arguments
.iter()
.any(|v| v.1.contains_symbol(rep_symbol))
|| lambda_set_variables
.iter()
.any(|v| v.0.contains_symbol(rep_symbol))
}
Alias {
symbol: alias_symbol,
@ -1055,41 +1063,41 @@ impl Type {
region: Region,
aliases: &ImMap<Symbol, Alias>,
var_store: &mut VarStore,
introduced: &mut ImSet<Variable>,
new_lambda_set_variables: &mut ImSet<Variable>,
) {
use Type::*;
match self {
Function(args, closure, ret) => {
for arg in args {
arg.instantiate_aliases(region, aliases, var_store, introduced);
arg.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
closure.instantiate_aliases(region, aliases, var_store, introduced);
ret.instantiate_aliases(region, aliases, var_store, introduced);
closure.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
ret.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
FunctionOrTagUnion(_, _, ext) => {
if let TypeExtension::Open(ext) = ext {
ext.instantiate_aliases(region, aliases, var_store, introduced);
ext.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
for (_, args) in tags {
for x in args {
x.instantiate_aliases(region, aliases, var_store, introduced);
x.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
}
if let TypeExtension::Open(ext) = ext {
ext.instantiate_aliases(region, aliases, var_store, introduced);
ext.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
}
Record(fields, ext) => {
for (_, x) in fields.iter_mut() {
x.instantiate_aliases(region, aliases, var_store, introduced);
x.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
if let TypeExtension::Open(ext) = ext {
ext.instantiate_aliases(region, aliases, var_store, introduced);
ext.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
}
DelayedAlias(AliasCommon { .. }) => {
@ -1109,17 +1117,52 @@ impl Type {
} => {
for arg in type_args {
arg.1
.instantiate_aliases(region, aliases, var_store, introduced);
.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
for arg in lambda_set_variables {
arg.instantiate_aliases(region, aliases, var_store, introduced);
arg.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
actual_type.instantiate_aliases(region, aliases, var_store, introduced);
actual_type.instantiate_aliases(
region,
aliases,
var_store,
new_lambda_set_variables,
);
}
Apply(symbol, args, _) => {
if let Some(alias) = aliases.get(symbol) {
// TODO switch to this, but we still need to check for recursion with the
// `else` branch
if false {
let mut type_var_to_arg = Vec::new();
for (loc_var, arg_ann) in alias.type_variables.iter().zip(args) {
let name = loc_var.value.0.clone();
type_var_to_arg.push((name, arg_ann.clone()));
}
let mut lambda_set_variables =
Vec::with_capacity(alias.lambda_set_variables.len());
for _ in 0..alias.lambda_set_variables.len() {
let lvar = var_store.fresh();
new_lambda_set_variables.insert(lvar);
lambda_set_variables.push(LambdaSet(Type::Variable(lvar)));
}
let alias = Type::DelayedAlias(AliasCommon {
symbol: *symbol,
type_arguments: type_var_to_arg,
lambda_set_variables,
});
*self = alias;
} else {
if args.len() != alias.type_variables.len() {
*self = Type::Erroneous(Problem::BadTypeArguments {
symbol: *symbol,
@ -1145,7 +1188,12 @@ impl Type {
) in alias.type_variables.iter().zip(args.iter())
{
let mut filler = filler.clone();
filler.instantiate_aliases(region, aliases, var_store, introduced);
filler.instantiate_aliases(
region,
aliases,
var_store,
new_lambda_set_variables,
);
named_args.push((lowercase.clone(), filler.clone()));
substitution.insert(*placeholder, filler);
}
@ -1156,7 +1204,7 @@ impl Type {
for typ in alias.lambda_set_variables.iter() {
if let Type::Variable(var) = typ.0 {
let fresh = var_store.fresh();
introduced.insert(fresh);
new_lambda_set_variables.insert(fresh);
substitution.insert(var, Type::Variable(fresh));
lambda_set_variables.push(LambdaSet(Type::Variable(fresh)));
} else {
@ -1164,7 +1212,12 @@ impl Type {
}
}
actual.instantiate_aliases(region, aliases, var_store, introduced);
actual.instantiate_aliases(
region,
aliases,
var_store,
new_lambda_set_variables,
);
actual.substitute(&substitution);
@ -1184,23 +1237,25 @@ impl Type {
actual = Type::RecursiveTagUnion(new_rec_var, tags, ext);
}
*self = Type::Alias {
let alias = Type::Alias {
symbol: *symbol,
type_arguments: named_args,
lambda_set_variables,
actual: Box::new(actual),
kind: alias.kind,
};
*self = alias;
}
} else {
// one of the special-cased Apply types.
for x in args {
x.instantiate_aliases(region, aliases, var_store, introduced);
x.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
}
}
RangedNumber(typ, _) => {
typ.instantiate_aliases(region, aliases, var_store, introduced);
typ.instantiate_aliases(region, aliases, var_store, new_lambda_set_variables);
}
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Erroneous(_) | Variable(_) => {}
}
@ -1406,10 +1461,18 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
// this rec var doesn't need to be in flex_vars or rigid_vars
accum.remove(rec);
}
DelayedAlias(AliasCommon { type_arguments, .. }) => {
DelayedAlias(AliasCommon {
type_arguments,
lambda_set_variables,
..
}) => {
for (_, arg) in type_arguments {
variables_help(arg, accum);
}
for lambda_set in lambda_set_variables {
variables_help(&lambda_set.0, accum);
}
}
Alias {
type_arguments,
@ -1530,10 +1593,22 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
accum.recursion_variables.insert(*rec);
}
DelayedAlias(AliasCommon { type_arguments, .. }) => {
DelayedAlias(AliasCommon {
type_arguments,
lambda_set_variables,
..
}) => {
for (_, arg) in type_arguments {
variables_help_detailed(arg, accum);
}
for lambda_set in lambda_set_variables {
if let Type::Variable(v) = lambda_set.0 {
accum.lambda_set_variables.push(v);
} else {
variables_help_detailed(&lambda_set.0, accum);
}
}
}
Alias {
type_arguments,