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

nim check: make error msgs less redundant with nkError #709

Draft
wants to merge 10 commits into
base: devel
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ type
nfExecuteOnReload # A top-level statement that will be executed during reloads
nfLastRead # this node is a last read
nfFirstWrite# this node is a first write
nfErrorShown # error already shown

TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: ~40)
Expand Down
9 changes: 7 additions & 2 deletions compiler/errorhandling.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ proc errorSubNode*(n: PNode): PNode =
if result != nil: break

proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
assert wrongNode.kind != nkError
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
Expand All @@ -43,7 +42,6 @@ proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
for a in args: result.add a

proc newError*(wrongNode: PNode; msg: string): PNode =
assert wrongNode.kind != nkError
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
Expand All @@ -52,6 +50,13 @@ proc newError*(wrongNode: PNode; msg: string): PNode =
result.add newIntNode(nkIntLit, ord(CustomError))
result.add newStrNode(msg, wrongNode.info)

proc newErrorShown*(wrongNode: PNode = nil): PNode =
if wrongNode == nil:
result = newNodeIT(nkError, PNode.default.info.type.default, newType(tyError, ItemId(module: -1, item: -1), nil))
else:
result = newError(wrongNode, "already shown D20210428T104841")
result.flags.incl nfErrorShown

proc errorToString*(config: ConfigRef; n: PNode): string =
assert n.kind == nkError
assert n.len > 1
Expand Down
7 changes: 7 additions & 0 deletions compiler/hlo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,20 @@ proc hlo(c: PContext, n: PNode): PNode =
else:
# perform type checking, so that the replacement still fits:
if isEmptyType(n.typ) and isEmptyType(result.typ):
# dbg n.typ, result.typ
discard
else:
# dbg n.typ, c.config$n.info
result = fitNode(c, n.typ, result, n.info)
# dbg result.kind
# optimization has been applied so check again:
# dbg result.kind, c.config$n.info
result = commonOptimizations(c.graph, c.idgen, c.module, result)
# dbg result.kind
result = hlo(c, result)
# dbg result.kind
result = commonOptimizations(c.graph, c.idgen, c.module, result)
# dbg result.kind

proc hloBody(c: PContext, n: PNode): PNode =
# fast exit:
Expand Down
1 change: 1 addition & 0 deletions compiler/lookups.nim
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr
# prevent excessive errors for 'nim check'
c.recursiveDep = ""
localError(c.config, info, errGenerated, err)
# echo getStacktrace()

proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym =
var extra = ""
Expand Down
5 changes: 5 additions & 0 deletions compiler/msgs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import
options, strutils, os, tables, ropes, terminal, macros,
lineinfos, pathutils
import ast
import std/private/miscdollars
import strutils2

Expand Down Expand Up @@ -592,6 +593,10 @@ template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "")
template localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doNothing, instLoc())

template localErrorShown*(conf: ConfigRef; info: TLineInfo, arg: string): PNode =
liMessage(conf, info, errGenerated, arg, doNothing, instLoc())
newErrorShown(nil)

template message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing, instLoc())

Expand Down
3 changes: 2 additions & 1 deletion compiler/renderer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1694,7 +1694,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkError:
putWithSpace(g, tkSymbol, "error")
#gcomma(g, n, c)
gsub(g, n[0], c)
if n.len > 0:
gsub(g, n[0], c)
else:
#nkNone, nkExplicitTypeListCall:
internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')')
Expand Down
1 change: 1 addition & 0 deletions compiler/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =


proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
# dbg arg.typ, formal, arg.kind
if arg.typ.isNil:
localError(c.config, arg.info, "expression has no type: " &
renderTree(arg, {renderNoComments}))
Expand Down
12 changes: 10 additions & 2 deletions compiler/semcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# included from sem.nim

from algorithm import sort
import errorhandling

proc sameMethodDispatcher(a, b: PSym): bool =
result = false
Expand Down Expand Up @@ -268,7 +269,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):

const
errTypeMismatch = "type mismatch: got <"
errButExpected = "but expected one of: "
errButExpected = "but expected one of:"
errUndeclaredField = "undeclared field: '$1'"
errUndeclaredRoutine = "attempting to call undeclared routine: '$1'"
errBadRoutine = "attempting to call routine: '$1'$2"
Expand Down Expand Up @@ -337,7 +338,9 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
discard
else:
typeHint = " for type " & getProcHeader(c.config, sym)
result = errUndeclaredField % ident & typeHint & " " & result
if result.len > 0:
result = " " & result
result = errUndeclaredField % ident & typeHint & result
else:
if result.len == 0: result = errUndeclaredRoutine % ident
else: result = errBadRoutine % [ident, result]
Expand Down Expand Up @@ -413,6 +416,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
if efNoUndeclared notin flags: # for tests/pragmas/tcustom_pragma.nim
# xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident)
localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f))
result.errorNode = newError(n, "D20210428T023435")
result.errorNode.flags.incl nfErrorShown
return
elif result.state != csMatch:
if nfExprCall in n.flags:
Expand Down Expand Up @@ -568,6 +573,9 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags): PNode {.nosinks.} =
var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
if r.errorNode != nil:
assert r.errorNode.kind == nkError
return r.errorNode
if r.state == csMatch:
# this may be triggered, when the explain pragma is used
if errors.len > 0:
Expand Down
77 changes: 38 additions & 39 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

