@@ -33,25 +33,27 @@ constructor. In particular, returns
3333```
3434fun params x1 x2 x3 x1' x2' x3' => (x1 = x1' → x2 = x2' → x3 = x3' → P)
3535```
36- where `x1 x2 x3` and `x1' x2' x3'` are the fields of a constructor application of `ctorName`,
37- omitting equalities between propositions and using `HEq` where needed.
36+ where `x1 x2 x3` and `x1' x2' x3'` are the parameters and fields of a constructor application of
37+ `ctorName`, omitting equalities between propositions and using `HEq` where needed.
3838-/
3939def mkNoConfusionCtorArg (ctorName : Name) (P : Expr) : MetaM Expr := do
4040 let ctorInfo ← getConstInfoCtor ctorName
4141 -- We bring the constructor's parameters into scope abstractly, this way
4242 -- we can check if we need to use HEq. (The concrete fields could allow Eq)
43- forallBoundedTelescope ctorInfo.type ctorInfo.numParams fun xs t => do
44- forallTelescopeReducing t fun fields1 _ => do
45- forallTelescopeReducing t fun fields2 _ => do
46- withPrimedNames fields2 do
43+ forallBoundedTelescope ctorInfo.type ctorInfo.numParams fun xs1 t1 => do
44+ forallTelescopeReducing t1 fun fields1 _ => do
45+ forallBoundedTelescope ctorInfo.type ctorInfo.numParams fun xs2 t2 => do
46+ withPrimedNames xs2 do
47+ forallTelescopeReducing t2 fun fields2 _ => do
48+ withPrimedNames fields2 do
4749 let mut t := P
4850 for f1 in fields1.reverse, f2 in fields2.reverse do
4951 if (← isProof f1) then
5052 continue
5153 let name := (← f1.fvarId!.getUserName).appendAfter "_eq"
5254 let eq ← mkEqHEq f1 f2
5355 t := mkForall name .default eq t
54- mkLambdaFVars (xs ++ fields1 ++ fields2) t
56+ mkLambdaFVars (xs1 ++ fields1 ++ xs2 ++ fields2) t
5557
5658register_builtin_option backward.linearNoConfusionType : Bool := {
5759 defValue := true
@@ -89,54 +91,57 @@ def mkNoConfusionType (indName : Name) : MetaM Unit := do
8991 let v::us := casesOnInfo.levelParams.map mkLevelParam | panic! "unexpected universe levels on `casesOn`"
9092 let e := mkConst casesOnName (v.succ::us)
9193 let t ← inferType e
92- let e ← forallBoundedTelescope t info.numParams fun xs t => do
93- let e := mkAppN e xs
94- let PType := mkSort v
95- withLocalDeclD `P PType fun P => do
96- let motive ← forallTelescope (← whnfD t).bindingDomain! fun ys _ =>
97- mkLambdaFVars ys PType
98- let ti ← instantiateForall t #[motive]
99- let e := mkApp e motive
100- forallBoundedTelescope ti (some (info.numIndices + 1 )) fun ysx1 t => do -- indices and major
101- forallBoundedTelescope ti (some (info.numIndices + 1 )) fun ysx2 _ => do -- indices and major
94+ let PType := mkSort v
95+ let e ← withLocalDeclD `P PType fun P => do
96+ forallBoundedTelescope t info.numParams fun xs1 t1 => do
97+ forallBoundedTelescope t info.numParams fun xs2 t2 => do
98+ withPrimedNames xs2 do
99+ let e := mkAppN e xs1
100+ let motive1 ← forallTelescope (← whnfD t1).bindingDomain! fun ys _ => mkLambdaFVars ys PType
101+ let t1 ← instantiateForall t1 #[motive1]
102+ let e := mkApp e motive1
103+ let motive2 ← forallTelescope (← whnfD t2).bindingDomain! fun ys _ => mkLambdaFVars ys PType
104+ let t2 ← instantiateForall t2 #[motive2]
105+ forallBoundedTelescope t1 (some (info.numIndices + 1 )) fun ysx1 t1 => do -- indices and major
106+ forallBoundedTelescope t2 (some (info.numIndices + 1 )) fun ysx2 _t2 => do -- indices and major
102107 withPrimedNames ysx2 do
103108 let e := mkAppN e ysx1
104- let altTypes ← arrowDomainsN info.numCtors t
109+ let altTypes ← arrowDomainsN info.numCtors t1
105110 let alts ← altTypes.mapIdxM fun i altType => do
106111 forallTelescope altType fun zs1 _ => do
107112 if useLinearConstruction then
108- let ctorIdxApp := mkAppN (mkConst (mkCtorIdxName indName) us) (xs ++ ysx2)
113+ let ctorIdxApp := mkAppN (mkConst (mkCtorIdxName indName) us) (xs2 ++ ysx2)
109114 let alt ← mkIfNatEq PType (ctorIdxApp) (mkRawNatLit i)
110115 («else » := fun _ => pure P) fun h => do
111116 let conName := info.ctors[i]!
112117 let withName := mkConstructorElimName indName conName
113118 let e := mkConst withName (v.succ :: us)
114- let e := mkAppN e (xs ++ #[motive ] ++ ysx2 ++ #[h])
119+ let e := mkAppN e (xs2 ++ #[motive2 ] ++ ysx2 ++ #[h])
115120 let e := mkApp e <|
116121 ← forallTelescopeReducing ((← whnf (← inferType e)).bindingDomain!) fun zs2 _ => do
117- let k := (← mkNoConfusionCtorArg conName P).beta (xs ++ zs1 ++ zs2)
122+ let k := (← mkNoConfusionCtorArg conName P).beta (xs1 ++ zs1 ++ xs2 ++ zs2)
118123 let t ← mkArrow k P
119124 mkLambdaFVars zs2 t
120125 pure e
121126 mkLambdaFVars zs1 alt
122127 else
123128 let conName := info.ctors[i]!
124129 let alt := mkConst casesOnName (v.succ :: us)
125- let alt := mkAppN alt (xs ++ #[motive ] ++ ysx2)
130+ let alt := mkAppN alt (xs2 ++ #[motive2 ] ++ ysx2)
126131 let t2 ← inferType alt
127132 let altTypes2 ← arrowDomainsN info.numCtors t2
128133 let alts2 ← altTypes2.mapIdxM fun j altType2 => do
129134 forallTelescope altType2 fun zs2 _ => do
130135 if i = j then
131- let k := (← mkNoConfusionCtorArg conName P).beta (xs ++ zs1 ++ zs2)
136+ let k := (← mkNoConfusionCtorArg conName P).beta (xs1 ++ zs1 ++ xs2 ++ zs2)
132137 let t ← mkArrow k P
133138 mkLambdaFVars zs2 t
134139 else
135140 mkLambdaFVars zs2 P
136141 let alt := mkAppN alt alts2
137142 mkLambdaFVars zs1 alt
138143 let e := mkAppN e alts
139- mkLambdaFVars (xs ++ #[P] ++ ysx1 ++ ysx2) e
144+ mkLambdaFVars (#[P] ++ xs1 ++ ysx1 ++ xs2 ++ ysx2) e
140145
141146 addDecl (.defnDecl (← mkDefinitionValInferringUnsafe
142147 (name := declName)
@@ -220,19 +225,19 @@ def mkNoConfusionCoreImp (indName : Name) : MetaM Unit := do
220225 let casesOnInfo ← getConstVal casesOnName
221226 let v::us := casesOnInfo.levelParams.map mkLevelParam | panic! "unexpected universe levels on `casesOn`"
222227 trace[Meta.mkNoConfusion] m!"mkNoConfusionCoreImp for {declName}"
223- let e ← forallBoundedTelescope (← inferType (mkConst noConfusionTypeName (v::us))) (some (info.numParams + 1 ) ) fun xs t => do
224- let params : Array Expr : = xs[:info.numParams]
225- let P := xs[ info.numParams]!
226- forallBoundedTelescope t (some (info.numIndices + 1 )) fun ysx1 _ => do -- indices and major
227- forallBoundedTelescope t (some (info.numIndices + 1 )) fun ysx2 _ => do -- indices and major
228- withPrimedNames ysx2 do
229- withImplicitBinderInfos (( ysx1 ++ ysx2).push P) do
230- let target1 := mkAppN (mkConst noConfusionTypeName (v :: us)) (params ++ #[P] ++ ysx1 ++ ysx1 )
228+ let e ← forallBoundedTelescope (← inferType (mkConst noConfusionTypeName (v::us))) (some 1 ) fun xs t => do
229+ let P : = xs[0 ]!
230+ forallBoundedTelescope t (some ( info.numParams + info.numIndices + 1 )) fun xs1 t => do -- params, indices and major
231+ forallBoundedTelescope t (some (info.numParams + info. numIndices + 1 )) fun xs2 _ => do -- params, indices and major
232+ withImplicitBinderInfos ((xs1 ++ xs2).push P) do
233+ let params1 : Array Expr := xs1[:info.numParams]
234+ let ysx1 : Array Expr := xs1[info.numParams:]
235+ let target1 := mkAppN (mkConst noConfusionTypeName (v :: us)) (#[P] ++ xs1 ++ xs1 )
231236 let motive1 ← mkLambdaFVars ysx1 target1
232237 let alts ← info.ctors.mapM fun ctor => do
233- let ctorType ← inferType (mkAppN (mkConst ctor us) params )
234- forallTelescopeReducing ctorType fun fs _ => do
235- let kType := (← mkNoConfusionCtorArg ctor P).beta (params ++ fs ++ fs )
238+ let ctorType ← inferType (mkAppN (mkConst ctor us) params1 )
239+ forallTelescopeReducing ctorType fun fs1 _ => do
240+ let kType := (← mkNoConfusionCtorArg ctor P).beta (params1 ++ fs1 ++ params1 ++ fs1 )
236241 withLocalDeclD `k kType fun k => do
237242 let mut e := k
238243 let eqns ← arrowDomainsN kType.getNumHeadForalls kType
@@ -243,12 +248,12 @@ def mkNoConfusionCoreImp (indName : Name) : MetaM Unit := do
243248 e := mkApp e (← mkHEqRefl x)
244249 else
245250 throwError "unexpected equation {eqn} in `mkNoConfusionCtorArg` for {ctor}"
246- mkLambdaFVars (fs ++ #[k]) e
247- let e := mkAppN (mkConst casesOnName (v :: us)) (params ++ #[motive1] ++ ysx1 ++ alts)
248- let target2 := mkAppN (mkConst noConfusionTypeName (v :: us)) (params ++ #[P] ++ ysx1 ++ ysx2 )
249- let motive2 ← mkLambdaFVars ysx2 target2
250- let e ← mkEqNDRecTelescope motive2 e ysx1 ysx2
251- mkLambdaFVars (params ++ #[P] ++ ysx1 ++ ysx2 ) e
251+ mkLambdaFVars (fs1 ++ #[k]) e
252+ let e := mkAppN (mkConst casesOnName (v :: us)) (params1 ++ #[motive1] ++ ysx1 ++ alts)
253+ let target2 := mkAppN (mkConst noConfusionTypeName (v :: us)) (#[P] ++ xs1 ++ xs2 )
254+ let motive2 ← mkLambdaFVars xs2 target2
255+ let e ← mkEqNDRecTelescope motive2 e xs1 xs2
256+ mkLambdaFVars (#[P] ++ xs1 ++ xs2 ) e
252257
253258 addDecl (.defnDecl (← mkDefinitionValInferringUnsafe
254259 (name := declName)
@@ -265,8 +270,8 @@ def mkNoConfusionCoreImp (indName : Name) : MetaM Unit := do
265270
266271/--
267272Creates per-constructor no-confusion definitions. These specialize the general noConfusion
268- declaration to equalities between two applications of the same constructor, to effectively cache
269- the computation of `noConfusionType` for that constructor:
273+ declaration to (homogeneous!) equalities between two applications of the same constructor, to
274+ effectively cache the computation of `noConfusionType` for that constructor:
270275
271276```
272277def L.cons.noConfusion.{u_1, u} : {α : Type u} → {P : Sort u_1} →
@@ -282,6 +287,14 @@ def Vec.cons.noConfusion.{u_1, u} : {α : Type u} → {P : Sort u_1} →
282287 (n = n' → x = x' → xs ≍ xs' → P)
283288 → P
284289```
290+
291+ These are specialized to equal parameters. The main use of these theorems is `injection` through
292+ `Meta.mkNoConfusion`, which deals with homogeneous equalities, so no need for the generality.
293+
294+ These still accept a heterogeneous equality between the two constructor applications: if we tried
295+ to phrase this theroem with a homogeneous equality, this would force those constructor fields that
296+ appear in indices to be equal, which is too strong: we can have homogenenous equalities between
297+ two constructor applications with different fields but same indices.
285298-/
286299def mkNoConfusionCtors (declName : Name) : MetaM Unit := do
287300 -- Do not do anything unless can_elim_to_type.
@@ -312,11 +325,21 @@ def mkNoConfusionCtors (declName : Name) : MetaM Unit := do
312325 -- When the kernel checks this definition, it will perform the potentially expensive
313326 -- computation that `noConfusionType h` is equal to `$kType → P`
314327 let kType ← mkNoConfusionCtorArg ctor P
315- let kType := kType.beta (xs ++ fields1 ++ fields2)
328+ let kType := kType.beta (xs ++ fields1 ++ xs ++ fields2)
329+ -- TODO: Turn HEq to Eq in kType
316330 withLocalDeclD `k kType fun k => do
317331 let mut e := mkConst noConfusionName (v :: us)
318- e := mkAppN e (xs ++ #[P] ++ is1 ++ #[ctor1] ++ is2 ++ #[ctor2])
319- -- eqs may have more Eq rather than HEq than expected by `noConfusion`
332+ e := mkAppN e (#[P] ++ xs ++ is1 ++ #[ctor1] ++ xs ++ is2 ++ #[ctor2])
333+ -- Pass rfl equalities for parameters
334+ for _ in [:xs.size] do
335+ let eq ← whnf (← whnfForall (← inferType e)).bindingDomain!
336+ if let some (_,i,_,_) := eq.heq? then
337+ e := mkApp e (← mkHEqRefl i)
338+ else if let some (_,i,_) := eq.eq? then
339+ e := mkApp e (← mkEqRefl i)
340+ else
341+ throwError "mkNoConfusion: unexpected equality `{eq}` as next argument to{inlineExpr (← inferType e)}"
342+ -- Equalities for indices. May require going from Eq to HEq
320343 for eq in eqs do
321344 let needsHEq := (← whnfForall (← inferType e)).bindingDomain!.isHEq
322345 if needsHEq && (← inferType eq).isEq then
@@ -336,11 +359,10 @@ def mkNoConfusionCtors (declName : Name) : MetaM Unit := do
336359 (hints := ReducibilityHints.abbrev)
337360 ))
338361 setReducibleAttribute name
339- let arity := ctorInfo.numParams + 1 + 2 * ctorInfo.numFields + indVal.numIndices + 1
362+ let arity := ctorInfo.numParams + 1 + 2 * ctorInfo.numFields + eqvs.size
340363 let fields := kType.getNumHeadForalls
341364 modifyEnv fun env => markNoConfusion env name (.perCtor arity fields)
342365
343-
344366def mkNoConfusionCore (declName : Name) : MetaM Unit := do
345367 -- Do not do anything unless can_elim_to_type. TODO: Extract to util
346368 let .inductInfo indVal ← getConstInfo declName | return
0 commit comments