Use a shared env for desugaring and the rest of canonicalization

This refactor simplifies the desugar pass by reducing the number of
arguments threaded through each recursive function call.

- Add the module src string to `Env`.
- Add `line_info` to `Env` as a lazy-evaled function.
- Refactor desugar functions to take the `can::Env` struct in place of a
  number of params. This is mostly a find-and-replace, but in a few
  places `Vec::from_iter_in` was changed to `Vec::with_capacity_in`
  followed by a `for` loop in order to avoid lifetime issues.
- Remove unnecessary linter annotations for `clippy::too_many_arguments`
This commit is contained in:
Elias Mulhall 2024-09-03 11:56:07 -04:00
parent 640bd15ca1
commit b515bfa77e
No known key found for this signature in database
GPG key ID: 8D1F3C219EAB45F2
6 changed files with 349 additions and 880 deletions

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ use roc_collections::{MutMap, VecSet};
use roc_module::ident::{Ident, ModuleName};
use roc_module::symbol::{IdentIdsByModule, ModuleId, PQModuleName, PackageModuleIds, Symbol};
use roc_problem::can::{Problem, RuntimeError};
use roc_region::all::{Loc, Region};
use roc_region::all::{LineInfo, Loc, Region};
use roc_types::subs::Variable;
/// The canonicalization environment for a particular module.
@ -44,11 +44,16 @@ pub struct Env<'a> {
pub arena: &'a Bump,
pub opt_shorthand: Option<&'a str>,
pub src: &'a str,
line_info: &'a mut Option<LineInfo>,
}
impl<'a> Env<'a> {
pub fn new(
arena: &'a Bump,
src: &'a str,
home: ModuleId,
module_path: &'a Path,
dep_idents: &'a IdentIdsByModule,
@ -57,6 +62,7 @@ impl<'a> Env<'a> {
) -> Env<'a> {
Env {
arena,
src,
home,
module_path,
dep_idents,
@ -69,6 +75,7 @@ impl<'a> Env<'a> {
top_level_symbols: VecSet::default(),
home_params_record: None,
opt_shorthand,
line_info: arena.alloc(None),
}
}
@ -219,4 +226,14 @@ impl<'a> Env<'a> {
pub fn problem(&mut self, problem: Problem) {
self.problems.push(problem)
}
/// Lazily calculate line_info only if required. This way it there are no
/// `dbg` statements, we never pay the cast of scanning the source an extra
/// time.
pub fn line_info(&mut self) -> &LineInfo {
if self.line_info.is_none() {
*self.line_info = Some(LineInfo::new(self.src));
}
self.line_info.as_ref().unwrap()
}
}

View file

@ -240,6 +240,7 @@ pub fn canonicalize_module_defs<'a>(
);
let mut env = Env::new(
arena,
src,
home,
arena.alloc(Path::new(module_path)),
dep_idents,
@ -266,16 +267,7 @@ 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,
&mut scope,
loc_defs,
src,
&mut None,
module_path,
true,
&mut env.problems,
);
crate::desugar::desugar_defs_node_values(&mut env, &mut scope, loc_defs, true);
let mut rigid_variables = RigidVariables::default();

View file

@ -53,6 +53,17 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
Default::default(),
);
let dep_idents = IdentIds::exposed_builtins(0);
let mut env = Env::new(
arena,
expr_str,
home,
Path::new("Test.roc"),
&dep_idents,
&qualified_module_ids,
None,
);
// Desugar operators (convert them to Apply calls, taking into account
// operator precedence and associativity rules), before doing other canonicalization.
//
@ -60,15 +71,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
// visited a BinOp node we'd recursively try to apply this to each of its nested
// operators, and then again on *their* nested operators, ultimately applying the
// rules multiple times unnecessarily.
let loc_expr = desugar::desugar_expr(
arena,
&mut scope,
&loc_expr,
expr_str,
&mut None,
arena.alloc("TestPath"),
&mut Default::default(),
);
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
scope.add_alias(
Symbol::NUM_INT,
@ -82,15 +85,6 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
roc_types::types::AliasKind::Structural,
);
let dep_idents = IdentIds::exposed_builtins(0);
let mut env = Env::new(
arena,
home,
Path::new("Test.roc"),
&dep_idents,
&qualified_module_ids,
None,
);
let (loc_expr, output) = canonicalize_expr(
&mut env,
&mut var_store,

View file

@ -6,32 +6,39 @@ mod suffixed_tests {
use bumpalo::Bump;
use insta::assert_snapshot;
use roc_can::desugar::desugar_defs_node_values;
use roc_can::env::Env;
use roc_can::scope::Scope;
use roc_module::symbol::{IdentIds, ModuleIds};
use roc_module::symbol::{IdentIds, ModuleIds, PackageModuleIds};
use roc_parse::test_helpers::parse_defs_with;
use std::path::Path;
macro_rules! run_test {
($src:expr) => {{
let arena = &Bump::new();
let home = ModuleIds::default().get_or_insert(&"Test".into());
let mut scope = Scope::new(
home,
"TestPath".into(),
IdentIds::default(),
Default::default(),
);
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
desugar_defs_node_values(
let dep_idents = IdentIds::exposed_builtins(0);
let qualified_module_ids = PackageModuleIds::default();
let mut env = Env::new(
arena,
&mut scope,
&mut defs,
$src,
&mut None,
"test.roc",
true,
&mut Default::default(),
home,
Path::new("test.roc"),
&dep_idents,
&qualified_module_ids,
None,
);
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
desugar_defs_node_values(&mut env, &mut scope, &mut defs, true);
let snapshot = format!("{:#?}", &defs);
println!("{}", snapshot);
assert_snapshot!(snapshot);

View file

@ -168,6 +168,17 @@ pub fn can_expr_with<'a>(
Default::default(),
);
let dep_idents = IdentIds::exposed_builtins(0);
let mut env = Env::new(
arena,
expr_str,
home,
Path::new("Test.roc"),
&dep_idents,
&module_ids,
None,
);
// Desugar operators (convert them to Apply calls, taking into account
// operator precedence and associativity rules), before doing other canonicalization.
//
@ -175,25 +186,8 @@ pub fn can_expr_with<'a>(
// visited a BinOp node we'd recursively try to apply this to each of its nested
// operators, and then again on *their* nested operators, ultimately applying the
// rules multiple times unnecessarily.
let loc_expr = desugar::desugar_expr(
arena,
&mut scope,
&loc_expr,
expr_str,
&mut None,
arena.alloc("TestPath"),
&mut Default::default(),
);
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
let dep_idents = IdentIds::exposed_builtins(0);
let mut env = Env::new(
arena,
home,
Path::new("Test.roc"),
&dep_idents,
&module_ids,
None,
);
let (loc_expr, output) = canonicalize_expr(
&mut env,
&mut var_store,