/- Copyright (c) 2020 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Mario Carneiro -/ prelude import Lean.Data.AssocList import Lean.Expr import Lean.LocalContext import Lean.Util.ReplaceExpr namespace Lean.Meta /-- Some tactics substitute hypotheses with expressions. We track these substitutions using `FVarSubst`. It is just a mapping from the original FVarId (internal) name to an expression. The free variables occurring in the expression must be defined in the new goal. -/ structure FVarSubst where map : AssocList FVarId Expr := {} deriving Inhabited namespace FVarSubst def empty : FVarSubst := {} def isEmpty (s : FVarSubst) : Bool := s.map.isEmpty def contains (s : FVarSubst) (fvarId : FVarId) : Bool := s.map.contains fvarId /-- Add entry `fvarId |-> v` to `s` if `s` does not contain an entry for `fvarId`. -/ def insert (s : FVarSubst) (fvarId : FVarId) (v : Expr) : FVarSubst := if s.contains fvarId then s else let map := s.map.mapVal fun e => e.replaceFVarId fvarId v; { map := map.insertNew fvarId v } def erase (s : FVarSubst) (fvarId : FVarId) : FVarSubst := { map := s.map.erase fvarId } def find? (s : FVarSubst) (fvarId : FVarId) : Option Expr := s.map.find? fvarId def get (s : FVarSubst) (fvarId : FVarId) : Expr := match s.map.find? fvarId with | none => mkFVar fvarId -- it has not been replaced | some v => v /-- Given `e`, for each `(x => v)` in `s` replace `x` with `v` in `e` -/ def apply (s : FVarSubst) (e : Expr) : Expr := if s.map.isEmpty then e else if !e.hasFVar then e else e.replace fun e => match e with | Expr.fvar fvarId => match s.map.find? fvarId with | none => e | some v => v | _ => none def domain (s : FVarSubst) : List FVarId := s.map.foldl (init := []) fun r k _ => k :: r def any (p : FVarId → Expr → Bool) (s : FVarSubst) : Bool := s.map.any p /-- Constructs a substitution consisting of `s` followed by `t`. This satisfies `(s.append t).apply e = t.apply (s.apply e)` -/ def append (s t : FVarSubst) : FVarSubst := s.1.foldl (fun s' k v => s'.insert k (t.apply v)) t end FVarSubst end Meta def LocalDecl.applyFVarSubst (s : Meta.FVarSubst) : LocalDecl → LocalDecl | LocalDecl.cdecl i id n t bi k => LocalDecl.cdecl i id n (s.apply t) bi k | LocalDecl.ldecl i id n t v nd k => LocalDecl.ldecl i id n (s.apply t) (s.apply v) nd k abbrev Expr.applyFVarSubst (s : Meta.FVarSubst) (e : Expr) : Expr := s.apply e end Lean