fixes more nil handling regressions

This commit is contained in:
Araq 2018-08-13 17:27:44 +02:00
commit 420ed0596b
13 changed files with 49 additions and 60 deletions

View file

@ -971,8 +971,8 @@ const
tyFloat..tyFloat128, tyUInt..tyUInt64} tyFloat..tyFloat128, tyUInt..tyUInt64}
ConstantDataTypes*: TTypeKinds = {tyArray, tySet, ConstantDataTypes*: TTypeKinds = {tyArray, tySet,
tyTuple, tySequence} tyTuple, tySequence}
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence, NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr,
tyProc, tyString, tyError} tyProc, tyError}
ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType, ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
skIterator, skIterator,
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias} skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}

View file

@ -21,14 +21,17 @@ type
formals: int formals: int
c: PContext c: PContext
subMatch: bool # subnode matches are special subMatch: bool # subnode matches are special
mappingIsFull: bool
PPatternContext = var TPatternContext PPatternContext = var TPatternContext
proc getLazy(c: PPatternContext, sym: PSym): PNode = proc getLazy(c: PPatternContext, sym: PSym): PNode =
if not isNil(c.mapping): if c.mappingIsFull:
result = c.mapping[sym.position] result = c.mapping[sym.position]
proc putLazy(c: PPatternContext, sym: PSym, n: PNode) = proc putLazy(c: PPatternContext, sym: PSym, n: PNode) =
if isNil(c.mapping): newSeq(c.mapping, c.formals) if not c.mappingIsFull:
newSeq(c.mapping, c.formals)
c.mappingIsFull = true
c.mapping[sym.position] = n c.mapping[sym.position] = n
proc matches(c: PPatternContext, p, n: PNode): bool proc matches(c: PPatternContext, p, n: PNode): bool
@ -211,6 +214,7 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
# we need to undo any bindings: # we need to undo any bindings:
when defined(nimNoNilSeqs): when defined(nimNoNilSeqs):
c.mapping = @[] c.mapping = @[]
c.mappingIsFull = false
else: else:
if not isNil(c.mapping): c.mapping = nil if not isNil(c.mapping): c.mapping = nil
return false return false

View file

@ -43,7 +43,6 @@ type
t: Thread[ptr Actor[In, Out]] t: Thread[ptr Actor[In, Out]]
PActor*[In, Out] = ptr Actor[In, Out] ## an actor PActor*[In, Out] = ptr Actor[In, Out] ## an actor
{.deprecated: [TTask: Task, TActor: Actor].}
proc spawn*[In, Out](action: proc( proc spawn*[In, Out](action: proc(
self: PActor[In, Out]){.thread.}): PActor[In, Out] = self: PActor[In, Out]){.thread.}): PActor[In, Out] =
@ -168,7 +167,7 @@ proc terminate*[In, Out](a: var ActorPool[In, Out]) =
for i in 0..<a.actors.len: join(a.actors[i]) for i in 0..<a.actors.len: join(a.actors[i])
when Out isnot void: when Out isnot void:
close(a.outputs) close(a.outputs)
a.actors = nil a.actors = @[]
proc join*[In, Out](a: var ActorPool[In, Out]) = proc join*[In, Out](a: var ActorPool[In, Out]) =
## short-cut for `sync` and then `terminate`. ## short-cut for `sync` and then `terminate`.

View file

@ -378,23 +378,23 @@ proc newMultipartData*: MultipartData =
## Constructs a new ``MultipartData`` object. ## Constructs a new ``MultipartData`` object.
MultipartData(content: @[]) MultipartData(content: @[])
proc add*(p: var MultipartData, name, content: string, filename: string = nil, proc add*(p: var MultipartData, name, content: string, filename: string = "",
contentType: string = nil) = contentType: string = "") =
## Add a value to the multipart data. Raises a `ValueError` exception if ## Add a value to the multipart data. Raises a `ValueError` exception if
## `name`, `filename` or `contentType` contain newline characters. ## `name`, `filename` or `contentType` contain newline characters.
if {'\c','\L'} in name: if {'\c','\L'} in name:
raise newException(ValueError, "name contains a newline character") raise newException(ValueError, "name contains a newline character")
if filename != nil and {'\c','\L'} in filename: if {'\c','\L'} in filename:
raise newException(ValueError, "filename contains a newline character") raise newException(ValueError, "filename contains a newline character")
if contentType != nil and {'\c','\L'} in contentType: if {'\c','\L'} in contentType:
raise newException(ValueError, "contentType contains a newline character") raise newException(ValueError, "contentType contains a newline character")
var str = "Content-Disposition: form-data; name=\"" & name & "\"" var str = "Content-Disposition: form-data; name=\"" & name & "\""
if filename != nil: if filename.len > 0:
str.add("; filename=\"" & filename & "\"") str.add("; filename=\"" & filename & "\"")
str.add("\c\L") str.add("\c\L")
if contentType != nil: if contentType.len > 0:
str.add("Content-Type: " & contentType & "\c\L") str.add("Content-Type: " & contentType & "\c\L")
str.add("\c\L" & content & "\c\L") str.add("\c\L" & content & "\c\L")
@ -434,7 +434,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
var contentType: string var contentType: string
let (_, fName, ext) = splitFile(file) let (_, fName, ext) = splitFile(file)
if ext.len > 0: if ext.len > 0:
contentType = m.getMimetype(ext[1..ext.high], nil) contentType = m.getMimetype(ext[1..ext.high], "")
p.add(name, readFile(file), fName & ext, contentType) p.add(name, readFile(file), fName & ext, contentType)
result = p result = p

View file

@ -41,16 +41,16 @@ let str2 = "NN"
let a = case str1: let a = case str1:
of "Y": true of "Y": true
of "N": false of "N": false
else: else:
echo "no good" echo "no good"
quit("quiting") quit("quiting")
proc toBool(s: string): bool = proc toBool(s: string): bool =
case s: case s:
of nil, "": raise newException(ValueError, "Invalid boolean") of "": raise newException(ValueError, "Invalid boolean")
elif s[0] == 'Y': true elif s[0] == 'Y': true
elif s[0] == 'N': false elif s[0] == 'N': false
else: "error".quit(2) else: "error".quit(2)
let b = "NN".toBool() let b = "NN".toBool()
@ -66,7 +66,7 @@ static:
var bb: bool var bb: bool
doassert(not compiles( doassert(not compiles(
bb = case str2: bb = case str2:
of nil, "": raise newException(ValueError, "Invalid boolean") of "": raise newException(ValueError, "Invalid boolean")
elif str.startsWith("Y"): true elif str.startsWith("Y"): true
elif str.startsWith("N"): false elif str.startsWith("N"): false
)) ))
@ -94,7 +94,7 @@ doassert(not compiles(
bb = case str2: bb = case str2:
of "Y": of "Y":
raise newException(ValueError, "Invalid Y") raise newException(ValueError, "Invalid Y")
true true
else: raise newException(ValueError, "Invalid") else: raise newException(ValueError, "Invalid")
)) ))
@ -103,6 +103,6 @@ doassert(not compiles(
bb = case str2: bb = case str2:
of "Y": of "Y":
"invalid Y".quit(3) "invalid Y".quit(3)
true true
else: raise newException(ValueError, "Invalid") else: raise newException(ValueError, "Invalid")
)) ))

View file

