Skip to content

Commit c474775

Browse files
authored
fix: detect private references in inferred type of public def (#10762)
This PR fixes an inconsistency in the module system around defs with elided types.
1 parent ed4d453 commit c474775

17 files changed

+101
-67
lines changed

src/Lean/Elab/BuiltinEvalCommand.lean

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,29 @@ where
8383
let (args, _, _) ← forallMetaBoundedTelescope (← inferType m) 1
8484
return mkAppN m args
8585

86-
private def addAndCompileExprForEval (declName : Name) (value : Expr) (allowSorry := false) : TermElabM Unit := do
86+
private def addAndCompileExprForEval (declName : Name) (value : Expr) (allowSorry := false) : TermElabM Name := do
8787
-- Use the `elabMutualDef` machinery to be able to support `let rec`.
8888
-- Hack: since we are using the `TermElabM` version, we can insert the `value` as a metavariable via `exprToSyntax`.
8989
-- An alternative design would be to make `elabTermForEval` into a term elaborator and elaborate the command all at once
9090
-- with `unsafe def _eval := term_for_eval% $t`, which we did try, but unwanted error messages
9191
-- such as "failed to infer definition type" can surface.
92-
let defView := mkDefViewOfDef { isUnsafe := true, visibility := .public }
92+
let defView := mkDefViewOfDef { isUnsafe := true, visibility := .private }
9393
(← `(Parser.Command.definition|
9494
def $(mkIdent <| `_root_ ++ declName) := $(← Term.exprToSyntax value)))
95+
let declName := mkPrivateName (← getEnv) declName
9596
-- Allow access to both `meta` and non-`meta` declarations as the compilation result does not
9697
-- escape the current module.
9798
withOptions (Compiler.compiler.checkMeta.set · false) do
9899
Term.elabMutualDef #[] { header := "" } #[defView]
100+
assert! (← getEnv).contains declName
99101
unless allowSorry do
100102
let axioms ← collectAxioms declName
101103
if axioms.contains ``sorryAx then
102104
throwError "\
103105
aborting evaluation since the expression depends on the 'sorry' axiom, \
104106
which can lead to runtime instability and crashes.\n\n\
105107
To attempt to evaluate anyway despite the risks, use the '#eval!' command."
108+
return declName
106109

