Merge branch 'main' into specialize-exprs

This commit is contained in:
Agus Zubiaga 2024-11-23 01:48:51 -03:00
commit 2e96aca0fd
No known key found for this signature in database
797 changed files with 17394 additions and 12632 deletions

View file

@ -20,3 +20,5 @@ ven_pretty = { path = "../../vendor/pretty" }
bumpalo.workspace = true
static_assertions.workspace = true
soa.workspace = true

View file

@ -1,7 +1,7 @@
#![allow(clippy::too_many_arguments)]
use crate::subs::{
self, AliasVariables, Content, FlatType, GetSubsSlice, Label, Subs, SubsIndex, UnionLabels,
self, AliasVariables, Content, FlatType, GetSubsSlice, Label, Subs, UnionLabels,
UnsortedUnionLabels, Variable,
};
use crate::types::{
@ -15,9 +15,7 @@ use roc_module::symbol::{Interns, ModuleId, Symbol};
pub static WILDCARD: &str = "*";
static EMPTY_RECORD: &str = "{}";
static EMPTY_TAG_UNION: &str = "[]";
// TODO: since we technically don't support empty tuples at the source level, this should probably be removed
static EMPTY_TUPLE: &str = "()";
static EFFECTFUL_FUNC: &str = "! : ... => ?";
/// Requirements for parentheses.
///
@ -152,7 +150,7 @@ fn find_names_needed(
// User-defined names are already taken.
// We must not accidentally generate names that collide with them!
let name = subs.field_names[name_index.index as usize].clone();
let name = subs.field_names[name_index.index()].clone();
match names_taken.get(&name) {
Some(var) if *var == root => {}
Some(_) => {
@ -180,7 +178,7 @@ fn find_names_needed(
);
}
}
Structure(Func(arg_vars, closure_var, ret_var)) => {
Structure(Func(arg_vars, closure_var, ret_var, fx_var)) => {
for index in arg_vars.into_iter() {
let var = subs[index];
find_names_needed(
@ -210,7 +208,17 @@ fn find_names_needed(
names_taken,
find_under_alias,
);
find_names_needed(
*fx_var,
subs,
roots,
root_appearances,
names_taken,
find_under_alias,
);
}
Structure(EffectfulFunc) => {}
Structure(Record(sorted_fields, ext_var)) => {
for index in sorted_fields.iter_variables() {
let var = subs[index];
@ -404,8 +412,9 @@ fn find_names_needed(
}
Error
| Structure(EmptyRecord)
| Structure(EmptyTuple)
| Structure(EmptyTagUnion)
| Pure
| Effectful
| ErasedLambda => {
// Errors and empty records don't need names.
}
@ -535,12 +544,12 @@ fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) {
match old_content {
FlexVar(_) => {
let name_index = SubsIndex::push_new(&mut subs.field_names, name);
let name_index = subs.push_field_name(name);
let content = FlexVar(Some(name_index));
subs.set_content(root, content);
}
&FlexAbleVar(_, ability) => {
let name_index = SubsIndex::push_new(&mut subs.field_names, name);
let name_index = subs.push_field_name(name);
let content = FlexAbleVar(Some(name_index), ability);
subs.set_content(root, content);
}
@ -549,7 +558,7 @@ fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) {
structure,
} => {
let structure = *structure;
let name_index = SubsIndex::push_new(&mut subs.field_names, name);
let name_index = subs.push_field_name(name);
let content = RecursionVar {
structure,
opt_name: Some(name_index),
@ -680,24 +689,24 @@ fn write_content<'a>(
match subs.get_content_without_compacting(var) {
FlexVar(Some(name_index)) => {
let name = &subs.field_names[name_index.index as usize];
let name = &subs.field_names[name_index.index()];
buf.push_str(name.as_str())
}
FlexVar(None) => buf.push_str(WILDCARD),
RigidVar(name_index) => {
let name = &subs.field_names[name_index.index as usize];
let name = &subs.field_names[name_index.index()];
buf.push_str(name.as_str())
}
FlexAbleVar(opt_name_index, abilities) => {
let name = opt_name_index
.map(|name_index| subs.field_names[name_index.index as usize].as_str())
.map(|name_index| subs.field_names[name_index.index()].as_str())
.unwrap_or(WILDCARD);
let abilities = AbilitySet::from_iter(subs.get_subs_slice(*abilities).iter().copied());
ctx.able_variables.push((name, abilities));
buf.push_str(name);
}
RigidAbleVar(name_index, abilities) => {
let name = subs.field_names[name_index.index as usize].as_str();
let name = subs.field_names[name_index.index()].as_str();
let abilities = AbilitySet::from_iter(subs.get_subs_slice(*abilities).iter().copied());
ctx.able_variables.push((name, abilities));
buf.push_str(name);
@ -713,7 +722,7 @@ fn write_content<'a>(
ctx.recursion_structs_to_expand.insert(structure_root);
} else {
let name = &subs.field_names[name_index.index as usize];
let name = &subs.field_names[name_index.index()];
buf.push_str(name.as_str())
}
}
@ -876,6 +885,12 @@ fn write_content<'a>(
// Easy mode 🤠
buf.push('?');
}
Pure => {
buf.push_str("->");
}
Effectful => {
buf.push_str("=>");
}
RangedNumber(range) => {
buf.push_str("Range(");
for (i, &var) in range.variable_slice().iter().enumerate() {
@ -1113,19 +1128,20 @@ fn write_flat_type<'a>(
pol,
),
EmptyRecord => buf.push_str(EMPTY_RECORD),
EmptyTuple => buf.push_str(EMPTY_TUPLE),
EmptyTagUnion => buf.push_str(EMPTY_TAG_UNION),
Func(args, closure, ret) => write_fn(
Func(args, closure, ret, fx) => write_fn(
env,
ctx,
subs.get_subs_slice(*args),
*closure,
*ret,
*fx,
subs,
buf,
parens,
pol,
),
EffectfulFunc => buf.push_str(EFFECTFUL_FUNC),
Record(fields, ext_var) => {
use crate::types::{gather_fields, RecordStructure};
@ -1220,19 +1236,12 @@ fn write_flat_type<'a>(
buf.push_str(" )");
match subs.get_content_without_compacting(ext_var) {
Content::Structure(EmptyTuple) => {
// This is a closed tuple. We're done!
}
_ => {
// This is an open tuple, so print the variable
// right after the ')'
//
// e.g. the "*" at the end of `( I64, I64 )*`
// or the "r" at the end of `( I64, I64 )r`
write_content(env, ctx, ext_var, subs, buf, parens, pol)
}
}
// This is an open tuple, so print the variable
// right after the ')'
//
// e.g. the "*" at the end of `( I64, I64 )*`
// or the "r" at the end of `( I64, I64 )r`
write_content(env, ctx, ext_var, subs, buf, parens, pol)
}
TagUnion(tags, ext_var) => {
buf.push('[');
@ -1460,6 +1469,7 @@ fn write_fn<'a>(
args: &[Variable],
closure: Variable,
ret: Variable,
fx: Variable,
subs: &'a Subs,
buf: &mut String,
parens: Parens,
@ -1483,11 +1493,14 @@ fn write_fn<'a>(
}
if !env.debug.print_lambda_sets {
buf.push_str(" -> ");
buf.push(' ');
write_content(env, ctx, fx, subs, buf, Parens::Unnecessary, Polarity::Neg);
buf.push(' ');
} else {
buf.push_str(" -");
write_content(env, ctx, closure, subs, buf, parens, pol);
buf.push_str("-> ");
write_content(env, ctx, fx, subs, buf, Parens::Unnecessary, Polarity::Neg);
buf.push(' ');
}
write_content(env, ctx, ret, subs, buf, Parens::InFn, Polarity::Pos);

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@ use crate::subs::{
VariableSubsSlice,
};
use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap};
use roc_collections::soa::{Index, Slice};
use roc_collections::soa::{index_push_new, slice_extend_new};
use roc_collections::VecMap;
use roc_error_macros::internal_error;
use roc_module::called_via::CalledVia;
@ -13,6 +13,7 @@ use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
use roc_module::low_level::LowLevel;
use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_region::all::{Loc, Region};
use soa::{Index, Slice};
use std::fmt;
use std::fmt::Write;
use std::path::PathBuf;
@ -375,6 +376,8 @@ pub enum TypeTag {
Index<TypeTag>,
/// return type
Index<TypeTag>,
/// fx type
Index<TypeTag>,
),
/// Closure arguments are implicit
ClosureTag {
@ -418,6 +421,9 @@ pub enum TypeTag {
RecursiveTagUnion(Variable, UnionTags, ExtImplicitOpenness),
Record(RecordFields),
Tuple(TupleElems),
// A function fx type
Pure,
Effectful,
}
/// Look-aside slice of types used in [Types], when the slice does not correspond to the direct
@ -602,7 +608,7 @@ impl Types {
self.tags_slices
.extend(repeat(Slice::default()).take(length));
Slice::extend_new(&mut self.tags, repeat(TypeTag::EmptyRecord).take(length))
slice_extend_new(&mut self.tags, repeat(TypeTag::EmptyRecord).take(length))
}
fn reserve_type_tag(&mut self) -> Index<TypeTag> {
@ -610,7 +616,7 @@ impl Types {
self.tags_slices.push(Slice::default());
Index::push_new(&mut self.tags, TypeTag::EmptyRecord)
index_push_new(&mut self.tags, TypeTag::EmptyRecord)
}
fn set_type_tag(&mut self, index: Index<TypeTag>, tag: TypeTag, type_slice: Slice<TypeTag>) {
@ -644,10 +650,10 @@ impl Types {
extension: &TypeExtension,
) -> (UnionTags, Slice<TypeTag>) {
let tag_names_slice =
Slice::extend_new(&mut self.tag_names, tags.iter().map(|(n, _)| n.clone()));
slice_extend_new(&mut self.tag_names, tags.iter().map(|(n, _)| n.clone()));
// Store the payload slices in the aside buffer
let type_slices = Slice::extend_new(
let type_slices = slice_extend_new(
&mut self.aside_types_slices,
std::iter::repeat(Slice::default()).take(tags.len()),
);
@ -698,7 +704,7 @@ impl Types {
Slice::new(slice.start() as _, slice.len() as _)
};
let type_argument_abilities = Slice::extend_new(
let type_argument_abilities = slice_extend_new(
&mut self.type_arg_abilities,
type_arguments
.iter()
@ -706,7 +712,7 @@ impl Types {
);
// TODO: populate correctly
let type_argument_regions = Slice::extend_new(
let type_argument_regions = slice_extend_new(
&mut self.regions,
std::iter::repeat(Region::zero()).take(type_arguments.len()),
);
@ -732,10 +738,11 @@ impl Types {
arguments: Slice<TypeTag>,
lambda_set: Index<TypeTag>,
ret: Index<TypeTag>,
fx: Index<TypeTag>,
) -> Index<TypeTag> {
let index = self.reserve_type_tag();
let tag = TypeTag::Function(lambda_set, ret);
let tag = TypeTag::Function(lambda_set, ret, fx);
self.set_type_tag(index, tag, arguments);
index
}
@ -747,19 +754,20 @@ impl Types {
Type::EmptyTagUnion => {
self.set_type_tag(index, TypeTag::EmptyTagUnion, Slice::default())
}
Type::Function(arguments, lambda_set, return_type) => {
Type::Function(arguments, lambda_set, return_type, fx_type) => {
let argument_slice = self.from_old_type_slice(arguments.iter());
let tag = TypeTag::Function(
self.from_old_type(lambda_set),
self.from_old_type(return_type),
self.from_old_type(fx_type),
);
self.set_type_tag(index, tag, argument_slice)
}
Type::Apply(symbol, arguments, region) => {
let type_argument_regions =
Slice::extend_new(&mut self.regions, arguments.iter().map(|t| t.region));
slice_extend_new(&mut self.regions, arguments.iter().map(|t| t.region));
let type_slice = {
let slice = self.reserve_type_tags(arguments.len());
@ -835,17 +843,17 @@ impl Types {
slice
};
let field_types = Slice::extend_new(
let field_types = slice_extend_new(
&mut self.field_types,
fields.values().map(|f| f.map(|_| ())),
);
let field_names = Slice::extend_new(&mut self.field_names, fields.keys().cloned());
let field_names = slice_extend_new(&mut self.field_names, fields.keys().cloned());
let record_fields = RecordFields {
length: fields.len() as u16,
field_names_start: field_names.start() as u32,
variables_start: field_type_slice.start() as u32,
variables_start: field_type_slice.start(),
field_types_start: field_types.start() as u32,
};
@ -870,11 +878,11 @@ impl Types {
};
let elem_index_slice =
Slice::extend_new(&mut self.tuple_elem_indices, elems.iter().map(|(i, _)| *i));
slice_extend_new(&mut self.tuple_elem_indices, elems.iter().map(|(i, _)| *i));
let tuple_elems = TupleElems {
length: elems.len() as u16,
variables_start: elem_type_slice.start() as u32,
variables_start: elem_type_slice.start(),
elem_index_start: elem_index_slice.start() as u32,
};
@ -902,7 +910,7 @@ impl Types {
infer_ext_in_output_types,
}) => {
let type_argument_regions =
Slice::extend_new(&mut self.regions, type_arguments.iter().map(|t| t.region));
slice_extend_new(&mut self.regions, type_arguments.iter().map(|t| t.region));
let type_arguments_slice = {
let slice = self.reserve_type_tags(type_arguments.len());
@ -936,7 +944,7 @@ impl Types {
Slice::new(slice.start() as _, slice.len() as _)
};
let type_argument_abilities = Slice::extend_new(
let type_argument_abilities = slice_extend_new(
&mut self.type_arg_abilities,
type_arguments
.iter()
@ -951,7 +959,7 @@ impl Types {
infer_ext_in_output_variables: infer_ext_in_output_slice,
};
let shared = Index::push_new(&mut self.aliases, alias_shared);
let shared = index_push_new(&mut self.aliases, alias_shared);
let tag = TypeTag::DelayedAlias { shared };
@ -982,7 +990,7 @@ impl Types {
infer_ext_in_output_types,
);
let shared = Index::push_new(&mut self.aliases, alias_shared);
let shared = index_push_new(&mut self.aliases, alias_shared);
let actual = self.from_old_type(actual);
let tag = match kind {
@ -1000,6 +1008,8 @@ impl Types {
self.set_type_tag(index, TypeTag::RangedNumber(*range), Slice::default())
}
Type::Error => self.set_type_tag(index, TypeTag::Error, Slice::default()),
Type::Pure => self.set_type_tag(index, TypeTag::Pure, Slice::default()),
Type::Effectful => self.set_type_tag(index, TypeTag::Effectful, Slice::default()),
}
}
@ -1056,7 +1066,7 @@ impl Types {
lambda_set_variables: new_lambda_set_variables,
infer_ext_in_output_variables: new_infer_ext_in_output_variables,
};
Index::push_new(&mut self.aliases, new_shared)
index_push_new(&mut self.aliases, new_shared)
}};
}
@ -1064,7 +1074,7 @@ impl Types {
($union_tags:expr) => {{
let (tags, payload_slices) = self.union_tag_slices($union_tags);
let new_payload_slices = Slice::extend_new(
let new_payload_slices = slice_extend_new(
&mut self.aside_types_slices,
std::iter::repeat(Slice::default()).take(payload_slices.len()),
);
@ -1092,14 +1102,15 @@ impl Types {
Variable(v) => (Variable(subst!(v)), Default::default()),
EmptyRecord => (EmptyRecord, Default::default()),
EmptyTagUnion => (EmptyTagUnion, Default::default()),
Function(clos, ret) => {
Function(clos, ret, fx) => {
let args = self.get_type_arguments(typ);
let new_args = defer_slice!(args);
let new_clos = defer!(clos);
let new_ret = defer!(ret);
let new_fx = defer!(fx);
(Function(new_clos, new_ret), new_args)
(Function(new_clos, new_ret, new_fx), new_args)
}
ClosureTag {
name,
@ -1251,6 +1262,8 @@ impl Types {
}
RangedNumber(range) => (RangedNumber(range), Default::default()),
Error => (Error, Default::default()),
Pure => (Pure, Default::default()),
Effectful => (Effectful, Default::default()),
};
self.set_type_tag(dest_index, tag, args);
@ -1280,8 +1293,8 @@ mod debug_types {
};
use super::{TypeTag, Types};
use roc_collections::soa::{Index, Slice};
use roc_module::ident::TagName;
use soa::{Index, Slice};
use ven_pretty::{text, Arena, DocAllocator, DocBuilder};
pub struct DebugTag<'a>(pub &'a Types, pub Index<TypeTag>);
@ -1327,7 +1340,7 @@ mod debug_types {
let group = match types[tag] {
TypeTag::EmptyRecord => f.text("{}"),
TypeTag::EmptyTagUnion => f.text("[]"),
TypeTag::Function(clos, ret) => {
TypeTag::Function(clos, ret, fx) => {
let args = types.get_type_arguments(tag);
maybe_paren!(
Free,
@ -1338,6 +1351,8 @@ mod debug_types {
)
.append(f.text(" -"))
.append(typ(types, f, Free, clos))
.append(f.text(" -"))
.append(typ(types, f, Free, fx))
.append(f.text("->"))
.append(f.line())
.append(typ(types, f, Arg, ret))
@ -1419,8 +1434,8 @@ mod debug_types {
let (names, kind, tys) = types.record_fields_slices(fields);
let fmt_fields = names
.into_iter()
.zip(kind.into_iter())
.zip(tys.into_iter())
.zip(kind)
.zip(tys)
.map(|((name, kind), ty)| {
let (name, kind) = (&types[name], types[kind]);
let fmt_kind = f.text(match kind {
@ -1458,6 +1473,8 @@ mod debug_types {
.align(),
)
}
TypeTag::Pure => f.text("Pure"),
TypeTag::Effectful => f.text("Effectful"),
};
group.group()
}
@ -1482,19 +1499,19 @@ mod debug_types {
ext_slice: Slice<TypeTag>,
) -> DocBuilder<'a, Arena<'a>> {
let (tags, payload_slices) = types.union_tag_slices(tags);
let fmt_tags =
tags.into_iter()
.zip(payload_slices.into_iter())
.map(|(tag, payload_slice_index)| {
let payload_slice = types[payload_slice_index];
let fmt_payloads = payload_slice
.into_iter()
.map(|p| typ(types, f, TPrec::Arg, p));
let iter = Some(f.text(types[tag].0.to_string()))
.into_iter()
.chain(fmt_payloads);
f.intersperse(iter, f.text(" "))
});
let fmt_tags = tags
.into_iter()
.zip(payload_slices)
.map(|(tag, payload_slice_index)| {
let payload_slice = types[payload_slice_index];
let fmt_payloads = payload_slice
.into_iter()
.map(|p| typ(types, f, TPrec::Arg, p));
let iter = Some(f.text(types[tag].0.to_string()))
.into_iter()
.chain(fmt_payloads);
f.intersperse(iter, f.text(" "))
});
prefix.append(f.text("[")).append(
f.intersperse(fmt_tags, f.reflow(", "))
@ -1523,7 +1540,7 @@ mod debug_types {
let args = types.get_type_arguments(tag);
let fmt_args = args
.into_iter()
.zip(type_argument_abilities.into_iter())
.zip(type_argument_abilities)
.map(|(arg, abilities)| {
let abilities = &types[abilities];
let arg = typ(types, f, Arg, arg);
@ -1652,8 +1669,8 @@ impl std::ops::Index<Slice<AsideTypeSlice>> for Types {
pub enum Type {
EmptyRec,
EmptyTagUnion,
/// A function. The types of its arguments, size of its closure, then the type of its return value.
Function(Vec<Type>, Box<Type>, Box<Type>),
/// A function. The types of its arguments, size of its closure, its return value, then the fx type.
Function(Vec<Type>, Box<Type>, Box<Type>, Box<Type>),
Record(SendMap<Lowercase, RecordField<Type>>, TypeExtension),
Tuple(VecMap<usize, Type>, TypeExtension),
TagUnion(Vec<(TagName, Vec<Type>)>, TypeExtension),
@ -1685,6 +1702,9 @@ pub enum Type {
Apply(Symbol, Vec<Loc<Type>>, Region),
Variable(Variable),
RangedNumber(NumericRange),
/// A function's fx type
Pure,
Effectful,
/// A type error, which will code gen to a runtime error
Error,
}
@ -1729,8 +1749,8 @@ impl Clone for Type {
match self {
Self::EmptyRec => Self::EmptyRec,
Self::EmptyTagUnion => Self::EmptyTagUnion,
Self::Function(arg0, arg1, arg2) => {
Self::Function(arg0.clone(), arg1.clone(), arg2.clone())
Self::Function(arg0, arg1, arg2, arg3) => {
Self::Function(arg0.clone(), arg1.clone(), arg2.clone(), arg3.clone())
}
Self::Record(arg0, arg1) => Self::Record(arg0.clone(), arg1.clone()),
Self::Tuple(arg0, arg1) => Self::Tuple(arg0.clone(), arg1.clone()),
@ -1773,6 +1793,8 @@ impl Clone for Type {
Self::Variable(arg0) => Self::Variable(*arg0),
Self::RangedNumber(arg1) => Self::RangedNumber(*arg1),
Self::Error => Self::Error,
Type::Pure => Self::Pure,
Type::Effectful => Self::Effectful,
}
}
}
@ -1885,7 +1907,7 @@ impl fmt::Debug for Type {
match self {
Type::EmptyRec => write!(f, "{{}}"),
Type::EmptyTagUnion => write!(f, "[]"),
Type::Function(args, closure, ret) => {
Type::Function(args, closure, ret, fx) => {
write!(f, "Fn(")?;
for (index, arg) in args.iter().enumerate() {
@ -1897,7 +1919,8 @@ impl fmt::Debug for Type {
}
write!(f, " |{closure:?}|")?;
write!(f, " -> ")?;
write!(f, " -{fx:?}")?;
write!(f, "-> ")?;
ret.fmt(f)?;
@ -2136,13 +2159,15 @@ impl fmt::Debug for Type {
Type::UnspecializedLambdaSet { unspecialized } => {
write!(f, "{unspecialized:?}")
}
Type::Pure => write!(f, "->"),
Type::Effectful => write!(f, "=>"),
}
}
}
impl Type {
pub fn arity(&self) -> usize {
if let Type::Function(args, _, _) = self {
if let Type::Function(args, _, _, _) = self {
args.len()
} else {
0
@ -2186,10 +2211,11 @@ impl Type {
*typ = replacement.clone();
}
}
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
stack.extend(args);
stack.push(closure);
stack.push(ret);
stack.push(fx);
}
ClosureTag {
name: _,
@ -2298,7 +2324,7 @@ impl Type {
);
}
EmptyRec | EmptyTagUnion | Error => {}
EmptyRec | EmptyTagUnion | Error | Pure | Effectful => {}
}
}
}
@ -2315,10 +2341,11 @@ impl Type {
*v = *replacement;
}
}
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
stack.extend(args);
stack.push(closure);
stack.push(ret);
stack.push(fx);
}
ClosureTag {
name: _,
@ -2420,7 +2447,7 @@ impl Type {
);
}
EmptyRec | EmptyTagUnion | Error => {}
EmptyRec | EmptyTagUnion | Error | Pure | Effectful => {}
}
}
}
@ -2436,12 +2463,13 @@ impl Type {
use Type::*;
match self {
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
for arg in args {
arg.substitute_alias(rep_symbol, rep_args, actual)?;
}
closure.substitute_alias(rep_symbol, rep_args, actual)?;
ret.substitute_alias(rep_symbol, rep_args, actual)
ret.substitute_alias(rep_symbol, rep_args, actual)?;
fx.substitute_alias(rep_symbol, rep_args, actual)
}
FunctionOrTagUnion(_, _, ext) => match ext {
TypeExtension::Open(ext, _) => ext.substitute_alias(rep_symbol, rep_args, actual),
@ -2535,7 +2563,13 @@ impl Type {
}
RangedNumber(_) => Ok(()),
UnspecializedLambdaSet { .. } => Ok(()),
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => Ok(()),
EmptyRec
| EmptyTagUnion
| ClosureTag { .. }
| Error
| Variable(_)
| Pure
| Effectful => Ok(()),
}
}
@ -2550,7 +2584,7 @@ impl Type {
use Type::*;
match self {
Function(args, closure, ret) => {
Function(args, closure, ret, _fx) => {
ret.contains_symbol(rep_symbol)
|| closure.contains_symbol(rep_symbol)
|| args.iter().any(|arg| arg.contains_symbol(rep_symbol))
@ -2598,7 +2632,13 @@ impl Type {
UnspecializedLambdaSet {
unspecialized: Uls(_, sym, _),
} => *sym == rep_symbol,
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => false,
EmptyRec
| EmptyTagUnion
| ClosureTag { .. }
| Error
| Variable(_)
| Pure
| Effectful => false,
}
}
@ -2614,10 +2654,11 @@ impl Type {
match self {
Variable(v) => *v == rep_variable,
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
ret.contains_variable(rep_variable)
|| closure.contains_variable(rep_variable)
|| args.iter().any(|arg| arg.contains_variable(rep_variable))
|| fx.contains_variable(rep_variable)
}
FunctionOrTagUnion(_, _, ext) => Self::contains_variable_ext(ext, rep_variable),
ClosureTag {
@ -2659,7 +2700,7 @@ impl Type {
.iter()
.any(|arg| arg.value.contains_variable(rep_variable)),
RangedNumber(_) => false,
EmptyRec | EmptyTagUnion | Error => false,
EmptyRec | EmptyTagUnion | Error | Pure | Effectful => false,
}
}
@ -2760,8 +2801,11 @@ impl Type {
}
TypeExtension::Closed => fields.values().all(|field| field.as_inner().is_narrow()),
},
Type::Function(args, clos, ret) => {
args.iter().all(|a| a.is_narrow()) && clos.is_narrow() && ret.is_narrow()
Type::Function(args, clos, ret, fx) => {
args.iter().all(|a| a.is_narrow())
&& clos.is_narrow()
&& ret.is_narrow()
&& fx.is_narrow()
}
// Lists and sets are morally two-tagged unions, as they can be empty
Type::Apply(Symbol::LIST_LIST | Symbol::SET_SET, _, _) => false,
@ -2800,12 +2844,13 @@ fn instantiate_aliases<'a, F>(
use Type::*;
match typ {
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
for arg in args {
instantiate_aliases(arg, region, aliases, ctx);
}
instantiate_aliases(closure, region, aliases, ctx);
instantiate_aliases(ret, region, aliases, ctx);
instantiate_aliases(fx, region, aliases, ctx);
}
FunctionOrTagUnion(_, _, ext) => {
if let TypeExtension::Open(ext, _) = ext {
@ -2964,7 +3009,7 @@ fn instantiate_aliases<'a, F>(
}
RangedNumber(_) => {}
UnspecializedLambdaSet { .. } => {}
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => {}
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) | Pure | Effectful => {}
}
}
@ -2976,9 +3021,10 @@ fn symbols_help(initial: &Type) -> Vec<Symbol> {
while let Some(tipe) = stack.pop() {
match tipe {
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
stack.push(ret);
stack.push(closure);
stack.push(fx);
stack.extend(args);
}
FunctionOrTagUnion(_, _, ext) => {
@ -3025,7 +3071,13 @@ fn symbols_help(initial: &Type) -> Vec<Symbol> {
} => {
// ignore the member symbol because unspecialized lambda sets are internal-only
}
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => {}
EmptyRec
| EmptyTagUnion
| ClosureTag { .. }
| Error
| Variable(_)
| Pure
| Effectful => {}
}
}
@ -3045,12 +3097,13 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
accum.insert(*v);
}
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
for arg in args {
variables_help(arg, accum);
}
variables_help(closure, accum);
variables_help(ret, accum);
variables_help(fx, accum);
}
Record(fields, ext) => {
for (_, field) in fields {
@ -3146,6 +3199,7 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
variables_help(&x.value, accum);
}
}
Pure | Effectful => {}
}
}
@ -3174,7 +3228,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
accum.type_variables.insert(*v);
}
Function(args, closure, ret) => {
Function(args, closure, ret, fx) => {
for arg in args {
variables_help_detailed(arg, accum);
}
@ -3185,6 +3239,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
}
variables_help_detailed(ret, accum);
variables_help_detailed(fx, accum);
}
Record(fields, ext) => {
for (_, field) in fields {
@ -3288,6 +3343,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
variables_help_detailed(&x.value, accum);
}
}
Pure | Effectful => {}
}
}
@ -3392,6 +3448,7 @@ pub enum Reason {
foreign_symbol: ForeignSymbol,
arg_index: HumanIndex,
},
Stmt(Option<Symbol>),
FloatLiteral,
IntLiteral,
NumLiteral,
@ -3425,6 +3482,7 @@ pub enum Reason {
},
CrashArg,
ImportParams(ModuleId),
FunctionOutput,
}
#[derive(PartialEq, Eq, Debug, Clone)]
@ -3474,6 +3532,7 @@ pub enum Category {
Expect,
Dbg,
Return,
Unknown,
}
@ -3608,6 +3667,7 @@ pub enum ErrorType {
/// If the name was auto-generated, it will start with a `#`.
FlexVar(Lowercase),
RigidVar(Lowercase),
EffectfulFunc,
/// If the name was auto-generated, it will start with a `#`.
FlexAbleVar(Lowercase, AbilitySet),
RigidAbleVar(Lowercase, AbilitySet),
@ -3620,12 +3680,23 @@ pub enum ErrorType {
TypeExt,
Polarity,
),
Function(Vec<ErrorType>, Box<ErrorType>, Box<ErrorType>),
Function(
Vec<ErrorType>,
Box<ErrorType>,
ErrorFunctionFx,
Box<ErrorType>,
),
Alias(Symbol, Vec<ErrorType>, Box<ErrorType>, AliasKind),
Range(Vec<ErrorType>),
Error,
}
#[derive(PartialEq, Eq, Clone, Hash)]
pub enum ErrorFunctionFx {
Pure,
Effectful,
}
impl std::fmt::Debug for ErrorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO remove clone
@ -3671,7 +3742,7 @@ impl ErrorType {
.for_each(|(_, ts)| ts.iter().for_each(|t| t.add_names(taken)));
ext.add_names(taken);
}
Function(args, capt, ret) => {
Function(args, capt, _fx, ret) => {
args.iter().for_each(|t| t.add_names(taken));
capt.add_names(taken);
ret.add_names(taken);
@ -3687,6 +3758,7 @@ impl ErrorType {
t.add_names(taken);
});
}
EffectfulFunc => {}
Error => {}
}
}
@ -3757,7 +3829,7 @@ fn write_error_type_help(
}
}
}
Function(arguments, _closure, result) => {
Function(arguments, _closure, fx, result) => {
let write_parens = parens != Parens::Unnecessary;
if write_parens {
@ -3773,7 +3845,10 @@ fn write_error_type_help(
}
}
buf.push_str(" -> ");
match fx {
ErrorFunctionFx::Pure => buf.push_str(" -> "),
ErrorFunctionFx::Effectful => buf.push_str(" => "),
}
write_error_type_help(interns, *result, buf, Parens::InFn);
@ -3836,6 +3911,7 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
buf.push(')');
}
}
EffectfulFunc => buf.push_str("EffectfulFunc"),
Type(symbol, arguments) => {
let write_parens = parens == Parens::InTypeParam && !arguments.is_empty();
@ -3907,7 +3983,7 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
buf.push(')');
}
}
Function(arguments, _closure, result) => {
Function(arguments, _closure, fx, result) => {
let write_parens = parens != Parens::Unnecessary;
if write_parens {
@ -3923,7 +3999,10 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
}
}
buf.push_str(" -> ");
match fx {
ErrorFunctionFx::Pure => buf.push_str(" -> "),
ErrorFunctionFx::Effectful => buf.push_str(" => "),
}
write_debug_error_type_help(*result, buf, Parens::InFn);
@ -4411,7 +4490,7 @@ fn instantiate_lambda_sets_as_unspecialized(
match typ {
Type::EmptyRec => {}
Type::EmptyTagUnion => {}
Type::Function(args, lambda_set, ret) => {
Type::Function(args, lambda_set, ret, fx) => {
debug_assert!(
matches!(**lambda_set, Type::Variable(..)),
"lambda set already bound"
@ -4419,6 +4498,7 @@ fn instantiate_lambda_sets_as_unspecialized(
**lambda_set = new_uls();
stack.push(ret);
stack.push(fx);
stack.extend(args.iter_mut().rev());
}
Type::Record(fields, ext) => {
@ -4487,6 +4567,7 @@ fn instantiate_lambda_sets_as_unspecialized(
Type::Variable(_) => {}
Type::RangedNumber(_) => {}
Type::Error => {}
Type::Pure | Type::Effectful => {}
}
}
}
@ -4501,16 +4582,20 @@ mod test {
let l1 = Box::new(Type::Variable(var_store.fresh()));
let l2 = Box::new(Type::Variable(var_store.fresh()));
let l3 = Box::new(Type::Variable(var_store.fresh()));
let fx1 = Box::new(Type::Variable(var_store.fresh()));
let fx2 = Box::new(Type::Variable(var_store.fresh()));
let fx3 = Box::new(Type::Variable(var_store.fresh()));
let mut typ = Type::Function(
vec![Type::Function(vec![], l2, Box::new(Type::EmptyRec))],
vec![Type::Function(vec![], l2, Box::new(Type::EmptyRec), fx1)],
l1,
Box::new(Type::TagUnion(
vec![(
TagName("A".into()),
vec![Type::Function(vec![], l3, Box::new(Type::EmptyRec))],
vec![Type::Function(vec![], l3, Box::new(Type::EmptyRec), fx2)],
)],
TypeExtension::Closed,
)),
fx3,
);
let able_var = var_store.fresh();
@ -4531,11 +4616,11 @@ mod test {
}
match typ {
Type::Function(args, l1, ret) => {
Type::Function(args, l1, ret, _fx) => {
check_uls!(*l1, 1);
match args.as_slice() {
[Type::Function(args, l2, ret)] => {
[Type::Function(args, l2, ret, _fx)] => {
check_uls!(**l2, 2);
assert!(args.is_empty());
assert!(matches!(**ret, Type::EmptyRec));
@ -4548,7 +4633,7 @@ mod test {
[(name, args)] => {
assert_eq!(name.0.as_str(), "A");
match args.as_slice() {
[Type::Function(args, l3, ret)] => {
[Type::Function(args, l3, ret, _fx)] => {
check_uls!(**l3, 3);
assert!(args.is_empty());
assert!(matches!(**ret, Type::EmptyRec));