mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Merge remote-tracking branch 'origin/trunk' into fix-lambda-set-debug-instance
This commit is contained in:
commit
97d14f421d
47 changed files with 379 additions and 235 deletions
1
AUTHORS
1
AUTHORS
|
@ -61,3 +61,4 @@ Shahn Hogan <shahnhogan@hotmail.com>
|
||||||
Tankor Smash <tankorsmash+github@gmail.com>
|
Tankor Smash <tankorsmash+github@gmail.com>
|
||||||
Matthias Devlamynck <matthias.devlamynck@mailoo.org>
|
Matthias Devlamynck <matthias.devlamynck@mailoo.org>
|
||||||
Jan Van Bruggen <JanCVanB@users.noreply.github.com>
|
Jan Van Bruggen <JanCVanB@users.noreply.github.com>
|
||||||
|
Mats Sigge <<mats.sigge@gmail.com>>
|
||||||
|
|
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -3248,12 +3248,12 @@ dependencies = [
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_load",
|
"roc_load",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
"roc_problem",
|
"roc_problem",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"roc_reporting",
|
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"snafu",
|
"snafu",
|
||||||
|
@ -3338,6 +3338,7 @@ dependencies = [
|
||||||
"roc_constrain",
|
"roc_constrain",
|
||||||
"roc_docs",
|
"roc_docs",
|
||||||
"roc_editor",
|
"roc_editor",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_fmt",
|
"roc_fmt",
|
||||||
"roc_gen_llvm",
|
"roc_gen_llvm",
|
||||||
"roc_linker",
|
"roc_linker",
|
||||||
|
@ -3470,6 +3471,10 @@ dependencies = [
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_error_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_fmt"
|
name = "roc_fmt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -3495,12 +3500,12 @@ dependencies = [
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
"roc_problem",
|
"roc_problem",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"roc_reporting",
|
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
"roc_std",
|
"roc_std",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
|
@ -3517,9 +3522,9 @@ dependencies = [
|
||||||
"morphic_lib",
|
"morphic_lib",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_reporting",
|
|
||||||
"roc_std",
|
"roc_std",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
]
|
]
|
||||||
|
@ -3531,9 +3536,9 @@ dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_reporting",
|
|
||||||
"roc_std",
|
"roc_std",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ members = [
|
||||||
"ast",
|
"ast",
|
||||||
"cli",
|
"cli",
|
||||||
"code_markup",
|
"code_markup",
|
||||||
|
"error_macros",
|
||||||
"reporting",
|
"reporting",
|
||||||
"roc_std",
|
"roc_std",
|
||||||
"test_utils",
|
"test_utils",
|
||||||
|
|
|
@ -47,7 +47,7 @@ install-zig-llvm-valgrind-clippy-rustfmt:
|
||||||
|
|
||||||
copy-dirs:
|
copy-dirs:
|
||||||
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
||||||
COPY --dir cli cli_utils compiler docs editor ast code_markup utils test_utils reporting roc_std vendor examples linker Cargo.toml Cargo.lock version.txt ./
|
COPY --dir cli cli_utils compiler docs editor ast code_markup error_macros utils test_utils reporting roc_std vendor examples linker Cargo.toml Cargo.lock version.txt ./
|
||||||
|
|
||||||
test-zig:
|
test-zig:
|
||||||
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
||||||
|
|
|
@ -17,7 +17,7 @@ roc_problem = { path = "../compiler/problem" }
|
||||||
roc_types = { path = "../compiler/types" }
|
roc_types = { path = "../compiler/types" }
|
||||||
roc_unify = { path = "../compiler/unify"}
|
roc_unify = { path = "../compiler/unify"}
|
||||||
roc_load = { path = "../compiler/load" }
|
roc_load = { path = "../compiler/load" }
|
||||||
roc_reporting = { path = "../reporting" }
|
roc_error_macros = { path = "../error_macros" }
|
||||||
arrayvec = "0.7.2"
|
arrayvec = "0.7.2"
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
libc = "0.2.106"
|
libc = "0.2.106"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::{called_via::CalledVia, symbol::Symbol};
|
use roc_module::{called_via::CalledVia, symbol::Symbol};
|
||||||
use roc_parse::ast::StrLiteral;
|
use roc_parse::ast::StrLiteral;
|
||||||
use roc_reporting::internal_error;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast_error::{ASTResult, UnexpectedASTNode},
|
ast_error::{ASTResult, UnexpectedASTNode},
|
||||||
|
|
|
@ -62,6 +62,7 @@ roc_gen_llvm = { path = "../compiler/gen_llvm", optional = true }
|
||||||
roc_build = { path = "../compiler/build", default-features = false }
|
roc_build = { path = "../compiler/build", default-features = false }
|
||||||
roc_fmt = { path = "../compiler/fmt" }
|
roc_fmt = { path = "../compiler/fmt" }
|
||||||
roc_reporting = { path = "../reporting" }
|
roc_reporting = { path = "../reporting" }
|
||||||
|
roc_error_macros = { path = "../error_macros" }
|
||||||
roc_editor = { path = "../editor", optional = true }
|
roc_editor = { path = "../editor", optional = true }
|
||||||
roc_linker = { path = "../linker" }
|
roc_linker = { path = "../linker" }
|
||||||
clap = { version = "= 3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] }
|
clap = { version = "= 3.0.0-beta.5", default-features = false, features = ["std", "color", "suggestions"] }
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use roc_error_macros::{internal_error, user_error};
|
||||||
use roc_fmt::def::fmt_def;
|
use roc_fmt::def::fmt_def;
|
||||||
use roc_fmt::module::fmt_module;
|
use roc_fmt::module::fmt_module;
|
||||||
use roc_fmt::Buf;
|
use roc_fmt::Buf;
|
||||||
|
@ -21,7 +22,6 @@ use roc_parse::{
|
||||||
state::State,
|
state::State,
|
||||||
};
|
};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_reporting::{internal_error, user_error};
|
|
||||||
|
|
||||||
pub fn format(files: std::vec::Vec<PathBuf>) {
|
pub fn format(files: std::vec::Vec<PathBuf>) {
|
||||||
for file in files {
|
for file in files {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use const_format::concatcp;
|
use const_format::concatcp;
|
||||||
#[cfg(feature = "llvm")]
|
#[cfg(feature = "llvm")]
|
||||||
use gen::{gen_and_eval, ReplOutput};
|
use gen::{gen_and_eval, ReplOutput};
|
||||||
use roc_parse::parser::{EExpr, SyntaxError};
|
use roc_parse::parser::{EExpr, ELambda, SyntaxError};
|
||||||
use rustyline::highlight::{Highlighter, PromptInfo};
|
use rustyline::highlight::{Highlighter, PromptInfo};
|
||||||
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
|
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
|
||||||
use rustyline_derive::{Completer, Helper, Hinter};
|
use rustyline_derive::{Completer, Helper, Hinter};
|
||||||
|
@ -97,7 +97,8 @@ impl Validator for InputValidator {
|
||||||
match roc_parse::expr::parse_loc_expr(0, &arena, state) {
|
match roc_parse::expr::parse_loc_expr(0, &arena, state) {
|
||||||
// Special case some syntax errors to allow for multi-line inputs
|
// Special case some syntax errors to allow for multi-line inputs
|
||||||
Err((_, EExpr::DefMissingFinalExpr(_), _))
|
Err((_, EExpr::DefMissingFinalExpr(_), _))
|
||||||
| Err((_, EExpr::DefMissingFinalExpr2(_, _), _)) => {
|
| Err((_, EExpr::DefMissingFinalExpr2(_, _), _))
|
||||||
|
| Err((_, EExpr::Lambda(ELambda::Body(_, _), _), _)) => {
|
||||||
Ok(ValidationResult::Incomplete)
|
Ok(ValidationResult::Incomplete)
|
||||||
}
|
}
|
||||||
_ => Ok(ValidationResult::Valid(None)),
|
_ => Ok(ValidationResult::Valid(None)),
|
||||||
|
|
|
@ -925,4 +925,38 @@ mod repl_eval {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn issue_2343_complete_mono_with_shadowed_vars() {
|
||||||
|
expect_failure(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
b = False
|
||||||
|
f = \b ->
|
||||||
|
when b is
|
||||||
|
True -> 5
|
||||||
|
False -> 15
|
||||||
|
f b
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── DUPLICATE NAME ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
The b name is first defined here:
|
||||||
|
|
||||||
|
4│ b = False
|
||||||
|
^
|
||||||
|
|
||||||
|
But then it's defined a second time here:
|
||||||
|
|
||||||
|
5│ f = \b ->
|
||||||
|
^
|
||||||
|
|
||||||
|
Since these variables have the same name, it's easy to use the wrong
|
||||||
|
one on accident. Give one of them a new name.
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ interface List
|
||||||
set,
|
set,
|
||||||
single,
|
single,
|
||||||
sortWith,
|
sortWith,
|
||||||
|
split,
|
||||||
|
sublist,
|
||||||
sum,
|
sum,
|
||||||
swap,
|
swap,
|
||||||
walk,
|
walk,
|
||||||
|
@ -205,7 +207,7 @@ empty : List *
|
||||||
## Returns a list with the given length, where every element is the given value.
|
## Returns a list with the given length, where every element is the given value.
|
||||||
##
|
##
|
||||||
##
|
##
|
||||||
repeat : elem, Nat -> List elem
|
repeat : Nat, elem -> List elem
|
||||||
|
|
||||||
## Returns a list of all the integers between one and another,
|
## Returns a list of all the integers between one and another,
|
||||||
## including both of the given numbers.
|
## including both of the given numbers.
|
||||||
|
@ -277,7 +279,7 @@ map4 : List a, List b, List c, List d, (a, b, c, d -> e) -> List e
|
||||||
|
|
||||||
## This works like [List.map], except it also passes the index
|
## This works like [List.map], except it also passes the index
|
||||||
## of the element to the conversion function.
|
## of the element to the conversion function.
|
||||||
mapWithIndex : List before, (before, Nat -> after) -> List after
|
mapWithIndex : List before, (Nat, before -> after) -> List after
|
||||||
|
|
||||||
## This works like [List.map], except at any time you can return `Err` to
|
## This works like [List.map], except at any time you can return `Err` to
|
||||||
## cancel the entire operation immediately, and return that #Err.
|
## cancel the entire operation immediately, and return that #Err.
|
||||||
|
|
|
@ -390,7 +390,7 @@ fn can_annotation_help(
|
||||||
) {
|
) {
|
||||||
Ok(symbol) => symbol,
|
Ok(symbol) => symbol,
|
||||||
|
|
||||||
Err((original_region, shadow)) => {
|
Err((original_region, shadow, _new_symbol)) => {
|
||||||
let problem = Problem::Shadowed(original_region, shadow.clone());
|
let problem = Problem::Shadowed(original_region, shadow.clone());
|
||||||
|
|
||||||
env.problem(roc_problem::can::Problem::ShadowingInAnnotation {
|
env.problem(roc_problem::can::Problem::ShadowingInAnnotation {
|
||||||
|
|
|
@ -809,7 +809,7 @@ fn pattern_to_vars_by_symbol(
|
||||||
) {
|
) {
|
||||||
use Pattern::*;
|
use Pattern::*;
|
||||||
match pattern {
|
match pattern {
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) | Shadowed(_, _, symbol) => {
|
||||||
vars_by_symbol.insert(*symbol, expr_var);
|
vars_by_symbol.insert(*symbol, expr_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,8 +832,6 @@ fn pattern_to_vars_by_symbol(
|
||||||
| Underscore
|
| Underscore
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
| UnsupportedPattern(_) => {}
|
| UnsupportedPattern(_) => {}
|
||||||
|
|
||||||
Shadowed(_, _) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +882,7 @@ fn canonicalize_pending_def<'a>(
|
||||||
Pattern::Identifier(symbol) => RuntimeError::NoImplementationNamed {
|
Pattern::Identifier(symbol) => RuntimeError::NoImplementationNamed {
|
||||||
def_symbol: *symbol,
|
def_symbol: *symbol,
|
||||||
},
|
},
|
||||||
Pattern::Shadowed(region, loc_ident) => RuntimeError::Shadowing {
|
Pattern::Shadowed(region, loc_ident, _new_symbol) => RuntimeError::Shadowing {
|
||||||
original_region: *region,
|
original_region: *region,
|
||||||
shadow: loc_ident.clone(),
|
shadow: loc_ident.clone(),
|
||||||
},
|
},
|
||||||
|
@ -1502,7 +1500,7 @@ fn to_pending_def<'a>(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
Err((original_region, loc_shadowed_symbol)) => {
|
Err((original_region, loc_shadowed_symbol, _new_symbol)) => {
|
||||||
env.problem(Problem::ShadowingInAnnotation {
|
env.problem(Problem::ShadowingInAnnotation {
|
||||||
original_region,
|
original_region,
|
||||||
shadow: loc_shadowed_symbol,
|
shadow: loc_shadowed_symbol,
|
||||||
|
|
|
@ -398,7 +398,7 @@ fn fix_values_captured_in_closure_pattern(
|
||||||
| FloatLiteral(_, _, _)
|
| FloatLiteral(_, _, _)
|
||||||
| StrLiteral(_)
|
| StrLiteral(_)
|
||||||
| Underscore
|
| Underscore
|
||||||
| Shadowed(_, _)
|
| Shadowed(..)
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
| UnsupportedPattern(_) => (),
|
| UnsupportedPattern(_) => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub enum Pattern {
|
||||||
Underscore,
|
Underscore,
|
||||||
|
|
||||||
// Runtime Exceptions
|
// Runtime Exceptions
|
||||||
Shadowed(Region, Loc<Ident>),
|
Shadowed(Region, Loc<Ident>, Symbol),
|
||||||
// Example: (5 = 1 + 2) is an unsupported pattern in an assignment; Int patterns aren't allowed in assignments!
|
// Example: (5 = 1 + 2) is an unsupported pattern in an assignment; Int patterns aren't allowed in assignments!
|
||||||
UnsupportedPattern(Region),
|
UnsupportedPattern(Region),
|
||||||
// parse error patterns
|
// parse error patterns
|
||||||
|
@ -65,7 +65,7 @@ pub fn symbols_from_pattern_help(pattern: &Pattern, symbols: &mut Vec<Symbol>) {
|
||||||
use Pattern::*;
|
use Pattern::*;
|
||||||
|
|
||||||
match pattern {
|
match pattern {
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) | Shadowed(_, _, symbol) => {
|
||||||
symbols.push(*symbol);
|
symbols.push(*symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,8 +92,6 @@ pub fn symbols_from_pattern_help(pattern: &Pattern, symbols: &mut Vec<Symbol>) {
|
||||||
| Underscore
|
| Underscore
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
| UnsupportedPattern(_) => {}
|
| UnsupportedPattern(_) => {}
|
||||||
|
|
||||||
Shadowed(_, _) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,13 +119,14 @@ pub fn canonicalize_pattern<'a>(
|
||||||
|
|
||||||
Pattern::Identifier(symbol)
|
Pattern::Identifier(symbol)
|
||||||
}
|
}
|
||||||
Err((original_region, shadow)) => {
|
Err((original_region, shadow, new_symbol)) => {
|
||||||
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
||||||
original_region,
|
original_region,
|
||||||
shadow: shadow.clone(),
|
shadow: shadow.clone(),
|
||||||
}));
|
}));
|
||||||
|
output.references.bound_symbols.insert(new_symbol);
|
||||||
|
|
||||||
Pattern::Shadowed(original_region, shadow)
|
Pattern::Shadowed(original_region, shadow, new_symbol)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GlobalTag(name) => {
|
GlobalTag(name) => {
|
||||||
|
@ -268,7 +267,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err((original_region, shadow)) => {
|
Err((original_region, shadow, new_symbol)) => {
|
||||||
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
||||||
original_region,
|
original_region,
|
||||||
shadow: shadow.clone(),
|
shadow: shadow.clone(),
|
||||||
|
@ -278,7 +277,8 @@ pub fn canonicalize_pattern<'a>(
|
||||||
// are, we're definitely shadowed and will
|
// are, we're definitely shadowed and will
|
||||||
// get a runtime exception as soon as we
|
// get a runtime exception as soon as we
|
||||||
// encounter the first bad pattern.
|
// encounter the first bad pattern.
|
||||||
opt_erroneous = Some(Pattern::Shadowed(original_region, shadow));
|
opt_erroneous =
|
||||||
|
Some(Pattern::Shadowed(original_region, shadow, new_symbol));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err((original_region, shadow)) => {
|
Err((original_region, shadow, new_symbol)) => {
|
||||||
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
||||||
original_region,
|
original_region,
|
||||||
shadow: shadow.clone(),
|
shadow: shadow.clone(),
|
||||||
|
@ -349,7 +349,8 @@ pub fn canonicalize_pattern<'a>(
|
||||||
// are, we're definitely shadowed and will
|
// are, we're definitely shadowed and will
|
||||||
// get a runtime exception as soon as we
|
// get a runtime exception as soon as we
|
||||||
// encounter the first bad pattern.
|
// encounter the first bad pattern.
|
||||||
opt_erroneous = Some(Pattern::Shadowed(original_region, shadow));
|
opt_erroneous =
|
||||||
|
Some(Pattern::Shadowed(original_region, shadow, new_symbol));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -452,7 +453,7 @@ fn add_bindings_from_patterns(
|
||||||
use Pattern::*;
|
use Pattern::*;
|
||||||
|
|
||||||
match pattern {
|
match pattern {
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) | Shadowed(_, _, symbol) => {
|
||||||
answer.push((*symbol, *region));
|
answer.push((*symbol, *region));
|
||||||
}
|
}
|
||||||
AppliedTag {
|
AppliedTag {
|
||||||
|
@ -477,7 +478,6 @@ fn add_bindings_from_patterns(
|
||||||
| FloatLiteral(_, _, _)
|
| FloatLiteral(_, _, _)
|
||||||
| StrLiteral(_)
|
| StrLiteral(_)
|
||||||
| Underscore
|
| Underscore
|
||||||
| Shadowed(_, _)
|
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
| UnsupportedPattern(_) => (),
|
| UnsupportedPattern(_) => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,15 +110,21 @@ impl Scope {
|
||||||
exposed_ident_ids: &IdentIds,
|
exposed_ident_ids: &IdentIds,
|
||||||
all_ident_ids: &mut IdentIds,
|
all_ident_ids: &mut IdentIds,
|
||||||
region: Region,
|
region: Region,
|
||||||
) -> Result<Symbol, (Region, Loc<Ident>)> {
|
) -> Result<Symbol, (Region, Loc<Ident>, Symbol)> {
|
||||||
match self.idents.get(&ident) {
|
match self.idents.get(&ident) {
|
||||||
Some((_, original_region)) => {
|
Some(&(_, original_region)) => {
|
||||||
let shadow = Loc {
|
let shadow = Loc {
|
||||||
value: ident,
|
value: ident.clone(),
|
||||||
region,
|
region,
|
||||||
};
|
};
|
||||||
|
|
||||||
Err((*original_region, shadow))
|
let ident_id = all_ident_ids.add(ident.clone());
|
||||||
|
let symbol = Symbol::new(self.home, ident_id);
|
||||||
|
|
||||||
|
self.symbols.insert(symbol, region);
|
||||||
|
self.idents.insert(ident, (symbol, region));
|
||||||
|
|
||||||
|
Err((original_region, shadow, symbol))
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// If this IdentId was already added previously
|
// If this IdentId was already added previously
|
||||||
|
|
|
@ -368,9 +368,11 @@ mod test_can {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
|
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
|
||||||
|
|
||||||
assert_eq!(problems.len(), 1);
|
assert_eq!(problems.len(), 2);
|
||||||
assert!(problems.iter().all(|problem| match problem {
|
assert!(problems.iter().all(|problem| match problem {
|
||||||
Problem::RuntimeError(RuntimeError::Shadowing { .. }) => true,
|
Problem::RuntimeError(RuntimeError::Shadowing { .. }) => true,
|
||||||
|
// Due to one of the shadows
|
||||||
|
Problem::UnusedDef(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -389,9 +391,11 @@ mod test_can {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
|
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
|
||||||
|
|
||||||
assert_eq!(problems.len(), 1);
|
assert_eq!(problems.len(), 2);
|
||||||
assert!(problems.iter().all(|problem| match problem {
|
assert!(problems.iter().all(|problem| match problem {
|
||||||
Problem::RuntimeError(RuntimeError::Shadowing { .. }) => true,
|
Problem::RuntimeError(RuntimeError::Shadowing { .. }) => true,
|
||||||
|
// Due to one of the shadows
|
||||||
|
Problem::UnusedDef(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -410,10 +414,12 @@ mod test_can {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
|
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
|
||||||
|
|
||||||
assert_eq!(problems.len(), 1);
|
assert_eq!(problems.len(), 2);
|
||||||
println!("{:#?}", problems);
|
println!("{:#?}", problems);
|
||||||
assert!(problems.iter().all(|problem| match problem {
|
assert!(problems.iter().all(|problem| match problem {
|
||||||
Problem::RuntimeError(RuntimeError::Shadowing { .. }) => true,
|
Problem::RuntimeError(RuntimeError::Shadowing { .. }) => true,
|
||||||
|
// Due to one of the shadows
|
||||||
|
Problem::UnusedDef(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,11 @@ fn headers_from_annotation_help(
|
||||||
headers: &mut SendMap<Symbol, Loc<Type>>,
|
headers: &mut SendMap<Symbol, Loc<Type>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match pattern {
|
match pattern {
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) | Shadowed(_, _, symbol) => {
|
||||||
headers.insert(*symbol, annotation.clone());
|
headers.insert(*symbol, annotation.clone());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Underscore
|
Underscore
|
||||||
| Shadowed(_, _)
|
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
| UnsupportedPattern(_)
|
| UnsupportedPattern(_)
|
||||||
| NumLiteral(_, _, _)
|
| NumLiteral(_, _, _)
|
||||||
|
@ -159,11 +158,11 @@ pub fn constrain_pattern(
|
||||||
PresenceConstraint::IsOpen,
|
PresenceConstraint::IsOpen,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Underscore | UnsupportedPattern(_) | MalformedPattern(_, _) | Shadowed(_, _) => {
|
Underscore | UnsupportedPattern(_) | MalformedPattern(_, _) => {
|
||||||
// Neither the _ pattern nor erroneous ones add any constraints.
|
// Neither the _ pattern nor erroneous ones add any constraints.
|
||||||
}
|
}
|
||||||
|
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) | Shadowed(_, _, symbol) => {
|
||||||
if destruct_position {
|
if destruct_position {
|
||||||
state.constraints.push(Constraint::Present(
|
state.constraints.push(Constraint::Present(
|
||||||
expected.get_type_ref().clone(),
|
expected.get_type_ref().clone(),
|
||||||
|
|
|
@ -16,7 +16,7 @@ roc_builtins = { path = "../builtins" }
|
||||||
roc_unify = { path = "../unify" }
|
roc_unify = { path = "../unify" }
|
||||||
roc_solve = { path = "../solve" }
|
roc_solve = { path = "../solve" }
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
roc_reporting = { path = "../../reporting" }
|
roc_error_macros = { path = "../../error_macros" }
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
target-lexicon = "0.12.2"
|
target-lexicon = "0.12.2"
|
||||||
# TODO: Deal with the update of object to 0.27.
|
# TODO: Deal with the update of object to 0.27.
|
||||||
|
|
|
@ -3,9 +3,9 @@ use crate::Relocation;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use packed_struct::prelude::*;
|
use packed_struct::prelude::*;
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
use roc_reporting::internal_error;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -2,11 +2,11 @@ use crate::{Backend, Env, Relocation};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::code_gen_help::CodeGenHelp;
|
use roc_mono::code_gen_help::CodeGenHelp;
|
||||||
use roc_mono::ir::{BranchInfo, JoinPointId, Literal, Param, ProcLayout, SelfRecursive, Stmt};
|
use roc_mono::ir::{BranchInfo, JoinPointId, Literal, Param, ProcLayout, SelfRecursive, Stmt};
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, Layout};
|
||||||
use roc_reporting::internal_error;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub mod aarch64;
|
pub mod aarch64;
|
||||||
|
|
|
@ -5,9 +5,9 @@ use crate::{
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, Layout};
|
||||||
use roc_reporting::internal_error;
|
|
||||||
|
|
||||||
// Not sure exactly how I want to represent registers.
|
// Not sure exactly how I want to represent registers.
|
||||||
// If we want max speed, we would likely make them structs that impl the same trait to avoid ifs.
|
// If we want max speed, we would likely make them structs that impl the same trait to avoid ifs.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use bumpalo::{collections::Vec, Bump};
|
use bumpalo::{collections::Vec, Bump};
|
||||||
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::ident::{ModuleName, TagName};
|
use roc_module::ident::{ModuleName, TagName};
|
||||||
use roc_module::low_level::{LowLevel, LowLevelWrapperType};
|
use roc_module::low_level::{LowLevel, LowLevelWrapperType};
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
|
@ -14,7 +15,6 @@ use roc_mono::ir::{
|
||||||
SelfRecursive, Stmt,
|
SelfRecursive, Stmt,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutId, LayoutIds};
|
use roc_mono::layout::{Builtin, Layout, LayoutId, LayoutIds};
|
||||||
use roc_reporting::internal_error;
|
|
||||||
|
|
||||||
mod generic64;
|
mod generic64;
|
||||||
mod object_builder;
|
mod object_builder;
|
||||||
|
|
|
@ -8,11 +8,11 @@ use object::{
|
||||||
SymbolFlags, SymbolKind, SymbolScope,
|
SymbolFlags, SymbolKind, SymbolScope,
|
||||||
};
|
};
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol;
|
use roc_module::symbol;
|
||||||
use roc_module::symbol::Interns;
|
use roc_module::symbol::Interns;
|
||||||
use roc_mono::ir::{Proc, ProcLayout};
|
use roc_mono::ir::{Proc, ProcLayout};
|
||||||
use roc_mono::layout::LayoutIds;
|
use roc_mono::layout::LayoutIds;
|
||||||
use roc_reporting::internal_error;
|
|
||||||
use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple};
|
use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple};
|
||||||
|
|
||||||
// This is used by some code below which is currently commented out.
|
// This is used by some code below which is currently commented out.
|
||||||
|
|
|
@ -10,7 +10,7 @@ edition = "2018"
|
||||||
roc_collections = { path = "../collections" }
|
roc_collections = { path = "../collections" }
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
roc_builtins = { path = "../builtins" }
|
roc_builtins = { path = "../builtins" }
|
||||||
roc_reporting = { path = "../../reporting" }
|
roc_error_macros = { path = "../../error_macros" }
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
roc_std = { path = "../../roc_std" }
|
roc_std = { path = "../../roc_std" }
|
||||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||||
|
|
|
@ -55,6 +55,7 @@ use morphic_lib::{
|
||||||
use roc_builtins::bitcode::{self, FloatWidth, IntWidth, IntrinsicName};
|
use roc_builtins::bitcode::{self, FloatWidth, IntWidth, IntrinsicName};
|
||||||
use roc_builtins::{float_intrinsic, int_intrinsic};
|
use roc_builtins::{float_intrinsic, int_intrinsic};
|
||||||
use roc_collections::all::{ImMap, MutMap, MutSet};
|
use roc_collections::all::{ImMap, MutMap, MutSet};
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
use roc_mono::ir::{
|
use roc_mono::ir::{
|
||||||
|
@ -62,7 +63,6 @@ use roc_mono::ir::{
|
||||||
ModifyRc, OptLevel, ProcLayout,
|
ModifyRc, OptLevel, ProcLayout,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
||||||
use roc_reporting::internal_error;
|
|
||||||
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
|
|
|
@ -12,4 +12,4 @@ roc_collections = { path = "../collections" }
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
roc_std = { path = "../../roc_std" }
|
roc_std = { path = "../../roc_std" }
|
||||||
roc_reporting = { path = "../../reporting" }
|
roc_error_macros = { path = "../../error_macros" }
|
||||||
|
|
|
@ -12,8 +12,8 @@ use roc_mono::ir::{
|
||||||
ProcLayout, Stmt,
|
ProcLayout, Stmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
use roc_mono::layout::{Builtin, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
||||||
use roc_reporting::internal_error;
|
|
||||||
|
|
||||||
use crate::layout::{CallConv, ReturnMethod, WasmLayout};
|
use crate::layout::{CallConv, ReturnMethod, WasmLayout};
|
||||||
use crate::low_level::LowLevelCall;
|
use crate::low_level::LowLevelCall;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::low_level::{LowLevel, LowLevel::*};
|
use roc_module::low_level::{LowLevel, LowLevel::*};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{Builtin, Layout, UnionLayout};
|
use roc_mono::layout::{Builtin, Layout, UnionLayout};
|
||||||
use roc_reporting::internal_error;
|
|
||||||
|
|
||||||
use crate::backend::WasmBackend;
|
use crate::backend::WasmBackend;
|
||||||
use crate::layout::CallConv;
|
use crate::layout::CallConv;
|
||||||
|
|
|
@ -2,9 +2,9 @@ use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
use roc_reporting::internal_error;
|
|
||||||
|
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
CallConv, ReturnMethod, StackMemoryFormat, WasmLayout, ZigVersion, BUILTINS_ZIG_VERSION,
|
CallConv, ReturnMethod, StackMemoryFormat, WasmLayout, ZigVersion, BUILTINS_ZIG_VERSION,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use bumpalo::collections::vec::Vec;
|
use bumpalo::collections::vec::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use roc_reporting::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
|
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub mod serialize;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
pub use code_builder::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState};
|
pub use code_builder::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState};
|
||||||
pub use linking::SymInfo;
|
pub use linking::SymInfo;
|
||||||
use roc_reporting::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
pub use sections::{ConstExpr, Export, ExportType, Global, GlobalType, Signature};
|
pub use sections::{ConstExpr, Export, ExportType, Global, GlobalType, Signature};
|
||||||
|
|
||||||
use crate::wasm_module::serialize::SkipBytes;
|
use crate::wasm_module::serialize::SkipBytes;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use roc_reporting::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
|
|
||||||
use super::serialize::{parse_u32_or_panic, SkipBytes};
|
use super::serialize::{parse_u32_or_panic, SkipBytes};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use bumpalo::collections::vec::Vec;
|
use bumpalo::collections::vec::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_reporting::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
|
|
||||||
use super::dead_code::{
|
use super::dead_code::{
|
||||||
copy_preloads_shrinking_dead_fns, parse_preloads_call_graph, trace_call_graph,
|
copy_preloads_shrinking_dead_fns, parse_preloads_call_graph, trace_call_graph,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{fmt::Debug, iter::FromIterator};
|
use std::{fmt::Debug, iter::FromIterator};
|
||||||
|
|
||||||
use bumpalo::collections::vec::Vec;
|
use bumpalo::collections::vec::Vec;
|
||||||
use roc_reporting::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
|
|
||||||
/// In the WebAssembly binary format, all integers are variable-length encoded (using LEB-128)
|
/// In the WebAssembly binary format, all integers are variable-length encoded (using LEB-128)
|
||||||
/// A small value like 3 or 100 is encoded as 1 byte. The value 128 needs 2 bytes, etc.
|
/// A small value like 3 or 100 is encoded as 1 byte. The value 128 needs 2 bytes, etc.
|
||||||
|
|
|
@ -1980,12 +1980,12 @@ fn pattern_to_when<'a>(
|
||||||
// for underscore we generate a dummy Symbol
|
// for underscore we generate a dummy Symbol
|
||||||
(env.unique_symbol(), body)
|
(env.unique_symbol(), body)
|
||||||
}
|
}
|
||||||
Shadowed(region, loc_ident) => {
|
Shadowed(region, loc_ident, new_symbol) => {
|
||||||
let error = roc_problem::can::RuntimeError::Shadowing {
|
let error = roc_problem::can::RuntimeError::Shadowing {
|
||||||
original_region: *region,
|
original_region: *region,
|
||||||
shadow: loc_ident.clone(),
|
shadow: loc_ident.clone(),
|
||||||
};
|
};
|
||||||
(env.unique_symbol(), Loc::at_zero(RuntimeError(error)))
|
(*new_symbol, Loc::at_zero(RuntimeError(error)))
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsupportedPattern(region) => {
|
UnsupportedPattern(region) => {
|
||||||
|
@ -5118,41 +5118,42 @@ fn register_capturing_closure<'a>(
|
||||||
|
|
||||||
let is_self_recursive = !matches!(recursive, roc_can::expr::Recursive::NotRecursive);
|
let is_self_recursive = !matches!(recursive, roc_can::expr::Recursive::NotRecursive);
|
||||||
|
|
||||||
// does this function capture any local values?
|
let captured_symbols = match *env.subs.get_content_without_compacting(function_type) {
|
||||||
let function_layout = layout_cache.raw_from_var(env.arena, function_type, env.subs);
|
Content::Structure(FlatType::Func(_, closure_var, _)) => {
|
||||||
|
match LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes) {
|
||||||
let captured_symbols = match function_layout {
|
Ok(lambda_set) => {
|
||||||
Ok(RawFunctionLayout::Function(_, lambda_set, _)) => {
|
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
|
||||||
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
|
CapturedSymbols::None
|
||||||
CapturedSymbols::None
|
} else {
|
||||||
} else {
|
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
||||||
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
temp.sort();
|
||||||
temp.sort();
|
CapturedSymbols::Captured(temp.into_bump_slice())
|
||||||
CapturedSymbols::Captured(temp.into_bump_slice())
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// just allow this. see https://github.com/rtfeldman/roc/issues/1585
|
||||||
|
if captured_symbols.is_empty() {
|
||||||
|
CapturedSymbols::None
|
||||||
|
} else {
|
||||||
|
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
||||||
|
temp.sort();
|
||||||
|
CapturedSymbols::Captured(temp.into_bump_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(RawFunctionLayout::ZeroArgumentThunk(_)) => {
|
_ => {
|
||||||
// top-level thunks cannot capture any variables
|
// This is a value (zero-argument thunk); it cannot capture any variables.
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
captured_symbols.is_empty(),
|
captured_symbols.is_empty(),
|
||||||
"{:?} with layout {:?} {:?} {:?}",
|
"{:?} with layout {:?} {:?} {:?}",
|
||||||
&captured_symbols,
|
&captured_symbols,
|
||||||
function_layout,
|
layout_cache.raw_from_var(env.arena, function_type, env.subs),
|
||||||
env.subs,
|
env.subs,
|
||||||
(function_type, closure_type, closure_ext_var),
|
(function_type, closure_type, closure_ext_var),
|
||||||
);
|
);
|
||||||
CapturedSymbols::None
|
CapturedSymbols::None
|
||||||
}
|
}
|
||||||
Err(_) => {
|
|
||||||
// just allow this. see https://github.com/rtfeldman/roc/issues/1585
|
|
||||||
if captured_symbols.is_empty() {
|
|
||||||
CapturedSymbols::None
|
|
||||||
} else {
|
|
||||||
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
|
||||||
temp.sort();
|
|
||||||
CapturedSymbols::Captured(temp.into_bump_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let partial_proc = PartialProc::from_named_function(
|
let partial_proc = PartialProc::from_named_function(
|
||||||
|
@ -7652,7 +7653,7 @@ fn from_can_pattern_help<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())),
|
StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())),
|
||||||
Shadowed(region, ident) => Err(RuntimeError::Shadowing {
|
Shadowed(region, ident, _new_symbol) => Err(RuntimeError::Shadowing {
|
||||||
original_region: *region,
|
original_region: *region,
|
||||||
shadow: ident.clone(),
|
shadow: ident.clone(),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_problem::can::RuntimeError;
|
use roc_problem::can::RuntimeError;
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
Content, FlatType, RecordFields, Subs, UnionTags, Variable, VariableSubsSlice,
|
Content, FlatType, RecordFields, Subs, UnionTags, UnsortedUnionTags, Variable,
|
||||||
};
|
};
|
||||||
use roc_types::types::{gather_fields_unsorted_iter, RecordField};
|
use roc_types::types::{gather_fields_unsorted_iter, RecordField};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
@ -1580,18 +1580,26 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TagUnion(tags, ext_var) => {
|
TagUnion(tags, ext_var) => {
|
||||||
|
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
|
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
|
||||||
Ok(layout_from_tag_union(arena, tags, subs, env.ptr_bytes))
|
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
|
||||||
}
|
}
|
||||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(
|
||||||
|
ext_var_is_empty_tag_union(subs, ext_var),
|
||||||
|
"If ext_var wasn't empty, this wouldn't be a FunctionOrTagUnion!"
|
||||||
|
);
|
||||||
|
|
||||||
let tags = UnionTags::from_tag_name_index(tag_name);
|
let union_tags = UnionTags::from_tag_name_index(tag_name);
|
||||||
|
let (tags, _) = union_tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
|
|
||||||
Ok(layout_from_tag_union(arena, tags, subs, env.ptr_bytes))
|
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
|
||||||
}
|
}
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||||
|
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
|
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
|
||||||
// some observations
|
// some observations
|
||||||
|
@ -1603,9 +1611,8 @@ fn layout_from_flat_type<'a>(
|
||||||
// That means none of the optimizations for enums or single tag tag unions apply
|
// That means none of the optimizations for enums or single tag tag unions apply
|
||||||
|
|
||||||
let rec_var = subs.get_root_key_without_compacting(rec_var);
|
let rec_var = subs.get_root_key_without_compacting(rec_var);
|
||||||
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
|
let tags_vec = tags.tags;
|
||||||
|
let mut tag_layouts = Vec::with_capacity_in(tags_vec.len(), arena);
|
||||||
let tags_vec = cheap_sort_tags(arena, tags, subs);
|
|
||||||
|
|
||||||
let mut nullable = None;
|
let mut nullable = None;
|
||||||
|
|
||||||
|
@ -1619,7 +1626,7 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
env.insert_seen(rec_var);
|
env.insert_seen(rec_var);
|
||||||
for (index, (_name, variables)) in tags_vec.into_iter().enumerate() {
|
for (index, &(_name, variables)) in tags_vec.iter().enumerate() {
|
||||||
if matches!(nullable, Some(i) if i == index as TagIdIntType) {
|
if matches!(nullable, Some(i) if i == index as TagIdIntType) {
|
||||||
// don't add the nullable case
|
// don't add the nullable case
|
||||||
continue;
|
continue;
|
||||||
|
@ -1627,8 +1634,7 @@ fn layout_from_flat_type<'a>(
|
||||||
|
|
||||||
let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena);
|
let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena);
|
||||||
|
|
||||||
for var_index in variables {
|
for &var in variables {
|
||||||
let var = subs[var_index];
|
|
||||||
// TODO does this cause problems with mutually recursive unions?
|
// TODO does this cause problems with mutually recursive unions?
|
||||||
if rec_var == subs.get_root_key_without_compacting(var) {
|
if rec_var == subs.get_root_key_without_compacting(var) {
|
||||||
tag_layout.push(Layout::RecursivePointer);
|
tag_layout.push(Layout::RecursivePointer);
|
||||||
|
@ -1911,13 +1917,14 @@ fn is_recursive_tag_union(layout: &Layout) -> bool {
|
||||||
|
|
||||||
fn union_sorted_tags_help_new<'a>(
|
fn union_sorted_tags_help_new<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
mut tags_vec: Vec<(&'_ TagName, VariableSubsSlice)>,
|
tags_list: &[(&'_ TagName, &[Variable])],
|
||||||
opt_rec_var: Option<Variable>,
|
opt_rec_var: Option<Variable>,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
ptr_bytes: u32,
|
ptr_bytes: u32,
|
||||||
) -> UnionVariant<'a> {
|
) -> UnionVariant<'a> {
|
||||||
// sort up front; make sure the ordering stays intact!
|
// sort up front; make sure the ordering stays intact!
|
||||||
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
let mut tags_list = Vec::from_iter_in(tags_list.iter(), arena);
|
||||||
|
tags_list.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
|
||||||
let mut env = Env {
|
let mut env = Env {
|
||||||
arena,
|
arena,
|
||||||
|
@ -1926,27 +1933,26 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
ptr_bytes,
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
match tags_vec.len() {
|
match tags_list.len() {
|
||||||
0 => {
|
0 => {
|
||||||
// trying to instantiate a type with no values
|
// trying to instantiate a type with no values
|
||||||
UnionVariant::Never
|
UnionVariant::Never
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
let (tag_name, arguments) = tags_vec.remove(0);
|
let &(tag_name, arguments) = tags_list.remove(0);
|
||||||
let tag_name = tag_name.clone();
|
let tag_name = tag_name.clone();
|
||||||
|
|
||||||
// just one tag in the union (but with arguments) can be a struct
|
// just one tag in the union (but with arguments) can be a struct
|
||||||
let mut layouts = Vec::with_capacity_in(tags_vec.len(), arena);
|
let mut layouts = Vec::with_capacity_in(tags_list.len(), arena);
|
||||||
|
|
||||||
// special-case NUM_AT_NUM: if its argument is a FlexVar, make it Int
|
// special-case NUM_AT_NUM: if its argument is a FlexVar, make it Int
|
||||||
match tag_name {
|
match tag_name {
|
||||||
TagName::Private(Symbol::NUM_AT_NUM) => {
|
TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||||
let var = subs[arguments.into_iter().next().unwrap()];
|
let var = arguments[0];
|
||||||
layouts.push(unwrap_num_tag(subs, var, ptr_bytes).expect("invalid num layout"));
|
layouts.push(unwrap_num_tag(subs, var, ptr_bytes).expect("invalid num layout"));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
for var_index in arguments {
|
for &var in arguments {
|
||||||
let var = subs[var_index];
|
|
||||||
match Layout::from_var(&mut env, var) {
|
match Layout::from_var(&mut env, var) {
|
||||||
Ok(layout) => {
|
Ok(layout) => {
|
||||||
layouts.push(layout);
|
layouts.push(layout);
|
||||||
|
@ -1989,7 +1995,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
}
|
}
|
||||||
num_tags => {
|
num_tags => {
|
||||||
// default path
|
// default path
|
||||||
let mut answer = Vec::with_capacity_in(tags_vec.len(), arena);
|
let mut answer = Vec::with_capacity_in(tags_list.len(), arena);
|
||||||
let mut has_any_arguments = false;
|
let mut has_any_arguments = false;
|
||||||
|
|
||||||
let mut nullable: Option<(TagIdIntType, TagName)> = None;
|
let mut nullable: Option<(TagIdIntType, TagName)> = None;
|
||||||
|
@ -1997,7 +2003,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
// only recursive tag unions can be nullable
|
// only recursive tag unions can be nullable
|
||||||
let is_recursive = opt_rec_var.is_some();
|
let is_recursive = opt_rec_var.is_some();
|
||||||
if is_recursive && GENERATE_NULLABLE {
|
if is_recursive && GENERATE_NULLABLE {
|
||||||
for (index, (name, variables)) in tags_vec.iter().enumerate() {
|
for (index, (name, variables)) in tags_list.iter().enumerate() {
|
||||||
if variables.is_empty() {
|
if variables.is_empty() {
|
||||||
nullable = Some((index as TagIdIntType, (*name).clone()));
|
nullable = Some((index as TagIdIntType, (*name).clone()));
|
||||||
break;
|
break;
|
||||||
|
@ -2005,7 +2011,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, (tag_name, arguments)) in tags_vec.into_iter().enumerate() {
|
for (index, &(tag_name, arguments)) in tags_list.into_iter().enumerate() {
|
||||||
// reserve space for the tag discriminant
|
// reserve space for the tag discriminant
|
||||||
if matches!(nullable, Some((i, _)) if i as usize == index) {
|
if matches!(nullable, Some((i, _)) if i as usize == index) {
|
||||||
debug_assert!(arguments.is_empty());
|
debug_assert!(arguments.is_empty());
|
||||||
|
@ -2014,8 +2020,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
|
|
||||||
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, arena);
|
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, arena);
|
||||||
|
|
||||||
for var_index in arguments {
|
for &var in arguments {
|
||||||
let var = subs[var_index];
|
|
||||||
match Layout::from_var(&mut env, var) {
|
match Layout::from_var(&mut env, var) {
|
||||||
Ok(layout) => {
|
Ok(layout) => {
|
||||||
has_any_arguments = true;
|
has_any_arguments = true;
|
||||||
|
@ -2326,38 +2331,15 @@ pub fn union_sorted_tags_help<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cheap_sort_tags<'a, 'b>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
tags: UnionTags,
|
|
||||||
subs: &'b Subs,
|
|
||||||
) -> Vec<'a, (&'b TagName, VariableSubsSlice)> {
|
|
||||||
let mut tags_vec = Vec::with_capacity_in(tags.len(), arena);
|
|
||||||
|
|
||||||
for (tag_index, index) in tags.iter_all() {
|
|
||||||
let tag = &subs[tag_index];
|
|
||||||
let slice = subs[index];
|
|
||||||
|
|
||||||
tags_vec.push((tag, slice));
|
|
||||||
}
|
|
||||||
|
|
||||||
tags_vec
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout_from_newtype<'a>(
|
fn layout_from_newtype<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
tags: UnionTags,
|
tags: &UnsortedUnionTags,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
ptr_bytes: u32,
|
ptr_bytes: u32,
|
||||||
) -> Layout<'a> {
|
) -> Layout<'a> {
|
||||||
debug_assert!(tags.is_newtype_wrapper(subs));
|
debug_assert!(tags.is_newtype_wrapper(subs));
|
||||||
|
|
||||||
let slice_index = tags.variables().into_iter().next().unwrap();
|
let (tag_name, var) = tags.get_newtype(subs);
|
||||||
let slice = subs[slice_index];
|
|
||||||
let var_index = slice.into_iter().next().unwrap();
|
|
||||||
let var = subs[var_index];
|
|
||||||
|
|
||||||
let tag_name_index = tags.tag_names().into_iter().next().unwrap();
|
|
||||||
let tag_name = &subs[tag_name_index];
|
|
||||||
|
|
||||||
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
|
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
|
||||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||||
|
@ -2388,7 +2370,7 @@ fn layout_from_newtype<'a>(
|
||||||
|
|
||||||
fn layout_from_tag_union<'a>(
|
fn layout_from_tag_union<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
tags: UnionTags,
|
tags: &UnsortedUnionTags,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
ptr_bytes: u32,
|
ptr_bytes: u32,
|
||||||
) -> Layout<'a> {
|
) -> Layout<'a> {
|
||||||
|
@ -2398,14 +2380,13 @@ fn layout_from_tag_union<'a>(
|
||||||
return layout_from_newtype(arena, tags, subs, ptr_bytes);
|
return layout_from_newtype(arena, tags, subs, ptr_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tags_vec = cheap_sort_tags(arena, tags, subs);
|
let tags_vec = &tags.tags;
|
||||||
|
|
||||||
match tags_vec.get(0) {
|
match tags_vec.get(0) {
|
||||||
Some((tag_name, arguments)) if *tag_name == &TagName::Private(Symbol::NUM_AT_NUM) => {
|
Some((tag_name, arguments)) if *tag_name == &TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||||
debug_assert_eq!(arguments.len(), 1);
|
debug_assert_eq!(arguments.len(), 1);
|
||||||
|
|
||||||
let var_index = arguments.into_iter().next().unwrap();
|
let &var = arguments.iter().next().unwrap();
|
||||||
let var = subs[var_index];
|
|
||||||
|
|
||||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1367,3 +1367,85 @@ fn monomorphized_tag_with_polymorphic_arg_and_monomorphic_arg() {
|
||||||
u8
|
u8
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn issue_2365_monomorphize_tag_with_non_empty_ext_var() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Single a : [A, B, C]a
|
||||||
|
Compound a : Single [D, E, F]a
|
||||||
|
|
||||||
|
single : {} -> Single *
|
||||||
|
single = \{} -> C
|
||||||
|
|
||||||
|
compound : {} -> Compound *
|
||||||
|
compound = \{} -> single {}
|
||||||
|
|
||||||
|
main = compound {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2, // C
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn issue_2365_monomorphize_tag_with_non_empty_ext_var_wrapped() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Single a : [A, B, C]a
|
||||||
|
Compound a : Single [D, E, F]a
|
||||||
|
|
||||||
|
single : {} -> Result Str (Single *)
|
||||||
|
single = \{} -> Err C
|
||||||
|
|
||||||
|
compound : {} -> Result Str (Compound *)
|
||||||
|
compound = \{} ->
|
||||||
|
when single {} is
|
||||||
|
Ok s -> Ok s
|
||||||
|
Err e -> Err e
|
||||||
|
|
||||||
|
main = compound {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2, // C
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn issue_2365_monomorphize_tag_with_non_empty_ext_var_wrapped_nested() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Single a : [A, B, C]a
|
||||||
|
Compound a : Single [D, E, F]a
|
||||||
|
|
||||||
|
main =
|
||||||
|
single : {} -> Result Str (Single *)
|
||||||
|
single = \{} -> Err C
|
||||||
|
|
||||||
|
compound : {} -> Result Str (Compound *)
|
||||||
|
compound = \{} ->
|
||||||
|
when single {} is
|
||||||
|
Ok s -> Ok s
|
||||||
|
Err e -> Err e
|
||||||
|
|
||||||
|
compound {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2, // C
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -406,8 +406,8 @@ fn write_sorted_tags2<'a>(
|
||||||
ext_var: Variable,
|
ext_var: Variable,
|
||||||
) -> ExtContent<'a> {
|
) -> ExtContent<'a> {
|
||||||
// Sort the fields so they always end up in the same order.
|
// Sort the fields so they always end up in the same order.
|
||||||
let (it, new_ext_var) = tags.unsorted_iterator_and_ext(subs, ext_var);
|
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
let mut sorted_fields: Vec<_> = it.collect();
|
let mut sorted_fields = tags.tags;
|
||||||
|
|
||||||
let interns = &env.interns;
|
let interns = &env.interns;
|
||||||
let home = env.home;
|
let home = env.home;
|
||||||
|
|
|
@ -1813,16 +1813,17 @@ impl UnionTags {
|
||||||
it.map(f)
|
it.map(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unsorted_iterator_and_ext<'a>(
|
#[inline(always)]
|
||||||
|
pub fn unsorted_tags_and_ext<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
ext: Variable,
|
ext: Variable,
|
||||||
) -> (impl Iterator<Item = (&TagName, &[Variable])> + 'a, Variable) {
|
) -> (UnsortedUnionTags<'a>, Variable) {
|
||||||
let (it, ext) = crate::types::gather_tags_unsorted_iter(subs, *self, ext);
|
let (it, ext) = crate::types::gather_tags_unsorted_iter(subs, *self, ext);
|
||||||
|
|
||||||
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
||||||
|
let it = it.map(f);
|
||||||
|
|
||||||
(it.map(f), ext)
|
(UnsortedUnionTags { tags: it.collect() }, ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -1877,6 +1878,25 @@ impl UnionTags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UnsortedUnionTags<'a> {
|
||||||
|
pub tags: Vec<(&'a TagName, &'a [Variable])>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UnsortedUnionTags<'a> {
|
||||||
|
pub fn is_newtype_wrapper(&self, _subs: &Subs) -> bool {
|
||||||
|
if self.tags.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.tags[0].1.len() == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_newtype(&self, _subs: &Subs) -> (&TagName, Variable) {
|
||||||
|
let (tag_name, vars) = self.tags[0];
|
||||||
|
(tag_name, vars[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type SortedTagsIterator<'a> = Box<dyn Iterator<Item = (TagName, &'a [Variable])> + 'a>;
|
pub type SortedTagsIterator<'a> = Box<dyn Iterator<Item = (TagName, &'a [Variable])> + 'a>;
|
||||||
pub type SortedTagsSlicesIterator<'a> = Box<dyn Iterator<Item = (TagName, VariableSubsSlice)> + 'a>;
|
pub type SortedTagsSlicesIterator<'a> = Box<dyn Iterator<Item = (TagName, VariableSubsSlice)> + 'a>;
|
||||||
|
|
||||||
|
@ -2025,6 +2045,21 @@ impl RecordFields {
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn unsorted_iterator_and_ext<'a>(
|
||||||
|
&'a self,
|
||||||
|
subs: &'a Subs,
|
||||||
|
ext: Variable,
|
||||||
|
) -> (
|
||||||
|
impl Iterator<Item = (&Lowercase, RecordField<Variable>)> + 'a,
|
||||||
|
Variable,
|
||||||
|
) {
|
||||||
|
let (it, ext) = crate::types::gather_fields_unsorted_iter(subs, *self, ext)
|
||||||
|
.expect("Something weird ended up in a record type");
|
||||||
|
|
||||||
|
(it, ext)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a sorted iterator over the fields of this record type
|
/// Get a sorted iterator over the fields of this record type
|
||||||
///
|
///
|
||||||
/// Implementation: When the record has an `ext` variable that is the empty record, then
|
/// Implementation: When the record has an `ext` variable that is the empty record, then
|
||||||
|
|
8
error_macros/Cargo.toml
Normal file
8
error_macros/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "roc_error_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The Roc Contributors"]
|
||||||
|
license = "UPL-1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
31
error_macros/src/lib.rs
Normal file
31
error_macros/src/lib.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/// `internal_error!` should be used whenever a compiler invariant is broken.
|
||||||
|
/// It is a wrapper around panic that tells the user to file a bug.
|
||||||
|
/// This should only be used in cases where there would be a compiler bug and the user can't fix it.
|
||||||
|
/// If there is simply an unimplemented feature, please use `unimplemented!`
|
||||||
|
/// If there is a user error, please use roc_reporting to print a nice error message.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! internal_error {
|
||||||
|
($($arg:tt)*) => ({
|
||||||
|
eprintln!("An internal compiler expectation was broken.");
|
||||||
|
eprintln!("This is definitely a compiler bug.");
|
||||||
|
// TODO: update this to the new bug template.
|
||||||
|
eprintln!("Please file an issue here: https://github.com/rtfeldman/roc/issues/new/choose");
|
||||||
|
#[allow(clippy::panic)] {
|
||||||
|
panic!($($arg)*);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `user_error!` should only ever be used temporarily.
|
||||||
|
/// It is a way to document locations where we do not yet have nice error reporting.
|
||||||
|
/// All cases of `user_error!` should eventually be replaced with pretty error printing using roc_reporting.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! user_error {
|
||||||
|
($($arg:tt)*) => ({
|
||||||
|
eprintln!("We ran into an issue while compiling your code.");
|
||||||
|
eprintln!("Sadly, we don't havs a pretty error message for this case yet.");
|
||||||
|
eprintln!("If you can't figure out the problem from the context below, please reach out at: https://roc.zulipchat.com/");
|
||||||
|
eprintln!($($arg)*);
|
||||||
|
std::process::exit(1);
|
||||||
|
})
|
||||||
|
}
|
|
@ -21,22 +21,6 @@ main =
|
||||||
|
|
||||||
|> Task.map (\_ -> {})
|
|> Task.map (\_ -> {})
|
||||||
|
|
||||||
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
|
||||||
nest = \f, n, e -> Task.loop { s: n, f, m: n, x: e } nestHelp
|
|
||||||
|
|
||||||
State : { s : I64, f : I64, Expr -> IO Expr, m : I64, x : Expr }
|
|
||||||
|
|
||||||
nestHelp : State -> IO [ Step State, Done Expr ]
|
|
||||||
nestHelp = \{ s, f, m, x } ->
|
|
||||||
when m is
|
|
||||||
0 ->
|
|
||||||
Task.succeed (Done x)
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
w <- Task.after (f (s - m) x)
|
|
||||||
|
|
||||||
Task.succeed (Step { s, f, m: (m - 1), x: w })
|
|
||||||
|
|
||||||
Expr : [ Val I64, Var Str, Add Expr Expr, Mul Expr Expr, Pow Expr Expr, Ln Expr ]
|
Expr : [ Val I64, Var Str, Add Expr Expr, Mul Expr Expr, Pow Expr Expr, Ln Expr ]
|
||||||
|
|
||||||
divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
|
divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
|
||||||
|
@ -196,6 +180,18 @@ count = \expr ->
|
||||||
Ln f ->
|
Ln f ->
|
||||||
count f
|
count f
|
||||||
|
|
||||||
|
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||||
|
nest = \f, n, e -> nestHelp n f n e
|
||||||
|
|
||||||
|
nestHelp : I64, (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||||
|
nestHelp = \s, f, m, x ->
|
||||||
|
when m is
|
||||||
|
0 ->
|
||||||
|
Task.succeed x
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
f (s - m) x |> Task.after \w -> nestHelp s f (m - 1) w
|
||||||
|
|
||||||
deriv : I64, Expr -> IO Expr
|
deriv : I64, Expr -> IO Expr
|
||||||
deriv = \i, f ->
|
deriv = \i, f ->
|
||||||
fprime = d "x" f
|
fprime = d "x" f
|
||||||
|
|
|
@ -89,10 +89,6 @@ isWhitespace = \char ->
|
||||||
== 0x9# tab
|
== 0x9# tab
|
||||||
interpretCtx : Context -> Task Context InterpreterErrors
|
interpretCtx : Context -> Task Context InterpreterErrors
|
||||||
interpretCtx = \ctx ->
|
interpretCtx = \ctx ->
|
||||||
Task.loop ctx interpretCtxLoop
|
|
||||||
|
|
||||||
interpretCtxLoop : Context -> Task [ Step Context, Done Context ] InterpreterErrors
|
|
||||||
interpretCtxLoop = \ctx ->
|
|
||||||
when ctx.state is
|
when ctx.state is
|
||||||
Executing if Context.inWhileScope ctx ->
|
Executing if Context.inWhileScope ctx ->
|
||||||
# Deal with the current while loop potentially looping.
|
# Deal with the current while loop potentially looping.
|
||||||
|
@ -108,11 +104,11 @@ interpretCtxLoop = \ctx ->
|
||||||
if n == 0 then
|
if n == 0 then
|
||||||
newScope = { scope & whileInfo: None }
|
newScope = { scope & whileInfo: None }
|
||||||
|
|
||||||
Task.succeed (Step { popCtx & scopes: List.set ctx.scopes last newScope })
|
interpretCtx { popCtx & scopes: List.set ctx.scopes last newScope }
|
||||||
else
|
else
|
||||||
newScope = { scope & whileInfo: Some { state: InBody, body, cond } }
|
newScope = { scope & whileInfo: Some { state: InBody, body, cond } }
|
||||||
|
|
||||||
Task.succeed (Step { popCtx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: body, index: 0, whileInfo: None } })
|
interpretCtx { popCtx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: body, index: 0, whileInfo: None } }
|
||||||
|
|
||||||
Err e ->
|
Err e ->
|
||||||
Task.fail e
|
Task.fail e
|
||||||
|
@ -121,7 +117,7 @@ interpretCtxLoop = \ctx ->
|
||||||
# Just rand the body. Run the condition again.
|
# Just rand the body. Run the condition again.
|
||||||
newScope = { scope & whileInfo: Some { state: InCond, body, cond } }
|
newScope = { scope & whileInfo: Some { state: InCond, body, cond } }
|
||||||
|
|
||||||
Task.succeed (Step { ctx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: cond, index: 0, whileInfo: None } })
|
interpretCtx { ctx & scopes: List.append (List.set ctx.scopes last newScope) { data: None, buf: cond, index: 0, whileInfo: None } }
|
||||||
|
|
||||||
None ->
|
None ->
|
||||||
Task.fail NoScope
|
Task.fail NoScope
|
||||||
|
@ -135,7 +131,7 @@ interpretCtxLoop = \ctx ->
|
||||||
when result is
|
when result is
|
||||||
Ok (T val newCtx) ->
|
Ok (T val newCtx) ->
|
||||||
execCtx <- Task.await (stepExecCtx newCtx val)
|
execCtx <- Task.await (stepExecCtx newCtx val)
|
||||||
Task.succeed (Step execCtx)
|
interpretCtx execCtx
|
||||||
|
|
||||||
Err NoScope ->
|
Err NoScope ->
|
||||||
Task.fail NoScope
|
Task.fail NoScope
|
||||||
|
@ -147,9 +143,9 @@ interpretCtxLoop = \ctx ->
|
||||||
|
|
||||||
# If no scopes left, all execution complete.
|
# If no scopes left, all execution complete.
|
||||||
if List.isEmpty dropCtx.scopes then
|
if List.isEmpty dropCtx.scopes then
|
||||||
Task.succeed (Done dropCtx)
|
Task.succeed dropCtx
|
||||||
else
|
else
|
||||||
Task.succeed (Step dropCtx)
|
interpretCtx dropCtx
|
||||||
|
|
||||||
InComment ->
|
InComment ->
|
||||||
result <- Task.attempt (Context.getChar ctx)
|
result <- Task.attempt (Context.getChar ctx)
|
||||||
|
@ -157,9 +153,9 @@ interpretCtxLoop = \ctx ->
|
||||||
Ok (T val newCtx) ->
|
Ok (T val newCtx) ->
|
||||||
if val == 0x7D then
|
if val == 0x7D then
|
||||||
# `}` end of comment
|
# `}` end of comment
|
||||||
Task.succeed (Step { newCtx & state: Executing })
|
interpretCtx { newCtx & state: Executing }
|
||||||
else
|
else
|
||||||
Task.succeed (Step { newCtx & state: InComment })
|
interpretCtx { newCtx & state: InComment }
|
||||||
|
|
||||||
Err NoScope ->
|
Err NoScope ->
|
||||||
Task.fail NoScope
|
Task.fail NoScope
|
||||||
|
@ -178,13 +174,13 @@ interpretCtxLoop = \ctx ->
|
||||||
# so this is make i64 mul by 10 then convert back to i32.
|
# so this is make i64 mul by 10 then convert back to i32.
|
||||||
nextAccum = (10 * Num.intCast accum) + Num.intCast (val - 0x30)
|
nextAccum = (10 * Num.intCast accum) + Num.intCast (val - 0x30)
|
||||||
|
|
||||||
Task.succeed (Step { newCtx & state: InNumber (Num.intCast nextAccum) })
|
interpretCtx { newCtx & state: InNumber (Num.intCast nextAccum) }
|
||||||
else
|
else
|
||||||
# outside of number now, this needs to be executed.
|
# outside of number now, this needs to be executed.
|
||||||
pushCtx = Context.pushStack newCtx (Number accum)
|
pushCtx = Context.pushStack newCtx (Number accum)
|
||||||
|
|
||||||
execCtx <- Task.await (stepExecCtx { pushCtx & state: Executing } val)
|
execCtx <- Task.await (stepExecCtx { pushCtx & state: Executing } val)
|
||||||
Task.succeed (Step execCtx)
|
interpretCtx execCtx
|
||||||
|
|
||||||
Err NoScope ->
|
Err NoScope ->
|
||||||
Task.fail NoScope
|
Task.fail NoScope
|
||||||
|
@ -201,12 +197,12 @@ interpretCtxLoop = \ctx ->
|
||||||
when Str.fromUtf8 bytes is
|
when Str.fromUtf8 bytes is
|
||||||
Ok str ->
|
Ok str ->
|
||||||
{ } <- Task.await (Stdout.raw str)
|
{ } <- Task.await (Stdout.raw str)
|
||||||
Task.succeed (Step { newCtx & state: Executing })
|
interpretCtx { newCtx & state: Executing }
|
||||||
|
|
||||||
Err _ ->
|
Err _ ->
|
||||||
Task.fail BadUtf8
|
Task.fail BadUtf8
|
||||||
else
|
else
|
||||||
Task.succeed (Step { newCtx & state: InString (List.append bytes val) })
|
interpretCtx { newCtx & state: InString (List.append bytes val) }
|
||||||
|
|
||||||
Err NoScope ->
|
Err NoScope ->
|
||||||
Task.fail NoScope
|
Task.fail NoScope
|
||||||
|
@ -220,17 +216,17 @@ interpretCtxLoop = \ctx ->
|
||||||
Ok (T val newCtx) ->
|
Ok (T val newCtx) ->
|
||||||
if val == 0x5B then
|
if val == 0x5B then
|
||||||
# start of a nested lambda `[`
|
# start of a nested lambda `[`
|
||||||
Task.succeed (Step { newCtx & state: InLambda (depth + 1) (List.append bytes val) })
|
interpretCtx { newCtx & state: InLambda (depth + 1) (List.append bytes val) }
|
||||||
else if val == 0x5D then
|
else if val == 0x5D then
|
||||||
# `]` end of current lambda
|
# `]` end of current lambda
|
||||||
if depth == 0 then
|
if depth == 0 then
|
||||||
# end of all lambdas
|
# end of all lambdas
|
||||||
Task.succeed (Step (Context.pushStack { newCtx & state: Executing } (Lambda bytes)))
|
interpretCtx (Context.pushStack { newCtx & state: Executing } (Lambda bytes))
|
||||||
else
|
else
|
||||||
# end of nested lambda
|
# end of nested lambda
|
||||||
Task.succeed (Step { newCtx & state: InLambda (depth - 1) (List.append bytes val) })
|
interpretCtx { newCtx & state: InLambda (depth - 1) (List.append bytes val) }
|
||||||
else
|
else
|
||||||
Task.succeed (Step { newCtx & state: InLambda depth (List.append bytes val) })
|
interpretCtx { newCtx & state: InLambda depth (List.append bytes val) }
|
||||||
|
|
||||||
Err NoScope ->
|
Err NoScope ->
|
||||||
Task.fail NoScope
|
Task.fail NoScope
|
||||||
|
@ -256,14 +252,14 @@ interpretCtxLoop = \ctx ->
|
||||||
|
|
||||||
when result2 is
|
when result2 is
|
||||||
Ok a ->
|
Ok a ->
|
||||||
Task.succeed (Step a)
|
interpretCtx a
|
||||||
|
|
||||||
Err e ->
|
Err e ->
|
||||||
Task.fail e
|
Task.fail e
|
||||||
|
|
||||||
Ok (T 0x9F newCtx) ->
|
Ok (T 0x9F newCtx) ->
|
||||||
# This is supposed to flush io buffers. We don't buffer, so it does nothing
|
# This is supposed to flush io buffers. We don't buffer, so it does nothing
|
||||||
Task.succeed (Step newCtx)
|
interpretCtx newCtx
|
||||||
|
|
||||||
Ok (T x _) ->
|
Ok (T x _) ->
|
||||||
data = Num.toStr (Num.intCast x)
|
data = Num.toStr (Num.intCast x)
|
||||||
|
@ -280,7 +276,7 @@ interpretCtxLoop = \ctx ->
|
||||||
result <- Task.attempt (Context.getChar { ctx & state: Executing })
|
result <- Task.attempt (Context.getChar { ctx & state: Executing })
|
||||||
when result is
|
when result is
|
||||||
Ok (T x newCtx) ->
|
Ok (T x newCtx) ->
|
||||||
Task.succeed (Step (Context.pushStack newCtx (Number (Num.intCast x))))
|
interpretCtx (Context.pushStack newCtx (Number (Num.intCast x)))
|
||||||
|
|
||||||
Err NoScope ->
|
Err NoScope ->
|
||||||
Task.fail NoScope
|
Task.fail NoScope
|
||||||
|
|
|
@ -1,27 +1,9 @@
|
||||||
interface Task
|
interface Task
|
||||||
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult, loop ]
|
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult ]
|
||||||
imports [ fx.Effect ]
|
imports [ fx.Effect ]
|
||||||
|
|
||||||
Task ok err : Effect.Effect (Result ok err)
|
Task ok err : Effect.Effect (Result ok err)
|
||||||
|
|
||||||
loop : state, (state -> Task [ Step state, Done done ] err) -> Task done err
|
|
||||||
loop = \state, step ->
|
|
||||||
looper = \current ->
|
|
||||||
step current
|
|
||||||
|> Effect.map
|
|
||||||
\res ->
|
|
||||||
when res is
|
|
||||||
Ok (Step newState) ->
|
|
||||||
Step newState
|
|
||||||
|
|
||||||
Ok (Done result) ->
|
|
||||||
Done (Ok result)
|
|
||||||
|
|
||||||
Err e ->
|
|
||||||
Done (Err e)
|
|
||||||
|
|
||||||
Effect.loop state looper
|
|
||||||
|
|
||||||
succeed : val -> Task val *
|
succeed : val -> Task val *
|
||||||
succeed = \val ->
|
succeed = \val ->
|
||||||
Effect.always (Ok val)
|
Effect.always (Ok val)
|
||||||
|
|
|
@ -4,35 +4,3 @@
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod report;
|
pub mod report;
|
||||||
|
|
||||||
/// `internal_error!` should be used whenever a compiler invariant is broken.
|
|
||||||
/// It is a wrapper around panic that tells the user to file a bug.
|
|
||||||
/// This should only be used in cases where there would be a compiler bug and the user can't fix it.
|
|
||||||
/// If there is simply an unimplemented feature, please use `unimplemented!`
|
|
||||||
/// If there is a user error, please use roc_reporting to print a nice error message.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! internal_error {
|
|
||||||
($($arg:tt)*) => ({
|
|
||||||
eprintln!("An internal compiler expectation was broken.");
|
|
||||||
eprintln!("This is definitely a compiler bug.");
|
|
||||||
// TODO: update this to the new bug template.
|
|
||||||
eprintln!("Please file an issue here: https://github.com/rtfeldman/roc/issues/new/choose");
|
|
||||||
#[allow(clippy::panic)] {
|
|
||||||
panic!($($arg)*);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `user_error!` should only ever be used temporarily.
|
|
||||||
/// It is a way to document locations where we do not yet have nice error reporting.
|
|
||||||
/// All cases of `user_error!` should eventually be replaced with pretty error printing using roc_reporting.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! user_error {
|
|
||||||
($($arg:tt)*) => ({
|
|
||||||
eprintln!("We ran into an issue while compiling your code.");
|
|
||||||
eprintln!("Sadly, we don't havs a pretty error message for this case yet.");
|
|
||||||
eprintln!("If you can't figure out the problem from the context below, please reach out at: https://roc.zulipchat.com/");
|
|
||||||
eprintln!($($arg)*);
|
|
||||||
std::process::exit(1);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -424,6 +424,16 @@ mod test_reporting {
|
||||||
|
|
||||||
`Booly` is not used anywhere in your code.
|
`Booly` is not used anywhere in your code.
|
||||||
|
|
||||||
|
3│ Booly : [ Yes, No, Maybe ]
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
If you didn't intend on using `Booly` then remove it so future readers
|
||||||
|
of your code don't wonder why it is there.
|
||||||
|
|
||||||
|
── UNUSED DEFINITION ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
`Booly` is not used anywhere in your code.
|
||||||
|
|
||||||
1│ Booly : [ Yes, No ]
|
1│ Booly : [ Yes, No ]
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue