diff options
Diffstat (limited to 'compiler/sempass2.nim')
-rw-r--r-- | compiler/sempass2.nim | 86 |
1 files changed, 76 insertions, 10 deletions
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e2d45a388..0a160897f 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -11,9 +11,9 @@ import ast, astalgo, msgs, renderer, magicsys, types, idents, trees, wordrecg, options, guards, lineinfos, semfold, semdata, modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, - semstrictfuncs + semstrictfuncs, suggestsymdb, pushpoppragmas -import std/[tables, intsets, strutils] +import std/[tables, intsets, strutils, sequtils] when defined(nimPreviewSlimSystem): import std/assertions @@ -66,8 +66,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 forbids: PNode # list of tags bottom, inTryStmt, inExceptOrFinallyStmt, leftPartOfAsgn, inIfStmt, currentBlock: int @@ -81,6 +85,7 @@ type isInnerProc: bool inEnforcedNoSideEffects: bool currOptions: TOptions + optionsStack: seq[(TOptions, TNoteKinds)] config: ConfigRef graph: ModuleGraph c: PContext @@ -106,7 +111,7 @@ proc getObjDepth(t: PType): (int, ItemId) = proc collectObjectTree(graph: ModuleGraph, n: PNode) = for section in n: - if section.kind == nkTypeDef and section[^1].kind in {nkObjectTy, nkRefTy, nkPtrTy}: + if section.kind == nkTypeDef and section[^1].kind in {nkObjectTy, nkRefTy, nkPtrTy} and section[^1].typ != nil: let typ = section[^1].typ.skipTypes(skipPtrs) if typ.kind == tyObject and typ.baseClass != nil: let (depthLevel, root) = getObjDepth(typ) @@ -411,7 +416,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 = @@ -492,6 +497,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 @@ -500,12 +517,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], bsNone) + when defined(nimsuggest): + tracked.caughtExceptions.pop + var branches = 1 var hasFinally = false inc tracked.inExceptOrFinallyStmt @@ -578,9 +616,16 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) = for i in 0..<n.len: var it = n[i] let pragma = whichPragma(it) - if pragma == wEffects: + case pragma + of wEffects: # list the computed effects up to here: listEffects(tracked) + of wPush: + processPushBackendOption(tracked.c.config, tracked.optionsStack, tracked.currOptions, n, i+1) + of wPop: + processPopBackendOption(tracked.c.config, tracked.optionsStack, tracked.currOptions) + else: + discard template notGcSafe(t): untyped = {tfGcSafe, tfNoSideEffect} * t.flags == {} @@ -619,7 +664,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = if paramType != nil and tfNotNil in paramType.flags and n.typ != nil: let ntyp = n.typ.skipTypesOrNil({tyVar, tyLent, tySink}) if ntyp != nil and tfNotNil notin ntyp.flags: - if isAddrNode(n): + if n.kind in {nkAddr, nkHiddenAddr}: # addr(x[]) can't be proven, but addr(x) can: if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return elif (n.kind == nkSym and n.sym.kind in routineKinds) or @@ -917,6 +962,19 @@ proc checkForSink(tracked: PEffects; n: PNode) = if tracked.inIfStmt == 0 and optSinkInference in tracked.config.options: checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n) +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): @@ -937,6 +995,13 @@ proc trackCall(tracked: PEffects; n: PNode) = 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) + let notConstExpr = getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) == nil if notConstExpr: if a.kind == nkCast and a[1].typ.kind == tyProc: @@ -1145,9 +1210,10 @@ proc track(tracked: PEffects, n: PNode) = if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags: tracked.owner.flags.incl sfInjectDestructors # bug #15038: ensure consistency - if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ + if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ = n.sym.typ of nkHiddenAddr, nkAddr: - if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym): + if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym) and + n.typ.kind notin {tyVar, tyLent}: useVarNoInitCheck(tracked, n[0], n[0].sym) else: track(tracked, n[0]) @@ -1536,7 +1602,7 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; c: PContext): TEffects result = TEffects(exc: effects[exceptionEffects], tags: effects[tagEffects], forbids: effects[forbiddenEffects], owner: s, ownerModule: s.getModule, init: @[], locked: @[], graph: g, config: g.config, c: c, - currentBlock: 1 + currentBlock: 1, optionsStack: @[(g.config.options, g.config.notes)] ) result.guards.s = @[] result.guards.g = g @@ -1667,7 +1733,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = dataflowAnalysis(s, body) when false: trackWrites(s, body) - if strictNotNil in c.features and s.kind == skProc: + if strictNotNil in c.features and s.kind in {skProc, skFunc, skMethod, skConverter}: checkNil(s, body, g.config, c.idgen) proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) = |