summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/commands.nim2
-rw-r--r--compiler/options.nim2
-rw-r--r--compiler/semcall.nim7
-rw-r--r--compiler/semexprs.nim8
-rw-r--r--compiler/sigmatch.nim7
-rw-r--r--doc/advopt.txt3
-rw-r--r--doc/manual/generics.txt4
-rw-r--r--tests/concepts/tgraph.nim29
-rw-r--r--web/news.txt3
9 files changed, 59 insertions, 6 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 6b2f074e8..2ed3f92a9 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -434,6 +434,8 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
   of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
   of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
+  of "reportconceptfailures":
+    processOnOffSwitchG({optReportConceptFailures}, arg, pass, info)
   of "threads":
     processOnOffSwitchG({optThreads}, arg, pass, info)
     #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
diff --git a/compiler/options.nim b/compiler/options.nim
index 98224a11d..6dd917ad4 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -40,7 +40,7 @@ type                          # please make sure we have under 32 options
   TGlobalOption* = enum       # **keep binary compatible**
     gloptNone, optForceFullMake, optDeadCodeElim,
     optListCmd, optCompileOnly, optNoLinking,
-    optSafeCode,              # only allow safe code
+    optReportConceptFailures, # report 'compiles' or 'concept' matching failures
     optCDebug,                # turn on debugging information
     optGenDynLib,             # generate a dynamic library
     optGenStaticLib,          # generate a static library
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 381093531..d8838e347 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -95,7 +95,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 c.compilesContextId > 0 and optReportConceptFailures notin gGlobalOptions:
     # fail fast:
     globalError(n.info, errTypeMismatch, "")
   if errors.isNil or errors.len == 0:
@@ -133,7 +133,10 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
     add(candidates, "\n")
   if candidates != "":
     add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
-  localError(n.info, errGenerated, result)
+  if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions:
+    globalError(n.info, errGenerated, result)
+  else:
+    localError(n.info, errGenerated, result)
 
 proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
   for scope in walkScopes(c.currentScope):
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 664102b75..f1016595a 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -292,8 +292,6 @@ proc semConv(c: PContext, n: PNode): PNode =
 
 proc semCast(c: PContext, n: PNode): PNode =
   ## Semantically analyze a casting ("cast[type](param)")
-  if optSafeCode in gGlobalOptions: localError(n.info, errCastNotInSafeMode)
-  #incl(c.p.owner.flags, sfSideEffect)
   checkSonsLen(n, 2)
   result = newNodeI(nkCast, n.info)
   result.typ = semTypeNode(c, n.sons[0], nil)
@@ -1659,11 +1657,13 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   let oldInGenericInst = c.inGenericInst
   let oldProcCon = c.p
   c.generics = @[]
+  var err: string
   try:
     result = semExpr(c, n, flags)
     if msgs.gErrorCounter != oldErrorCount: result = nil
   except ERecoverableError:
-    discard
+    if optReportConceptFailures in gGlobalOptions:
+      err = getCurrentExceptionMsg()
   # undo symbol table changes (as far as it's possible):
   c.compilesContextId = oldCompilesId
   c.generics = oldGenerics
@@ -1677,6 +1677,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   errorOutputs = oldErrorOutputs
   msgs.gErrorCounter = oldErrorCount
   msgs.gErrorMax = oldErrorMax
+  if optReportConceptFailures in gGlobalOptions and not err.isNil:
+    localError(n.info, err)
 
 proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # we replace this node by a 'true' or 'false' node:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 642f50330..9fda8c860 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -684,6 +684,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyAnything:
     return if f.kind == tyAnything: isGeneric
            else: isNone
+
+  of tyUserTypeClass, tyUserTypeClassInst:
+    # consider this: 'var g: Node' *within* a concept where 'Node'
+    # is a concept too (tgraph)
+    let x = typeRel(c, a, f, false)
+    if x >= isGeneric:
+      return isGeneric
   else: discard
 
   case f.kind
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 18a5a527b..02849498f 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -52,6 +52,9 @@ Advanced options:
   --embedsrc                embeds the original source code as comments
                             in the generated output
   --threadanalysis:on|off   turn thread analysis on|off
+  --reportConceptFailures:on|off
+                            show errors for 'system.compiles' and concept
+                            evaluation
   --tlsEmulation:on|off     turn thread local storage emulation on|off
   --taintMode:on|off        turn taint mode on|off
   --implicitStatic:on|off   turn implicit compile time evaluation on|off
diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt
index c6206d030..a73e22988 100644
--- a/doc/manual/generics.txt
+++ b/doc/manual/generics.txt
@@ -246,6 +246,10 @@ Much like generics, concepts are instantiated exactly
 once for each tested type and any static code included within them is also
 executed once.
 
+**Hint**: Since concepts are still very rough at the edges there is a
+command line switch ``--reportConceptFailures:on`` to make debugging
+concept related type failures more easy.
+
 
 Symbol lookup in generics
 -------------------------
diff --git a/tests/concepts/tgraph.nim b/tests/concepts/tgraph.nim
new file mode 100644
index 000000000..a0177a043
--- /dev/null
+++ b/tests/concepts/tgraph.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''XY is Node
+MyGraph is Graph'''
+"""
+# bug #3452
+import math
+
+type
+    Node* = concept n
+        `==`(n, n) is bool
+
+    Graph* = concept g
+        var x: Node
+        distance(g, x, x) is float
+
+    XY* = tuple[x, y: int]
+
+    MyGraph* = object
+        points: seq[XY]
+
+if XY is Node:
+    echo "XY is Node"
+
+proc distance*( g: MyGraph, a, b: XY): float =
+    sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
+
+if MyGraph is Graph:
+    echo "MyGraph is Graph"
+
diff --git a/web/news.txt b/web/news.txt
index d1a730ea5..f0485f75b 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -151,6 +151,9 @@ can be found `here <https://nimworkshop.splashthat.com/>`_.
     (issue `#2599 <https://github.com/nim-lang/Nim/issues/2599>`_).
   - The compiler now supports a `bitsize pragma <docs/manual.html#pragmas-bitsize-pragma>`_
     for constructing bitfields.
+  - Added a new ``--reportConceptFailures`` switch for better debugging of
+    concept related type mismatches. This can also be used to debug
+    ``system.compiles`` failures.
 
 
   Language Additions