mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-22 23:35:22 +00:00
nicer error messages (untested)
This commit is contained in:
@@ -40,8 +40,7 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
||||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||
proc tryExpr(c: PContext, n: PNode,
|
||||
flags: TExprFlags = {}, bufferErrors = false): PNode
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc fixImmediateParams(n: PNode): PNode
|
||||
proc activate(c: PContext, n: PNode)
|
||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||
|
||||
@@ -39,7 +39,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
initialBinding: PNode,
|
||||
filter: TSymKinds,
|
||||
best, alt: var TCandidate,
|
||||
errors: var seq[string]) =
|
||||
errors: var CandidateErrors) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var symScope = o.lastOverloadScope
|
||||
@@ -58,10 +58,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
z.calleeSym = sym
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(getProcHeader(sym))
|
||||
errors.safeAdd(sym)
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors[errors.len - 1].add("\n " & err)
|
||||
errors.add(err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||
@@ -74,7 +74,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
else: discard
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
@@ -83,18 +83,39 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
if errors.len == 0:
|
||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1))
|
||||
add(result, ')')
|
||||
|
||||
# to avoid confusing errors like:
|
||||
# got (SslPtr, SocketHandle)
|
||||
# but expected one of:
|
||||
# openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
|
||||
# we do a pre-analysis. If all types produce the same string, we will add
|
||||
# module information.
|
||||
let proto = describeArgs(c, n, 1, preferName)
|
||||
|
||||
var prefer = preferName
|
||||
for err in errors:
|
||||
var errProto = "("
|
||||
let n = err.typ.n
|
||||
for i in countup(1, n.len - 1):
|
||||
var p = n.sons[i]
|
||||
if p.kind == nkSym:
|
||||
add(errProto, typeToString(p.sym.typ, prefer))
|
||||
if i != n.len-1: add(errProto, ", ")
|
||||
# else: ignore internal error as we're already in error handling mode
|
||||
add(errProto, ')')
|
||||
if errProto == proto:
|
||||
prefer = preferModuleInfo
|
||||
break
|
||||
# now use the information stored in 'prefer' to produce a nice error message:
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1, prefer))
|
||||
add(result, ')')
|
||||
var candidates = ""
|
||||
for err in errors:
|
||||
add(candidates, err)
|
||||
add(candidates, err.getProcHeader(prefer))
|
||||
add(candidates, "\n")
|
||||
|
||||
if candidates != "":
|
||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||
|
||||
localError(n.info, errGenerated, result)
|
||||
|
||||
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
|
||||
@@ -114,7 +135,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
else:
|
||||
initialBinding = nil
|
||||
|
||||
var errors: seq[string]
|
||||
var errors: CandidateErrors
|
||||
var usedSyms: seq[PNode]
|
||||
|
||||
template pickBest(headSymbol: expr) =
|
||||
|
||||
@@ -72,8 +72,7 @@ type
|
||||
libs*: TLinkedList # all libs used by this module
|
||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
|
||||
bufferErrors = false): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
|
||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||
|
||||
@@ -1551,8 +1551,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
newNode(nkCall, n.info, quotes)])
|
||||
result = semExpandToAst(c, result)
|
||||
|
||||
proc tryExpr(c: PContext, n: PNode,
|
||||
flags: TExprFlags = {}, bufferErrors = false): PNode =
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# watch out, hacks ahead:
|
||||
let oldErrorCount = msgs.gErrorCounter
|
||||
let oldErrorMax = msgs.gErrorMax
|
||||
@@ -1566,7 +1565,7 @@ proc tryExpr(c: PContext, n: PNode,
|
||||
let oldOwnerLen = len(gOwners)
|
||||
let oldGenerics = c.generics
|
||||
let oldErrorOutputs = errorOutputs
|
||||
errorOutputs = if bufferErrors: {eInMemory} else: {}
|
||||
#errorOutputs = if bufferErrors: {eInMemory} else: {}
|
||||
let oldContextLen = msgs.getInfoContextLen()
|
||||
|
||||
let oldInGenericContext = c.inGenericContext
|
||||
|
||||
@@ -22,6 +22,7 @@ type
|
||||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
|
||||
CandidateErrors* = seq[PSym]
|
||||
TCandidate* {.final.} = object
|
||||
c*: PContext
|
||||
exactMatches*: int # also misused to prefer iters over procs
|
||||
@@ -45,7 +46,7 @@ type
|
||||
# a distrinct type
|
||||
typedescMatched: bool
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
errors*: seq[string] # additional clarifications to be displayed to the
|
||||
errors*: CandidateErrors # additional clarifications to be displayed to the
|
||||
# user if overload resolution fails
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
@@ -202,16 +203,17 @@ proc writeMatches*(c: TCandidate) =
|
||||
writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||
writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||
|
||||
proc argTypeToString(arg: PNode): string =
|
||||
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||
if arg.kind in nkSymChoices:
|
||||
result = typeToString(arg[0].typ)
|
||||
result = typeToString(arg[0].typ, prefer)
|
||||
for i in 1 .. <arg.len:
|
||||
result.add(" | ")
|
||||
result.add typeToString(arg[i].typ)
|
||||
result.add typeToString(arg[i].typ, prefer)
|
||||
else:
|
||||
result = arg.typ.typeToString
|
||||
result = arg.typ.typeToString(prefer)
|
||||
|
||||
proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||
proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||
prefer: TPreferedDesc = preferName): string =
|
||||
result = ""
|
||||
for i in countup(startIdx, n.len - 1):
|
||||
var arg = n.sons[i]
|
||||
@@ -227,7 +229,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||
arg = c.semOperand(c, n.sons[i])
|
||||
n.sons[i] = arg
|
||||
if arg.typ.kind == tyError: return
|
||||
add(result, argTypeToString(arg))
|
||||
add(result, argTypeToString(arg, prefer))
|
||||
if i != sonsLen(n) - 1: add(result, ", ")
|
||||
|
||||
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
||||
@@ -480,8 +482,8 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
dummyParam.typ = dummyType
|
||||
addDecl(c, dummyParam)
|
||||
|
||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree, bufferErrors = false)
|
||||
m.errors = bufferedMsgs
|
||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
||||
#m.errors = bufferedMsgs
|
||||
clearBufferedMsgs()
|
||||
if checkedBody == nil: return isNone
|
||||
|
||||
|
||||
@@ -16,11 +16,10 @@ proc firstOrd*(t: PType): BiggestInt
|
||||
proc lastOrd*(t: PType): BiggestInt
|
||||
proc lengthOrd*(t: PType): BiggestInt
|
||||
type
|
||||
TPreferedDesc* = enum
|
||||
preferName, preferDesc, preferExported
|
||||
TPreferedDesc* = enum
|
||||
preferName, preferDesc, preferExported, preferModuleInfo
|
||||
|
||||
proc typeToString*(typ: PType, prefer: TPreferedDesc = preferName): string
|
||||
proc getProcHeader*(sym: PSym): string
|
||||
proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
|
||||
proc base*(t: PType): PType
|
||||
# ------------------- type iterator: ----------------------------------------
|
||||
type
|
||||
@@ -121,7 +120,7 @@ proc isCompatibleToCString(a: PType): bool =
|
||||
(a.sons[1].kind == tyChar):
|
||||
result = true
|
||||
|
||||
proc getProcHeader(sym: PSym): string =
|
||||
proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
|
||||
result = sym.owner.name.s & '.' & sym.name.s & '('
|
||||
var n = sym.typ.n
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
@@ -129,13 +128,14 @@ proc getProcHeader(sym: PSym): string =
|
||||
if p.kind == nkSym:
|
||||
add(result, p.sym.name.s)
|
||||
add(result, ": ")
|
||||
add(result, typeToString(p.sym.typ))
|
||||
add(result, typeToString(p.sym.typ, prefer))
|
||||
if i != sonsLen(n)-1: add(result, ", ")
|
||||
else:
|
||||
internalError("getProcHeader")
|
||||
add(result, ')')
|
||||
if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ))
|
||||
|
||||
if n.sons[0].typ != nil:
|
||||
result.add(": " & typeToString(n.sons[0].typ, prefer))
|
||||
|
||||
proc elemType*(t: PType): PType =
|
||||
assert(t != nil)
|
||||
case t.kind
|
||||
@@ -415,10 +415,14 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
var t = typ
|
||||
result = ""
|
||||
if t == nil: return
|
||||
if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags:
|
||||
if prefer in {preferName, preferModuleInfo} and t.sym != nil and
|
||||
sfAnon notin t.sym.flags:
|
||||
if t.kind == tyInt and isIntLit(t):
|
||||
return t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||
return t.sym.name.s
|
||||
if prefer == preferName:
|
||||
return t.sym.name.s
|
||||
else:
|
||||
return t.sym.skipGenericOwner.name.s & '.' & t.sym.name.s
|
||||
case t.kind
|
||||
of tyInt:
|
||||
if not isIntLit(t) or prefer == preferExported:
|
||||
@@ -492,8 +496,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
result = "set[" & typeToString(t.sons[0]) & ']'
|
||||
of tyOpenArray:
|
||||
result = "openarray[" & typeToString(t.sons[0]) & ']'
|
||||
of tyDistinct:
|
||||
result = "distinct " & typeToString(t.sons[0], preferName)
|
||||
of tyDistinct:
|
||||
result = "distinct " & typeToString(t.sons[0],
|
||||
if prefer == preferModuleInfo: preferModuleInfo else: preferName)
|
||||
of tyTuple:
|
||||
# we iterate over t.sons here, because t.n may be nil
|
||||
result = "tuple["
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
{.push hints: off.}
|
||||
|
||||
include "system/inclrtl.nim"
|
||||
include "system/hti.nim"
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -57,7 +57,7 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
|
||||
## may contain a path that will be created.
|
||||
assert(z.mode != fmRead)
|
||||
if not fileExists(src):
|
||||
raise newException(EIO, "File '" & src & "' does not exist")
|
||||
raise newException(IOError, "File '" & src & "' does not exist")
|
||||
var zipsrc = zip_source_file(z.w, src, 0, -1)
|
||||
if zipsrc == nil:
|
||||
#echo("Dest: " & dest)
|
||||
|
||||
@@ -2030,16 +2030,17 @@ when not defined(nimrodVM) and hostOS != "standalone":
|
||||
## returns an informative string about the GC's activity. This may be useful
|
||||
## for tweaking.
|
||||
|
||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
||||
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
||||
# XXX mark these as 'locks: 0' once 0.10.0 has been released
|
||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", gcsafe.}
|
||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", gcsafe.}
|
||||
proc GC_ref*(x: string) {.magic: "GCref", gcsafe.}
|
||||
## marks the object `x` as referenced, so that it will not be freed until
|
||||
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
||||
## n calls to `GC_unref` are needed to unmark `x`.
|
||||
|
||||
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
||||
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||
proc GC_unref*[T](x: ref T) {.magic: "GCunref", gcsafe.}
|
||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", gcsafe.}
|
||||
proc GC_unref*(x: string) {.magic: "GCunref", gcsafe.}
|
||||
## see the documentation of `GC_ref`.
|
||||
|
||||
template accumulateResult*(iter: expr) =
|
||||
@@ -2178,9 +2179,14 @@ when not declared(sysFatal):
|
||||
e.msg = message & arg
|
||||
raise e
|
||||
|
||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
|
||||
## get type information for `x`. Ordinary code should not use this, but
|
||||
## the `typeinfo` module instead.
|
||||
when defined(nimlocks):
|
||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe, locks: 0.}
|
||||
## get type information for `x`. Ordinary code should not use this, but
|
||||
## the `typeinfo` module instead.
|
||||
else:
|
||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe.}
|
||||
## get type information for `x`. Ordinary code should not use this, but
|
||||
## the `typeinfo` module instead.
|
||||
|
||||
{.push stackTrace: off.}
|
||||
proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} =
|
||||
@@ -2379,7 +2385,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||
|
||||
when not defined(booting):
|
||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
||||
tags: [WriteIOEffect], benign.}
|
||||
tags: [WriteIOEffect], gcsafe, locks: 0.}
|
||||
## writes the values `x` to `f` and then writes "\n".
|
||||
## May throw an IO exception.
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user