Merge remote-tracking branch 'origin/main' into abilities-syntax

This commit is contained in:
Richard Feldman 2023-08-10 20:29:27 -04:00
commit 2da41be29f
No known key found for this signature in database
GPG key ID: F1F21AA5B1D9E43B
524 changed files with 47536 additions and 15089 deletions

View file

@ -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");
}
}

View file

@ -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();
}

View file

@ -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}")
}
}

View file

@ -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));

View file

@ -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);

View file

@ -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),

View file

@ -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);

View file

@ -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.
"###
);
}