mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
Merge remote-tracking branch 'origin/trunk' into builtins-in-roc-delayed-alias
This commit is contained in:
commit
4e1197165b
181 changed files with 9495 additions and 2273 deletions
|
@ -1,12 +1,15 @@
|
|||
use crate::env::Env;
|
||||
use crate::scope::Scope;
|
||||
use roc_collections::all::{ImMap, MutMap, MutSet, SendMap};
|
||||
use roc_error_macros::todo_abilities;
|
||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_parse::ast::{AssignedField, Pattern, Tag, TypeAnnotation, TypeHeader};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{Alias, AliasKind, LambdaSet, Problem, RecordField, Type};
|
||||
use roc_types::types::{
|
||||
Alias, AliasCommon, AliasKind, LambdaSet, Problem, RecordField, Type, TypeExtension,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Annotation {
|
||||
|
@ -28,25 +31,27 @@ pub struct IntroducedVariables {
|
|||
// But then between annotations, the same name can occur multiple times,
|
||||
// but a variable can only have one name. Therefore
|
||||
// `ftv : SendMap<Variable, Lowercase>`.
|
||||
pub wildcards: Vec<Variable>,
|
||||
pub wildcards: Vec<Loc<Variable>>,
|
||||
pub lambda_sets: Vec<Variable>,
|
||||
pub inferred: Vec<Variable>,
|
||||
pub var_by_name: SendMap<Lowercase, Variable>,
|
||||
pub inferred: Vec<Loc<Variable>>,
|
||||
// NB: A mapping of a -> Loc<v1> in this map has the region of the first-seen var, but there
|
||||
// may be multiple occurrences of it!
|
||||
pub var_by_name: SendMap<Lowercase, Loc<Variable>>,
|
||||
pub name_by_var: SendMap<Variable, Lowercase>,
|
||||
pub host_exposed_aliases: MutMap<Symbol, Variable>,
|
||||
}
|
||||
|
||||
impl IntroducedVariables {
|
||||
pub fn insert_named(&mut self, name: Lowercase, var: Variable) {
|
||||
pub fn insert_named(&mut self, name: Lowercase, var: Loc<Variable>) {
|
||||
self.var_by_name.insert(name.clone(), var);
|
||||
self.name_by_var.insert(var, name);
|
||||
self.name_by_var.insert(var.value, name);
|
||||
}
|
||||
|
||||
pub fn insert_wildcard(&mut self, var: Variable) {
|
||||
pub fn insert_wildcard(&mut self, var: Loc<Variable>) {
|
||||
self.wildcards.push(var);
|
||||
}
|
||||
|
||||
pub fn insert_inferred(&mut self, var: Variable) {
|
||||
pub fn insert_inferred(&mut self, var: Loc<Variable>) {
|
||||
self.inferred.push(var);
|
||||
}
|
||||
|
||||
|
@ -69,7 +74,7 @@ impl IntroducedVariables {
|
|||
}
|
||||
|
||||
pub fn var_by_name(&self, name: &Lowercase) -> Option<&Variable> {
|
||||
self.var_by_name.get(name)
|
||||
self.var_by_name.get(name).map(|v| &v.value)
|
||||
}
|
||||
|
||||
pub fn name_by_var(&self, var: Variable) -> Option<&Lowercase> {
|
||||
|
@ -242,6 +247,7 @@ pub fn find_type_def_symbols(
|
|||
SpaceBefore(inner, _) | SpaceAfter(inner, _) => {
|
||||
stack.push(inner);
|
||||
}
|
||||
Where(..) => todo_abilities!(),
|
||||
Inferred | Wildcard | Malformed(_) => {}
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +290,7 @@ fn can_annotation_help(
|
|||
let ret = can_annotation_help(
|
||||
env,
|
||||
&return_type.value,
|
||||
region,
|
||||
return_type.region,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
|
@ -312,7 +318,7 @@ fn can_annotation_help(
|
|||
let arg_ann = can_annotation_help(
|
||||
env,
|
||||
&arg.value,
|
||||
region,
|
||||
arg.region,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
|
@ -337,22 +343,43 @@ fn can_annotation_help(
|
|||
return error;
|
||||
}
|
||||
|
||||
let (type_arguments, lambda_set_variables, actual) =
|
||||
instantiate_and_freshen_alias_type(
|
||||
var_store,
|
||||
introduced_variables,
|
||||
&alias.type_variables,
|
||||
args,
|
||||
&alias.lambda_set_variables,
|
||||
alias.typ.clone(),
|
||||
);
|
||||
// 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() {
|
||||
let mut type_var_to_arg = Vec::new();
|
||||
|
||||
Type::Alias {
|
||||
symbol,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
actual: Box::new(actual),
|
||||
kind: alias.kind,
|
||||
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));
|
||||
}
|
||||
|
||||
Type::DelayedAlias(AliasCommon {
|
||||
symbol,
|
||||
type_arguments: type_var_to_arg,
|
||||
lambda_set_variables: alias.lambda_set_variables.clone(),
|
||||
})
|
||||
} else {
|
||||
let (type_arguments, lambda_set_variables, actual) =
|
||||
instantiate_and_freshen_alias_type(
|
||||
var_store,
|
||||
introduced_variables,
|
||||
&alias.type_variables,
|
||||
args,
|
||||
&alias.lambda_set_variables,
|
||||
alias.typ.clone(),
|
||||
);
|
||||
|
||||
Type::Alias {
|
||||
symbol,
|
||||
type_arguments,
|
||||
lambda_set_variables,
|
||||
actual: Box::new(actual),
|
||||
kind: alias.kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
None => Type::Apply(symbol, args, region),
|
||||
|
@ -366,7 +393,7 @@ fn can_annotation_help(
|
|||
None => {
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named(name, var);
|
||||
introduced_variables.insert_named(name, Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -430,7 +457,8 @@ fn can_annotation_help(
|
|||
} else {
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named(var_name.clone(), var);
|
||||
introduced_variables
|
||||
.insert_named(var_name.clone(), Loc::at(loc_var.region, var));
|
||||
vars.push((var_name.clone(), Type::Variable(var)));
|
||||
|
||||
lowercase_vars.push(Loc::at(loc_var.region, (var_name, var)));
|
||||
|
@ -537,7 +565,7 @@ fn can_annotation_help(
|
|||
// just `a` does not mean the same as `{}a`, so even
|
||||
// if there are no fields, still make this a `Record`,
|
||||
// not an EmptyRec
|
||||
Type::Record(Default::default(), Box::new(ext_type))
|
||||
Type::Record(Default::default(), TypeExtension::from_type(ext_type))
|
||||
}
|
||||
|
||||
None => Type::EmptyRec,
|
||||
|
@ -554,7 +582,7 @@ fn can_annotation_help(
|
|||
references,
|
||||
);
|
||||
|
||||
Type::Record(field_types, Box::new(ext_type))
|
||||
Type::Record(field_types, TypeExtension::from_type(ext_type))
|
||||
}
|
||||
}
|
||||
TagUnion { tags, ext, .. } => {
|
||||
|
@ -575,7 +603,7 @@ fn can_annotation_help(
|
|||
// just `a` does not mean the same as `{}a`, so even
|
||||
// if there are no fields, still make this a `Record`,
|
||||
// not an EmptyRec
|
||||
Type::TagUnion(Default::default(), Box::new(ext_type))
|
||||
Type::TagUnion(Default::default(), TypeExtension::from_type(ext_type))
|
||||
}
|
||||
|
||||
None => Type::EmptyTagUnion,
|
||||
|
@ -597,7 +625,7 @@ fn can_annotation_help(
|
|||
// in theory we save a lot of time by sorting once here
|
||||
insertion_sort_by(&mut tag_types, |a, b| a.0.cmp(&b.0));
|
||||
|
||||
Type::TagUnion(tag_types, Box::new(ext_type))
|
||||
Type::TagUnion(tag_types, TypeExtension::from_type(ext_type))
|
||||
}
|
||||
}
|
||||
SpaceBefore(nested, _) | SpaceAfter(nested, _) => can_annotation_help(
|
||||
|
@ -613,7 +641,7 @@ fn can_annotation_help(
|
|||
Wildcard => {
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_wildcard(var);
|
||||
introduced_variables.insert_wildcard(Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -622,16 +650,17 @@ fn can_annotation_help(
|
|||
// make a fresh unconstrained variable, and let the type solver fill it in for us 🤠
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_inferred(var);
|
||||
introduced_variables.insert_inferred(Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
Where(..) => todo_abilities!(),
|
||||
Malformed(string) => {
|
||||
malformed(env, region, string);
|
||||
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_wildcard(var);
|
||||
introduced_variables.insert_wildcard(Loc::at(region, var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -682,7 +711,7 @@ fn can_extension_type<'a>(
|
|||
local_aliases,
|
||||
references,
|
||||
);
|
||||
if valid_extension_type(ext_type.shallow_dealias()) {
|
||||
if valid_extension_type(shallow_dealias_with_scope(scope, &ext_type)) {
|
||||
ext_type
|
||||
} else {
|
||||
// Report an error but mark the extension variable to be inferred
|
||||
|
@ -697,7 +726,7 @@ fn can_extension_type<'a>(
|
|||
|
||||
let var = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_inferred(var);
|
||||
introduced_variables.insert_inferred(Loc::at_zero(var));
|
||||
|
||||
Type::Variable(var)
|
||||
}
|
||||
|
@ -706,6 +735,29 @@ fn can_extension_type<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// a shallow dealias, continue until the first constructor is not an alias.
|
||||
fn shallow_dealias_with_scope<'a>(scope: &'a mut Scope, typ: &'a Type) -> &'a Type {
|
||||
let mut result = typ;
|
||||
loop {
|
||||
match result {
|
||||
Type::Alias { actual, .. } => {
|
||||
// another loop
|
||||
result = actual;
|
||||
}
|
||||
Type::DelayedAlias(AliasCommon { symbol, .. }) => match scope.lookup_alias(*symbol) {
|
||||
None => unreachable!(),
|
||||
Some(alias) => {
|
||||
result = &alias.typ;
|
||||
}
|
||||
},
|
||||
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn instantiate_and_freshen_alias_type(
|
||||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
|
@ -866,7 +918,10 @@ fn can_assigned_fields<'a>(
|
|||
Type::Variable(*var)
|
||||
} else {
|
||||
let field_var = var_store.fresh();
|
||||
introduced_variables.insert_named(field_name.clone(), field_var);
|
||||
introduced_variables.insert_named(
|
||||
field_name.clone(),
|
||||
Loc::at(loc_field_name.region, field_var),
|
||||
);
|
||||
Type::Variable(field_var)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -247,6 +247,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
NUM_TO_U64_CHECKED => num_to_u64_checked,
|
||||
NUM_TO_U128 => num_to_u128,
|
||||
NUM_TO_U128_CHECKED => num_to_u128_checked,
|
||||
NUM_TO_NAT => num_to_nat,
|
||||
NUM_TO_NAT_CHECKED => num_to_nat_checked,
|
||||
NUM_TO_STR => num_to_str,
|
||||
RESULT_MAP => result_map,
|
||||
RESULT_MAP_ERR => result_map_err,
|
||||
|
@ -254,6 +256,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
RESULT_WITH_DEFAULT => result_with_default,
|
||||
RESULT_IS_OK => result_is_ok,
|
||||
RESULT_IS_ERR => result_is_err,
|
||||
BOX_BOX_FUNCTION => box_box,
|
||||
BOX_UNBOX => box_unbox,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,6 +459,12 @@ fn num_to_u128(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
|
||||
}
|
||||
|
||||
// Num.toNat : Int * -> Nat
|
||||
fn num_to_nat(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
// Defer to IntCast
|
||||
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
|
||||
}
|
||||
|
||||
fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel) -> Def {
|
||||
let bool_var = var_store.fresh();
|
||||
let num_var_1 = var_store.fresh();
|
||||
|
@ -561,6 +571,7 @@ num_to_checked! {
|
|||
num_to_u32_checked
|
||||
num_to_u64_checked
|
||||
num_to_u128_checked
|
||||
num_to_nat_checked
|
||||
}
|
||||
|
||||
// Num.toStr : Num a -> Str
|
||||
|
@ -5314,6 +5325,16 @@ fn num_bytes_to(symbol: Symbol, var_store: &mut VarStore, offset: i64, low_level
|
|||
)
|
||||
}
|
||||
|
||||
/// Box.box : a -> Box a
|
||||
fn box_box(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_1(symbol, LowLevel::BoxExpr, var_store)
|
||||
}
|
||||
|
||||
/// Box.unbox : Box a -> a
|
||||
fn box_unbox(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_1(symbol, LowLevel::UnboxExpr, var_store)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn defn_help(
|
||||
fn_name: Symbol,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::expected::{Expected, PExpected};
|
||||
use roc_collections::soa::{Index, Slice};
|
||||
use roc_collections::soa::{EitherIndex, Index, Slice};
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
|
@ -120,14 +120,27 @@ impl Constraints {
|
|||
pub const PCATEGORY_CHARACTER: Index<PatternCategory> = Index::new(10);
|
||||
|
||||
#[inline(always)]
|
||||
pub fn push_type(&mut self, typ: Type) -> Index<Type> {
|
||||
pub fn push_type(&mut self, typ: Type) -> EitherIndex<Type, Variable> {
|
||||
match typ {
|
||||
Type::EmptyRec => Self::EMPTY_RECORD,
|
||||
Type::EmptyTagUnion => Self::EMPTY_TAG_UNION,
|
||||
other => Index::push_new(&mut self.types, other),
|
||||
Type::EmptyRec => EitherIndex::from_left(Self::EMPTY_RECORD),
|
||||
Type::EmptyTagUnion => EitherIndex::from_left(Self::EMPTY_TAG_UNION),
|
||||
Type::Variable(var) => Self::push_type_variable(var),
|
||||
other => {
|
||||
let index: Index<Type> = Index::push_new(&mut self.types, other);
|
||||
EitherIndex::from_left(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn push_type_variable(var: Variable) -> EitherIndex<Type, Variable> {
|
||||
// that's right, we use the variable's integer value as the index
|
||||
// that way, we don't need to push anything onto a vector
|
||||
let index: Index<Variable> = Index::new(var.index());
|
||||
|
||||
EitherIndex::from_right(index)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn push_expected_type(&mut self, expected: Expected<Type>) -> Index<Expected<Type>> {
|
||||
Index::push_new(&mut self.expectations, expected)
|
||||
|
@ -180,13 +193,56 @@ impl Constraints {
|
|||
category: Category,
|
||||
region: Region,
|
||||
) -> Constraint {
|
||||
let type_index = Index::push_new(&mut self.types, typ);
|
||||
let type_index = self.push_type(typ);
|
||||
let expected_index = Index::push_new(&mut self.expectations, expected);
|
||||
let category_index = Self::push_category(self, category);
|
||||
|
||||
Constraint::Eq(type_index, expected_index, category_index, region)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn equal_types_var(
|
||||
&mut self,
|
||||
var: Variable,
|
||||
expected: Expected<Type>,
|
||||
category: Category,
|
||||
region: Region,
|
||||
) -> Constraint {
|
||||
let type_index = Self::push_type_variable(var);
|
||||
let expected_index = Index::push_new(&mut self.expectations, expected);
|
||||
let category_index = Self::push_category(self, category);
|
||||
|
||||
Constraint::Eq(type_index, expected_index, category_index, region)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn equal_types_with_storage(
|
||||
&mut self,
|
||||
typ: Type,
|
||||
expected: Expected<Type>,
|
||||
category: Category,
|
||||
region: Region,
|
||||
storage_var: Variable,
|
||||
) -> Constraint {
|
||||
let type_index = self.push_type(typ);
|
||||
let expected_index = Index::push_new(&mut self.expectations, expected);
|
||||
let category_index = Self::push_category(self, category);
|
||||
|
||||
let equal = Constraint::Eq(type_index, expected_index, category_index, region);
|
||||
|
||||
let storage_type_index = Self::push_type_variable(storage_var);
|
||||
let storage_category = Category::Storage(std::file!(), std::line!());
|
||||
let storage_category_index = Self::push_category(self, storage_category);
|
||||
let storage = Constraint::Eq(
|
||||
storage_type_index,
|
||||
expected_index,
|
||||
storage_category_index,
|
||||
region,
|
||||
);
|
||||
|
||||
self.and_constraint([equal, storage])
|
||||
}
|
||||
|
||||
pub fn equal_pattern_types(
|
||||
&mut self,
|
||||
typ: Type,
|
||||
|
@ -194,7 +250,7 @@ impl Constraints {
|
|||
category: PatternCategory,
|
||||
region: Region,
|
||||
) -> Constraint {
|
||||
let type_index = Index::push_new(&mut self.types, typ);
|
||||
let type_index = self.push_type(typ);
|
||||
let expected_index = Index::push_new(&mut self.pattern_expectations, expected);
|
||||
let category_index = Self::push_pattern_category(self, category);
|
||||
|
||||
|
@ -208,7 +264,7 @@ impl Constraints {
|
|||
category: PatternCategory,
|
||||
region: Region,
|
||||
) -> Constraint {
|
||||
let type_index = Index::push_new(&mut self.types, typ);
|
||||
let type_index = self.push_type(typ);
|
||||
let expected_index = Index::push_new(&mut self.pattern_expectations, expected);
|
||||
let category_index = Index::push_new(&mut self.pattern_categories, category);
|
||||
|
||||
|
@ -216,7 +272,7 @@ impl Constraints {
|
|||
}
|
||||
|
||||
pub fn is_open_type(&mut self, typ: Type) -> Constraint {
|
||||
let type_index = Index::push_new(&mut self.types, typ);
|
||||
let type_index = self.push_type(typ);
|
||||
|
||||
Constraint::IsOpenType(type_index)
|
||||
}
|
||||
|
@ -309,7 +365,7 @@ impl Constraints {
|
|||
let let_index = Index::new(self.let_constraints.len() as _);
|
||||
self.let_constraints.push(let_contraint);
|
||||
|
||||
Constraint::Let(let_index)
|
||||
Constraint::Let(let_index, Slice::default())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -335,7 +391,7 @@ impl Constraints {
|
|||
let let_index = Index::new(self.let_constraints.len() as _);
|
||||
self.let_constraints.push(let_contraint);
|
||||
|
||||
Constraint::Let(let_index)
|
||||
Constraint::Let(let_index, Slice::default())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -353,6 +409,7 @@ impl Constraints {
|
|||
I3: IntoIterator<Item = (Symbol, Loc<Type>)>,
|
||||
I3::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
// defs and ret constraint are stored consequtively, so we only need to store one index
|
||||
let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
|
||||
|
||||
self.constraints.push(defs_constraint);
|
||||
|
@ -368,7 +425,55 @@ impl Constraints {
|
|||
let let_index = Index::new(self.let_constraints.len() as _);
|
||||
self.let_constraints.push(let_contraint);
|
||||
|
||||
Constraint::Let(let_index)
|
||||
Constraint::Let(let_index, Slice::default())
|
||||
}
|
||||
|
||||
/// A variant of `Let` used specifically for imports. When importing types from another module,
|
||||
/// we use a StorageSubs to store the data, and copy over the relevant
|
||||
/// variables/content/flattype/tagname etc.
|
||||
///
|
||||
/// The general idea is to let-generalize the imorted types in the target module.
|
||||
/// More concretely, we need to simulate what `type_to_var` (solve.rs) does to a `Type`.
|
||||
/// While the copying puts all the data the right place, it misses that `type_to_var` puts
|
||||
/// the variables that it creates (to store the nodes of a Type in Subs) in the pool of the
|
||||
/// current rank (so they can be generalized).
|
||||
///
|
||||
/// So, during copying of an import (`copy_import_to`, subs.rs) we track the variables that
|
||||
/// we need to put into the pool (simulating what `type_to_var` would do). Those variables
|
||||
/// then need to find their way to the pool, and a convenient approach turned out to be to
|
||||
/// tag them onto the `Let` that we used to add the imported values.
|
||||
#[inline(always)]
|
||||
pub fn let_import_constraint<I1, I2>(
|
||||
&mut self,
|
||||
rigid_vars: I1,
|
||||
def_types: I2,
|
||||
module_constraint: Constraint,
|
||||
pool_variables: &[Variable],
|
||||
) -> Constraint
|
||||
where
|
||||
I1: IntoIterator<Item = Variable>,
|
||||
I2: IntoIterator<Item = (Symbol, Loc<Type>)>,
|
||||
I2::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
// defs and ret constraint are stored consequtively, so we only need to store one index
|
||||
let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
|
||||
|
||||
self.constraints.push(Constraint::True);
|
||||
self.constraints.push(module_constraint);
|
||||
|
||||
let let_contraint = LetConstraint {
|
||||
rigid_vars: self.variable_slice(rigid_vars),
|
||||
flex_vars: Slice::default(),
|
||||
def_types: self.def_types_slice(def_types),
|
||||
defs_and_ret_constraint,
|
||||
};
|
||||
|
||||
let let_index = Index::new(self.let_constraints.len() as _);
|
||||
self.let_constraints.push(let_contraint);
|
||||
|
||||
let pool_slice = self.variable_slice(pool_variables.iter().copied());
|
||||
|
||||
Constraint::Let(let_index, pool_slice)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -408,6 +513,7 @@ impl Constraints {
|
|||
region,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool {
|
||||
match constraint {
|
||||
Constraint::Eq(..) => false,
|
||||
|
@ -416,7 +522,7 @@ impl Constraints {
|
|||
Constraint::Pattern(..) => false,
|
||||
Constraint::True => false,
|
||||
Constraint::SaveTheEnvironment => true,
|
||||
Constraint::Let(index) => {
|
||||
Constraint::Let(index, _) => {
|
||||
let let_constraint = &self.let_constraints[index.index()];
|
||||
|
||||
let offset = let_constraint.defs_and_ret_constraint.index();
|
||||
|
@ -446,35 +552,63 @@ impl Constraints {
|
|||
filename: &'static str,
|
||||
line_number: u32,
|
||||
) -> Constraint {
|
||||
let type_index = Index::push_new(&mut self.types, typ);
|
||||
let type_index = self.push_type(typ);
|
||||
let string_index = Index::push_new(&mut self.strings, filename);
|
||||
|
||||
Constraint::Store(type_index, variable, string_index, line_number)
|
||||
}
|
||||
|
||||
pub fn store_index(
|
||||
&mut self,
|
||||
type_index: EitherIndex<Type, Variable>,
|
||||
variable: Variable,
|
||||
filename: &'static str,
|
||||
line_number: u32,
|
||||
) -> Constraint {
|
||||
let string_index = Index::push_new(&mut self.strings, filename);
|
||||
|
||||
Constraint::Store(type_index, variable, string_index, line_number)
|
||||
}
|
||||
}
|
||||
|
||||
static_assertions::assert_eq_size!([u8; 3 * 8], Constraint);
|
||||
roc_error_macros::assert_sizeof_default!(Constraint, 3 * 8);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Constraint {
|
||||
Eq(Index<Type>, Index<Expected<Type>>, Index<Category>, Region),
|
||||
Store(Index<Type>, Variable, Index<&'static str>, u32),
|
||||
Eq(
|
||||
EitherIndex<Type, Variable>,
|
||||
Index<Expected<Type>>,
|
||||
Index<Category>,
|
||||
Region,
|
||||
),
|
||||
Store(
|
||||
EitherIndex<Type, Variable>,
|
||||
Variable,
|
||||
Index<&'static str>,
|
||||
u32,
|
||||
),
|
||||
Lookup(Symbol, Index<Expected<Type>>, Region),
|
||||
Pattern(
|
||||
Index<Type>,
|
||||
EitherIndex<Type, Variable>,
|
||||
Index<PExpected<Type>>,
|
||||
Index<PatternCategory>,
|
||||
Region,
|
||||
),
|
||||
True, // Used for things that always unify, e.g. blanks and runtime errors
|
||||
/// Used for things that always unify, e.g. blanks and runtime errors
|
||||
True,
|
||||
SaveTheEnvironment,
|
||||
Let(Index<LetConstraint>),
|
||||
/// A Let constraint introduces symbols and their annotation at a certain level of nesting
|
||||
///
|
||||
/// The `Slice<Variable>` is used for imports where we manually put the Content into Subs
|
||||
/// by copying from another module, but have to make sure that any variables we use to store
|
||||
/// these contents are added to `Pool` at the correct rank
|
||||
Let(Index<LetConstraint>, Slice<Variable>),
|
||||
And(Slice<Constraint>),
|
||||
/// Presence constraints
|
||||
IsOpenType(Index<Type>), // Theory; always applied to a variable? if yes the use that
|
||||
IsOpenType(EitherIndex<Type, Variable>), // Theory; always applied to a variable? if yes the use that
|
||||
IncludesTag(Index<IncludesTag>),
|
||||
PatternPresence(
|
||||
Index<Type>,
|
||||
EitherIndex<Type, Variable>,
|
||||
Index<PExpected<Type>>,
|
||||
Index<PatternCategory>,
|
||||
Region,
|
||||
|
@ -503,3 +637,36 @@ pub struct IncludesTag {
|
|||
pub pattern_category: Index<PatternCategory>,
|
||||
pub region: Region,
|
||||
}
|
||||
|
||||
/// Custom impl to limit vertical space used by the debug output
|
||||
impl std::fmt::Debug for Constraint {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Eq(arg0, arg1, arg2, arg3) => {
|
||||
write!(f, "Eq({:?}, {:?}, {:?}, {:?})", arg0, arg1, arg2, arg3)
|
||||
}
|
||||
Self::Store(arg0, arg1, arg2, arg3) => {
|
||||
write!(f, "Store({:?}, {:?}, {:?}, {:?})", arg0, arg1, arg2, arg3)
|
||||
}
|
||||
Self::Lookup(arg0, arg1, arg2) => {
|
||||
write!(f, "Lookup({:?}, {:?}, {:?})", arg0, arg1, arg2)
|
||||
}
|
||||
Self::Pattern(arg0, arg1, arg2, arg3) => {
|
||||
write!(f, "Pattern({:?}, {:?}, {:?}, {:?})", arg0, arg1, arg2, arg3)
|
||||
}
|
||||
Self::True => write!(f, "True"),
|
||||
Self::SaveTheEnvironment => write!(f, "SaveTheEnvironment"),
|
||||
Self::Let(arg0, arg1) => f.debug_tuple("Let").field(arg0).field(arg1).finish(),
|
||||
Self::And(arg0) => f.debug_tuple("And").field(arg0).finish(),
|
||||
Self::IsOpenType(arg0) => f.debug_tuple("IsOpenType").field(arg0).finish(),
|
||||
Self::IncludesTag(arg0) => f.debug_tuple("IncludesTag").field(arg0).finish(),
|
||||
Self::PatternPresence(arg0, arg1, arg2, arg3) => {
|
||||
write!(
|
||||
f,
|
||||
"PatternPresence({:?}, {:?}, {:?}, {:?})",
|
||||
arg0, arg1, arg2, arg3
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::procedure::References;
|
|||
use crate::scope::create_alias;
|
||||
use crate::scope::Scope;
|
||||
use roc_collections::all::{default_hasher, ImMap, ImSet, MutMap, MutSet, SendMap};
|
||||
use roc_error_macros::todo_abilities;
|
||||
use roc_module::ident::Lowercase;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_parse::ast;
|
||||
|
@ -286,21 +287,19 @@ pub fn canonicalize_defs<'a>(
|
|||
|
||||
// Record all the annotation's references in output.references.lookups
|
||||
for symbol in can_ann.references {
|
||||
output.references.lookups.insert(symbol);
|
||||
output.references.type_lookups.insert(symbol);
|
||||
output.references.referenced_type_defs.insert(symbol);
|
||||
}
|
||||
|
||||
let mut can_vars: Vec<Loc<(Lowercase, Variable)>> = Vec::with_capacity(vars.len());
|
||||
let mut is_phantom = false;
|
||||
|
||||
let mut var_by_name = can_ann.introduced_variables.var_by_name.clone();
|
||||
for loc_lowercase in vars.iter() {
|
||||
if let Some(var) = can_ann
|
||||
.introduced_variables
|
||||
.var_by_name(&loc_lowercase.value)
|
||||
{
|
||||
if let Some(var) = var_by_name.remove(&loc_lowercase.value) {
|
||||
// This is a valid lowercase rigid var for the type def.
|
||||
can_vars.push(Loc {
|
||||
value: (loc_lowercase.value.clone(), *var),
|
||||
value: (loc_lowercase.value.clone(), var.value),
|
||||
region: loc_lowercase.region,
|
||||
});
|
||||
} else {
|
||||
|
@ -319,6 +318,33 @@ pub fn canonicalize_defs<'a>(
|
|||
continue;
|
||||
}
|
||||
|
||||
let IntroducedVariables {
|
||||
wildcards,
|
||||
inferred,
|
||||
..
|
||||
} = can_ann.introduced_variables;
|
||||
let num_unbound = var_by_name.len() + wildcards.len() + inferred.len();
|
||||
if num_unbound > 0 {
|
||||
let one_occurrence = var_by_name
|
||||
.iter()
|
||||
.map(|(_, v)| v)
|
||||
.chain(wildcards.iter())
|
||||
.chain(inferred.iter())
|
||||
.next()
|
||||
.unwrap()
|
||||
.region;
|
||||
|
||||
env.problems.push(Problem::UnboundTypeVariable {
|
||||
typ: symbol,
|
||||
num_unbound,
|
||||
one_occurrence,
|
||||
kind,
|
||||
});
|
||||
|
||||
// Bail out
|
||||
continue;
|
||||
}
|
||||
|
||||
let alias = create_alias(
|
||||
symbol,
|
||||
name.region,
|
||||
|
@ -331,7 +357,7 @@ pub fn canonicalize_defs<'a>(
|
|||
|
||||
// Now that we know the alias dependency graph, we can try to insert recursion variables
|
||||
// where aliases are recursive tag unions, or detect illegal recursions.
|
||||
let mut aliases = correct_mutual_recursive_type_alias(env, &aliases, var_store);
|
||||
let mut aliases = correct_mutual_recursive_type_alias(env, aliases, var_store);
|
||||
for (symbol, alias) in aliases.iter() {
|
||||
scope.add_alias(
|
||||
*symbol,
|
||||
|
@ -383,7 +409,8 @@ pub fn canonicalize_defs<'a>(
|
|||
CanDefs {
|
||||
refs_by_symbol,
|
||||
can_defs_by_symbol,
|
||||
aliases,
|
||||
// The result needs a thread-safe `SendMap`
|
||||
aliases: aliases.into_iter().collect(),
|
||||
},
|
||||
scope,
|
||||
output,
|
||||
|
@ -409,7 +436,7 @@ pub fn sort_can_defs(
|
|||
|
||||
// Determine the full set of references by traversing the graph.
|
||||
let mut visited_symbols = MutSet::default();
|
||||
let returned_lookups = ImSet::clone(&output.references.lookups);
|
||||
let returned_lookups = ImSet::clone(&output.references.value_lookups);
|
||||
|
||||
// Start with the return expression's referenced locals. They're the only ones that count!
|
||||
//
|
||||
|
@ -482,10 +509,10 @@ pub fn sort_can_defs(
|
|||
let mut loc_succ = local_successors(references, &env.closures);
|
||||
|
||||
// if the current symbol is a closure, peek into its body
|
||||
if let Some(References { lookups, .. }) = env.closures.get(symbol) {
|
||||
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
||||
let home = env.home;
|
||||
|
||||
for lookup in lookups {
|
||||
for lookup in value_lookups {
|
||||
if lookup != symbol && lookup.module_id() == home {
|
||||
// DO NOT register a self-call behind a lambda!
|
||||
//
|
||||
|
@ -532,8 +559,8 @@ pub fn sort_can_defs(
|
|||
let mut loc_succ = local_successors(references, &env.closures);
|
||||
|
||||
// if the current symbol is a closure, peek into its body
|
||||
if let Some(References { lookups, .. }) = env.closures.get(symbol) {
|
||||
for lookup in lookups {
|
||||
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
||||
for lookup in value_lookups {
|
||||
loc_succ.insert(*lookup);
|
||||
}
|
||||
}
|
||||
|
@ -901,7 +928,7 @@ fn canonicalize_pending_def<'a>(
|
|||
can_defs_by_symbol: &mut MutMap<Symbol, Def>,
|
||||
var_store: &mut VarStore,
|
||||
refs_by_symbol: &mut MutMap<Symbol, (Region, References)>,
|
||||
aliases: &mut SendMap<Symbol, Alias>,
|
||||
aliases: &mut ImMap<Symbol, Alias>,
|
||||
) -> Output {
|
||||
use PendingDef::*;
|
||||
|
||||
|
@ -919,7 +946,7 @@ fn canonicalize_pending_def<'a>(
|
|||
// Record all the annotation's references in output.references.lookups
|
||||
|
||||
for symbol in type_annotation.references.iter() {
|
||||
output.references.lookups.insert(*symbol);
|
||||
output.references.type_lookups.insert(*symbol);
|
||||
output.references.referenced_type_defs.insert(*symbol);
|
||||
}
|
||||
|
||||
|
@ -1041,7 +1068,7 @@ fn canonicalize_pending_def<'a>(
|
|||
|
||||
// Record all the annotation's references in output.references.lookups
|
||||
for symbol in type_annotation.references.iter() {
|
||||
output.references.lookups.insert(*symbol);
|
||||
output.references.type_lookups.insert(*symbol);
|
||||
output.references.referenced_type_defs.insert(*symbol);
|
||||
}
|
||||
|
||||
|
@ -1121,7 +1148,7 @@ fn canonicalize_pending_def<'a>(
|
|||
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
||||
// would result in circular def errors!)
|
||||
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
||||
refs.lookups = refs.lookups.without(&symbol);
|
||||
refs.value_lookups = refs.value_lookups.without(&symbol);
|
||||
});
|
||||
|
||||
// renamed_closure_def = Some(&symbol);
|
||||
|
@ -1261,7 +1288,7 @@ fn canonicalize_pending_def<'a>(
|
|||
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
||||
// would result in circular def errors!)
|
||||
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
||||
refs.lookups = refs.lookups.without(&symbol);
|
||||
refs.value_lookups = refs.value_lookups.without(&symbol);
|
||||
});
|
||||
|
||||
loc_can_expr.value = Closure(ClosureData {
|
||||
|
@ -1356,7 +1383,8 @@ pub fn can_defs_with_return<'a>(
|
|||
// Now that we've collected all the references, check to see if any of the new idents
|
||||
// we defined went unused by the return expression. If any were unused, report it.
|
||||
for (symbol, region) in symbols_introduced {
|
||||
if !output.references.has_lookup(symbol) {
|
||||
if !output.references.has_value_lookup(symbol) && !output.references.has_type_lookup(symbol)
|
||||
{
|
||||
env.problem(Problem::UnusedDef(symbol, region));
|
||||
}
|
||||
}
|
||||
|
@ -1587,6 +1615,8 @@ fn to_pending_def<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
Ability { .. } => todo_abilities!(),
|
||||
|
||||
Expect(_condition) => todo!(),
|
||||
|
||||
SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => {
|
||||
|
@ -1625,16 +1655,12 @@ fn pending_typed_body<'a>(
|
|||
/// Make aliases recursive
|
||||
fn correct_mutual_recursive_type_alias<'a>(
|
||||
env: &mut Env<'a>,
|
||||
original_aliases: &SendMap<Symbol, Alias>,
|
||||
mut original_aliases: SendMap<Symbol, Alias>,
|
||||
var_store: &mut VarStore,
|
||||
) -> SendMap<Symbol, Alias> {
|
||||
let mut symbols_introduced = ImSet::default();
|
||||
) -> ImMap<Symbol, Alias> {
|
||||
let symbols_introduced: Vec<Symbol> = original_aliases.keys().copied().collect();
|
||||
|
||||
for (key, _) in original_aliases.iter() {
|
||||
symbols_introduced.insert(*key);
|
||||
}
|
||||
|
||||
let all_successors_with_self = |symbol: &Symbol| -> ImSet<Symbol> {
|
||||
let all_successors_with_self = |symbol: &Symbol| -> Vec<Symbol> {
|
||||
match original_aliases.get(symbol) {
|
||||
Some(alias) => {
|
||||
let mut loc_succ = alias.typ.symbols();
|
||||
|
@ -1643,7 +1669,7 @@ fn correct_mutual_recursive_type_alias<'a>(
|
|||
|
||||
loc_succ
|
||||
}
|
||||
None => ImSet::default(),
|
||||
None => vec![],
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1651,44 +1677,39 @@ fn correct_mutual_recursive_type_alias<'a>(
|
|||
let defined_symbols: Vec<Symbol> = original_aliases.keys().copied().collect();
|
||||
|
||||
let cycles = strongly_connected_components(&defined_symbols, all_successors_with_self);
|
||||
let mut solved_aliases = SendMap::default();
|
||||
let mut solved_aliases = ImMap::default();
|
||||
|
||||
for cycle in cycles {
|
||||
debug_assert!(!cycle.is_empty());
|
||||
|
||||
let mut pending_aliases: SendMap<_, _> = cycle
|
||||
let mut pending_aliases: ImMap<_, _> = cycle
|
||||
.iter()
|
||||
.map(|&sym| (sym, original_aliases.get(&sym).unwrap().clone()))
|
||||
.map(|&sym| (sym, original_aliases.remove(&sym).unwrap()))
|
||||
.collect();
|
||||
|
||||
// Make sure we report only one error for the cycle, not an error for every
|
||||
// alias in the cycle.
|
||||
let mut can_still_report_error = true;
|
||||
|
||||
for &rec in cycle.iter() {
|
||||
// First, we need to instantiate the alias with any symbols in the currrent module it
|
||||
// depends on.
|
||||
// We only need to worry about symbols in this SCC or any prior one, since the SCCs
|
||||
// were sorted topologically, and we've already instantiated aliases coming from other
|
||||
// modules.
|
||||
let mut to_instantiate: ImMap<_, _> = solved_aliases.clone().into_iter().collect();
|
||||
let mut others_in_scc = Vec::with_capacity(cycle.len() - 1);
|
||||
for &other in cycle.iter() {
|
||||
if rec != other {
|
||||
others_in_scc.push(other);
|
||||
if let Some(alias) = original_aliases.get(&other) {
|
||||
to_instantiate.insert(other, alias.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
// We need to instantiate the alias with any symbols in the currrent module it
|
||||
// depends on.
|
||||
// We only need to worry about symbols in this SCC or any prior one, since the SCCs
|
||||
// were sorted topologically, and we've already instantiated aliases coming from other
|
||||
// modules.
|
||||
// NB: ImMap::clone is O(1): https://docs.rs/im/latest/src/im/hash/map.rs.html#1527-1544
|
||||
let mut to_instantiate = solved_aliases.clone().union(pending_aliases.clone());
|
||||
|
||||
for &rec in cycle.iter() {
|
||||
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();
|
||||
alias.typ.instantiate_aliases(
|
||||
alias.region,
|
||||
&to_instantiate,
|
||||
var_store,
|
||||
&mut ImSet::default(),
|
||||
);
|
||||
to_instantiate.insert(rec, original_alias_def);
|
||||
|
||||
// Now mark the alias recursive, if it needs to be.
|
||||
let is_self_recursive = alias.typ.contains_symbol(rec);
|
||||
|
@ -1752,7 +1773,7 @@ fn make_tag_union_of_alias_recursive<'a>(
|
|||
.map(|l| (l.value.0.clone(), Type::Variable(l.value.1)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
make_tag_union_recursive_help(
|
||||
let made_recursive = make_tag_union_recursive_help(
|
||||
env,
|
||||
Loc::at(alias.header_region(), (alias_name, &alias_args)),
|
||||
alias.region,
|
||||
|
@ -1760,7 +1781,24 @@ fn make_tag_union_of_alias_recursive<'a>(
|
|||
&mut alias.typ,
|
||||
var_store,
|
||||
can_report_error,
|
||||
)
|
||||
);
|
||||
|
||||
match made_recursive {
|
||||
MakeTagUnionRecursive::Cyclic => Ok(()),
|
||||
MakeTagUnionRecursive::MadeRecursive { recursion_variable } => {
|
||||
alias.recursion_variables.clear();
|
||||
alias.recursion_variables.insert(recursion_variable);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
MakeTagUnionRecursive::InvalidRecursion => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
enum MakeTagUnionRecursive {
|
||||
Cyclic,
|
||||
MadeRecursive { recursion_variable: Variable },
|
||||
InvalidRecursion,
|
||||
}
|
||||
|
||||
/// Attempt to make a tag union recursive at the position of `recursive_alias`; for example,
|
||||
|
@ -1792,7 +1830,9 @@ fn make_tag_union_recursive_help<'a>(
|
|||
typ: &mut Type,
|
||||
var_store: &mut VarStore,
|
||||
can_report_error: &mut bool,
|
||||
) -> Result<(), ()> {
|
||||
) -> MakeTagUnionRecursive {
|
||||
use MakeTagUnionRecursive::*;
|
||||
|
||||
let Loc {
|
||||
value: (symbol, args),
|
||||
region: alias_region,
|
||||
|
@ -1800,15 +1840,17 @@ fn make_tag_union_recursive_help<'a>(
|
|||
let vars = args.iter().map(|(_, t)| t.clone()).collect::<Vec<_>>();
|
||||
match typ {
|
||||
Type::TagUnion(tags, ext) => {
|
||||
let rec_var = var_store.fresh();
|
||||
let mut pending_typ = Type::RecursiveTagUnion(rec_var, tags.to_vec(), ext.clone());
|
||||
let recursion_variable = var_store.fresh();
|
||||
let mut pending_typ =
|
||||
Type::RecursiveTagUnion(recursion_variable, tags.to_vec(), ext.clone());
|
||||
let substitution_result =
|
||||
pending_typ.substitute_alias(symbol, &vars, &Type::Variable(rec_var));
|
||||
pending_typ.substitute_alias(symbol, &vars, &Type::Variable(recursion_variable));
|
||||
match substitution_result {
|
||||
Ok(()) => {
|
||||
// We can substitute the alias presence for the variable exactly.
|
||||
*typ = pending_typ;
|
||||
Ok(())
|
||||
|
||||
MadeRecursive { recursion_variable }
|
||||
}
|
||||
Err(differing_recursion_region) => {
|
||||
env.problems.push(Problem::NestedDatatype {
|
||||
|
@ -1816,11 +1858,14 @@ fn make_tag_union_recursive_help<'a>(
|
|||
def_region: alias_region,
|
||||
differing_recursion_region,
|
||||
});
|
||||
Err(())
|
||||
|
||||
InvalidRecursion
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::RecursiveTagUnion(_, _, _) => Ok(()),
|
||||
Type::RecursiveTagUnion(recursion_variable, _, _) => MadeRecursive {
|
||||
recursion_variable: *recursion_variable,
|
||||
},
|
||||
Type::Alias {
|
||||
actual,
|
||||
type_arguments,
|
||||
|
@ -1838,7 +1883,7 @@ fn make_tag_union_recursive_help<'a>(
|
|||
mark_cyclic_alias(env, typ, symbol, region, others, *can_report_error);
|
||||
*can_report_error = false;
|
||||
|
||||
Ok(())
|
||||
Cyclic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use roc_module::ident::TagName;
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{AliasKind, Type};
|
||||
use roc_types::types::{AliasKind, Type, TypeExtension};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub(crate) struct HostedGeneratedFunctions {
|
||||
|
@ -210,7 +210,7 @@ fn build_effect_always(
|
|||
let signature = {
|
||||
// Effect.always : a -> Effect a
|
||||
let var_a = var_store.fresh();
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
|
||||
let effect_a = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -223,7 +223,7 @@ fn build_effect_always(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
Type::Function(
|
||||
vec![Type::Variable(var_a)],
|
||||
|
@ -402,8 +402,8 @@ fn build_effect_map(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_a = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -426,7 +426,7 @@ fn build_effect_map(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
let a_to_b = {
|
||||
Type::Function(
|
||||
vec![Type::Variable(var_a)],
|
||||
|
@ -436,7 +436,7 @@ fn build_effect_map(
|
|||
};
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
Type::Function(
|
||||
vec![effect_a, a_to_b],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
|
@ -571,8 +571,8 @@ fn build_effect_after(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_a = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -595,7 +595,7 @@ fn build_effect_after(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
let a_to_effect_b = Type::Function(
|
||||
vec![Type::Variable(var_a)],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
|
@ -603,7 +603,7 @@ fn build_effect_after(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
Type::Function(
|
||||
vec![effect_a, a_to_effect_b],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
|
@ -831,8 +831,8 @@ fn build_effect_forever(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_a = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -855,7 +855,7 @@ fn build_effect_forever(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
Type::Function(
|
||||
vec![effect_a],
|
||||
|
@ -1089,8 +1089,8 @@ fn build_effect_loop(
|
|||
let var_a = var_store.fresh();
|
||||
let var_b = var_store.fresh();
|
||||
|
||||
introduced_variables.insert_named("a".into(), var_a);
|
||||
introduced_variables.insert_named("b".into(), var_b);
|
||||
introduced_variables.insert_named("a".into(), Loc::at_zero(var_a));
|
||||
introduced_variables.insert_named("b".into(), Loc::at_zero(var_b));
|
||||
|
||||
let effect_b = build_effect_alias(
|
||||
effect_symbol,
|
||||
|
@ -1111,13 +1111,13 @@ fn build_effect_loop(
|
|||
(step_tag_name, vec![Type::Variable(var_a)]),
|
||||
(done_tag_name, vec![Type::Variable(var_b)]),
|
||||
],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
};
|
||||
|
||||
let effect_state_type = {
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
let actual = {
|
||||
Type::TagUnion(
|
||||
|
@ -1129,7 +1129,7 @@ fn build_effect_loop(
|
|||
Box::new(state_type.clone()),
|
||||
)],
|
||||
)],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1145,7 +1145,7 @@ fn build_effect_loop(
|
|||
};
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
let step_type = Type::Function(
|
||||
vec![Type::Variable(var_a)],
|
||||
|
@ -1154,7 +1154,7 @@ fn build_effect_loop(
|
|||
);
|
||||
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
Type::Function(
|
||||
vec![Type::Variable(var_a), step_type],
|
||||
|
@ -1559,7 +1559,7 @@ fn build_effect_alias(
|
|||
introduced_variables: &mut IntroducedVariables,
|
||||
) -> Type {
|
||||
let closure_var = var_store.fresh();
|
||||
introduced_variables.insert_wildcard(closure_var);
|
||||
introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
|
||||
|
||||
let actual = {
|
||||
Type::TagUnion(
|
||||
|
@ -1571,7 +1571,7 @@ fn build_effect_alias(
|
|||
Box::new(a_type),
|
||||
)],
|
||||
)],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1600,7 +1600,7 @@ pub fn build_effect_actual(
|
|||
Box::new(a_type),
|
||||
)],
|
||||
)],
|
||||
Box::new(Type::EmptyTagUnion),
|
||||
TypeExtension::Closed,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,11 @@ pub struct Env<'a> {
|
|||
/// current closure name (if any)
|
||||
pub closure_name_symbol: Option<Symbol>,
|
||||
|
||||
/// Symbols which were referenced by qualified lookups.
|
||||
pub qualified_lookups: MutSet<Symbol>,
|
||||
/// Symbols of values/functions which were referenced by qualified lookups.
|
||||
pub qualified_value_lookups: MutSet<Symbol>,
|
||||
|
||||
/// Symbols of types which were referenced by qualified lookups.
|
||||
pub qualified_type_lookups: MutSet<Symbol>,
|
||||
|
||||
pub top_level_symbols: MutSet<Symbol>,
|
||||
|
||||
|
@ -51,7 +54,8 @@ impl<'a> Env<'a> {
|
|||
exposed_ident_ids,
|
||||
problems: Vec::new(),
|
||||
closures: MutMap::default(),
|
||||
qualified_lookups: MutSet::default(),
|
||||
qualified_value_lookups: MutSet::default(),
|
||||
qualified_type_lookups: MutSet::default(),
|
||||
tailcallable_symbol: None,
|
||||
closure_name_symbol: None,
|
||||
top_level_symbols: MutSet::default(),
|
||||
|
@ -71,6 +75,8 @@ impl<'a> Env<'a> {
|
|||
ident
|
||||
);
|
||||
|
||||
let is_type_name = ident.starts_with(|c: char| c.is_uppercase());
|
||||
|
||||
let module_name = ModuleName::from(module_name_str);
|
||||
let ident = Ident::from(ident);
|
||||
|
||||
|
@ -83,7 +89,11 @@ impl<'a> Env<'a> {
|
|||
Some(ident_id) => {
|
||||
let symbol = Symbol::new(module_id, *ident_id);
|
||||
|
||||
self.qualified_lookups.insert(symbol);
|
||||
if is_type_name {
|
||||
self.qualified_type_lookups.insert(symbol);
|
||||
} else {
|
||||
self.qualified_value_lookups.insert(symbol);
|
||||
}
|
||||
|
||||
Ok(symbol)
|
||||
}
|
||||
|
@ -107,7 +117,11 @@ impl<'a> Env<'a> {
|
|||
Some(ident_id) => {
|
||||
let symbol = Symbol::new(module_id, *ident_id);
|
||||
|
||||
self.qualified_lookups.insert(symbol);
|
||||
if is_type_name {
|
||||
self.qualified_type_lookups.insert(symbol);
|
||||
} else {
|
||||
self.qualified_value_lookups.insert(symbol);
|
||||
}
|
||||
|
||||
Ok(symbol)
|
||||
}
|
||||
|
|
|
@ -493,7 +493,7 @@ pub fn canonicalize_expr<'a>(
|
|||
Ok((name, opaque_def)) => {
|
||||
let argument = Box::new(args.pop().unwrap());
|
||||
output.references.referenced_type_defs.insert(name);
|
||||
output.references.lookups.insert(name);
|
||||
output.references.type_lookups.insert(name);
|
||||
|
||||
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
||||
freshen_opaque_def(var_store, opaque_def);
|
||||
|
@ -587,7 +587,7 @@ pub fn canonicalize_expr<'a>(
|
|||
}
|
||||
}
|
||||
ast::Expr::Var { module_name, ident } => {
|
||||
canonicalize_lookup(env, scope, module_name, ident, region)
|
||||
canonicalize_var_lookup(env, scope, module_name, ident, region)
|
||||
}
|
||||
ast::Expr::Underscore(name) => {
|
||||
// we parse underscores, but they are not valid expression syntax
|
||||
|
@ -661,8 +661,12 @@ pub fn canonicalize_expr<'a>(
|
|||
&loc_body_expr.value,
|
||||
);
|
||||
|
||||
let mut captured_symbols: MutSet<Symbol> =
|
||||
new_output.references.lookups.iter().copied().collect();
|
||||
let mut captured_symbols: MutSet<Symbol> = new_output
|
||||
.references
|
||||
.value_lookups
|
||||
.iter()
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
// filter out the closure's name itself
|
||||
captured_symbols.remove(&symbol);
|
||||
|
@ -684,7 +688,10 @@ pub fn canonicalize_expr<'a>(
|
|||
output.union(new_output);
|
||||
|
||||
// filter out aliases
|
||||
captured_symbols.retain(|s| !output.references.referenced_type_defs.contains(s));
|
||||
debug_assert!(captured_symbols
|
||||
.iter()
|
||||
.all(|s| !output.references.referenced_type_defs.contains(s)));
|
||||
// captured_symbols.retain(|s| !output.references.referenced_type_defs.contains(s));
|
||||
|
||||
// filter out functions that don't close over anything
|
||||
captured_symbols.retain(|s| !output.non_closures.contains(s));
|
||||
|
@ -693,7 +700,7 @@ pub fn canonicalize_expr<'a>(
|
|||
// went unreferenced. If any did, report them as unused arguments.
|
||||
for (sub_symbol, region) in scope.symbols() {
|
||||
if !original_scope.contains_symbol(*sub_symbol) {
|
||||
if !output.references.has_lookup(*sub_symbol) {
|
||||
if !output.references.has_value_lookup(*sub_symbol) {
|
||||
// The body never referenced this argument we declared. It's an unused argument!
|
||||
env.problem(Problem::UnusedArgument(symbol, *sub_symbol, *region));
|
||||
}
|
||||
|
@ -701,7 +708,7 @@ pub fn canonicalize_expr<'a>(
|
|||
// We shouldn't ultimately count arguments as referenced locals. Otherwise,
|
||||
// we end up with weird conclusions like the expression (\x -> x + 1)
|
||||
// references the (nonexistent) local variable x!
|
||||
output.references.lookups.remove(sub_symbol);
|
||||
output.references.value_lookups.remove(sub_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1082,8 +1089,10 @@ fn canonicalize_when_branch<'a>(
|
|||
for (symbol, region) in scope.symbols() {
|
||||
let symbol = *symbol;
|
||||
|
||||
if !output.references.has_lookup(symbol)
|
||||
&& !branch_output.references.has_lookup(symbol)
|
||||
if !output.references.has_value_lookup(symbol)
|
||||
&& !output.references.has_type_lookup(symbol)
|
||||
&& !branch_output.references.has_value_lookup(symbol)
|
||||
&& !branch_output.references.has_type_lookup(symbol)
|
||||
&& !original_scope.contains_symbol(symbol)
|
||||
{
|
||||
env.problem(Problem::UnusedDef(symbol, *region));
|
||||
|
@ -1107,7 +1116,7 @@ pub fn local_successors<'a>(
|
|||
references: &'a References,
|
||||
closures: &'a MutMap<Symbol, References>,
|
||||
) -> ImSet<Symbol> {
|
||||
let mut answer = references.lookups.clone();
|
||||
let mut answer = references.value_lookups.clone();
|
||||
|
||||
for call_symbol in references.calls.iter() {
|
||||
answer = answer.union(call_successors(*call_symbol, closures));
|
||||
|
@ -1127,7 +1136,7 @@ fn call_successors(call_symbol: Symbol, closures: &MutMap<Symbol, References>) -
|
|||
}
|
||||
|
||||
if let Some(references) = closures.get(&symbol) {
|
||||
answer.extend(references.lookups.iter().copied());
|
||||
answer.extend(references.value_lookups.iter().copied());
|
||||
queue.extend(references.calls.iter().copied());
|
||||
|
||||
seen.insert(symbol);
|
||||
|
@ -1152,7 +1161,7 @@ where
|
|||
Some((_, refs)) => {
|
||||
visited.insert(defined_symbol);
|
||||
|
||||
for local in refs.lookups.iter() {
|
||||
for local in refs.value_lookups.iter() {
|
||||
if !visited.contains(local) {
|
||||
let other_refs: References =
|
||||
references_from_local(*local, visited, refs_by_def, closures);
|
||||
|
@ -1160,7 +1169,7 @@ where
|
|||
answer = answer.union(other_refs);
|
||||
}
|
||||
|
||||
answer.lookups.insert(*local);
|
||||
answer.value_lookups.insert(*local);
|
||||
}
|
||||
|
||||
for call in refs.calls.iter() {
|
||||
|
@ -1194,7 +1203,7 @@ where
|
|||
|
||||
visited.insert(call_symbol);
|
||||
|
||||
for closed_over_local in references.lookups.iter() {
|
||||
for closed_over_local in references.value_lookups.iter() {
|
||||
if !visited.contains(closed_over_local) {
|
||||
let other_refs =
|
||||
references_from_local(*closed_over_local, visited, refs_by_def, closures);
|
||||
|
@ -1202,7 +1211,7 @@ where
|
|||
answer = answer.union(other_refs);
|
||||
}
|
||||
|
||||
answer.lookups.insert(*closed_over_local);
|
||||
answer.value_lookups.insert(*closed_over_local);
|
||||
}
|
||||
|
||||
for call in references.calls.iter() {
|
||||
|
@ -1335,7 +1344,7 @@ fn canonicalize_field<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn canonicalize_lookup(
|
||||
fn canonicalize_var_lookup(
|
||||
env: &mut Env<'_>,
|
||||
scope: &mut Scope,
|
||||
module_name: &str,
|
||||
|
@ -1350,7 +1359,7 @@ fn canonicalize_lookup(
|
|||
// Look it up in scope!
|
||||
match scope.lookup(&(*ident).into(), region) {
|
||||
Ok(symbol) => {
|
||||
output.references.lookups.insert(symbol);
|
||||
output.references.value_lookups.insert(symbol);
|
||||
|
||||
Var(symbol)
|
||||
}
|
||||
|
@ -1365,7 +1374,7 @@ fn canonicalize_lookup(
|
|||
// Look it up in the env!
|
||||
match env.qualified_lookup(module_name, ident, region) {
|
||||
Ok(symbol) => {
|
||||
output.references.lookups.insert(symbol);
|
||||
output.references.value_lookups.insert(symbol);
|
||||
|
||||
Var(symbol)
|
||||
}
|
||||
|
|
|
@ -23,21 +23,29 @@ pub struct Module {
|
|||
pub module_id: ModuleId,
|
||||
pub exposed_imports: MutMap<Symbol, Variable>,
|
||||
pub exposed_symbols: MutSet<Symbol>,
|
||||
pub references: MutSet<Symbol>,
|
||||
pub referenced_values: MutSet<Symbol>,
|
||||
pub referenced_types: MutSet<Symbol>,
|
||||
pub aliases: MutMap<Symbol, Alias>,
|
||||
pub rigid_variables: MutMap<Variable, Lowercase>,
|
||||
pub rigid_variables: RigidVariables,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RigidVariables {
|
||||
pub named: MutMap<Variable, Lowercase>,
|
||||
pub wildcards: MutSet<Variable>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleOutput {
|
||||
pub aliases: MutMap<Symbol, Alias>,
|
||||
pub rigid_variables: MutMap<Variable, Lowercase>,
|
||||
pub rigid_variables: RigidVariables,
|
||||
pub declarations: Vec<Declaration>,
|
||||
pub exposed_imports: MutMap<Symbol, Variable>,
|
||||
pub lookups: Vec<(Symbol, Variable, Region)>,
|
||||
pub problems: Vec<Problem>,
|
||||
pub ident_ids: IdentIds,
|
||||
pub references: MutSet<Symbol>,
|
||||
pub referenced_values: MutSet<Symbol>,
|
||||
pub referenced_types: MutSet<Symbol>,
|
||||
pub scope: Scope,
|
||||
}
|
||||
|
||||
|
@ -206,7 +214,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
|
||||
let mut lookups = Vec::with_capacity(num_deps);
|
||||
let mut rigid_variables = MutMap::default();
|
||||
let mut rigid_variables = RigidVariables::default();
|
||||
|
||||
// Exposed values are treated like defs that appear before any others, e.g.
|
||||
//
|
||||
|
@ -291,38 +299,38 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// See if any of the new idents we defined went unused.
|
||||
// If any were unused and also not exposed, report it.
|
||||
for (symbol, region) in symbols_introduced {
|
||||
if !output.references.has_lookup(symbol) && !exposed_symbols.contains(&symbol) {
|
||||
if !output.references.has_value_lookup(symbol)
|
||||
&& !output.references.has_type_lookup(symbol)
|
||||
&& !exposed_symbols.contains(&symbol)
|
||||
{
|
||||
env.problem(Problem::UnusedDef(symbol, region));
|
||||
}
|
||||
}
|
||||
|
||||
for (var, lowercase) in output.introduced_variables.name_by_var {
|
||||
rigid_variables.insert(var, lowercase.clone());
|
||||
rigid_variables.named.insert(var, lowercase.clone());
|
||||
}
|
||||
|
||||
for var in output.introduced_variables.wildcards {
|
||||
rigid_variables.insert(var, "*".into());
|
||||
rigid_variables.wildcards.insert(var.value);
|
||||
}
|
||||
|
||||
let mut references = MutSet::default();
|
||||
let mut referenced_values = MutSet::default();
|
||||
let mut referenced_types = MutSet::default();
|
||||
|
||||
// Gather up all the symbols that were referenced across all the defs' lookups.
|
||||
for symbol in output.references.lookups.iter() {
|
||||
references.insert(*symbol);
|
||||
}
|
||||
referenced_values.extend(output.references.value_lookups);
|
||||
referenced_types.extend(output.references.type_lookups);
|
||||
|
||||
// Gather up all the symbols that were referenced across all the defs' calls.
|
||||
for symbol in output.references.calls.iter() {
|
||||
references.insert(*symbol);
|
||||
}
|
||||
referenced_values.extend(output.references.calls);
|
||||
|
||||
// Gather up all the symbols that were referenced from other modules.
|
||||
for symbol in env.qualified_lookups.iter() {
|
||||
references.insert(*symbol);
|
||||
}
|
||||
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
||||
referenced_types.extend(env.qualified_type_lookups.iter().copied());
|
||||
|
||||
// add any builtins used by other builtins
|
||||
let transitive_builtins: Vec<Symbol> = references
|
||||
let transitive_builtins: Vec<Symbol> = referenced_values
|
||||
.iter()
|
||||
.filter(|s| s.is_builtin())
|
||||
.map(|s| crate::builtins::builtin_dependencies(*s))
|
||||
|
@ -330,7 +338,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
.copied()
|
||||
.collect();
|
||||
|
||||
references.extend(transitive_builtins);
|
||||
referenced_values.extend(transitive_builtins);
|
||||
|
||||
// NOTE previously we inserted builtin defs into the list of defs here
|
||||
// this is now done later, in file.rs.
|
||||
|
@ -340,7 +348,12 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// symbols from this set
|
||||
let mut exposed_but_not_defined = exposed_symbols.clone();
|
||||
|
||||
match sort_can_defs(&mut env, defs, Output::default()) {
|
||||
let new_output = Output {
|
||||
aliases: output.aliases,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
match sort_can_defs(&mut env, defs, new_output) {
|
||||
(Ok(mut declarations), output) => {
|
||||
use crate::def::Declaration::*;
|
||||
|
||||
|
@ -504,19 +517,15 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
|
||||
// Incorporate any remaining output.lookups entries into references.
|
||||
for symbol in output.references.lookups {
|
||||
references.insert(symbol);
|
||||
}
|
||||
referenced_values.extend(output.references.value_lookups);
|
||||
referenced_types.extend(output.references.type_lookups);
|
||||
|
||||
// Incorporate any remaining output.calls entries into references.
|
||||
for symbol in output.references.calls {
|
||||
references.insert(symbol);
|
||||
}
|
||||
referenced_values.extend(output.references.calls);
|
||||
|
||||
// Gather up all the symbols that were referenced from other modules.
|
||||
for symbol in env.qualified_lookups.iter() {
|
||||
references.insert(*symbol);
|
||||
}
|
||||
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
||||
referenced_types.extend(env.qualified_type_lookups.iter().copied());
|
||||
|
||||
for declaration in declarations.iter_mut() {
|
||||
match declaration {
|
||||
|
@ -530,7 +539,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
// TODO this loops over all symbols in the module, we can speed it up by having an
|
||||
// iterator over all builtin symbols
|
||||
for symbol in references.iter() {
|
||||
for symbol in referenced_values.iter() {
|
||||
if symbol.is_builtin() {
|
||||
// this can fail when the symbol is for builtin types, or has no implementation yet
|
||||
if let Some(def) = crate::builtins::builtin_defs_map(*symbol, var_store) {
|
||||
|
@ -544,7 +553,8 @@ pub fn canonicalize_module_defs<'a>(
|
|||
aliases,
|
||||
rigid_variables,
|
||||
declarations,
|
||||
references,
|
||||
referenced_values,
|
||||
referenced_types,
|
||||
exposed_imports: can_exposed_imports,
|
||||
problems: env.problems,
|
||||
lookups,
|
||||
|
|
|
@ -96,6 +96,7 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> {
|
|||
SpaceBefore(def, _) | SpaceAfter(def, _) => desugar_def(arena, def),
|
||||
alias @ Alias { .. } => *alias,
|
||||
opaque @ Opaque { .. } => *opaque,
|
||||
ability @ Ability { .. } => *ability,
|
||||
ann @ Annotation(_, _) => *ann,
|
||||
AnnotatedBody {
|
||||
ann_pattern,
|
||||
|
|
|
@ -254,7 +254,7 @@ pub fn canonicalize_pattern<'a>(
|
|||
freshen_opaque_def(var_store, opaque_def);
|
||||
|
||||
output.references.referenced_type_defs.insert(opaque);
|
||||
output.references.lookups.insert(opaque);
|
||||
output.references.type_lookups.insert(opaque);
|
||||
|
||||
Pattern::UnwrappedOpaque {
|
||||
whole_var: var_store.fresh(),
|
||||
|
|
|
@ -45,7 +45,8 @@ impl Procedure {
|
|||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct References {
|
||||
pub bound_symbols: ImSet<Symbol>,
|
||||
pub lookups: ImSet<Symbol>,
|
||||
pub type_lookups: ImSet<Symbol>,
|
||||
pub value_lookups: ImSet<Symbol>,
|
||||
/// Aliases or opaque types referenced
|
||||
pub referenced_type_defs: ImSet<Symbol>,
|
||||
pub calls: ImSet<Symbol>,
|
||||
|
@ -57,7 +58,8 @@ impl References {
|
|||
}
|
||||
|
||||
pub fn union(mut self, other: References) -> Self {
|
||||
self.lookups = self.lookups.union(other.lookups);
|
||||
self.value_lookups = self.value_lookups.union(other.value_lookups);
|
||||
self.type_lookups = self.type_lookups.union(other.type_lookups);
|
||||
self.calls = self.calls.union(other.calls);
|
||||
self.bound_symbols = self.bound_symbols.union(other.bound_symbols);
|
||||
self.referenced_type_defs = self.referenced_type_defs.union(other.referenced_type_defs);
|
||||
|
@ -66,13 +68,18 @@ impl References {
|
|||
}
|
||||
|
||||
pub fn union_mut(&mut self, other: References) {
|
||||
self.lookups.extend(other.lookups);
|
||||
self.value_lookups.extend(other.value_lookups);
|
||||
self.type_lookups.extend(other.type_lookups);
|
||||
self.calls.extend(other.calls);
|
||||
self.bound_symbols.extend(other.bound_symbols);
|
||||
self.referenced_type_defs.extend(other.referenced_type_defs);
|
||||
}
|
||||
|
||||
pub fn has_lookup(&self, symbol: Symbol) -> bool {
|
||||
self.lookups.contains(&symbol)
|
||||
pub fn has_value_lookup(&self, symbol: Symbol) -> bool {
|
||||
self.value_lookups.contains(&symbol)
|
||||
}
|
||||
|
||||
pub fn has_type_lookup(&self, symbol: Symbol) -> bool {
|
||||
self.type_lookups.contains(&symbol)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue