Skip to content

Commit 2677ca8

Browse files
authored
fix: import-merging theorems under the module system (#10556)
1 parent 78b09d5 commit 2677ca8

File tree

4 files changed

+45
-5
lines changed

4 files changed

+45
-5
lines changed

src/Lean/Environment.lean

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,15 +2125,39 @@ and theorems are (mostly) opaque in Lean. For `Acc.rec`, we may unfold theorems
21252125
during type-checking, but we are assuming this is not an issue in practice,
21262126
and we are planning to address this issue in the future.
21272127
-/
2128-
private def subsumesInfo (cinfo₁ cinfo₂ : ConstantInfo) : Bool :=
2128+
private def subsumesInfo (constMap : Std.HashMap Name ConstantInfo) (cinfo₁ cinfo₂ : ConstantInfo) : Bool :=
21292129
cinfo₁.name == cinfo₂.name &&
21302130
cinfo₁.type == cinfo₂.type &&
21312131
cinfo₁.levelParams == cinfo₂.levelParams &&
21322132
match cinfo₁, cinfo₂ with
21332133
| .thmInfo tval₁, .thmInfo tval₂ => tval₁.all == tval₂.all
21342134
| .thmInfo tval₁, .axiomInfo aval₂ => tval₁.all == [aval₂.name] && !aval₂.isUnsafe
2135-
| .axiomInfo aval₁, .axiomInfo aval₂ => aval₁.isUnsafe == aval₂.isUnsafe
2135+
| .axiomInfo aval₁, .axiomInfo aval₂ =>
2136+
-- In this case, we cannot a priori assume that both axioms came from theorems and thus their
2137+
-- former bodies are irrelevant - they could be both from definitions with different bodies
2138+
-- that were used to derive statements that would be contradictory if the axioms were merged.
2139+
-- Thus we do a rough, pure approximation of `Lean.Meta.isProp` that is sufficient for the
2140+
-- restricted types we use for realizable theorems and ensures the former bodies of the two
2141+
-- axioms must be irrelevant after all.
2142+
aval₁.isUnsafe == aval₂.isUnsafe && isPropCheap aval₁.type
21362143
| _, _ => false
2144+
where
2145+
/--
2146+
Check if `ty = ∀ ..., p xs...` and `p : ∀ args..., Prop` where `xs` and `args` are of the same
2147+
length.
2148+
-/
2149+
isPropCheap (ty : Expr) : Bool := Id.run do
2150+
let mut ty := ty
2151+
while ty.isForall do
2152+
let .forallE (body := body) .. := ty | return false
2153+
ty := body
2154+
let .const n .. := ty.getAppFn | return false
2155+
let some decl := constMap[n]? | return false
2156+
let mut p := decl.type
2157+
for _ in 0...ty.getAppNumArgs do
2158+
let .forallE (body := body) .. := p | return false
2159+
p := body
2160+
p.isProp
21372161

21382162
/--
21392163
Constructs environment from `importModulesCore` results.
@@ -2172,9 +2196,9 @@ def finalizeImport (s : ImportState) (imports : Array Import) (opts : Options) (
21722196
privateConstantMap := constantMap'
21732197
if let some cinfoPrev := cinfoPrev? then
21742198
-- Recall that the map has not been modified when `cinfoPrev? = some _`.
2175-
if subsumesInfo cinfo cinfoPrev then
2199+
if subsumesInfo privateConstantMap cinfo cinfoPrev then
21762200
privateConstantMap := privateConstantMap.insert cname cinfo
2177-
else if !subsumesInfo cinfoPrev cinfo then
2201+
else if !subsumesInfo privateConstantMap cinfoPrev cinfo then
21782202
throwAlreadyImported s const2ModIdx modIdx cname
21792203
const2ModIdx := const2ModIdx.insertIfNew cname modIdx
21802204
if let some data := irData[modIdx]? then
@@ -2189,7 +2213,7 @@ def finalizeImport (s : ImportState) (imports : Array Import) (opts : Options) (
21892213
| (cinfoPrev?, constantMap') =>
21902214
publicConstantMap := constantMap'
21912215
if let some cinfoPrev := cinfoPrev? then
2192-
if subsumesInfo cinfo cinfoPrev then
2216+
if subsumesInfo publicConstantMap cinfo cinfoPrev then
21932217
publicConstantMap := publicConstantMap.insert cname cinfo
21942218
-- no need to check for duplicates again, `privateConstMap` should be a superset
21952219

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module
2+
3+
/-! A definition incompatible with that in `Basic`. -/
4+
5+
public def f := 2
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module
2+
3+
prelude
4+
public import Module.Basic
5+
public import Module.Basic2
6+
7+
/-!
8+
It should not be possible to import conflicting definitions even if as axioms they look identical.
9+
-/

tests/pkg/module/test.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#!/usr/bin/env bash
2+
set -e
23

34
rm -rf .lake/build
45
LEAN_ABORT_ON_PANIC=1 lake build
6+
lake lean Module/ConflictingImported.lean | grep "already contains 'f'"

0 commit comments

Comments
 (0)