Merge remote-tracking branch 'upstream/MAIN' into early-return-if-else

This commit is contained in:
snobee 2024-09-06 17:11:28 -07:00
commit e82dd43465
No known key found for this signature in database
GPG key ID: 77D517A21B16CC87
28 changed files with 761 additions and 1087 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,19 @@ pub struct Env<'a> {
pub arena: &'a Bump,
pub opt_shorthand: Option<&'a str>,
pub src: &'a str,
/// Lazily calculated line info. This data is only needed if the code contains calls to `dbg`,
/// otherwise we can leave it as `None` and never pay the cost of scanning the source an extra
/// time.
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 +65,7 @@ impl<'a> Env<'a> {
) -> Env<'a> {
Env {
arena,
src,
home,
module_path,
dep_idents,
@ -69,6 +78,7 @@ impl<'a> Env<'a> {
top_level_symbols: VecSet::default(),
home_params_record: None,
opt_shorthand,
line_info: arena.alloc(None),
}
}
@ -219,4 +229,11 @@ impl<'a> Env<'a> {
pub fn problem(&mut self, problem: Problem) {
self.problems.push(problem)
}
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

@ -1209,8 +1209,20 @@ pub fn canonicalize_expr<'a>(
output,
)
}
ast::Expr::Dbg | ast::Expr::DbgStmt(_, _) => {
internal_error!("Dbg should have been desugared by now")
ast::Expr::Dbg => {
// Dbg was not desugared as either part of an `Apply` or a `Pizza` binop, so it's
// invalid.
env.problem(Problem::UnappliedDbg { region });
let invalid_dbg_expr = crate::desugar::desugar_invalid_dbg_expr(env, scope, region);
let (loc_expr, output) =
canonicalize_expr(env, var_store, scope, region, invalid_dbg_expr);
(loc_expr.value, output)
}
ast::Expr::DbgStmt(_, _) => {
internal_error!("DbgStmt should have been desugared by now")
}
ast::Expr::LowLevelDbg((source_location, source), message, continuation) => {
let mut output = Output::default();

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,
var_store,
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

@ -466,7 +466,7 @@ impl Scope {
self.home.register_debug_idents(&self.locals.ident_ids)
}
/// Generates a unique, new symbol like "$1" or "$5",
/// Generates a unique, new symbol like "1" or "5",
/// using the home module as the module_id.
///
/// This is used, for example, during canonicalization of an Expr::Closure
@ -475,6 +475,12 @@ impl Scope {
Symbol::new(self.home, self.locals.gen_unique())
}
/// Generates a unique new symbol and return the symbol's unqualified identifier name.
pub fn gen_unique_symbol_name(&mut self) -> &str {
let ident_id = self.locals.gen_unique();
self.locals.ident_ids.get_name(ident_id).unwrap()
}
/// Introduce a new ignored variable (variable starting with an underscore).
/// The underscore itself should not be included in `ident`.
pub fn introduce_ignored_local(&mut self, ident: &str, region: Region) {

View file

@ -46,6 +46,24 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
let var = var_store.fresh();
let qualified_module_ids = PackageModuleIds::default();
let mut scope = Scope::new(
home,
"TestPath".into(),
IdentIds::default(),
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.
//
@ -53,22 +71,8 @@ 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 var_store,
&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 mut scope = Scope::new(
home,
"TestPath".into(),
IdentIds::default(),
Default::default(),
);
scope.add_alias(
Symbol::NUM_INT,
Region::zero(),
@ -81,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

@ -1,6 +1,6 @@
---
source: crates/compiler/can/tests/test_suffixed.rs
assertion_line: 449
assertion_line: 463
expression: snapshot
---
Defs {
@ -44,7 +44,7 @@ Defs {
value_defs: [
Body(
@15-26 Identifier {
ident: "64",
ident: "1",
},
@15-26 ParensAround(
Defs(
@ -66,7 +66,7 @@ Defs {
value_defs: [
Body(
@20-25 Identifier {
ident: "63",
ident: "0",
},
@20-25 Apply(
@22-23 Var {
@ -101,14 +101,14 @@ Defs {
[
@20-25 Var {
module_name: "",
ident: "63",
ident: "0",
},
],
Space,
),
@20-25 Var {
module_name: "",
ident: "63",
ident: "0",
},
),
),
@ -129,14 +129,14 @@ Defs {
[
@15-26 Var {
module_name: "",
ident: "64",
ident: "1",
},
],
Space,
),
@15-26 Var {
module_name: "",
ident: "64",
ident: "1",
},
),
),

View file

@ -1,6 +1,6 @@
---
source: crates/compiler/can/tests/test_suffixed.rs
assertion_line: 459
assertion_line: 473
expression: snapshot
---
Defs {
@ -8,7 +8,7 @@ Defs {
Index(2147483648),
],
regions: [
@0-19,
@0-51,
],
space_before: [
Slice(start = 0, length = 0),
@ -25,13 +25,13 @@ Defs {
@0-4 Identifier {
ident: "main",
},
@11-19 Defs(
@11-51 Defs(
Defs {
tags: [
Index(2147483648),
],
regions: [
@11-12,
@11-40,
],
space_before: [
Slice(start = 0, length = 0),
@ -43,36 +43,98 @@ Defs {
type_defs: [],
value_defs: [
Body(
@11-12 Identifier {
ident: "63",
@11-40 Identifier {
ident: "1",
},
@11-12 Num(
"1",
@11-40 Apply(
@31-38 Var {
module_name: "Num",
ident: "add",
},
[
@11-23 Defs(
Defs {
tags: [
Index(2147483648),
],
regions: [
@11-12,
],
space_before: [
Slice(start = 0, length = 0),
],
space_after: [
Slice(start = 0, length = 0),
],
spaces: [],
type_defs: [],
value_defs: [
Body(
@11-12 Identifier {
ident: "0",
},
@11-12 Num(
"1",
),
),
],
},
@11-23 LowLevelDbg(
(
"test.roc:2",
" ",
),
@11-12 Apply(
@11-12 Var {
module_name: "Inspect",
ident: "toStr",
},
[
@11-12 Var {
module_name: "",
ident: "0",
},
],
Space,
),
@11-12 Var {
module_name: "",
ident: "0",
},
),
),
@39-40 Num(
"2",
),
],
BinOp(
Pizza,
),
),
),
],
},
@11-19 LowLevelDbg(
@11-51 LowLevelDbg(
(
"test.roc:2",
" ",
" main =\n 1\n ",
),
@11-12 Apply(
@11-12 Var {
@11-40 Apply(
@11-40 Var {
module_name: "Inspect",
ident: "toStr",
},
[
@11-12 Var {
@11-40 Var {
module_name: "",
ident: "63",
ident: "1",
},
],
Space,
),
@11-12 Var {
@11-40 Var {
module_name: "",
ident: "63",
ident: "1",
},
),
),

View file

@ -6,25 +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, PackageModuleIds};
use roc_parse::test_helpers::parse_defs_with;
use roc_types::subs::VarStore;
use std::path::Path;
macro_rules! run_test {
($src:expr) => {{
let arena = &Bump::new();
let mut var_store = VarStore::default();
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
desugar_defs_node_values(
arena,
&mut var_store,
&mut defs,
$src,
&mut None,
"test.roc",
true,
&mut Default::default(),
let home = ModuleIds::default().get_or_insert(&"Test".into());
let mut scope = Scope::new(
home,
"TestPath".into(),
IdentIds::default(),
Default::default(),
);
let dep_idents = IdentIds::exposed_builtins(0);
let qualified_module_ids = PackageModuleIds::default();
let mut env = Env::new(
arena,
$src,
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);
@ -454,6 +468,19 @@ mod suffixed_tests {
);
}
#[test]
fn pizza_dbg() {
run_test!(
r#"
main =
1
|> dbg
|> Num.add 2
|> dbg
"#
)
}
#[test]
fn apply_argument_single() {
run_test!(

View file

@ -161,23 +161,6 @@ pub fn can_expr_with<'a>(
// ensure the Test module is accessible in our tests
module_ids.get_or_insert(&PQModuleName::Unqualified("Test".into()));
// Desugar operators (convert them to Apply calls, taking into account
// operator precedence and associativity rules), before doing other canonicalization.
//
// If we did this *during* canonicalization, then each time we
// 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 var_store,
&loc_expr,
expr_str,
&mut None,
arena.alloc("TestPath"),
&mut Default::default(),
);
let mut scope = Scope::new(
home,
"TestPath".into(),
@ -188,12 +171,23 @@ pub fn can_expr_with<'a>(
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.
//
// If we did this *during* canonicalization, then each time we
// 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(&mut env, &mut scope, &loc_expr);
let (loc_expr, output) = canonicalize_expr(
&mut env,
&mut var_store,

View file

@ -14521,7 +14521,7 @@ All branches in an `if` must have the same type!
4 1 + dbg + 2
^^^
This `63` value is a:
This value is a:
{}
@ -14555,7 +14555,7 @@ All branches in an `if` must have the same type!
4 1 + dbg "" "" + 2
^^^^^^^^^
This `63` value is a:
This value is a:
{}

View file

@ -1665,7 +1665,7 @@ fn state_thread_step<'a>(
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
}
Msg::FailedToReadFile { filename, error } => {
let buf = to_file_problem_report_string(filename, error);
let buf = to_file_problem_report_string(filename, error, true);
Err(LoadingProblem::FormattedReport(buf))
}
@ -1839,7 +1839,7 @@ pub fn report_loading_problem(
}
LoadingProblem::FormattedReport(report) => report,
LoadingProblem::FileProblem { filename, error } => {
to_file_problem_report_string(filename, error)
to_file_problem_report_string(filename, error, true)
}
LoadingProblem::NoPlatformPackage {
filename,

View file

@ -123,6 +123,10 @@ impl Symbol {
.any(|(_, (s, _))| *s == self)
}
pub fn is_generated(self, interns: &Interns) -> bool {
self.ident_ids(interns).is_generated_id(self.ident_id())
}
pub fn module_string<'a>(&self, interns: &'a Interns) -> &'a ModuleName {
interns
.module_ids
@ -137,24 +141,15 @@ impl Symbol {
}
pub fn as_str(self, interns: &Interns) -> &str {
let ident_ids = interns
.all_ident_ids
.get(&self.module_id())
self.ident_ids(interns)
.get_name(self.ident_id())
.unwrap_or_else(|| {
internal_error!(
"ident_string could not find IdentIds for module {:?} in {:?}",
self.module_id(),
interns
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
self.ident_id().0,
self.module_id()
)
});
ident_ids.get_name(self.ident_id()).unwrap_or_else(|| {
internal_error!(
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
self.ident_id().0,
self.module_id()
)
})
})
}
pub const fn as_u64(self) -> u64 {
@ -186,6 +181,19 @@ impl Symbol {
pub fn contains(self, needle: &str) -> bool {
format!("{self:?}").contains(needle)
}
fn ident_ids(self, interns: &Interns) -> &IdentIds {
interns
.all_ident_ids
.get(&self.module_id())
.unwrap_or_else(|| {
internal_error!(
"ident_string could not find IdentIds for module {:?} in {:?}",
self.module_id(),
interns
)
})
}
}
/// Rather than displaying as this:
@ -707,6 +715,12 @@ impl IdentIds {
IdentId(self.interner.insert_index_str() as u32)
}
pub fn is_generated_id(&self, id: IdentId) -> bool {
self.interner
.try_get(id.0 as usize)
.map_or(false, |str| str.starts_with(|c: char| c.is_ascii_digit()))
}
#[inline(always)]
pub fn get_id(&self, ident_name: &str) -> Option<IdentId> {
self.interner

View file

@ -47,10 +47,10 @@ procedure Str.3 (#Attr.2, #Attr.3):
ret Str.236;
procedure Test.0 ():
let Test.4 : I64 = 1i64;
let Test.1 : I64 = 2i64;
let Test.2 : Str = CallByName Inspect.33 Test.1;
dbg Test.2;
dec Test.2;
let Test.3 : I64 = CallByName Num.19 Test.4 Test.1;
ret Test.3;
let Test.5 : I64 = 1i64;
let Test.2 : I64 = 2i64;
let Test.3 : Str = CallByName Inspect.33 Test.2;
dbg Test.3;
dec Test.3;
let Test.4 : I64 = CallByName Num.19 Test.5 Test.2;
ret Test.4;

View file

@ -44,15 +44,15 @@ procedure Str.3 (#Attr.2, #Attr.3):
ret Str.238;
procedure Test.0 ():
let Test.4 : Str = "Hello ";
let Test.1 : Str = "world";
inc Test.1;
let Test.2 : Str = CallByName Inspect.33 Test.1;
dbg Test.2;
dec Test.2;
let Test.7 : Str = "!";
let Test.5 : Str = CallByName Str.3 Test.1 Test.7;
dec Test.7;
let Test.3 : Str = CallByName Str.3 Test.4 Test.5;
dec Test.5;
ret Test.3;
let Test.5 : Str = "Hello ";
let Test.2 : Str = "world";
inc Test.2;
let Test.3 : Str = CallByName Inspect.33 Test.2;
dbg Test.3;
dec Test.3;
let Test.8 : Str = "!";
let Test.6 : Str = CallByName Str.3 Test.2 Test.8;
dec Test.8;
let Test.4 : Str = CallByName Str.3 Test.5 Test.6;
dec Test.6;
ret Test.4;

View file

@ -43,14 +43,14 @@ procedure Str.3 (#Attr.2, #Attr.3):
ret Str.236;
procedure Test.0 ():
let Test.3 : I64 = 1i64;
let Test.4 : Str = CallByName Inspect.33 Test.3;
dbg Test.4;
dec Test.4;
let Test.5 : Str = CallByName Inspect.33 Test.3;
dbg Test.5;
dec Test.5;
let Test.6 : Str = CallByName Inspect.33 Test.3;
dbg Test.6;
dec Test.6;
ret Test.3;
let Test.6 : I64 = 1i64;
let Test.7 : Str = CallByName Inspect.33 Test.6;
dbg Test.7;
dec Test.7;
let Test.8 : Str = CallByName Inspect.33 Test.6;
dbg Test.8;
dec Test.8;
let Test.9 : Str = CallByName Inspect.33 Test.6;
dbg Test.9;
dec Test.9;
ret Test.6;

View file

@ -0,0 +1,59 @@
procedure Inspect.278 (Inspect.279, Inspect.277):
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
dec Inspect.318;
ret Inspect.317;
procedure Inspect.30 (Inspect.147):
ret Inspect.147;
procedure Inspect.33 (Inspect.152):
let Inspect.322 : Str = CallByName Inspect.5 Inspect.152;
let Inspect.321 : Str = CallByName Inspect.64 Inspect.322;
ret Inspect.321;
procedure Inspect.39 (Inspect.301):
let Inspect.311 : Str = "";
ret Inspect.311;
procedure Inspect.5 (Inspect.150):
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
let Inspect.309 : {} = Struct {};
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
ret Inspect.307;
procedure Inspect.57 (Inspect.277):
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
ret Inspect.313;
procedure Inspect.63 (Inspect.300, Inspect.296):
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
ret Inspect.320;
procedure Inspect.64 (Inspect.302):
ret Inspect.302;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.281 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.281;
procedure Num.96 (#Attr.2):
let Num.282 : Str = lowlevel NumToStr #Attr.2;
ret Num.282;
procedure Str.3 (#Attr.2, #Attr.3):
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
ret Str.236;
procedure Test.0 ():
let Test.4 : I64 = 1i64;
let Test.5 : Str = CallByName Inspect.33 Test.4;
dbg Test.5;
dec Test.5;
let Test.9 : I64 = 2i64;
let Test.3 : I64 = CallByName Num.19 Test.4 Test.9;
let Test.6 : Str = CallByName Inspect.33 Test.3;
dbg Test.6;
dec Test.6;
ret Test.3;

View file

@ -3295,6 +3295,18 @@ fn dbg_inside_string() {
)
}
#[mono_test]
fn pizza_dbg() {
indoc!(
r#"
1
|> dbg
|> Num.add 2
|> dbg
"#
)
}
#[mono_test]
fn linked_list_reverse() {
indoc!(

View file

@ -0,0 +1,16 @@
SpaceAfter(
BinOps(
[
(
@0-1 Num(
"1",
),
@2-4 Pizza,
),
],
@5-8 Dbg,
),
[
Newline,
],
)

View file

@ -0,0 +1 @@
1 |> dbg

View file

@ -442,6 +442,7 @@ mod test_snapshots {
pass/pattern_as_spaces.expr,
pass/pattern_with_space_in_parens.expr, // https://github.com/roc-lang/roc/issues/929
pass/pizza_bang.moduledefs,
pass/pizza_dbg.expr,
pass/plus_if.expr,
pass/plus_when.expr,
pass/pos_inf_float.expr,