summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/msgs.nim18
-rw-r--r--compiler/sem.nim1
-rw-r--r--compiler/semcall.nim6
-rw-r--r--compiler/semexprs.nim11
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/sigmatch.nim9
-rw-r--r--tests/concepts/texplain.nim84
-rw-r--r--tests/testament/tester.nim6
8 files changed, 84 insertions, 53 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 8f7c43312..3a97f1ed2 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -133,7 +133,7 @@ type
     hintConditionAlwaysTrue, hintName, hintPattern,
     hintExecuting, hintLinking, hintDependency,
     hintSource, hintStackTrace, hintGCStats,
-    hintUser
+    hintUser, hintUserRaw
 
 const
   MsgKindToStr*: array[TMsgKind, string] = [
@@ -434,10 +434,11 @@ const
     hintSource: "$1",
     hintStackTrace: "$1",
     hintGCStats: "$1",
-    hintUser: "$1"]
+    hintUser: "$1",
+    hintUserRaw: "$1"]
 
 const
-  WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
+  WarningsToStr* = ["CannotOpenFile", "OctalEscape",
     "XIsNeverRead", "XmightNotBeenInit",
     "Deprecated", "ConfigDeprecated",
     "SmallLshouldNotBeUsed", "UnknownMagic",
@@ -449,12 +450,12 @@ const
     "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
     "GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
 
-  HintsToStr*: array[0..22, string] = ["Success", "SuccessX", "LineTooLong",
+  HintsToStr* = ["Success", "SuccessX", "LineTooLong",
     "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
     "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
     "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
     "Source", "StackTrace", "GCStats",
-    "User"]
+    "User", "UserRaw"]
 
 const
   fatalMin* = errUnknown
@@ -658,9 +659,6 @@ proc concat(strings: openarray[string]): string =
   result = newStringOfCap totalLen
   for s in strings: result.add s
 
-template writeBufferedMsg(args: varargs[string, `$`]) =
-  bufferedMsgs.safeAdd concat(args)
-
 proc suggestWriteln*(s: string) =
   if eStdOut in errorOutputs:
     if isNil(writelnHook):
@@ -929,7 +927,7 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
     if msg notin gNotes: return
     title = HintTitle
     color = HintColor
-    kind = HintsToStr[ord(msg) - ord(hintMin)]
+    if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
     inc(gHintCounter)
   let s = msgKindToString(msg) % args
 
@@ -997,7 +995,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     ignoreMsg = optHints notin gOptions or msg notin gNotes
     title = HintTitle
     color = HintColor
-    kind = HintsToStr[ord(msg) - ord(hintMin)]
+    if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
     inc(gHintCounter)
   # NOTE: currently line info line numbers start with 1,
   # but column numbers start with 0, however most editors expect
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 6ad77e3fb..57b87e0bb 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -215,7 +215,6 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
 proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
-proc isOpImpl(c: PContext, n: PNode): PNode
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
                      flags: TExprFlags = {}): PNode
 proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 291cf0c6d..49b4930eb 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -148,7 +148,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   # Gives a detailed error message; this is separated from semOverloadedCall,
   # as semOverlodedCall is already pretty slow (and we need this information
   # only in case of an error).
-  if c.compilesContextId > 0:
+  if errorOutputs == {}:
     # fail fast:
     globalError(n.info, errTypeMismatch, "")
   if errors.isNil or errors.len == 0:
@@ -263,7 +263,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
     internalAssert result.state == csMatch
     #writeMatches(result)
     #writeMatches(alt)
-    if c.compilesContextId > 0:
+    if errorOutputs == {}:
       # quick error message for performance of 'compiles' built-in:
       globalError(n.info, errGenerated, "ambiguous call")
     elif gErrorCounter == 0:
@@ -374,7 +374,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
     # this may be triggered, when the explain pragma is used
     if errors.len > 0:
       let (_, candidates) = presentFailedCandidates(c, n, errors)
-      message(n.info, hintUser,
+      message(n.info, hintUserRaw,
               "Non-matching candidates for " & renderTree(n) & "\n" &
               candidates)
     result = semResolvedCall(c, n, r)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 59b7e7d7f..b5e9e6dc4 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -302,7 +302,7 @@ proc semOf(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyBool)
   result = n
 
-proc isOpImpl(c: PContext, n: PNode): PNode =
+proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
   internalAssert n.sonsLen == 3 and
     n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
@@ -324,12 +324,13 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
     maybeLiftType(t2, c, n.info)
     var m: TCandidate
     initCandidate(c, m, t2)
+    if efExplain in flags: m.diagnostics = @[]
     let match = typeRel(m, t2, t1) >= isSubtype # isNone
     result = newIntNode(nkIntLit, ord(match))
 
   result.typ = n.typ
 
-proc semIs(c: PContext, n: PNode): PNode =
+proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if sonsLen(n) != 3:
     localError(n.info, errXExpectsTwoArguments, "is")
 
@@ -349,7 +350,7 @@ proc semIs(c: PContext, n: PNode): PNode =
     return
 
   # BUGFIX: don't evaluate this too early: ``T is void``
-  if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n)
+  if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n, flags)
 
 proc semOpAux(c: PContext, n: PNode) =
   const flags = {efDetermineType}
@@ -754,7 +755,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # This is a proc variable, apply normal overload resolution
     let m = resolveIndirectCall(c, n, nOrig, t)
     if m.state != csMatch:
-      if c.compilesContextId > 0:
+      if errorOutputs == {}:
         # speed up error generation:
         globalError(n.info, errTypeMismatch, "")
         return emptyNode
@@ -1837,7 +1838,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mLow: result = semLowHigh(c, setMs(n, s), mLow)
   of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
   of mSizeOf: result = semSizeof(c, setMs(n, s))
-  of mIs: result = semIs(c, setMs(n, s))
+  of mIs: result = semIs(c, setMs(n, s), flags)
   of mOf: result = semOf(c, setMs(n, s))
   of mShallowCopy: result = semShallowCopy(c, n, flags)
   of mExpandToAst: result = semExpandToAst(c, n, s, flags)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 09631c793..d42eb5433 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1609,7 +1609,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
       n.typ = n.sons[i].typ
       return
     else:
-      var expr = semExpr(c, n.sons[i])
+      var expr = semExpr(c, n.sons[i], flags)
       n.sons[i] = expr
       if c.inTypeClass > 0 and expr.typ != nil:
         case expr.typ.kind
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index c76b08eb9..5a6f4e015 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -664,6 +664,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
   var
     oldWriteHook: type(writelnHook)
     diagnostics: seq[string]
+    errorPrefix: string
     flags: TExprFlags = {}
     collectDiagnostics = m.diagnostics != nil or
                          sfExplain in Concept.sym.flags
@@ -673,9 +674,13 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
     # XXX: we can't write to m.diagnostics directly, because
     # Nim doesn't support capturing var params in closures
     diagnostics = @[]
-    writelnHook = proc (s: string) = diagnostics.add(s)
     flags = {efExplain}
-
+    writelnHook = proc (s: string) =
+      if errorPrefix == nil: errorPrefix = Concept.sym.name.s & ":"
+      let msg = s.replace("Error:", errorPrefix)
+      if oldWriteHook != nil: oldWriteHook msg
+      diagnostics.add msg
+   
   var checkedBody = c.semTryExpr(c, body.copyTree, flags)
   
   if collectDiagnostics:
diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim
index 9b2b1f70d..186621f5b 100644
--- a/tests/concepts/texplain.nim
+++ b/tests/concepts/texplain.nim
@@ -1,36 +1,63 @@
 discard """
   cmd: "nim c --verbosity:0 --colors:off $file"
   nimout: '''
-tests/concepts/texplain.nim(71, 10) Hint: Non-matching candidates for e(y)
+tests/concepts/texplain.nim(99, 10) Hint: Non-matching candidates for e(y)
 proc e(i: int): int
- [User]
-tests/concepts/texplain.nim(74, 7) Hint: Non-matching candidates for e(10)
-proc e[ExplainedConcept](o: ExplainedConcept): int
-tests/concepts/texplain.nim(38, 6) Error: undeclared field: 'foo'
-tests/concepts/texplain.nim(38, 6) Error: undeclared field: '.'
-tests/concepts/texplain.nim(38, 6) Error: type mismatch: got (
- [User]
-tests/concepts/texplain.nim(77, 10) Hint: Non-matching candidates for e(10)
-proc e[ExplainedConcept](o: ExplainedConcept): int
-tests/concepts/texplain.nim(38, 6) Error: undeclared field: 'foo'
-tests/concepts/texplain.nim(38, 6) Error: undeclared field: '.'
-tests/concepts/texplain.nim(38, 6) Error: type mismatch: got (
- [User]
-tests/concepts/texplain.nim(81, 20) Error: type mismatch: got (
-tests/concepts/texplain.nim(82, 20) Error: type mismatch: got (
-tests/concepts/texplain.nim(83, 20) Hint: Non-matching candidates for r(y)
+
+tests/concepts/texplain.nim(102, 7) Hint: Non-matching candidates for e(10)
+proc e(o: ExplainedConcept): int
+tests/concepts/texplain.nim(65, 6) ExplainedConcept: undeclared field: 'foo'
+tests/concepts/texplain.nim(65, 6) ExplainedConcept: undeclared field: '.'
+tests/concepts/texplain.nim(65, 6) ExplainedConcept: expression '.' cannot be called
+tests/concepts/texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+tests/concepts/texplain.nim(66, 6) ExplainedConcept: undeclared field: 'bar'
+tests/concepts/texplain.nim(66, 6) ExplainedConcept: undeclared field: '.'
+tests/concepts/texplain.nim(66, 6) ExplainedConcept: expression '.' cannot be called
+tests/concepts/texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+
+tests/concepts/texplain.nim(105, 10) Hint: Non-matching candidates for e(10)
+proc e(o: ExplainedConcept): int
+tests/concepts/texplain.nim(65, 6) ExplainedConcept: undeclared field: 'foo'
+tests/concepts/texplain.nim(65, 6) ExplainedConcept: undeclared field: '.'
+tests/concepts/texplain.nim(65, 6) ExplainedConcept: expression '.' cannot be called
+tests/concepts/texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+tests/concepts/texplain.nim(66, 6) ExplainedConcept: undeclared field: 'bar'
+tests/concepts/texplain.nim(66, 6) ExplainedConcept: undeclared field: '.'
+tests/concepts/texplain.nim(66, 6) ExplainedConcept: expression '.' cannot be called
+tests/concepts/texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+
+tests/concepts/texplain.nim(109, 20) Error: type mismatch: got (NonMatchingType)
+but expected one of: 
+proc e(o: ExplainedConcept): int
+tests/concepts/texplain.nim(65, 5) ExplainedConcept: type class predicate failed
+proc e(i: int): int
+
+tests/concepts/texplain.nim(110, 20) Error: type mismatch: got (NonMatchingType)
+but expected one of: 
+proc r(o: RegularConcept): int
+tests/concepts/texplain.nim(69, 5) RegularConcept: type class predicate failed
+proc r[T](a: SomeNumber; b: T; c: auto)
 proc r(i: string): int
- [User]
-tests/concepts/texplain.nim(91, 2) Error: type mismatch: got (MatchingType)
+
+tests/concepts/texplain.nim(111, 20) Hint: Non-matching candidates for r(y)
+proc r[T](a: SomeNumber; b: T; c: auto)
+proc r(i: string): int
+
+tests/concepts/texplain.nim(119, 2) Error: type mismatch: got (MatchingType)
 but expected one of: 
-proc f[NestedConcept](o: NestedConcept)
-tests/concepts/texplain.nim(42, 6) Error: undeclared field: 'foo'
-tests/concepts/texplain.nim(42, 6) Error: undeclared field: '.'
-tests/concepts/texplain.nim(42, 6) Error: type mismatch: got (
-tests/concepts/texplain.nim(46, 5) Error: type class predicate failed
+proc f(o: NestedConcept)
+tests/concepts/texplain.nim(69, 6) RegularConcept: undeclared field: 'foo'
+tests/concepts/texplain.nim(69, 6) RegularConcept: undeclared field: '.'
+tests/concepts/texplain.nim(69, 6) RegularConcept: expression '.' cannot be called
+tests/concepts/texplain.nim(69, 5) RegularConcept: type class predicate failed
+tests/concepts/texplain.nim(70, 6) RegularConcept: undeclared field: 'bar'
+tests/concepts/texplain.nim(70, 6) RegularConcept: undeclared field: '.'
+tests/concepts/texplain.nim(70, 6) RegularConcept: expression '.' cannot be called
+tests/concepts/texplain.nim(69, 5) RegularConcept: type class predicate failed
+tests/concepts/texplain.nim(73, 5) NestedConcept: type class predicate failed
 '''
-  line: 46
-  errormsg: "type class predicate failed"
+  line: 119
+  errormsg: "type mismatch: got (MatchingType)"
 """
 
 type
@@ -56,6 +83,7 @@ type
 proc e(o: ExplainedConcept): int = 1
 proc e(i: int): int = i
 
+proc r[T](a: SomeNumber, b: T, c: auto) = discard
 proc r(o: RegularConcept): int = 1
 proc r(i: string): int = 1
 
@@ -77,11 +105,11 @@ echo(e(10) {.explain.}, 20)
 discard e(10)
 
 static:
-  # provide diagnostics why the compile block failed 
+  # provide diagnostics why the compile block failed
   assert(compiles(e(n)) {.explain.} == false)
   assert(compiles(r(n)) {.explain.} == false)
   assert(compiles(r(y)) {.explain.} == true)
-  
+
   # these should not produce any output
   assert(compiles(r(10)) == false)
   assert(compiles(e(10)) == true)
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index 908eba962..2d758ef0d 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -63,6 +63,8 @@ let
 
 var targets = {low(TTarget)..high(TTarget)}
 
+proc normalizeMsg(s: string): string = s.strip.replace("\C\L", "\L")
+
 proc callCompiler(cmdTemplate, filename, options: string,
                   target: TTarget): TSpec =
   let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
@@ -184,7 +186,7 @@ proc addResult(r: var TResults, test: TTest,
 proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
   if strip(expected.msg) notin strip(given.msg):
     r.addResult(test, expected.msg, given.msg, reMsgsDiffer)
-  elif expected.nimout.len > 0 and expected.nimout.normalize notin given.nimout.normalize:
+  elif expected.nimout.len > 0 and expected.nimout.normalizeMsg notin given.nimout.normalizeMsg:
     r.addResult(test, expected.nimout, given.nimout, reMsgsDiffer)
   elif expected.tfile == "" and extractFilename(expected.file) != extractFilename(given.file) and
       "internal error:" notin expected.msg:
@@ -235,8 +237,6 @@ proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) =
   if exp notin giv:
     given.err = reMsgsDiffer
 
-proc normalize(s: string): string = s.strip.replace("\C\L", "\L")
-
 proc makeDeterministic(s: string): string =
   var x = splitLines(s)
   sort(x, system.cmp)