This PR adds server-side support for dedicated 'unsolved goals' and 'goals accomplished' diagnostics that will have special support in the Lean 4 VS Code extension. The special 'unsolved goals' diagnostic is adapted from the 'unsolved goals' error diagnostic, while the 'goals accomplished' diagnostic is issued when a `theorem` or `Prop`-typed `example` has no errors or `sorry`s. The Lean 4 VS Code extension companion PR is at leanprover/vscode-lean4#585. Specifically, this PR extends the diagnostics served by the language server with the following fields: - `leanTags`: Custom tags that denote the kind of diagnostic that is being served. As opposed to the `code`, `leanTags` should never be displayed in the UI. Examples introduced by this PR are a tag to distinguish 'unsolved goals' errors from other diagnostics, as well as a tag to distinguish the new 'goals accomplished' diagnostic from other diagnostics. - `isSilent`: Whether a diagnostic should not be displayed as a regular diagnostic in the editor. In VS Code, this means that the diagnostic is displayed in the InfoView under 'Messages', but that it will not be displayed under 'All Messages' and that it will also not be displayed with a squiggly line. The `isSilent` field is also implemented for `Message` so that silent diagnostics can be logged in the elaborator. All code paths except for the language server that display diagnostics to users are adjusted to filter `Message`s with `isSilent := true`.
112 lines
4.4 KiB
Text
112 lines
4.4 KiB
Text
/-
|
|
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
prelude
|
|
import Lean.Util.Sorry
|
|
import Lean.Message
|
|
|
|
namespace Lean
|
|
|
|
/--
|
|
The `MonadLog` interface for logging error messages.
|
|
-/
|
|
class MonadLog (m : Type → Type) extends MonadFileMap m where
|
|
/-- Return the current reference syntax being used to provide position information. -/
|
|
getRef : m Syntax
|
|
/-- The name of the file being processed. -/
|
|
getFileName : m String
|
|
/-- Return `true` if errors have been logged. -/
|
|
hasErrors : m Bool
|
|
/-- Log a new message. -/
|
|
logMessage : Message → m Unit
|
|
|
|
export MonadLog (getFileName logMessage)
|
|
|
|
instance (m n) [MonadLift m n] [MonadLog m] : MonadLog n where
|
|
getRef := liftM (MonadLog.getRef : m _)
|
|
getFileMap := liftM (getFileMap : m _)
|
|
getFileName := liftM (getFileName : m _)
|
|
hasErrors := liftM (MonadLog.hasErrors : m _)
|
|
logMessage := fun msg => liftM (logMessage msg : m _ )
|
|
|
|
variable [Monad m] [MonadLog m] [AddMessageContext m] [MonadOptions m]
|
|
|
|
/--
|
|
Return the position (as `String.pos`) associated with the current reference syntax (i.e., the syntax object returned by `getRef`.)
|
|
-/
|
|
def getRefPos : m String.Pos := do
|
|
let ref ← MonadLog.getRef
|
|
return ref.getPos?.getD 0
|
|
|
|
/--
|
|
Return the line and column numbers associated with the current reference syntax (i.e., the syntax object returned by `getRef`.)
|
|
-/
|
|
def getRefPosition : m Position := do
|
|
let fileMap ← getFileMap
|
|
return fileMap.toPosition (← getRefPos)
|
|
|
|
/-- If `warningAsError` is set to `true`, then warning messages are treated as errors. -/
|
|
register_builtin_option warningAsError : Bool := {
|
|
defValue := false
|
|
descr := "treat warnings as errors"
|
|
}
|
|
|
|
/--
|
|
Log the message `msgData` at the position provided by `ref` with the given `severity`.
|
|
If `getRef` has position information but `ref` does not, we use `getRef`.
|
|
We use the `fileMap` to find the line and column numbers for the error message.
|
|
-/
|
|
def logAt (ref : Syntax) (msgData : MessageData)
|
|
(severity : MessageSeverity := MessageSeverity.error) (isSilent : Bool := false) : m Unit :=
|
|
unless severity == .error && msgData.hasSyntheticSorry do
|
|
let severity := if severity == .warning && warningAsError.get (← getOptions) then .error else severity
|
|
let ref := replaceRef ref (← MonadLog.getRef)
|
|
let pos := ref.getPos?.getD 0
|
|
let endPos := ref.getTailPos?.getD pos
|
|
let fileMap ← getFileMap
|
|
let msgData ← addMessageContext msgData
|
|
logMessage {
|
|
fileName := (← getFileName)
|
|
pos := fileMap.toPosition pos
|
|
endPos := fileMap.toPosition endPos
|
|
data := msgData
|
|
severity
|
|
isSilent
|
|
}
|
|
|
|
/-- Log a new error message using the given message data. The position is provided by `ref`. -/
|
|
def logErrorAt (ref : Syntax) (msgData : MessageData) : m Unit :=
|
|
logAt ref msgData MessageSeverity.error
|
|
|
|
/-- Log a new warning message using the given message data. The position is provided by `ref`. -/
|
|
def logWarningAt [MonadOptions m] (ref : Syntax) (msgData : MessageData) : m Unit := do
|
|
logAt ref msgData .warning
|
|
|
|
/-- Log a new information message using the given message data. The position is provided by `ref`. -/
|
|
def logInfoAt (ref : Syntax) (msgData : MessageData) : m Unit :=
|
|
logAt ref msgData MessageSeverity.information
|
|
|
|
/-- Log a new error/warning/information message using the given message data and `severity`. The position is provided by `getRef`. -/
|
|
def log (msgData : MessageData) (severity : MessageSeverity := MessageSeverity.error): m Unit := do
|
|
let ref ← MonadLog.getRef
|
|
logAt ref msgData severity
|
|
|
|
/-- Log a new error message using the given message data. The position is provided by `getRef`. -/
|
|
def logError (msgData : MessageData) : m Unit :=
|
|
log msgData MessageSeverity.error
|
|
|
|
/-- Log a new warning message using the given message data. The position is provided by `getRef`. -/
|
|
def logWarning [MonadOptions m] (msgData : MessageData) : m Unit := do
|
|
log msgData (if warningAsError.get (← getOptions) then .error else .warning)
|
|
|
|
/-- Log a new information message using the given message data. The position is provided by `getRef`. -/
|
|
def logInfo (msgData : MessageData) : m Unit :=
|
|
log msgData MessageSeverity.information
|
|
|
|
/-- Log the error message "unknown declaration" -/
|
|
def logUnknownDecl (declName : Name) : m Unit :=
|
|
logError m!"unknown declaration '{declName}'"
|
|
|
|
end Lean
|