.error for routines now can also have a custom error message; improve error message for 'nil' strings

This commit is contained in:
Araq 2018-09-25 00:28:39 +02:00
commit 548fc778c9
4 changed files with 33 additions and 15 deletions

View file

@ -81,6 +81,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimAshr") defineSymbol("nimAshr")
defineSymbol("nimNoNilSeqs") defineSymbol("nimNoNilSeqs")
defineSymbol("nimNoNilSeqs2") defineSymbol("nimNoNilSeqs2")
defineSymbol("nimHasUserErrors")
defineSymbol("nimHasNilSeqs") defineSymbol("nimHasNilSeqs")
for f in low(Feature)..high(Feature): for f in low(Feature)..high(Feature):

View file

@ -954,12 +954,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
recordPragma(c, it, "warning", s) recordPragma(c, it, "warning", s)
message(c.config, it.info, warnUser, s) message(c.config, it.info, warnUser, s)
of wError: of wError:
if sym != nil and sym.isRoutine: if sym != nil and (sym.isRoutine or sym.kind == skType):
# This is subtle but correct: the error *statement* is only # This is subtle but correct: the error *statement* is only
# allowed for top level statements. Seems to be easier than # allowed for top level statements. Seems to be easier than
# distinguishing properly between # distinguishing properly between
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}`` # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
noVal(c, it) if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
incl(sym.flags, sfError) incl(sym.flags, sfError)
else: else:
let s = expectStrLit(c, it) let s = expectStrLit(c, it)

View file

@ -33,7 +33,7 @@
# included from sigmatch.nim # included from sigmatch.nim
import algorithm, prefixmatches, lineinfos, pathutils import algorithm, prefixmatches, lineinfos, pathutils
from wordrecg import wDeprecated from wordrecg import wDeprecated, wError
when defined(nimsuggest): when defined(nimsuggest):
import passes, tables # importer import passes, tables # importer
@ -453,33 +453,42 @@ proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym;
isDecl: isDecl:
suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0)) suggestResult(conf, symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) = proc extractPragma(s: PSym): PNode =
var pragmaNode: PNode
if s.kind in routineKinds: if s.kind in routineKinds:
pragmaNode = s.ast[pragmasPos] result = s.ast[pragmasPos]
elif s.kind in {skType}: elif s.kind in {skType}:
# s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma] # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
pragmaNode = s.ast[0][1] result = s.ast[0][1]
doAssert result == nil or result.kind == nkPragma
doAssert pragmaNode == nil or pragmaNode.kind == nkPragma
proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) =
let pragmaNode = extractPragma(s)
if pragmaNode != nil: if pragmaNode != nil:
for it in pragmaNode: for it in pragmaNode:
if whichPragma(it) == wDeprecated and it.safeLen == 2 and if whichPragma(it) == wDeprecated and it.safeLen == 2 and
it[1].kind in {nkStrLit..nkTripleStrLit}: it[1].kind in {nkStrLit..nkTripleStrLit}:
message(conf, info, warnDeprecated, it[1].strVal & "; " & s.name.s) message(conf, info, warnDeprecated, it[1].strVal & "; " & s.name.s)
return return
message(conf, info, warnDeprecated, s.name.s) message(conf, info, warnDeprecated, s.name.s)
proc userError(conf: ConfigRef; info: TLineInfo; s: PSym) =
let pragmaNode = extractPragma(s)
if pragmaNode != nil:
for it in pragmaNode:
if whichPragma(it) == wError and it.safeLen == 2 and
it[1].kind in {nkStrLit..nkTripleStrLit}:
localError(conf, info, it[1].strVal & "; usage of '$1' is a user-defined error" % s.name.s)
return
localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s)
proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
if s.kind == skEnumField and s.owner != nil: if s.kind == skEnumField and s.owner != nil:
incl(s.owner.flags, sfUsed) incl(s.owner.flags, sfUsed)
if {sfDeprecated, sfError} * s.flags != {}: if {sfDeprecated, sfError} * s.flags != {}:
if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s) if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s)
if sfError in s.flags: localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s) if sfError in s.flags: userError(conf, info, s)
when defined(nimsuggest): when defined(nimsuggest):
suggestSym(conf, info, s, usageSym, false) suggestSym(conf, info, s, usageSym, false)

View file

@ -4112,8 +4112,16 @@ proc `==`*(x, y: cstring): bool {.magic: "EqCString", noSideEffect,
when defined(nimNoNilSeqs2): when defined(nimNoNilSeqs2):
when not compileOption("nilseqs"): when not compileOption("nilseqs"):
proc `==`*(x: string; y: type(nil)): bool {.error.} = discard when defined(nimHasUserErrors):
proc `==`*(x: type(nil); y: string): bool {.error.} = discard proc `==`*(x: string; y: type(nil)): bool {.
error: "'nil' is now invalid for 'string'; compile with --nilseqs:on for a migration period".} =
discard
proc `==`*(x: type(nil); y: string): bool {.
error: "'nil' is now invalid for 'string'; compile with --nilseqs:on for a migration period".} =
discard
else:
proc `==`*(x: string; y: type(nil)): bool {.error.} = discard
proc `==`*(x: type(nil); y: string): bool {.error.} = discard
template closureScope*(body: untyped): untyped = template closureScope*(body: untyped): untyped =
## Useful when creating a closure in a loop to capture local loop variables by ## Useful when creating a closure in a loop to capture local loop variables by