-
Notifications
You must be signed in to change notification settings - Fork 24
Add type unification to VCs from procedure pre/post conditions #415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
CC: @shigoel |
| let actual_tys := args.filterMap getExprType | ||
| let lhs_tys := lhs.filterMap (fun l => | ||
| (E.exprEnv.state.findD l (none, .fvar () l none)).fst) | ||
| let input_constraints := actual_tys.zip input_tys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I asked Claude to review and it had this to say:
1. (Correctness bug) filterMap + zip can misalign type constraints — StatementEval.lean:148-152
This is the most important thing to check. In computeTypeSubst:
let actual_tys := args.filterMap getExprType
...
let input_constraints := actual_tys.zip input_tys
filterMap drops any arg where getExprType returns none, shrinking the list. zip then pairs by position, so if arg i has no type, arg i+1's type gets paired with formal
type i, producing an incorrect constraint. For example, if args = [a, b, c] and getExprType yields [some T1, none, some T3], the constraints become [(T1, input_0), (T3,
input_1)] instead of the intended [(T1, input_0), (T3, input_2)]. The same issue applies to lhs_tys/output_constraints. A zipWith/pairwise approach that keeps index
alignment (e.g., zip first, then filter pairs where the type is some) would be safer.
It's obvious to me why the zip is ok either.
| let constraints := input_constraints ++ output_constraints | ||
| match Constraints.unify constraints SubstInfo.empty with | ||
| | .ok substInfo => substInfo.subst | ||
| | .error _ => Subst.empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More Claude:
2. (Design) Silent failure on unification error — StatementEval.lean:154-156
| .error _ => Subst.empty
If unification fails, the code silently returns an empty substitution, meaning type variables remain uninstantiated in VCs sent to the SMT solver. Verify this is the
desired behavior vs. propagating a diagnostic. At minimum, consider whether a warning should be emitted.
| @@ -119,6 +163,10 @@ def Command.evalCall (E : Env) (old_var_subst : SubstMap) | |||
| (md : Imperative.MetaData Expression) : Command × Env := | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add some comments about the relationships between the variables in old_var_subst , lhs and E? It's a little unclear to me which typing context the various expressions are in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, we are given a term lhs := p(xs) where p takes in arguments of type input_tys and returns arguments of types output_tys. E should contain the types for the free variables in LHS (guaranteed by the StatementEval execution). I believe that old_var_subst has to do with var -> expression maps, not type substitutions. I can add a comment explaining this.
| Compute type substitution by unifying actual argument types with input types | ||
| and LHS types with output types. | ||
| -/ | ||
| private def computeTypeSubst (input_tys output_tys: List LMonoTy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| private def computeTypeSubst (input_tys output_tys: List LMonoTy) | |
| private def computeTypeSubst (input_tys output_tys : List LMonoTy) |
|
To Joe's comments - the correctness of both of these rely on the fact that the typechecker has already run on the constituent parts so all terms are annotated with their types. The unification must succeed because we are given precondition (or postcondition) |
Issue #, if available: #398
Description of changes: Performs type unification on generated VCs from (already typechecked) procedure pre and post conditions, so that polymorphic type variables are instantiated before SMT encoding.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.