summary refs log tree commit diff stats
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2024-09-06 12:25:51 +0300
committerGitHub <noreply@github.com>2024-09-06 11:25:51 +0200
commit4a548deb0886ba7ae7b21a0134ce5becfac7ea5e (patch)
tree14f6c8a6af6043749305ebba5852ba1688458cab
parentd77ea0783786e863804a1c51186d6811187215f7 (diff)
downloadNim-4a548deb0886ba7ae7b21a0134ce5becfac7ea5e.tar.gz
proper errors for subscript overloads (#24068)
The magic `mArrGet`/`mArrPut` subscript overloads always match, so if a
subscript doesn't match any other subscript overloads and isn't a
regular language-handled subscript, it creates a fake overload mismatch
error in `semArrGet` that doesn't have any information (gives stuff like
"first mismatch at index: 0" for every single mismatch). Instead of
generating the fake mismatches, we only generate the fake mismatch for
`mArrGet`/`mArrPut`, and process every overload except them as a real
call and get the errors from there.
-rw-r--r--compiler/semcall.nim50
-rw-r--r--compiler/semexprs.nim2
-rw-r--r--compiler/semmagic.nim2
-rw-r--r--tests/errmsgs/t10735.nim60
-rw-r--r--tests/errmsgs/t22753.nim45
-rw-r--r--tests/errmsgs/tsubscriptmismatch.nim11
-rw-r--r--tests/errmsgs/tsubscriptmismatch_legacy.nim10
7 files changed, 128 insertions, 52 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 5fb61d537..06dd09b69 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -458,23 +458,6 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
       result.add("\n" & errExpectedPosition & "\n" & candidates)
     localError(c.config, n.info, result)
 
-proc bracketNotFoundError(c: PContext; n: PNode) =
-  var errors: CandidateErrors = @[]
-  var o: TOverloadIter = default(TOverloadIter)
-  let headSymbol = n[0]
-  var symx = initOverloadIter(o, c, headSymbol)
-  while symx != nil:
-    if symx.kind in routineKinds:
-      errors.add(CandidateError(sym: symx,
-                                firstMismatch: MismatchInfo(),
-                                diagnostics: @[],
-                                enabled: false))
-    symx = nextOverloadIter(o, c, headSymbol)
-  if errors.len == 0:
-    localError(c.config, n.info, "could not resolve: " & $n)
-  else:
-    notFoundError(c, n, errors)
-
 proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
   result = ""
   if c.compilesContextId > 0:
@@ -603,6 +586,39 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         getProcHeader(c.config, alt.calleeSym),
         args])
 
+proc bracketNotFoundError(c: PContext; n: PNode; flags: TExprFlags) =
+  var errors: CandidateErrors = @[]
+  let headSymbol = n[0]
+  block:
+    # we build a closed symchoice of all `[]` overloads for their errors,
+    # except add a custom error for the magics which always match
+    var choice = newNodeIT(nkClosedSymChoice, headSymbol.info, newTypeS(tyNone, c))
+    var o: TOverloadIter = default(TOverloadIter)
+    var symx = initOverloadIter(o, c, headSymbol)
+    while symx != nil:
+      if symx.kind in routineKinds:
+        if symx.magic in {mArrGet, mArrPut}:
+          errors.add(CandidateError(sym: symx,
+                                    firstMismatch: MismatchInfo(),
+                                    diagnostics: @[],
+                                    enabled: false))
+        else:
+          choice.add newSymNode(symx, headSymbol.info)
+      symx = nextOverloadIter(o, c, headSymbol)
+    n[0] = choice
+  # copied from semOverloadedCallAnalyzeEffects, might be overkill:
+  const baseFilter = {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}
+  let filter =
+    if flags*{efInTypeof, efWantIterator, efWantIterable} != {}:
+      baseFilter + {skIterator}
+    else: baseFilter
+  # this will add the errors:
+  var r = resolveOverloads(c, n, n, filter, flags, errors, true)
+  if errors.len == 0:
+    localError(c.config, n.info, "could not resolve: " & $n)
+  else:
+    notFoundError(c, n, errors)
+
 proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
   let a = if a.kind == nkHiddenDeref: a[0] else: a
   if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 39121a671..9b255bdf4 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1993,7 +1993,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
       result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]="))
       result.add(n[1])
       if mode == noOverloadedSubscript:
-        bracketNotFoundError(c, result)
+        bracketNotFoundError(c, result, {})
         return errorNode(c, n)
       else:
         result = semExprNoType(c, result)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 1d97f1926..524c9a0ab 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -68,7 +68,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
   if result.isNil:
     let x = copyTree(n)
     x[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
-    bracketNotFoundError(c, x)
+    bracketNotFoundError(c, x, flags)
     #localError(c.config, n.info, "could not resolve: " & $n)
     result = errorNode(c, n)
 
diff --git a/tests/errmsgs/t10735.nim b/tests/errmsgs/t10735.nim
index f480d35ac..a39cd196e 100644
--- a/tests/errmsgs/t10735.nim
+++ b/tests/errmsgs/t10735.nim
@@ -2,40 +2,62 @@ discard """
   cmd: "nim check $file"
   errormsg: "illformed AST: case buf[pos]"
   nimout: '''
-t10735.nim(43, 5) Error: 'let' symbol requires an initialization
-t10735.nim(44, 10) Error: undeclared identifier: 'pos'
-t10735.nim(44, 10) Error: expression 'pos' has no type (or is ambiguous)
-t10735.nim(44, 10) Error: expression 'pos' has no type (or is ambiguous)
-t10735.nim(44, 9) Error: type mismatch: got <cstring, >
+t10735.nim(65, 5) Error: 'let' symbol requires an initialization
+t10735.nim(66, 10) Error: undeclared identifier: 'pos'
+t10735.nim(66, 10) Error: expression 'pos' has no type (or is ambiguous)
+t10735.nim(66, 10) Error: expression 'pos' has no type (or is ambiguous)
+t10735.nim(66, 9) Error: type mismatch: got <cstring, >
 but expected one of:
 proc `[]`(s: string; i: BackwardsIndex): char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: string
+  but expression 'buf' is of type: cstring
 proc `[]`(s: var string; i: BackwardsIndex): var char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: var string
+  but expression 'buf' is of type: cstring
 proc `[]`[I: Ordinal; T](a: T; i: I): T
   first type mismatch at position: 0
 proc `[]`[Idx, T; U, V: Ordinal](a: array[Idx, T]; x: HSlice[U, V]): seq[T]
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: array[Idx, T]
+  but expression 'buf' is of type: cstring
 proc `[]`[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: array[Idx, T]
+  but expression 'buf' is of type: cstring
 proc `[]`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: var array[Idx, T]
+  but expression 'buf' is of type: cstring
 proc `[]`[T, U: Ordinal](s: string; x: HSlice[T, U]): string
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: string
+  but expression 'buf' is of type: cstring
 proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T]
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: openArray[T]
+  but expression 'buf' is of type: cstring
 proc `[]`[T](s: openArray[T]; i: BackwardsIndex): T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: openArray[T]
+  but expression 'buf' is of type: cstring
 proc `[]`[T](s: var openArray[T]; i: BackwardsIndex): var T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: var openArray[T]
+  but expression 'buf' is of type: cstring
 template `[]`(a: WideCStringObj; idx: int): Utf16Char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: WideCStringObj
+  but expression 'buf' is of type: cstring
 template `[]`(s: string; i: int): char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: string
+  but expression 'buf' is of type: cstring
 
-expression: `[]`(buf, pos)
-t10735.nim(44, 9) Error: expression '' has no type (or is ambiguous)
-t10735.nim(46, 3) Error: illformed AST: case buf[pos]
+expression: buf[pos]
+t10735.nim(66, 9) Error: expression '' has no type (or is ambiguous)
+t10735.nim(68, 3) Error: illformed AST: case buf[pos]
 '''
   joinable: false
 """
diff --git a/tests/errmsgs/t22753.nim b/tests/errmsgs/t22753.nim
index af6a871f1..8a504109a 100644
--- a/tests/errmsgs/t22753.nim
+++ b/tests/errmsgs/t22753.nim
@@ -3,33 +3,50 @@ cmd: "nim check --hints:off $file"
 errormsg: "type mismatch"
 nimoutFull: true
 nimout: '''
-t22753.nim(34, 13) Error: array expects two type parameters
-t22753.nim(35, 1) Error: expression 'x' has no type (or is ambiguous)
-t22753.nim(35, 1) Error: expression 'x' has no type (or is ambiguous)
-t22753.nim(35, 2) Error: type mismatch: got <>
+t22753.nim(51, 13) Error: array expects two type parameters
+t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous)
+t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous)
+t22753.nim(52, 2) Error: type mismatch: got <>
 but expected one of:
 proc `[]=`(s: var string; i: BackwardsIndex; x: char)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for i: BackwardsIndex
+  but expression '0' is of type: int literal(0)
 proc `[]=`[I: Ordinal; T, S](a: T; i: I; x: sink S)
   first type mismatch at position: 0
 proc `[]=`[Idx, T; U, V: Ordinal](a: var array[Idx, T]; x: HSlice[U, V];
                                   b: openArray[T])
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for x: HSlice[[]=.U, []=.V]
+  but expression '0' is of type: int literal(0)
 proc `[]=`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for i: BackwardsIndex
+  but expression '0' is of type: int literal(0)
 proc `[]=`[T, U: Ordinal](s: var string; x: HSlice[T, U]; b: string)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for x: HSlice[[]=.T, []=.U]
+  but expression '0' is of type: int literal(0)
 proc `[]=`[T; U, V: Ordinal](s: var seq[T]; x: HSlice[U, V]; b: openArray[T])
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for x: HSlice[[]=.U, []=.V]
+  but expression '0' is of type: int literal(0)
 proc `[]=`[T](s: var openArray[T]; i: BackwardsIndex; x: T)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for i: BackwardsIndex
+  but expression '0' is of type: int literal(0)
 template `[]=`(a: WideCStringObj; idx: int; val: Utf16Char)
-  first type mismatch at position: 0
+  first type mismatch at position: 3
+  required type for val: Utf16Char
+  but expression '9' is of type: int literal(9)
 template `[]=`(s: string; i: int; val: char)
-  first type mismatch at position: 0
+  first type mismatch at position: 3
+  required type for val: char
+  but expression '9' is of type: int literal(9)
 
-expression: `[]=`(x, 0, 9)
+expression: x[0] = 9
 '''
 """
+
 var x: array[3] # bug #22753
-x[0] = 9
\ No newline at end of file
+x[0] = 9
diff --git a/tests/errmsgs/tsubscriptmismatch.nim b/tests/errmsgs/tsubscriptmismatch.nim
new file mode 100644
index 000000000..a2b297b68
--- /dev/null
+++ b/tests/errmsgs/tsubscriptmismatch.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "-d:testsConciseTypeMismatch"
+  nimout: '''
+[1] proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T]
+'''
+"""
+
+type Foo = object
+let x = Foo()
+discard x[1] #[tt.Error
+         ^ type mismatch]#
diff --git a/tests/errmsgs/tsubscriptmismatch_legacy.nim b/tests/errmsgs/tsubscriptmismatch_legacy.nim
new file mode 100644
index 000000000..3e1f1eb71
--- /dev/null
+++ b/tests/errmsgs/tsubscriptmismatch_legacy.nim
@@ -0,0 +1,10 @@
+discard """
+  nimout: '''
+  but expression 'x' is of type: Foo
+'''
+"""
+
+type Foo = object
+let x = Foo()
+discard x[1] #[tt.Error
+         ^ type mismatch: got <Foo, int literal(1)>]#