@@ -391,20 +391,19 @@ inductive Expr where
391391 /--
392392 Let-expressions.
393393
394- **IMPORTANT** : The `nonDep` flag is for "local" use only. That is, a module should not "trust" its value for any purpose.
395- In the intended use-case, the compiler will set this flag, and be responsible for maintaining it.
396- Other modules may not preserve its value while applying transformations.
394+ The let-expression `let x : Nat := 2; Nat.succ x` is represented as
395+ ```
396+ Expr.letE `x (.const `Nat []) (.lit (.natVal 2)) (.app (.const `Nat.succ []) (.bvar 0)) true
397+ ```
397398
399+ If the `nonDep` flag is `true`, then the elaborator treats this as a *non-dependent `let`* (known as a *`have` expression* ).
398400 Given an environment, a metavariable context, and a local context,
399401 we say a let-expression `let x : t := v; e` is non-dependent when it is equivalent
400402 to `(fun x : t => e) v`. In contrast, the dependent let-expression
401403 `let n : Nat := 2; fun (a : Array Nat n) (b : Array Nat 2) => a = b` is type correct,
402404 but `(fun (n : Nat) (a : Array Nat n) (b : Array Nat 2) => a = b) 2` is not.
403405
404- The let-expression `let x : Nat := 2; Nat.succ x` is represented as
405- ```
406- Expr.letE `x (.const `Nat []) (.lit (.natVal 2)) (.app (.const `Nat.succ []) (.bvar 0)) true
407- ```
406+ The kernel does not pay attention to `nonDep` when type checking.
408407 -/
409408 | letE (declName : Name) (type : Expr) (value : Expr) (body : Expr) (nonDep : Bool)
410409
@@ -671,12 +670,14 @@ def mkSimpleThunkType (type : Expr) : Expr :=
671670def mkSimpleThunk (type : Expr) : Expr :=
672671 mkLambda `_ BinderInfo.default (mkConst `Unit) type
673672
674- /--
675- `.letE x t v b nonDep` is now the preferred form.
676- -/
677- def mkLet (x : Name) (t : Expr) (v : Expr) (b : Expr) (nonDep : Bool := false ) : Expr :=
673+ /-- Returns `let x : t := v; b`, a dependent `let` expression. If `nonDep := true`, then returns a `have`. -/
674+ @[inline] def mkLet (x : Name) (t : Expr) (v : Expr) (b : Expr) (nonDep : Bool := false ) : Expr :=
678675 .letE x t v b nonDep
679676
677+ /-- Returns `have x : t := v; b`, a non-dependent `let` expression. -/
678+ @[inline] def mkHave (x : Name) (t : Expr) (v : Expr) (b : Expr) : Expr :=
679+ .letE x t v b true
680+
680681@[match_pattern] def mkAppB (f a b : Expr) := mkApp (mkApp f a) b
681682@[match_pattern] def mkApp2 (f a b : Expr) := mkAppB f a b
682683@[match_pattern] def mkApp3 (f a b c : Expr) := mkApp (mkAppB f a b) c
@@ -723,7 +724,7 @@ def mkStrLit (s : String) : Expr :=
723724@[export lean_expr_mk_app] def mkAppEx : Expr → Expr → Expr := mkApp
724725@[export lean_expr_mk_lambda] def mkLambdaEx (n : Name) (d b : Expr) (bi : BinderInfo) : Expr := mkLambda n bi d b
725726@[export lean_expr_mk_forall] def mkForallEx (n : Name) (d b : Expr) (bi : BinderInfo) : Expr := mkForall n bi d b
726- @[export lean_expr_mk_let] def mkLetEx (n : Name) (t v b : Expr) : Expr := mkLet n t v b
727+ @[export lean_expr_mk_let] def mkLetEx (n : Name) (t v b : Expr) (nonDep : Bool) : Expr := mkLet n t v b nonDep
727728@[export lean_expr_mk_lit] def mkLitEx : Literal → Expr := mkLit
728729@[export lean_expr_mk_mdata] def mkMDataEx : MData → Expr → Expr := mkMData
729730@[export lean_expr_mk_proj] def mkProjEx : Name → Nat → Expr → Expr := mkProj
@@ -867,11 +868,18 @@ def isBinding : Expr → Bool
867868 | forallE .. => true
868869 | _ => false
869870
870- /-- Return `true` if the given expression is a let-expression. -/
871+ /-- Return `true` if the given expression is a let-expression or a have-expression . -/
871872def isLet : Expr → Bool
872873 | letE .. => true
873874 | _ => false
874875
876+ /-- Return `true` if the given expression is a non-dependent let-expression (a have-expression). -/
877+ def isHave : Expr → Bool
878+ | letE (nonDep := nonDep) .. => nonDep
879+ | _ => false
880+
881+ @[export lean_expr_isHave] def isHaveEx : Expr → Bool := isHave
882+
875883/-- Return `true` if the given expression is a metadata. -/
876884def isMData : Expr → Bool
877885 | mdata .. => true
@@ -1012,6 +1020,10 @@ def letBody! : Expr → Expr
10121020 | letE _ _ _ b .. => b
10131021 | _ => panic! "let expression expected"
10141022
1023+ def letNonDep! : Expr → Bool
1024+ | letE _ _ _ _ nonDep => nonDep
1025+ | _ => panic! "let expression expected"
1026+
10151027def consumeMData : Expr → Expr
10161028 | mdata _ e => consumeMData e
10171029 | e => e
@@ -1842,21 +1854,28 @@ def updateLambda! (e : Expr) (newBinfo : BinderInfo) (newDomain : Expr) (newBody
18421854 | lam n d b bi => updateLambda! (lam n d b bi) bi newDomain newBody
18431855 | _ => panic! "lambda expected"
18441856
1845- @[inline] private unsafe def updateLet!Impl (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) : Expr :=
1857+ @[inline] private unsafe def updateLet!Impl (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) (newNonDep : Bool) : Expr :=
18461858 match e with
18471859 | letE n t v b nonDep =>
1848- if ptrEq t newType && ptrEq v newVal && ptrEq b newBody then
1860+ if ptrEq t newType && ptrEq v newVal && ptrEq b newBody && nonDep == newNonDep then
18491861 e
18501862 else
1851- letE n newType newVal newBody nonDep
1863+ letE n newType newVal newBody newNonDep
18521864 | _ => panic! "let expression expected"
18531865
18541866@[implemented_by updateLet!Impl]
1855- def updateLet! (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) : Expr :=
1867+ def updateLet! (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) (newNonDep : Bool) : Expr :=
18561868 match e with
1857- | letE n _ _ _ c => letE n newType newVal newBody c
1869+ | letE n _ _ _ _ => letE n newType newVal newBody newNonDep
18581870 | _ => panic! "let expression expected"
18591871
1872+ /-- Like `Expr.updateLet!` but preserves the `nonDep` flag. -/
1873+ @[inline]
1874+ def updateLetE! (e : Expr) (newType : Expr) (newVal : Expr) (newBody : Expr) : Expr :=
1875+ match e with
1876+ | letE n t v b nonDep => updateLet! (letE n t v b nonDep) newType newVal newBody nonDep
1877+ | _ => panic! "let expression expected"
1878+
18601879def updateFn : Expr → Expr → Expr
18611880 | e@(app f a), g => e.updateApp! (updateFn f g) a
18621881 | _, g => g
@@ -1965,7 +1984,7 @@ def letFun? (e : Expr) : Option (Name × Expr × Expr × Expr) :=
19651984 | .app (.app (.app (.app (.const ``letFun _) t) _β) v) f =>
19661985 match f with
19671986 | .lam n _ b _ => some (n, t, v, b)
1968- | _ => some (.anonymous, t, v, .app f (.bvar 0 ))
1987+ | _ => some (.anonymous, t, v, .app (f.liftLooseBVars 0 1 ) (.bvar 0 ))
19691988 | _ => none
19701989
19711990/--
@@ -1982,15 +2001,15 @@ def letFunAppArgs? (e : Expr) : Option (Array Expr × Name × Expr × Expr × Ex
19822001 let rest := args.extract 4 args.size
19832002 match f with
19842003 | .lam n _ b _ => some (rest, n, t, v, b)
1985- | _ => some (rest, .anonymous, t, v, .app f (.bvar 0 ))
2004+ | _ => some (rest, .anonymous, t, v, .app (f.liftLooseBVars 0 1 ) (.bvar 0 ))
19862005
19872006/-- Maps `f` on each immediate child of the given expression. -/
19882007@[specialize]
19892008def traverseChildren [Applicative M] (f : Expr → M Expr) : Expr → M Expr
19902009 | e@(forallE _ d b _) => pure e.updateForallE! <*> f d <*> f b
19912010 | e@(lam _ d b _) => pure e.updateLambdaE! <*> f d <*> f b
19922011 | e@(mdata _ b) => e.updateMData! <$> f b
1993- | e@(letE _ t v b _) => pure e.updateLet ! <*> f t <*> f v <*> f b
2012+ | e@(letE _ t v b _) => pure e.updateLetE ! <*> f t <*> f v <*> f b
19942013 | e@(app l r) => pure e.updateApp! <*> f l <*> f r
19952014 | e@(proj _ _ b) => e.updateProj! <$> f b
19962015 | e => pure e
0 commit comments