Merge pull request #7005 from smores56/deprecate-backpassing

Deprecate backpassing to prepare for eventual removal
This commit is contained in:
Sam Mohr 2024-08-18 08:08:29 -04:00 committed by GitHub
commit 7c7485bb04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 818 additions and 556 deletions

View file

@ -129,8 +129,8 @@ hashDict = \hasher, dict -> Hash.hashUnordered hasher (toList dict) List.walk
toInspectorDict : Dict k v -> Inspector f where k implements Inspect & Hash & Eq, v implements Inspect, f implements InspectFormatter
toInspectorDict = \dict ->
fmt <- Inspect.custom
Inspect.apply (Inspect.dict dict walk Inspect.toInspector Inspect.toInspector) fmt
Inspect.custom \fmt ->
Inspect.apply (Inspect.dict dict walk Inspect.toInspector Inspect.toInspector) fmt
## Return an empty dictionary.
## ```roc
@ -894,9 +894,9 @@ calcNumBuckets = \shifts ->
maxBucketCount
fillBucketsFromData = \buckets0, data, shifts ->
buckets1, (key, _), dataIndex <- List.walkWithIndex data buckets0
(bucketIndex, distAndFingerprint) = nextWhileLess buckets1 key shifts
placeAndShiftUp buckets1 { distAndFingerprint, dataIndex: Num.toU32 dataIndex } bucketIndex
List.walkWithIndex data buckets0 \buckets1, (key, _), dataIndex ->
(bucketIndex, distAndFingerprint) = nextWhileLess buckets1 key shifts
placeAndShiftUp buckets1 { distAndFingerprint, dataIndex: Num.toU32 dataIndex } bucketIndex
nextWhileLess : List Bucket, k, U8 -> (U64, U32) where k implements Hash & Eq
nextWhileLess = \buckets, key, shifts ->
@ -1213,15 +1213,15 @@ expect
]
dict =
acc, k <- List.walk badKeys (Dict.empty {})
Dict.update acc k \val ->
when val is
Present p -> Present (p |> Num.addWrap 1)
Missing -> Present 0
List.walk badKeys (Dict.empty {}) \acc, k ->
Dict.update acc k \val ->
when val is
Present p -> Present (p |> Num.addWrap 1)
Missing -> Present 0
allInsertedCorrectly =
acc, k <- List.walk badKeys Bool.true
acc && Dict.contains dict k
List.walk badKeys Bool.true \acc, k ->
acc && Dict.contains dict k
allInsertedCorrectly

View file

