Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
Do not enrich type_decls with incoherent manifests #1468
As discussed in the MPR and GPR linked above, recursive module can add inconsistent equations in the environment. The two previous PRs updated parts of the codebase, which were previously relying on the fact that the environment is consistent, to keep working even when that's not the case.
This GPR proposes to handle the issue differently by preventing the addition of inconsistent equations to the environment in the first place, and reverting to the old attitude of "if the environment is inconsistent, there is a bug in the compiler, let's crash now".
A few remarks:
referenced this pull request
Nov 27, 2017
Another way to look at this patch, is that it ensures that environments are no less consistent than they might be when using GADTs.
As for the check being conservative, it has to be fairly conservative. Consider the example:
when considering if we can add the equation
There are other places in the compiler where I would like to have a function that tells me, given two fully-inferred types (after type-checking is finished), whether, in a given typing environment:
Below is the code I started writing for this, also relying on
let may_equal_type ~existentials env t1 t2 = let snap = Btype.snapshot () in (* the `rigidify` calls are inspired by the `matches` function *) let tyv1 = rigidify t1 in let tyv2 = rigidify t2 in try mcomp env t1 t2; let equal_modulo_existentials v1 v2 = (* this is inspired by `all_distinct_vars` *) let v1 = expand_head env v1 in let v2 = expand_head env v2 in (List.mem v1 existentials && List.mem v2 existentials) || (v1 == v2) in let check_vars v1 v2 = if not (equal_modulo_existentials v1 v2) then raise (Unify ) in List.iter2 check_vars tyv1 tyv2; undo_compress snap; true with Unify _ -> undo_compress snap; false let may_equal_constr c1 c2 = match c1.cstr_tag, c2.cstr_tag with | Cstr_constant i1, Cstr_constant i2 -> i2 = i1 | Cstr_block i1, Cstr_block i2 -> i2 = i1 | Cstr_unboxed, Cstr_unboxed -> true | Cstr_extension (path1, b1), Cstr_extension (path2, b2) -> let equal = Path.same path1 path && b1 = b2 in let may_equal () = let existentials = c1.existentials in c1.cstr_arity = c2.cstr_arity && List.for_all2 (may_equal_type ~existentials) c1.cstr_args c2.cstr_args in equal || may_equal () | (Cstr_constant _|Cstr_block _|Cstr_unboxed|Cstr_extension _), _ -> false
The constraints we would need for such a function is to always be correct in the choice it makes between the three categories :-)
The new implementation ( in commit fc069f3 ) is not much different: we just replace all the
The function doing the replacement is called
I have also added some tests to this PR.