Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport 1.6] + added nimsuggest support for exception inlay hints (#23202) #23421

Open
wants to merge 2 commits into
base: version-1-6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 9 additions & 16 deletions compiler/modulegraphs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.

import intsets, tables, hashes, md5, sequtils
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import intsets, tables, hashes, md5, sequtils, algorithm
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages, suggestsymdb
import ic / [packed_ast, ic]

type
Expand Down Expand Up @@ -50,11 +50,6 @@ type
concreteTypes*: seq[FullId]
inst*: PInstantiation

SymInfoPair* = object
sym*: PSym
info*: TLineInfo
isDecl*: bool

ModuleGraph* {.acyclic.} = ref object
ifaces*: seq[Iface] ## indexed by int32 fileIdx
packed*: PackedModuleGraph
Expand Down Expand Up @@ -85,7 +80,7 @@ type
doStopCompile*: proc(): bool {.closure.}
usageSym*: PSym # for nimsuggest
owners*: seq[PSym]
suggestSymbols*: Table[FileIndex, seq[SymInfoPair]]
suggestSymbols*: SuggestSymbolDatabase
suggestErrors*: Table[FileIndex, seq[Suggest]]
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
systemModule*: PSym
Expand Down Expand Up @@ -438,7 +433,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.importStack = @[]
result.inclToMod = initTable[FileIndex, FileIndex]()
result.owners = @[]
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
result.suggestSymbols = initTable[FileIndex, SuggestFileSymbolDatabase]()
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
result.methods = @[]
initStrTable(result.compilerprocs)
Expand Down Expand Up @@ -642,16 +637,14 @@ func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
## Check if symbol belongs to the 'stdlib' package.
sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId

proc `==`*(a, b: SymInfoPair): bool =
result = a.sym == b.sym and a.info.exactEquals(b.info)

proc fileSymbols*(graph: ModuleGraph, fileIdx: FileIndex): seq[SymInfoPair] =
result = graph.suggestSymbols.getOrDefault(fileIdx, @[])
proc fileSymbols*(graph: ModuleGraph, fileIdx: FileIndex): SuggestFileSymbolDatabase =
result = graph.suggestSymbols.getOrDefault(fileIdx, newSuggestFileSymbolDatabase(fileIdx, optIdeExceptionInlayHints in graph.config.globalOptions))
doAssert(result.fileIndex == fileIdx)

iterator suggestSymbolsIter*(g: ModuleGraph): SymInfoPair =
for xs in g.suggestSymbols.values:
for x in xs:
yield x
for i in xs.lineInfo.low..xs.lineInfo.high:
yield xs.getSymInfoPair(i)

iterator suggestErrorsIter*(g: ModuleGraph): Suggest =
for xs in g.suggestErrors.values:
Expand Down
2 changes: 2 additions & 0 deletions compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type # please make sure we have under 32 options
# also: generate header file
optIdeDebug # idetools: debug mode
optIdeTerse # idetools: use terse descriptions
optIdeExceptionInlayHints
optExcessiveStackTrace # fully qualified module filenames
optShowAllMismatches # show all overloading resolution candidates
optWholeProject # for 'doc': output any dependency
Expand Down Expand Up @@ -273,6 +274,7 @@ type
SuggestInlayHintKind* = enum
sihkType = "Type",
sihkParameter = "Parameter"
sihkException = "Exception"

SuggestInlayHint* = ref object
kind*: SuggestInlayHintKind
Expand Down
63 changes: 61 additions & 2 deletions compiler/sempass2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables,
suggestsymdb

when defined(useDfa):
import dfa
Expand Down Expand Up @@ -60,8 +61,12 @@ discard """
"""

type
CaughtExceptionsStack = object
nodes: seq[seq[PType]]
TEffects = object
exc: PNode # stack of exceptions
when defined(nimsuggest):
caughtExceptions: CaughtExceptionsStack
tags: PNode # list of tags
bottom, inTryStmt, inExceptOrFinallyStmt, leftPartOfAsgn: int
owner: PSym
Expand Down Expand Up @@ -347,7 +352,7 @@ proc throws(tracked, n, orig: PNode) =
else:
tracked.add n

proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
proc getEbase*(g: ModuleGraph; info: TLineInfo): PType =
result = g.sysTypeFromName(info, "Exception")

proc excType(g: ModuleGraph; n: PNode): PType =
Expand Down Expand Up @@ -423,6 +428,18 @@ proc catchesAll(tracked: PEffects) =
if tracked.exc.len > 0:
setLen(tracked.exc.sons, tracked.bottom)

proc push(s: var CaughtExceptionsStack) =
s.nodes.add(@[])

proc pop(s: var CaughtExceptionsStack) =
s.nodes.del(high(s.nodes))

proc addCatch(s: var CaughtExceptionsStack, e: PType) =
s.nodes[high(s.nodes)].add(e)

proc addCatchAll(s: var CaughtExceptionsStack) =
s.nodes[high(s.nodes)].add(nil)

proc track(tracked: PEffects, n: PNode)
proc trackTryStmt(tracked: PEffects, n: PNode) =
let oldBottom = tracked.bottom
Expand All @@ -431,12 +448,33 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
let oldState = tracked.init.len
var inter: TIntersection = @[]

when defined(nimsuggest):
tracked.caughtExceptions.push
for i in 1..<n.len:
let b = n[i]
if b.kind == nkExceptBranch:
if b.len == 1:
tracked.caughtExceptions.addCatchAll
else:
for j in 0..<b.len - 1:
if b[j].isInfixAs():
assert(b[j][1].kind == nkType)
tracked.caughtExceptions.addCatch(b[j][1].typ)
else:
assert(b[j].kind == nkType)
tracked.caughtExceptions.addCatch(b[j].typ)
else:
assert b.kind == nkFinally

inc tracked.inTryStmt
track(tracked, n[0])
dec tracked.inTryStmt
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])

