feat: adjust message range on unexpected token error

This commit is contained in:
Sebastian Ullrich 2023-08-04 12:48:04 +02:00
parent 6c0baf4aed
commit e580c903e6
5 changed files with 69 additions and 15 deletions

View file

@ -208,13 +208,15 @@ end MessageData
/-- A `Message` is a richly formatted piece of information emitted by Lean.
They are rendered by client editors in the infoview and in diagnostic windows. -/
structure Message where
fileName : String
pos : Position
endPos : Option Position := none
severity : MessageSeverity := MessageSeverity.error
caption : String := ""
fileName : String
pos : Position
endPos : Option Position := none
/-- If `true`, report range as given; see `msgToInteractiveDiagnostic`. -/
keepFullRange : Bool := false
severity : MessageSeverity := MessageSeverity.error
caption : String := ""
/-- The content of the message. -/
data : MessageData
data : MessageData
deriving Inhabited
namespace Message

View file

@ -32,9 +32,17 @@ structure ModuleParserState where
recovering : Bool := false
deriving Inhabited
private def mkErrorMessage (c : InputContext) (pos : String.Pos) (errorMsg : String) : Message :=
let pos := c.fileMap.toPosition pos
{ fileName := c.fileName, pos := pos, data := errorMsg }
private def mkErrorMessage (c : InputContext) (s : ParserState) (e : Parser.Error) : Message := Id.run do
let mut pos := c.fileMap.toPosition s.pos
if e.stopPos?.isSome then
if let .original (trailing := trailing) .. := s.stxStack.back.getTailInfo then
if trailing.stopPos == s.pos then
pos := c.fileMap.toPosition trailing.startPos
{ fileName := c.fileName
pos
endPos := c.fileMap.toPosition <$> e.stopPos?
keepFullRange := true
data := toString e }
def parseHeader (inputCtx : InputContext) : IO (Syntax × ModuleParserState × MessageLog) := do
let dummyEnv ← mkEmptyEnvironment
@ -44,7 +52,7 @@ def parseHeader (inputCtx : InputContext) : IO (Syntax × ModuleParserState × M
let stx := if s.stxStack.isEmpty then .missing else s.stxStack.back
match s.errorMsg with
| some errorMsg =>
let msg := mkErrorMessage inputCtx s.pos (toString errorMsg)
let msg := mkErrorMessage inputCtx s errorMsg
pure (stx, { pos := s.pos, recovering := true }, { : MessageLog }.add msg)
| none =>
pure (stx, { pos := s.pos }, {})
@ -96,7 +104,7 @@ partial def parseCommand (inputCtx : InputContext) (pmctx : ParserModuleContext)
We claim a syntactically incorrect command containing no token or identifier is irrelevant for intellisense and should be ignored. -/
let ignore := s.stxStack.isEmpty || s.stxStack.back.getPos?.isNone
unless recovering && ignore do
messages := messages.add <| mkErrorMessage inputCtx s.pos (toString errorMsg)
messages := messages.add <| mkErrorMessage inputCtx s errorMsg
recovering := true
if ignore then
continue

View file

@ -174,10 +174,8 @@ def msgToInteractiveDiagnostic (text : FileMap) (m : Message) (hasWidgets : Bool
| some endPos =>
/-
Truncate messages that are more than one line long.
This is a workaround to avoid big blocks of "red squiggly lines" on VS Code.
TODO: should it be a parameter?
-/
let endPos := if endPos.line > m.pos.line then { line := m.pos.line + 1, column := 0 } else endPos
This is a workaround to avoid big blocks of "red squiggly lines" on VS Code. -/
let endPos := if !m.keepFullRange && endPos.line > m.pos.line then { line := m.pos.line + 1, column := 0 } else endPos
text.leanPosToLspPos endPos
| none => low
let range : Range := ⟨low, high⟩

41
tests/lean/1971.lean Normal file
View file

@ -0,0 +1,41 @@
/-!
# More helpful ranges of parser error messages on unexpected tokens
When the parser hits an unexpected token, it will now include all preceding
whitespace in the error message range as the expected token could be inserted
at any of these places to fix the error. -/
/-!
In the following example, we want the parser error to start right after
`exact` as the error belongs to this declaration, not the next one, and
otherwise would be too easy to overlook. -/
theorem lem1 : True := by
exact
theorem lem2 : True := ⟨⟩
/-!
Outside of tactics as well it is generally a better idea to place the error
right after the last correct token. -/
def f1
def f2 := 0
/-!
We do not currently special-case linebreaks in this; on a single line,
the shift is usually not very noticeable nor clearly worse than before. -/
def f3 := def f4 := 0
/-! Test other expected token errors as well -/
inductive
example := 0
-- merge of token errors
set_option pp.all
example := 0

View file

@ -0,0 +1,5 @@
1971.lean:14:7-16:7: error: expected term
1971.lean:22:6-24:3: error: expected ':=', 'where' or '|'
1971.lean:30:9-30:13: error: expected term
1971.lean:34:9-36:7: error: expected identifier
1971.lean:39:17-41:7: error: expected 'false', 'true', numeral or string literal