-
Notifications
You must be signed in to change notification settings - Fork 717
feat: add the nondep field of Expr.letE to the C++ data model
#8751
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
Changes from 1 commit
3086957
fc17746
0cc256a
fa0bfa4
64186ad
f5e90b2
61698ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -391,20 +391,19 @@ inductive Expr where | |
| /-- | ||
| Let-expressions. | ||
|
|
||
| **IMPORTANT**: The `nonDep` flag is for "local" use only. That is, a module should not "trust" its value for any purpose. | ||
| In the intended use-case, the compiler will set this flag, and be responsible for maintaining it. | ||
| Other modules may not preserve its value while applying transformations. | ||
| The let-expression `let x : Nat := 2; Nat.succ x` is represented as | ||
| ``` | ||
| Expr.letE `x (.const `Nat []) (.lit (.natVal 2)) (.app (.const `Nat.succ []) (.bvar 0)) true | ||
| ``` | ||
|
|
||
| If the `nonDep` flag is `true`, then the elaborator treats this as a *non-dependent `let`* (known as a *`have` expression*). | ||
| Given an environment, a metavariable context, and a local context, | ||
| we say a let-expression `let x : t := v; e` is non-dependent when it is equivalent | ||
| to `(fun x : t => e) v`. In contrast, the dependent let-expression | ||
| `let n : Nat := 2; fun (a : Array Nat n) (b : Array Nat 2) => a = b` is type correct, | ||
| but `(fun (n : Nat) (a : Array Nat n) (b : Array Nat 2) => a = b) 2` is not. | ||
|
|
||
| The let-expression `let x : Nat := 2; Nat.succ x` is represented as | ||
| ``` | ||
| Expr.letE `x (.const `Nat []) (.lit (.natVal 2)) (.app (.const `Nat.succ []) (.bvar 0)) true | ||
| ``` | ||
| The kernel does not pay attention to `nonDep` when type checking. | ||
| -/ | ||
| | letE (declName : Name) (type : Expr) (value : Expr) (body : Expr) (nonDep : Bool) | ||
|
|
||
|
|
@@ -671,12 +670,14 @@ def mkSimpleThunkType (type : Expr) : Expr := | |
| def mkSimpleThunk (type : Expr) : Expr := | ||
| mkLambda `_ BinderInfo.default (mkConst `Unit) type | ||
|
|
||
| /-- | ||
| `.letE x t v b nonDep` is now the preferred form. | ||
| -/ | ||
| def mkLet (x : Name) (t : Expr) (v : Expr) (b : Expr) (nonDep : Bool := false) : Expr := | ||
| /-- Returns `let x : t := v; b`, a dependent `let` expression. If `nonDep := true`, then returns a `have`. -/ | ||
| @[inline] def mkLet (x : Name) (t : Expr) (v : Expr) (b : Expr) (nonDep : Bool := false) : Expr := | ||
| .letE x t v b nonDep | ||
|
|
||
| /-- Returns `have x : t := v; b`, a non-dependent `let` expression. -/ | ||
| @[inline] def mkHave (x : Name) (t : Expr) (v : Expr) (b : Expr) : Expr := | ||
| .letE x t v b true | ||
|
|
||
| @[match_pattern] def mkAppB (f a b : Expr) := mkApp (mkApp f a) b | ||
| @[match_pattern] def mkApp2 (f a b : Expr) := mkAppB f a b | ||
| @[match_pattern] def mkApp3 (f a b c : Expr) := mkApp (mkAppB f a b) c | ||
|
|
@@ -723,7 +724,7 @@ def mkStrLit (s : String) : Expr := | |
| @[export lean_expr_mk_app] def mkAppEx : Expr → Expr → Expr := mkApp | ||
| @[export lean_expr_mk_lambda] def mkLambdaEx (n : Name) (d b : Expr) (bi : BinderInfo) : Expr := mkLambda n bi d b | ||
| @[export lean_expr_mk_forall] def mkForallEx (n : Name) (d b : Expr) (bi : BinderInfo) : Expr := mkForall n bi d b | ||
| @[export lean_expr_mk_let] def mkLetEx (n : Name) (t v b : Expr) : Expr := mkLet n t v b | ||
| @[export lean_expr_mk_let] def mkLetEx (n : Name) (t v b : Expr) (nonDep : Bool) : Expr := mkLet n t v b nonDep | ||
| @[export lean_expr_mk_lit] def mkLitEx : Literal → Expr := mkLit | ||
| @[export lean_expr_mk_mdata] def mkMDataEx : MData → Expr → Expr := mkMData | ||
| @[export lean_expr_mk_proj] def mkProjEx : Name → Nat → Expr → Expr := mkProj | ||
|
|
@@ -867,11 +868,18 @@ def isBinding : Expr → Bool | |
| | forallE .. => true | ||
| | _ => false | ||
|
|
||
| /-- Return `true` if the given expression is a let-expression. -/ | ||
| /-- Return `true` if the given expression is a let-expression or a have-expression. -/ | ||
| def isLet : Expr → Bool | ||
| | letE .. => true | ||
| | _ => false | ||
|
|
||
| /-- Return `true` if the given expression is a non-dependent let-expression (a have-expression). -/ | ||
| def isHave : Expr → Bool | ||
| | letE (nonDep := nonDep) .. => nonDep | ||
| | _ => false | ||
|
|
||
| @[export lean_expr_isHave] def isHaveEx : Expr → Bool := isHave | ||
|
|
||
| /-- Return `true` if the given expression is a metadata. -/ | ||
| def isMData : Expr → Bool | ||
| | mdata .. => true | ||
|
|
@@ -1012,6 +1020,10 @@ def letBody! : Expr → Expr | |
| | letE _ _ _ b .. => b | ||
| | _ => panic! "let expression expected" | ||
|
|
||
| def letNonDep! : Expr → Bool | ||
| | letE _ _ _ _ nonDep => nonDep | ||
| | _ => panic! "let expression expected" | ||
|
|
||
| def consumeMData : Expr → Expr | ||
| | mdata _ e => consumeMData e | ||
| | e => e | ||
|
|
@@ -1842,21 +1854,28 @@ def updateLambda! (e : Expr) (newBinfo : BinderInfo) (newDomain : Expr) (newBody | |
| | lam n d b bi => updateLambda! (lam n d b bi) bi newDomain newBody | ||
| | _ => panic! "lambda expected" | ||
|
|
||
| @[inline] private unsafe def updateLet!Impl (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) : Expr := | ||
| @[inline] private unsafe def updateLet!Impl (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) (newNonDep : Bool) : Expr := | ||
| match e with | ||
| | letE n t v b nonDep => | ||
| if ptrEq t newType && ptrEq v newVal && ptrEq b newBody then | ||
| if ptrEq t newType && ptrEq v newVal && ptrEq b newBody && nonDep == newNonDep then | ||
| e | ||
| else | ||
| letE n newType newVal newBody nonDep | ||
| letE n newType newVal newBody newNonDep | ||
| | _ => panic! "let expression expected" | ||
|
|
||
| @[implemented_by updateLet!Impl] | ||
| def updateLet! (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) : Expr := | ||
| def updateLet! (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) (newNonDep : Bool) : Expr := | ||
| match e with | ||
| | letE n _ _ _ c => letE n newType newVal newBody c | ||
| | letE n _ _ _ _ => letE n newType newVal newBody newNonDep | ||
| | _ => panic! "let expression expected" | ||
|
|
||
| /-- Like `Expr.updateLet!` but preserves the `nonDep` flag. -/ | ||
| @[inline] | ||
| def updateLetE! (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) : Expr := | ||
| match e with | ||
| | letE n t v b nonDep => updateLet! (letE n t v b nonDep) newType newVal newBody nonDep | ||
| | _ => panic! "let expression expected" | ||
|
|
||
| def updateFn : Expr → Expr → Expr | ||
| | e@(app f a), g => e.updateApp! (updateFn f g) a | ||
| | _, g => g | ||
|
|
@@ -1965,7 +1984,7 @@ def letFun? (e : Expr) : Option (Name × Expr × Expr × Expr) := | |
| | .app (.app (.app (.app (.const ``letFun _) t) _β) v) f => | ||
| match f with | ||
| | .lam n _ b _ => some (n, t, v, b) | ||
| | _ => some (.anonymous, t, v, .app f (.bvar 0)) | ||
| | _ => some (.anonymous, t, v, .app (f.liftLooseBVars 0 1) (.bvar 0)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you hit this bug when implementing this PR?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, this wasn't good PR hygiene. I found this bug in other work, and I was extracting changes to Expr.lean to make this PR. I plan to deprecate/delete this function anyway, but I left in the change because it does fix a bug. |
||
| | _ => none | ||
|
|
||
| /-- | ||
|
|
@@ -1982,15 +2001,15 @@ def letFunAppArgs? (e : Expr) : Option (Array Expr × Name × Expr × Expr × Ex | |
| let rest := args.extract 4 args.size | ||
| match f with | ||
| | .lam n _ b _ => some (rest, n, t, v, b) | ||
| | _ => some (rest, .anonymous, t, v, .app f (.bvar 0)) | ||
| | _ => some (rest, .anonymous, t, v, .app (f.liftLooseBVars 0 1) (.bvar 0)) | ||
|
|
||
| /-- Maps `f` on each immediate child of the given expression. -/ | ||
| @[specialize] | ||
| def traverseChildren [Applicative M] (f : Expr → M Expr) : Expr → M Expr | ||
| | e@(forallE _ d b _) => pure e.updateForallE! <*> f d <*> f b | ||
| | e@(lam _ d b _) => pure e.updateLambdaE! <*> f d <*> f b | ||
| | e@(mdata _ b) => e.updateMData! <$> f b | ||
| | e@(letE _ t v b _) => pure e.updateLet! <*> f t <*> f v <*> f b | ||
| | e@(letE _ t v b _) => pure e.updateLetE! <*> f t <*> f v <*> f b | ||
| | e@(app l r) => pure e.updateApp! <*> f l <*> f r | ||
| | e@(proj _ _ b) => e.updateProj! <$> f b | ||
| | e => pure e | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.