107110
/--
108111
Try to make a `@projFn ty inst e` application, even if it takes unfolding the type `ty` of `e` to synthesize the instance `inst`.
@@ -181,13 +184,13 @@ unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax) (expectedType? :
181184
| return none
182185
let eType := e.appFn!.appArg!
183186
if ← isDefEq eType (mkConst ``Unit) then
184-
addAndCompileExprForEval declName e (allowSorry := bang)
187+
let declName ← addAndCompileExprForEval declName e (allowSorry := bang)
185188
let mf : m Unit ← evalConst (m Unit) declName (checkMeta := !Elab.inServer.get (← getOptions))
186189
return some { eval := do MonadEvalT.monadEval mf; pure "", printVal := none }
187190
else
188191
let rf ← withLocalDeclD `x eType fun x => do mkLambdaFVars #[x] (← mkT x)
189192
let r ← mkAppM ``Functor.map #[rf, e]
190-
addAndCompileExprForEval declName r (allowSorry := bang)
193+
let declName ← addAndCompileExprForEval declName r (allowSorry := bang)
191194
let mf : m t ← evalConst (m t) declName (checkMeta := !Elab.inServer.get (← getOptions))
192195
return some { eval := toMessageData <$> MonadEvalT.monadEval mf, printVal := some eType }
193196
if let some act ← mkMAct? ``CommandElabM CommandElabM e
@@ -212,15 +215,15 @@ unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax) (expectedType? :
212215
throwError m!"unable to synthesize `{.ofConstName ``MonadEval}` instance \
213216
to adapt{indentExpr (← inferType e)}\n\
214217
to `{.ofConstName ``IO}` or `{.ofConstName ``CommandElabM}`."
215-
addAndCompileExprForEval declName r (allowSorry := bang)
218+
let declName ← addAndCompileExprForEval declName r (allowSorry := bang)
216219
-- `evalConst` may emit IO, but this is collected by `withIsolatedStreams` below.
217220
let r ← toMessageData <$> evalConst t declName (checkMeta := !Elab.inServer.get (← getOptions))
218221
return { eval := pure r, printVal := some (← inferType e) }
219222
let (output, exOrRes) ← IO.FS.withIsolatedStreams (isolateStderr := Core.stderrAsMessages.get (← getOptions)) do
220223
try
221224
-- Generate an action without executing it. We use `withoutModifyingEnv` to ensure
222225
-- we don't pollute the environment with auxiliary declarations.
223-
let act : EvalAction ← liftTermElabM do Term.withDeclName declName do withoutModifyingEnv do
226+
let act : EvalAction ← liftTermElabM do Term.withDeclName (mkPrivateName (← getEnv) declName) do withoutModifyingEnv do
224227
withSaveInfoContext do -- save the environment post-elaboration (for matchers, let rec, etc.)
225228
let e ← elabTermForEval term expectedType?
226229
-- If there is an elaboration error, don't evaluate!

src/Lean/Elab/MutualDef.lean

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,14 @@ private def elabFunValues (headers : Array DefViewElabHeader) (vars : Array Expr
547547
-- leads to more section variables being included than necessary
548548
instantiateMVarsProfiling val
549549
let val ← mkLambdaFVars xs val
550+
if header.type?.isNone && (← getEnv).header.isModule && !(← getEnv).isExporting &&
551+
!isPrivateName header.declName && header.kind != .example then
552+
-- If the type of a non-exposed definition was elided, we need to check after the fact
553+
-- whether it is in fact well-formed.
554+
withRef header.declId do
555+
withExporting do
556+
let type ← instantiateMVars type
557+
Meta.check type
550558
if linter.unusedSectionVars.get (← getOptions) && !header.type.hasSorry && !val.hasSorry then
551559
let unusedVars ← vars.filterMapM fun var => do
552560
let varDecl ← var.fvarId!.getDecl
@@ -1194,6 +1202,8 @@ where
11941202
Term.expandDeclId (← getCurrNamespace) (← getLevelNames) view.declId view.modifiers
11951203
withExporting (isExporting :=
11961204
-- `example`s are always private unless explicitly marked `public`
1205+
-- (it would be more consistent to give them a private name as well but that exposes that
1206+
-- encoded name in e.g. kernel errors where it's hard to replace it)
11971207
views.any (fun view => view.kind != .example || view.modifiers.isPublic) &&
11981208
expandedDeclIds.any (!isPrivateName ·.declName)) do
11991209
let headers ← elabHeaders views expandedDeclIds bodyPromises tacPromises

src/lake/Lake/Config/Pattern.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module
88
prelude
99
public import Init.Data.Array.Basic
1010
public import Init.System.FilePath
11+
public import Std.Data.TreeMap.Basic
12+
public import Lean.Data.Name
1113
import Lake.Util.Name
1214

1315
open System Lean

tests/lakefile.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ name = "tests"
33
# Allow `module` in tests when opened in the language server.
44
# Enabled during actual test runs in the respective test_single.sh.
55
moreGlobalServerArgs = ["-Dexperimental.module=true"]
6+
7+
[[lean_lib]]
8+
name = "Tests"
9+
globs = ["lean.*"]

tests/lean/binopInfoTree.lean.expected.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fun n m l => ↑n + (↑m + ↑l) : Nat → Nat → Nat → Int
6060
• [Term] n : Nat @ ⟨7, 29⟩-⟨7, 30⟩ @ Lean.Elab.Term.elabIdent
6161
• [Completion-Id] n : none @ ⟨7, 29⟩-⟨7, 30⟩
6262
• [Term] n : Nat @ ⟨7, 29⟩-⟨7, 30⟩
63-
• [Term] ↑m + ↑l : Int @ ⟨7, 34⟩-⟨7, 40⟩ @ «_aux_binopInfoTree___macroRules_term_+'__1»
63+
• [Term] ↑m + ↑l : Int @ ⟨7, 34⟩-⟨7, 40⟩ @ «_aux_lean_binopInfoTree___macroRules_term_+'__1»
6464
• [MacroExpansion]
6565
m +' l
6666
===>

tests/lean/dbgMacros.lean.expected.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
PANIC at f dbgMacros:2:14: unexpected zero
1+
PANIC at f lean.dbgMacros:2:14: unexpected zero
22
0
33
9
4-
PANIC at g dbgMacros:10:14: unreachable code has been reached
4+
PANIC at g lean.dbgMacros:10:14: unreachable code has been reached
55
0
66
0
7-
PANIC at h dbgMacros:16:0: assertion violation: x != 0
7+
PANIC at h lean.dbgMacros:16:0: assertion violation: x != 0
88
0
99
f2, x: 10
1010
11

tests/lean/ppNotationCode.lean.expected.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[Elab.definition.body] «term_+++_» : Lean.TrailingParserDescr :=
22
Lean.ParserDescr.trailingNode `«term_+++_» 45 46
33
(Lean.ParserDescr.binary `andthen (Lean.ParserDescr.symbol "+++") (Lean.ParserDescr.cat `term 46))
4-
[Elab.definition.body] «_aux_ppNotationCode___macroRules_term_+++__1» : Lean.Macro :=
4+
[Elab.definition.body] «_aux_lean_ppNotationCode___macroRules_term_+++__1» : Lean.Macro :=
55
fun x =>
66
have __discr := x;
77
if __discr.isOfKind `«term_+++_» = true then
@@ -24,7 +24,7 @@
2424
else
2525
have __discr := x;
2626
throw Lean.Macro.Exception.unsupportedSyntax
27-
[Elab.definition.body] _aux_ppNotationCode___unexpand_Nat_add_1 : Lean.PrettyPrinter.Unexpander :=
27+
[Elab.definition.body] _aux_lean_ppNotationCode___unexpand_Nat_add_1 : Lean.PrettyPrinter.Unexpander :=
2828
fun x =>
2929
have __discr := x;
3030
if __discr.isOfKind `Lean.Parser.Term.app = true then

