This PR redefines `String.take` and variants to operate on `String.Slice`. While previously functions returning a substring of the input sometimes returned `String` and sometimes returned `Substring.Raw`, they now uniformly return `String.Slice`. This is a BREAKING change, because many functions now have a different return type. So for example, if `s` is a string and `f` is a function accepting a string, `f (s.drop 1)` will no longer compile because `s.drop 1` is a `String.Slice`. To fix this, insert a call to `copy` to restore the old behavior: `f (s.drop 1).copy`. Of course, in many cases, there will be more efficient options. For example, don't write `f <| s.drop 1 |>.copy |>.dropEnd 1 |>.copy`, write `f <| s.drop 1 |>.dropEnd 1 |>.copy` instead. Also, instead of `(s.drop 1).copy = "Hello"`, write `s.drop 1 == "Hello".toSlice` instead.
133 lines
3.7 KiB
Text
133 lines
3.7 KiB
Text
module
|
||
|
||
meta import Lean.ErrorExplanation
|
||
import Lean.Meta.Basic
|
||
import all Lean.Language.Basic
|
||
open Lean Meta
|
||
|
||
/-!
|
||
# Error explanation non-interactive elaboration tests
|
||
|
||
Tests the elaborators for `register_error_explanation` and named-error macros.
|
||
-/
|
||
|
||
/-! ## Name and metadata -/
|
||
|
||
def dummyMetadata : ErrorExplanation.Metadata := {
|
||
summary := "A removed error"
|
||
sinceVersion := "4.21.0"
|
||
}
|
||
|
||
/-- Example -/
|
||
register_error_explanation lean.foo {
|
||
summary := "A removed error."
|
||
sinceVersion := "4.0.0"
|
||
removedVersion? := "4.21.0"
|
||
}
|
||
|
||
/-- error: Cannot add explanation: An error explanation already exists for `lean.foo` -/
|
||
#guard_msgs in
|
||
/-- Duplicate -/
|
||
register_error_explanation lean.foo dummyMetadata
|
||
|
||
/--
|
||
error: Invalid name `TopLevelName`: Error explanation names must have two components
|
||
|
||
Note: The first component of an error explanation name identifies the package from which the error originates, and the second identifies the error itself.
|
||
-/
|
||
#guard_msgs in
|
||
/-- Invalid -/
|
||
register_error_explanation TopLevelName dummyMetadata
|
||
|
||
macro "register_bad_error_explanation" : command =>
|
||
`(/-- -/ register_error_explanation Lean.MacroScoped { summary := "", sinceVersion := "" })
|
||
/--
|
||
error: Invalid name `Lean.MacroScoped✝`: Error explanations cannot have inaccessible names. This error often occurs when an error explanation is generated using a macro.
|
||
-/
|
||
#guard_msgs in
|
||
register_bad_error_explanation
|
||
|
||
/-- Example -/
|
||
register_error_explanation lean.bar {
|
||
summary := "An error."
|
||
sinceVersion := "4.21.0"
|
||
}
|
||
|
||
/-- warning: The error name `lean.foo` was removed in Lean version 4.21.0 and should not be used. -/
|
||
#guard_msgs in
|
||
example : MetaM Unit := throwNamedError lean.foo "Error"
|
||
|
||
example : MetaM Unit := throwNamedError lean.bar "foo"
|
||
|
||
/-! ## Message data tests -/
|
||
|
||
def logErrorNames (x : MetaM Unit) : MetaM Unit := do
|
||
Core.setMessageLog {}
|
||
x
|
||
let log ← Core.getMessageLog
|
||
let mut newLog := {}
|
||
for msg in log.toArray do
|
||
newLog := newLog.add <|
|
||
if let some errorName := msg.errorName? then
|
||
{ msg with data := m!"({errorName}) " ++ msg.data }
|
||
else
|
||
msg
|
||
Core.setMessageLog newLog
|
||
|
||
/--
|
||
error: (lean.bar) Logged error
|
||
---
|
||
error: (lean.bar) Logged error with ref
|
||
---
|
||
warning: (lean.bar) Logged warning
|
||
---
|
||
warning: (lean.bar) Logged warning with ref
|
||
-/
|
||
#guard_msgs in
|
||
run_meta logErrorNames do
|
||
logNamedError lean.bar m!"Logged error"
|
||
logNamedErrorAt (← getRef) lean.bar m!"Logged error with ref"
|
||
logNamedWarning lean.bar m!"Logged warning"
|
||
logNamedWarningAt (← getRef) lean.bar m!"Logged warning with ref"
|
||
|
||
/-- error: (lean.bar) Thrown error -/
|
||
#guard_msgs in
|
||
run_meta logErrorNames do
|
||
try
|
||
throwNamedError lean.bar "Thrown error"
|
||
catch e =>
|
||
logError e.toMessageData
|
||
|
||
/-- error: (lean.bar) Thrown error with ref -/
|
||
#guard_msgs in
|
||
run_meta logErrorNames do
|
||
try
|
||
throwNamedErrorAt (← getRef) lean.bar "Thrown error with ref"
|
||
catch e =>
|
||
logError e.toMessageData
|
||
|
||
/-! # Message name in serialized output -/
|
||
|
||
def withReportedOutput (x : MetaM α) : MetaM Unit := do
|
||
Core.resetMessageLog
|
||
discard <| x
|
||
let (res, fileName) ← IO.FS.withIsolatedStreams do
|
||
let msgs := (← getThe Core.State).messages
|
||
let fileName := msgs.toList[0]!.fileName
|
||
discard <| Language.reportMessages msgs {} false {} 0
|
||
pure fileName
|
||
Core.resetMessageLog
|
||
-- We need to omit the path to the file, since that's host-dependent; also drop line
|
||
-- number to avoid noise
|
||
let dropped := res.splitOn fileName |>.map (fun (s : String) => s.dropWhile (· != ' '))
|
||
logInfo ("".toSlice.intercalate dropped)
|
||
|
||
/--
|
||
info: error(lean.bar): function is noncomputable
|
||
warning(lean.bar): function is noncomputable
|
||
-/
|
||
#guard_msgs in
|
||
run_meta withReportedOutput do
|
||
let msg := "function is noncomputable"
|
||
logNamedError lean.bar msg
|
||
logNamedWarning lean.bar msg
|