summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2018-02-12 18:55:41 +0100
committerAraq <rumpf_a@web.de>2018-02-12 18:55:41 +0100
commit4c702d5ab22d47f24c6e7a3c6679f2d43136f2d2 (patch)
treed6b603ba1ffc1da1ed320f3a76c714326de6da78 /compiler
parent358709e9cbc4ed3e084dc6d1db313a862b8356e4 (diff)
parent04af9d4051a40a6d1c17be9730224678ce687d02 (diff)
downloadNim-4c702d5ab22d47f24c6e7a3c6679f2d43136f2d2.tar.gz
Merge branch 'devel' into araq-fixes-6960
Diffstat (limited to 'compiler')
-rw-r--r--compiler/commands.nim5
-rw-r--r--compiler/modulepaths.nim201
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/semcall.nim18
-rw-r--r--compiler/semstmts.nim2
5 files changed, 131 insertions, 102 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim
index aa7d13703..766b78798 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -274,9 +274,10 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
 
 proc processPath(path: string, info: TLineInfo,
                  notRelativeToProj = false): string =
-  let p = if notRelativeToProj or os.isAbsolute(path) or
-              '$' in path:
+  let p = if os.isAbsolute(path) or '$' in path:
             path
+          elif notRelativeToProj:
+            getCurrentDir() / path
           else:
             options.gProjectPath / path
   try:
diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim
index 5d112c6b9..878c22cf8 100644
--- a/compiler/modulepaths.nim
+++ b/compiler/modulepaths.nim
@@ -11,38 +11,39 @@ import ast, renderer, strutils, msgs, options, idents, os
 
 import nimblecmd
 
-const
-  considerParentDirs = not defined(noParentProjects)
-  considerNimbleDirs = not defined(noNimbleDirs)
+when false:
+  const
+    considerParentDirs = not defined(noParentProjects)
+    considerNimbleDirs = not defined(noNimbleDirs)
 
-proc findInNimbleDir(pkg, subdir, dir: string): string =
-  var best = ""
-  var bestv = ""
-  for k, p in os.walkDir(dir, relative=true):
-    if k == pcDir and p.len > pkg.len+1 and
-        p[pkg.len] == '-' and p.startsWith(pkg):
-      let (_, a) = getPathVersion(p)
-      if bestv.len == 0 or bestv < a:
-        bestv = a
-        best = dir / p
+  proc findInNimbleDir(pkg, subdir, dir: string): string =
+    var best = ""
+    var bestv = ""
+    for k, p in os.walkDir(dir, relative=true):
+      if k == pcDir and p.len > pkg.len+1 and
+          p[pkg.len] == '-' and p.startsWith(pkg):
+        let (_, a) = getPathVersion(p)
+        if bestv.len == 0 or bestv < a:
+          bestv = a
+          best = dir / p
 
-  if best.len > 0:
-    var f: File
-    if open(f, best / changeFileExt(pkg, ".nimble-link")):
-      # the second line contains what we're interested in, see:
-      # https://github.com/nim-lang/nimble#nimble-link
-      var override = ""
-      discard readLine(f, override)
-      discard readLine(f, override)
-      close(f)
-      if not override.isAbsolute():
-        best = best / override
-      else:
-        best = override
-  let f = if subdir.len == 0: pkg else: subdir
-  let res = addFileExt(best / f, "nim")
-  if best.len > 0 and fileExists(res):
-    result = res
+    if best.len > 0:
+      var f: File
+      if open(f, best / changeFileExt(pkg, ".nimble-link")):
+        # the second line contains what we're interested in, see:
+        # https://github.com/nim-lang/nimble#nimble-link
+        var override = ""
+        discard readLine(f, override)
+        discard readLine(f, override)
+        close(f)
+        if not override.isAbsolute():
+          best = best / override
+        else:
+          best = override
+    let f = if subdir.len == 0: pkg else: subdir
+    let res = addFileExt(best / f, "nim")
+    if best.len > 0 and fileExists(res):
+      result = res
 
 const stdlibDirs = [
   "pure", "core", "arch",
@@ -51,65 +52,66 @@ const stdlibDirs = [
   "wrappers", "wrappers/linenoise",
   "windows", "posix", "js"]
 
-proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
-  template attempt(a) =
-    let x = addFileExt(a, "nim")
-    if fileExists(x): return x
+when false:
+  proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
+    template attempt(a) =
+      let x = addFileExt(a, "nim")
+      if fileExists(x): return x
 
-  case pkg
-  of "stdlib":
-    if subdir.len == 0:
-      return options.libpath
-    else:
-      for candidate in stdlibDirs:
-        attempt(options.libpath / candidate / subdir)
-  of "root":
-    let root = project.splitFile.dir
-    if subdir.len == 0:
-      return root
+    case pkg
+    of "stdlib":
+      if subdir.len == 0:
+        return options.libpath
+      else:
+        for candidate in stdlibDirs:
+          attempt(options.libpath / candidate / subdir)
+    of "root":
+      let root = project.splitFile.dir
+      if subdir.len == 0:
+        return root
+      else:
+        attempt(root / subdir)
     else:
-      attempt(root / subdir)
-  else:
-    when considerParentDirs:
-      var p = parentDir(source.splitFile.dir)
-      # support 'import $karax':
-      let f = if subdir.len == 0: pkg else: subdir
+      when considerParentDirs:
+        var p = parentDir(source.splitFile.dir)
+        # support 'import $karax':
+        let f = if subdir.len == 0: pkg else: subdir
 
-      while p.len > 0:
-        let dir = p / pkg
-        if dirExists(dir):
-          attempt(dir / f)
-          # 2nd attempt: try to use 'karax/karax'
-          attempt(dir / pkg / f)
-          # 3rd attempt: try to use 'karax/src/karax'
-          attempt(dir / "src" / f)
-          attempt(dir / "src" / pkg / f)
-        p = parentDir(p)
+        while p.len > 0:
+          let dir = p / pkg
+          if dirExists(dir):
+            attempt(dir / f)
+            # 2nd attempt: try to use 'karax/karax'
+            attempt(dir / pkg / f)
+            # 3rd attempt: try to use 'karax/src/karax'
+            attempt(dir / "src" / f)
+            attempt(dir / "src" / pkg / f)
+          p = parentDir(p)
 
-    when considerNimbleDirs:
-      if not options.gNoNimblePath:
-        var nimbleDir = getEnv("NIMBLE_DIR")
-        if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble"
-        result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs")
-        if result.len > 0: return result
-        when not defined(windows):
-          result = findInNimbleDir(pkg, subdir, "/opt/nimble/pkgs")
+      when considerNimbleDirs:
+        if not options.gNoNimblePath:
+          var nimbleDir = getEnv("NIMBLE_DIR")
+          if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble"
+          result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs")
           if result.len > 0: return result
+          when not defined(windows):
+            result = findInNimbleDir(pkg, subdir, "/opt/nimble/pkgs")
+            if result.len > 0: return result
 
-proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
-  result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
-  if result.isNil: result = ""
+  proc scriptableImport(pkg, sub: string; info: TLineInfo): string =
+    result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info)
+    if result.isNil: result = ""
 
-proc lookupPackage(pkg, subdir: PNode): string =
-  let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
-  case pkg.kind
-  of nkStrLit, nkRStrLit, nkTripleStrLit:
-    result = scriptableImport(pkg.strVal, sub, pkg.info)
-  of nkIdent:
-    result = scriptableImport(pkg.ident.s, sub, pkg.info)
-  else:
-    localError(pkg.info, "package name must be an identifier or string literal")
-    result = ""
+  proc lookupPackage(pkg, subdir: PNode): string =
+    let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
+    case pkg.kind
+    of nkStrLit, nkRStrLit, nkTripleStrLit:
+      result = scriptableImport(pkg.strVal, sub, pkg.info)
+    of nkIdent:
+      result = scriptableImport(pkg.ident.s, sub, pkg.info)
+    else:
+      localError(pkg.info, "package name must be an identifier or string literal")
+      result = ""
 
 proc getModuleName*(n: PNode): string =
   # This returns a short relative module name without the nim extension
@@ -136,23 +138,34 @@ proc getModuleName*(n: PNode): string =
       n.sons[1] = n.sons[2]
       n.sons.setLen(2)
       return getModuleName(n.sons[0])
