mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Merge branch 'trunk' into edit_big_string
This commit is contained in:
commit
a1a08fbb8a
20 changed files with 1841 additions and 49 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3060,6 +3060,7 @@ dependencies = [
|
||||||
"roc_reporting",
|
"roc_reporting",
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
|
"roc_unify",
|
||||||
"ropey",
|
"ropey",
|
||||||
"serde",
|
"serde",
|
||||||
"snafu",
|
"snafu",
|
||||||
|
|
|
@ -89,4 +89,16 @@ impl<T> Expected<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn replace_ref<U>(&self, new: U) -> Expected<U> {
|
||||||
|
match self {
|
||||||
|
Expected::NoExpectation(_val) => Expected::NoExpectation(new),
|
||||||
|
Expected::ForReason(reason, _val, region) => {
|
||||||
|
Expected::ForReason(reason.clone(), new, *region)
|
||||||
|
}
|
||||||
|
Expected::FromAnnotation(pattern, size, source, _val) => {
|
||||||
|
Expected::FromAnnotation(pattern.clone(), *size, *source, new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,6 +409,18 @@ pub fn canonicalize_expr<'a>(
|
||||||
ast::Expr::Var { module_name, ident } => {
|
ast::Expr::Var { module_name, ident } => {
|
||||||
canonicalize_lookup(env, scope, module_name, ident, region)
|
canonicalize_lookup(env, scope, module_name, ident, region)
|
||||||
}
|
}
|
||||||
|
ast::Expr::Underscore(name) => {
|
||||||
|
// we parse underscores, but they are not valid expression syntax
|
||||||
|
let problem = roc_problem::can::RuntimeError::MalformedIdentifier(
|
||||||
|
(*name).into(),
|
||||||
|
roc_parse::ident::BadIdent::Underscore(region.start_line, region.start_col),
|
||||||
|
region,
|
||||||
|
);
|
||||||
|
|
||||||
|
env.problem(Problem::RuntimeError(problem.clone()));
|
||||||
|
|
||||||
|
(RuntimeError(problem), Output::default())
|
||||||
|
}
|
||||||
ast::Expr::Defs(loc_defs, loc_ret) => {
|
ast::Expr::Defs(loc_defs, loc_ret) => {
|
||||||
can_defs_with_return(
|
can_defs_with_return(
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -119,6 +119,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
|
||||||
| Str(_)
|
| Str(_)
|
||||||
| AccessorFunction(_)
|
| AccessorFunction(_)
|
||||||
| Var { .. }
|
| Var { .. }
|
||||||
|
| Underscore { .. }
|
||||||
| MalformedIdent(_, _)
|
| MalformedIdent(_, _)
|
||||||
| MalformedClosure
|
| MalformedClosure
|
||||||
| PrecedenceConflict { .. }
|
| PrecedenceConflict { .. }
|
||||||
|
|
|
@ -198,7 +198,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
|
|
||||||
Underscore(_) => match pattern_type {
|
Underscore(_) => match pattern_type {
|
||||||
WhenBranch | FunctionArg => Pattern::Underscore,
|
WhenBranch | FunctionArg => Pattern::Underscore,
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
TopLevelDef | DefExpr => bad_underscore(env, region),
|
||||||
},
|
},
|
||||||
|
|
||||||
NumLiteral(string) => match pattern_type {
|
NumLiteral(string) => match pattern_type {
|
||||||
|
@ -402,7 +402,21 @@ pub fn canonicalize_pattern<'a>(
|
||||||
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
||||||
/// assign to Int patterns), report it to Env and return an UnsupportedPattern runtime error pattern.
|
/// assign to Int patterns), report it to Env and return an UnsupportedPattern runtime error pattern.
|
||||||
fn unsupported_pattern(env: &mut Env, pattern_type: PatternType, region: Region) -> Pattern {
|
fn unsupported_pattern(env: &mut Env, pattern_type: PatternType, region: Region) -> Pattern {
|
||||||
env.problem(Problem::UnsupportedPattern(pattern_type, region));
|
use roc_problem::can::BadPattern;
|
||||||
|
env.problem(Problem::UnsupportedPattern(
|
||||||
|
BadPattern::Unsupported(pattern_type),
|
||||||
|
region,
|
||||||
|
));
|
||||||
|
|
||||||
|
Pattern::UnsupportedPattern(region)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad_underscore(env: &mut Env, region: Region) -> Pattern {
|
||||||
|
use roc_problem::can::BadPattern;
|
||||||
|
env.problem(Problem::UnsupportedPattern(
|
||||||
|
BadPattern::UnderscoreInDef,
|
||||||
|
region,
|
||||||
|
));
|
||||||
|
|
||||||
Pattern::UnsupportedPattern(region)
|
Pattern::UnsupportedPattern(region)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
||||||
| Access(_, _)
|
| Access(_, _)
|
||||||
| AccessorFunction(_)
|
| AccessorFunction(_)
|
||||||
| Var { .. }
|
| Var { .. }
|
||||||
|
| Underscore { .. }
|
||||||
| MalformedIdent(_, _)
|
| MalformedIdent(_, _)
|
||||||
| MalformedClosure
|
| MalformedClosure
|
||||||
| GlobalTag(_)
|
| GlobalTag(_)
|
||||||
|
@ -189,6 +190,10 @@ impl<'a> Formattable<'a> for Expr<'a> {
|
||||||
|
|
||||||
buf.push_str(ident);
|
buf.push_str(ident);
|
||||||
}
|
}
|
||||||
|
Underscore(name) => {
|
||||||
|
buf.push('_');
|
||||||
|
buf.push_str(name);
|
||||||
|
}
|
||||||
Apply(loc_expr, loc_args, _) => {
|
Apply(loc_expr, loc_args, _) => {
|
||||||
if apply_needs_parens {
|
if apply_needs_parens {
|
||||||
buf.push('(');
|
buf.push('(');
|
||||||
|
|
|
@ -115,6 +115,8 @@ pub enum Expr<'a> {
|
||||||
ident: &'a str,
|
ident: &'a str,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Underscore(&'a str),
|
||||||
|
|
||||||
// Tags
|
// Tags
|
||||||
GlobalTag(&'a str),
|
GlobalTag(&'a str),
|
||||||
PrivateTag(&'a str),
|
PrivateTag(&'a str),
|
||||||
|
|
|
@ -192,6 +192,30 @@ fn record_field_access<'a>() -> impl Parser<'a, &'a str, EExpr<'a>> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// In some contexts we want to parse the `_` as an expression, so it can then be turned into a
|
||||||
|
/// pattern later
|
||||||
|
fn parse_loc_term_or_underscore<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
options: ExprParseOptions,
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
) -> ParseResult<'a, Located<Expr<'a>>, EExpr<'a>> {
|
||||||
|
one_of!(
|
||||||
|
loc_expr_in_parens_etc_help(min_indent),
|
||||||
|
loc!(specialize(EExpr::Str, string_literal_help())),
|
||||||
|
loc!(specialize(EExpr::Number, positive_number_literal_help())),
|
||||||
|
loc!(specialize(EExpr::Lambda, closure_help(min_indent, options))),
|
||||||
|
loc!(underscore_expression()),
|
||||||
|
loc!(record_literal_help(min_indent)),
|
||||||
|
loc!(specialize(EExpr::List, list_literal_help(min_indent))),
|
||||||
|
loc!(map_with_arena!(
|
||||||
|
assign_or_destructure_identifier(),
|
||||||
|
ident_to_expr
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.parse(arena, state)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_loc_term<'a>(
|
fn parse_loc_term<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
options: ExprParseOptions,
|
options: ExprParseOptions,
|
||||||
|
@ -213,6 +237,26 @@ fn parse_loc_term<'a>(
|
||||||
.parse(arena, state)
|
.parse(arena, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn underscore_expression<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||||
|
move |arena: &'a Bump, state: State<'a>| {
|
||||||
|
let (_, _, next_state) = word1(b'_', EExpr::Underscore).parse(arena, state)?;
|
||||||
|
|
||||||
|
let lowercase_ident_expr = {
|
||||||
|
let row = state.line;
|
||||||
|
let col = state.column;
|
||||||
|
|
||||||
|
specialize(move |_, _, _| EExpr::End(row, col), lowercase_ident())
|
||||||
|
};
|
||||||
|
|
||||||
|
let (_, output, final_state) = optional(lowercase_ident_expr).parse(arena, next_state)?;
|
||||||
|
|
||||||
|
match output {
|
||||||
|
Some(name) => Ok((MadeProgress, Expr::Underscore(name), final_state)),
|
||||||
|
None => Ok((MadeProgress, Expr::Underscore(&""), final_state)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn loc_possibly_negative_or_negated_term<'a>(
|
fn loc_possibly_negative_or_negated_term<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
options: ExprParseOptions,
|
options: ExprParseOptions,
|
||||||
|
@ -243,10 +287,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
|arena, state| {
|
|arena, state| { parse_loc_term_or_underscore(min_indent, options, arena, state) }
|
||||||
// TODO use parse_loc_term_better
|
|
||||||
parse_loc_term(min_indent, options, arena, state)
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1316,6 +1357,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
||||||
Ok(Pattern::QualifiedIdentifier { module_name, ident })
|
Ok(Pattern::QualifiedIdentifier { module_name, ident })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::Underscore(opt_name) => Ok(Pattern::Underscore(opt_name)),
|
||||||
Expr::GlobalTag(value) => Ok(Pattern::GlobalTag(value)),
|
Expr::GlobalTag(value) => Ok(Pattern::GlobalTag(value)),
|
||||||
Expr::PrivateTag(value) => Ok(Pattern::PrivateTag(value)),
|
Expr::PrivateTag(value) => Ok(Pattern::PrivateTag(value)),
|
||||||
Expr::Apply(loc_val, loc_args, _) => {
|
Expr::Apply(loc_val, loc_args, _) => {
|
||||||
|
|
|
@ -411,6 +411,7 @@ pub enum EExpr<'a> {
|
||||||
If(If<'a>, Row, Col),
|
If(If<'a>, Row, Col),
|
||||||
|
|
||||||
Lambda(ELambda<'a>, Row, Col),
|
Lambda(ELambda<'a>, Row, Col),
|
||||||
|
Underscore(Row, Col),
|
||||||
|
|
||||||
InParens(EInParens<'a>, Row, Col),
|
InParens(EInParens<'a>, Row, Col),
|
||||||
Record(ERecord<'a>, Row, Col),
|
Record(ERecord<'a>, Row, Col),
|
||||||
|
|
|
@ -1573,7 +1573,7 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn single_underscore_closure() {
|
fn single_underscore_closure() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let pattern = Located::new(0, 0, 1, 2, Underscore(&""));
|
let pattern = Located::new(0, 0, 1, 2, Pattern::Underscore(&""));
|
||||||
let patterns = &[pattern];
|
let patterns = &[pattern];
|
||||||
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42"))));
|
let expected = Closure(patterns, arena.alloc(Located::new(0, 0, 6, 8, Num("42"))));
|
||||||
let actual = parse_expr_with(&arena, "\\_ -> 42");
|
let actual = parse_expr_with(&arena, "\\_ -> 42");
|
||||||
|
@ -1635,8 +1635,8 @@ mod test_parse {
|
||||||
#[test]
|
#[test]
|
||||||
fn closure_with_underscores() {
|
fn closure_with_underscores() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let underscore1 = Located::new(0, 0, 1, 2, Underscore(&""));
|
let underscore1 = Located::new(0, 0, 1, 2, Pattern::Underscore(&""));
|
||||||
let underscore2 = Located::new(0, 0, 4, 9, Underscore(&"name"));
|
let underscore2 = Located::new(0, 0, 4, 9, Pattern::Underscore(&"name"));
|
||||||
let patterns = bumpalo::vec![in &arena; underscore1, underscore2];
|
let patterns = bumpalo::vec![in &arena; underscore1, underscore2];
|
||||||
let expected = Closure(
|
let expected = Closure(
|
||||||
arena.alloc(patterns),
|
arena.alloc(patterns),
|
||||||
|
@ -1866,6 +1866,49 @@ mod test_parse {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn underscore_backpassing() {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
||||||
|
let underscore = Located::new(1, 1, 0, 1, Pattern::Underscore(&""));
|
||||||
|
let identifier_y = Located::new(1, 1, 7, 8, Identifier("y"));
|
||||||
|
|
||||||
|
let num_4 = Num("4");
|
||||||
|
|
||||||
|
let var_y = Var {
|
||||||
|
module_name: "",
|
||||||
|
ident: "y",
|
||||||
|
};
|
||||||
|
let loc_var_y = arena.alloc(Located::new(1, 1, 12, 13, var_y));
|
||||||
|
|
||||||
|
let closure = ParensAround(arena.alloc(Closure(arena.alloc([identifier_y]), loc_var_y)));
|
||||||
|
let loc_closure = Located::new(1, 1, 5, 14, closure);
|
||||||
|
|
||||||
|
let ret = Expr::SpaceBefore(arena.alloc(num_4), newlines.into_bump_slice());
|
||||||
|
let loc_ret = Located::new(3, 3, 0, 1, ret);
|
||||||
|
|
||||||
|
let reset_indentation = bumpalo::vec![in &arena; LineComment(" leading comment")];
|
||||||
|
let expected = Expr::SpaceBefore(
|
||||||
|
arena.alloc(Expr::Backpassing(
|
||||||
|
arena.alloc([underscore]),
|
||||||
|
arena.alloc(loc_closure),
|
||||||
|
arena.alloc(loc_ret),
|
||||||
|
)),
|
||||||
|
reset_indentation.into_bump_slice(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_parses_to(
|
||||||
|
indoc!(
|
||||||
|
r#"# leading comment
|
||||||
|
_ <- (\y -> y)
|
||||||
|
|
||||||
|
4
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
expected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn two_backpassing() {
|
fn two_backpassing() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
|
@ -2624,7 +2667,7 @@ mod test_parse {
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = &[Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore("")), newlines);
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), newlines);
|
||||||
let loc_pattern2 = Located::new(3, 3, 4, 5, pattern2);
|
let loc_pattern2 = Located::new(3, 3, 4, 5, pattern2);
|
||||||
let expr2 = Num("4");
|
let expr2 = Num("4");
|
||||||
let loc_expr2 = Located::new(3, 3, 9, 10, expr2);
|
let loc_expr2 = Located::new(3, 3, 9, 10, expr2);
|
||||||
|
@ -2661,7 +2704,7 @@ mod test_parse {
|
||||||
|
|
||||||
let branch1 = {
|
let branch1 = {
|
||||||
let newlines = &[Newline];
|
let newlines = &[Newline];
|
||||||
let pattern1 = Pattern::SpaceBefore(arena.alloc(Underscore("")), newlines);
|
let pattern1 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), newlines);
|
||||||
let loc_pattern1 = Located::new(1, 1, 4, 5, pattern1);
|
let loc_pattern1 = Located::new(1, 1, 4, 5, pattern1);
|
||||||
let num_1 = Num("1");
|
let num_1 = Num("1");
|
||||||
let expr1 = Located::new(
|
let expr1 = Located::new(
|
||||||
|
@ -2680,7 +2723,8 @@ mod test_parse {
|
||||||
};
|
};
|
||||||
|
|
||||||
let branch2 = {
|
let branch2 = {
|
||||||
let pattern1 = Pattern::SpaceBefore(arena.alloc(Underscore("")), &[Newline, Newline]);
|
let pattern1 =
|
||||||
|
Pattern::SpaceBefore(arena.alloc(Pattern::Underscore("")), &[Newline, Newline]);
|
||||||
let loc_pattern1 = Located::new(4, 4, 4, 5, pattern1);
|
let loc_pattern1 = Located::new(4, 4, 4, 5, pattern1);
|
||||||
let num_1 = Num("2");
|
let num_1 = Num("2");
|
||||||
let expr1 = Located::new(
|
let expr1 = Located::new(
|
||||||
|
@ -3576,7 +3620,7 @@ mod test_parse {
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = &[Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore(&"")), newlines);
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore(&"")), newlines);
|
||||||
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
||||||
let expr2 = Num("4");
|
let expr2 = Num("4");
|
||||||
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
||||||
|
@ -3621,7 +3665,7 @@ mod test_parse {
|
||||||
guard: None,
|
guard: None,
|
||||||
});
|
});
|
||||||
let newlines = &[Newline];
|
let newlines = &[Newline];
|
||||||
let pattern2 = Pattern::SpaceBefore(arena.alloc(Underscore(&"")), newlines);
|
let pattern2 = Pattern::SpaceBefore(arena.alloc(Pattern::Underscore(&"")), newlines);
|
||||||
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
let loc_pattern2 = Located::new(2, 2, 4, 5, pattern2);
|
||||||
let expr2 = Num("4");
|
let expr2 = Num("4");
|
||||||
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
let loc_expr2 = Located::new(2, 2, 9, 10, expr2);
|
||||||
|
|
|
@ -14,6 +14,12 @@ pub struct CycleEntry {
|
||||||
pub expr_region: Region,
|
pub expr_region: Region,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum BadPattern {
|
||||||
|
UnderscoreInDef,
|
||||||
|
Unsupported(PatternType),
|
||||||
|
}
|
||||||
|
|
||||||
/// Problems that can occur in the course of canonicalization.
|
/// Problems that can occur in the course of canonicalization.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Problem {
|
pub enum Problem {
|
||||||
|
@ -25,7 +31,7 @@ pub enum Problem {
|
||||||
UnusedArgument(Symbol, Symbol, Region),
|
UnusedArgument(Symbol, Symbol, Region),
|
||||||
PrecedenceProblem(PrecedenceProblem),
|
PrecedenceProblem(PrecedenceProblem),
|
||||||
// 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(PatternType, Region),
|
UnsupportedPattern(BadPattern, Region),
|
||||||
ShadowingInAnnotation {
|
ShadowingInAnnotation {
|
||||||
original_region: Region,
|
original_region: Region,
|
||||||
shadow: Located<Ident>,
|
shadow: Located<Ident>,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use roc_collections::all::MutSet;
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_parse::parser::{Col, Row};
|
use roc_parse::parser::{Col, Row};
|
||||||
use roc_problem::can::PrecedenceProblem::BothNonAssociative;
|
use roc_problem::can::PrecedenceProblem::BothNonAssociative;
|
||||||
use roc_problem::can::{FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
use roc_problem::can::{BadPattern, FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -103,7 +103,11 @@ pub fn can_problem<'b>(
|
||||||
},
|
},
|
||||||
alloc.region(region),
|
alloc.region(region),
|
||||||
]),
|
]),
|
||||||
Problem::UnsupportedPattern(pattern_type, region) => {
|
Problem::UnsupportedPattern(BadPattern::UnderscoreInDef, region) => alloc.stack(vec![
|
||||||
|
alloc.reflow("Underscore patterns are not allowed in definitions"),
|
||||||
|
alloc.region(region),
|
||||||
|
]),
|
||||||
|
Problem::UnsupportedPattern(BadPattern::Unsupported(pattern_type), region) => {
|
||||||
use roc_parse::pattern::PatternType::*;
|
use roc_parse::pattern::PatternType::*;
|
||||||
|
|
||||||
let this_thing = match pattern_type {
|
let this_thing = match pattern_type {
|
||||||
|
|
|
@ -6334,4 +6334,27 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn underscore_let() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
_ = 3
|
||||||
|
|
||||||
|
4
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
Underscore patterns are not allowed in definitions
|
||||||
|
|
||||||
|
1│ _ = 3
|
||||||
|
^
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -858,7 +858,7 @@ pub enum PReason {
|
||||||
OptionalField,
|
OptionalField,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum AnnotationSource {
|
pub enum AnnotationSource {
|
||||||
TypedIfBranch { index: Index, num_branches: usize },
|
TypedIfBranch { index: Index, num_branches: usize },
|
||||||
TypedWhenBranch { index: Index },
|
TypedWhenBranch { index: Index },
|
||||||
|
|
|
@ -15,6 +15,7 @@ roc_region = { path = "../compiler/region" }
|
||||||
roc_module = { path = "../compiler/module" }
|
roc_module = { path = "../compiler/module" }
|
||||||
roc_problem = { path = "../compiler/problem" }
|
roc_problem = { path = "../compiler/problem" }
|
||||||
roc_types = { path = "../compiler/types" }
|
roc_types = { path = "../compiler/types" }
|
||||||
|
roc_unify = { path = "../compiler/unify" }
|
||||||
roc_fmt = { path = "../compiler/fmt" }
|
roc_fmt = { path = "../compiler/fmt" }
|
||||||
roc_reporting = { path = "../compiler/reporting" }
|
roc_reporting = { path = "../compiler/reporting" }
|
||||||
roc_solve = { path = "../compiler/solve" }
|
roc_solve = { path = "../compiler/solve" }
|
||||||
|
|
|
@ -7,4 +7,5 @@ mod pattern;
|
||||||
pub mod pool;
|
pub mod pool;
|
||||||
pub mod roc_file;
|
pub mod roc_file;
|
||||||
pub mod scope;
|
pub mod scope;
|
||||||
|
pub mod solve;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
|
@ -153,7 +153,7 @@ pub fn to_pattern2<'a>(
|
||||||
|
|
||||||
Underscore(_) => match pattern_type {
|
Underscore(_) => match pattern_type {
|
||||||
WhenBranch | FunctionArg => Pattern2::Underscore,
|
WhenBranch | FunctionArg => Pattern2::Underscore,
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
TopLevelDef | DefExpr => underscore_in_def(env, region),
|
||||||
},
|
},
|
||||||
|
|
||||||
FloatLiteral(ref string) => match pattern_type {
|
FloatLiteral(ref string) => match pattern_type {
|
||||||
|
@ -521,7 +521,21 @@ fn unsupported_pattern<'a>(
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
region: Region,
|
region: Region,
|
||||||
) -> Pattern2 {
|
) -> Pattern2 {
|
||||||
env.problem(Problem::UnsupportedPattern(pattern_type, region));
|
use roc_problem::can::BadPattern;
|
||||||
|
env.problem(Problem::UnsupportedPattern(
|
||||||
|
BadPattern::Unsupported(pattern_type),
|
||||||
|
region,
|
||||||
|
));
|
||||||
|
|
||||||
|
Pattern2::UnsupportedPattern(region)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn underscore_in_def<'a>(env: &mut Env<'a>, region: Region) -> Pattern2 {
|
||||||
|
use roc_problem::can::BadPattern;
|
||||||
|
env.problem(Problem::UnsupportedPattern(
|
||||||
|
BadPattern::UnderscoreInDef,
|
||||||
|
region,
|
||||||
|
));
|
||||||
|
|
||||||
Pattern2::UnsupportedPattern(region)
|
Pattern2::UnsupportedPattern(region)
|
||||||
}
|
}
|
||||||
|
|
1595
editor/src/lang/solve.rs
Normal file
1595
editor/src/lang/solve.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,45 +5,50 @@ extern crate indoc;
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_can::expected::Expected;
|
use roc_can::expected::Expected;
|
||||||
|
use roc_collections::all::MutMap;
|
||||||
|
use roc_editor::lang::solve;
|
||||||
use roc_editor::lang::{
|
use roc_editor::lang::{
|
||||||
constrain::constrain_expr,
|
constrain::constrain_expr,
|
||||||
|
constrain::Constraint,
|
||||||
expr::{str_to_expr2, Env},
|
expr::{str_to_expr2, Env},
|
||||||
pool::Pool,
|
pool::Pool,
|
||||||
scope::Scope,
|
scope::Scope,
|
||||||
types::Type2,
|
types::Type2,
|
||||||
};
|
};
|
||||||
|
use roc_module::ident::Lowercase;
|
||||||
|
use roc_module::symbol::Symbol;
|
||||||
use roc_module::symbol::{IdentIds, ModuleIds};
|
use roc_module::symbol::{IdentIds, ModuleIds};
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
use roc_solve::module::run_solve;
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::{pretty_print::content_to_string, subs::VarStore, types::Type};
|
use roc_types::subs::{Subs, Variable};
|
||||||
|
use roc_types::{pretty_print::content_to_string, subs::VarStore};
|
||||||
|
|
||||||
fn ed_constraint_to_can_constraint(
|
fn run_solve(
|
||||||
constraint: roc_editor::lang::constrain::Constraint,
|
mempool: &mut Pool,
|
||||||
) -> roc_can::constraint::Constraint {
|
aliases: MutMap<Symbol, roc_types::types::Alias>,
|
||||||
match constraint {
|
rigid_variables: MutMap<Variable, Lowercase>,
|
||||||
roc_editor::lang::constrain::Constraint::Eq(typ, expected, category, region) => {
|
constraint: Constraint,
|
||||||
let new_typ = type2_to_type(&typ);
|
var_store: VarStore,
|
||||||
let expected_typ = expected.get_type_ref();
|
) -> (Solved<Subs>, solve::Env, Vec<solve::TypeError>) {
|
||||||
|
let env = solve::Env {
|
||||||
|
vars_by_symbol: MutMap::default(),
|
||||||
|
aliases,
|
||||||
|
};
|
||||||
|
|
||||||
let expected_typ = type2_to_type(expected_typ);
|
let mut subs = Subs::new(var_store.into());
|
||||||
|
|
||||||
roc_can::constraint::Constraint::Eq(
|
for (var, name) in rigid_variables {
|
||||||
new_typ,
|
subs.rigid_var(var, name);
|
||||||
expected.replace(expected_typ),
|
|
||||||
category,
|
|
||||||
region,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => todo!("{:?}", constraint),
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn type2_to_type(typ: &Type2) -> Type {
|
// Now that the module is parsed, canonicalized, and constrained,
|
||||||
match typ {
|
// we need to type check it.
|
||||||
Type2::Apply(symbol, _) => Type::Apply(*symbol, Vec::new()),
|
let mut problems = Vec::new();
|
||||||
Type2::Variable(var) => Type::Variable(*var),
|
|
||||||
_ => todo!("{:?}", typ),
|
// Run the solver to populate Subs.
|
||||||
}
|
let (solved_subs, solved_env) = solve::run(mempool, &env, &mut problems, subs, &constraint);
|
||||||
|
|
||||||
|
(solved_subs, solved_env, problems)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_eq(actual: &str, expected_str: &str) {
|
fn infer_eq(actual: &str, expected_str: &str) {
|
||||||
|
@ -83,20 +88,29 @@ fn infer_eq(actual: &str, expected_str: &str) {
|
||||||
Expected::NoExpectation(Type2::Variable(var)),
|
Expected::NoExpectation(Type2::Variable(var)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let constraint = ed_constraint_to_can_constraint(constraint);
|
let Env {
|
||||||
|
pool,
|
||||||
|
var_store: ref_var_store,
|
||||||
|
..
|
||||||
|
} = env;
|
||||||
|
|
||||||
|
// extract the var_store out of the env again
|
||||||
|
let mut var_store = VarStore::default();
|
||||||
|
std::mem::swap(ref_var_store, &mut var_store);
|
||||||
|
|
||||||
let (mut solved, _, _) = run_solve(
|
let (mut solved, _, _) = run_solve(
|
||||||
|
pool,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
constraint,
|
constraint,
|
||||||
var_store,
|
var_store,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut subs = solved.inner_mut();
|
let subs = solved.inner_mut();
|
||||||
|
|
||||||
let content = subs.get(var).content;
|
let content = subs.get(var).content;
|
||||||
|
|
||||||
let actual_str = content_to_string(content, &mut subs, mod_id, &Default::default());
|
let actual_str = content_to_string(content, &subs, mod_id, &Default::default());
|
||||||
|
|
||||||
assert_eq!(actual_str, expected_str);
|
assert_eq!(actual_str, expected_str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ app "http-get"
|
||||||
|
|
||||||
main : Task.Task {} *
|
main : Task.Task {} *
|
||||||
main =
|
main =
|
||||||
{} <- await (Stdout.line "What URL should I get?")
|
_ <- await (Stdout.line "What URL should I get?")
|
||||||
|
|
||||||
url <- await Stdin.line
|
url <- await Stdin.line
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue