Open TWal opened 4 months ago
Thanks Théophile. I think this is a minimization of the same problem:
val bind : #a:Type -> #b:Type -> a -> (a -> b) -> b
let bind x f = f x
let test (x:nat) =
bind x (fun n ->
assert (n >= 0); n)
The assert fails since the implicit for bind is inferred to be int
.
Dumping some thoughts:
1- This does not work since we do not accumulate subtyping constraints (i.e. we try to solve deferred constraints) when checking an abstraction, so the implicit defaults to int since that is how it's used in the body.
2- Even if we did, we would get the following two constraints in the unifier: nat <: ?u
and ?u <: int
. There's no guarantee that we solve to nat
instead of int
. Perhaps we can do a pass to collect these constraints and solve to the most restrictive one, but it's also unclear that's the right choice...
Minimized a bit more:
let test (x:nat) =
let f = (fun n -> assert (n >= 0); n) in
f x
The problem is described in the comments of the following code:
I feel like it would be reasonable to expect that the second attempt at defining
g
(un-wrapping and re-wrapping the inductive) should work, why isn't it the case?In the line
let*? x = return1 (f ()) in
, the implicit must be resolved asnat
because anything else would lead to a type error, and in the linereturn1 (return2 x)
the implicit must be resolved asint
for the same reason, I don't get why the type inference take other decisions.