@ -7,10 +7,10 @@ Check passed'''
# bug #5628 # bug #5628
proc checkException(ex: ref Exception) = proc checkException(ex: ref Exception) =
doAssert(ex.name == "ValueError") doAssert(ex.name == cstring"ValueError")
doAssert(ex.msg == "SecondException") doAssert(ex.msg == "SecondException")
doAssert(ex.parent != nil) doAssert(ex.parent != nil)
doAssert(ex.parent.name == "KeyError") doAssert(ex.parent.name == cstring"KeyError")
doAssert(ex.parent.msg == "FirstException") doAssert(ex.parent.msg == "FirstException")
echo "Check passed" echo "Check passed"

View file

@ -1,5 +1,5 @@
discard """ discard """
line: 22 line: 13
errormsg: "type mismatch" errormsg: "type mismatch"
""" """
{.experimental: "notnil".} {.experimental: "notnil".}
@ -8,16 +8,6 @@ type
TObj = object TObj = object
x: int x: int
MyString = string not nil
#var x: PObj = nil
proc p(x: string not nil): int =
result = 45
proc q(x: MyString) = discard
proc q2(x: string) = discard proc q2(x: string) = discard
q2(nil) q2(nil)
q(nil)

View file

@ -2,4 +2,4 @@
template serializationKey*(s: string) {.pragma.} template serializationKey*(s: string) {.pragma.}
template defaultValue*(V: typed) {.pragma.} template defaultValue*(V: typed) {.pragma.}
template alternativeKey*(s: string = nil, V: typed) {.pragma.} template alternativeKey*(s: string = "", V: typed) {.pragma.}

View file

@ -26,8 +26,8 @@ doAssert "nan" == $(0.0/0.0)
var x: seq[string] var x: seq[string]
doAssert "nil" == $(x) doAssert "nil" == $(x)
var y: string = nil var y: string
doAssert nil == $(y) doAssert "" == $(y)
type type
Foo = object Foo = object
@ -54,7 +54,7 @@ doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '
doAssert $cstring(unsafeAddr arr) == "Hello World!" doAssert $cstring(unsafeAddr arr) == "Hello World!"
proc takes(c: cstring) = proc takes(c: cstring) =
doAssert c == "" doAssert c == cstring""
proc testm() = proc testm() =
var x: string var x: string
@ -90,12 +90,8 @@ proc stringCompare() =
doAssert e == "" doAssert e == ""
doAssert "" == e doAssert "" == e
doAssert nil == e
doAssert e == nil
doAssert f == g doAssert f == g
doAssert "" == "" doAssert "" == ""
doAssert "" == nil
doAssert nil == ""
g.setLen(10) g.setLen(10)
doAssert g == "\0\0\0\0\0\0\0\0\0\0" doAssert g == "\0\0\0\0\0\0\0\0\0\0"

View file

@ -5,9 +5,9 @@ discard """
import actors import actors
var var
pool: TActorPool[int, void] pool: ActorPool[int, void]
createActorPool(pool) createActorPool(pool)
for i in 0 .. < 300: for i in 0 ..< 300:
pool.spawn(i, proc (x: int) {.thread.} = echo x) pool.spawn(i, proc (x: int) {.thread.} = echo x)
pool.join() pool.join()

View file

@ -73,7 +73,7 @@ type
const const
DefaultPrec = 6 ## Default precision for floating point numbers. DefaultPrec = 6 ## Default precision for floating point numbers.
DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil) DefaultFmt: Format = (ftDefault, -1, -1, "", faDefault, fsMinus, false, false, false, "")
## Default format corresponding to the empty format string, i.e. ## Default format corresponding to the empty format string, i.e.
## `x.format("") == x.format(DefaultFmt)`. ## `x.format("") == x.format(DefaultFmt)`.
round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005] round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005]
@ -124,7 +124,7 @@ proc parse(fmt: string): Format {.nosideeffect.} =
if fmt.rawmatch(p, 0, caps) < 0: if fmt.rawmatch(p, 0, caps) < 0:
raise newException(FormatError, "Invalid format string") raise newException(FormatError, "Invalid format string")
result.fill = fmt.get(caps, 0, nil) result.fill = fmt.get(caps, 0, "")
case fmt.get(caps, 1, 0.char) case fmt.get(caps, 1, 0.char)
of '<': result.align = faLeft of '<': result.align = faLeft
@ -144,7 +144,7 @@ proc parse(fmt: string): Format {.nosideeffect.} =
result.width = fmt.get(caps, 4, -1) result.width = fmt.get(caps, 4, -1)
if caps.has(4) and fmt[caps.bounds(4).first] == '0': if caps.has(4) and fmt[caps.bounds(4).first] == '0':
if result.fill != nil: if result.fill != "":
raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character") raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character")
if result.align != faDefault: if result.align != faDefault:
raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment") raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment")
@ -171,7 +171,7 @@ proc parse(fmt: string): Format {.nosideeffect.} =
of '%': result.typ = ftPercent of '%': result.typ = ftPercent
else: result.typ = ftDefault else: result.typ = ftDefault
result.arysep = fmt.get(caps, 8, nil, 1) result.arysep = fmt.get(caps, 8, "", 1)
proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} = proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} =
## Returns the number of left and right padding characters for a ## Returns the number of left and right padding characters for a
@ -218,7 +218,7 @@ proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) =
elif fmt.sign == fsPlus: write(o, '+') elif fmt.sign == fsPlus: write(o, '+')
elif fmt.sign == fsSpace: write(o, ' ') elif fmt.sign == fsSpace: write(o, ' ')
if fmt.fill == nil: if fmt.fill.len == 0:
for i in 1..n: write(o, ' ') for i in 1..n: write(o, ' ')
else: else:
for i in 1..n: for i in 1..n:
@ -626,19 +626,19 @@ proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
else: else:
lvl.dec lvl.dec
let clpos = pos let clpos = pos
var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested) var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: "", index: int.high, nested: nested)
if fmtpart.fmt.len > 0: if fmtpart.fmt.len > 0:
var m: array[0..3, string] var m: array[0..3, string]
if not fmtpart.fmt.match(subpeg, m): if not fmtpart.fmt.match(subpeg, m):
error("invalid format string") error("invalid format string")
if m[1] != nil and m[1].len > 0: if m[1].len > 0:
fmtpart.field = m[1].substr(1) fmtpart.field = m[1].substr(1)
if m[2] != nil and m[2].len > 0: if m[2].len > 0:
discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index) discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index)
if m[0].len > 0: discard parseInt(m[0], fmtpart.arg) if m[0].len > 0: discard parseInt(m[0], fmtpart.arg)
if m[3] == nil or m[3].len == 0: if m[3].len == 0:
fmtpart.fmt = "" fmtpart.fmt = ""
elif m[3][0] == ':': elif m[3][0] == ':':
fmtpart.fmt = m[3].substr(1) fmtpart.fmt = m[3].substr(1)
@ -650,7 +650,7 @@ proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
proc literal(s: string): NimNode {.compiletime, nosideeffect.} = proc literal(s: string): NimNode {.compiletime, nosideeffect.} =
## Return the nim literal of string `s`. This handles the case if ## Return the nim literal of string `s`. This handles the case if
## `s` is nil. ## `s` is nil.
result = if s == nil: newNilLit() else: newLit(s) result = newLit(s)
proc literal(b: bool): NimNode {.compiletime, nosideeffect.} = proc literal(b: bool): NimNode {.compiletime, nosideeffect.} =
## Return the nim literal of boolean `b`. This is either `true` ## Return the nim literal of boolean `b`. This is either `true`
@ -713,7 +713,7 @@ proc generatefmt(fmtstr: string;
args[arg].cnt = args[arg].cnt + 1 args[arg].cnt = args[arg].cnt + 1
arg.inc arg.inc
# possible field access # possible field access
if part.field != nil and part.field.len > 0: if part.field.len > 0:
argexpr = newDotExpr(argexpr, part.field.ident) argexpr = newDotExpr(argexpr, part.field.ident)
# possible array access # possible array access
if part.index < int.high: if part.index < int.high:
@ -724,7 +724,7 @@ proc generatefmt(fmtstr: string;
# nested format string. Compute the format string by # nested format string. Compute the format string by
# concatenating the parts of the substring. # concatenating the parts of the substring.
for e in generatefmt(part.fmt, args, arg): for e in generatefmt(part.fmt, args, arg):
var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt) var newexpr = if part.fmt.len == 0: e.val else: newCall(bindsym"format", e.val, e.fmt)
if fmtexpr != nil and fmtexpr.kind != nnkNilLit: if fmtexpr != nil and fmtexpr.kind != nnkNilLit:
fmtexpr = infix(fmtexpr, "&", newexpr) fmtexpr = infix(fmtexpr, "&", newexpr)
else: else:

View file

@ -3,8 +3,8 @@ discard """
@[1, 2, 3]''' @[1, 2, 3]'''
""" """
template foo(s: string = nil) = template foo(s: string = "") =
if isNil(s): if s.len == 0:
echo "it's nil" echo "it's nil"
else: else:
echo s echo s

View file

@ -22,7 +22,7 @@ when true:
import os import os
type type
In_out = tuple[src, dest, options: string] In_out = tuple[src, dest: string, options: ref int]
let let
nil_var: In_out = ("hey"/"there", "something", nil) nil_var: In_out = ("hey"/"there", "something", nil)