mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Merge remote-tracking branch 'origin/main' into abilities-syntax
This commit is contained in:
commit
2da41be29f
524 changed files with 47536 additions and 15089 deletions
|
@ -133,13 +133,13 @@ pub fn report_problems(
|
|||
problems_reported = warnings.len();
|
||||
|
||||
for warning in warnings.iter() {
|
||||
println!("\n{}\n", warning);
|
||||
println!("\n{warning}\n");
|
||||
}
|
||||
} else {
|
||||
problems_reported = errors.len();
|
||||
|
||||
for error in errors.iter() {
|
||||
println!("\n{}\n", error);
|
||||
println!("\n{error}\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -557,14 +557,8 @@ pub fn can_problem<'b>(
|
|||
doc = alloc.stack([
|
||||
alloc.reflow("This string interpolation is invalid:"),
|
||||
alloc.region(lines.convert_region(region)),
|
||||
alloc.concat([
|
||||
alloc.reflow(r"I was expecting an identifier, like "),
|
||||
alloc.parser_suggestion("\\u(message)"),
|
||||
alloc.reflow(" or "),
|
||||
alloc.parser_suggestion("\\u(LoremIpsum.text)"),
|
||||
alloc.text("."),
|
||||
]),
|
||||
alloc.reflow(r"Learn more about string interpolation at TODO"),
|
||||
alloc.reflow(r"String interpolations cannot contain newlines or other interpolations."),
|
||||
alloc.reflow(r"You can learn more about string interpolation at <https://www.roc-lang.org/tutorial#string-interpolation>"),
|
||||
]);
|
||||
|
||||
title = SYNTAX_PROBLEM.to_string();
|
||||
|
@ -845,7 +839,7 @@ pub fn can_problem<'b>(
|
|||
alloc.reflow("An implementation of "), alloc.symbol_unqualified(member), alloc.reflow(" could not be found in this scope:"),
|
||||
]),
|
||||
alloc.region(lines.convert_region(region)),
|
||||
alloc.tip().append(alloc.concat([alloc.reflow("consider adding a value of name "), alloc.symbol_unqualified(member), alloc.reflow(" in this scope, or using another variable that implements this ability member, like "), alloc.type_str(&format!("{{ {}: my{} }}", member_str, member_str))]))
|
||||
alloc.tip().append(alloc.concat([alloc.reflow("consider adding a value of name "), alloc.symbol_unqualified(member), alloc.reflow(" in this scope, or using another variable that implements this ability member, like "), alloc.type_str(&format!("{{ {member_str}: my{member_str} }}"))]))
|
||||
]);
|
||||
title = IMPLEMENTATION_NOT_FOUND.to_string();
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ impl<'a> Renderer<'a> {
|
|||
&crate::report::DEFAULT_PALETTE,
|
||||
);
|
||||
|
||||
write!(writer, "{}", buf)
|
||||
write!(writer, "{buf}")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -238,6 +238,6 @@ impl<'a> Renderer<'a> {
|
|||
&crate::report::DEFAULT_PALETTE,
|
||||
);
|
||||
|
||||
write!(writer, "{}", buf)
|
||||
write!(writer, "{buf}")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,6 +300,15 @@ fn to_expr_report<'a>(
|
|||
alloc.parser_suggestion("!"),
|
||||
alloc.reflow(" and the expression after it."),
|
||||
],
|
||||
"<|" => vec![
|
||||
alloc.reflow("Roc doesn't have a "),
|
||||
alloc.parser_suggestion("<|"),
|
||||
alloc.reflow(" operator. Please use parentheses "),
|
||||
alloc.parser_suggestion("()"),
|
||||
alloc.reflow(" or "),
|
||||
alloc.parser_suggestion("|>"),
|
||||
alloc.reflow(" instead."),
|
||||
],
|
||||
_ => vec![
|
||||
alloc.reflow("I have no specific suggestion for this operator, "),
|
||||
alloc.reflow("see TODO for the full list of operators in Roc."),
|
||||
|
@ -3469,7 +3478,7 @@ fn to_provides_report<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
EProvides::Provides(pos) => {
|
||||
EProvides::Provides(pos) | EProvides::IndentProvides(pos) => {
|
||||
let surroundings = Region::new(start, pos);
|
||||
let region = LineColumnRegion::from_pos(lines.convert_pos(pos));
|
||||
|
||||
|
|
|
@ -1048,7 +1048,7 @@ fn to_expr_report<'b>(
|
|||
region,
|
||||
Some(expr_region),
|
||||
alloc.reflow("This list contains elements with different types:"),
|
||||
alloc.string(format!("Its {} element is", ith)),
|
||||
alloc.string(format!("Its {ith} element is")),
|
||||
alloc.reflow(prev_elems_msg),
|
||||
Some(alloc.reflow("Every element in a list must have the same type!")),
|
||||
)
|
||||
|
@ -1181,7 +1181,7 @@ fn to_expr_report<'b>(
|
|||
if arity == 1 {
|
||||
"1 argument".into()
|
||||
} else {
|
||||
format!("{} arguments", arity)
|
||||
format!("{arity} arguments")
|
||||
}
|
||||
)),
|
||||
]),
|
||||
|
@ -1228,7 +1228,7 @@ fn to_expr_report<'b>(
|
|||
if n == 1 {
|
||||
"1 argument".into()
|
||||
} else {
|
||||
format!("{} arguments", n)
|
||||
format!("{n} arguments")
|
||||
},
|
||||
arity
|
||||
)),
|
||||
|
@ -1252,7 +1252,7 @@ fn to_expr_report<'b>(
|
|||
if n == 1 {
|
||||
"1 argument".into()
|
||||
} else {
|
||||
format!("{} arguments", n)
|
||||
format!("{n} arguments")
|
||||
},
|
||||
arity
|
||||
)),
|
||||
|
@ -1866,10 +1866,7 @@ fn format_category<'b>(
|
|||
),
|
||||
CallResult(None, _) => (this_is, alloc.text(":")),
|
||||
LowLevelOpResult(op) => {
|
||||
panic!(
|
||||
"Compiler bug: invalid return type from low-level op {:?}",
|
||||
op
|
||||
);
|
||||
panic!("Compiler bug: invalid return type from low-level op {op:?}");
|
||||
}
|
||||
ForeignCall => {
|
||||
panic!("Compiler bug: invalid return type from foreign call",);
|
||||
|
@ -4379,8 +4376,8 @@ fn type_problem_to_pretty<'b>(
|
|||
match suggestions.get(0) {
|
||||
None => alloc.nil(),
|
||||
Some(nearest) => {
|
||||
let typo_str = format!("{}", typo);
|
||||
let nearest_str = format!("{}", nearest);
|
||||
let typo_str = format!("{typo}");
|
||||
let nearest_str = format!("{nearest}");
|
||||
|
||||
let found = alloc.text(typo_str).annotate(Annotation::Typo);
|
||||
let suggestion = alloc.text(nearest_str).annotate(Annotation::TypoSuggestion);
|
||||
|
@ -4431,7 +4428,7 @@ fn type_problem_to_pretty<'b>(
|
|||
match suggestions.get(0) {
|
||||
None => alloc.nil(),
|
||||
Some(nearest) => {
|
||||
let nearest_str = format!("{}", nearest);
|
||||
let nearest_str = format!("{nearest}");
|
||||
|
||||
let found = alloc.text(typo_str).annotate(Annotation::Typo);
|
||||
let suggestion = alloc.text(nearest_str).annotate(Annotation::TypoSuggestion);
|
||||
|
|
|
@ -438,7 +438,7 @@ impl<'a> RocDocAllocator<'a> {
|
|||
}
|
||||
|
||||
pub fn wrapped_opaque_name(&'a self, opaque: Symbol) -> DocBuilder<'a, Self, Annotation> {
|
||||
debug_assert_eq!(opaque.module_id(), self.home, "Opaque wrappings can only be defined in the same module they're defined in, but this one is defined elsewhere: {:?}", opaque);
|
||||
debug_assert_eq!(opaque.module_id(), self.home, "Opaque wrappings can only be defined in the same module they're defined in, but this one is defined elsewhere: {opaque:?}");
|
||||
|
||||
text!(self, "@{}", opaque.as_str(self.interns)).annotate(Annotation::Opaque)
|
||||
}
|
||||
|
@ -1612,7 +1612,7 @@ pub fn to_file_problem_report<'b>(
|
|||
}
|
||||
_ => {
|
||||
let error = std::io::Error::from(error);
|
||||
let formatted = format!("{}", error);
|
||||
let formatted = format!("{error}");
|
||||
let doc = alloc.stack([
|
||||
alloc.reflow(r"I tried to read this file:"),
|
||||
alloc.string(filename).annotate(Annotation::Error).indent(4),
|
||||
|
|
|
@ -15,7 +15,9 @@ use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds};
|
|||
use roc_parse::parser::{SourceError, SyntaxError};
|
||||
use roc_problem::can::Problem;
|
||||
use roc_region::all::Loc;
|
||||
use roc_solve::solve::{self, Aliases};
|
||||
use roc_solve::module::SolveConfig;
|
||||
use roc_solve::solve::RunSolveOutput;
|
||||
use roc_solve::{solve, Aliases, FunctionKind};
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_types::subs::{Content, Subs, VarStore, Variable};
|
||||
use roc_types::types::Types;
|
||||
|
@ -33,26 +35,28 @@ pub fn infer_expr(
|
|||
problems: &mut Vec<TypeError>,
|
||||
types: Types,
|
||||
constraints: &Constraints,
|
||||
constraint: &Constraint,
|
||||
constraint: Constraint,
|
||||
pending_derives: PendingDerives,
|
||||
aliases: &mut Aliases,
|
||||
abilities_store: &mut AbilitiesStore,
|
||||
derived_module: SharedDerivedModule,
|
||||
expr_var: Variable,
|
||||
) -> (Content, Subs) {
|
||||
let (solved, _) = solve::run(
|
||||
ModuleId::ATTR,
|
||||
let config = SolveConfig {
|
||||
types,
|
||||
constraints,
|
||||
problems,
|
||||
subs,
|
||||
aliases,
|
||||
constraint,
|
||||
root_constraint: constraint,
|
||||
home: ModuleId::ATTR,
|
||||
pending_derives,
|
||||
abilities_store,
|
||||
&Default::default(),
|
||||
exposed_by_module: &Default::default(),
|
||||
derived_module,
|
||||
);
|
||||
function_kind: FunctionKind::LambdaSet,
|
||||
#[cfg(debug_assertions)]
|
||||
checkmate: None,
|
||||
};
|
||||
|
||||
let RunSolveOutput { solved, .. } =
|
||||
solve::run(config, problems, subs, aliases, abilities_store);
|
||||
|
||||
let content = *solved.inner().get_content_without_compacting(expr_var);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ mod test_reporting {
|
|||
DEFAULT_PALETTE,
|
||||
};
|
||||
use roc_reporting::report::{RocDocAllocator, RocDocBuilder};
|
||||
use roc_solve::FunctionKind;
|
||||
use roc_solve_problem::TypeError;
|
||||
use roc_types::subs::Subs;
|
||||
use std::path::PathBuf;
|
||||
|
@ -86,7 +87,7 @@ mod test_reporting {
|
|||
path.push("snapshots");
|
||||
path.push("fail");
|
||||
let kind = if is_expr { "expr" } else { "header" };
|
||||
path.push(format!("{}.{}.roc", test_name, kind));
|
||||
path.push(format!("{test_name}.{kind}.roc"));
|
||||
|
||||
std::fs::write(path, src).unwrap();
|
||||
}
|
||||
|
@ -113,20 +114,21 @@ mod test_reporting {
|
|||
// Use a deterministic temporary directory.
|
||||
// We can't have all tests use "tmp" because tests run in parallel,
|
||||
// so append the test name to the tmp path.
|
||||
let tmp = format!("tmp/{}", subdir);
|
||||
let tmp = format!("tmp/{subdir}");
|
||||
let dir = roc_test_utils::TmpDir::new(&tmp);
|
||||
|
||||
let filename = PathBuf::from("Test.roc");
|
||||
let file_path = dir.path().join(filename);
|
||||
let full_file_path = file_path.clone();
|
||||
let mut file = File::create(file_path).unwrap();
|
||||
writeln!(file, "{}", module_src).unwrap();
|
||||
writeln!(file, "{module_src}").unwrap();
|
||||
let load_config = LoadConfig {
|
||||
target_info: roc_target::TargetInfo::default_x86_64(),
|
||||
render: RenderTarget::Generic,
|
||||
palette: DEFAULT_PALETTE,
|
||||
threading: Threading::Single,
|
||||
exec_mode: ExecutionMode::Check,
|
||||
function_kind: FunctionKind::LambdaSet,
|
||||
};
|
||||
let result = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
|
@ -218,7 +220,7 @@ mod test_reporting {
|
|||
buf
|
||||
}
|
||||
Err(other) => {
|
||||
panic!("failed to load: {:?}", other);
|
||||
panic!("failed to load: {other:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,7 +260,7 @@ mod test_reporting {
|
|||
subs.rigid_var(var.value, "*".into());
|
||||
}
|
||||
|
||||
let mut solve_aliases = roc_solve::solve::Aliases::default();
|
||||
let mut solve_aliases = roc_solve::Aliases::default();
|
||||
|
||||
for (name, alias) in output.aliases {
|
||||
solve_aliases.insert(&mut types, name, alias);
|
||||
|
@ -271,7 +273,7 @@ mod test_reporting {
|
|||
&mut unify_problems,
|
||||
types,
|
||||
&constraints,
|
||||
&constraint,
|
||||
constraint,
|
||||
// Use `new_report_problem_as` in order to get proper derives.
|
||||
// TODO: remove the non-new reporting test infra.
|
||||
PendingDerives::default(),
|
||||
|
@ -389,7 +391,7 @@ mod test_reporting {
|
|||
// convenient to copy-paste the generated message
|
||||
if buf != expected_rendering {
|
||||
for line in buf.split('\n') {
|
||||
println!(" {}", line);
|
||||
println!(" {line}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5363,24 +5365,6 @@ Tab characters are not allowed."###,
|
|||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
interpolate_not_identifier,
|
||||
r#""abc\(32)def""#,
|
||||
@r###"
|
||||
── SYNTAX PROBLEM ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This string interpolation is invalid:
|
||||
|
||||
4│ "abc\(32)def"
|
||||
^^
|
||||
|
||||
I was expecting an identifier, like \u(message) or
|
||||
\u(LoremIpsum.text).
|
||||
|
||||
Learn more about string interpolation at TODO
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
unicode_too_large,
|
||||
r#""abc\u(110000)def""#,
|
||||
|
@ -5642,8 +5626,8 @@ All branches in an `if` must have the same type!
|
|||
|
||||
Num.sin
|
||||
Num.div
|
||||
Num.abs
|
||||
Num.neg
|
||||
Num.min
|
||||
Num.e
|
||||
"###
|
||||
);
|
||||
|
||||
|
@ -5938,6 +5922,40 @@ In roc, functions are always written as a lambda, like{}
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_provides_in_app_header() {
|
||||
report_header_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
app "broken"
|
||||
packages {
|
||||
pf: "https://github.com/roc-lang/basic-cli/releases/download/0.3.2/tE4xS_zLdmmxmHwHih9kHWQ7fsXtJr7W7h3425-eZFk.tar.br",
|
||||
}
|
||||
imports [
|
||||
pf.Stdout,
|
||||
]
|
||||
|
||||
main =
|
||||
Stdout.line "answer"
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── WEIRD PROVIDES ──────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
I am partway through parsing a header, but I got stuck here:
|
||||
|
||||
7│ ]
|
||||
^
|
||||
|
||||
I am expecting the `provides` keyword next, like
|
||||
|
||||
provides [Animal, default, tame]
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn platform_requires_rigids() {
|
||||
report_header_problem_as(
|
||||
|
@ -10304,7 +10322,7 @@ In roc, functions are always written as a lambda, like{}
|
|||
optional_field_in_record_builder,
|
||||
indoc!(
|
||||
r#"
|
||||
{
|
||||
{
|
||||
a: <- apply "a",
|
||||
b,
|
||||
c ? "optional"
|
||||
|
@ -10320,7 +10338,7 @@ In roc, functions are always written as a lambda, like{}
|
|||
1│ app "test" provides [main] to "./platform"
|
||||
2│
|
||||
3│ main =
|
||||
4│ {
|
||||
4│ {
|
||||
5│ a: <- apply "a",
|
||||
6│ b,
|
||||
7│ c ? "optional"
|
||||
|
@ -10409,7 +10427,7 @@ In roc, functions are always written as a lambda, like{}
|
|||
r#"
|
||||
succeed = \_ -> crash ""
|
||||
|
||||
succeed {
|
||||
succeed {
|
||||
a: <- "a",
|
||||
}
|
||||
"#
|
||||
|
@ -13847,4 +13865,44 @@ In roc, functions are always written as a lambda, like{}
|
|||
Tip: It looks like it takes too many arguments. I'm seeing 1 extra.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
pizza_parens_right,
|
||||
indoc!(
|
||||
r#"
|
||||
2 |> (Num.sub 3)
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── TOO FEW ARGS ────────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
The `sub` function expects 2 arguments, but it got only 1:
|
||||
|
||||
4│ 2 |> (Num.sub 3)
|
||||
^^^^^^^
|
||||
|
||||
Roc does not allow functions to be partially applied. Use a closure to
|
||||
make partial application explicit.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
pizza_parens_middle,
|
||||
indoc!(
|
||||
r#"
|
||||
2 |> (Num.sub 3) |> Num.sub 3
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── TOO FEW ARGS ────────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
The `sub` function expects 2 arguments, but it got only 1:
|
||||
|
||||
4│ 2 |> (Num.sub 3) |> Num.sub 3
|
||||
^^^^^^^
|
||||
|
||||
Roc does not allow functions to be partially applied. Use a closure to
|
||||
make partial application explicit.
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue