mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
Merge branch 'precompiled-legacy' into https-packages
This commit is contained in:
commit
f5cb2d73a1
96 changed files with 4063 additions and 1334 deletions
|
@ -621,6 +621,7 @@ fn run_in_place(
|
|||
state.env
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Work<'a> {
|
||||
Constraint {
|
||||
env: &'a Env,
|
||||
|
@ -2232,10 +2233,14 @@ fn either_type_index_to_var(
|
|||
aliases,
|
||||
type_index,
|
||||
);
|
||||
unsafe {
|
||||
types.emplace_variable(type_index, var);
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
matches!(types[type_index], TypeTag::Variable(v) if v == var)
|
||||
|| matches!(
|
||||
types[type_index],
|
||||
TypeTag::EmptyRecord | TypeTag::EmptyTagUnion
|
||||
)
|
||||
);
|
||||
var
|
||||
}
|
||||
Err(var_index) => {
|
||||
|
@ -2311,14 +2316,17 @@ impl RegisterVariable {
|
|||
| TypeTag::HostExposedAlias { shared, .. } => {
|
||||
let AliasShared { symbol, .. } = types[shared];
|
||||
if let Some(reserved) = Variable::get_reserved(symbol) {
|
||||
if rank.is_none() {
|
||||
let direct_var = if rank.is_none() {
|
||||
// reserved variables are stored with rank NONE
|
||||
return Direct(reserved);
|
||||
reserved
|
||||
} else {
|
||||
// for any other rank, we need to copy; it takes care of adjusting the rank
|
||||
let copied = deep_copy_var_in(subs, rank, pools, reserved, arena);
|
||||
return Direct(copied);
|
||||
}
|
||||
deep_copy_var_in(subs, rank, pools, reserved, arena)
|
||||
};
|
||||
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||
// was not already transformed before (if it was, we'd be in the Variable branch!)
|
||||
let _old_typ = unsafe { types.emplace_variable(typ, direct_var) };
|
||||
return Direct(direct_var);
|
||||
}
|
||||
|
||||
Deferred
|
||||
|
@ -2334,15 +2342,19 @@ impl RegisterVariable {
|
|||
pools: &mut Pools,
|
||||
arena: &'_ bumpalo::Bump,
|
||||
types: &mut Types,
|
||||
typ: Index<TypeTag>,
|
||||
typ_index: Index<TypeTag>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> Variable {
|
||||
match Self::from_type(subs, rank, pools, arena, types, typ) {
|
||||
match Self::from_type(subs, rank, pools, arena, types, typ_index) {
|
||||
Self::Direct(var) => var,
|
||||
Self::Deferred => {
|
||||
let var = subs.fresh_unnamed_flex_var();
|
||||
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||
// was not already transformed before (if it was, it wouldn't be deferred!)
|
||||
let typ = unsafe { types.emplace_variable(typ_index, var) };
|
||||
stack.push(TypeToVar::Defer {
|
||||
typ,
|
||||
typ_index,
|
||||
destination: var,
|
||||
ambient_function: AmbientFunctionPolicy::NoFunction,
|
||||
});
|
||||
|
@ -2405,7 +2417,8 @@ impl AmbientFunctionPolicy {
|
|||
#[derive(Debug)]
|
||||
enum TypeToVar {
|
||||
Defer {
|
||||
typ: Index<TypeTag>,
|
||||
typ: TypeTag,
|
||||
typ_index: Index<TypeTag>,
|
||||
destination: Variable,
|
||||
ambient_function: AmbientFunctionPolicy,
|
||||
},
|
||||
|
@ -2443,11 +2456,18 @@ fn type_to_variable<'a>(
|
|||
}
|
||||
RegisterVariable::Deferred => {
|
||||
let var = subs.fresh_unnamed_flex_var();
|
||||
|
||||
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||
// was not already transformed before (if it was, it wouldn't be deferred!)
|
||||
let typ = unsafe { types.emplace_variable($typ, var) };
|
||||
|
||||
stack.push(TypeToVar::Defer {
|
||||
typ: $typ,
|
||||
typ,
|
||||
typ_index: $typ,
|
||||
destination: var,
|
||||
ambient_function: $ambient_function_policy,
|
||||
});
|
||||
|
||||
var
|
||||
}
|
||||
}
|
||||
|
@ -2460,15 +2480,16 @@ fn type_to_variable<'a>(
|
|||
let result = helper!(typ);
|
||||
|
||||
while let Some(TypeToVar::Defer {
|
||||
typ_index,
|
||||
typ,
|
||||
destination,
|
||||
ambient_function,
|
||||
}) = stack.pop()
|
||||
{
|
||||
use TypeTag::*;
|
||||
match types[typ] {
|
||||
match typ {
|
||||
Variable(_) | EmptyRecord | EmptyTagUnion => {
|
||||
unreachable!("This variant should never be deferred!")
|
||||
unreachable!("This variant should never be deferred!",)
|
||||
}
|
||||
RangedNumber(range) => {
|
||||
let content = Content::RangedNumber(range);
|
||||
|
@ -2480,7 +2501,7 @@ fn type_to_variable<'a>(
|
|||
type_argument_regions: _,
|
||||
region: _,
|
||||
} => {
|
||||
let arguments = types.get_type_arguments(typ);
|
||||
let arguments = types.get_type_arguments(typ_index);
|
||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
||||
for (target_index, var_index) in
|
||||
(new_arguments.indices()).zip(arguments.into_iter())
|
||||
|
@ -2499,7 +2520,7 @@ fn type_to_variable<'a>(
|
|||
name,
|
||||
ambient_function,
|
||||
} => {
|
||||
let captures = types.get_type_arguments(typ);
|
||||
let captures = types.get_type_arguments(typ_index);
|
||||
let union_lambdas = create_union_lambda(
|
||||
subs, rank, pools, arena, types, name, captures, &mut stack,
|
||||
);
|
||||
|
@ -2546,7 +2567,7 @@ fn type_to_variable<'a>(
|
|||
}
|
||||
// This case is important for the rank of boolean variables
|
||||
Function(closure_type, ret_type) => {
|
||||
let arguments = types.get_type_arguments(typ);
|
||||
let arguments = types.get_type_arguments(typ_index);
|
||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
||||
for (target_index, var_index) in
|
||||
(new_arguments.indices()).zip(arguments.into_iter())
|
||||
|
@ -2564,7 +2585,7 @@ fn type_to_variable<'a>(
|
|||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
Record(fields) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
|
||||
// An empty fields is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyRecord in canonicalization
|
||||
|
@ -2611,7 +2632,7 @@ fn type_to_variable<'a>(
|
|||
}
|
||||
|
||||
TagUnion(tags) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
|
||||
// An empty tags is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||
|
@ -2625,8 +2646,8 @@ fn type_to_variable<'a>(
|
|||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
FunctionOrTagUnion(symbol) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
let tag_name = types.get_tag_name(&typ).clone();
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
let tag_name = types.get_tag_name(&typ_index).clone();
|
||||
|
||||
debug_assert!(ext_slice.len() <= 1);
|
||||
let temp_ext_var = match ext_slice.into_iter().next() {
|
||||
|
@ -2654,7 +2675,7 @@ fn type_to_variable<'a>(
|
|||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags) => {
|
||||
let ext_slice = types.get_type_arguments(typ);
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
|
||||
// An empty tags is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||
|
@ -2692,7 +2713,7 @@ fn type_to_variable<'a>(
|
|||
infer_ext_in_output_variables,
|
||||
} = types[shared];
|
||||
|
||||
let type_arguments = types.get_type_arguments(typ);
|
||||
let type_arguments = types.get_type_arguments(typ_index);
|
||||
|
||||
let alias_variables = {
|
||||
let all_vars_length = type_arguments.len()
|
||||
|
@ -2773,7 +2794,7 @@ fn type_to_variable<'a>(
|
|||
}
|
||||
|
||||
StructuralAlias { shared, actual } | OpaqueAlias { shared, actual } => {
|
||||
let kind = match types[typ] {
|
||||
let kind = match typ {
|
||||
StructuralAlias { .. } => AliasKind::Structural,
|
||||
OpaqueAlias { .. } => AliasKind::Opaque,
|
||||
_ => internal_error!(),
|
||||
|
@ -2789,7 +2810,7 @@ fn type_to_variable<'a>(
|
|||
|
||||
debug_assert!(roc_types::subs::Variable::get_reserved(symbol).is_none());
|
||||
|
||||
let type_arguments = types.get_type_arguments(typ);
|
||||
let type_arguments = types.get_type_arguments(typ_index);
|
||||
|
||||
let alias_variables = {
|
||||
let all_vars_length = type_arguments.len()
|
||||
|
@ -2860,7 +2881,7 @@ fn type_to_variable<'a>(
|
|||
infer_ext_in_output_variables: _, // TODO
|
||||
} = types[shared];
|
||||
|
||||
let type_arguments = types.get_type_arguments(typ);
|
||||
let type_arguments = types.get_type_arguments(typ_index);
|
||||
|
||||
let alias_variables = {
|
||||
let length = type_arguments.len() + lambda_set_variables.len();
|
||||
|
|
|
@ -382,7 +382,6 @@ mod solve_expr {
|
|||
let known_specializations = abilities_store.iter_declared_implementations().filter_map(
|
||||
|(impl_key, member_impl)| match member_impl {
|
||||
MemberImpl::Impl(impl_symbol) => {
|
||||
dbg!(impl_symbol);
|
||||
let specialization = abilities_store.specialization_info(*impl_symbol).expect(
|
||||
"declared implementations should be resolved conclusively after solving",
|
||||
);
|
||||
|
@ -8200,6 +8199,31 @@ mod solve_expr {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inferred_fixed_fixpoints() {
|
||||
infer_queries!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [job] to "./platform"
|
||||
|
||||
F : [Bar, FromG G]
|
||||
G : [G {lst : List F}]
|
||||
|
||||
job : { lst : List F } -> G
|
||||
job = \config -> G config
|
||||
#^^^{-1}
|
||||
# ^^^^^^ ^^^^^^^^
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
job : { lst : List [Bar, FromG a] } -[[job(0)]]-> [G { lst : List [Bar, FromG a] }] as a
|
||||
config : { lst : List [Bar, FromG ([G { lst : List [Bar, FromG a] }] as a)] }
|
||||
G config : [G { lst : List [Bar, FromG a] }] as a
|
||||
"###
|
||||
print_only_under_alias: true
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fix_recursion_under_alias_issue_4368() {
|
||||
infer_eq_without_problem(
|
||||
|
@ -8220,7 +8244,7 @@ mod solve_expr {
|
|||
"#
|
||||
),
|
||||
"{} -> Task",
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -8260,4 +8284,74 @@ mod solve_expr {
|
|||
"MDict v -> MDict v | v has Eq",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unify_types_with_fixed_fixpoints_outside_fixing_region() {
|
||||
infer_queries!(indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Input := [
|
||||
FromJob Job
|
||||
]
|
||||
|
||||
Job := [
|
||||
Job (List Input)
|
||||
]
|
||||
|
||||
job : List Input -> Job
|
||||
job = \inputs ->
|
||||
@Job (Job inputs)
|
||||
|
||||
helloWorld : Job
|
||||
helloWorld =
|
||||
@Job ( Job [ @Input (FromJob greeting) ] )
|
||||
# ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
greeting : Job
|
||||
greeting =
|
||||
job []
|
||||
|
||||
main = (\_ -> "Which platform am I running on now?\n") helloWorld
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
@Input (FromJob greeting) : [FromJob ([Job (List [FromJob a])] as a)]
|
||||
"###
|
||||
print_only_under_alias: true
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_concrete_type_with_inference_var() {
|
||||
infer_queries!(indoc!(
|
||||
r#"
|
||||
app "test" provides [f] to "./platform"
|
||||
|
||||
f : _ -> {}
|
||||
f = \_ -> f {}
|
||||
#^{-1}
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
f : {} -[[f(0)]]-> {}
|
||||
"###
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn solve_inference_var_in_annotation_requiring_recursion_fix() {
|
||||
infer_queries!(indoc!(
|
||||
r#"
|
||||
app "test" provides [translateStatic] to "./platform"
|
||||
|
||||
translateStatic : _ -> _
|
||||
translateStatic = \Element c ->
|
||||
#^^^^^^^^^^^^^^^{-1}
|
||||
Element (List.map c translateStatic)
|
||||
"#
|
||||
),
|
||||
@"translateStatic : [Element (List a)] as a -[[translateStatic(0)]]-> [Element (List b)]* as b"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue