mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
fix segfault in generic param mismatch error, skip typedesc (#24140)
refs #24010, refs https://github.com/nim-lang/Nim/issues/24125#issuecomment-2358377076 The generic mismatch errors added in #24010 made it possible for `nArg` to be `nil` in the error reporting since it checked the call argument list, not the generic parameter list for the mismatching argument node, which causes a segfault. This is fixed by checking the generic parameter list immediately on any generic mismatch error. Also the `typedesc` type is skipped for the value of the generic params since it's redundant and the generic parameter constraints don't have it.
This commit is contained in:
@@ -246,10 +246,18 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
candidates.add(getProcHeader(c.config, err.sym, prefer))
|
||||
candidates.addDeclaredLocMaybe(c.config, err.sym)
|
||||
candidates.add("\n")
|
||||
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
|
||||
const genericParamMismatches = {kGenericParamTypeMismatch, kExtraGenericParam, kMissingGenericParam}
|
||||
let isGenericMismatch = err.firstMismatch.kind in genericParamMismatches
|
||||
var argList = n
|
||||
if isGenericMismatch and n[0].kind == nkBracketExpr:
|
||||
argList = n[0]
|
||||
let nArg =
|
||||
if err.firstMismatch.arg < argList.len:
|
||||
argList[err.firstMismatch.arg]
|
||||
else:
|
||||
nil
|
||||
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
|
||||
if n.len > 1:
|
||||
const genericParamMismatches = {kGenericParamTypeMismatch, kExtraGenericParam, kMissingGenericParam}
|
||||
if verboseTypeMismatch notin c.config.legacyFeatures:
|
||||
case err.firstMismatch.kind
|
||||
of kUnknownNamedParam:
|
||||
@@ -309,7 +317,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
var wanted = err.firstMismatch.formal.typ
|
||||
if wanted.kind == tyGenericParam and wanted.genericParamHasConstraints:
|
||||
wanted = wanted.genericConstraint
|
||||
let got = arg.typ
|
||||
let got = arg.typ.skipTypes({tyTypeDesc})
|
||||
doAssert err.firstMismatch.formal != nil
|
||||
doAssert wanted != nil
|
||||
doAssert got != nil
|
||||
@@ -350,17 +358,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
of kMissingGenericParam:
|
||||
candidates.add("\n missing generic parameter: " & nameParam)
|
||||
of kTypeMismatch, kGenericParamTypeMismatch, kVarNeeded:
|
||||
var arg: PNode = nArg
|
||||
let genericMismatch = err.firstMismatch.kind == kGenericParamTypeMismatch
|
||||
if genericMismatch:
|
||||
let pos = err.firstMismatch.arg
|
||||
doAssert n[0].kind == nkBracketExpr and pos < n[0].len
|
||||
arg = n[0][pos]
|
||||
else:
|
||||
arg = nArg
|
||||
doAssert arg != nil
|
||||
doAssert nArg != nil
|
||||
var wanted = err.firstMismatch.formal.typ
|
||||
if genericMismatch and wanted.kind == tyGenericParam and
|
||||
if isGenericMismatch and wanted.kind == tyGenericParam and
|
||||
wanted.genericParamHasConstraints:
|
||||
wanted = wanted.genericConstraint
|
||||
doAssert err.firstMismatch.formal != nil
|
||||
@@ -368,16 +368,17 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
|
||||
candidates.add "\n but expression '"
|
||||
if err.firstMismatch.kind == kVarNeeded:
|
||||
candidates.add renderNotLValue(arg)
|
||||
candidates.add renderNotLValue(nArg)
|
||||
candidates.add "' is immutable, not 'var'"
|
||||
else:
|
||||
candidates.add renderTree(arg)
|
||||
candidates.add renderTree(nArg)
|
||||
candidates.add "' is of type: "
|
||||
let got = arg.typ
|
||||
var got = nArg.typ
|
||||
if isGenericMismatch: got = got.skipTypes({tyTypeDesc})
|
||||
candidates.addTypeDeclVerboseMaybe(c.config, got)
|
||||
if arg.kind in nkSymChoices:
|
||||
if nArg.kind in nkSymChoices:
|
||||
candidates.add "\n"
|
||||
candidates.add ambiguousIdentifierMsg(arg, indent = 2)
|
||||
candidates.add ambiguousIdentifierMsg(nArg, indent = 2)
|
||||
doAssert wanted != nil
|
||||
if got != nil:
|
||||
if got.kind == tyProc and wanted.kind == tyProc:
|
||||
|
||||
13
tests/errmsgs/tgenericmismatchsegfault.nim
Normal file
13
tests/errmsgs/tgenericmismatchsegfault.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
discard """
|
||||
matrix: "-d:testsConciseTypeMismatch"
|
||||
"""
|
||||
|
||||
template v[T](c: SomeOrdinal): T = T(c)
|
||||
discard v[int, char]('A') #[tt.Error
|
||||
^ type mismatch
|
||||
Expression: v[int, char]('A')
|
||||
[1] 'A': char
|
||||
|
||||
Expected one of (first mismatch at [position]):
|
||||
[2] template v[T](c: SomeOrdinal): T
|
||||
generic parameter mismatch, expected SomeOrdinal but got 'char' of type: char]#
|
||||
10
tests/errmsgs/tgenericmismatchsegfault_legacy.nim
Normal file
10
tests/errmsgs/tgenericmismatchsegfault_legacy.nim
Normal file
@@ -0,0 +1,10 @@
|
||||
template v[T](c: SomeOrdinal): T = T(c)
|
||||
discard v[int, char]('A') #[tt.Error
|
||||
^ type mismatch: got <char>
|
||||
but expected one of:
|
||||
template v[T](c: SomeOrdinal): T
|
||||
first type mismatch at position: 2 in generic parameters
|
||||
required type for SomeOrdinal: SomeOrdinal
|
||||
but expression 'char' is of type: char
|
||||
|
||||
expression: v[int, char]('A')]#
|
||||
@@ -9,7 +9,7 @@ Expression: newImage[string](320, 200)
|
||||
|
||||
Expected one of (first mismatch at [position]):
|
||||
[1] proc newImage[T: int32 | int64](w, h: int): ref Image[T]
|
||||
generic parameter mismatch, expected int32 or int64 but got 'string' of type: typedesc[string]
|
||||
generic parameter mismatch, expected int32 or int64 but got 'string' of type: string
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ but expected one of:
|
||||
proc newImage[T: int32 | int64](w, h: int): ref Image[T]
|
||||
first type mismatch at position: 1 in generic parameters
|
||||
required type for T: int32 or int64
|
||||
but expression 'string' is of type: typedesc[string]
|
||||
but expression 'string' is of type: string
|
||||
|
||||
expression: newImage[string](320, 200)
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user