mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
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.
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
x[0] = 9
|
||||
|
||||
11
tests/errmsgs/tsubscriptmismatch.nim
Normal file
11
tests/errmsgs/tsubscriptmismatch.nim
Normal file
@@ -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]#
|
||||
10
tests/errmsgs/tsubscriptmismatch_legacy.nim
Normal file
10
tests/errmsgs/tsubscriptmismatch_legacy.nim
Normal file
@@ -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)>]#
|
||||
Reference in New Issue
Block a user