Add fx to ErrorType

This commit is contained in:
Agus Zubiaga 2024-10-17 22:59:44 -03:00
parent 8a65617704
commit 6533e9084d
No known key found for this signature in database
6 changed files with 66 additions and 30 deletions

View file

@ -57,8 +57,8 @@ pub fn remove_module_param_arguments(
drop_last_argument(expected); drop_last_argument(expected);
if let ( if let (
ErrorType::Function(found_args, _, _), ErrorType::Function(found_args, _, _, _),
ErrorType::Function(expected_args, _, _), ErrorType::Function(expected_args, _, _, _),
) = (found, expected) ) = (found, expected)
{ {
if found_args.len() > expected_args.len() { if found_args.len() > expected_args.len() {
@ -194,7 +194,7 @@ fn remove_for_reason(
fn drop_last_argument(err_type: &mut ErrorType) { fn drop_last_argument(err_type: &mut ErrorType) {
match err_type { match err_type {
ErrorType::Function(arguments, _, _) => { ErrorType::Function(arguments, _, _, _) => {
arguments.pop(); arguments.pop();
} }
// Irrelevant // Irrelevant

View file

@ -1,7 +1,7 @@
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
use crate::types::{ use crate::types::{
name_type_var, AbilitySet, AliasKind, ErrorType, ExtImplicitOpenness, Polarity, RecordField, name_type_var, AbilitySet, AliasKind, ErrorFunctionFx, ErrorType, ExtImplicitOpenness,
RecordFieldsError, TupleElemsError, TypeExt, Uls, Polarity, RecordField, RecordFieldsError, TupleElemsError, TypeExt, Uls,
}; };
use crate::unification_table::{self, UnificationTable}; use crate::unification_table::{self, UnificationTable};
use roc_collections::all::{FnvMap, ImMap, ImSet, MutSet, SendMap}; use roc_collections::all::{FnvMap, ImMap, ImSet, MutSet, SendMap};
@ -4206,7 +4206,7 @@ fn flat_type_to_err_type(
ErrorType::Type(symbol, arg_types) ErrorType::Type(symbol, arg_types)
} }
Func(arg_vars, closure_var, ret_var, _fx_var) => { Func(arg_vars, closure_var, ret_var, fx_var) => {
let args = arg_vars let args = arg_vars
.into_iter() .into_iter()
.map(|index| { .map(|index| {
@ -4217,9 +4217,23 @@ fn flat_type_to_err_type(
let ret = var_to_err_type(subs, state, ret_var, Polarity::Pos); let ret = var_to_err_type(subs, state, ret_var, Polarity::Pos);
let closure = var_to_err_type(subs, state, closure_var, pol); let closure = var_to_err_type(subs, state, closure_var, pol);
let fx = match subs.get_content_without_compacting(fx_var) {
Content::Pure | Content::FlexVar(_) | Content::Error => ErrorFunctionFx::Pure,
Content::Effectful => ErrorFunctionFx::Effectful,
Content::RigidVar(_)
| Content::FlexAbleVar(_, _)
| Content::RigidAbleVar(_, _)
| Content::RecursionVar { .. }
| Content::LambdaSet(_)
| Content::ErasedLambda
| Content::Structure(_)
| Content::Alias(_, _, _, _)
| Content::RangedNumber(_) => {
internal_error!("Unexpected content in fx var")
}
};
// [purity-inference] TODO: add fx var to the error type ErrorType::Function(args, Box::new(closure), fx, Box::new(ret))
ErrorType::Function(args, Box::new(closure), Box::new(ret))
} }
EmptyRecord => ErrorType::Record(SendMap::default(), TypeExt::Closed), EmptyRecord => ErrorType::Record(SendMap::default(), TypeExt::Closed),

View file

@ -3680,12 +3680,23 @@ pub enum ErrorType {
TypeExt, TypeExt,
Polarity, Polarity,
), ),
Function(Vec<ErrorType>, Box<ErrorType>, Box<ErrorType>), Function(
Vec<ErrorType>,
Box<ErrorType>,
ErrorFunctionFx,
Box<ErrorType>,
),
Alias(Symbol, Vec<ErrorType>, Box<ErrorType>, AliasKind), Alias(Symbol, Vec<ErrorType>, Box<ErrorType>, AliasKind),
Range(Vec<ErrorType>), Range(Vec<ErrorType>),
Error, Error,
} }
#[derive(PartialEq, Eq, Clone, Hash)]
pub enum ErrorFunctionFx {
Pure,
Effectful,
}
impl std::fmt::Debug for ErrorType { impl std::fmt::Debug for ErrorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO remove clone // TODO remove clone
@ -3731,7 +3742,7 @@ impl ErrorType {
.for_each(|(_, ts)| ts.iter().for_each(|t| t.add_names(taken))); .for_each(|(_, ts)| ts.iter().for_each(|t| t.add_names(taken)));
ext.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)); args.iter().for_each(|t| t.add_names(taken));
capt.add_names(taken); capt.add_names(taken);
ret.add_names(taken); ret.add_names(taken);
@ -3817,7 +3828,7 @@ fn write_error_type_help(
} }
} }
} }
Function(arguments, _closure, result) => { Function(arguments, _closure, fx, result) => {
let write_parens = parens != Parens::Unnecessary; let write_parens = parens != Parens::Unnecessary;
if write_parens { if write_parens {
@ -3833,7 +3844,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); write_error_type_help(interns, *result, buf, Parens::InFn);
@ -3967,7 +3981,7 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
buf.push(')'); buf.push(')');
} }
} }
Function(arguments, _closure, result) => { Function(arguments, _closure, fx, result) => {
let write_parens = parens != Parens::Unnecessary; let write_parens = parens != Parens::Unnecessary;
if write_parens { if write_parens {
@ -3983,7 +3997,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); write_debug_error_type_help(*result, buf, Parens::InFn);

View file

@ -1406,7 +1406,6 @@ fn add_type_help<'a>(
} }
}, },
Content::Structure(FlatType::Func(args, closure_var, ret_var, _fx_var)) => { Content::Structure(FlatType::Func(args, closure_var, ret_var, _fx_var)) => {
// [purity-inference] TODO: fx var
let is_toplevel = false; // or in any case, we cannot assume that we are let is_toplevel = false; // or in any case, we cannot assume that we are
add_function_type( add_function_type(

View file

@ -1846,7 +1846,7 @@ fn describe_wanted_function(tipe: &ErrorType) -> DescribedFunction {
use ErrorType::*; use ErrorType::*;
match tipe { match tipe {
Function(args, _, _) => DescribedFunction::Arguments(args.len()), Function(args, _, _, _) => DescribedFunction::Arguments(args.len()),
Alias(_, _, actual, AliasKind::Structural) => describe_wanted_function(actual), Alias(_, _, actual, AliasKind::Structural) => describe_wanted_function(actual),
Alias(_, _, actual, AliasKind::Opaque) => { Alias(_, _, actual, AliasKind::Opaque) => {
let tag = if matches!( let tag = if matches!(
@ -2698,12 +2698,13 @@ fn to_doc_help<'b>(
use ErrorType::*; use ErrorType::*;
match tipe { match tipe {
Function(args, _, ret) => report_text::function( Function(args, _, fx, ret) => report_text::function(
alloc, alloc,
parens, parens,
args.into_iter() args.into_iter()
.map(|arg| to_doc_help(ctx, gen_usages, alloc, Parens::InFn, arg)) .map(|arg| to_doc_help(ctx, gen_usages, alloc, Parens::InFn, arg))
.collect(), .collect(),
fx,
to_doc_help(ctx, gen_usages, alloc, Parens::InFn, *ret), to_doc_help(ctx, gen_usages, alloc, Parens::InFn, *ret),
), ),
Infinite => alloc.text(""), Infinite => alloc.text(""),
@ -2940,7 +2941,7 @@ fn count_generated_name_usages<'a>(
stack.extend(tags.values().flatten().map(|t| (t, only_unseen))); stack.extend(tags.values().flatten().map(|t| (t, only_unseen)));
ext_stack.push((ext, only_unseen)); ext_stack.push((ext, only_unseen));
} }
Function(args, _lset, ret) => { Function(args, _lset, _fx, ret) => {
stack.extend(args.iter().map(|t| (t, only_unseen))); stack.extend(args.iter().map(|t| (t, only_unseen)));
stack.push((ret, only_unseen)); stack.push((ret, only_unseen));
} }
@ -3115,7 +3116,7 @@ fn to_diff<'b>(
} }
} }
(Function(args1, _, ret1), Function(args2, _, ret2)) => { (Function(args1, _, fx1, ret1), Function(args2, _, fx2, ret2)) => {
if args1.len() == args2.len() { if args1.len() == args2.len() {
let mut status = Status::Similar; let mut status = Status::Similar;
let arg_diff = diff_args(alloc, Parens::InFn, args1, args2); let arg_diff = diff_args(alloc, Parens::InFn, args1, args2);
@ -3123,8 +3124,8 @@ fn to_diff<'b>(
status.merge(arg_diff.status); status.merge(arg_diff.status);
status.merge(ret_diff.status); status.merge(ret_diff.status);
let left = report_text::function(alloc, parens, arg_diff.left, ret_diff.left); let left = report_text::function(alloc, parens, arg_diff.left, fx1, ret_diff.left);
let right = report_text::function(alloc, parens, arg_diff.right, ret_diff.right); let right = report_text::function(alloc, parens, arg_diff.right, fx2, ret_diff.right);
let mut left_able = arg_diff.left_able; let mut left_able = arg_diff.left_able;
left_able.extend(ret_diff.left_able); left_able.extend(ret_diff.left_able);
let mut right_able = arg_diff.right_able; let mut right_able = arg_diff.right_able;
@ -3713,9 +3714,10 @@ fn should_show_diff(t1: &ErrorType, t2: &ErrorType) -> bool {
.any(|(p1, p2)| should_show_diff(p1, p2)) .any(|(p1, p2)| should_show_diff(p1, p2))
}) })
} }
(Function(params1, ret1, l1), Function(params2, ret2, l2)) => { (Function(params1, ret1, fx1, l1), Function(params2, ret2, fx2, l2)) => {
if params1.len() != params2.len() if params1.len() != params2.len()
|| should_show_diff(ret1, ret2) || should_show_diff(ret1, ret2)
|| fx1 != fx2
|| should_show_diff(l1, l2) || should_show_diff(l1, l2)
{ {
return true; return true;
@ -3777,8 +3779,8 @@ fn should_show_diff(t1: &ErrorType, t2: &ErrorType) -> bool {
| (_, TagUnion(_, _, _)) | (_, TagUnion(_, _, _))
| (RecursiveTagUnion(_, _, _, _), _) | (RecursiveTagUnion(_, _, _, _), _)
| (_, RecursiveTagUnion(_, _, _, _)) | (_, RecursiveTagUnion(_, _, _, _))
| (Function(_, _, _), _) | (Function(_, _, _, _), _)
| (_, Function(_, _, _)) => true, | (_, Function(_, _, _, _)) => true,
} }
} }
@ -4236,7 +4238,7 @@ mod report_text {
use crate::report::{Annotation, RocDocAllocator, RocDocBuilder}; use crate::report::{Annotation, RocDocAllocator, RocDocBuilder};
use roc_module::ident::Lowercase; use roc_module::ident::Lowercase;
use roc_types::pretty_print::Parens; use roc_types::pretty_print::Parens;
use roc_types::types::{ErrorType, RecordField, TypeExt}; use roc_types::types::{ErrorFunctionFx, ErrorType, RecordField, TypeExt};
use ven_pretty::DocAllocator; use ven_pretty::DocAllocator;
fn with_parens<'b>( fn with_parens<'b>(
@ -4250,11 +4252,15 @@ mod report_text {
alloc: &'b RocDocAllocator<'b>, alloc: &'b RocDocAllocator<'b>,
parens: Parens, parens: Parens,
args: Vec<RocDocBuilder<'b>>, args: Vec<RocDocBuilder<'b>>,
fx: ErrorFunctionFx,
ret: RocDocBuilder<'b>, ret: RocDocBuilder<'b>,
) -> RocDocBuilder<'b> { ) -> RocDocBuilder<'b> {
let function_doc = alloc.concat([ let function_doc = alloc.concat([
alloc.intersperse(args, alloc.reflow(", ")), alloc.intersperse(args, alloc.reflow(", ")),
alloc.reflow(" -> "), match fx {
ErrorFunctionFx::Pure => alloc.text(" -> "),
ErrorFunctionFx::Effectful => alloc.text(" => "),
},
ret, ret,
]); ]);
@ -4820,7 +4826,7 @@ fn type_problem_to_pretty<'b>(
rigid_able_vs_different_flex_able(x, abilities, other_abilities) rigid_able_vs_different_flex_able(x, abilities, other_abilities)
} }
RigidVar(y) | RigidAbleVar(y, _) => bad_double_rigid(x, y), RigidVar(y) | RigidAbleVar(y, _) => bad_double_rigid(x, y),
Function(_, _, _) => rigid_able_vs_concrete(x, alloc.reflow("a function value")), Function(_, _, _, _) => rigid_able_vs_concrete(x, alloc.reflow("a function value")),
Record(_, _) => rigid_able_vs_concrete(x, alloc.reflow("a record value")), Record(_, _) => rigid_able_vs_concrete(x, alloc.reflow("a record value")),
Tuple(_, _) => rigid_able_vs_concrete(x, alloc.reflow("a tuple value")), Tuple(_, _) => rigid_able_vs_concrete(x, alloc.reflow("a tuple value")),
TagUnion(_, _, _) | RecursiveTagUnion(_, _, _, _) => { TagUnion(_, _, _) | RecursiveTagUnion(_, _, _, _) => {
@ -4909,7 +4915,7 @@ fn type_problem_to_pretty<'b>(
bad_rigid_var(x, msg) bad_rigid_var(x, msg)
} }
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")),
Tuple(_, _) => bad_rigid_var(x, alloc.reflow("a tuple value")), Tuple(_, _) => bad_rigid_var(x, alloc.reflow("a tuple value")),
TagUnion(_, _, _) | RecursiveTagUnion(_, _, _, _) => { TagUnion(_, _, _) | RecursiveTagUnion(_, _, _, _) => {