mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Merge pull request #2722 from rtfeldman/various-bug-fixes
Various recently filed bug fixes
This commit is contained in:
commit
422a88eced
8 changed files with 212 additions and 27 deletions
|
@ -504,12 +504,22 @@ pub fn constrain_pattern(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Link the entire wrapped opaque type (with the now-constrained argument) to the type
|
// Link the entire wrapped opaque type (with the now-constrained argument) to the type
|
||||||
// variables of the opaque type
|
// variables of the opaque type.
|
||||||
// TODO: better expectation here
|
//
|
||||||
let link_type_variables_con = constraints.equal_types(
|
// For example, suppose we have `O k := [ A k, B k ]`, and the pattern `@O (A s) -> s == ""`.
|
||||||
(**specialized_def_type).clone(),
|
// Previous constraints will have solved `typeof s ~ Str`, and we have the
|
||||||
Expected::NoExpectation(arg_pattern_type),
|
// `specialized_def_type` being `[ A k1, B k1 ]`, specializing `k` as `k1` for this opaque
|
||||||
Category::OpaqueWrap(*opaque),
|
// usage.
|
||||||
|
// We now want to link `typeof s ~ k1`, so to capture this relationship, we link
|
||||||
|
// the type of `A s` (the arg type) to `[ A k1, B k1 ]` (the specialized opaque type).
|
||||||
|
//
|
||||||
|
// This must **always** be a presence constraint, that is enforcing
|
||||||
|
// `[ A k1, B k1 ] += typeof (A s)`, because we are in a destructure position and not
|
||||||
|
// all constructors are covered in this branch!
|
||||||
|
let link_type_variables_con = constraints.pattern_presence(
|
||||||
|
arg_pattern_type,
|
||||||
|
PExpected::NoExpectation((**specialized_def_type).clone()),
|
||||||
|
PatternCategory::Opaque(*opaque),
|
||||||
loc_arg_pattern.region,
|
loc_arg_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -6558,7 +6558,13 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
|
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
|
||||||
NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
|
NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
|
||||||
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
|
NumLte => bd.build_int_compare(SLE, lhs, rhs, "int_lte").into(),
|
||||||
NumRemUnchecked => bd.build_int_signed_rem(lhs, rhs, "rem_int").into(),
|
NumRemUnchecked => {
|
||||||
|
if int_width.is_signed() {
|
||||||
|
bd.build_int_signed_rem(lhs, rhs, "rem_int").into()
|
||||||
|
} else {
|
||||||
|
bd.build_int_unsigned_rem(lhs, rhs, "rem_uint").into()
|
||||||
|
}
|
||||||
|
}
|
||||||
NumIsMultipleOf => {
|
NumIsMultipleOf => {
|
||||||
// this builds the following construct
|
// this builds the following construct
|
||||||
//
|
//
|
||||||
|
@ -6632,7 +6638,13 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
&bitcode::NUM_POW_INT[int_width],
|
&bitcode::NUM_POW_INT[int_width],
|
||||||
),
|
),
|
||||||
NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
|
NumDivUnchecked => {
|
||||||
|
if int_width.is_signed() {
|
||||||
|
bd.build_int_signed_div(lhs, rhs, "div_int").into()
|
||||||
|
} else {
|
||||||
|
bd.build_int_unsigned_div(lhs, rhs, "div_uint").into()
|
||||||
|
}
|
||||||
|
}
|
||||||
NumDivCeilUnchecked => call_bitcode_fn(
|
NumDivCeilUnchecked => call_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
|
|
|
@ -5573,4 +5573,57 @@ mod solve_expr {
|
||||||
r#"[ A, B, C ]"#,
|
r#"[ A, B, C ]"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// https://github.com/rtfeldman/roc/issues/2702
|
||||||
|
fn tag_inclusion_behind_opaque() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Outer k := [ Empty, Wrapped k ]
|
||||||
|
|
||||||
|
insert : Outer k, k -> Outer k
|
||||||
|
insert = \m, var ->
|
||||||
|
when m is
|
||||||
|
$Outer Empty -> $Outer (Wrapped var)
|
||||||
|
$Outer (Wrapped _) -> $Outer (Wrapped var)
|
||||||
|
|
||||||
|
insert
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"Outer k, k -> Outer k"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tag_inclusion_behind_opaque_infer() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Outer k := [ Empty, Wrapped k ]
|
||||||
|
|
||||||
|
when ($Outer Empty) is
|
||||||
|
$Outer Empty -> $Outer (Wrapped "")
|
||||||
|
$Outer (Wrapped k) -> $Outer (Wrapped k)
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"Outer Str"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tag_inclusion_behind_opaque_infer_single_ctor() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Outer := [ A, B ]
|
||||||
|
|
||||||
|
when ($Outer A) is
|
||||||
|
$Outer A -> $Outer A
|
||||||
|
$Outer B -> $Outer B
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"Outer"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2831,3 +2831,31 @@ fn upcast_of_int_checked_is_zext() {
|
||||||
u16
|
u16
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn modulo_of_unsigned() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
0b1111_1111u8 % 64
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
63,
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn div_of_unsigned() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
0b1111_1111u8 // 2
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
127,
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -180,10 +180,12 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
||||||
// println!("\n --------------- \n");
|
// println!("\n --------------- \n");
|
||||||
let content_1 = subs.get(ctx.first).content;
|
let content_1 = subs.get(ctx.first).content;
|
||||||
let content_2 = subs.get(ctx.second).content;
|
let content_2 = subs.get(ctx.second).content;
|
||||||
|
let mode = if ctx.mode.is_eq() { "~" } else { "+=" };
|
||||||
println!(
|
println!(
|
||||||
"{:?} {:?} ~ {:?} {:?}",
|
"{:?} {:?} {} {:?} {:?}",
|
||||||
ctx.first,
|
ctx.first,
|
||||||
roc_types::subs::SubsFmtContent(&content_1, subs),
|
roc_types::subs::SubsFmtContent(&content_1, subs),
|
||||||
|
mode,
|
||||||
ctx.second,
|
ctx.second,
|
||||||
roc_types::subs::SubsFmtContent(&content_2, subs),
|
roc_types::subs::SubsFmtContent(&content_2, subs),
|
||||||
);
|
);
|
||||||
|
@ -334,7 +336,13 @@ fn unify_alias(
|
||||||
problems.extend(merge(subs, ctx, *other_content));
|
problems.extend(merge(subs, ctx, *other_content));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if problems.is_empty() { problems.extend(unify_pool(subs, pool, real_var, *other_real_var)); }
|
// THEORY: if two aliases or opaques have the same name and arguments, their
|
||||||
|
// real_var is the same and we don't need to check it.
|
||||||
|
// See https://github.com/rtfeldman/roc/pull/1510
|
||||||
|
//
|
||||||
|
// if problems.is_empty() && either_is_opaque {
|
||||||
|
// problems.extend(unify_pool(subs, pool, real_var, *other_real_var, ctx.mode));
|
||||||
|
// }
|
||||||
|
|
||||||
problems
|
problems
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -281,7 +281,7 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||||
let (newtype_containers, content) = unroll_newtypes(env, content);
|
let (newtype_containers, content) = unroll_newtypes(env, content);
|
||||||
let content = unroll_aliases(env, content);
|
let content = unroll_aliases(env, content);
|
||||||
|
|
||||||
macro_rules! helper {
|
macro_rules! num_helper {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
app.call_function(main_fn_name, |_, num: $ty| {
|
app.call_function(main_fn_name, |_, num: $ty| {
|
||||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||||
|
@ -297,21 +297,24 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||||
use IntWidth::*;
|
use IntWidth::*;
|
||||||
|
|
||||||
let result = match int_width {
|
let result = match (content, int_width) {
|
||||||
U8 | I8 => {
|
(Content::Structure(FlatType::Apply(Symbol::NUM_NUM, _)), U8) => num_helper!(u8),
|
||||||
// NOTE: `helper!` does not handle 8-bit numbers yet
|
(_, U8) => {
|
||||||
|
// This is not a number, it's a tag union or something else
|
||||||
app.call_function(main_fn_name, |mem: &A::Memory, num: u8| {
|
app.call_function(main_fn_name, |mem: &A::Memory, num: u8| {
|
||||||
byte_to_ast(env, mem, num, content)
|
byte_to_ast(env, mem, num, content)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
U16 => helper!(u16),
|
// The rest are numbers... for now
|
||||||
U32 => helper!(u32),
|
(_, U16) => num_helper!(u16),
|
||||||
U64 => helper!(u64),
|
(_, U32) => num_helper!(u32),
|
||||||
U128 => helper!(u128),
|
(_, U64) => num_helper!(u64),
|
||||||
I16 => helper!(i16),
|
(_, U128) => num_helper!(u128),
|
||||||
I32 => helper!(i32),
|
(_, I8) => num_helper!(i8),
|
||||||
I64 => helper!(i64),
|
(_, I16) => num_helper!(i16),
|
||||||
I128 => helper!(i128),
|
(_, I32) => num_helper!(i32),
|
||||||
|
(_, I64) => num_helper!(i64),
|
||||||
|
(_, I128) => num_helper!(i128),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -320,14 +323,14 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||||
use FloatWidth::*;
|
use FloatWidth::*;
|
||||||
|
|
||||||
let result = match float_width {
|
let result = match float_width {
|
||||||
F32 => helper!(f32),
|
F32 => num_helper!(f32),
|
||||||
F64 => helper!(f64),
|
F64 => num_helper!(f64),
|
||||||
F128 => todo!("F128 not implemented"),
|
F128 => todo!("F128 not implemented"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Decimal) => Ok(helper!(RocDec)),
|
Layout::Builtin(Builtin::Decimal) => Ok(num_helper!(RocDec)),
|
||||||
Layout::Builtin(Builtin::Str) => {
|
Layout::Builtin(Builtin::Str) => {
|
||||||
let size = layout.stack_size(env.target_info) as usize;
|
let size = layout.stack_size(env.target_info) as usize;
|
||||||
Ok(
|
Ok(
|
||||||
|
@ -438,7 +441,16 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||||
unreachable!("RecursivePointers can only be inside structures")
|
unreachable!("RecursivePointers can only be inside structures")
|
||||||
}
|
}
|
||||||
Layout::LambdaSet(_) => Ok(OPAQUE_FUNCTION),
|
Layout::LambdaSet(_) => Ok(OPAQUE_FUNCTION),
|
||||||
Layout::Boxed(_inner) => todo!(),
|
Layout::Boxed(_) => {
|
||||||
|
let size = layout.stack_size(env.target_info);
|
||||||
|
Ok(app.call_function_dynamic_size(
|
||||||
|
main_fn_name,
|
||||||
|
size as usize,
|
||||||
|
|mem: &A::Memory, addr| {
|
||||||
|
addr_to_ast(env, mem, addr, layout, WhenRecursive::Unreachable, content)
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
result.map(|e| apply_newtypes(env, newtype_containers, e))
|
result.map(|e| apply_newtypes(env, newtype_containers, e))
|
||||||
}
|
}
|
||||||
|
@ -730,6 +742,25 @@ fn addr_to_ast<'a, M: ReplAppMemory>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(Content::Structure(FlatType::Apply(Symbol::BOX_BOX_TYPE, args)), Layout::Boxed(inner_layout)) => {
|
||||||
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let inner_var_index = args.into_iter().next().unwrap();
|
||||||
|
let inner_var = env.subs[inner_var_index];
|
||||||
|
let inner_content = env.subs.get_content_without_compacting(inner_var);
|
||||||
|
|
||||||
|
let addr_of_inner = mem.deref_usize(addr);
|
||||||
|
let inner_expr = addr_to_ast(env, mem, addr_of_inner, inner_layout, WhenRecursive::Unreachable, inner_content);
|
||||||
|
|
||||||
|
let box_box = env.arena.alloc(Loc::at_zero(Expr::Var {
|
||||||
|
module_name: "Box", ident: "box"
|
||||||
|
}));
|
||||||
|
let box_box_arg = &*env.arena.alloc(Loc::at_zero(inner_expr));
|
||||||
|
let box_box_args = env.arena.alloc([box_box_arg]);
|
||||||
|
|
||||||
|
Expr::Apply(box_box, box_box_args, CalledVia::Space)
|
||||||
|
}
|
||||||
|
(_, Layout::Boxed(_)) => unreachable!("Box layouts can only be behind a `Box.Box` application"),
|
||||||
other => {
|
other => {
|
||||||
todo!(
|
todo!(
|
||||||
"TODO add support for rendering pointer to {:?} in the REPL",
|
"TODO add support for rendering pointer to {:?} in the REPL",
|
||||||
|
|
|
@ -1051,3 +1051,46 @@ fn dec_in_repl() {
|
||||||
r#"1.23 : Dec"#,
|
r#"1.23 : Dec"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn print_i8_issue_2710() {
|
||||||
|
expect_success(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
a : I8
|
||||||
|
a = -1
|
||||||
|
a
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"-1 : I8"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "wasm"))]
|
||||||
|
#[test]
|
||||||
|
fn box_box() {
|
||||||
|
expect_success(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Box.box "container store"
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"Box.box "container store" : Box Str"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "wasm"))]
|
||||||
|
#[test]
|
||||||
|
fn box_box_type_alias() {
|
||||||
|
expect_success(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
HeapStr : Box Str
|
||||||
|
helloHeap : HeapStr
|
||||||
|
helloHeap = Box.box "bye stacks"
|
||||||
|
helloHeap
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"Box.box "bye stacks" : HeapStr"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -8369,7 +8369,7 @@ I need all branches in an `if` to have the same type!
|
||||||
|
|
||||||
But all the previous branches match:
|
But all the previous branches match:
|
||||||
|
|
||||||
F [ A ]
|
F [ A ]a
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue