Skip to content

Commit

Permalink
fix segfault in generic param mismatch error, skip typedesc (#24140)
Browse files Browse the repository at this point in the history
refs #24010, refs
#24125 (comment)

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.
  • Loading branch information
metagn authored Sep 19, 2024
1 parent 6cc50ec commit ff005ad
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 20 deletions.
37 changes: 19 additions & 18 deletions compiler/semcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -350,34 +358,27 @@ 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
candidates.add("\n required type for " & nameParam & ": ")
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:
Expand Down
13 changes: 13 additions & 0 deletions tests/errmsgs/tgenericmismatchsegfault.nim
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions tests/errmsgs/tgenericmismatchsegfault_legacy.nim
Original file line number Diff line number Diff line change
@@ -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')]#
2 changes: 1 addition & 1 deletion tests/errmsgs/twrong_explicit_typeargs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
'''
"""

Expand Down
2 changes: 1 addition & 1 deletion tests/errmsgs/twrong_explicit_typeargs_legacy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
'''
Expand Down

0 comments on commit ff005ad

Please sign in to comment.