-    if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
-      if n0.kind == nkIdent and n0.ident.s == "/":
-        result = lookupPackage(n1[1], n[2])
-      else:
-        localError(n.info, "only '/' supported with $package notation")
-        result = ""
+    when false:
+      if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
+        if n0.kind == nkIdent and n0.ident.s == "/":
+          result = lookupPackage(n1[1], n[2])
+        else:
+          localError(n.info, "only '/' supported with $package notation")
+          result = ""
     else:
+      let modname = getModuleName(n[2])
+      if $n1 == "std":
+        template attempt(a) =
+          let x = addFileExt(a, "nim")
+          if fileExists(x): return x
+        for candidate in stdlibDirs:
+          attempt(options.libpath / candidate / modname)
+
       # hacky way to implement 'x / y /../ z':
       result = getModuleName(n1)
       result.add renderTree(n0, {renderNoComments})
-      result.add getModuleName(n[2])
+      result.add modname
   of nkPrefix:
-    if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
-      result = lookupPackage(n[1], nil)
-    else:
-      # hacky way to implement 'x / y /../ z':
-      result = renderTree(n, {renderNoComments}).replace(" ")
+    when false:
+      if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
+        result = lookupPackage(n[1], nil)
+      else:
+        discard
+    # hacky way to implement 'x / y /../ z':
+    result = renderTree(n, {renderNoComments}).replace(" ")
   of nkDotExpr:
     result = renderTree(n, {renderNoComments}).replace(".", "/")
   of nkImportAs:
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index d52d8b614..4ed1cea24 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -657,15 +657,16 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
     result = qualifiedLookUp(c, n, {checkUndeclared})
 
 proc semCustomPragma(c: PContext, n: PNode): PNode =
-  assert(n.kind in nkPragmaCallKinds + {nkIdent})
-
   if n.kind == nkIdent:
     result = newTree(nkCall, n)
   elif n.kind == nkExprColonExpr:
     # pragma: arg -> pragma(arg)
     result = newTree(nkCall, n[0], n[1])
-  else:
+  elif n.kind in nkPragmaCallKinds + {nkIdent}:
     result = n
+  else:
+    invalidPragma(n)
+    return n
 
   let r = c.semOverloadedCall(c, result, n, {skTemplate}, {})
   if r.isNil or sfCustomPragma notin r[0].sym.flags:
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index d8ee6e7a1..c4f13a237 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -124,6 +124,15 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
     else:
       break
 
+proc effectProblem(f, a: PType; result: var string) =
+  if f.kind == tyProc and a.kind == tyProc:
+    if tfThread in f.flags and tfThread notin a.flags:
+      result.add "\n  This expression is not GC-safe. Annotate the " &
+          "proc with {.gcsafe.} to get extended error information."
+    elif tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
+      result.add "\n  This expression can have side effects. Annotate the " &
+          "proc with {.noSideEffect.} to get extended error information."
+
 proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
                             (TPreferedDesc, string) =
   var prefer = preferName
@@ -158,15 +167,20 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
     if err.firstMismatch != 0 and n.len > 2:
       add(candidates, "  first type mismatch at position: " & $err.firstMismatch &
         "\n  required type: ")
+      var wanted, got: PType = nil
       if err.firstMismatch < err.sym.typ.len:
-        candidates.add typeToString(err.sym.typ.sons[err.firstMismatch])
+        wanted = err.sym.typ.sons[err.firstMismatch]
+        candidates.add typeToString(wanted)
       else:
         candidates.add "none"
       if err.firstMismatch < n.len:
         candidates.add "\n  but expression '"
         candidates.add renderTree(n[err.firstMismatch])
         candidates.add "' is of type: "
-        candidates.add typeToString(n[err.firstMismatch].typ)
+        got = n[err.firstMismatch].typ
+        candidates.add typeToString(got)
+      if wanted != nil and got != nil:
+        effectProblem(wanted, got, candidates)
       candidates.add "\n"
     elif err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
       add(candidates, "for a 'var' type a variable needs to be passed, but '" &
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index f4614272c..f0784021e 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -17,7 +17,7 @@ proc semDiscard(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
-    if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone:
+    if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
       localError(n.info, errInvalidDiscard)
 
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =