summary refs log tree commit diff stats
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2024-09-19 08:19:07 +0300
committerGitHub <noreply@github.com>2024-09-19 07:19:07 +0200
commitff005ad7dc8b4f3a36a1eb0e18ebd4cc5e062883 (patch)
tree7920309ebbbb5a0acab46d6c3e40731920c599e0
parent6cc50ec3163c79b120bf17e32810946bad6b3893 (diff)
downloadNim-ff005ad7dc8b4f3a36a1eb0e18ebd4cc5e062883.tar.gz
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.
-rw-r--r--compiler/semcall.nim37
-rw-r--r--tests/errmsgs/tgenericmismatchsegfault.nim13
-rw-r--r--tests/errmsgs/tgenericmismatchsegfault_legacy.nim10
-rw-r--r--tests/errmsgs/twrong_explicit_typeargs.nim2
-rw-r--r--tests/errmsgs/twrong_explicit_typeargs_legacy.nim2
5 files changed, 44 insertions, 20 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 9111e3807..13f2273a9 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -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:
diff --git a/tests/errmsgs/tgenericmismatchsegfault.nim b/tests/errmsgs/tgenericmismatchsegfault.nim
new file mode 100644
index 000000000..dbb783cb3
--- /dev/null
+++ b/tests/errmsgs/tgenericmismatchsegfault.nim
@@ -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]#
diff --git a/tests/errmsgs/tgenericmismatchsegfault_legacy.nim b/tests/errmsgs/tgenericmismatchsegfault_legacy.nim
new file mode 100644
index 000000000..1532611b9
--- /dev/null
+++ b/tests/errmsgs/tgenericmismatchsegfault_legacy.nim
@@ -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')]#
diff --git a/tests/errmsgs/twrong_explicit_typeargs.nim b/tests/errmsgs/twrong_explicit_typeargs.nim
index 705eec52b..5236e5f4f 100644
--- a/tests/errmsgs/twrong_explicit_typeargs.nim
+++ b/tests/errmsgs/twrong_explicit_typeargs.nim
@@ -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
 '''
 """
 
diff --git a/tests/errmsgs/twrong_explicit_typeargs_legacy.nim b/tests/errmsgs/twrong_explicit_typeargs_legacy.nim
index fb81412dc..cfa528c54 100644
--- a/tests/errmsgs/twrong_explicit_typeargs_legacy.nim
+++ b/tests/errmsgs/twrong_explicit_typeargs_legacy.nim
@@ -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)
 '''