@ -138,203 +138,203 @@ dbgInit = \{} -> @DbgFormatter { data: "" }
dbgList : list, ElemWalker (DbgFormatter, Bool) list elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter
dbgList = \content, walkFn, toDbgInspector ->
f0 <- custom
dbgWrite f0 "["
|> \f1 ->
(f2, prependSep), elem <- walkFn content (f1, Bool.false)
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
custom \f0 ->
dbgWrite f0 "["
|> \f1 ->
walkFn content (f1, Bool.false) \(f2, prependSep), elem ->
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
elem
|> toDbgInspector
|> apply f3
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "]"
elem
|> toDbgInspector
|> apply f3
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "]"
dbgSet : set, ElemWalker (DbgFormatter, Bool) set elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter
dbgSet = \content, walkFn, toDbgInspector ->
f0 <- custom
dbgWrite f0 "{"
|> \f1 ->
(f2, prependSep), elem <- walkFn content (f1, Bool.false)
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
custom \f0 ->
dbgWrite f0 "{"
|> \f1 ->
walkFn content (f1, Bool.false) \(f2, prependSep), elem ->
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
elem
|> toDbgInspector
|> apply f3
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "}"
elem
|> toDbgInspector
|> apply f3
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "}"
dbgDict : dict, KeyValWalker (DbgFormatter, Bool) dict key value, (key -> Inspector DbgFormatter), (value -> Inspector DbgFormatter) -> Inspector DbgFormatter
dbgDict = \d, walkFn, keyToInspector, valueToInspector ->
f0 <- custom
dbgWrite f0 "{"
|> \f1 ->
(f2, prependSep), key, value <- walkFn d (f1, Bool.false)
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
custom \f0 ->
dbgWrite f0 "{"
|> \f1 ->
walkFn d (f1, Bool.false) \(f2, prependSep), key, value ->
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
apply (keyToInspector key) f3
|> dbgWrite ": "
|> \x -> apply (valueToInspector value) x
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "}"
apply (keyToInspector key) f3
|> dbgWrite ": "
|> \x -> apply (valueToInspector value) x
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "}"
dbgTag : Str, List (Inspector DbgFormatter) -> Inspector DbgFormatter
dbgTag = \name, fields ->
if List.isEmpty fields then
f0 <- custom
dbgWrite f0 name
custom \f0 ->
dbgWrite f0 name
else
f0 <- custom
dbgWrite f0 "("
|> dbgWrite name
|> \f1 ->
f2, inspector <- List.walk fields f1
dbgWrite f2 " "
|> \x -> apply inspector x
|> dbgWrite ")"
custom \f0 ->
dbgWrite f0 "("
|> dbgWrite name
|> \f1 ->
List.walk fields f1 \f2, inspector ->
dbgWrite f2 " "
|> \x -> apply inspector x
|> dbgWrite ")"
dbgTuple : List (Inspector DbgFormatter) -> Inspector DbgFormatter
dbgTuple = \fields ->
f0 <- custom
dbgWrite f0 "("
|> \f1 ->
(f2, prependSep), inspector <- List.walk fields (f1, Bool.false)
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
custom \f0 ->
dbgWrite f0 "("
|> \f1 ->
List.walk fields (f1, Bool.false) \(f2, prependSep), inspector ->
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
apply inspector f3
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite ")"
apply inspector f3
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite ")"
dbgRecord : List { key : Str, value : Inspector DbgFormatter } -> Inspector DbgFormatter
dbgRecord = \fields ->
f0 <- custom
dbgWrite f0 "{"
|> \f1 ->
(f2, prependSep), { key, value } <- List.walk fields (f1, Bool.false)
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
custom \f0 ->
dbgWrite f0 "{"
|> \f1 ->
List.walk fields (f1, Bool.false) \(f2, prependSep), { key, value } ->
f3 =
if prependSep then
dbgWrite f2 ", "
else
f2
dbgWrite f3 key
|> dbgWrite ": "
|> \x -> apply value x
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "}"
dbgWrite f3 key
|> dbgWrite ": "
|> \x -> apply value x
|> \f4 -> (f4, Bool.true)
|> .0
|> dbgWrite "}"
dbgBool : Bool -> Inspector DbgFormatter
dbgBool = \b ->
if b then
f0 <- custom
dbgWrite f0 "Bool.true"
custom \f0 ->
dbgWrite f0 "Bool.true"
else
f0 <- custom
dbgWrite f0 "Bool.false"
custom \f0 ->
dbgWrite f0 "Bool.false"
dbgStr : Str -> Inspector DbgFormatter
dbgStr = \s ->
f0 <- custom
f0
|> dbgWrite "\""
|> dbgWrite s # TODO: Should we be escaping strings for dbg/logging?
|> dbgWrite "\""
custom \f0 ->
f0
|> dbgWrite "\""
|> dbgWrite s # TODO: Should we be escaping strings for dbg/logging?
|> dbgWrite "\""
dbgOpaque : * -> Inspector DbgFormatter
dbgOpaque = \_ ->
f0 <- custom
dbgWrite f0 "<opaque>"
custom \f0 ->
dbgWrite f0 "<opaque>"
dbgFunction : * -> Inspector DbgFormatter
dbgFunction = \_ ->
f0 <- custom
dbgWrite f0 "<function>"
custom \f0 ->
dbgWrite f0 "<function>"
dbgU8 : U8 -> Inspector DbgFormatter
dbgU8 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgI8 : I8 -> Inspector DbgFormatter
dbgI8 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgU16 : U16 -> Inspector DbgFormatter
dbgU16 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgI16 : I16 -> Inspector DbgFormatter
dbgI16 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgU32 : U32 -> Inspector DbgFormatter
dbgU32 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgI32 : I32 -> Inspector DbgFormatter
dbgI32 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgU64 : U64 -> Inspector DbgFormatter
dbgU64 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgI64 : I64 -> Inspector DbgFormatter
dbgI64 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgU128 : U128 -> Inspector DbgFormatter
dbgU128 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgI128 : I128 -> Inspector DbgFormatter
dbgI128 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgF32 : F32 -> Inspector DbgFormatter
dbgF32 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgF64 : F64 -> Inspector DbgFormatter
dbgF64 = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgDec : Dec -> Inspector DbgFormatter
dbgDec = \num ->
f0 <- custom
dbgWrite f0 (num |> Num.toStr)
custom \f0 ->
dbgWrite f0 (num |> Num.toStr)
dbgWrite : DbgFormatter, Str -> DbgFormatter
dbgWrite = \@DbgFormatter { data }, added ->

View file

@ -62,8 +62,8 @@ hashSet = \hasher, @Set inner -> Hash.hash hasher inner
toInspectorSet : Set k -> Inspector f where k implements Inspect & Hash & Eq, f implements InspectFormatter
toInspectorSet = \set ->
fmt <- Inspect.custom
Inspect.apply (Inspect.set set walk Inspect.toInspector) fmt
Inspect.custom \fmt ->
Inspect.apply (Inspect.set set walk Inspect.toInspector) fmt
## Creates a new empty `Set`.
## ```roc

View file

