summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2020-06-07 09:55:56 +0200
committerGitHub <noreply@github.com>2020-06-07 09:55:56 +0200
commit66c50c2ffcfdd31f9f1eecfaf23b1b58b22d3a36 (patch)
tree6b20a4fea12283ae5ec7f08004f7dc4bca3ba6e8
parent51b71e35f2c0000def4f35d65ceb28ecdeb7ee10 (diff)
downloadNim-66c50c2ffcfdd31f9f1eecfaf23b1b58b22d3a36.tar.gz
implement the 'bind' statement for generics, it was an oversight that this was never implemented (#14584)
-rw-r--r--compiler/semgnrc.nim15
-rw-r--r--tests/lookups/tbind_for_generics.nim17
2 files changed, 28 insertions, 4 deletions
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 6fefc2233..23b6e9b9d 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -28,7 +28,7 @@ proc getIdentNode(c: PContext; n: PNode): PNode =
 
 type
   GenericCtx = object
-    toMixin: IntSet
+    toMixin, toBind: IntSet
     cursorInBody: bool # only for nimsuggest
     bracketExpr: PNode
 
@@ -124,7 +124,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
     if ident.id notin ctx.toMixin and withinMixin notin flags:
       errorUndeclaredIdentifier(c, n.info, ident.s)
   else:
-    if withinBind in flags:
+    if withinBind in flags or s.id in ctx.toBind:
       result = symChoice(c, n, s, scClosed)
     elif s.isMixedIn:
       result = symChoice(c, n, s, scForceOpen)
@@ -155,7 +155,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
     var s = searchInScopes(c, ident, routineKinds).skipAlias(n, c.config)
     if s != nil:
       isMacro = s.kind in {skTemplate, skMacro}
-      if withinBind in flags:
+      if withinBind in flags or s.id in ctx.toBind:
         result = newDot(result, symChoice(c, n, s, scClosed))
       elif s.isMixedIn:
         result = newDot(result, symChoice(c, n, s, scForceOpen))
@@ -211,6 +211,8 @@ proc semGenericStmt(c: PContext, n: PNode,
     result = semGenericStmt(c, n[0], flags+{withinBind}, ctx)
   of nkMixinStmt:
     result = semMixinStmt(c, n, ctx.toMixin)
+  of nkBindStmt:
+    result = semBindStmt(c, n, ctx.toBind)
   of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
     # check if it is an expression macro:
     checkMinSonsLen(n, 1, c.config)
@@ -227,7 +229,10 @@ proc semGenericStmt(c: PContext, n: PNode,
     if s != nil:
       incl(s.flags, sfUsed)
       mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mAstToStr}
-      let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen)
+      let whichChoice = if s.id in ctx.toBind: scClosed
+                        elif s.isMixedIn: scForceOpen
+                        else: scOpen
+      let sc = symChoice(c, fn, s, whichChoice)
       case s.kind
       of skMacro:
         if macroToExpand(s) and sc.safeLen <= 1:
@@ -492,12 +497,14 @@ proc semGenericStmt(c: PContext, n: PNode,
 proc semGenericStmt(c: PContext, n: PNode): PNode =
   var ctx: GenericCtx
   ctx.toMixin = initIntSet()
+  ctx.toBind = initIntSet()
   result = semGenericStmt(c, n, {}, ctx)
   semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
 
 proc semConceptBody(c: PContext, n: PNode): PNode =
   var ctx: GenericCtx
   ctx.toMixin = initIntSet()
+  ctx.toBind = initIntSet()
   result = semGenericStmt(c, n, {withinConcept}, ctx)
   semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
 
diff --git a/tests/lookups/tbind_for_generics.nim b/tests/lookups/tbind_for_generics.nim
new file mode 100644
index 000000000..db5fbebbc
--- /dev/null
+++ b/tests/lookups/tbind_for_generics.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "type mismatch: got <Foo, Foo>"
+  line: 8
+"""
+proc g[T](x: T) =
+  bind `+`
+  # because we bind `+` here, we must not find the `+` for 'Foo' below:
+  echo x + x
+
+type
+  Foo = object
+    a: int
+
+proc `+`(a, b: Foo): Foo = Foo(a: a.a+b.a)
+
+g(3)
+g(Foo(a: 8))