when defined(nimsuggest):
tracked.caughtExceptions.pop

var branches = 1
var hasFinally = false
inc tracked.inExceptOrFinallyStmt
Expand Down Expand Up @@ -807,6 +845,19 @@ proc passedToEffectsDelayedParam(tracked: PEffects; n: PNode) =
markSideEffect(tracked, n, n.info)
]#

proc markCaughtExceptions(tracked: PEffects; g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym) =
when defined(nimsuggest):
proc internalMarkCaughtExceptions(tracked: PEffects; q: var SuggestFileSymbolDatabase; info: TLineInfo) =
var si = q.findSymInfoIndex(info)
if si != -1:
q.caughtExceptionsSet[si] = true
for w1 in tracked.caughtExceptions.nodes:
for w2 in w1:
q.caughtExceptions[si].add(w2)

if optIdeExceptionInlayHints in tracked.config.globalOptions:
internalMarkCaughtExceptions(tracked, g.suggestSymbols.mgetOrPut(info.fileIndex, newSuggestFileSymbolDatabase(info.fileIndex, true)), info)

proc trackCall(tracked: PEffects; n: PNode) =
template gcsafeAndSideeffectCheck() =
if notGcSafe(op) and not importedFromC(a):
Expand All @@ -827,6 +878,14 @@ proc trackCall(tracked: PEffects; n: PNode) =
if n.typ != nil:
if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
createTypeBoundOps(tracked, n.typ, n.info)

when defined(nimsuggest):
var actualLoc = a.info
if n.kind == nkHiddenCallConv:
actualLoc = n.info
if a.kind == nkSym:
markCaughtExceptions(tracked, tracked.graph, actualLoc, a.sym, tracked.graph.usageSym)

if getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) == nil:
if a.kind == nkCast and a[1].typ.kind == tyProc:
a = a[1]
Expand Down
50 changes: 46 additions & 4 deletions compiler/suggest.nim
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

# included from sigmatch.nim

import algorithm, sets, prefixmatches, parseutils, tables
import algorithm, sets, prefixmatches, parseutils, tables, suggestsymdb
from wordrecg import wDeprecated, wError, wAddr, wYield

when defined(nimsuggest):
Expand Down Expand Up @@ -110,6 +110,10 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo; skip
result = skipUntil(line, '`', column)
if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0:
result = 0
elif column >= 0 and line[column] == '`' and isOpeningBacktick(column):
result = skipUntil(line, '`', column + 1) + 2
if cmpIgnoreStyle(line[column + 1..column + result - 2], ident) != 0:
result = 0
elif ident[0] in linter.Letters and ident[^1] != '=':
result = identLen(line, column)
if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0:
Expand Down Expand Up @@ -260,7 +264,7 @@ proc `$`*(suggest: Suggest): string =
result.add(sep)
result.add($suggest.endCol)

proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint =
proc suggestToSuggestInlayTypeHint*(sug: Suggest): SuggestInlayHint =
SuggestInlayHint(
kind: sihkType,
line: sug.line,
Expand All @@ -272,6 +276,30 @@ proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint =
tooltip: ""
)

proc suggestToSuggestInlayExceptionHintLeft*(sug: Suggest, propagatedExceptions: seq[PType]): SuggestInlayHint =
SuggestInlayHint(
kind: sihkException,
line: sug.line,
column: sug.column,
label: "try ",
paddingLeft: false,
paddingRight: false,
allowInsert: false,
tooltip: "propagated exceptions: " & $propagatedExceptions
)

proc suggestToSuggestInlayExceptionHintRight*(sug: Suggest, propagatedExceptions: seq[PType]): SuggestInlayHint =
SuggestInlayHint(
kind: sihkException,
line: sug.line,
column: sug.column + sug.tokenLen,
label: "!",
paddingLeft: false,
paddingRight: false,
allowInsert: false,
tooltip: "propagated exceptions: " & $propagatedExceptions
)

proc suggestResult*(conf: ConfigRef; s: Suggest) =
if not isNil(conf.suggestionResultHook):
conf.suggestionResultHook(s)
Expand Down Expand Up @@ -515,7 +543,21 @@ proc isTracked*(current, trackPos: TLineInfo, tokenLen: int): bool =
if current.fileIndex==trackPos.fileIndex and current.line==trackPos.line:
let col = trackPos.col
if col >= current.col and col <= current.col+tokenLen-1:
return true
result = true
else:
result = false
else:
result = false

proc isTracked*(current, trackPos: TinyLineInfo, tokenLen: int): bool =
if current.line==trackPos.line:
let col = trackPos.col
if col >= current.col and col <= current.col+tokenLen-1:
result = true
else:
result = false
else:
result = false

when defined(nimsuggest):
# Since TLineInfo defined a == operator that doesn't include the column,
Expand Down Expand Up @@ -567,7 +609,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
## misnamed: should be 'symDeclared'
let conf = g.config
when defined(nimsuggest):
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info, isDecl: isDecl)
g.suggestSymbols.add SymInfoPair(sym: s, info: info, isDecl: isDecl), optIdeExceptionInlayHints in g.config.globalOptions

if conf.suggestVersion == 0:
if s.allUsages.len == 0:
Expand Down