tests/lean/root.lean.expected.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ root.lean:35:14-35:22: error: protected declarations must be in a namespace
77
root.lean:41:7-41:8: error(lean.unknownIdentifier): Unknown identifier `h`
88
root.lean:43:7-43:8: error(lean.unknownIdentifier): Unknown identifier `f`
99
Bla.f (x : Nat) : Nat
10-
_private.root.0.prv : Nat -> Nat
10+
_private.lean.root.0.prv : Nat -> Nat
1111
root.lean:90:89-90:93: error: unsolved goals
1212
x : Nat
1313
⊢ isEven (x + 1 + 1) = isEven x

tests/lean/run/decideNative.lean

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,7 @@ instance : Decidable ItsTrue2 :=
126126
panic! "oh no"
127127

128128
-- Note: this test fails within VS Code
129-
/-- info: output: PANIC at instDecidableItsTrue2 decideNative:126:2: oh no -/
129+
/--
130+
info: output: PANIC at instDecidableItsTrue2 lean.run.decideNative:126:2: oh no
131+
-/
130132
#guard_msgs in example : ItsTrue2 := by collect_stdout native_decide

tests/lean/run/emptyLcnf.lean

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ trace: [Compiler.result] size: 0
1212
1313
---
1414
trace: [Compiler.result] size: 5
15-
def _eval._lam_0 _x.1 _x.2 _y.3 _y.4 _y.5 _y.6 _y.7 _y.8 _y.9 : EStateM.Result Lean.Exception lcRealWorld PUnit :=
15+
def _private.lean.run.emptyLcnf.0._eval._lam_0 _x.1 _x.2 _y.3 _y.4 _y.5 _y.6 _y.7 _y.8 _y.9 : EStateM.Result
16+
Lean.Exception lcRealWorld PUnit :=
1617
let _x.10 := Lean.Compiler.compile _x.1 _y.7 _y.8 _y.9;
1718
cases _x.10 : EStateM.Result Lean.Exception lcRealWorld PUnit
1819
| EStateM.Result.ok a.11 a.12 =>
@@ -21,34 +22,34 @@ trace: [Compiler.result] size: 5
2122
| EStateM.Result.error a.14 a.15 =>
2223
return _x.10
2324
[Compiler.result] size: 1
24-
def _eval._closed_0 : String :=
25+
def _private.lean.run.emptyLcnf.0._eval._closed_0 : String :=
2526
let _x.1 := "f";
2627
return _x.1
2728
[Compiler.result] size: 2
28-
def _eval._closed_1 : Lean.Name :=
29-
let _x.1 := _eval._closed_0;
29+
def _private.lean.run.emptyLcnf.0._eval._closed_1 : Lean.Name :=
30+
let _x.1 := _eval._closed_0.2;
3031
let _x.2 := Lean.Name.mkStr1 _x.1;
3132
return _x.2
3233
[Compiler.result] size: 2
33-
def _eval._closed_2 : Array Lean.Name :=
34+
def _private.lean.run.emptyLcnf.0._eval._closed_2 : Array Lean.Name :=
3435
let _x.1 := 1;
3536
let _x.2 := Array.mkEmpty ◾ _x.1;
3637
return _x.2
3738
[Compiler.result] size: 3
38-
def _eval._closed_3 : Array Lean.Name :=
39-
let _x.1 := _eval._closed_1;
40-
let _x.2 := _eval._closed_2;
39+
def _private.lean.run.emptyLcnf.0._eval._closed_3 : Array Lean.Name :=
40+
let _x.1 := _eval._closed_1.2;
41+
let _x.2 := _eval._closed_2.2;
4142
let _x.3 := Array.push ◾ _x.2 _x.1;
4243
return _x.3
4344
[Compiler.result] size: 8
44-
def _eval a.1 a.2 a.3 : EStateM.Result Lean.Exception lcRealWorld PUnit :=
45-
let _x.4 := _eval._closed_0;
46-
let _x.5 := _eval._closed_1;
45+
def _private.lean.run.emptyLcnf.0._eval a.1 a.2 a.3 : EStateM.Result Lean.Exception lcRealWorld PUnit :=
46+
let _x.4 := _eval._closed_0.2;
47+
let _x.5 := _eval._closed_1.2;
4748
let _x.6 := 1;
48-
let _x.7 := _eval._closed_2;
49-
let _x.8 := _eval._closed_3;
49+
let _x.7 := _eval._closed_2.2;
50+
let _x.8 := _eval._closed_3.2;
5051
let _x.9 := PUnit.unit;
51-
let _f.10 := _eval._lam_0 _x.8 _x.9;
52+
let _f.10 := _eval._lam_0.2 _x.8 _x.9;
5253
let _x.11 := Lean.Elab.Command.liftTermElabM._redArg _f.10 a.1 a.2 a.3;
5354
return _x.11
5455
-/

0 commit comments

Comments
 (0)