Merge branch 'devel' into araq-fixes-6960
This commit is contained in:
commit
4c702d5ab2
10 changed files with 191 additions and 111 deletions
|
|
@ -251,3 +251,12 @@ bar()
|
||||||
- The ``securehash`` module is now deprecated. Instead import ``std / sha1``.
|
- The ``securehash`` module is now deprecated. Instead import ``std / sha1``.
|
||||||
- ``db_mysql`` module: ``DbConn`` is now a ``distinct`` type that doesn't expose the
|
- ``db_mysql`` module: ``DbConn`` is now a ``distinct`` type that doesn't expose the
|
||||||
details of the underlying ``PMySQL`` type.
|
details of the underlying ``PMySQL`` type.
|
||||||
|
- Standard library modules can now also be imported via the ``std`` pseudo-directory.
|
||||||
|
This is useful in order to distinguish between standard library and nimble package
|
||||||
|
imports:
|
||||||
|
|
||||||
|
```nim
|
||||||
|
|
||||||
|
import std / [strutils, os, osproc]
|
||||||
|
import someNimblePackage / [strutils, os]
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -274,9 +274,10 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||||
|
|
||||||
proc processPath(path: string, info: TLineInfo,
|
proc processPath(path: string, info: TLineInfo,
|
||||||
notRelativeToProj = false): string =
|
notRelativeToProj = false): string =
|
||||||
let p = if notRelativeToProj or os.isAbsolute(path) or
|
let p = if os.isAbsolute(path) or '$' in path:
|
||||||
'$' in path:
|
|
||||||
path
|
path
|
||||||
|
elif notRelativeToProj:
|
||||||
|
getCurrentDir() / path
|
||||||
else:
|
else:
|
||||||
options.gProjectPath / path
|
options.gProjectPath / path
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import ast, renderer, strutils, msgs, options, idents, os
|
||||||
|
|
||||||
import nimblecmd
|
import nimblecmd
|
||||||
|
|
||||||
|
when false:
|
||||||
const
|
const
|
||||||
considerParentDirs = not defined(noParentProjects)
|
considerParentDirs = not defined(noParentProjects)
|
||||||
considerNimbleDirs = not defined(noNimbleDirs)
|
considerNimbleDirs = not defined(noNimbleDirs)
|
||||||
|
|
@ -51,6 +52,7 @@ const stdlibDirs = [
|
||||||
"wrappers", "wrappers/linenoise",
|
"wrappers", "wrappers/linenoise",
|
||||||
"windows", "posix", "js"]
|
"windows", "posix", "js"]
|
||||||
|
|
||||||
|
when false:
|
||||||
proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
|
proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string =
|
||||||
template attempt(a) =
|
template attempt(a) =
|
||||||
let x = addFileExt(a, "nim")
|
let x = addFileExt(a, "nim")
|
||||||
|
|
@ -136,6 +138,7 @@ proc getModuleName*(n: PNode): string =
|
||||||
n.sons[1] = n.sons[2]
|
n.sons[1] = n.sons[2]
|
||||||
n.sons.setLen(2)
|
n.sons.setLen(2)
|
||||||
return getModuleName(n.sons[0])
|
return getModuleName(n.sons[0])
|
||||||
|
when false:
|
||||||
if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
|
if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
|
||||||
if n0.kind == nkIdent and n0.ident.s == "/":
|
if n0.kind == nkIdent and n0.ident.s == "/":
|
||||||
result = lookupPackage(n1[1], n[2])
|
result = lookupPackage(n1[1], n[2])
|
||||||
|
|
@ -143,14 +146,24 @@ proc getModuleName*(n: PNode): string =
|
||||||
localError(n.info, "only '/' supported with $package notation")
|
localError(n.info, "only '/' supported with $package notation")
|
||||||
result = ""
|
result = ""
|
||||||
else:
|
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':
|
# hacky way to implement 'x / y /../ z':
|
||||||
result = getModuleName(n1)
|
result = getModuleName(n1)
|
||||||
result.add renderTree(n0, {renderNoComments})
|
result.add renderTree(n0, {renderNoComments})
|
||||||
result.add getModuleName(n[2])
|
result.add modname
|
||||||
of nkPrefix:
|
of nkPrefix:
|
||||||
|
when false:
|
||||||
if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
|
if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
|
||||||
result = lookupPackage(n[1], nil)
|
result = lookupPackage(n[1], nil)
|
||||||
else:
|
else:
|
||||||
|
discard
|
||||||
# hacky way to implement 'x / y /../ z':
|
# hacky way to implement 'x / y /../ z':
|
||||||
result = renderTree(n, {renderNoComments}).replace(" ")
|
result = renderTree(n, {renderNoComments}).replace(" ")
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
|
|
|
||||||
|
|
@ -657,15 +657,16 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||||
result = qualifiedLookUp(c, n, {checkUndeclared})
|
result = qualifiedLookUp(c, n, {checkUndeclared})
|
||||||
|
|
||||||
proc semCustomPragma(c: PContext, n: PNode): PNode =
|
proc semCustomPragma(c: PContext, n: PNode): PNode =
|
||||||
assert(n.kind in nkPragmaCallKinds + {nkIdent})
|
|
||||||
|
|
||||||
if n.kind == nkIdent:
|
if n.kind == nkIdent:
|
||||||
result = newTree(nkCall, n)
|
result = newTree(nkCall, n)
|
||||||
elif n.kind == nkExprColonExpr:
|
elif n.kind == nkExprColonExpr:
|
||||||
# pragma: arg -> pragma(arg)
|
# pragma: arg -> pragma(arg)
|
||||||
result = newTree(nkCall, n[0], n[1])
|
result = newTree(nkCall, n[0], n[1])
|
||||||
else:
|
elif n.kind in nkPragmaCallKinds + {nkIdent}:
|
||||||
result = n
|
result = n
|
||||||
|
else:
|
||||||
|
invalidPragma(n)
|
||||||
|
return n
|
||||||
|
|
||||||
let r = c.semOverloadedCall(c, result, n, {skTemplate}, {})
|
let r = c.semOverloadedCall(c, result, n, {skTemplate}, {})
|
||||||
if r.isNil or sfCustomPragma notin r[0].sym.flags:
|
if r.isNil or sfCustomPragma notin r[0].sym.flags:
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,15 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
else:
|
else:
|
||||||
break
|
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):
|
proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
(TPreferedDesc, string) =
|
(TPreferedDesc, string) =
|
||||||
var prefer = preferName
|
var prefer = preferName
|
||||||
|
|
@ -158,15 +167,20 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||||
if err.firstMismatch != 0 and n.len > 2:
|
if err.firstMismatch != 0 and n.len > 2:
|
||||||
add(candidates, " first type mismatch at position: " & $err.firstMismatch &
|
add(candidates, " first type mismatch at position: " & $err.firstMismatch &
|
||||||
"\n required type: ")
|
"\n required type: ")
|
||||||
|
var wanted, got: PType = nil
|
||||||
if err.firstMismatch < err.sym.typ.len:
|
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:
|
else:
|
||||||
candidates.add "none"
|
candidates.add "none"
|
||||||
if err.firstMismatch < n.len:
|
if err.firstMismatch < n.len:
|
||||||
candidates.add "\n but expression '"
|
candidates.add "\n but expression '"
|
||||||
candidates.add renderTree(n[err.firstMismatch])
|
candidates.add renderTree(n[err.firstMismatch])
|
||||||
candidates.add "' is of type: "
|
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"
|
candidates.add "\n"
|
||||||
elif err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
|
elif err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
|
||||||
add(candidates, "for a 'var' type a variable needs to be passed, but '" &
|
add(candidates, "for a 'var' type a variable needs to be passed, but '" &
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ proc semDiscard(c: PContext, n: PNode): PNode =
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
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)
|
localError(n.info, errInvalidDiscard)
|
||||||
|
|
||||||
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -425,19 +425,19 @@ proc toHtmlTag(s: string): HtmlTag =
|
||||||
|
|
||||||
|
|
||||||
proc htmlTag*(n: XmlNode): HtmlTag =
|
proc htmlTag*(n: XmlNode): HtmlTag =
|
||||||
## gets `n`'s tag as a ``HtmlTag``.
|
## Gets `n`'s tag as a ``HtmlTag``.
|
||||||
if n.clientData == 0:
|
if n.clientData == 0:
|
||||||
n.clientData = toHtmlTag(n.tag).ord
|
n.clientData = toHtmlTag(n.tag).ord
|
||||||
result = HtmlTag(n.clientData)
|
result = HtmlTag(n.clientData)
|
||||||
|
|
||||||
proc htmlTag*(s: string): HtmlTag =
|
proc htmlTag*(s: string): HtmlTag =
|
||||||
## converts `s` to a ``HtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is
|
## Converts `s` to a ``HtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is
|
||||||
## returned.
|
## returned.
|
||||||
let s = if allLower(s): s else: toLowerAscii(s)
|
let s = if allLower(s): s else: toLowerAscii(s)
|
||||||
result = toHtmlTag(s)
|
result = toHtmlTag(s)
|
||||||
|
|
||||||
proc entityToUtf8*(entity: string): string =
|
proc entityToUtf8*(entity: string): string =
|
||||||
## converts an HTML entity name like ``Ü`` to its UTF-8 equivalent.
|
## Converts an HTML entity name like ``Ü`` to its UTF-8 equivalent.
|
||||||
## "" is returned if the entity name is unknown. The HTML parser
|
## "" is returned if the entity name is unknown. The HTML parser
|
||||||
## already converts entities to UTF-8.
|
## already converts entities to UTF-8.
|
||||||
for name, val in items(Entities):
|
for name, val in items(Entities):
|
||||||
|
|
@ -565,7 +565,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
|
||||||
|
|
||||||
proc parseHtml*(s: Stream, filename: string,
|
proc parseHtml*(s: Stream, filename: string,
|
||||||
errors: var seq[string]): XmlNode =
|
errors: var seq[string]): XmlNode =
|
||||||
## parses the XML from stream `s` and returns a ``PXmlNode``. Every
|
## Parses the XML from stream `s` and returns a ``XmlNode``. Every
|
||||||
## occurred parsing error is added to the `errors` sequence.
|
## occurred parsing error is added to the `errors` sequence.
|
||||||
var x: XmlParser
|
var x: XmlParser
|
||||||
open(x, s, filename, {reportComments, reportWhitespace})
|
open(x, s, filename, {reportComments, reportWhitespace})
|
||||||
|
|
@ -588,14 +588,19 @@ proc parseHtml*(s: Stream, filename: string,
|
||||||
result = result[0]
|
result = result[0]
|
||||||
|
|
||||||
proc parseHtml*(s: Stream): XmlNode =
|
proc parseHtml*(s: Stream): XmlNode =
|
||||||
## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing
|
## Parses the HTML from stream `s` and returns a ``XmlNode``. All parsing
|
||||||
## errors are ignored.
|
## errors are ignored.
|
||||||
var errors: seq[string] = @[]
|
var errors: seq[string] = @[]
|
||||||
result = parseHtml(s, "unknown_html_doc", errors)
|
result = parseHtml(s, "unknown_html_doc", errors)
|
||||||
|
|
||||||
|
proc parseHtml*(html: string): XmlNode =
|
||||||
|
## Parses the HTML from string ``html`` and returns a ``XmlNode``. All parsing
|
||||||
|
## errors are ignored.
|
||||||
|
parseHtml(newStringStream(html))
|
||||||
|
|
||||||
proc loadHtml*(path: string, errors: var seq[string]): XmlNode =
|
proc loadHtml*(path: string, errors: var seq[string]): XmlNode =
|
||||||
## Loads and parses HTML from file specified by ``path``, and returns
|
## Loads and parses HTML from file specified by ``path``, and returns
|
||||||
## a ``PXmlNode``. Every occurred parsing error is added to
|
## a ``XmlNode``. Every occurred parsing error is added to
|
||||||
## the `errors` sequence.
|
## the `errors` sequence.
|
||||||
var s = newFileStream(path, fmRead)
|
var s = newFileStream(path, fmRead)
|
||||||
if s == nil: raise newException(IOError, "Unable to read file: " & path)
|
if s == nil: raise newException(IOError, "Unable to read file: " & path)
|
||||||
|
|
@ -603,7 +608,7 @@ proc loadHtml*(path: string, errors: var seq[string]): XmlNode =
|
||||||
|
|
||||||
proc loadHtml*(path: string): XmlNode =
|
proc loadHtml*(path: string): XmlNode =
|
||||||
## Loads and parses HTML from file specified by ``path``, and returns
|
## Loads and parses HTML from file specified by ``path``, and returns
|
||||||
## a ``PXmlNode``. All parsing errors are ignored.
|
## a ``XmlNode``. All parsing errors are ignored.
|
||||||
var errors: seq[string] = @[]
|
var errors: seq[string] = @[]
|
||||||
result = loadHtml(path, errors)
|
result = loadHtml(path, errors)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1896,7 +1896,7 @@ macro to*(node: JsonNode, T: typedesc): untyped =
|
||||||
## doAssert data.person.age == 21
|
## doAssert data.person.age == 21
|
||||||
## doAssert data.list == @[1, 2, 3, 4]
|
## doAssert data.list == @[1, 2, 3, 4]
|
||||||
|
|
||||||
let typeNode = getType(T)
|
let typeNode = getTypeInst(T)
|
||||||
expectKind(typeNode, nnkBracketExpr)
|
expectKind(typeNode, nnkBracketExpr)
|
||||||
doAssert(($typeNode[0]).normalize == "typedesc")
|
doAssert(($typeNode[0]).normalize == "typedesc")
|
||||||
|
|
||||||
|
|
|
||||||
30
tests/errmsgs/tgcsafety.nim
Normal file
30
tests/errmsgs/tgcsafety.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim check $file"
|
||||||
|
errormsg: "type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]{.locks: <unknown>.}>"
|
||||||
|
nimout: '''
|
||||||
|
type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]{.locks: <unknown>.}>
|
||||||
|
but expected one of:
|
||||||
|
proc serve(server: AsyncHttpServer; port: Port;
|
||||||
|
callback: proc (request: Request): Future[void]; address = ""): Future[void]
|
||||||
|
first type mismatch at position: 3
|
||||||
|
required type: proc (request: Request): Future[system.void]{.closure, gcsafe.}
|
||||||
|
but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: <unknown>.}
|
||||||
|
This expression is not GC-safe. Annotate the proc with {.gcsafe.} to get extended error information.
|
||||||
|
|
||||||
|
expression: serve(server, Port(7898), cb)
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #6186
|
||||||
|
|
||||||
|
import asyncdispatch, asynchttpserver
|
||||||
|
|
||||||
|
var server = newAsyncHttpServer()
|
||||||
|
|
||||||
|
var foo = "foo"
|
||||||
|
proc cb(req: Request) {.async.} =
|
||||||
|
var baa = foo & "asds"
|
||||||
|
await req.respond(Http200, baa)
|
||||||
|
|
||||||
|
asyncCheck server.serve(Port(7898), cb )
|
||||||
|
runForever()
|
||||||
|
|
@ -381,3 +381,10 @@ when isMainModule:
|
||||||
doAssert dataDeser.a == 1
|
doAssert dataDeser.a == 1
|
||||||
doAssert dataDeser.f == 6
|
doAssert dataDeser.f == 6
|
||||||
doAssert dataDeser.i == 9.9'f32
|
doAssert dataDeser.i == 9.9'f32
|
||||||
|
|
||||||
|
# deserialize directly into a table
|
||||||
|
block:
|
||||||
|
let s = """{"a": 1, "b": 2}"""
|
||||||
|
let t = parseJson(s).to(Table[string, int])
|
||||||
|
doAssert t["a"] == 1
|
||||||
|
doAssert t["b"] == 2
|
||||||
Loading…
Add table
Add a link
Reference in a new issue