less verbose type mismatch messages (#21191)
* less verbose type mismatch messages * Update compiler/types.nim * fixes i386 * fixes i386
This commit is contained in:
parent
646932b3f3
commit
761c5a0830
7 changed files with 105 additions and 27 deletions
|
|
@ -135,6 +135,8 @@
|
||||||
|
|
||||||
- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection.
|
- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection.
|
||||||
|
|
||||||
|
- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
|
||||||
|
|
||||||
## Standard library additions and changes
|
## Standard library additions and changes
|
||||||
|
|
||||||
[//]: # "Changes:"
|
[//]: # "Changes:"
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,7 @@ type
|
||||||
## are not anymore.
|
## are not anymore.
|
||||||
laxEffects
|
laxEffects
|
||||||
## Lax effects system prior to Nim 2.0.
|
## Lax effects system prior to Nim 2.0.
|
||||||
|
verboseTypeMismatch
|
||||||
|
|
||||||
SymbolFilesOption* = enum
|
SymbolFilesOption* = enum
|
||||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
## This module implements semantic checking for calls.
|
## This module implements semantic checking for calls.
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
from algorithm import sort
|
from std/algorithm import sort
|
||||||
|
|
||||||
|
|
||||||
proc sameMethodDispatcher(a, b: PSym): bool =
|
proc sameMethodDispatcher(a, b: PSym): bool =
|
||||||
result = false
|
result = false
|
||||||
|
|
@ -192,7 +193,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
# argument in order to remove plenty of candidates. This is
|
# argument in order to remove plenty of candidates. This is
|
||||||
# comparable to what C# does and C# is doing fine.
|
# comparable to what C# does and C# is doing fine.
|
||||||
var filterOnlyFirst = false
|
var filterOnlyFirst = false
|
||||||
if optShowAllMismatches notin c.config.globalOptions:
|
if optShowAllMismatches notin c.config.globalOptions and verboseTypeMismatch in c.config.legacyFeatures:
|
||||||
for err in errors:
|
for err in errors:
|
||||||
if err.firstMismatch.arg > 1:
|
if err.firstMismatch.arg > 1:
|
||||||
filterOnlyFirst = true
|
filterOnlyFirst = true
|
||||||
|
|
@ -208,6 +209,10 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
if filterOnlyFirst and err.firstMismatch.arg == 1:
|
if filterOnlyFirst and err.firstMismatch.arg == 1:
|
||||||
inc skipped
|
inc skipped
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if verboseTypeMismatch notin c.config.legacyFeatures:
|
||||||
|
candidates.add "[" & $err.firstMismatch.arg & "] "
|
||||||
|
|
||||||
if err.sym.kind in routineKinds and err.sym.ast != nil:
|
if err.sym.kind in routineKinds and err.sym.ast != nil:
|
||||||
candidates.add(renderTree(err.sym.ast,
|
candidates.add(renderTree(err.sym.ast,
|
||||||
{renderNoBody, renderNoComments, renderNoPragmas}))
|
{renderNoBody, renderNoComments, renderNoPragmas}))
|
||||||
|
|
@ -217,7 +222,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
candidates.add("\n")
|
candidates.add("\n")
|
||||||
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
|
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
|
||||||
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
|
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
|
||||||
if n.len > 1:
|
if n.len > 1 and verboseTypeMismatch in c.config.legacyFeatures:
|
||||||
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
|
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
|
||||||
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
|
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
|
||||||
case err.firstMismatch.kind
|
case err.firstMismatch.kind
|
||||||
|
|
@ -274,11 +279,28 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
const
|
const
|
||||||
errTypeMismatch = "type mismatch: got <"
|
errTypeMismatch = "type mismatch: got <"
|
||||||
errButExpected = "but expected one of:"
|
errButExpected = "but expected one of:"
|
||||||
|
errExpectedPosition = "Expected one of (first mismatch at position [#]):"
|
||||||
errUndeclaredField = "undeclared field: '$1'"
|
errUndeclaredField = "undeclared field: '$1'"
|
||||||
errUndeclaredRoutine = "attempting to call undeclared routine: '$1'"
|
errUndeclaredRoutine = "attempting to call undeclared routine: '$1'"
|
||||||
errBadRoutine = "attempting to call routine: '$1'$2"
|
errBadRoutine = "attempting to call routine: '$1'$2"
|
||||||
errAmbiguousCallXYZ = "ambiguous call; both $1 and $2 match for: $3"
|
errAmbiguousCallXYZ = "ambiguous call; both $1 and $2 match for: $3"
|
||||||
|
|
||||||
|
proc describeParamList(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string =
|
||||||
|
result = "Expression: " & $n
|
||||||
|
for i in startIdx..<n.len:
|
||||||
|
result.add "\n [" & $i & "] " & renderTree(n[i]) & ": "
|
||||||
|
result.add describeArg(c, n, i, startIdx, prefer)
|
||||||
|
result.add "\n"
|
||||||
|
|
||||||
|
template legacynotFoundError(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
|
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
|
||||||
|
var result = errTypeMismatch
|
||||||
|
result.add(describeArgs(c, n, 1, prefer))
|
||||||
|
result.add('>')
|
||||||
|
if candidates != "":
|
||||||
|
result.add("\n" & errButExpected & "\n" & candidates)
|
||||||
|
localError(c.config, n.info, result & "\nexpression: " & $n)
|
||||||
|
|
||||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||||
# as semOverloadedCall is already pretty slow (and we need this information
|
# as semOverloadedCall is already pretty slow (and we need this information
|
||||||
|
|
@ -306,13 +328,15 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
|
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if verboseTypeMismatch in c.config.legacyFeatures:
|
||||||
|
legacynotFoundError(c, n, errors)
|
||||||
|
else:
|
||||||
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
|
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
|
||||||
var result = errTypeMismatch
|
var result = "type mismatch\n"
|
||||||
result.add(describeArgs(c, n, 1, prefer))
|
result.add describeParamList(c, n, 1, prefer)
|
||||||
result.add('>')
|
|
||||||
if candidates != "":
|
if candidates != "":
|
||||||
result.add("\n" & errButExpected & "\n" & candidates)
|
result.add("\n" & errExpectedPosition & "\n" & candidates)
|
||||||
localError(c.config, n.info, result & "\nexpression: " & $n)
|
localError(c.config, n.info, result)
|
||||||
|
|
||||||
proc bracketNotFoundError(c: PContext; n: PNode) =
|
proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||||
var errors: CandidateErrors = @[]
|
var errors: CandidateErrors = @[]
|
||||||
|
|
|
||||||
|
|
@ -322,9 +322,7 @@ proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||||
else:
|
else:
|
||||||
result = arg.typ.typeToString(prefer)
|
result = arg.typ.typeToString(prefer)
|
||||||
|
|
||||||
proc describeArgs*(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string =
|
template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = preferName) =
|
||||||
result = ""
|
|
||||||
for i in startIdx..<n.len:
|
|
||||||
var arg = n[i]
|
var arg = n[i]
|
||||||
if n[i].kind == nkExprEqExpr:
|
if n[i].kind == nkExprEqExpr:
|
||||||
result.add renderTree(n[i][0])
|
result.add renderTree(n[i][0])
|
||||||
|
|
@ -342,6 +340,14 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1; prefer = preferName): st
|
||||||
n[i] = arg
|
n[i] = arg
|
||||||
if arg.typ != nil and arg.typ.kind == tyError: return
|
if arg.typ != nil and arg.typ.kind == tyError: return
|
||||||
result.add argTypeToString(arg, prefer)
|
result.add argTypeToString(arg, prefer)
|
||||||
|
|
||||||
|
proc describeArg*(c: PContext, n: PNode, i: int, startIdx = 1; prefer = preferName): string =
|
||||||
|
describeArgImpl(c, n, i, startIdx, prefer)
|
||||||
|
|
||||||
|
proc describeArgs*(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string =
|
||||||
|
result = ""
|
||||||
|
for i in startIdx..<n.len:
|
||||||
|
describeArgImpl(c, n, i, startIdx, prefer)
|
||||||
if i != n.len - 1: result.add ", "
|
if i != n.len - 1: result.add ", "
|
||||||
|
|
||||||
proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
|
proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,4 @@ when defined(windows):
|
||||||
switch("tlsEmulation", "off")
|
switch("tlsEmulation", "off")
|
||||||
|
|
||||||
switch("warningAserror", "UnnamedBreak")
|
switch("warningAserror", "UnnamedBreak")
|
||||||
|
switch("legacy", "verboseTypeMismatch")
|
||||||
|
|
|
||||||
23
tests/errmsgs/tconcisetypemismatch.nim
Normal file
23
tests/errmsgs/tconcisetypemismatch.nim
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim c --hints:off --skipParentCfg $file"
|
||||||
|
errormsg: "type mismatch"
|
||||||
|
nimout: '''
|
||||||
|
tconcisetypemismatch.nim(23, 47) Error: type mismatch
|
||||||
|
Expression: int(inNanoseconds(t2 - t1)) / 100.5
|
||||||
|
[1] int(inNanoseconds(t2 - t1)): int
|
||||||
|
[2] 100.5: float64
|
||||||
|
|
||||||
|
Expected one of (first mismatch at position [#]):
|
||||||
|
[1] proc `/`(x, y: float): float
|
||||||
|
[1] proc `/`(x, y: float32): float32
|
||||||
|
[2] proc `/`(x, y: int): float
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import std/monotimes
|
||||||
|
from times import inNanoseconds
|
||||||
|
|
||||||
|
let t1 = getMonotime()
|
||||||
|
let result = 1 + 2
|
||||||
|
let t2 = getMonotime()
|
||||||
|
echo "Elapsed: ", (t2 - t1).inNanoseconds.int / 100.5
|
||||||
21
tests/errmsgs/tconcisetypemismatch.nims
Normal file
21
tests/errmsgs/tconcisetypemismatch.nims
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
switch("path", "$lib/../testament/lib")
|
||||||
|
# so we can `import stdtest/foo` inside tests
|
||||||
|
# Using $lib/../ instead of $nim/ so you can use a different nim to run tests
|
||||||
|
# during local testing, e.g. nim --lib:lib.
|
||||||
|
|
||||||
|
## prevent common user config settings to interfere with testament expectations
|
||||||
|
## Indifidual tests can override this if needed to test for these options.
|
||||||
|
switch("colors", "off")
|
||||||
|
|
||||||
|
switch("excessiveStackTrace", "off")
|
||||||
|
|
||||||
|
when (NimMajor, NimMinor, NimPatch) >= (1,5,1):
|
||||||
|
# to make it easier to test against older nim versions, (best effort only)
|
||||||
|
switch("filenames", "legacyRelProj")
|
||||||
|
switch("spellSuggest", "0")
|
||||||
|
|
||||||
|
# for std/unittest
|
||||||
|
switch("define", "nimUnittestOutputLevel:PRINT_FAILURES")
|
||||||
|
switch("define", "nimUnittestColor:off")
|
||||||
|
|
||||||
|
hint("Processing", off)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue