summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/lookups.nim21
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--compiler/semcall.nim13
-rw-r--r--compiler/semexprs.nim2
-rw-r--r--compiler/semgnrc.nim2
-rw-r--r--compiler/semmagic.nim2
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtempl.nim2
-rw-r--r--compiler/sigmatch.nim2
-rw-r--r--doc/manual/type_rel.txt2
-rw-r--r--lib/system/nimscript.nim2
-rw-r--r--readme.md4
-rw-r--r--tests/converter/tor_in_converter.nim23
-rw-r--r--tests/generics/twrong_explicit_typeargs.nim2
-rw-r--r--tests/lookups/test.nim17
15 files changed, 74 insertions, 26 deletions
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 9ca864406..df19a6afb 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -99,8 +99,11 @@ proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
 
 proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
   for scope in walkScopes(c.currentScope):
-    result = strTableGet(scope.symbols, s)
-    if result != nil and result.kind in filter: return
+    var ti: TIdentIter
+    var candidate = initIdentIter(ti, scope.symbols, s)
+    while candidate != nil:
+      if candidate.kind in filter: return candidate
+      candidate = nextIdentIter(ti, scope.symbols)
   result = nil
 
 proc errorSym*(c: PContext, n: PNode): PSym =
@@ -266,13 +269,17 @@ proc lookUp*(c: PContext, n: PNode): PSym =
 
 type
   TLookupFlag* = enum
-    checkAmbiguity, checkUndeclared
+    checkAmbiguity, checkUndeclared, checkModule
 
-proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
+proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
+  const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
   case n.kind
   of nkIdent, nkAccQuoted:
     var ident = considerQuotedIdent(n)
-    result = searchInScopes(c, ident).skipAlias(n)
+    if checkModule in flags:
+      result = searchInScopes(c, ident).skipAlias(n)
+    else:
+      result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
     if result == nil and checkUndeclared in flags:
       fixSpelling(n, ident, searchInScopes)
       localError(n.info, errUndeclaredIdentifier, ident.s)
@@ -286,7 +293,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
       errorUseQualifier(c, n.info, n.sym)
   of nkDotExpr:
     result = nil
-    var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
+    var m = qualifiedLookUp(c, n.sons[0], (flags*{checkUndeclared})+{checkModule})
     if m != nil and m.kind == skModule:
       var ident: PIdent = nil
       if n.sons[1].kind == nkIdent:
@@ -331,7 +338,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
     o.mode = oimDone
   of nkDotExpr:
     o.mode = oimOtherModule
-    o.m = qualifiedLookUp(c, n.sons[0])
+    o.m = qualifiedLookUp(c, n.sons[0], {checkUndeclared, checkModule})
     if o.m != nil and o.m.kind == skModule:
       var ident: PIdent = nil
       if n.sons[1].kind == nkIdent:
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 50d5bb1b5..781aab687 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -569,7 +569,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
     localError(pragma.info, "list of key:value pairs expected"); return
   for n in pragma:
     if n.kind in {nkExprColonExpr, nkExprEqExpr}:
-      let dest = qualifiedLookUp(c, n[1])
+      let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
       let src = considerQuotedIdent(n[0])
       let alias = newSym(skAlias, src, dest, n[0].info)
       incl(alias.flags, sfExported)
@@ -594,7 +594,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
       # and perform the lookup on demand instead.
       result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
   else:
-    result = qualifiedLookUp(c, n)
+    result = qualifiedLookUp(c, n, {checkUndeclared})
 
 proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
                   validPragmas: TSpecialWords): bool =
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index c62f53a62..97209167d 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -396,12 +396,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
     let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
     let arg = n[i].typ
     let tm = typeRel(m, formal, arg, true)
-    if tm in {isNone, isConvertible}:
-      if formal.sonsLen > 0 and formal.sons[0].kind != tyNone:
-        typeMismatch(n, formal.sons[0], arg)
-      else:
-        typeMismatch(n, formal, arg)
-      break
+    if tm in {isNone, isConvertible}: return nil
   var newInst = generateInstance(c, s, m.bindings, n.info)
   markUsed(n.info, s)
   styleCheckUse(n.info, s)
@@ -422,6 +417,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
          "; got " & $(n.len-1) & " type(s) but expected " & $expected)
       return n
     result = explicitGenericSym(c, n, s)
+    if result == nil: result = explicitGenericInstError(n)
   elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
     # choose the generic proc with the proper number of type parameters.
     # XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
@@ -434,11 +430,12 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
         # it suffices that the candidate has the proper number of generic
         # type parameters:
         if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
-          result.add(explicitGenericSym(c, n, candidate))
+          let x = explicitGenericSym(c, n, candidate)
+          if x != nil: result.add(x)
     # get rid of nkClosedSymChoice if not ambiguous:
     if result.len == 1 and a.kind == nkClosedSymChoice:
       result = result[0]
-    # candidateCount != 1: return explicitGenericInstError(n)
+    elif result.len == 0: result = explicitGenericInstError(n)
   else:
     result = explicitGenericInstError(n)
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 2d5e97fa1..70f795d4a 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1107,7 +1107,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # here at all!
   #if isSymChoice(n.sons[1]): return
 
-  var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
+  var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
   if s != nil:
     if s.kind in OverloadableSyms:
       result = symChoice(c, n, s, scClosed)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index e4fd715da..9ea3efd0c 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -127,7 +127,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
   assert n.kind == nkDotExpr
   semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
 