when defined(nimCompilerStackraceHints):
import std/stackframes

import errorhandling
const
errExprXHasNoType = "expression '$1' has no type (or is ambiguous)"
errXExpectsTypeOrValue = "'$1' expects a type or value"
Expand Down Expand Up @@ -60,56 +60,45 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyVoid, c)
else:
localError(c.config, n.info, errExprXHasNoType %
result = localErrorShown(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)

proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
rejectEmptyNode(n)
result = semExpr(c, n, flags+{efWantValue})

let
isEmpty = result.kind == nkEmpty
isTypeError = result.typ != nil and result.typ.kind == tyError

if isEmpty or isTypeError:
# bug #12741, redundant error messages are the lesser evil here:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))

if isEmpty:
# do not produce another redundant error message:
result = errorNode(c, n)
if result.kind == nkEmpty or (result.typ != nil and result.typ.kind == tyError):
result = newError(result, "D20210428T103116") # PRTEMP
# result = newErrorShown(result)

proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExprCheck(c, n, flags)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
elif result.kind == nkError:
if nfErrorShown notin result.flags:
localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments}))
result.flags.incl nfErrorShown # PRTEMP FACTOR
elif result.typ == nil or result.typ == c.enforceVoidContext:
localError(c.config, n.info, errExprXHasNoType %
result = localErrorShown(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
elif result.typ.kind == tyError:
# associates the type error to the current owner
result.typ = errorType(c)
doAssert false
else:
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)

proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExprCheck(c, n, flags)
if result.typ == nil:
localError(c.config, n.info, errExprXHasNoType %
result = localErrorShown(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)

proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scClosed)

proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} =
result = copyTree(s.ast)
if result.isNil:
localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
result = newSymNode(s)
result = localErrorShown(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
else:
result.typ = s.typ
result.info = n.info
Expand Down Expand Up @@ -260,8 +249,7 @@ proc isOwnedSym(c: PContext; n: PNode): bool =

proc semConv(c: PContext, n: PNode): PNode =
if n.len != 2:
localError(c.config, n.info, "a type conversion takes exactly one argument")
return n
result = localErrorShown(c.config, n.info, "a type conversion takes exactly one argument")

result = newNodeI(nkConv, n.info)

Expand Down Expand Up @@ -302,7 +290,7 @@ proc semConv(c: PContext, n: PNode): PNode =
# special case to make MyObject(x = 3) produce a nicer error message:
if n[1].kind == nkExprEqExpr and
targetType.skipTypes(abstractPtrs).kind == tyObject:
localError(c.config, n.info, "object construction uses ':', not '='")
return localErrorShown(c.config, n.info, "object construction uses ':', not '='")
var op = semExprWithType(c, n[1])
if targetType.kind != tyGenericParam and targetType.isMetaType:
let final = inferWithMetatype(c, targetType, op, true)
Expand Down Expand Up @@ -333,12 +321,12 @@ proc semConv(c: PContext, n: PNode): PNode =
of convNotLegal:
result = fitNode(c, result.typ, result[1], result.info)
if result == nil:
localError(c.config, n.info, "illegal conversion from '$1' to '$2'" %
return localErrorShown(c.config, n.info, "illegal conversion from '$1' to '$2'" %
[op.typ.typeToString, result.typ.typeToString])
of convNotInRange:
let value =
if op.kind in {nkCharLit..nkUInt64Lit}: $op.getInt else: $op.getFloat
localError(c.config, n.info, errGenerated, value & " can't be converted to " &
return localErrorShown(c.config, n.info, value & " can't be converted to " &
result.typ.typeToString)
else:
for i in 0..<op.len:
Expand All @@ -357,12 +345,12 @@ proc semCast(c: PContext, n: PNode): PNode =
let targetType = semTypeNode(c, n[0], nil)
let castedExpr = semExprWithType(c, n[1])
if tfHasMeta in targetType.flags:
localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
return localErrorShown(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
if not isCastable(c, targetType, castedExpr.typ):
let tar = $targetType
let alt = typeToString(targetType, preferDesc)
let msg = if tar != alt: tar & "=" & alt else: tar
localError(c.config, n.info, "expression cannot be cast to " & msg)
return localErrorShown(c.config, n.info, "expression cannot be cast to " & msg)
result = newNodeI(nkCast, n.info)
result.typ = targetType
result.add copyTree(n[0])
Expand All @@ -372,7 +360,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
const
opToStr: array[mLow..mHigh, string] = ["low", "high"]
if n.len != 2:
localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m])
return localErrorShown(c.config, n.info, errXExpectsTypeOrValue % opToStr[m])
else:
n[1] = semExprWithType(c, n[1], {efDetermineType})
var typ = skipTypes(n[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
Expand All @@ -391,7 +379,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
# that could easily turn into an infinite recursion in semtypinst
n.typ = makeTypeFromExpr(c, n.copyTree)
else:
localError(c.config, n.info, "invalid argument for: " & opToStr[m])
return localErrorShown(c.config, n.info, "invalid argument for: " & opToStr[m])

result = n

proc fixupStaticType(c: PContext, n: PNode) =
Expand Down Expand Up @@ -458,7 +447,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =

proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len != 3:
localError(c.config, n.info, "'is' operator takes 2 arguments")
return localErrorShown(c.config, n.info, "'is' operator takes 2 arguments")

let boolType = getSysType(c.graph, n.info, tyBool)
result = n
Expand Down Expand Up @@ -596,7 +585,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
if x.kind == nkExprColonExpr and x.len == 2:
var idx = semConstExpr(c, x[0])
if not isOrdinalType(idx.typ):
localError(c.config, idx.info, "expected ordinal value for array " &
return localErrorShown(c.config, idx.info, "expected ordinal value for array " &
"index, got '$1'" % renderTree(idx))
else:
firstIndex = getOrdValue(idx)
Expand All @@ -613,15 +602,15 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
if lastIndex == lastValidIndex:
let validIndex = makeRangeType(c, toInt64(firstIndex), toInt64(lastValidIndex), n.info,
indexType)
localError(c.config, n.info, "size of array exceeds range of index " &
return localErrorShown(c.config, n.info, "size of array exceeds range of index " &
"type '$1' by $2 elements" % [typeToString(validIndex), $(n.len-i)])

x = n[i]
if x.kind == nkExprColonExpr and x.len == 2:
var idx = semConstExpr(c, x[0])
idx = fitNode(c, indexType, idx, x.info)
if lastIndex+1 != getOrdValue(idx):
localError(c.config, x.info, "invalid order in array constructor")
return localErrorShown(c.config, x.info, "invalid order in array constructor")
x = x[1]

let xx = semExprWithType(c, x, flags*{efAllowDestructor})
Expand Down Expand Up @@ -693,7 +682,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
result.add n
if isAssignable(c, n) notin {arLValue, arLocalLValue}:
localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n))
return localErrorShown(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n))

proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
result = n
Expand Down Expand Up @@ -870,6 +859,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
{skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags)

if result != nil:
if result.kind == nkError: return result
if result[0].kind != nkSym:
internalError(c.config, "semOverloadedCallAnalyseEffects")
return
Expand Down Expand Up @@ -1025,7 +1015,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# See bug #904 of how to trigger it:
return result
#result = afterCallActions(c, result, nOrig, flags)
if result[0].kind == nkSym:
if result.kind == nkError:
discard
elif result[0].kind == nkSym:
result = afterCallActions(c, result, nOrig, flags)
else:
fixAbstractType(c, result)
Expand Down Expand Up @@ -2808,6 +2800,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of skProc, skFunc, skMethod, skConverter, skIterator:
if s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
of skUnknown:
# `errorNode` uses `skEmpty`
# which causes redundant errors in D20210426T153714 for `let a = nonexistant`,
# because nim can't distinguish with `let a {.importc:"foo".}` which is valid.
result = newError(n, "D20210427T212052.1")
result.flags.incl nfErrorShown # hacky, instead `errorSym` should do this
# dbg result.flags, cast[int](result)
else:
#liMessage(n.info, warnUser, renderTree(n));
result = semIndirectOp(c, n, flags)
Expand Down
9 changes: 8 additions & 1 deletion compiler/sempass2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,14 @@ proc track(tracked: PEffects, n: PNode) =
for i in 1 ..< n.len: track(tracked, n[i])
inc tracked.leftPartOfAsgn
of nkError:
localError(tracked.config, n.info, errorToString(tracked.config, n))
discard
# echo "in nkError D20210428T112031" # PRTEMP
# dbg n.flags, tracked.config$n.info
# if nfErrorShown notin n.flags:
# localError(tracked.config, n.info, errorToString(tracked.config, n))
# dbg cast[int](n), n.flags, tracked.config$n.info, n
# n.flags.incl nfErrorShown
# # echo getStacktrace()
else:
for i in 0..<n.safeLen: track(tracked, n[i])

Expand Down
2 changes: 2 additions & 0 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
checkNilable(c, v)
# allow let to not be initialised if imported from C:
if v.kind == skLet and sfImportc notin v.flags:
# D20210426T153714:here
# dbg a.kind, v.kind, def, def.kind
localError(c.config, a.info, errLetNeedsInit)
if sfCompileTime in v.flags:
var x = newNodeI(result.kind, v.info)
Expand Down
Loading