renamed inCompilesContext to compilesContextId; added test case for #3313

This commit is contained in:
Araq
2015-09-18 11:29:43 +02:00
parent 5b2f54ffa1
commit c921f30b1d
7 changed files with 112 additions and 14 deletions

View File

@@ -116,7 +116,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's imported from some unknown module to prevent cascading errors:
if gCmd != cmdInteractive and c.inCompilesContext == 0:
if gCmd != cmdInteractive and c.compilesContextId == 0:
c.importTable.addSym(result)
type

View File

@@ -95,7 +95,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
if c.inCompilesContext > 0:
if c.compilesContextId > 0:
# fail fast:
globalError(n.info, errTypeMismatch, "")
if errors.isNil or errors.len == 0:
@@ -235,7 +235,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
internalAssert result.state == csMatch
#writeMatches(result)
#writeMatches(alt)
if c.inCompilesContext > 0:
if c.compilesContextId > 0:
# quick error message for performance of 'compiles' built-in:
globalError(n.info, errGenerated, "ambiguous call")
elif gErrorCounter == 0:

View File

@@ -71,7 +71,7 @@ type
inTypeClass*: int # > 0 if we are in a user-defined type class
inGenericContext*: int # > 0 if we are in a generic type
inUnrolledContext*: int # > 0 if we are unrolling a loop
inCompilesContext*: int # > 0 if we are in a ``compiles`` magic
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
compilesContextIdGenerator*: int
inGenericInst*: int # > 0 if we are instantiating a generic
converters*: TSymSeq # sequence of converters

View File

@@ -818,7 +818,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# This is a proc variable, apply normal overload resolution
let m = resolveIndirectCall(c, n, nOrig, t)
if m.state != csMatch:
if c.inCompilesContext > 0:
if c.compilesContextId > 0:
# speed up error generation:
globalError(n.info, errTypeMismatch, "")
return emptyNode
@@ -1636,9 +1636,9 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# watch out, hacks ahead:
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
let oldCompilesId = c.inCompilesContext
let oldCompilesId = c.compilesContextId
inc c.compilesContextIdGenerator
c.inCompilesContext = c.compilesContextIdGenerator
c.compilesContextId = c.compilesContextIdGenerator
# do not halt after first error:
msgs.gErrorMax = high(int)
@@ -1662,7 +1662,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
except ERecoverableError:
discard
# undo symbol table changes (as far as it's possible):
c.inCompilesContext = oldCompilesId
c.compilesContextId = oldCompilesId
c.generics = oldGenerics
c.inGenericContext = oldInGenericContext
c.inUnrolledContext = oldInUnrolledContext

View File

@@ -250,14 +250,14 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
if tfTriggersCompileTime in result.typ.flags:
incl(result.flags, sfCompileTime)
n.sons[genericParamsPos] = ast.emptyNode
var oldPrc = genericCacheGet(fn, entry[], c.inCompilesContext)
var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId)
if oldPrc == nil:
# we MUST not add potentially wrong instantiations to the caching mechanism.
# This means recursive instantiations behave differently when in
# a ``compiles`` context but this is the lesser evil. See
# bug #1055 (tevilcompiles).
#if c.inCompilesContext == 0:
entry.compilesId = c.inCompilesContext
#if c.compilesContextId == 0:
entry.compilesId = c.compilesContextId
fn.procInstCache.safeAdd(entry)
c.generics.add(makeInstPair(fn, entry))
if n.sons[pragmasPos].kind != nkEmpty:

View File

@@ -335,8 +335,8 @@ proc suggestExpr*(c: PContext, node: PNode) =
if cp == cpNone: return
var outputs = 0
# This keeps semExpr() from coming here recursively:
if c.inCompilesContext > 0: return
inc(c.inCompilesContext)
if c.compilesContextId > 0: return
inc(c.compilesContextId)
if gIdeCmd == ideSug:
var n = if nfIsCursor in node.flags: node else: findClosestDot(node)
@@ -365,7 +365,7 @@ proc suggestExpr*(c: PContext, node: PNode) =
addSon(a, x)
suggestCall(c, a, n, outputs)
dec(c.inCompilesContext)
dec(c.compilesContextId)
if outputs > 0 and gIdeCmd != ideUse: suggestQuit()
proc suggestStmt*(c: PContext, n: PNode) =

View File

@@ -0,0 +1,98 @@
# bug #3313
import unittest, future
type
ListNodeKind = enum
lnkNil, lnkCons
List*[T] = ref object
## List ADT
case kind: ListNodeKind
of lnkNil:
discard
of lnkCons:
value: T
next: List[T] not nil
proc Cons*[T](head: T, tail: List[T]): List[T] =
## Constructs non empty list
List[T](kind: lnkCons, value: head, next: tail)
proc Nil*[T](): List[T] =
## Constructs empty list
List[T](kind: lnkNil)
proc head*[T](xs: List[T]): T =
## Returns list's head
xs.value
# TODO
# proc headOption*[T](xs: List[T]): Option[T] = ???
proc tail*[T](xs: List[T]): List[T] =
## Returns list's tail
case xs.kind
of lnkCons: xs.next
else: xs
proc isEmpty*(xs: List): bool =
## Checks if list is empty
xs.kind == lnkNil
proc `==`*[T](xs, ys: List[T]): bool =
## Compares two lists
if (xs.isEmpty, ys.isEmpty) == (true, true): true
elif (xs.isEmpty, ys.isEmpty) == (false, false): xs.head == ys.head and xs.tail == ys.tail
else: false
proc asList*[T](xs: varargs[T]): List[T] =
## Creates list from varargs
proc initListImpl(i: int, xs: openarray[T]): List[T] =
if i > high(xs):
Nil[T]()
else:
Cons(xs[i], initListImpl(i+1, xs))
initListImpl(0, xs)
proc foldRight*[T,U](xs: List[T], z: U, f: (T, U) -> U): U =
case xs.isEmpty
of true: z
else: f(xs.head, xs.tail.foldRight(z, f))
proc dup*[T](xs: List[T]): List[T] =
## Duplicates the list
xs.foldRight(Nil[T](), (x: T, xs: List[T]) => Cons(x, xs))
type
ListFormat = enum
lfADT, lfSTD
proc asString[T](xs: List[T], f = lfSTD): string =
proc asAdt(xs: List[T]): string =
case xs.isEmpty
of true: "Nil"
else: "Cons(" & $xs.head & ", " & xs.tail.asAdt & ")"
proc asStd(xs: List[T]): string =
"List(" & xs.foldLeft("", (s: string, v: T) =>
(if s == "": $v else: s & ", " & $v)) & ")"
case f
of lfADT: xs.asAdt
else: xs.asStd
proc `$`*[T](xs: List[T]): string =
## Converts list to string
result = xs.asString
proc foldLeft*[T,U](xs: List[T], z: U, f: (U, T) -> U): U =
case xs.isEmpty
of true: z
else: foldLeft(xs.tail, f(z, xs.head), f)
suite "unittest compilation error":
test "issue 3313":
let lst = lc[$x | (x <- 'a'..'z'), string].asList
let lstCopy = lst.dup
check: lstCopy == lst