Parse effectful arrow in function annotations

This commit is contained in:
Agus Zubiaga 2024-09-17 20:41:14 -03:00
parent 1a5776653c
commit ef4eeb5c1a
No known key found for this signature in database
30 changed files with 178 additions and 19 deletions

View file

@ -448,7 +448,7 @@ pub fn find_type_def_symbols(
stack.push(&t.value);
}
}
Function(arguments, result) => {
Function(arguments, _arrow, result) => {
for t in arguments.iter() {
stack.push(&t.value);
}
@ -554,7 +554,8 @@ fn can_annotation_help(
use roc_parse::ast::TypeAnnotation::*;
match annotation {
Function(argument_types, return_type) => {
Function(argument_types, _arrow, return_type) => {
// [purity-inference] TODO: arrow
let mut args = Vec::new();
for arg in *argument_types {

View file

@ -149,7 +149,7 @@ impl<'a> Formattable for TypeAnnotation<'a> {
}
Wildcard | Inferred | BoundVariable(_) | Malformed(_) => false,
Function(args, result) => {
Function(args, _arrow, result) => {
result.value.is_multiline()
|| args.iter().any(|loc_arg| loc_arg.value.is_multiline())
}
@ -195,7 +195,8 @@ impl<'a> Formattable for TypeAnnotation<'a> {
let self_is_multiline = self.is_multiline();
match self {
Function(args, ret) => {
Function(args, _arrow, ret) => {
// [purity-infrence] TODO: format arrow
let needs_parens = parens != Parens::NotNeeded;
buf.indent(indent);

View file

@ -443,7 +443,8 @@ fn contains_unexposed_type(
Malformed(_) | Inferred | Wildcard | BoundVariable(_) => false,
Function(loc_args, loc_ret) => {
Function(loc_args, _arrow, loc_ret) => {
// [purity-inference] TODO: arrow
let loc_args_contains_unexposed_type = loc_args.iter().any(|loc_arg| {
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
});
@ -611,7 +612,8 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) ->
ast::TypeAnnotation::SpaceAfter(&sub_type_ann, _) => {
type_to_docs(in_func_type_ann, sub_type_ann)
}
ast::TypeAnnotation::Function(ast_arg_anns, output_ann) => {
ast::TypeAnnotation::Function(ast_arg_anns, _arrow, output_ann) => {
// [purity-inference] TODO: arrow
let mut doc_arg_anns = Vec::new();
for ast_arg_ann in ast_arg_anns {

View file

@ -1530,10 +1530,22 @@ impl ImplementsAbilities<'_> {
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FunctionArrow {
/// ->
Pure,
/// =>
Effectful,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum TypeAnnotation<'a> {
/// A function. The types of its arguments, then the type of its return value.
Function(&'a [Loc<TypeAnnotation<'a>>], &'a Loc<TypeAnnotation<'a>>),
/// A function. The types of its arguments, the type of arrow used, then the type of its return value.
Function(
&'a [Loc<TypeAnnotation<'a>>],
FunctionArrow,
&'a Loc<TypeAnnotation<'a>>,
),
/// Applying a type to some arguments (e.g. Map.Map String Int)
Apply(&'a str, &'a str, &'a [Loc<TypeAnnotation<'a>>]),
@ -2755,7 +2767,7 @@ impl<'a> Malformed for ModuleImportParams<'a> {
impl<'a> Malformed for TypeAnnotation<'a> {
fn is_malformed(&self) -> bool {
match self {
TypeAnnotation::Function(args, ret) => {
TypeAnnotation::Function(args, _arrow, ret) => {
args.iter().any(|arg| arg.is_malformed()) || ret.is_malformed()
}
TypeAnnotation::Apply(_, _, args) => args.iter().any(|arg| arg.is_malformed()),

View file

@ -881,8 +881,9 @@ impl<'a> Normalize<'a> for Pattern<'a> {
impl<'a> Normalize<'a> for TypeAnnotation<'a> {
fn normalize(&self, arena: &'a Bump) -> Self {
match *self {
TypeAnnotation::Function(a, b) => TypeAnnotation::Function(
TypeAnnotation::Function(a, arrow, b) => TypeAnnotation::Function(
arena.alloc(a.normalize(arena)),
arrow,
arena.alloc(b.normalize(arena)),
),
TypeAnnotation::Apply(a, b, c) => TypeAnnotation::Apply(a, b, c.normalize(arena)),

View file

@ -1,6 +1,7 @@
use crate::ast::{
AbilityImpls, AssignedField, CommentOrNewline, Expr, ImplementsAbilities, ImplementsAbility,
ImplementsClause, Pattern, Spaceable, Spaced, Tag, TypeAnnotation, TypeHeader,
AbilityImpls, AssignedField, CommentOrNewline, Expr, FunctionArrow, ImplementsAbilities,
ImplementsAbility, ImplementsClause, Pattern, Spaceable, Spaced, Tag, TypeAnnotation,
TypeHeader,
};
use crate::blankspace::{
space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
@ -594,16 +595,23 @@ fn expression<'a>(
],
))
.trace("type_annotation:expression:rest_args"),
skip_second(
and(
space0_e(EType::TIndentStart),
two_bytes(b'-', b'>', EType::TStart),
one_of![
map(two_bytes(b'-', b'>', EType::TStart), |_| {
FunctionArrow::Pure
}),
map(two_bytes(b'=', b'>', EType::TStart), |_| {
FunctionArrow::Effectful
}),
],
)
.trace("type_annotation:expression:arrow"),
)
.parse(arena, state.clone(), min_indent);
let (progress, annot, state) = match result {
Ok((p2, (rest, space_before_arrow), state)) => {
Ok((p2, (rest, (space_before_arrow, arrow)), state)) => {
let (p3, return_type, state) =
space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
.parse(arena, state, min_indent)?;
@ -626,7 +634,7 @@ fn expression<'a>(
let result = Loc {
region,
value: TypeAnnotation::Function(output, arena.alloc(return_type)),
value: TypeAnnotation::Function(output, arrow, arena.alloc(return_type)),
};
let progress = p1.or(p2).or(p3);
(progress, result, state)

View file

@ -40,6 +40,7 @@ SpaceAfter(
],
),
],
Pure,
@40-43 Apply(
"",
"U64",

View file

@ -35,6 +35,7 @@ SpaceAfter(
"a",
),
],
Pure,
@30-33 Apply(
"",
"U64",
@ -55,6 +56,7 @@ SpaceAfter(
"a",
),
],
Pure,
@49-52 Apply(
"",
"U64",

View file

@ -31,6 +31,7 @@ SpaceAfter(
"a",
),
],
Pure,
@28-31 Apply(
"",
"U64",

View file

@ -38,6 +38,7 @@ SpaceAfter(
"a",
),
],
Pure,
@26-28 Record {
fields: [],
ext: None,
@ -75,6 +76,7 @@ SpaceAfter(
"a",
),
],
Pure,
@79-81 Record {
fields: [],
ext: None,

View file

@ -0,0 +1,5 @@
launchTheNukes : {} -> Result Bool LaunchNukeErr
launchTheNukes = \{} ->
crash "todo"
launchTheNukes

View file

@ -0,0 +1,94 @@
SpaceAfter(
Defs(
Defs {
tags: [
Index(2147483648),
],
regions: [
@0-89,
],
space_before: [
Slice(start = 0, length = 0),
],
space_after: [
Slice(start = 0, length = 0),
],
spaces: [],
type_defs: [],
value_defs: [
AnnotatedBody {
ann_pattern: @0-14 Identifier {
ident: "launchTheNukes",
},
ann_type: @17-48 Function(
[
@17-19 Record {
fields: [],
ext: None,
},
],
Effectful,
@23-48 Apply(
"",
"Result",
[
@30-34 Apply(
"",
"Bool",
[],
),
@35-48 Apply(
"",
"LaunchNukeErr",
[],
),
],
),
),
lines_between: [
Newline,
],
body_pattern: @49-63 Identifier {
ident: "launchTheNukes",
},
body_expr: @66-89 Closure(
[
@67-69 RecordDestructure(
[],
),
],
@77-89 SpaceBefore(
Apply(
@77-82 Crash,
[
@83-89 Str(
PlainLine(
"todo",
),
),
],
Space,
),
[
Newline,
],
),
),
},
],
},
@91-105 SpaceBefore(
Var {
module_name: "",
ident: "launchTheNukes",
},
[
Newline,
Newline,
],
),
),
[
Newline,
],
)

View file

@ -0,0 +1,5 @@
launchTheNukes : {} => Result Bool LaunchNukeErr
launchTheNukes = \{} ->
crash "todo"
launchTheNukes

View file

@ -46,6 +46,7 @@ Defs(
ext: None,
},
],
Pure,
@39-44 Apply(
"",
"Table",

View file

@ -37,6 +37,7 @@ SpaceAfter(
),
},
],
Pure,
@14-20 Tuple {
elems: [
@15-18 Apply(

View file

@ -28,6 +28,7 @@ SpaceAfter(
[],
),
],
Pure,
@11-21 Tuple {
elems: [
@12-15 Apply(

View file

@ -51,6 +51,7 @@ Defs {
"a",
),
],
Pure,
@34-38 Apply(
"",
"Bool",

View file

@ -55,6 +55,7 @@ SpaceAfter(
[],
),
],
Pure,
@65-75 Apply(
"",
"Effect",

View file

@ -32,6 +32,7 @@ SpaceAfter(
ext: None,
},
],
Pure,
@19-24 Apply(
"",
"Model",
@ -55,6 +56,7 @@ SpaceAfter(
[],
),
],
Pure,
@49-54 Apply(
"",
"Model",
@ -73,6 +75,7 @@ SpaceAfter(
[],
),
],
Pure,
@72-75 Apply(
"",
"Str",

View file

@ -37,6 +37,7 @@ Defs(
ext: None,
},
],
Pure,
@17-27 Tuple {
elems: [
@18-21 Apply(

View file

@ -41,6 +41,7 @@ Defs(
),
},
],
Pure,
@18-29 Tuple {
elems: [
@19-22 Apply(

View file

@ -27,6 +27,7 @@ Defs(
[],
),
],
Pure,
@20-30 Apply(
"",
"Task",

View file

@ -32,6 +32,7 @@ Defs(
[],
),
],
Pure,
@20-24 Apply(
"",
"Bool",

View file

@ -27,12 +27,14 @@ SpaceAfter(
"a",
),
],
Pure,
@10-16 Function(
[
@10-11 BoundVariable(
"b",
),
],
Pure,
@15-16 BoundVariable(
"c",
),

View file

@ -34,6 +34,7 @@ SpaceAfter(
"a",
),
],
Pure,
@9-10 BoundVariable(
"b",
),
@ -89,6 +90,7 @@ SpaceAfter(
"a",
),
],
Pure,
@84-85 BoundVariable(
"b",
),

View file

@ -27,12 +27,14 @@ SpaceAfter(
"a",
),
],
Pure,
@10-16 Function(
[
@10-11 BoundVariable(
"b",
),
],
Pure,
@15-16 BoundVariable(
"c",
),

View file

@ -28,12 +28,14 @@ SpaceAfter(
"a",
),
],
Pure,
@10-16 Function(
[
@10-11 BoundVariable(
"b",
),
],
Pure,
@15-16 BoundVariable(
"c",
),

View file

@ -28,6 +28,7 @@ SpaceAfter(
"a",
),
],
Pure,
@9-12 Apply(
"",
"U64",

View file

@ -275,6 +275,7 @@ mod test_snapshots {
pass/add_var_with_spaces.expr,
pass/add_with_spaces.expr,
pass/ann_closed_union.expr,
pass/ann_effectful_fn.expr,
pass/ann_open_union.expr,
pass/annotated_record_destructure.expr,
pass/annotated_tag_destructure.expr,

View file

@ -386,9 +386,11 @@ impl IterTokens for PlatformRequires<'_> {
impl IterTokens for Loc<TypeAnnotation<'_>> {
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
match self.value {
TypeAnnotation::Function(params, ret) => (params.iter_tokens(arena).into_iter())
.chain(ret.iter_tokens(arena))
.collect_in(arena),
TypeAnnotation::Function(params, _arrow, ret) => {
(params.iter_tokens(arena).into_iter())
.chain(ret.iter_tokens(arena))
.collect_in(arena)
}
TypeAnnotation::Apply(_mod, _type, args) => args.iter_tokens(arena),
TypeAnnotation::BoundVariable(_) => onetoken(Token::Type, self.region, arena),
TypeAnnotation::As(ty, _, as_ty) => (ty.iter_tokens(arena).into_iter())