diff --git a/RELEASES.md b/RELEASES.md index c93bd351e6..c069d59e7b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,9 @@ Unreleased --------- +* Add `dsimp` and `dsimp!` tactics. They guarantee the result term is definitionally equal, and only apply + `rfl`-theorems. + * Fix binder information for `match` patterns that use definitions tagged with `[matchPattern]` (e.g., `Nat.add`). We now have proper binder information for the variable `y` in the following example. ```lean diff --git a/src/Init/Meta.lean b/src/Init/Meta.lean index faf799c1b8..f28811f979 100644 --- a/src/Init/Meta.lean +++ b/src/Init/Meta.lean @@ -1062,12 +1062,17 @@ namespace Parser.Tactic macro "erw " s:rwRuleSeq loc:(location)? : tactic => `(rw (config := { transparency := Lean.Meta.TransparencyMode.default }) $s:rwRuleSeq $[$loc:location]?) -macro "declare_simp_like_tactic" opt:(("(" &"all " " := " &"true" ")")?) tacName:ident tacToken:str updateCfg:term : command => do +syntax simpAllKind := atomic("(" &"all") " := " &"true" ")" +syntax dsimpKind := atomic("(" &"dsimp") " := " &"true" ")" + +macro "declare_simp_like_tactic" opt:((simpAllKind <|> dsimpKind)?) tacName:ident tacToken:str updateCfg:term : command => do let (kind, tkn, stx) ← if opt.isNone then pure (← `(``simp), ← `("simp "), ← `(syntax (name := $tacName:ident) $tacToken:str (config)? (discharger)? (&"only ")? ("[" (simpStar <|> simpErase <|> simpLemma),* "]")? (location)? : tactic)) - else + else if opt[0].getKind == ``simpAllKind then pure (← `(``simpAll), ← `("simp_all "), ← `(syntax (name := $tacName:ident) $tacToken:str (config)? (discharger)? (&"only ")? ("[" (simpErase <|> simpLemma),* "]")? : tactic)) + else + pure (← `(``dsimp), ← `("dsimp "), ← `(syntax (name := $tacName:ident) $tacToken:str (config)? (discharger)? (&"only ")? ("[" (simpStar <|> simpErase <|> simpLemma),* "]")? (location)? : tactic)) `($stx:command @[macro $tacName:ident] def expandSimp : Macro := fun s => do let c ← match s[1][0] with @@ -1086,6 +1091,8 @@ declare_simp_like_tactic (all := true) simpAllAutoUnfold "simp_all! " fun (c : L declare_simp_like_tactic (all := true) simpAllArith "simp_all_arith " fun (c : Lean.Meta.Simp.ConfigCtx) => { c with arith := true } declare_simp_like_tactic (all := true) simpAllArithAutoUnfold "simp_all_arith! " fun (c : Lean.Meta.Simp.ConfigCtx) => { c with arith := true, autoUnfold := true } +declare_simp_like_tactic (dsimp := true) dsimpAutoUnfold "dsimp! " fun (c : Lean.Meta.DSimp.Config) => { c with autoUnfold := true } + end Parser.Tactic end Lean diff --git a/src/Lean/Meta/Tactic/Simp/Main.lean b/src/Lean/Meta/Tactic/Simp/Main.lean index 0448d75462..0703f51c15 100644 --- a/src/Lean/Meta/Tactic/Simp/Main.lean +++ b/src/Lean/Meta/Tactic/Simp/Main.lean @@ -932,7 +932,7 @@ def dsimpGoal (mvarId : MVarId) (ctx : Simp.Context) (simplifyTarget : Bool := t assignExprMVar mvarId (mkConst ``True.intro) return none if let some (_, lhs, rhs) := targetNew.eq? then - if (← isDefEq lhs rhs) then + if (← withReducible <| isDefEq lhs rhs) then assignExprMVar mvarId (← mkEqRefl lhs) return none if target != targetNew then diff --git a/tests/lean/run/dsimp1.lean b/tests/lean/run/dsimp1.lean index 0e93bed5c3..bc22865a12 100644 --- a/tests/lean/run/dsimp1.lean +++ b/tests/lean/run/dsimp1.lean @@ -9,10 +9,16 @@ example (x : Nat) : (1 + id x.succ.pred).isZero = false := by simp [Nat.succ_add] dsimp [Nat.isZero] +#check Nat.pred_succ + +example (x : Nat) : (id x.succ.succ).isZero = false := by + dsimp [Nat.isZero] + +example (x : Nat) : (id x.succ.succ).isZero = false := by + dsimp! + @[simp] theorem isZero_succ (x : Nat) : (x + 1).isZero = false := rfl theorem ex1 (x : Nat) : (id x.succ.succ.pred).isZero = false := by dsimp - -#print ex1