-  let luf = if withinMixin notin flags: {checkUndeclared} else: {}
+  let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
 
   var s = qualifiedLookUp(c, n, luf)
   if s != nil:
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 451745884..d9fec6275 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -133,7 +133,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
     return errorNode(c, n)
 
   let id = newIdentNode(getIdent(sl.strVal), n.info)
-  let s = qualifiedLookUp(c, id)
+  let s = qualifiedLookUp(c, id, {checkUndeclared})
   if s != nil:
     # we need to mark all symbols:
     var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index f59acd7be..ab9ecd1a6 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -675,7 +675,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     let name = a.sons[0]
     var s: PSym
     if name.kind == nkDotExpr:
-      s = qualifiedLookUp(c, name)
+      s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
       if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
         localError(name.info, "only .partial objects can be extended")
     else:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 9341e2929..4d3b6d038 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -80,7 +80,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
     # the same symbol!
     # This is however not true anymore for hygienic templates as semantic
     # processing for them changes the symbol table...
-    let s = qualifiedLookUp(c, a)
+    let s = qualifiedLookUp(c, a, {checkUndeclared})
     if s != nil:
       # we need to mark all symbols:
       let sc = symChoice(c, n, s, scClosed)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index df094402c..95f5f0b07 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1031,6 +1031,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         if x < isSubtype: return isNone
         # 'and' implies minimum matching result:
         if x < result: result = x
+      if result > isGeneric: result = isGeneric
       bindingRet result
 
   of tyOr:
@@ -1041,6 +1042,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         # 'or' implies maximum matching result:
         if x > result: result = x
       if result >= isSubtype:
+        if result > isGeneric: result = isGeneric
         bindingRet result
       else:
         result = isNone
diff --git a/doc/manual/type_rel.txt b/doc/manual/type_rel.txt
index b9b83919c..5b68f73aa 100644
--- a/doc/manual/type_rel.txt
+++ b/doc/manual/type_rel.txt
@@ -313,7 +313,7 @@ matches better than just ``T`` then.
 Automatic dereferencing
 -----------------------
 
-If the `experimental mode <experimental pragma>`_ is active and no other match
+If the `experimental mode <#pragmas-experimental-pragma>`_ is active and no other match
 is found, the first argument ``a`` is dereferenced automatically if it's a
 pointer type and overloading resolution is tried with ``a[]`` instead.
 
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index cc96bcba8..ad2b154d4 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -234,7 +234,7 @@ proc cd*(dir: string) {.raises: [OSError].} =
   ##
   ## The change is permanent for the rest of the execution, since this is just
   ## a shortcut for `os.setCurrentDir()
-  ## <http://nim-lang.org/os.html#setCurrentDir,string>`_ . Use the `withDir()
+  ## <http://nim-lang.org/docs/os.html#setCurrentDir,string>`_ . Use the `withDir()
   ## <#withDir>`_ template if you want to perform a temporary change only.
   setCurrentDir(dir)
   checkOsError()
diff --git a/readme.md b/readme.md
index fbaa5fd32..f56b054d6 100644
--- a/readme.md
+++ b/readme.md
@@ -27,6 +27,8 @@ To build from source you will need:
     are: clang, Visual C++, Intel's C++ compiler
   * git or wget
 
+**Note:** When installing ``gcc`` on Ubuntu (and likely other distros) ensure that the ``build-essentials`` package is installed also.
+
 If you are on a fairly modern *nix system, the following steps should work:
 
 ```
@@ -47,7 +49,7 @@ The above steps can be performed on Windows in a similar fashion, the
 instead of ``build.sh``.
 
 The ``koch`` tool is the Nim build tool, more ``koch`` related options are
-documented in [doc/koch.txt](doc/koch.txt).
+documented in [doc/koch.rst](doc/koch.rst).
 
 ## Nimble
 [Nimble](https://github.com/nim-lang/nimble) is Nim's package manager. For the
diff --git a/tests/converter/tor_in_converter.nim b/tests/converter/tor_in_converter.nim
new file mode 100644
index 000000000..5674526a1
--- /dev/null
+++ b/tests/converter/tor_in_converter.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''test
+test'''
+"""
+# bug #4537
+
+# nim js --d:nodejs
+
+type
+  Str = distinct string
+
+when true:
+  # crashes
+  converter convert(s: string | cstring): Str = Str($s)
+else:
+  # works!
+  converter convert(s: string): Str = Str($s)
+  converter convert(s: cstring): Str = Str($s)
+
+proc echoStr(s: Str) = echo s.string
+
+echoStr("test")
+echoStr("test".cstring)
diff --git a/tests/generics/twrong_explicit_typeargs.nim b/tests/generics/twrong_explicit_typeargs.nim
index 37d5b1e38..e47b38e99 100644
--- a/tests/generics/twrong_explicit_typeargs.nim
+++ b/tests/generics/twrong_explicit_typeargs.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "type mismatch: got (string) but expected 'int32 or int64'"
+  errormsg: "cannot instantiate: 'newImage[string]'"
   line: 16
 """
 
diff --git a/tests/lookups/test.nim b/tests/lookups/test.nim
new file mode 100644
index 000000000..a17d235a4
--- /dev/null
+++ b/tests/lookups/test.nim
@@ -0,0 +1,17 @@
+# This file needs to be called 'test' nim to provoke a clash
+# with the unittest.test name. Issue #
+
+import unittest, macros
+
+# bug #4555
+
+macro memo(n: untyped): typed =
+  result = n
+
+proc fastFib(n: int): int {.memo.} = 40
+proc fib(n: int): int = 40
+
+suite "memoization":
+  test "recursive function memoization":
+    check fastFib(40) == fib(40)
+