add Store constraint that does not report errors

This commit is contained in:
Folkert 2020-11-12 15:47:56 +01:00
parent 75d18eb8ba
commit bde82c3bb6
10 changed files with 109 additions and 26 deletions

View File

@ -765,6 +765,13 @@ fn variable_usage_help(con: &Constraint, declared: &mut SeenVariables, used: &mu
used.insert(v);
}
}
Store(tipe, var, _, _) => {
for v in tipe.variables() {
used.insert(v);
}
used.insert(*var);
}
Lookup(_, expectation, _) => {
for v in expectation.get_type_ref().variables() {
used.insert(v);

View File

@ -8,6 +8,7 @@ use roc_types::types::{Category, PatternCategory, Type};
#[derive(Debug, Clone, PartialEq)]
pub enum Constraint {
Eq(Type, Expected<Type>, Category, Region),
Store(Type, Variable, &'static str, u32),
Lookup(Symbol, Expected<Type>, Region),
Pattern(Region, PatternCategory, Type, PExpected<Type>),
True, // Used for things that always unify, e.g. blanks and runtime errors

View File

@ -1221,19 +1221,9 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
})),
// "the closure's type is equal to expected type"
Eq(fn_type.clone(), expected.clone(), Category::Lambda, region),
// "fn_var is equal to the closure's type" - fn_var is used in code gen
Eq(
Type::Variable(*fn_var),
NoExpectation(Type::Variable(expr_var)),
Category::Storage(std::file!(), std::line!()),
region,
),
Eq(
Type::Variable(expr_var),
expected,
Category::Storage(std::file!(), std::line!()),
region,
),
// Store type into AST vars. We use Store so errors aren't reported twice
Store(signature.clone(), *fn_var, std::file!(), std::line!()),
Store(signature, expr_var, std::file!(), std::line!()),
closure_constraint,
]),
)
@ -1579,18 +1569,9 @@ pub fn rec_defs_help(
})),
Eq(fn_type.clone(), expected.clone(), Category::Lambda, region),
// "fn_var is equal to the closure's type" - fn_var is used in code gen
Eq(
Type::Variable(*fn_var),
NoExpectation(fn_type),
Category::Storage(std::file!(), std::line!()),
region,
),
Eq(
Type::Variable(expr_var),
expected,
Category::Storage(std::file!(), std::line!()),
region,
),
// Store type into AST vars. We use Store so errors aren't reported twice
Store(signature.clone(), *fn_var, std::file!(), std::line!()),
Store(signature, expr_var, std::file!(), std::line!()),
closure_constraint,
]),
);

View File

@ -389,6 +389,13 @@ fn variable_usage_help(con: &Constraint, declared: &mut SeenVariables, used: &mu
used.insert(v);
}
}
Store(tipe, var, _, _) => {
for v in tipe.variables() {
used.insert(v);
}
used.insert(*var);
}
Lookup(_, expectation, _) => {
for v in expectation.get_type_ref().variables() {
used.insert(v);

View File

@ -402,6 +402,13 @@ fn variable_usage_help(con: &Constraint, declared: &mut SeenVariables, used: &mu
used.insert(v);
}
}
Store(tipe, var, _, _) => {
for v in tipe.variables() {
used.insert(v);
}
used.insert(*var);
}
Lookup(_, expectation, _) => {
for v in expectation.get_type_ref().variables() {
used.insert(v);

View File

@ -244,6 +244,34 @@ fn solve(
}
}
}
Store(source, target, _filename, _linenr) => {
// a special version of Eq that is used to store types in the AST.
// IT DOES NOT REPORT ERRORS!
let actual = type_to_var(subs, rank, pools, cached_aliases, source);
let target = *target;
match unify(subs, actual, target) {
Success(vars) => {
introduce(subs, rank, pools, &vars);
state
}
Failure(vars, _actual_type, _expected_type) => {
introduce(subs, rank, pools, &vars);
// ERROR NOT REPORTED
state
}
BadType(vars, _problem) => {
introduce(subs, rank, pools, &vars);
// ERROR NOT REPORTED
state
}
}
}
Lookup(symbol, expectation, region) => {
let var = *env.vars_by_symbol.get(&symbol).unwrap_or_else(|| {
// TODO Instead of panicking, solve this as True and record

View File

@ -417,6 +417,13 @@ fn variable_usage_help(con: &Constraint, declared: &mut SeenVariables, used: &mu
used.insert(v);
}
}
Store(tipe, var, _, _) => {
for v in tipe.variables() {
used.insert(v);
}
used.insert(*var);
}
Lookup(_, expectation, _) => {
for v in expectation.get_type_ref().variables() {
used.insert(v);

View File

@ -3481,4 +3481,42 @@ mod solve_expr {
"Dict Int Int",
);
}
#[test]
fn quicksort_partition_help() {
infer_eq_without_problem(
indoc!(
r#"
app Test provides [ partitionHelp ] imports []
swap : Int, Int, List a -> List a
swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) ->
list
|> List.set i atJ
|> List.set j atI
_ ->
[]
partitionHelp : Int, Int, List (Num a), Int, (Num a) -> [ Pair Int (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot ->
if j < high then
when List.get list j is
Ok value ->
if value <= pivot then
partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot
else
partitionHelp i (j + 1) list high pivot
Err _ ->
Pair i list
else
Pair i list
"#
),
"Int, Int, List (Num a), Int, Num a -> [ Pair Int (List (Num a)) ]",
);
}
}

View File

@ -1089,7 +1089,7 @@ fn unify_rigid(subs: &mut Subs, ctx: &Context, name: &Lowercase, other: &Content
RigidVar(_) | RecursionVar { .. } | Structure(_) | Alias(_, _, _) => {
// Type mismatch! Rigid can only unify with flex, even if the
// rigid names are the same.
mismatch!("Rigid with {:?}", &other)
mismatch!("Rigid {:?} with {:?}", ctx.first, &other)
}
Error => {
// Error propagates.

View File

@ -414,6 +414,13 @@ fn variable_usage_help(con: &Constraint, declared: &mut SeenVariables, used: &mu
used.insert(v);
}
}
Store(tipe, var, _, _) => {
for v in tipe.variables() {
used.insert(v);
}
used.insert(*var);
}
Lookup(_, expectation, _) => {
for v in expectation.get_type_ref().variables() {
used.insert(v);