mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Treat untyped suffixed functions as effectful
This commit is contained in:
parent
af6fc6306f
commit
cfc4be5254
25 changed files with 139 additions and 21 deletions
|
@ -986,6 +986,27 @@ mod cli_run {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(windows, ignore)]
|
||||||
|
fn effectful_untyped_passed_fx() {
|
||||||
|
test_roc_app(
|
||||||
|
"crates/cli/tests/effectful",
|
||||||
|
"untyped_passed_fx.roc",
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Before hello
|
||||||
|
Hello, World!
|
||||||
|
After hello
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
UseValgrind::No,
|
||||||
|
TestCliCommands::Dev,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(windows, ignore)]
|
#[cfg_attr(windows, ignore)]
|
||||||
fn transitive_expects() {
|
fn transitive_expects() {
|
||||||
|
|
13
crates/cli/tests/effectful/untyped_passed_fx.roc
Normal file
13
crates/cli/tests/effectful/untyped_passed_fx.roc
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
app [main!] { pf: platform "../../../../examples/cli/effects-platform/main.roc" }
|
||||||
|
|
||||||
|
import pf.Effect
|
||||||
|
|
||||||
|
main! : {} => {}
|
||||||
|
main! = \{} ->
|
||||||
|
logged! "hello" (\{} -> Effect.putLine! "Hello, World!")
|
||||||
|
|
||||||
|
|
||||||
|
logged! = \name, fx! ->
|
||||||
|
Effect.putLine! "Before $(name)"
|
||||||
|
fx! {}
|
||||||
|
Effect.putLine! "After $(name)"
|
|
@ -984,7 +984,7 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
||||||
|
|
||||||
// Everything else is a mechanical descent.
|
// Everything else is a mechanical descent.
|
||||||
Structure(flat_type) => match flat_type {
|
Structure(flat_type) => match flat_type {
|
||||||
EmptyRecord | EmptyTagUnion => Structure(flat_type),
|
EmptyRecord | EmptyTagUnion | EffectfulFunc => Structure(flat_type),
|
||||||
Apply(symbol, arguments) => {
|
Apply(symbol, arguments) => {
|
||||||
descend_slice!(arguments);
|
descend_slice!(arguments);
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,7 @@ fn index_var(
|
||||||
}
|
}
|
||||||
Content::Structure(structure) => match structure {
|
Content::Structure(structure) => match structure {
|
||||||
FlatType::Func(_, _, _, _) => return Err(TypeError),
|
FlatType::Func(_, _, _, _) => return Err(TypeError),
|
||||||
|
FlatType::EffectfulFunc => return Err(TypeError),
|
||||||
FlatType::Apply(Symbol::LIST_LIST, args) => {
|
FlatType::Apply(Symbol::LIST_LIST, args) => {
|
||||||
match (subs.get_subs_slice(*args), ctor) {
|
match (subs.get_subs_slice(*args), ctor) {
|
||||||
([elem_var], IndexCtor::List) => {
|
([elem_var], IndexCtor::List) => {
|
||||||
|
|
|
@ -514,6 +514,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"EffectfulFunc"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
@ -127,6 +127,7 @@ impl AsSchema<Content> for subs::FlatType {
|
||||||
),
|
),
|
||||||
subs::FlatType::EmptyRecord => Content::EmptyRecord(),
|
subs::FlatType::EmptyRecord => Content::EmptyRecord(),
|
||||||
subs::FlatType::EmptyTagUnion => Content::EmptyTagUnion(),
|
subs::FlatType::EmptyTagUnion => Content::EmptyTagUnion(),
|
||||||
|
subs::FlatType::EffectfulFunc => Content::EffectfulFunc(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ impl_content! {
|
||||||
},
|
},
|
||||||
EmptyRecord {},
|
EmptyRecord {},
|
||||||
EmptyTagUnion {},
|
EmptyTagUnion {},
|
||||||
|
EffectfulFunc {},
|
||||||
RangedNumber {
|
RangedNumber {
|
||||||
range: NumericRange,
|
range: NumericRange,
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,7 +6,7 @@ use roc_can::pattern::Pattern::{self, *};
|
||||||
use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct, TupleDestruct};
|
use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct, TupleDestruct};
|
||||||
use roc_collections::all::{HumanIndex, SendMap};
|
use roc_collections::all::{HumanIndex, SendMap};
|
||||||
use roc_collections::VecMap;
|
use roc_collections::VecMap;
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::{IdentSuffix, Lowercase};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
|
@ -299,12 +299,25 @@ pub fn constrain_pattern_help(
|
||||||
.push(constraints.is_open_type(type_index));
|
.push(constraints.is_open_type(type_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Identifiers introduced in nested patterns get let constraints
|
||||||
|
// and therefore don't need fx_pattern_suffix constraints.
|
||||||
if is_shallow {
|
if is_shallow {
|
||||||
// Identifiers introduced in nested patterns get let constraints
|
match symbol.suffix() {
|
||||||
// and therefore don't need fx_pattern_suffix constraints.
|
IdentSuffix::None => {
|
||||||
state
|
// Unsuffixed identifiers should be constrained after we know if they're functions
|
||||||
.delayed_fx_suffix_constraints
|
state
|
||||||
.push(constraints.fx_pattern_suffix(*symbol, type_index, region));
|
.delayed_fx_suffix_constraints
|
||||||
|
.push(constraints.fx_pattern_suffix(*symbol, type_index, region));
|
||||||
|
}
|
||||||
|
IdentSuffix::Bang => {
|
||||||
|
// Bang suffixed identifiers are always required to be functions
|
||||||
|
// We constrain this before the function's body,
|
||||||
|
// so that we don't think it's pure and complain about leftover statements
|
||||||
|
state
|
||||||
|
.constraints
|
||||||
|
.push(constraints.fx_pattern_suffix(*symbol, type_index, region));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.headers.insert(
|
state.headers.insert(
|
||||||
|
|
|
@ -81,7 +81,7 @@ impl FlatDecodable {
|
||||||
Err(Underivable) // yet
|
Err(Underivable) // yet
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
FlatType::Func(..) => Err(Underivable),
|
FlatType::Func(..) | FlatType::EffectfulFunc => Err(Underivable),
|
||||||
},
|
},
|
||||||
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
||||||
Some(lambda) => lambda,
|
Some(lambda) => lambda,
|
||||||
|
|
|
@ -117,7 +117,7 @@ impl FlatEncodable {
|
||||||
}
|
}
|
||||||
FlatType::EmptyRecord => Ok(Key(FlatEncodableKey::Record(vec![]))),
|
FlatType::EmptyRecord => Ok(Key(FlatEncodableKey::Record(vec![]))),
|
||||||
FlatType::EmptyTagUnion => Ok(Key(FlatEncodableKey::TagUnion(vec![]))),
|
FlatType::EmptyTagUnion => Ok(Key(FlatEncodableKey::TagUnion(vec![]))),
|
||||||
FlatType::Func(..) => Err(Underivable),
|
FlatType::Func(..) | FlatType::EffectfulFunc => Err(Underivable),
|
||||||
},
|
},
|
||||||
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
||||||
Some(lambda) => lambda,
|
Some(lambda) => lambda,
|
||||||
|
|
|
@ -112,7 +112,7 @@ impl FlatHash {
|
||||||
FlatType::EmptyRecord => Ok(Key(FlatHashKey::Record(vec![]))),
|
FlatType::EmptyRecord => Ok(Key(FlatHashKey::Record(vec![]))),
|
||||||
FlatType::EmptyTagUnion => Ok(Key(FlatHashKey::TagUnion(vec![]))),
|
FlatType::EmptyTagUnion => Ok(Key(FlatHashKey::TagUnion(vec![]))),
|
||||||
//
|
//
|
||||||
FlatType::Func(..) => Err(Underivable),
|
FlatType::Func(..) | FlatType::EffectfulFunc => Err(Underivable),
|
||||||
},
|
},
|
||||||
Content::Alias(sym, _, real_var, _) => match builtin_symbol_to_hash_lambda(sym) {
|
Content::Alias(sym, _, real_var, _) => match builtin_symbol_to_hash_lambda(sym) {
|
||||||
Some(lambda) => Ok(lambda),
|
Some(lambda) => Ok(lambda),
|
||||||
|
|
|
@ -129,6 +129,9 @@ impl FlatInspectable {
|
||||||
FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())),
|
FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())),
|
||||||
FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())),
|
FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())),
|
||||||
FlatType::Func(..) => Immediate(Symbol::INSPECT_FUNCTION),
|
FlatType::Func(..) => Immediate(Symbol::INSPECT_FUNCTION),
|
||||||
|
FlatType::EffectfulFunc => {
|
||||||
|
unreachable!("There must have been a bug in the solver, because we're trying to derive Inspect on a non-concrete type.");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Content::Alias(sym, _, real_var, kind) => match Self::from_builtin_alias(sym) {
|
Content::Alias(sym, _, real_var, kind) => match Self::from_builtin_alias(sym) {
|
||||||
Some(lambda) => lambda,
|
Some(lambda) => lambda,
|
||||||
|
|
|
@ -210,6 +210,7 @@ fn drop_last_argument(err_type: &mut ErrorType) {
|
||||||
| ErrorType::RecursiveTagUnion(_, _, _, _)
|
| ErrorType::RecursiveTagUnion(_, _, _, _)
|
||||||
| ErrorType::Alias(_, _, _, _)
|
| ErrorType::Alias(_, _, _, _)
|
||||||
| ErrorType::Range(_)
|
| ErrorType::Range(_)
|
||||||
| ErrorType::Error => {}
|
| ErrorType::Error
|
||||||
|
| ErrorType::EffectfulFunc => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10180,6 +10180,7 @@ fn find_lambda_sets_help(
|
||||||
}
|
}
|
||||||
FlatType::EmptyRecord => {}
|
FlatType::EmptyRecord => {}
|
||||||
FlatType::EmptyTagUnion => {}
|
FlatType::EmptyTagUnion => {}
|
||||||
|
FlatType::EffectfulFunc => {}
|
||||||
},
|
},
|
||||||
Content::Alias(_, _, actual, _) => {
|
Content::Alias(_, _, actual, _) => {
|
||||||
stack.push(*actual);
|
stack.push(*actual);
|
||||||
|
|
|
@ -2192,6 +2192,7 @@ fn lambda_set_size(subs: &Subs, var: Variable) -> (usize, usize, usize) {
|
||||||
}
|
}
|
||||||
stack.push((ext.var(), depth_any + 1, depth_lset));
|
stack.push((ext.var(), depth_any + 1, depth_lset));
|
||||||
}
|
}
|
||||||
|
FlatType::EffectfulFunc => internal_error!(),
|
||||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion => {}
|
FlatType::EmptyRecord | FlatType::EmptyTagUnion => {}
|
||||||
},
|
},
|
||||||
Content::FlexVar(_)
|
Content::FlexVar(_)
|
||||||
|
@ -3465,6 +3466,7 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
EmptyTagUnion => cacheable(Ok(Layout::VOID)),
|
EmptyTagUnion => cacheable(Ok(Layout::VOID)),
|
||||||
EmptyRecord => cacheable(Ok(Layout::UNIT)),
|
EmptyRecord => cacheable(Ok(Layout::UNIT)),
|
||||||
|
EffectfulFunc => internal_error!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -780,6 +780,12 @@ trait DerivableVisitor {
|
||||||
}
|
}
|
||||||
EmptyRecord => Self::visit_empty_record(var)?,
|
EmptyRecord => Self::visit_empty_record(var)?,
|
||||||
EmptyTagUnion => Self::visit_empty_tag_union(var)?,
|
EmptyTagUnion => Self::visit_empty_tag_union(var)?,
|
||||||
|
EffectfulFunc => {
|
||||||
|
return Err(NotDerivable {
|
||||||
|
var,
|
||||||
|
context: NotDerivableContext::NoContext,
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Alias(
|
Alias(
|
||||||
Symbol::NUM_NUM | Symbol::NUM_INTEGER,
|
Symbol::NUM_NUM | Symbol::NUM_INTEGER,
|
||||||
|
|
|
@ -187,7 +187,7 @@ fn deep_copy_var_help(
|
||||||
Func(new_arguments, new_closure_var, new_ret_var, new_fx_var)
|
Func(new_arguments, new_closure_var, new_ret_var, new_fx_var)
|
||||||
}
|
}
|
||||||
|
|
||||||
same @ EmptyRecord | same @ EmptyTagUnion => same,
|
same @ (EmptyRecord | EmptyTagUnion | EffectfulFunc) => same,
|
||||||
|
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
let record_fields = {
|
let record_fields = {
|
||||||
|
|
|
@ -1660,7 +1660,8 @@ fn solve_suffix_fx(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Content::FlexVar(_) => {
|
Content::FlexVar(_) => {
|
||||||
// [purity-inference] TODO: Require effectful fn
|
env.subs
|
||||||
|
.set_content(variable, Content::Structure(FlatType::EffectfulFunc));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
@ -2379,6 +2380,8 @@ fn adjust_rank_content(
|
||||||
// THEORY: an empty tag never needs to get generalized
|
// THEORY: an empty tag never needs to get generalized
|
||||||
EmptyTagUnion => Rank::toplevel(),
|
EmptyTagUnion => Rank::toplevel(),
|
||||||
|
|
||||||
|
EffectfulFunc => Rank::toplevel(),
|
||||||
|
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
pub static WILDCARD: &str = "*";
|
pub static WILDCARD: &str = "*";
|
||||||
static EMPTY_RECORD: &str = "{}";
|
static EMPTY_RECORD: &str = "{}";
|
||||||
static EMPTY_TAG_UNION: &str = "[]";
|
static EMPTY_TAG_UNION: &str = "[]";
|
||||||
|
static EFFECTFUL_FUNC: &str = "! : ... => ?";
|
||||||
|
|
||||||
/// Requirements for parentheses.
|
/// Requirements for parentheses.
|
||||||
///
|
///
|
||||||
|
@ -217,6 +218,7 @@ fn find_names_needed(
|
||||||
find_under_alias,
|
find_under_alias,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Structure(EffectfulFunc) => {}
|
||||||
Structure(Record(sorted_fields, ext_var)) => {
|
Structure(Record(sorted_fields, ext_var)) => {
|
||||||
for index in sorted_fields.iter_variables() {
|
for index in sorted_fields.iter_variables() {
|
||||||
let var = subs[index];
|
let var = subs[index];
|
||||||
|
@ -1139,6 +1141,7 @@ fn write_flat_type<'a>(
|
||||||
parens,
|
parens,
|
||||||
pol,
|
pol,
|
||||||
),
|
),
|
||||||
|
EffectfulFunc => buf.push_str(EFFECTFUL_FUNC),
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
use crate::types::{gather_fields, RecordStructure};
|
use crate::types::{gather_fields, RecordStructure};
|
||||||
|
|
||||||
|
|
|
@ -833,6 +833,7 @@ fn subs_fmt_flat_type(this: &FlatType, subs: &Subs, f: &mut fmt::Formatter) -> f
|
||||||
}
|
}
|
||||||
FlatType::EmptyRecord => write!(f, "EmptyRecord"),
|
FlatType::EmptyRecord => write!(f, "EmptyRecord"),
|
||||||
FlatType::EmptyTagUnion => write!(f, "EmptyTagUnion"),
|
FlatType::EmptyTagUnion => write!(f, "EmptyTagUnion"),
|
||||||
|
FlatType::EffectfulFunc => write!(f, "EffectfulFunc"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2584,6 +2585,8 @@ impl TagExt {
|
||||||
pub enum FlatType {
|
pub enum FlatType {
|
||||||
Apply(Symbol, VariableSubsSlice),
|
Apply(Symbol, VariableSubsSlice),
|
||||||
Func(VariableSubsSlice, Variable, Variable, Variable),
|
Func(VariableSubsSlice, Variable, Variable, Variable),
|
||||||
|
/// A function that we know nothing about yet except that it's effectful
|
||||||
|
EffectfulFunc,
|
||||||
Record(RecordFields, Variable),
|
Record(RecordFields, Variable),
|
||||||
Tuple(TupleElems, Variable),
|
Tuple(TupleElems, Variable),
|
||||||
TagUnion(UnionTags, TagExt),
|
TagUnion(UnionTags, TagExt),
|
||||||
|
@ -3492,7 +3495,7 @@ fn occurs(
|
||||||
|
|
||||||
short_circuit_help(subs, root_var, ctx, ext_var)
|
short_circuit_help(subs, root_var, ctx, ext_var)
|
||||||
}
|
}
|
||||||
EmptyRecord | EmptyTagUnion => Ok(()),
|
EmptyRecord | EmptyTagUnion | EffectfulFunc => Ok(()),
|
||||||
},
|
},
|
||||||
Alias(_, args, _, _) => {
|
Alias(_, args, _, _) => {
|
||||||
// THEORY: we only need to explore the args, as that is the surface of all
|
// THEORY: we only need to explore the args, as that is the surface of all
|
||||||
|
@ -3686,7 +3689,7 @@ fn explicit_substitute(
|
||||||
subs.set_content(in_var, Structure(Tuple(vars_by_elem, new_ext)));
|
subs.set_content(in_var, Structure(Tuple(vars_by_elem, new_ext)));
|
||||||
}
|
}
|
||||||
|
|
||||||
EmptyRecord | EmptyTagUnion => {}
|
EmptyRecord | EmptyTagUnion | EffectfulFunc => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
in_var
|
in_var
|
||||||
|
@ -3872,7 +3875,9 @@ fn get_var_names(
|
||||||
accum
|
accum
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion => taken_names,
|
FlatType::EmptyRecord | FlatType::EmptyTagUnion | FlatType::EffectfulFunc => {
|
||||||
|
taken_names
|
||||||
|
}
|
||||||
|
|
||||||
FlatType::Record(vars_by_field, ext) => {
|
FlatType::Record(vars_by_field, ext) => {
|
||||||
let mut accum = get_var_names(subs, ext, taken_names);
|
let mut accum = get_var_names(subs, ext, taken_names);
|
||||||
|
@ -4236,6 +4241,7 @@ fn flat_type_to_err_type(
|
||||||
ErrorType::Function(args, Box::new(closure), fx, Box::new(ret))
|
ErrorType::Function(args, Box::new(closure), fx, Box::new(ret))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectfulFunc => ErrorType::EffectfulFunc,
|
||||||
EmptyRecord => ErrorType::Record(SendMap::default(), TypeExt::Closed),
|
EmptyRecord => ErrorType::Record(SendMap::default(), TypeExt::Closed),
|
||||||
EmptyTagUnion => ErrorType::TagUnion(SendMap::default(), TypeExt::Closed, pol),
|
EmptyTagUnion => ErrorType::TagUnion(SendMap::default(), TypeExt::Closed, pol),
|
||||||
|
|
||||||
|
@ -4694,6 +4700,7 @@ impl StorageSubs {
|
||||||
),
|
),
|
||||||
FlatType::EmptyRecord => FlatType::EmptyRecord,
|
FlatType::EmptyRecord => FlatType::EmptyRecord,
|
||||||
FlatType::EmptyTagUnion => FlatType::EmptyTagUnion,
|
FlatType::EmptyTagUnion => FlatType::EmptyTagUnion,
|
||||||
|
FlatType::EffectfulFunc => FlatType::EffectfulFunc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5084,6 +5091,8 @@ fn storage_copy_var_to_help(env: &mut StorageCopyVarToEnv<'_>, var: Variable) ->
|
||||||
|
|
||||||
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectfulFunc => EffectfulFunc,
|
||||||
};
|
};
|
||||||
|
|
||||||
env.target
|
env.target
|
||||||
|
@ -5552,6 +5561,7 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
||||||
|
|
||||||
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
||||||
}
|
}
|
||||||
|
EffectfulFunc => EffectfulFunc,
|
||||||
};
|
};
|
||||||
|
|
||||||
env.target
|
env.target
|
||||||
|
@ -5890,6 +5900,8 @@ fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) {
|
||||||
stack.push(ext.var());
|
stack.push(ext.var());
|
||||||
stack.push(rec_var);
|
stack.push(rec_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectfulFunc => {}
|
||||||
},
|
},
|
||||||
Alias(_, args, var, _) => {
|
Alias(_, args, var, _) => {
|
||||||
let var = *var;
|
let var = *var;
|
||||||
|
@ -5997,7 +6009,7 @@ pub fn get_member_lambda_sets_at_region(subs: &Subs, var: Variable, target_regio
|
||||||
);
|
);
|
||||||
stack.push(ext.var());
|
stack.push(ext.var());
|
||||||
}
|
}
|
||||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion => {}
|
FlatType::EffectfulFunc | FlatType::EmptyRecord | FlatType::EmptyTagUnion => {}
|
||||||
},
|
},
|
||||||
Content::Alias(_, _, real_var, _) => {
|
Content::Alias(_, _, real_var, _) => {
|
||||||
stack.push(*real_var);
|
stack.push(*real_var);
|
||||||
|
@ -6073,6 +6085,7 @@ fn is_inhabited(subs: &Subs, var: Variable) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FlatType::EffectfulFunc => {}
|
||||||
FlatType::FunctionOrTagUnion(_, _, _) => {}
|
FlatType::FunctionOrTagUnion(_, _, _) => {}
|
||||||
FlatType::EmptyRecord => {}
|
FlatType::EmptyRecord => {}
|
||||||
FlatType::EmptyTagUnion => {
|
FlatType::EmptyTagUnion => {
|
||||||
|
|
|
@ -3660,6 +3660,7 @@ pub enum ErrorType {
|
||||||
/// If the name was auto-generated, it will start with a `#`.
|
/// If the name was auto-generated, it will start with a `#`.
|
||||||
FlexVar(Lowercase),
|
FlexVar(Lowercase),
|
||||||
RigidVar(Lowercase),
|
RigidVar(Lowercase),
|
||||||
|
EffectfulFunc,
|
||||||
/// If the name was auto-generated, it will start with a `#`.
|
/// If the name was auto-generated, it will start with a `#`.
|
||||||
FlexAbleVar(Lowercase, AbilitySet),
|
FlexAbleVar(Lowercase, AbilitySet),
|
||||||
RigidAbleVar(Lowercase, AbilitySet),
|
RigidAbleVar(Lowercase, AbilitySet),
|
||||||
|
@ -3750,6 +3751,7 @@ impl ErrorType {
|
||||||
t.add_names(taken);
|
t.add_names(taken);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
EffectfulFunc => {}
|
||||||
Error => {}
|
Error => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3902,6 +3904,7 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
|
||||||
buf.push(')');
|
buf.push(')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EffectfulFunc => buf.push_str("EffectfulFunc"),
|
||||||
Type(symbol, arguments) => {
|
Type(symbol, arguments) => {
|
||||||
let write_parens = parens == Parens::InTypeParam && !arguments.is_empty();
|
let write_parens = parens == Parens::InTypeParam && !arguments.is_empty();
|
||||||
|
|
||||||
|
|
|
@ -3334,6 +3334,17 @@ fn unify_flat_type<M: MetaCollector>(
|
||||||
|
|
||||||
outcome
|
outcome
|
||||||
}
|
}
|
||||||
|
(EffectfulFunc, Func(args, closure, ret, fx)) => {
|
||||||
|
let mut outcome = unify_pool(env, pool, Variable::EFFECTFUL, *fx, ctx.mode);
|
||||||
|
|
||||||
|
outcome.union(merge(
|
||||||
|
env,
|
||||||
|
ctx,
|
||||||
|
Structure(Func(*args, *closure, *ret, Variable::EFFECTFUL)),
|
||||||
|
));
|
||||||
|
|
||||||
|
outcome
|
||||||
|
}
|
||||||
(FunctionOrTagUnion(tag_names, tag_symbols, ext), Func(args, closure, ret, fx)) => {
|
(FunctionOrTagUnion(tag_names, tag_symbols, ext), Func(args, closure, ret, fx)) => {
|
||||||
unify_function_or_tag_union_and_func(
|
unify_function_or_tag_union_and_func(
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use roc_build::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use roc_collections::MutMap;
|
use roc_collections::MutMap;
|
||||||
use roc_error_macros::todo_lambda_erasure;
|
use roc_error_macros::{internal_error, todo_lambda_erasure};
|
||||||
use roc_gen_llvm::run_roc::RocCallResult;
|
use roc_gen_llvm::run_roc::RocCallResult;
|
||||||
use roc_load::{ExecutionMode, FunctionKind, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
use roc_load::{ExecutionMode, FunctionKind, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||||
use roc_mono::ir::{generate_glue_procs, CrashTag, GlueProc, OptLevel};
|
use roc_mono::ir::{generate_glue_procs, CrashTag, GlueProc, OptLevel};
|
||||||
|
@ -324,6 +324,7 @@ fn number_lambda_sets(subs: &Subs, initial: Variable) -> Vec<Variable> {
|
||||||
|
|
||||||
EmptyRecord => (),
|
EmptyRecord => (),
|
||||||
EmptyTagUnion => (),
|
EmptyTagUnion => (),
|
||||||
|
EffectfulFunc => internal_error!(),
|
||||||
|
|
||||||
Record(fields, ext) => {
|
Record(fields, ext) => {
|
||||||
let fields = *fields;
|
let fields = *fields;
|
||||||
|
|
|
@ -1340,7 +1340,8 @@ fn add_type_help<'a>(
|
||||||
Content::FlexVar(_)
|
Content::FlexVar(_)
|
||||||
| Content::RigidVar(_)
|
| Content::RigidVar(_)
|
||||||
| Content::FlexAbleVar(_, _)
|
| Content::FlexAbleVar(_, _)
|
||||||
| Content::RigidAbleVar(_, _) => {
|
| Content::RigidAbleVar(_, _)
|
||||||
|
| Content::Structure(FlatType::EffectfulFunc) => {
|
||||||
todo!("TODO give a nice error message for a non-concrete type being passed to the host")
|
todo!("TODO give a nice error message for a non-concrete type being passed to the host")
|
||||||
}
|
}
|
||||||
Content::Structure(FlatType::Tuple(..)) => {
|
Content::Structure(FlatType::Tuple(..)) => {
|
||||||
|
|
|
@ -2767,6 +2767,8 @@ fn to_doc_help<'b>(
|
||||||
alloc.type_variable(lowercase)
|
alloc.type_variable(lowercase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EffectfulFunc => alloc.text("effectful function"),
|
||||||
|
|
||||||
Type(symbol, args) => report_text::apply(
|
Type(symbol, args) => report_text::apply(
|
||||||
alloc,
|
alloc,
|
||||||
parens,
|
parens,
|
||||||
|
@ -2961,6 +2963,7 @@ fn count_generated_name_usages<'a>(
|
||||||
RigidVar(name) | RigidAbleVar(name, _) => {
|
RigidVar(name) | RigidAbleVar(name, _) => {
|
||||||
debug_assert!(!is_generated_name(name));
|
debug_assert!(!is_generated_name(name));
|
||||||
}
|
}
|
||||||
|
EffectfulFunc => {}
|
||||||
Type(_, tys) => {
|
Type(_, tys) => {
|
||||||
stack.extend(tys.iter().map(|t| (t, only_unseen)));
|
stack.extend(tys.iter().map(|t| (t, only_unseen)));
|
||||||
}
|
}
|
||||||
|
@ -3820,7 +3823,9 @@ fn should_show_diff(t1: &ErrorType, t2: &ErrorType) -> bool {
|
||||||
| (RecursiveTagUnion(_, _, _, _), _)
|
| (RecursiveTagUnion(_, _, _, _), _)
|
||||||
| (_, RecursiveTagUnion(_, _, _, _))
|
| (_, RecursiveTagUnion(_, _, _, _))
|
||||||
| (Function(_, _, _, _), _)
|
| (Function(_, _, _, _), _)
|
||||||
| (_, Function(_, _, _, _)) => true,
|
| (_, Function(_, _, _, _))
|
||||||
|
| (EffectfulFunc, _)
|
||||||
|
| (_, EffectfulFunc) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4861,7 +4866,7 @@ fn type_problem_to_pretty<'b>(
|
||||||
};
|
};
|
||||||
|
|
||||||
match tipe {
|
match tipe {
|
||||||
Infinite | Error | FlexVar(_) => alloc.nil(),
|
Infinite | Error | FlexVar(_) | EffectfulFunc => alloc.nil(),
|
||||||
FlexAbleVar(_, other_abilities) => {
|
FlexAbleVar(_, other_abilities) => {
|
||||||
rigid_able_vs_different_flex_able(x, abilities, other_abilities)
|
rigid_able_vs_different_flex_able(x, abilities, other_abilities)
|
||||||
}
|
}
|
||||||
|
@ -4954,6 +4959,7 @@ fn type_problem_to_pretty<'b>(
|
||||||
};
|
};
|
||||||
bad_rigid_var(x, msg)
|
bad_rigid_var(x, msg)
|
||||||
}
|
}
|
||||||
|
EffectfulFunc => alloc.reflow("an effectful function"),
|
||||||
RigidVar(y) | RigidAbleVar(y, _) => bad_double_rigid(x, y),
|
RigidVar(y) | RigidAbleVar(y, _) => bad_double_rigid(x, y),
|
||||||
Function(_, _, _, _) => bad_rigid_var(x, alloc.reflow("a function value")),
|
Function(_, _, _, _) => bad_rigid_var(x, alloc.reflow("a function value")),
|
||||||
Record(_, _) => bad_rigid_var(x, alloc.reflow("a record value")),
|
Record(_, _) => bad_rigid_var(x, alloc.reflow("a record value")),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue