summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semcall.nim33
-rw-r--r--compiler/semexprs.nim3
-rw-r--r--compiler/sigmatch.nim24
3 files changed, 37 insertions, 23 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index f443339f5..0df943531 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -59,7 +59,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
                        filter: TSymKinds,
                        best, alt: var TCandidate,
                        errors: var CandidateErrors,
-                       diagnosticsFlag = false) =
+                       diagnosticsFlag: bool) =
   var o: TOverloadIter
   var sym = initOverloadIter(o, c, headSymbol)
   var scope = o.lastOverloadScope
@@ -68,6 +68,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
   # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
   let counterInitial = c.currentScope.symbols.counter
   var syms: seq[tuple[s: PSym, scope: int]]
+  var noSyms = true
   var nextSymIndex = 0
   while sym != nil:
     if sym.kind in filter:
@@ -102,18 +103,20 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
           var cmp = cmpCandidates(best, z)
           if cmp < 0: best = z   # x is better than the best so far
           elif cmp == 0: alt = z # x is as good as the best so far
-      elif errors != nil or z.diagnostics != nil:
-        errors.safeAdd(CandidateError(
+      elif errors.enabled or z.diagnostics.enabled:
+        errors.s.safeAdd(CandidateError(
           sym: sym,
           unmatchedVarParam: int z.mutabilityProblem,
           firstMismatch: z.firstMismatch,
           diagnostics: z.diagnostics))
+        errors.enabled = true
     else:
       # Symbol table has been modified. Restart and pre-calculate all syms
       # before any further candidate init and compare. SLOW, but rare case.
       syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
                                   best, alt, o, diagnosticsFlag)
-    if syms == nil:
+      noSyms = false
+    if noSyms:
       sym = nextOverloadIter(o, c, headSymbol)
       scope = o.lastOverloadScope
     elif nextSymIndex < syms.len:
@@ -148,7 +151,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
   # we do a pre-analysis. If all types produce the same string, we will add
   # module information.
   let proto = describeArgs(c, n, 1, preferName)
-  for err in errors:
+  for err in errors.s:
     var errProto = ""
     let n = err.sym.typ.n
     for i in countup(1, n.len - 1):
@@ -162,7 +165,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
       break
 
   var candidates = ""
-  for err in errors:
+  for err in errors.s:
     if err.sym.kind in routineKinds and err.sym.ast != nil:
       add(candidates, renderTree(err.sym.ast,
             {renderNoBody, renderNoComments, renderNoPragmas}))
@@ -194,7 +197,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
       candidates.add("  for a 'var' type a variable needs to be passed, but '" &
                       renderNotLValue(n[err.unmatchedVarParam]) &
                       "' is immutable\n")
-    for diag in err.diagnostics:
+    for diag in err.diagnostics.s:
       candidates.add(diag & "\n")
 
   result = (prefer, candidates)
@@ -206,7 +209,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   if errorOutputs == {}:
     # fail fast:
     globalError(n.info, errTypeMismatch, "")
-  if errors.isNil or errors.len == 0:
+  if errors.s.len == 0:
     localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
     return
 
@@ -219,17 +222,18 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   localError(n.info, errGenerated, result & "\nexpression: " & $n)
 
 proc bracketNotFoundError(c: PContext; n: PNode) =
-  var errors: CandidateErrors = @[]
+  var errors = CandidateErrors(enabled: true, s: @[])
   var o: TOverloadIter
   let headSymbol = n[0]
   var symx = initOverloadIter(o, c, headSymbol)
   while symx != nil:
     if symx.kind in routineKinds:
-      errors.add(CandidateError(sym: symx,
+      errors.s.add(CandidateError(sym: symx,
                                 unmatchedVarParam: 0, firstMismatch: 0,
-                                diagnostics: nil))
+                                diagnostics: OptionalStringSeq(enabled: false, s: @[])))
+      errors.enabled = true
     symx = nextOverloadIter(o, c, headSymbol)
-  if errors.len == 0:
+  if errors.s.len == 0:
     localError(n.info, "could not resolve: " & $n)
   else:
     notFoundError(c, n, errors)
@@ -423,12 +427,11 @@ proc tryDeref(n: PNode): PNode =
 
 proc semOverloadedCall(c: PContext, n, nOrig: PNode,
                        filter: TSymKinds, flags: TExprFlags): PNode =
-  var errors: CandidateErrors = if efExplain in flags: @[]
-                                else: nil
+  var errors = CandidateErrors(enabled: efExplain in flags, s: nil)
   var r = resolveOverloads(c, n, nOrig, filter, flags, errors)
   if r.state == csMatch:
     # this may be triggered, when the explain pragma is used
-    if errors.len > 0:
+    if errors.s.len > 0:
       let (_, candidates) = presentFailedCandidates(c, n, errors)
       message(n.info, hintUserRaw,
               "Non-matching candidates for " & renderTree(n) & "\n" &
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 22dee81b7..66fe81ed3 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -305,7 +305,8 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
     maybeLiftType(t2, c, n.info)
     var m: TCandidate
     initCandidate(c, m, t2)
-    if efExplain in flags: m.diagnostics = @[]
+    if efExplain in flags:
+      m.diagnostics = OptionalStringSeq(enabled: true, s: @[])
     let match = typeRel(m, t2, t1) >= isSubtype # isNone
     result = newIntNode(nkIntLit, ord(match))
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 552d2cdca..0426a22f3 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -22,12 +22,18 @@ type
   TCandidateState* = enum
     csEmpty, csMatch, csNoMatch
 
+  OptionalStringSeq* = object
+    enabled*: bool
+    s*: seq[string]
+
   CandidateError* = object
     sym*: PSym
     unmatchedVarParam*, firstMismatch*: int
-    diagnostics*: seq[string]
+    diagnostics*: OptionalStringSeq # seq[string]
 
-  CandidateErrors* = seq[CandidateError]
+  CandidateErrors* = object
+    enabled*: bool
+    s*: seq[CandidateError]
 
   TCandidate* = object
     c*: PContext
@@ -60,7 +66,8 @@ type
                               # matching. they will be reset if the matching
                               # is not successful. may replace the bindings
                               # table in the future.
-    diagnostics*: seq[string] # when this is not nil, the matching process
+    diagnostics*: OptionalStringSeq # \
+                              # when diagnosticsEnabled, the matching process
                               # will collect extra diagnostics that will be
                               # displayed to the user.
                               # triggered when overload resolution fails
@@ -124,7 +131,8 @@ proc put(c: var TCandidate, key, val: PType) {.inline.} =
   idTablePut(c.bindings, key, val.skipIntLit)
 
 proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
-                    binding: PNode, calleeScope = -1, diagnostics = false) =
+                    binding: PNode, calleeScope = -1,
+                    diagnosticsEnabled = false) =
   initCandidateAux(ctx, c, callee.typ)
   c.calleeSym = callee
   if callee.kind in skProcKinds and calleeScope == -1:
@@ -139,7 +147,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
       c.calleeScope = 1
   else:
     c.calleeScope = calleeScope
-  c.diagnostics = if diagnostics: @[] else: nil
+  c.diagnostics = OptionalStringSeq(enabled: diagnosticsEnabled, s: @[])
   c.magic = c.calleeSym.magic
   initIdTable(c.bindings)
   if binding != nil and callee.kind in routineKinds:
@@ -717,7 +725,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
     diagnostics: seq[string]
     errorPrefix: string
     flags: TExprFlags = {}
-    collectDiagnostics = m.diagnostics != nil or
+    collectDiagnostics = m.diagnostics.enabled or
                          sfExplain in typeClass.sym.flags
 
   if collectDiagnostics:
@@ -736,7 +744,9 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
 
   if collectDiagnostics:
     writelnHook = oldWriteHook
-    for msg in diagnostics: m.diagnostics.safeAdd msg
+    for msg in diagnostics:
+      m.diagnostics.s.safeAdd msg
+      m.diagnostics.enabled = true
 
   if checkedBody == nil: return nil