nicer error messages (untested)

This commit is contained in:
Araq
2014-10-26 19:54:43 +01:00
parent fdf996925b
commit 7a48942719
9 changed files with 82 additions and 50 deletions

View File

@@ -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

View File

@@ -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) =

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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["

View File

@@ -13,6 +13,7 @@
{.push hints: off.}
include "system/inclrtl.nim"
include "system/hti.nim"
{.pop.}

View File

@@ -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)

View File

@@ -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: