diff --git a/compiler/semcall.nim b/compiler/semcall.nim index c580f8fd54..a8ab2f7429 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -106,6 +106,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, errors.safeAdd(CandidateError( sym: sym, unmatchedVarParam: int z.mutabilityProblem, + firstMismatch: z.firstMismatch, diagnostics: z.diagnostics)) else: # Symbol table has been modified. Restart and pre-calculate all syms @@ -154,7 +155,20 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): else: add(candidates, err.sym.getProcHeader(prefer)) add(candidates, "\n") - if err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len: + if err.firstMismatch != 0 and n.len > 2: + add(candidates, "first type mismatch at position: " & $err.firstMismatch & + "\nrequired type: ") + if err.firstMismatch < err.sym.typ.len: + candidates.add typeToString(err.sym.typ.sons[err.firstMismatch]) + else: + candidates.add "none" + if err.firstMismatch < n.len: + candidates.add "\nbut expression '" + candidates.add renderTree(n[err.firstMismatch]) + candidates.add "' is of type: " + candidates.add typeToString(n[err.firstMismatch].typ) + candidates.add "\n" + elif err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len: add(candidates, "for a 'var' type a variable needs to be passed, but '" & renderTree(n[err.unmatchedVarParam]) & "' is immutable\n") for diag in err.diagnostics: @@ -189,7 +203,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) = while symx != nil: if symx.kind in routineKinds: errors.add(CandidateError(sym: symx, - unmatchedVarParam: 0, + unmatchedVarParam: 0, firstMismatch: 0, diagnostics: nil)) symx = nextOverloadIter(o, c, headSymbol) if errors.len == 0: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 123e11c681..090f30f16c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -24,7 +24,7 @@ type CandidateError* = object sym*: PSym - unmatchedVarParam*: int + unmatchedVarParam*, firstMismatch*: int diagnostics*: seq[string] CandidateErrors* = seq[CandidateError] @@ -67,7 +67,9 @@ type # or when the explain pragma is used. may be # triggered with an idetools command in the # future. - inheritancePenalty: int # to prefer closest father object type + inheritancePenalty: int # to prefer closest father object type + firstMismatch*: int # position of the first type mismatch for + # better error messages TTypeRelFlag* = enum trDontBind @@ -2249,6 +2251,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, n.sons[a], nOrig.sons[a]) if arg == nil: m.state = csNoMatch + m.firstMismatch = f return if m.baseTypeMatch: #assert(container == nil) @@ -2303,6 +2306,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = else: # no default value m.state = csNoMatch + m.firstMismatch = f break else: # use default value: diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index bf8bffc7d4..6c9883618b 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -1,25 +1,48 @@ discard """ errormsg: "type mismatch: got (Bar[system.int])" nimout: ''' -t3330.nim(40, 4) Error: type mismatch: got (Bar[system.int]) +t3330.nim(63, 4) Error: type mismatch: got (Bar[system.int]) but expected one of: proc test(foo: Foo[int]) -t3330.nim(25, 8) Hint: Non-matching candidates for add(k, string, T) +t3330.nim(48, 8) Hint: Non-matching candidates for add(k, string, T) proc add(x: var string; y: string) +first type mismatch at position: 1 +required type: var string +but expression 'k' is of type: Alias proc add(x: var string; y: char) +first type mismatch at position: 1 +required type: var string +but expression 'k' is of type: Alias proc add(result: var string; x: int64) +first type mismatch at position: 1 +required type: var string +but expression 'k' is of type: Alias proc add(result: var string; x: float) +first type mismatch at position: 1 +required type: var string +but expression 'k' is of type: Alias proc add(x: var string; y: cstring) +first type mismatch at position: 1 +required type: var string +but expression 'k' is of type: Alias proc add[T](x: var seq[T]; y: openArray[T]) +first type mismatch at position: 1 +required type: var seq[T] +but expression 'k' is of type: Alias proc add[T](x: var seq[T]; y: T) +first type mismatch at position: 1 +required type: var seq[T] +but expression 'k' is of type: Alias -t3330.nim(25, 8) template/generic instantiation from here -t3330.nim(32, 6) Foo: 'bar.value' cannot be assigned to -t3330.nim(25, 8) template/generic instantiation from here -t3330.nim(33, 6) Foo: 'bar.x' cannot be assigned to -''' +t3330.nim(48, 8) template/generic instantiation from here +t3330.nim(55, 6) Foo: 'bar.value' cannot be assigned to +t3330.nim(48, 8) template/generic instantiation from here +t3330.nim(56, 6) Foo: 'bar.x' cannot be assigned to + +expression: test(bar)''' """ + type Foo[T] = concept k add(k, string, T) diff --git a/tests/errmsgs/tdetailed_position.nim b/tests/errmsgs/tdetailed_position.nim new file mode 100644 index 0000000000..d6db94c3e3 --- /dev/null +++ b/tests/errmsgs/tdetailed_position.nim @@ -0,0 +1,22 @@ + +discard """ +cmd: "nim check $file" +errormsg: "type mismatch: got (int literal(1), int literal(2), int literal(3))" +nimout: ''' +but expected one of: +proc main(a, b, c: string) +first type mismatch at position: 1 +required type: string +but expression '1' is of type: int literal(1) + +expression: main(1, 2, 3) +''' +""" + +const + myconst = "abcdefghijklmnopqrstuvwxyz" + +proc main(a, b, c: string) {.deprecated: "use foo " & "instead " & myconst.} = + return + +main(1, 2, 3)