@ -12,6 +12,7 @@ use roc_parse::ast::{
AssignedField, Collection, ModuleImportParams, OldRecordBuilderField, Pattern, StrLiteral,
StrSegment, TypeAnnotation, ValueDef, WhenBranch,
};
use roc_problem::can::Problem;
use roc_region::all::{LineInfo, Loc, Region};
// BinOp precedence logic adapted from Gluon by Markus Westerlind
@ -74,13 +75,14 @@ fn desugar_value_def<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> ValueDef<'a> {
use ValueDef::*;
match def {
Body(loc_pattern, loc_expr) => Body(
desugar_loc_pattern(arena, loc_pattern, src, line_info, module_path),
desugar_expr(arena, loc_expr, src, line_info, module_path),
desugar_loc_pattern(arena, loc_pattern, src, line_info, module_path, problems),
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
),
ann @ Annotation(_, _) => *ann,
AnnotatedBody {
@ -93,16 +95,29 @@ fn desugar_value_def<'a>(
ann_pattern,
ann_type,
lines_between,
body_pattern: desugar_loc_pattern(arena, body_pattern, src, line_info, module_path),
body_expr: desugar_expr(arena, body_expr, src, line_info, module_path),
body_pattern: desugar_loc_pattern(
arena,
body_pattern,
src,
line_info,
module_path,
problems,
),
body_expr: desugar_expr(arena, body_expr, src, line_info, module_path, problems),
},
Dbg {
condition,
preceding_comment,
} => {
let desugared_condition =
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
let desugared_condition = &*arena.alloc(desugar_expr(
arena,
condition,
src,
line_info,
module_path,
problems,
));
Dbg {
condition: desugared_condition,
preceding_comment: *preceding_comment,
@ -112,8 +127,14 @@ fn desugar_value_def<'a>(
condition,
preceding_comment,
} => {
let desugared_condition =
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
let desugared_condition = &*arena.alloc(desugar_expr(
arena,
condition,
src,
line_info,
module_path,
problems,
));
Expect {
condition: desugared_condition,
preceding_comment: *preceding_comment,
@ -123,8 +144,14 @@ fn desugar_value_def<'a>(
condition,
preceding_comment,
} => {
let desugared_condition =
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
let desugared_condition = &*arena.alloc(desugar_expr(
arena,
condition,
src,
line_info,
module_path,
problems,
));
ExpectFx {
condition: desugared_condition,
preceding_comment: *preceding_comment,
@ -141,7 +168,14 @@ fn desugar_value_def<'a>(
params.map(|ModuleImportParams { before, params }| ModuleImportParams {
before,
params: params.map(|params| {
desugar_field_collection(arena, *params, src, line_info, module_path)
desugar_field_collection(
arena,
*params,
src,
line_info,
module_path,
problems,
)
}),
});
@ -174,7 +208,7 @@ fn desugar_value_def<'a>(
)),
lines_between: &[],
body_pattern: new_pat,
body_expr: desugar_expr(arena, stmt_expr, src, line_info, module_path),
body_expr: desugar_expr(arena, stmt_expr, src, line_info, module_path, problems),
}
}
}
@ -187,9 +221,17 @@ pub fn desugar_defs_node_values<'a>(
line_info: &mut Option<LineInfo>,
module_path: &str,
top_level_def: bool,
problems: &mut std::vec::Vec<Problem>,
) {
for value_def in defs.value_defs.iter_mut() {
*value_def = desugar_value_def(arena, arena.alloc(*value_def), src, line_info, module_path);
*value_def = desugar_value_def(
arena,
arena.alloc(*value_def),
src,
line_info,
module_path,
problems,
);
}
// `desugar_defs_node_values` is called recursively in `desugar_expr`
@ -312,6 +354,7 @@ pub fn desugar_expr<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> &'a Loc<Expr<'a>> {
match &loc_expr.value {
Float(..)
@ -344,6 +387,7 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
)));
arena.alloc(Loc { region, value })
@ -352,7 +396,7 @@ pub fn desugar_expr<'a>(
let region = loc_expr.region;
let new_lines = Vec::from_iter_in(
lines.iter().map(|segments| {
desugar_str_segments(arena, segments, src, line_info, module_path)
desugar_str_segments(arena, segments, src, line_info, module_path, problems)
}),
arena,
);
@ -375,6 +419,7 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
)
.value,
paths,
@ -389,7 +434,8 @@ pub fn desugar_expr<'a>(
target,
} => {
let intermediate = arena.alloc(Loc::at(loc_expr.region, **sub_expr));
let new_sub_loc_expr = desugar_expr(arena, intermediate, src, line_info, module_path);
let new_sub_loc_expr =
desugar_expr(arena, intermediate, src, line_info, module_path, problems);
let new_sub_expr = arena.alloc(new_sub_loc_expr.value);
arena.alloc(Loc::at(
@ -413,6 +459,7 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
)
.value,
paths,
@ -424,7 +471,14 @@ pub fn desugar_expr<'a>(
let mut new_items = Vec::with_capacity_in(items.len(), arena);
for item in items.iter() {
new_items.push(desugar_expr(arena, item, src, line_info, module_path));
new_items.push(desugar_expr(
arena,
item,
src,
line_info,
module_path,
problems,
));
}
let new_items = new_items.into_bump_slice();
let value: Expr<'a> = List(items.replace_items(new_items));
@ -435,7 +489,8 @@ pub fn desugar_expr<'a>(
})
}
Record(fields) => {
let fields = desugar_field_collection(arena, *fields, src, line_info, module_path);
let fields =
desugar_field_collection(arena, *fields, src, line_info, module_path, problems);
arena.alloc(Loc {
region: loc_expr.region,
value: Record(fields),
@ -444,7 +499,7 @@ pub fn desugar_expr<'a>(
Tuple(fields) => {
let mut allocated = Vec::with_capacity_in(fields.len(), arena);
for field in fields.iter() {
let expr = desugar_expr(arena, field, src, line_info, module_path);
let expr = desugar_expr(arena, field, src, line_info, module_path, problems);
allocated.push(expr);
}
let fields = fields.replace_items(allocated.into_bump_slice());
@ -456,11 +511,12 @@ pub fn desugar_expr<'a>(
RecordUpdate { fields, update } => {
// NOTE the `update` field is always a `Var { .. }`, we only desugar it to get rid of
// any spaces before/after
let new_update = desugar_expr(arena, update, src, line_info, module_path);
let new_update = desugar_expr(arena, update, src, line_info, module_path, problems);
let mut allocated = Vec::with_capacity_in(fields.len(), arena);
for field in fields.iter() {
let value = desugar_field(arena, &field.value, src, line_info, module_path);
let value =
desugar_field(arena, &field.value, src, line_info, module_path, problems);
allocated.push(Loc {
value,
region: field.region,
@ -533,8 +589,8 @@ pub fn desugar_expr<'a>(
Closure(loc_patterns, loc_ret) => arena.alloc(Loc {
region: loc_expr.region,
value: Closure(
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path),
desugar_expr(arena, loc_ret, src, line_info, module_path),
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path, problems),
desugar_expr(arena, loc_ret, src, line_info, module_path, problems),
),
}),
Backpassing(loc_patterns, loc_body, loc_ret) => {
@ -542,12 +598,19 @@ pub fn desugar_expr<'a>(
//
// loc_ret
// first desugar the body, because it may contain |>
let desugared_body = desugar_expr(arena, loc_body, src, line_info, module_path);
let problem_region = Region::span_across(
&Region::across_all(loc_patterns.iter().map(|loc_pattern| &loc_pattern.region)),
&loc_body.region,
);
problems.push(Problem::DeprecatedBackpassing(problem_region));
let desugared_ret = desugar_expr(arena, loc_ret, src, line_info, module_path);
// first desugar the body, because it may contain |>
let desugared_body =
desugar_expr(arena, loc_body, src, line_info, module_path, problems);
let desugared_ret = desugar_expr(arena, loc_ret, src, line_info, module_path, problems);
let desugared_loc_patterns =
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path);
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path, problems);
let closure = Expr::Closure(desugared_loc_patterns, desugared_ret);
let loc_closure = Loc::at(loc_expr.region, closure);
@ -583,7 +646,7 @@ pub fn desugar_expr<'a>(
RecordBuilder { mapper, fields } => {
// NOTE the `mapper` is always a `Var { .. }`, we only desugar it to get rid of
// any spaces before/after
let new_mapper = desugar_expr(arena, mapper, src, line_info, module_path);
let new_mapper = desugar_expr(arena, mapper, src, line_info, module_path, problems);
if fields.is_empty() {
return arena.alloc(Loc {
@ -607,7 +670,8 @@ pub fn desugar_expr<'a>(
for field in fields.items {
let (name, value, ignored) =
match desugar_field(arena, &field.value, src, line_info, module_path) {
match desugar_field(arena, &field.value, src, line_info, module_path, problems)
{
AssignedField::RequiredValue(loc_name, _, loc_val) => {
(loc_name, loc_val, false)
}
@ -845,11 +909,20 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
),
Defs(defs, loc_ret) => {
let mut defs = (*defs).clone();
desugar_defs_node_values(arena, &mut defs, src, line_info, module_path, false);
let loc_ret = desugar_expr(arena, loc_ret, src, line_info, module_path);
desugar_defs_node_values(
arena,
&mut defs,
src,
line_info,
module_path,
false,
problems,
);
let loc_ret = desugar_expr(arena, loc_ret, src, line_info, module_path, problems);
arena.alloc(Loc::at(loc_expr.region, Defs(arena.alloc(defs), loc_ret)))
}
@ -881,14 +954,21 @@ pub fn desugar_expr<'a>(
}
};
desugared_args.push(desugar_expr(arena, arg, src, line_info, module_path));
desugared_args.push(desugar_expr(
arena,
arg,
src,
line_info,
module_path,
problems,
));
}
let desugared_args = desugared_args.into_bump_slice();
let mut apply: &Loc<Expr> = arena.alloc(Loc {
value: Apply(
desugar_expr(arena, loc_fn, src, line_info, module_path),
desugar_expr(arena, loc_fn, src, line_info, module_path, problems),
desugared_args,
*called_via,
),
@ -900,7 +980,8 @@ pub fn desugar_expr<'a>(
Some(apply_exprs) => {
for expr in apply_exprs {
let desugared_expr = desugar_expr(arena, expr, src, line_info, module_path);
let desugared_expr =
desugar_expr(arena, expr, src, line_info, module_path, problems);
let args = std::slice::from_ref(arena.alloc(apply));
@ -921,17 +1002,31 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
));
let mut desugared_branches = Vec::with_capacity_in(branches.len(), arena);
for branch in branches.iter() {
let desugared_expr =
desugar_expr(arena, &branch.value, src, line_info, module_path);
let desugared_patterns =
desugar_loc_patterns(arena, branch.patterns, src, line_info, module_path);
desugar_expr(arena, &branch.value, src, line_info, module_path, problems);
let desugared_patterns = desugar_loc_patterns(
arena,
branch.patterns,
src,
line_info,
module_path,
problems,
);
let desugared_guard = if let Some(guard) = &branch.guard {
Some(*desugar_expr(arena, guard, src, line_info, module_path))
Some(*desugar_expr(
arena,
guard,
src,
line_info,
module_path,
problems,
))
} else {
None
};
@ -969,8 +1064,14 @@ pub fn desugar_expr<'a>(
},
};
let loc_fn_var = arena.alloc(Loc { region, value });
let desugared_args =
arena.alloc([desugar_expr(arena, loc_arg, src, line_info, module_path)]);
let desugared_args = arena.alloc([desugar_expr(
arena,
loc_arg,
src,
line_info,
module_path,
problems,
)]);
arena.alloc(Loc {
value: Apply(loc_fn_var, desugared_args, CalledVia::UnaryOp(op)),
@ -989,6 +1090,7 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
)
}
ParensAround(expr) => {
@ -1001,6 +1103,7 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
);
arena.alloc(Loc {
@ -1016,14 +1119,15 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
));
let mut desugared_if_thens = Vec::with_capacity_in(if_thens.len(), arena);
for (condition, then_branch) in if_thens.iter() {
desugared_if_thens.push((
*desugar_expr(arena, condition, src, line_info, module_path),
*desugar_expr(arena, then_branch, src, line_info, module_path),
*desugar_expr(arena, condition, src, line_info, module_path, problems),
*desugar_expr(arena, then_branch, src, line_info, module_path, problems),
));
}
@ -1033,14 +1137,21 @@ pub fn desugar_expr<'a>(
})
}
Expect(condition, continuation) => {
let desugared_condition =
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
let desugared_condition = &*arena.alloc(desugar_expr(
arena,
condition,
src,
line_info,
module_path,
problems,
));
let desugared_continuation = &*arena.alloc(desugar_expr(
arena,
continuation,
src,
line_info,
module_path,
problems,
));
arena.alloc(Loc {
value: Expect(desugared_condition, desugared_continuation),
@ -1056,6 +1167,7 @@ pub fn desugar_expr<'a>(
src,
line_info,
module_path,
problems,
));
let region = condition.region;
@ -1068,8 +1180,14 @@ pub fn desugar_expr<'a>(
value: inspect_fn,
region,
});
let desugared_inspect_args =
arena.alloc([desugar_expr(arena, condition, src, line_info, module_path)]);
let desugared_inspect_args = arena.alloc([desugar_expr(
arena,
condition,
src,
line_info,
module_path,
problems,
)]);
let dbg_str = arena.alloc(Loc {
value: Apply(loc_inspect_fn_var, desugared_inspect_args, CalledVia::Space),
@ -1114,6 +1232,7 @@ fn desugar_str_segments<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> &'a [StrSegment<'a>] {
Vec::from_iter_in(
segments.iter().map(|segment| match segment {
@ -1130,6 +1249,7 @@ fn desugar_str_segments<'a>(
src,
line_info,
module_path,
problems,
);
StrSegment::DeprecatedInterpolated(Loc {
region: loc_desugared.region,
@ -1146,6 +1266,7 @@ fn desugar_str_segments<'a>(
src,
line_info,
module_path,
problems,
);
StrSegment::Interpolated(Loc {
region: loc_desugared.region,
@ -1164,11 +1285,12 @@ fn desugar_field_collection<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> Collection<'a, Loc<AssignedField<'a, Expr<'a>>>> {
let mut allocated = Vec::with_capacity_in(fields.len(), arena);
for field in fields.iter() {
let value = desugar_field(arena, &field.value, src, line_info, module_path);
let value = desugar_field(arena, &field.value, src, line_info, module_path, problems);
allocated.push(Loc::at(field.region, value));
}
@ -1182,6 +1304,7 @@ fn desugar_field<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> AssignedField<'a, Expr<'a>> {
use roc_parse::ast::AssignedField::*;
@ -1192,7 +1315,7 @@ fn desugar_field<'a>(
region: loc_str.region,
},
spaces,
desugar_expr(arena, loc_expr, src, line_info, module_path),
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
),
OptionalValue(loc_str, spaces, loc_expr) => OptionalValue(
Loc {
@ -1200,7 +1323,7 @@ fn desugar_field<'a>(
region: loc_str.region,
},
spaces,
desugar_expr(arena, loc_expr, src, line_info, module_path),
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
),
IgnoredValue(loc_str, spaces, loc_expr) => IgnoredValue(
Loc {
@ -1208,7 +1331,7 @@ fn desugar_field<'a>(
region: loc_str.region,
},
spaces,
desugar_expr(arena, loc_expr, src, line_info, module_path),
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
),
LabelOnly(loc_str) => {
// Desugar { x } into { x: x }
@ -1226,11 +1349,22 @@ fn desugar_field<'a>(
region: loc_str.region,
},
&[],
desugar_expr(arena, arena.alloc(loc_expr), src, line_info, module_path),
desugar_expr(
arena,
arena.alloc(loc_expr),
src,
line_info,
module_path,
problems,
),
)
}
SpaceBefore(field, _spaces) => desugar_field(arena, field, src, line_info, module_path),
SpaceAfter(field, _spaces) => desugar_field(arena, field, src, line_info, module_path),
SpaceBefore(field, _spaces) => {
desugar_field(arena, field, src, line_info, module_path, problems)
}
SpaceAfter(field, _spaces) => {
desugar_field(arena, field, src, line_info, module_path, problems)
}
Malformed(string) => Malformed(string),
}
@ -1242,11 +1376,19 @@ fn desugar_loc_patterns<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> &'a [Loc<Pattern<'a>>] {
Vec::from_iter_in(
loc_patterns.iter().map(|loc_pattern| Loc {
region: loc_pattern.region,
value: desugar_pattern(arena, loc_pattern.value, src, line_info, module_path),
value: desugar_pattern(
arena,
loc_pattern.value,
src,
line_info,
module_path,
problems,
),
}),
arena,
)
@ -1259,10 +1401,18 @@ fn desugar_loc_pattern<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> &'a Loc<Pattern<'a>> {
arena.alloc(Loc {
region: loc_pattern.region,
value: desugar_pattern(arena, loc_pattern.value, src, line_info, module_path),
value: desugar_pattern(
arena,
loc_pattern.value,
src,
line_info,
module_path,
problems,
),
})
}
@ -1272,6 +1422,7 @@ fn desugar_pattern<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> Pattern<'a> {
use roc_parse::ast::Pattern::*;
@ -1295,7 +1446,14 @@ fn desugar_pattern<'a>(
let desugared_arg_patterns = Vec::from_iter_in(
arg_patterns.iter().map(|arg_pattern| Loc {
region: arg_pattern.region,
value: desugar_pattern(arena, arg_pattern.value, src, line_info, module_path),
value: desugar_pattern(
arena,
arg_pattern.value,
src,
line_info,
module_path,
problems,
),
}),
arena,
)
@ -1306,8 +1464,14 @@ fn desugar_pattern<'a>(
RecordDestructure(field_patterns) => {
let mut allocated = Vec::with_capacity_in(field_patterns.len(), arena);
for field_pattern in field_patterns.iter() {
let value =
desugar_pattern(arena, field_pattern.value, src, line_info, module_path);
let value = desugar_pattern(
arena,
field_pattern.value,
src,
line_info,
module_path,
problems,
);
allocated.push(Loc {
value,
region: field_pattern.region,
@ -1319,15 +1483,17 @@ fn desugar_pattern<'a>(
}
RequiredField(name, field_pattern) => RequiredField(
name,
desugar_loc_pattern(arena, field_pattern, src, line_info, module_path),
desugar_loc_pattern(arena, field_pattern, src, line_info, module_path, problems),
),
OptionalField(name, expr) => OptionalField(
name,
desugar_expr(arena, expr, src, line_info, module_path, problems),
),
OptionalField(name, expr) => {
OptionalField(name, desugar_expr(arena, expr, src, line_info, module_path))
}
Tuple(patterns) => {
let mut allocated = Vec::with_capacity_in(patterns.len(), arena);
for pattern in patterns.iter() {
let value = desugar_pattern(arena, pattern.value, src, line_info, module_path);
let value =
desugar_pattern(arena, pattern.value, src, line_info, module_path, problems);
allocated.push(Loc {
value,
region: pattern.region,
@ -1340,7 +1506,8 @@ fn desugar_pattern<'a>(
List(patterns) => {
let mut allocated = Vec::with_capacity_in(patterns.len(), arena);
for pattern in patterns.iter() {
let value = desugar_pattern(arena, pattern.value, src, line_info, module_path);
let value =
desugar_pattern(arena, pattern.value, src, line_info, module_path, problems);
allocated.push(Loc {
value,
region: pattern.region,
@ -1351,14 +1518,14 @@ fn desugar_pattern<'a>(
List(patterns)
}
As(sub_pattern, symbol) => As(
desugar_loc_pattern(arena, sub_pattern, src, line_info, module_path),
desugar_loc_pattern(arena, sub_pattern, src, line_info, module_path, problems),
symbol,
),
SpaceBefore(sub_pattern, _spaces) => {
desugar_pattern(arena, *sub_pattern, src, line_info, module_path)
desugar_pattern(arena, *sub_pattern, src, line_info, module_path, problems)
}
SpaceAfter(sub_pattern, _spaces) => {
desugar_pattern(arena, *sub_pattern, src, line_info, module_path)
desugar_pattern(arena, *sub_pattern, src, line_info, module_path, problems)
}
}
}
@ -1479,6 +1646,7 @@ fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
}
}
#[allow(clippy::too_many_arguments)]
fn desugar_bin_ops<'a>(
arena: &'a Bump,
whole_region: Region,
@ -1487,19 +1655,27 @@ fn desugar_bin_ops<'a>(
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
problems: &mut std::vec::Vec<Problem>,
) -> &'a Loc<Expr<'a>> {
let mut arg_stack: Vec<&'a Loc<Expr>> = Vec::with_capacity_in(lefts.len() + 1, arena);
let mut op_stack: Vec<Loc<BinOp>> = Vec::with_capacity_in(lefts.len(), arena);
for (loc_expr, loc_op) in lefts {
arg_stack.push(desugar_expr(arena, loc_expr, src, line_info, module_path));
arg_stack.push(desugar_expr(
arena,
loc_expr,
src,
line_info,
module_path,
problems,
));
match run_binop_step(arena, whole_region, &mut arg_stack, &mut op_stack, *loc_op) {
Err(problem) => return problem,
Ok(()) => continue,
}
}
let mut expr = desugar_expr(arena, right, src, line_info, module_path);
let mut expr = desugar_expr(arena, right, src, line_info, module_path, problems);
for (left, loc_op) in arg_stack.into_iter().zip(op_stack.into_iter()).rev() {
expr = arena.alloc(new_op_call_expr(arena, left, loc_op, expr));

View file

@ -337,7 +337,15 @@ pub fn canonicalize_module_defs<'a>(
// operators, and then again on *their* nested operators, ultimately applying the
// rules multiple times unnecessarily.
crate::desugar::desugar_defs_node_values(arena, loc_defs, src, &mut None, module_path, true);
crate::desugar::desugar_defs_node_values(
arena,
loc_defs,
src,
&mut None,
module_path,
true,
&mut env.problems,
);
let mut rigid_variables = RigidVariables::default();

View file

@ -59,6 +59,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
expr_str,
&mut None,
arena.alloc("TestPath"),
&mut Default::default(),
);
let mut scope = Scope::new(

View file

@ -12,7 +12,15 @@ mod suffixed_tests {
($src:expr) => {{
let arena = &Bump::new();
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
desugar_defs_node_values(arena, &mut defs, $src, &mut None, "test.roc", true);
desugar_defs_node_values(
arena,
&mut defs,
$src,
&mut None,
"test.roc",
true,
&mut Default::default(),
);
let snapshot = format!("{:#?}", &defs);
println!("{}", snapshot);

View file

@ -174,6 +174,7 @@ pub fn can_expr_with<'a>(
expr_str,
&mut None,
arena.alloc("TestPath"),
&mut Default::default(),
);
let mut scope = Scope::new(

View file

@ -4816,7 +4816,7 @@ mod test_reporting {
expression_indentation_end,
indoc!(
r"
f <- Foo.foo
f = Foo.foo
"
),
@r#"
@ -4827,8 +4827,8 @@ mod test_reporting {
1 app "test" provides [main] to "./platform"
2
3 main =
4 f <- Foo.foo
^
4 f = Foo.foo
^
Looks like the indentation ends prematurely here. Did you mean to have
another expression after this line?
@ -6617,34 +6617,6 @@ All branches in an `if` must have the same type!
"
);
test_report!(
backpassing_type_error,
indoc!(
r#"
x <- List.map ["a", "b"]
x + 1
"#
),
@r#"
TYPE MISMATCH in /code/proj/Main.roc
This 2nd argument to `map` has an unexpected type:
4> x <- List.map ["a", "b"]
5>
6> x + 1
The argument is an anonymous function of type:
Num * -> Num *
But `map` needs its 2nd argument to be:
Str -> Num *
"#
);
test_report!(
expect_expr_type_error,
indoc!(
@ -10198,9 +10170,9 @@ All branches in an `if` must have the same type!
withOpen : (Handle -> Result {} *) -> Result {} *
withOpen = \callback ->
handle <- await (open {})
{} <- await (callback handle)
close handle
await (open {}) \handle ->
await (callback handle) \_ ->
close handle
withOpen
"
@ -10212,9 +10184,9 @@ All branches in an `if` must have the same type!
10 withOpen : (Handle -> Result {} *) -> Result {} *
11 withOpen = \callback ->
12> handle <- await (open {})
13> {} <- await (callback handle)
14> close handle
12> await (open {}) \handle ->
13> await (callback handle) \_ ->
14> close handle
The type annotation on `withOpen` says this `await` call should have the
type:
@ -10227,6 +10199,7 @@ All branches in an `if` must have the same type!
Tip: Any connection between types must use a named type variable, not
a `*`! Maybe the annotation on `withOpen` should have a named type
variable in place of the `*`?
"
);
@ -10830,7 +10803,7 @@ All branches in an `if` must have the same type!
7 a: <- "a",
^^^
Tip: Remove `<-` to assign the field directly.
Tip: Remove <- to assign the field directly.
"#
);
@ -10962,7 +10935,7 @@ All branches in an `if` must have the same type!
6 { xyz <-
^^^
Note: Record builders need a mapper function before the `<-` to combine
Note: Record builders need a mapper function before the <- to combine
fields together with.
"#
);
@ -11844,6 +11817,32 @@ All branches in an `if` must have the same type!
@r"
"
);
test_report!(
deprecated_backpassing,
indoc!(
r#"
foo = \bar ->
baz <- Result.try bar
Ok (baz * 3)
foo (Ok 123)
"#
),
@r###"
BACKPASSING DEPRECATED in /code/proj/Main.roc
Backpassing (<-) like this will soon be deprecated:
5 baz <- Result.try bar
^^^^^^^^^^^^^^^^^^^^^
You should use a ! for awaiting tasks or a ? for trying results, and
functions everywhere else.
"###
);
test_report!(
unknown_shorthand_no_deps,
indoc!(
@ -13881,7 +13880,7 @@ All branches in an `if` must have the same type!
"#
),
@r#"
DEFINITIONs ONLY USED IN RECURSION in /code/proj/Main.roc
DEFINITIONS ONLY USED IN RECURSION in /code/proj/Main.roc
These 2 definitions are only used in mutual recursion with themselves:
@ -13890,6 +13889,7 @@ All branches in an `if` must have the same type!
If you don't intend to use or export any of them, they should all be
removed!
"#
);
@ -13953,7 +13953,7 @@ All branches in an `if` must have the same type!
"#
),
@r#"
DEFINITIONs ONLY USED IN RECURSION in /code/proj/Main.roc
DEFINITIONS ONLY USED IN RECURSION in /code/proj/Main.roc
These 2 definitions are only used in mutual recursion with themselves:
@ -13962,6 +13962,7 @@ All branches in an `if` must have the same type!
If you don't intend to use or export any of them, they should all be
removed!
"#
);

View file

@ -118,6 +118,23 @@ impl std::fmt::Display for UnaryOp {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Suffix {
/// (!), e.g. (Stdin.line!)
Bang,
/// (?), e.g. (parseData? data)
Question,
}
impl std::fmt::Display for Suffix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Suffix::Bang => write!(f, "!"),
Suffix::Question => write!(f, "?"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BinOp {
// highest precedence

View file

@ -54,6 +54,7 @@ pub enum Problem {
new_symbol: Symbol,
existing_symbol_region: Region,
},
DeprecatedBackpassing(Region),
/// First symbol is the name of the closure with that argument
/// Bool is whether the closure is anonymous
/// Second symbol is the name of the argument that is unused
@ -257,6 +258,7 @@ impl Problem {
Problem::ExplicitBuiltinImport(_, _) => Warning,
Problem::ExplicitBuiltinTypeImport(_, _) => Warning,
Problem::ImportShadowsSymbol { .. } => RuntimeError,
Problem::DeprecatedBackpassing(_) => Warning,
Problem::ExposedButNotDefined(_) => RuntimeError,
Problem::UnknownGeneratesWith(_) => RuntimeError,
Problem::UnusedArgument(_, _, _, _) => Warning,
@ -340,6 +342,7 @@ impl Problem {
| Problem::ExplicitBuiltinImport(_, region)
| Problem::ExplicitBuiltinTypeImport(_, region)
| Problem::ImportShadowsSymbol { region, .. }
| Problem::DeprecatedBackpassing(region)
| Problem::UnknownGeneratesWith(Loc { region, .. })
| Problem::UnusedArgument(_, _, _, region)
| Problem::UnusedBranchDef(_, region)

View file

@ -2479,39 +2479,6 @@ fn expanded_result() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn backpassing_result() {
assert_evals_to!(
indoc!(
r#"
app "test" provides [main] to "./platform"
a : Result I64 Str
a = Ok 1
f = \x -> Ok (x + 1)
g = \y -> Ok (y * 2)
main : I64
main =
helper =
x <- Result.try a
y <- Result.try (f x)
z <- Result.try (g y)
Ok z
helper
|> Result.withDefault 0
"#
),
4,
i64
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[should_panic(expected = "Shadowing { original_region: @55-56, shadow: @72-73 Ident")]

View file

@ -3389,8 +3389,8 @@ fn inspect_custom_type() {
myToInspector : HelloWorld -> Inspector f where f implements InspectFormatter
myToInspector = \@HellowWorld {} ->
fmt <- Inspect.custom
Inspect.apply (Inspect.str "Hello, World!\n") fmt
Inspect.custom \fmt ->
Inspect.apply (Inspect.str "Hello, World!\n") fmt
main =
Inspect.inspect (@HelloWorld {})