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

@ -1,7 +1,7 @@
use crate::abilities::SpecializationId;
use crate::annotation::{freshen_opaque_def, IntroducedVariables};
use crate::builtins::builtin_defs_map;
use crate::def::{can_defs_with_return, Annotation, Def};
use crate::def::{can_defs_with_return, Annotation, Def, DefKind};
use crate::env::Env;
use crate::num::{
finish_parsing_base, finish_parsing_float, finish_parsing_num, float_expr_from_result,
@ -12,7 +12,7 @@ use crate::pattern::{canonicalize_pattern, BindingsFromPattern, Pattern, PermitS
use crate::procedure::{QualifiedReference, References};
use crate::scope::{Scope, SymbolLookup};
use crate::traverse::{walk_expr, Visitor};
use roc_collections::soa::Index;
use roc_collections::soa::index_push_new;
use roc_collections::{SendMap, VecMap, VecSet};
use roc_error_macros::internal_error;
use roc_module::called_via::CalledVia;
@ -27,6 +27,7 @@ use roc_region::all::{Loc, Region};
use roc_types::num::SingleQuoteBound;
use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, RedundantMark, VarStore, Variable};
use roc_types::types::{Alias, Category, IndexOrField, LambdaSet, OptAbleVar, Type};
use soa::Index;
use std::fmt::{Debug, Display};
use std::path::PathBuf;
use std::sync::Arc;
@ -38,7 +39,7 @@ pub type PendingDerives = VecMap<Symbol, (Type, Vec<Loc<Symbol>>)>;
#[derive(Clone, Default, Debug)]
pub struct Output {
pub references: References,
pub tail_call: Option<Symbol>,
pub tail_calls: Vec<Symbol>,
pub introduced_variables: IntroducedVariables,
pub aliases: VecMap<Symbol, Alias>,
pub non_closures: VecSet<Symbol>,
@ -49,8 +50,8 @@ impl Output {
pub fn union(&mut self, other: Self) {
self.references.union_mut(&other.references);
if let (None, Some(later)) = (self.tail_call, other.tail_call) {
self.tail_call = Some(later);
if self.tail_calls.is_empty() && !other.tail_calls.is_empty() {
self.tail_calls = other.tail_calls;
}
self.introduced_variables
@ -202,7 +203,7 @@ pub enum Expr {
/// This is *only* for calling functions, not for tag application.
/// The Tag variant contains any applied values inside it.
Call(
Box<(Variable, Loc<Expr>, Variable, Variable)>,
Box<(Variable, Loc<Expr>, Variable, Variable, Variable)>,
Vec<(Variable, Loc<Expr>)>,
CalledVia,
),
@ -318,13 +319,6 @@ pub enum Expr {
lookups_in_cond: Vec<ExpectLookup>,
},
// not parsed, but is generated when lowering toplevel effectful expects
ExpectFx {
loc_condition: Box<Loc<Expr>>,
loc_continuation: Box<Loc<Expr>>,
lookups_in_cond: Vec<ExpectLookup>,
},
Dbg {
source_location: Box<str>,
source: Box<str>,
@ -334,6 +328,11 @@ pub enum Expr {
symbol: Symbol,
},
Return {
return_value: Box<Loc<Expr>>,
return_var: Variable,
},
/// Rendered as empty box in editor
TypedHole(Variable),
@ -406,8 +405,8 @@ impl Expr {
Category::OpaqueWrap(opaque_name)
}
Self::Expect { .. } => Category::Expect,
Self::ExpectFx { .. } => Category::Expect,
Self::Crash { .. } => Category::Crash,
Self::Return { .. } => Category::Return,
Self::Dbg { .. } => Category::Expect,
@ -448,6 +447,8 @@ pub struct ClosureData {
pub function_type: Variable,
pub closure_type: Variable,
pub return_type: Variable,
pub fx_type: Variable,
pub early_returns: Vec<(Variable, Region)>,
pub name: Symbol,
pub captured_symbols: Vec<(Symbol, Variable)>,
pub recursive: Recursive,
@ -524,6 +525,8 @@ impl StructAccessorData {
function_type: function_var,
closure_type: closure_var,
return_type: field_var,
fx_type: Variable::PURE,
early_returns: vec![],
name,
captured_symbols: vec![],
recursive: Recursive::NotRecursive,
@ -597,6 +600,8 @@ impl OpaqueWrapFunctionData {
function_type: function_var,
closure_type: closure_var,
return_type: opaque_var,
fx_type: Variable::PURE,
early_returns: vec![],
name: function_name,
captured_symbols: vec![],
recursive: Recursive::NotRecursive,
@ -762,7 +767,6 @@ pub fn canonicalize_expr<'a>(
let output = Output {
references,
tail_call: None,
..Default::default()
};
@ -830,7 +834,6 @@ pub fn canonicalize_expr<'a>(
let output = Output {
references,
tail_call: None,
..Default::default()
};
@ -947,17 +950,19 @@ pub fn canonicalize_expr<'a>(
output.union(fn_expr_output);
// Default: We're not tail-calling a symbol (by name), we're tail-calling a function value.
output.tail_call = None;
output.tail_calls = vec![];
let expr = match fn_expr.value {
Var(symbol, _) => {
output.references.insert_call(symbol);
// we're tail-calling a symbol by name, check if it's the tail-callable symbol
output.tail_call = match &env.tailcallable_symbol {
Some(tc_sym) if *tc_sym == symbol => Some(symbol),
Some(_) | None => None,
};
if env
.tailcallable_symbol
.is_some_and(|tc_sym| tc_sym == symbol)
{
output.tail_calls.push(symbol);
}
Call(
Box::new((
@ -965,6 +970,7 @@ pub fn canonicalize_expr<'a>(
fn_expr,
var_store.fresh(),
var_store.fresh(),
var_store.fresh(),
)),
args,
*application_style,
@ -1004,6 +1010,7 @@ pub fn canonicalize_expr<'a>(
fn_expr,
var_store.fresh(),
var_store.fresh(),
var_store.fresh(),
)),
args,
*application_style,
@ -1056,7 +1063,7 @@ pub fn canonicalize_expr<'a>(
}
ast::Expr::Defs(loc_defs, loc_ret) => {
// The body expression gets a new scope for canonicalization,
scope.inner_scope(|inner_scope| {
scope.inner_def_scope(|inner_scope| {
let defs: Defs = (*loc_defs).clone();
can_defs_with_return(env, var_store, inner_scope, env.arena.alloc(defs), loc_ret)
})
@ -1083,12 +1090,12 @@ pub fn canonicalize_expr<'a>(
canonicalize_expr(env, var_store, scope, loc_cond.region, &loc_cond.value);
// the condition can never be a tail-call
output.tail_call = None;
output.tail_calls = vec![];
let mut can_branches = Vec::with_capacity(branches.len());
for branch in branches.iter() {
let (can_when_branch, branch_references) = scope.inner_scope(|inner_scope| {
let (can_when_branch, branch_references) = scope.inner_def_scope(|inner_scope| {
canonicalize_when_branch(
env,
var_store,
@ -1108,7 +1115,7 @@ pub fn canonicalize_expr<'a>(
// if code gen mistakenly thinks this is a tail call just because its condition
// happened to be one. (The condition gave us our initial output value.)
if branches.is_empty() {
output.tail_call = None;
output.tail_calls = vec![];
}
// Incorporate all three expressions into a combined Output value.
@ -1170,6 +1177,11 @@ pub fn canonicalize_expr<'a>(
ast::Expr::TrySuffix { .. } => internal_error!(
"a Expr::TrySuffix expression was not completely removed in desugar_value_def_suffixed"
),
ast::Expr::Try => {
// Treat remaining `try` keywords as normal variables so that we can continue to support `Result.try`
canonicalize_var_lookup(env, var_store, scope, "", "try", region)
}
ast::Expr::Tag(tag) => {
let variant_var = var_store.fresh();
let ext_var = var_store.fresh();
@ -1224,36 +1236,6 @@ pub fn canonicalize_expr<'a>(
}
}
}
ast::Expr::Expect(condition, continuation) => {
let mut output = Output::default();
let (loc_condition, output1) =
canonicalize_expr(env, var_store, scope, condition.region, &condition.value);
// Get all the lookups that were referenced in the condition,
// so we can print their values later.
let lookups_in_cond = get_lookup_symbols(&loc_condition.value);
let (loc_continuation, output2) = canonicalize_expr(
env,
var_store,
scope,
continuation.region,
&continuation.value,
);
output.union(output1);
output.union(output2);
(
Expect {
loc_condition: Box::new(loc_condition),
loc_continuation: Box::new(loc_continuation),
lookups_in_cond,
},
output,
)
}
ast::Expr::Dbg => {
// Dbg was not desugared as either part of an `Apply` or a `Pizza` binop, so it's
// invalid.
@ -1306,6 +1288,40 @@ pub fn canonicalize_expr<'a>(
output,
)
}
ast::Expr::Return(return_expr, after_return) => {
let mut output = Output::default();
if let Some(after_return) = after_return {
let region_with_return =
Region::span_across(&return_expr.region, &after_return.region);
env.problem(Problem::StatementsAfterReturn {
region: region_with_return,
});
}
let (loc_return_expr, output1) = canonicalize_expr(
env,
var_store,
scope,
return_expr.region,
&return_expr.value,
);
output.union(output1);
let return_var = var_store.fresh();
scope.early_returns.push((return_var, return_expr.region));
(
Return {
return_value: Box::new(loc_return_expr),
return_var,
},
output,
)
}
ast::Expr::If {
if_thens,
final_else: final_else_branch,
@ -1385,10 +1401,6 @@ pub fn canonicalize_expr<'a>(
Output::default(),
)
}
ast::Expr::MalformedClosure => {
use roc_problem::can::RuntimeError::*;
(RuntimeError(MalformedClosure(region)), Output::default())
}
ast::Expr::MalformedIdent(name, bad_ident) => {
use roc_problem::can::RuntimeError::*;
@ -1541,7 +1553,7 @@ pub fn canonicalize_closure<'a>(
loc_body_expr: &'a Loc<ast::Expr<'a>>,
opt_def_name: Option<Symbol>,
) -> (ClosureData, Output) {
scope.inner_scope(|inner_scope| {
scope.inner_function_scope(|inner_scope| {
canonicalize_closure_body(
env,
var_store,
@ -1656,6 +1668,17 @@ fn canonicalize_closure_body<'a>(
}
}
let mut final_expr = &loc_body_expr;
while let Expr::LetRec(_, inner, _) | Expr::LetNonRec(_, inner) = &final_expr.value {
final_expr = inner;
}
if let Expr::Return { return_value, .. } = &final_expr.value {
env.problem(Problem::ReturnAtEndOfFunction {
region: return_value.region,
});
}
// store the references of this function in the Env. This information is used
// when we canonicalize a surrounding def (if it exists)
env.closures.insert(symbol, output.references.clone());
@ -1669,10 +1692,14 @@ fn canonicalize_closure_body<'a>(
output.non_closures.insert(symbol);
}
let return_type_var = var_store.fresh();
let closure_data = ClosureData {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
return_type: return_type_var,
fx_type: var_store.fresh(),
early_returns: scope.early_returns.clone(),
name: symbol,
captured_symbols,
recursive: Recursive::NotRecursive,
@ -1955,10 +1982,6 @@ fn canonicalize_field<'a>(
SpaceBefore(sub_field, _) | SpaceAfter(sub_field, _) => {
canonicalize_field(env, var_store, scope, sub_field)
}
Malformed(_string) => {
internal_error!("TODO canonicalize malformed record field");
}
}
}
@ -2075,7 +2098,8 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
| other @ TypedHole { .. }
| other @ ForeignCall { .. }
| other @ OpaqueWrapFunction(_)
| other @ Crash { .. } => other,
| other @ Crash { .. }
| other @ Return { .. } => other,
List {
elem_var,
@ -2203,28 +2227,6 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
}
}
ExpectFx {
loc_condition,
loc_continuation,
lookups_in_cond,
} => {
let loc_condition = Loc {
region: loc_condition.region,
value: inline_calls(var_store, loc_condition.value),
};
let loc_continuation = Loc {
region: loc_continuation.region,
value: inline_calls(var_store, loc_continuation.value),
};
ExpectFx {
loc_condition: Box::new(loc_condition),
loc_continuation: Box::new(loc_continuation),
lookups_in_cond,
}
}
Dbg {
source_location,
source,
@ -2266,6 +2268,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
expr_var: def.expr_var,
pattern_vars: def.pattern_vars,
annotation: def.annotation,
kind: def.kind,
});
}
@ -2287,6 +2290,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
expr_var: def.expr_var,
pattern_vars: def.pattern_vars,
annotation: def.annotation,
kind: def.kind,
};
let loc_expr = Loc {
@ -2301,6 +2305,8 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
function_type,
closure_type,
return_type,
fx_type,
early_returns,
recursive,
name,
captured_symbols,
@ -2317,6 +2323,8 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
function_type,
closure_type,
return_type,
fx_type,
early_returns,
recursive,
name,
captured_symbols,
@ -2424,10 +2432,11 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
}
Call(boxed_tuple, args, called_via) => {
let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple;
let (fn_var, loc_expr, closure_var, expr_var, fx_var) = *boxed_tuple;
match loc_expr.value {
Var(symbol, _) if symbol.is_builtin() => {
// NOTE: This assumes builtins are not effectful!
match builtin_defs_map(symbol, var_store) {
Some(Def {
loc_expr:
@ -2471,6 +2480,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
expr_var,
pattern_vars,
annotation: None,
kind: DefKind::Let,
};
loc_answer = Loc {
@ -2495,7 +2505,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
_ => {
// For now, we only inline calls to builtins. Leave this alone!
Call(
Box::new((fn_var, loc_expr, closure_var, expr_var)),
Box::new((fn_var, loc_expr, closure_var, expr_var, fx_var)),
args,
called_via,
)
@ -2534,15 +2544,15 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::Expr::RecordUpdater(_)
| ast::Expr::Crash
| ast::Expr::Dbg
| ast::Expr::Try
| ast::Expr::Underscore(_)
| ast::Expr::MalformedIdent(_, _)
| ast::Expr::Tag(_)
| ast::Expr::OpaqueRef(_)
| ast::Expr::MalformedClosure => true,
| ast::Expr::OpaqueRef(_) => true,
// Newlines are disallowed inside interpolation, and these all require newlines
ast::Expr::DbgStmt(_, _)
| ast::Expr::LowLevelDbg(_, _, _)
| ast::Expr::Expect(_, _)
| ast::Expr::Return(_, _)
| ast::Expr::When(_, _)
| ast::Expr::Backpassing(_, _, _)
| ast::Expr::SpaceBefore(_, _)
@ -2563,9 +2573,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::StrSegment::Plaintext(_) => true,
// Disallow nested interpolation. Alternatively, we could allow it but require
// a comment above it apologizing to the next person who has to read the code.
ast::StrSegment::Interpolated(_) | ast::StrSegment::DeprecatedInterpolated(_) => {
false
}
ast::StrSegment::Interpolated(_) => false,
})
}
ast::Expr::Record(fields) => fields.iter().all(|loc_field| match loc_field.value {
@ -2574,7 +2582,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
}
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
ast::AssignedField::LabelOnly(_) => true,
ast::AssignedField::SpaceBefore(_, _) | ast::AssignedField::SpaceAfter(_, _) => false,
}),
ast::Expr::Tuple(fields) => fields
@ -2625,7 +2633,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
}
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
ast::AssignedField::LabelOnly(_) => true,
ast::AssignedField::SpaceBefore(_, _)
| ast::AssignedField::SpaceAfter(_, _) => false,
})
@ -2638,7 +2646,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::AssignedField::IgnoredValue(_label, loc_comments, loc_val) => {
loc_comments.is_empty() && is_valid_interpolation(&loc_val.value)
}
ast::AssignedField::Malformed(_) | ast::AssignedField::LabelOnly(_) => true,
ast::AssignedField::LabelOnly(_) => true,
ast::AssignedField::SpaceBefore(_, _)
| ast::AssignedField::SpaceAfter(_, _) => false,
})
@ -2696,7 +2704,7 @@ fn flatten_str_lines<'a>(
);
}
},
Interpolated(loc_expr) | DeprecatedInterpolated(loc_expr) => {
Interpolated(loc_expr) => {
if is_valid_interpolation(loc_expr.value) {
// Interpolations desugar to Str.concat calls
output.references.insert_call(Symbol::STR_CONCAT);
@ -2763,6 +2771,7 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec<StrSegment>) ->
fn_expr,
var_store.fresh(),
var_store.fresh(),
var_store.fresh(),
)),
vec![
(var_store.fresh(), empty_string),
@ -2799,6 +2808,7 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec<StrSegment>) ->
fn_expr,
var_store.fresh(),
var_store.fresh(),
var_store.fresh(),
)),
vec![
(var_store.fresh(), loc_new_expr),
@ -2845,6 +2855,7 @@ impl Declarations {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
declarations: Vec::with_capacity(capacity),
@ -2891,6 +2902,8 @@ impl Declarations {
let function_def = FunctionDef {
closure_type: loc_closure_data.value.closure_type,
return_type: loc_closure_data.value.return_type,
fx_type: loc_closure_data.value.fx_type,
early_returns: loc_closure_data.value.early_returns,
captured_symbols: loc_closure_data.value.captured_symbols,
arguments: loc_closure_data.value.arguments,
};
@ -2900,7 +2913,7 @@ impl Declarations {
let loc_function_def = Loc::at(loc_closure_data.region, function_def);
let function_def_index = Index::push_new(&mut self.function_bodies, loc_function_def);
let function_def_index = index_push_new(&mut self.function_bodies, loc_function_def);
let tag = match loc_closure_data.value.recursive {
Recursive::NotRecursive | Recursive::Recursive => {
@ -2942,6 +2955,8 @@ impl Declarations {
let function_def = FunctionDef {
closure_type: loc_closure_data.value.closure_type,
return_type: loc_closure_data.value.return_type,
fx_type: loc_closure_data.value.fx_type,
early_returns: loc_closure_data.value.early_returns,
captured_symbols: loc_closure_data.value.captured_symbols,
arguments: loc_closure_data.value.arguments,
};
@ -2951,7 +2966,7 @@ impl Declarations {
let loc_function_def = Loc::at(loc_closure_data.region, function_def);
let function_def_index = Index::push_new(&mut self.function_bodies, loc_function_def);
let function_def_index = index_push_new(&mut self.function_bodies, loc_function_def);
if let Some(annotation) = host_annotation {
self.host_exposed_annotations
@ -2991,24 +3006,6 @@ impl Declarations {
index
}
pub fn push_expect_fx(
&mut self,
preceding_comment: Region,
name: Symbol,
loc_expr: Loc<Expr>,
) -> usize {
let index = self.declarations.len();
self.declarations.push(DeclarationTag::ExpectationFx);
self.variables.push(Variable::BOOL);
self.symbols.push(Loc::at(preceding_comment, name));
self.annotations.push(None);
self.expressions.push(loc_expr);
index
}
pub fn push_value_def(
&mut self,
symbol: Loc<Symbol>,
@ -3057,7 +3054,7 @@ impl Declarations {
pattern_vars,
};
let destructure_def_index = Index::push_new(&mut self.destructs, destruct_def);
let destructure_def_index = index_push_new(&mut self.destructs, destruct_def);
self.declarations
.push(DeclarationTag::Destructure(destructure_def_index));
@ -3122,6 +3119,8 @@ impl Declarations {
let function_def = FunctionDef {
closure_type: closure_data.closure_type,
return_type: closure_data.return_type,
fx_type: closure_data.fx_type,
early_returns: closure_data.early_returns,
captured_symbols: closure_data.captured_symbols,
arguments: closure_data.arguments,
};
@ -3129,7 +3128,7 @@ impl Declarations {
let loc_function_def = Loc::at(def.loc_expr.region, function_def);
let function_def_index =
Index::push_new(&mut self.function_bodies, loc_function_def);
index_push_new(&mut self.function_bodies, loc_function_def);
self.declarations[index] = DeclarationTag::Function(function_def_index);
self.expressions[index] = *closure_data.loc_body;
@ -3162,6 +3161,8 @@ impl Declarations {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
fx_type: var_store.fresh(),
early_returns: vec![],
name: self.symbols[index].value,
captured_symbols: vec![],
recursive: Recursive::NotRecursive,
@ -3174,6 +3175,8 @@ impl Declarations {
let function_def = FunctionDef {
closure_type: loc_closure_data.value.closure_type,
return_type: loc_closure_data.value.return_type,
fx_type: loc_closure_data.value.fx_type,
early_returns: loc_closure_data.value.early_returns,
captured_symbols: loc_closure_data.value.captured_symbols,
arguments: loc_closure_data.value.arguments,
};
@ -3181,7 +3184,7 @@ impl Declarations {
let loc_function_def = Loc::at(region, function_def);
let function_def_index =
Index::push_new(&mut self.function_bodies, loc_function_def);
index_push_new(&mut self.function_bodies, loc_function_def);
if let Some(annotation) = &mut self.annotations[index] {
annotation.convert_to_fn(new_args_len, var_store);
@ -3255,12 +3258,6 @@ impl Declarations {
collector.visit_expr(&loc_expr.value, loc_expr.region, var);
}
ExpectationFx => {
let loc_expr =
toplevel_expect_to_inline_expect_fx(self.expressions[index].clone());
collector.visit_expr(&loc_expr.value, loc_expr.region, var);
}
}
}
@ -3279,7 +3276,6 @@ roc_error_macros::assert_sizeof_default!(DeclarationTag, 8);
pub enum DeclarationTag {
Value,
Expectation,
ExpectationFx,
Function(Index<Loc<FunctionDef>>),
Recursive(Index<Loc<FunctionDef>>),
TailRecursive(Index<Loc<FunctionDef>>),
@ -3297,7 +3293,7 @@ impl DeclarationTag {
match self {
Function(_) | Recursive(_) | TailRecursive(_) => 1,
Value => 1,
Expectation | ExpectationFx => 1,
Expectation => 1,
Destructure(_) => 1,
MutualRecursion { length, .. } => length as usize + 1,
}
@ -3308,6 +3304,8 @@ impl DeclarationTag {
pub struct FunctionDef {
pub closure_type: Variable,
pub return_type: Variable,
pub fx_type: Variable,
pub early_returns: Vec<(Variable, Region)>,
pub captured_symbols: Vec<(Symbol, Variable)>,
pub arguments: Vec<(Variable, AnnotatedMark, Loc<Pattern>)>,
}
@ -3441,9 +3439,6 @@ pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
Expr::Expect {
loc_continuation, ..
}
| Expr::ExpectFx {
loc_continuation, ..
}
| Expr::Dbg {
loc_continuation, ..
} => {
@ -3452,6 +3447,9 @@ pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
// Intentionally ignore the lookups in the nested `expect` condition itself,
// because they couldn't possibly influence the outcome of this `expect`!
}
Expr::Return { return_value, .. } => {
stack.push(&return_value.value);
}
Expr::Crash { msg, .. } => stack.push(&msg.value),
Expr::Num(_, _, _, _)
| Expr::Float(_, _, _, _, _)
@ -3496,15 +3494,7 @@ pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
/// This is supposed to happen just before monomorphization:
/// all type errors and such are generated from the user source,
/// but this transformation means that we don't need special codegen for toplevel expects
pub fn toplevel_expect_to_inline_expect_pure(loc_expr: Loc<Expr>) -> Loc<Expr> {
toplevel_expect_to_inline_expect_help(loc_expr, false)
}
pub fn toplevel_expect_to_inline_expect_fx(loc_expr: Loc<Expr>) -> Loc<Expr> {
toplevel_expect_to_inline_expect_help(loc_expr, true)
}
fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: bool) -> Loc<Expr> {
pub fn toplevel_expect_to_inline_expect_pure(mut loc_expr: Loc<Expr>) -> Loc<Expr> {
enum StoredDef {
NonRecursive(Region, Box<Def>),
Recursive(Region, Vec<Def>, IllegalCycleMark),
@ -3542,18 +3532,10 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
}
let expect_region = loc_expr.region;
let expect = if has_effects {
Expr::ExpectFx {
loc_condition: Box::new(loc_expr),
loc_continuation: Box::new(Loc::at_zero(Expr::EmptyRecord)),
lookups_in_cond,
}
} else {
Expr::Expect {
loc_condition: Box::new(loc_expr),
loc_continuation: Box::new(Loc::at_zero(Expr::EmptyRecord)),
lookups_in_cond,
}
let expect = Expr::Expect {
loc_condition: Box::new(loc_expr),
loc_continuation: Box::new(Loc::at_zero(Expr::EmptyRecord)),
lookups_in_cond,
};
let mut loc_expr = Loc::at(expect_region, expect);
@ -3585,11 +3567,6 @@ impl crate::traverse::Visitor for ExpectCollector {
lookups_in_cond,
loc_condition,
..
}
| Expr::ExpectFx {
lookups_in_cond,
loc_condition,
..
} => {
self.expects
.insert(loc_condition.region, lookups_in_cond.to_vec());