Merge ../Nim into devel

This commit is contained in:
Charles Blake 2015-08-09 06:58:36 -04:00
commit 9c3c48a6d0
22 changed files with 455 additions and 102 deletions

View file

@ -90,3 +90,4 @@ proc initDefines*() =
defineSymbol("nimnode")
defineSymbol("nimnomagic64")
defineSymbol("nimvarargstyped")
defineSymbol("nimtypedescfixed")

View file

@ -184,7 +184,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos]
# -1 is correct here as param.position is 0 based but we have at position 0
# some nkEffect node:
param.position = params.len-1
param.position = routine.typ.n.len-1
addSon(params, newSymNode(param))
incl(routine.typ.flags, tfCapturesEnv)
assert sfFromGeneric in param.flags

View file

@ -177,6 +177,15 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
else:
return nil
proc createDestructorCall(c: PContext, s: PSym): PNode =
let varTyp = s.typ
if varTyp == nil or sfGlobal in s.flags: return
let destructableT = instantiateDestructor(c, varTyp)
if destructableT != nil:
let call = semStmt(c, newNode(nkCall, s.info, @[
useSym(destructableT.destructor), useSym(s)]))
result = newNode(nkDefer, s.info, @[call])
proc insertDestructors(c: PContext,
varSection: PNode): tuple[outer, inner: PNode] =
# Accepts a var or let section.

View file

@ -2259,7 +2259,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkStaticStmt:
result = semStaticStmt(c, n)
of nkDefer:
localError(n.info, errGenerated, "'defer' not allowed in this context")
n.sons[0] = semExpr(c, n.sons[0])
if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]):
localError(n.info, errGenerated, "'defer' takes a 'void' expression")
#localError(n.info, errGenerated, "'defer' not allowed in this context")
else:
localError(n.info, errInvalidExpressionX,
renderTree(n, {renderNoComments}))

View file

@ -141,11 +141,13 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
elif s.name.id in ctx.toMixin:
result = newDot(result, symChoice(c, n, s, scForceOpen))
else:
let sym = semGenericStmtSymbol(c, n, s, ctx)
if sym.kind == nkSym:
result = newDot(result, symChoice(c, n, s, scForceOpen))
let syms = semGenericStmtSymbol(c, n, s, ctx)
if syms.kind == nkSym:
let choice = symChoice(c, n, s, scForceOpen)
choice.kind = nkClosedSymChoice
result = newDot(result, choice)
else:
result = newDot(result, sym)
result = newDot(result, syms)
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
let s = newSymS(skUnknown, getIdentNode(n), c)

View file

@ -369,6 +369,15 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
else:
result.add identDefs
proc addDefer(c: PContext; result: var PNode; s: PSym) =
let deferDestructorCall = createDestructorCall(c, s)
if deferDestructorCall != nil:
if result.kind != nkStmtList:
let oldResult = result
result = newNodeI(nkStmtList, result.info)
result.add oldResult
result.add deferDestructorCall
proc isDiscardUnderscore(v: PSym): bool =
if v.name.s == "_":
v.flags.incl(sfGenSym)
@ -469,6 +478,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if def.kind == nkPar: v.ast = def[j]
v.typ = tup.sons[j]
b.sons[j] = newSymNode(v)
addDefer(c, result, v)
checkNilable(v)
if sfCompileTime in v.flags: hasCompileTime = true
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
@ -1371,7 +1381,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
for i in countup(0, length - 1):
let k = n.sons[i].kind
case k
of nkFinally, nkExceptBranch, nkDefer:
of nkFinally, nkExceptBranch:
# stand-alone finally and except blocks are
# transformed into regular try blocks:
#
@ -1424,21 +1434,13 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
n.typ = n.sons[i].typ
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
case n.sons[i].kind
of nkVarSection, nkLetSection:
let (outer, inner) = insertDestructors(c, n.sons[i])
if outer != nil:
n.sons[i] = outer
var rest = newNode(nkStmtList, n.info, n.sons[i+1 .. length-1])
inner.addSon(semStmtList(c, rest, flags))
n.sons.setLen(i+1)
return
of LastBlockStmts:
for j in countup(i + 1, length - 1):
case n.sons[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
else: discard
if result.len == 1:
if result.len == 1 and result.sons[0].kind != nkDefer:
result = result.sons[0]
when defined(nimfix):
if result.kind == nkCommentStmt and not result.comment.isNil and

View file

@ -184,6 +184,21 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
else:
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
# fix #2670, consider:
#
# when b:
# var a = "hi"
# else:
# var a = 5
# echo a
#
# We need to ensure that both 'a' produce the same gensym'ed symbol.
# So we need only check the *current* scope.
let s = localSearchInScope(c.c, considerQuotedIdent ident)
if s != nil and s.owner == c.owner and sfGenSym in s.flags:
styleCheckUse(n.info, s)
replaceIdentBySym(n, newSymNode(s, n.info))
else:
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
styleCheckDef(n.info, local)

View file

@ -16,6 +16,7 @@
# * converts "continue" to "break"; disambiguates "break"
# * introduces method dispatchers
# * performs lambda lifting for closure support
# * transforms 'defer' into a 'try finally' statement
import
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
@ -44,6 +45,7 @@ type
inlining: int # > 0 if we are in inlining context (copy vars)
nestedProcs: int # > 0 if we are in a nested proc
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected: bool
PTransf = ref TTransfContext
proc newTransNode(a: PNode): PTransNode {.inline.} =
@ -680,6 +682,14 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
result = n
proc transform(c: PTransf, n: PNode): PTransNode =
when false:
var oldDeferAnchor: PNode
if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
nkBlockStmt, nkBlockExpr}:
oldDeferAnchor = c.deferAnchor
c.deferAnchor = n
case n.kind
of nkSym:
result = transformSym(c, n)
@ -712,13 +722,36 @@ proc transform(c: PTransf, n: PNode): PTransNode =
result = transformFor(c, n)
of nkParForStmt:
result = transformSons(c, n)
of nkCaseStmt: result = transformCase(c, n)
of nkCaseStmt:
result = transformCase(c, n)
of nkWhileStmt: result = transformWhile(c, n)
of nkBlockStmt, nkBlockExpr:
result = transformBlock(c, n)
of nkDefer:
c.deferDetected = true
result = transformSons(c, n)
when false:
let deferPart = newNodeI(nkFinally, n.info)
deferPart.add n.sons[0]
let tryStmt = newNodeI(nkTryStmt, n.info)
if c.deferAnchor.isNil:
tryStmt.add c.root
c.root = tryStmt
result = PTransNode(tryStmt)
else:
# modify the corresponding *action*, don't rely on nkStmtList:
let L = c.deferAnchor.len-1
tryStmt.add c.deferAnchor.sons[L]
c.deferAnchor.sons[L] = tryStmt
result = newTransNode(nkCommentStmt, n.info, 0)
tryStmt.addSon(deferPart)
# disable the original 'defer' statement:
n.kind = nkCommentStmt
of nkContinueStmt:
result = PTransNode(newNodeI(nkBreakStmt, n.info))
var labl = c.contSyms[c.contSyms.high]
add(result, PTransNode(newSymNode(labl)))
of nkBreakStmt: result = transformBreak(c, n)
of nkWhileStmt: result = transformWhile(c, n)
of nkCallKinds:
result = transformCall(c, n)
of nkAddr, nkHiddenAddr:
@ -754,8 +787,6 @@ proc transform(c: PTransf, n: PNode): PTransNode =
result = transformYield(c, n)
else:
result = transformSons(c, n)
of nkBlockStmt, nkBlockExpr:
result = transformBlock(c, n)
of nkIdentDefs, nkConstDef:
result = transformSons(c, n)
# XXX comment handling really sucks:
@ -764,6 +795,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
of nkClosure: return PTransNode(n)
else:
result = transformSons(c, n)
when false:
if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
var cnst = getConstExpr(c.module, PNode(result))
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
@ -785,12 +818,52 @@ proc openTransf(module: PSym, filename: string): PTransf =
result.breakSyms = @[]
result.module = module
proc flattenStmts(n: PNode) =
var goOn = true
while goOn:
goOn = false
for i in 0..<n.len:
let it = n[i]
if it.kind in {nkStmtList, nkStmtListExpr}:
n.sons[i..i] = it.sons[0..<it.len]
goOn = true
proc liftDeferAux(n: PNode) =
if n.kind in {nkStmtList, nkStmtListExpr}:
flattenStmts(n)
var goOn = true
while goOn:
goOn = false
let last = n.len-1
for i in 0..last:
if n.sons[i].kind == nkDefer:
let deferPart = newNodeI(nkFinally, n.sons[i].info)
deferPart.add n.sons[i].sons[0]
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
var body = newNodeI(n.kind, n.sons[i].info)
if i < last:
body.sons = n.sons[(i+1)..last]
tryStmt.addSon(body)
tryStmt.addSon(deferPart)
n.sons[i] = tryStmt
n.sons.setLen(i+1)
n.typ = n.sons[i].typ
goOn = true
break
for i in 0..n.safeLen-1:
liftDeferAux(n.sons[i])
template liftDefer(c, root) =
if c.deferDetected:
liftDeferAux(root)
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
if nfTransf in n.flags or prc.kind in {skTemplate}:
result = n
else:
var c = openTransf(module, "")
result = processTransf(c, n, prc)
liftDefer(c, result)
result = liftLambdas(prc, result)
#if prc.kind == skClosureIterator:
# result = lambdalifting.liftIterator(prc, result)
@ -805,6 +878,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode =
else:
var c = openTransf(module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
result = liftLambdasForTopLevel(module, result)
incl(result.flags, nfTransf)
when useEffectSystem: trackTopLevelStmt(module, result)
@ -815,4 +889,5 @@ proc transformExpr*(module: PSym, n: PNode): PNode =
else:
var c = openTransf(module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
incl(result.flags, nfTransf)

View file

@ -432,7 +432,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
assert regs[rb].kind == rkNode
let nb = regs[rb].node
case nb.kind
of nkCharLit..nkInt64Lit:
of nkCharLit..nkUInt64Lit:
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:

View file

@ -66,12 +66,14 @@ Running tests
You can run the tests with
::
./koch tests
which will run a good subset of tests. Some tests may fail. If you
only want to see the output of failing tests, go for
::
./koch tests --failing all
You can also run only a single category of tests. A category is a subdirectory
@ -79,6 +81,7 @@ in the ``tests`` directory. There are a couple of special categories; for a
list of these, see ``tests/testament/categories.nim``, at the bottom.
::
./koch tests c lib
Comparing tests
@ -92,6 +95,7 @@ reference test. You'll also need to the commit id, because that's what
the tester needs to know in order to compare the two.
::
git checkout devel
DEVEL_COMMIT=$(git rev-parse HEAD)
./koch tests
@ -99,6 +103,7 @@ the tester needs to know in order to compare the two.
Then switch over to your changes and run the tester again.
::
git checkout your-changes
./koch tests
@ -106,6 +111,7 @@ Then you can ask the tester to create a ``testresults.html`` which will
tell you if any new tests passed/failed.
::
./koch --print html $DEVEL_COMMIT

View file

@ -226,6 +226,10 @@ proc `$`*[A, B](t: Table[A, B]): string =
## The `$` operator for hash tables.
dollarImpl()
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = t[].hasKey(key)
template equalsImpl() =
if s.counter == t.counter:
# different insertion orders mean different 'data' seqs, so we have
@ -293,10 +297,6 @@ proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
## returns true iff `key` is in the table, otherwise inserts `value`.
t[].hasKeyOrPut(key, val)
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = t[].hasKey(key)
proc contains*[A, B](t: TableRef[A, B], key: A): bool =
## alias of `hasKey` for use with the `in` operator.
return hasKey[A, B](t, key)

View file

@ -608,29 +608,29 @@ proc newJArray*(): JsonNode =
proc getStr*(n: JsonNode, default: string = ""): string =
## Retrieves the string value of a `JString JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JString``.
if n.kind != JString: return default
## Returns ``default`` if ``n`` is not a ``JString``, or if ``n`` is nil.
if n.isNil or n.kind != JString: return default
else: return n.str
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
## Retrieves the int value of a `JInt JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JInt``.
if n.kind != JInt: return default
## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
if n.isNil or n.kind != JInt: return default
else: return n.num
proc getFNum*(n: JsonNode, default: float = 0.0): float =
## Retrieves the float value of a `JFloat JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JFloat``.
if n.kind != JFloat: return default
## Returns ``default`` if ``n`` is not a ``JFloat``, or if ``n`` is nil.
if n.isNil or n.kind != JFloat: return default
else: return n.fnum
proc getBVal*(n: JsonNode, default: bool = false): bool =
## Retrieves the bool value of a `JBool JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JBool``.
if n.kind != JBool: return default
## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil.
if n.isNil or n.kind != JBool: return default
else: return n.bval
proc getFields*(n: JsonNode,
@ -638,15 +638,15 @@ proc getFields*(n: JsonNode,
seq[tuple[key: string, val: JsonNode]] =
## Retrieves the key, value pairs of a `JObject JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JObject``.
if n.kind != JObject: return default
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
if n.isNil or n.kind != JObject: return default
else: return n.fields
proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
## Retrieves the int value of a `JArray JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JArray``.
if n.kind != JArray: return default
## Returns ``default`` if ``n`` is not a ``JArray``, or if ``n`` is nil.
if n.isNil or n.kind != JArray: return default
else: return n.elems
proc `%`*(s: string): JsonNode =

View file

@ -1052,6 +1052,117 @@ proc parse*(value, layout: string): TimeInfo =
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
return info
# Leap year calculations are adapted from:
# from http://www.codeproject.com/Articles/7358/Ultra-fast-Algorithms-for-Working-with-Leap-Years
# The dayOfTheWeek procs are adapated from:
# from http://stason.org/TULARC/society/calendars/2-5-What-day-of-the-week-was-2-August-1953.html
# Note: for leap years, start date is assumed to be 1 AD.
# counts the number of leap years up to January 1st of a given year.
# Keep in mind that if specified year is a leap year, the leap day
# has not happened before January 1st of that year.
proc countLeapYears(yearSpan: int): int =
(((yearSpan - 1) / 4) - ((yearSpan - 1) / 100) + ((yearSpan - 1)/400)).int
proc countDays(yearSpan: int): int =
(yearSpan - 1) * 365 + countLeapYears(yearSpan)
proc countYears(daySpan: int): int =
# counts the number of years spanned by a given number of days.
((daySpan - countLeapYears(daySpan div 365)) div 365)
proc countYearsAndDays(daySpan: int): tuple[years: int, days: int] =
# counts the number of years spanned by a given number of days and the remainder as days.
let days = daySpan - countLeapYears(daySpan div 365)
result.years = days div 365
result.days = days mod 365
const
secondsInMin = 60
secondsInHour = 60*60
secondsInDay = 60*60*24
epochStartYear = 1970
proc getDayOfWeek*(day, month, year: int): WeekDay =
## Returns the day of the week enum from day, month and year.
# Day & month start from one.
let
a = (14 - month) div 12
y = year - a
m = month + (12*a) - 2
d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct
# for the WeekDay type.
if d == 0: return dSun
result = (d-1).WeekDay
proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
## Returns the day of the week enum from day, month and year, according to the Julian calender.
# Day & month start from one.
let
a = (14 - month) div 12
y = year - a
m = month + (12*a) - 2
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
result = d.WeekDay
proc timeToTimeInfo*(t: Time): TimeInfo =
## Converts a Time to TimeInfo.
let
daysSinceEpoch = t.int div secondsInDay
(yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
daySeconds = t.int mod secondsInDay
y = yearsSinceEpoch + epochStartYear
var
mon = mJan
days = daysRemaining
daysInMonth = getDaysInMonth(mon, y)
# calculate month and day remainder
while days > daysInMonth and mon <= mDec:
days -= daysInMonth
mon.inc
daysInMonth = getDaysInMonth(mon, y)
let
yd = daysRemaining
m = mon # month is zero indexed enum
md = days
# NB: month is zero indexed but dayOfWeek expects 1 indexed.
wd = getDayOfWeek(days, mon.int + 1, y).Weekday
h = daySeconds div secondsInHour + 1
mi = (daySeconds mod secondsInHour) div secondsInMin
s = daySeconds mod secondsInMin
result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s)
proc timetoTimeInterval*(t: Time): TimeInterval =
## Converts a Time to a TimeInterval.
var
daysSinceEpoch = t.int div secondsInDay
(yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
daySeconds = t.int mod secondsInDay
result.years = yearsSinceEpoch + epochStartYear
var
mon = mJan
days = daysRemaining
daysInMonth = getDaysInMonth(mon, result.years)
# calculate month and day remainder
while days > daysInMonth and mon <= mDec:
days -= daysInMonth
mon.inc
daysInMonth = getDaysInMonth(mon, result.years)
result.months = mon.int + 1 # month is 1 indexed int
result.days = days
result.hours = daySeconds div secondsInHour + 1
result.minutes = (daySeconds mod secondsInHour) div secondsInMin
result.seconds = daySeconds mod secondsInMin
# Milliseconds not available from Time
when isMainModule:
# $ date --date='@2147483647'
@ -1137,3 +1248,18 @@ when isMainModule:
assert "15:04:00" in $s.parse(f)
when not defined(testing):
echo "Kitchen: " & $s.parse(f)
var ti = timeToTimeInfo(getTime())
echo "Todays date after decoding: ", ti
var tint = timeToTimeInterval(getTime())
echo "Todays date after decoding to interval: ", tint
# checking dayOfWeek matches known days
assert getDayOfWeek(21, 9, 1900) == dFri
assert getDayOfWeek(1, 1, 1970) == dThu
assert getDayOfWeek(21, 9, 1970) == dMon
assert getDayOfWeek(1, 1, 2000) == dSat
assert getDayOfWeek(1, 1, 2021) == dFri
# Julian tests
assert getDayOfWeekJulian(21, 9, 1900) == dFri
assert getDayOfWeekJulian(21, 9, 1970) == dMon
assert getDayOfWeekJulian(1, 1, 2000) == dSat
assert getDayOfWeekJulian(1, 1, 2021) == dFri

View file

@ -285,7 +285,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
result = getAst(rewrite(checked, checked.lineinfo, checked.toStrLit))
template require*(conditions: stmt): stmt {.immediate, dirty.} =
template require*(conditions: stmt): stmt {.immediate.} =
## Same as `check` except any failed test causes the program to quit
## immediately. Any teardown statements are not executed and the failed
## test output is not generated.

View file

@ -577,6 +577,9 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
## that one never needs to know ``x``'s size. As a special semantic rule,
## ``x`` may also be a type identifier (``sizeof(int)`` is valid).
when defined(nimtypedescfixed):
proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.}
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
## unary ``<`` that can be used for nice looking excluding ranges:
##
@ -1500,7 +1503,7 @@ when not defined(nimrodVM):
## containing zero, so it is somewhat safer than ``createU``.
## The allocated memory belongs to its allocating thread!
## Use `createShared` to allocate from a shared heap.
cast[ptr T](alloc0(T.sizeof * size))
cast[ptr T](alloc0(sizeof(T) * size))
proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign.}
## grows or shrinks a given memory block. If p is **nil** then a new

View file

@ -0,0 +1,47 @@
discard """
output: '''assign
destroy
destroy
destroy Foo: 5
5
destroy Foo: 123
123'''
"""
# bug #2821
{.experimental.}
type T = object
proc `=`(lhs: var T, rhs: T) =
echo "assign"
proc `=destroy`(v: var T) =
echo "destroy"
block:
var v1 : T
var v2 : T = v1
# bug #1632
type
Foo = object of RootObj
x: int
proc `=destroy`(a: var Foo) =
echo "destroy Foo: " & $a.x
template toFooPtr(a: int{lit}): ptr Foo =
var temp = Foo(x:a)
temp.addr
proc test(a: ptr Foo) =
echo a[].x
proc main =
test(toFooPtr(5))
test(toFooPtr(123))
main()

View file

@ -1,6 +1,11 @@
discard """
output: '''hi
hi'''
hi
1
hi
2
B
A'''
"""
# bug #1742
@ -16,3 +21,23 @@ import strutils
let x = try: parseInt("133a")
except: -1
finally: echo "hi"
template atFuncEnd =
defer:
echo "A"
defer:
echo "B"
template testB(): expr =
let a = 0
defer: echo "hi" # Delete this line to make it work
a
proc main =
atFuncEnd()
echo 1
let i = testB()
echo 2
main()

View file

@ -0,0 +1,10 @@
type R* = object
type Data*[T] = object
d*: T
proc same(r:R, d:int) = echo "TEST2"
proc doIt*(d:Data, r:R) =
r.same(1) # Expecting this to invoke the local `same()` method

View file

@ -0,0 +1,11 @@
discard """
output: "TEST2"
"""
# bug #2664
import mclosed_sym
proc same(r:R, d:int) = echo "TEST1"
doIt(Data[int](d:123), R())

View file

@ -21,6 +21,11 @@ test "unittest typedescs":
check(none(int) != some(1))
test "unittest multiple requires":
require(true)
require(true)
import math
from strutils import parseInt
proc defectiveRobot() =

View file

@ -0,0 +1,13 @@
discard """
output: "hi"
"""
# bug #2670
template testTemplate(b: bool): stmt =
when b:
var a = "hi"
else:
var a = 5
echo a
testTemplate(true)