make List.first/List.last work

This commit is contained in:
Folkert 2020-12-24 01:00:37 +01:00
parent 679ef168b1
commit 917ec9c44c
4 changed files with 51 additions and 10 deletions

View file

@ -292,13 +292,16 @@ mod repl_eval {
expect_success("List.sum [ 1.1, 2.2, 3.3 ]", "6.6 : F64"); expect_success("List.sum [ 1.1, 2.2, 3.3 ]", "6.6 : F64");
} }
// TODO add test cases for empty lists once error messages in the repl are correct
#[test] #[test]
fn list_first() { fn list_first() {
expect_success( expect_success(
"List.first [ 12, 9, 6, 3 ]", "List.first [ 12, 9, 6, 3 ]",
"Ok 12 : Result (Num *) [ ListWasEmpty ]*", "Ok 12 : Result (Num *) [ ListWasEmpty ]*",
); );
expect_success(
"List.first []",
"Err (ListWasEmpty) : Result * [ ListWasEmpty ]*",
);
} }
#[test] #[test]
@ -307,6 +310,11 @@ mod repl_eval {
"List.last [ 12, 9, 6, 3 ]", "List.last [ 12, 9, 6, 3 ]",
"Ok 3 : Result (Num *) [ ListWasEmpty ]*", "Ok 3 : Result (Num *) [ ListWasEmpty ]*",
); );
expect_success(
"List.last []",
"Err (ListWasEmpty) : Result * [ ListWasEmpty ]*",
);
} }
#[test] #[test]

View file

@ -2585,13 +2585,23 @@ pub fn with_hole<'a>(
let mut field_symbols_temp = Vec::with_capacity_in(args.len(), env.arena); let mut field_symbols_temp = Vec::with_capacity_in(args.len(), env.arena);
for (var, arg) in args.drain(..) { for (var, mut arg) in args.drain(..) {
// Layout will unpack this unwrapped tack if it only has one (non-zero-sized) field // Layout will unpack this unwrapped tack if it only has one (non-zero-sized) field
let layout = layout_cache let layout = match layout_cache.from_var(env.arena, var, env.subs) {
.from_var(env.arena, var, env.subs) Ok(cached) => cached,
.unwrap_or_else(|err| { Err(LayoutProblem::UnresolvedTypeVar(_)) => {
panic!("TODO turn fn_var into a RuntimeError {:?}", err) // this argument has type `forall a. a`, which is isomorphic to
}); // the empty type (Void, Never, the empty tag union `[]`)
use roc_can::expr::Expr;
use roc_problem::can::RuntimeError;
arg.value = Expr::RuntimeError(RuntimeError::VoidValue);
Layout::Struct(&[])
}
Err(LayoutProblem::Erroneous) => {
// something went very wrong
panic!("TODO turn fn_var into a RuntimeError")
}
};
let alignment = layout.alignment_bytes(8); let alignment = layout.alignment_bytes(8);
@ -3575,9 +3585,23 @@ pub fn with_hole<'a>(
let arg_symbols = arg_symbols.into_bump_slice(); let arg_symbols = arg_symbols.into_bump_slice();
// layout of the return type // layout of the return type
let layout = layout_cache let layout = match layout_cache.from_var(env.arena, ret_var, env.subs) {
.from_var(env.arena, ret_var, env.subs) Ok(cached) => cached,
.unwrap_or_else(|err| todo!("TODO turn fn_var into a RuntimeError {:?}", err)); Err(LayoutProblem::UnresolvedTypeVar(_)) => {
return Stmt::RuntimeError(env.arena.alloc(format!(
"UnresolvedTypeVar {} line {}",
file!(),
line!()
)));
}
Err(LayoutProblem::Erroneous) => {
return Stmt::RuntimeError(env.arena.alloc(format!(
"Erroneous {} line {}",
file!(),
line!()
)));
}
};
let result = Stmt::Let(assigned, Expr::RunLowLevel(op, arg_symbols), layout, hole); let result = Stmt::Let(assigned, Expr::RunLowLevel(op, arg_symbols), layout, hole);

View file

@ -147,6 +147,9 @@ pub enum RuntimeError {
/// When the author specifies a type annotation but no implementation /// When the author specifies a type annotation but no implementation
NoImplementation, NoImplementation,
/// cases where the `[]` value (or equivalently, `forall a. a`) pops up
VoidValue,
ExposedButNotDefined(Symbol), ExposedButNotDefined(Symbol),
} }

View file

@ -338,6 +338,12 @@ fn pretty_runtime_error<'b>(
runtime_error: RuntimeError, runtime_error: RuntimeError,
) -> RocDocBuilder<'b> { ) -> RocDocBuilder<'b> {
match runtime_error { match runtime_error {
RuntimeError::VoidValue => {
// is used to communicate to the compiler that
// a branch is unreachable; this should never reach a user
unreachable!("")
}
RuntimeError::Shadowing { RuntimeError::Shadowing {
original_region, original_region,
shadow, shadow,