guards.nim does compile

This commit is contained in:
Andreas Rumpf 2018-05-11 13:07:16 +02:00
commit 7eb39d9d26
13 changed files with 241 additions and 230 deletions

View file

@ -267,7 +267,7 @@ errSetTooBig: "set is too large",
errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
errInheritanceOnlyWithEnums: "inheritance only works with an enum", errInheritanceOnlyWithEnums: "inheritance only works with an enum",
errIllegalRecursionInTypeX: "illegal recursion in type '$1'", errIllegalRecursionInTypeX:,
errCannotInstantiateX: "cannot instantiate: '$1'", errCannotInstantiateX: "cannot instantiate: '$1'",
errExprHasNoAddress: "expression has no address", errExprHasNoAddress: "expression has no address",
errXStackEscape: "address of '$1' may not escape its stack frame", errXStackEscape: "address of '$1' may not escape its stack frame",
@ -307,7 +307,7 @@ errDefaultArgumentInvalid: "default argument invalid",
errNamedParamHasToBeIdent: "named parameter has to be an identifier", errNamedParamHasToBeIdent: "named parameter has to be an identifier",
errNoReturnTypeForX: "no return type allowed for $1", errNoReturnTypeForX: "no return type allowed for $1",
errConvNeedsOneArg: "a type conversion needs exactly one argument", errConvNeedsOneArg: "a type conversion needs exactly one argument",
errInvalidPragmaX: "invalid pragma: $1", errInvalidPragmaX: ,
errXNotAllowedHere: "$1 not allowed here", errXNotAllowedHere: "$1 not allowed here",
errInvalidControlFlowX: "invalid control flow: $1", errInvalidControlFlowX: "invalid control flow: $1",
errXisNoType: "invalid type: '$1'", errXisNoType: "invalid type: '$1'",
@ -345,7 +345,7 @@ errNewSectionExpected: "new section expected",
errWhitespaceExpected: "whitespace expected, got '$1'", errWhitespaceExpected: "whitespace expected, got '$1'",
errXisNoValidIndexFile: "'$1' is no valid index file", errXisNoValidIndexFile: "'$1' is no valid index file",
errCannotRenderX: "cannot render reStructuredText element '$1'", errCannotRenderX: "cannot render reStructuredText element '$1'",
errVarVarTypeNotAllowed: "type 'var var' is not allowed", errVarVarTypeNotAllowed: ,
errInstantiateXExplicitly: "instantiate '$1' explicitly", errInstantiateXExplicitly: "instantiate '$1' explicitly",
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",

View file

@ -613,7 +613,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}: if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
return false return false
var hashFile = toGeneratedFile(conf, cfile.cname.withPackageName, "sha1") var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
var currentHash = footprint(conf, cfile) var currentHash = footprint(conf, cfile)
var f: File var f: File
if open(f, hashFile, fmRead): if open(f, hashFile, fmRead):

View file

@ -10,7 +10,7 @@
## This module implements the 'implies' relation for guards. ## This module implements the 'implies' relation for guards.
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents, import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
saturate saturate, modulegraphs, options, configuration
const const
someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
@ -83,18 +83,25 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true) proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
let type
opLe = createMagic("<=", mLeI) Operators* = object
opLt = createMagic("<", mLtI) opNot, opContains, opLe, opLt, opAnd, opOr, opIsNil, opEq: PSym
opAnd = createMagic("and", mAnd) opAdd, opSub, opMul, opDiv, opLen: PSym
opOr = createMagic("or", mOr)
opIsNil = createMagic("isnil", mIsNil) proc initOperators*(g: ModuleGraph): Operators =
opEq = createMagic("==", mEqI) result.opLe = createMagic(g, "<=", mLeI)
opAdd = createMagic("+", mAddI) result.opLt = createMagic(g, "<", mLtI)
opSub = createMagic("-", mSubI) result.opAnd = createMagic(g, "and", mAnd)
opMul = createMagic("*", mMulI) result.opOr = createMagic(g, "or", mOr)
opDiv = createMagic("div", mDivI) result.opIsNil = createMagic(g, "isnil", mIsNil)
opLen = createMagic("len", mLengthSeq) result.opEq = createMagic(g, "==", mEqI)
result.opAdd = createMagic(g, "+", mAddI)
result.opSub = createMagic(g, "-", mSubI)
result.opMul = createMagic(g, "*", mMulI)
result.opDiv = createMagic(g, "div", mDivI)
result.opLen = createMagic(g, "len", mLengthSeq)
result.opNot = createMagic(g, "not", mNot)
result.opContains = createMagic(g, "contains", mInSet)
proc swapArgs(fact: PNode, newOp: PSym): PNode = proc swapArgs(fact: PNode, newOp: PSym): PNode =
result = newNodeI(nkCall, fact.info, 3) result = newNodeI(nkCall, fact.info, 3)
@ -102,16 +109,16 @@ proc swapArgs(fact: PNode, newOp: PSym): PNode =
result.sons[1] = fact.sons[2] result.sons[1] = fact.sons[2]
result.sons[2] = fact.sons[1] result.sons[2] = fact.sons[1]
proc neg(n: PNode): PNode = proc neg(n: PNode; o: Operators): PNode =
if n == nil: return nil if n == nil: return nil
case n.getMagic case n.getMagic
of mNot: of mNot:
result = n.sons[1] result = n.sons[1]
of someLt: of someLt:
# not (a < b) == a >= b == b <= a # not (a < b) == a >= b == b <= a
result = swapArgs(n, opLe) result = swapArgs(n, o.opLe)
of someLe: of someLe:
result = swapArgs(n, opLt) result = swapArgs(n, o.opLt)
of mInSet: of mInSet:
if n.sons[1].kind != nkCurly: return nil if n.sons[1].kind != nkCurly: return nil
let t = n.sons[2].typ.skipTypes(abstractInst) let t = n.sons[2].typ.skipTypes(abstractInst)
@ -133,11 +140,11 @@ proc neg(n: PNode): PNode =
of mOr: of mOr:
# not (a or b) --> not a and not b # not (a or b) --> not a and not b
let let
a = n.sons[1].neg a = n.sons[1].neg(o)
b = n.sons[2].neg b = n.sons[2].neg(o)
if a != nil and b != nil: if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3) result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd) result.sons[0] = newSymNode(o.opAnd)
result.sons[1] = a result.sons[1] = a
result.sons[2] = b result.sons[2] = b
elif a != nil: elif a != nil:
@ -147,7 +154,7 @@ proc neg(n: PNode): PNode =
else: else:
# leave not (a == 4) as it is # leave not (a == 4) as it is
result = newNodeI(nkCall, n.info, 2) result = newNodeI(nkCall, n.info, 2)
result.sons[0] = newSymNode(opNot) result.sons[0] = newSymNode(o.opNot)
result.sons[1] = n result.sons[1] = n
proc buildCall(op: PSym; a: PNode): PNode = proc buildCall(op: PSym; a: PNode): PNode =
@ -181,7 +188,7 @@ proc `|div|`(a, b: PNode): PNode =
if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal div b.intVal if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal div b.intVal
else: result.floatVal = a.floatVal / b.floatVal else: result.floatVal = a.floatVal / b.floatVal
proc negate(a, b, res: PNode): PNode = proc negate(a, b, res: PNode; o: Operators): PNode =
if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt): if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt):
var b = copyNode(b) var b = copyNode(b)
b.intVal = -b.intVal b.intVal = -b.intVal
@ -189,11 +196,11 @@ proc negate(a, b, res: PNode): PNode =
b.intVal = b.intVal |+| a.intVal b.intVal = b.intVal |+| a.intVal
result = b result = b
else: else:
result = buildCall(opAdd, a, b) result = buildCall(o.opAdd, a, b)
elif b.kind in {nkFloatLit..nkFloat64Lit}: elif b.kind in {nkFloatLit..nkFloat64Lit}:
var b = copyNode(b) var b = copyNode(b)
b.floatVal = -b.floatVal b.floatVal = -b.floatVal
result = buildCall(opAdd, a, b) result = buildCall(o.opAdd, a, b)
else: else:
result = res result = res
@ -205,7 +212,7 @@ proc lowBound*(x: PNode): PNode =
result = nkIntLit.newIntNode(firstOrd(x.typ)) result = nkIntLit.newIntNode(firstOrd(x.typ))
result.info = x.info result.info = x.info
proc highBound*(x: PNode): PNode = proc highBound*(x: PNode; o: Operators): PNode =
let typ = x.typ.skipTypes(abstractInst) let typ = x.typ.skipTypes(abstractInst)
result = if typ.kind == tyArray: result = if typ.kind == tyArray:
nkIntLit.newIntNode(lastOrd(typ)) nkIntLit.newIntNode(lastOrd(typ))
@ -213,23 +220,23 @@ proc highBound*(x: PNode): PNode =
x.sym.kind == skConst: x.sym.kind == skConst:
nkIntLit.newIntNode(x.sym.ast.len-1) nkIntLit.newIntNode(x.sym.ast.len-1)
else: else:
opAdd.buildCall(opLen.buildCall(x), minusOne()) o.opAdd.buildCall(o.opLen.buildCall(x), minusOne())
result.info = x.info result.info = x.info
proc reassociation(n: PNode): PNode = proc reassociation(n: PNode; o: Operators): PNode =
result = n result = n
# (foo+5)+5 --> foo+10; same for '*' # (foo+5)+5 --> foo+10; same for '*'
case result.getMagic case result.getMagic
of someAdd: of someAdd:
if result[2].isValue and if result[2].isValue and
result[1].getMagic in someAdd and result[1][2].isValue: result[1].getMagic in someAdd and result[1][2].isValue:
result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2]) result = o.opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
if result[2].intVal == 0: if result[2].intVal == 0:
result = result[1] result = result[1]
of someMul: of someMul:
if result[2].isValue and if result[2].isValue and
result[1].getMagic in someMul and result[1][2].isValue: result[1].getMagic in someMul and result[1][2].isValue:
result = opMul.buildCall(result[1][1], result[1][2] |*| result[2]) result = o.opMul.buildCall(result[1][1], result[1][2] |*| result[2])
if result[2].intVal == 1: if result[2].intVal == 1:
result = result[1] result = result[1]
elif result[2].intVal == 0: elif result[2].intVal == 0:
@ -243,12 +250,12 @@ proc pred(n: PNode): PNode =
else: else:
result = n result = n
proc canon*(n: PNode): PNode = proc canon*(n: PNode; o: Operators): PNode =
# XXX for now only the new code in 'semparallel' uses this # XXX for now only the new code in 'semparallel' uses this
if n.safeLen >= 1: if n.safeLen >= 1:
result = shallowCopy(n) result = shallowCopy(n)
for i in 0 ..< n.len: for i in 0 ..< n.len:
result.sons[i] = canon(n.sons[i]) result.sons[i] = canon(n.sons[i], o)
elif n.kind == nkSym and n.sym.kind == skLet and elif n.kind == nkSym and n.sym.kind == skLet and
n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin + n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv): someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv):
@ -263,24 +270,24 @@ proc canon*(n: PNode): PNode =
# (4 + foo) + 2 --> (foo + 4) + 2 # (4 + foo) + 2 --> (foo + 4) + 2
of someHigh: of someHigh:
# high == len+(-1) # high == len+(-1)
result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne()) result = o.opAdd.buildCall(o.opLen.buildCall(result[1]), minusOne())
of mUnaryLt: of mUnaryLt:
result = buildCall(opAdd, result[1], minusOne()) result = buildCall(o.opAdd, result[1], minusOne())
of someSub: of someSub:
# x - 4 --> x + (-4) # x - 4 --> x + (-4)
result = negate(result[1], result[2], result) result = negate(result[1], result[2], result, o)
of someLen: of someLen:
result.sons[0] = opLen.newSymNode result.sons[0] = o.opLen.newSymNode
of someLt: of someLt:
# x < y same as x <= y-1: # x < y same as x <= y-1:
let y = n[2].canon let y = n[2].canon(o)
let p = pred(y) let p = pred(y)
let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon let minus = if p != y: p else: o.opAdd.buildCall(y, minusOne()).canon(o)
result = opLe.buildCall(n[1].canon, minus) result = o.opLe.buildCall(n[1].canon(o), minus)
else: discard else: discard
result = skipConv(result) result = skipConv(result)
result = reassociation(result) result = reassociation(result, o)
# most important rule: (x-4) <= a.len --> x <= a.len+4 # most important rule: (x-4) <= a.len --> x <= a.len+4
case result.getMagic case result.getMagic
of someLe: of someLe:
@ -291,10 +298,10 @@ proc canon*(n: PNode): PNode =
case x.getMagic case x.getMagic
of someSub: of someSub:
result = buildCall(result[0].sym, x[1], result = buildCall(result[0].sym, x[1],
reassociation(opAdd.buildCall(y, x[2]))) reassociation(o.opAdd.buildCall(y, x[2]), o))
of someAdd: of someAdd:
# Rule A: # Rule A:
let plus = negate(y, x[2], nil).reassociation let plus = negate(y, x[2], nil, o).reassociation(o)
if plus != nil: result = buildCall(result[0].sym, x[1], plus) if plus != nil: result = buildCall(result[0].sym, x[1], plus)
else: discard else: discard
elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
@ -303,9 +310,9 @@ proc canon*(n: PNode): PNode =
case y.getMagic case y.getMagic
of someSub: of someSub:
result = buildCall(result[0].sym, y[1], result = buildCall(result[0].sym, y[1],
reassociation(opAdd.buildCall(x, y[2]))) reassociation(o.opAdd.buildCall(x, y[2]), o))
of someAdd: of someAdd:
let plus = negate(x, y[2], nil).reassociation let plus = negate(x, y[2], nil, o).reassociation(o)
# ensure that Rule A will not trigger afterwards with the # ensure that Rule A will not trigger afterwards with the
# additional 'not isLetLocation' constraint: # additional 'not isLetLocation' constraint:
if plus != nil and not isLetLocation(x, true): if plus != nil and not isLetLocation(x, true):
@ -323,15 +330,15 @@ proc canon*(n: PNode): PNode =
result.sons[2] = y[1] result.sons[2] = y[1]
else: discard else: discard
proc `+@`*(a: PNode; b: BiggestInt): PNode = #proc `+@`*(a: PNode; b: BiggestInt): PNode =
canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a) # canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a)
proc usefulFact(n: PNode): PNode = proc usefulFact(n: PNode; o: Operators): PNode =
case n.getMagic case n.getMagic
of someEq: of someEq:
if skipConv(n.sons[2]).kind == nkNilLit and ( if skipConv(n.sons[2]).kind == nkNilLit and (
isLetLocation(n.sons[1], false) or isVar(n.sons[1])): isLetLocation(n.sons[1], false) or isVar(n.sons[1])):
result = opIsNil.buildCall(n.sons[1]) result = o.opIsNil.buildCall(n.sons[1])
else: else:
if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true): if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1' # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
@ -351,11 +358,11 @@ proc usefulFact(n: PNode): PNode =
result = n result = n
of mAnd: of mAnd:
let let
a = usefulFact(n.sons[1]) a = usefulFact(n.sons[1], o)
b = usefulFact(n.sons[2]) b = usefulFact(n.sons[2], o)
if a != nil and b != nil: if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3) result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd) result.sons[0] = newSymNode(o.opAnd)
result.sons[1] = a result.sons[1] = a
result.sons[2] = b result.sons[2] = b
elif a != nil: elif a != nil:
@ -363,9 +370,9 @@ proc usefulFact(n: PNode): PNode =
elif b != nil: elif b != nil:
result = b result = b
of mNot: of mNot:
let a = usefulFact(n.sons[1]) let a = usefulFact(n.sons[1], o)
if a != nil: if a != nil:
result = a.neg result = a.neg(o)
of mOr: of mOr:
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
# with that knowledge... # with that knowledge...
@ -374,14 +381,14 @@ proc usefulFact(n: PNode): PNode =
# (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2)) # (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2))
# not (x != 3 and y != 2) # not (x != 3 and y != 2)
let let
a = usefulFact(n.sons[1]).neg a = usefulFact(n.sons[1], o).neg(o)
b = usefulFact(n.sons[2]).neg b = usefulFact(n.sons[2], o).neg(o)
if a != nil and b != nil: if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3) result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd) result.sons[0] = newSymNode(o.opAnd)
result.sons[1] = a result.sons[1] = a
result.sons[2] = b result.sons[2] = b
result = result.neg result = result.neg(o)
elif n.kind == nkSym and n.sym.kind == skLet: elif n.kind == nkSym and n.sym.kind == skLet:
# consider: # consider:
# let a = 2 < x # let a = 2 < x
@ -389,32 +396,34 @@ proc usefulFact(n: PNode): PNode =
# ... # ...
# We make can easily replace 'a' by '2 < x' here: # We make can easily replace 'a' by '2 < x' here:
if n.sym.ast != nil: if n.sym.ast != nil:
result = usefulFact(n.sym.ast) result = usefulFact(n.sym.ast, o)
elif n.kind == nkStmtListExpr: elif n.kind == nkStmtListExpr:
result = usefulFact(n.lastSon) result = usefulFact(n.lastSon, o)
type type
TModel* = seq[PNode] # the "knowledge base" TModel* = object
s: seq[PNode] # the "knowledge base"
o: Operators
proc addFact*(m: var TModel, nn: PNode) = proc addFact*(m: var TModel, nn: PNode) =
let n = usefulFact(nn) let n = usefulFact(nn, m.o)
if n != nil: m.add n if n != nil: m.s.add n
proc addFactNeg*(m: var TModel, n: PNode) = proc addFactNeg*(m: var TModel, n: PNode) =
let n = n.neg let n = n.neg(m.o)
if n != nil: addFact(m, n) if n != nil: addFact(m, n)
proc canonOpr(opr: PSym): PSym = proc sameOpr(a, b: PSym): bool =
case opr.magic case a.magic
of someEq: result = opEq of someEq: result = b.magic in someEq
of someLe: result = opLe of someLe: result = b.magic in someLe
of someLt: result = opLt of someLt: result = b.magic in someLt
of someLen: result = opLen of someLen: result = b.magic in someLen
of someAdd: result = opAdd of someAdd: result = b.magic in someAdd
of someSub: result = opSub of someSub: result = b.magic in someSub
of someMul: result = opMul of someMul: result = b.magic in someMul
of someDiv: result = opDiv of someDiv: result = b.magic in someDiv
else: result = opr else: result = a == b
proc sameTree*(a, b: PNode): bool = proc sameTree*(a, b: PNode): bool =
result = false result = false
@ -425,7 +434,7 @@ proc sameTree*(a, b: PNode): bool =
of nkSym: of nkSym:
result = a.sym == b.sym result = a.sym == b.sym
if not result and a.sym.magic != mNone: if not result and a.sym.magic != mNone:
result = a.sym.magic == b.sym.magic or canonOpr(a.sym) == canonOpr(b.sym) result = a.sym.magic == b.sym.magic or sameOpr(a.sym, b.sym)
of nkIdent: result = a.ident.id == b.ident.id of nkIdent: result = a.ident.id == b.ident.id
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
@ -462,8 +471,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
# The same mechanism could be used for more complex data stored on the heap; # The same mechanism could be used for more complex data stored on the heap;
# procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we # procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
# could CSE these expressions then and help C's optimizer. # could CSE these expressions then and help C's optimizer.
for i in 0..high(m): for i in 0..high(m.s):
if m[i] != nil and m[i].hasSubTree(n): m[i] = nil if m.s[i] != nil and m.s[i].hasSubTree(n): m.s[i] = nil
proc valuesUnequal(a, b: PNode): bool = proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue: if a.isValue and b.isValue:
@ -486,7 +495,7 @@ proc impliesEq(fact, eq: PNode): TImplication =
if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]): if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]):
if inSet(fact.sons[1], eq.sons[val]): result = impYes if inSet(fact.sons[1], eq.sons[val]): result = impYes
else: result = impNo else: result = impNo
of mNot, mOr, mAnd: internalError(eq.info, "impliesEq") of mNot, mOr, mAnd: assert(false, "impliesEq")
else: discard else: discard
proc leImpliesIn(x, c, aSet: PNode): TImplication = proc leImpliesIn(x, c, aSet: PNode): TImplication =
@ -549,7 +558,7 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
elif sameTree(fact.sons[2], loc): elif sameTree(fact.sons[2], loc):
# 4 < x --> 3 <= x # 4 < x --> 3 <= x
result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet) result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
of mNot, mOr, mAnd: internalError(loc.info, "impliesIn") of mNot, mOr, mAnd: assert(false, "impliesIn")
else: discard else: discard
proc valueIsNil(n: PNode): TImplication = proc valueIsNil(n: PNode): TImplication =
@ -567,11 +576,11 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
result = valueIsNil(fact.sons[2].skipConv) result = valueIsNil(fact.sons[2].skipConv)
elif sameTree(fact.sons[2], eq.sons[1]): elif sameTree(fact.sons[2], eq.sons[1]):
result = valueIsNil(fact.sons[1].skipConv) result = valueIsNil(fact.sons[1].skipConv)
of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil") of mNot, mOr, mAnd: assert(false, "impliesIsNil")
else: discard else: discard
proc impliesGe(fact, x, c: PNode): TImplication = proc impliesGe(fact, x, c: PNode): TImplication =
internalAssert isLocation(x) assert isLocation(x)
case fact.sons[0].sym.magic case fact.sons[0].sym.magic
of someEq: of someEq:
if sameTree(fact.sons[1], x): if sameTree(fact.sons[1], x):
@ -603,7 +612,7 @@ proc impliesGe(fact, x, c: PNode): TImplication =
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3 # fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
if isValue(fact.sons[1]) and isValue(c): if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1]): result = impYes if leValue(c, fact.sons[1]): result = impYes
of mNot, mOr, mAnd: internalError(x.info, "impliesGe") of mNot, mOr, mAnd: assert(false, "impliesGe")
else: discard else: discard
proc impliesLe(fact, x, c: PNode): TImplication = proc impliesLe(fact, x, c: PNode): TImplication =
@ -643,7 +652,7 @@ proc impliesLe(fact, x, c: PNode): TImplication =
if isValue(fact.sons[1]) and isValue(c): if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1].pred): result = impNo if leValue(c, fact.sons[1].pred): result = impNo
of mNot, mOr, mAnd: internalError(x.info, "impliesLe") of mNot, mOr, mAnd: assert(false, "impliesLe")
else: discard else: discard
proc impliesLt(fact, x, c: PNode): TImplication = proc impliesLt(fact, x, c: PNode): TImplication =
@ -707,14 +716,14 @@ proc factImplies(fact, prop: PNode): TImplication =
proc doesImply*(facts: TModel, prop: PNode): TImplication = proc doesImply*(facts: TModel, prop: PNode): TImplication =
assert prop.kind in nkCallKinds assert prop.kind in nkCallKinds
for f in facts: for f in facts.s:
# facts can be invalidated, in which case they are 'nil': # facts can be invalidated, in which case they are 'nil':
if not f.isNil: if not f.isNil:
result = f.factImplies(prop) result = f.factImplies(prop)
if result != impUnknown: return if result != impUnknown: return
proc impliesNotNil*(facts: TModel, arg: PNode): TImplication = proc impliesNotNil*(m: TModel, arg: PNode): TImplication =
result = doesImply(facts, opIsNil.buildCall(arg).neg) result = doesImply(m, m.o.opIsNil.buildCall(arg).neg(m.o))
proc simpleSlice*(a, b: PNode): BiggestInt = proc simpleSlice*(a, b: PNode): BiggestInt =
# returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched # returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched
@ -817,20 +826,20 @@ proc ple(m: TModel; a, b: PNode): TImplication =
if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and
a[1][2].isValue: a[1][2].isValue:
# simplify (x div 4) * 2 <= y to x div (c div d) <= y # simplify (x div 4) * 2 <= y to x div (c div d) <= y
if ple(m, buildCall(opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes: if ple(m, buildCall(m.o.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes:
return impYes return impYes
# x*3 + x == x*4. It follows that: # x*3 + x == x*4. It follows that:
# x*3 + y <= x*4 if y <= x and 3 <= 4 # x*3 + y <= x*4 if y <= x and 3 <= 4
if a =~ x*dc + y and b =~ x2*ec: if a =~ x*dc + y and b =~ x2*ec:
if sameTree(x, x2): if sameTree(x, x2):
let ec1 = opAdd.buildCall(ec, minusOne()) let ec1 = m.o.opAdd.buildCall(ec, minusOne())
if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x: if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x:
return impYes return impYes
elif a =~ x*dc and b =~ x2*ec + y: elif a =~ x*dc and b =~ x2*ec + y:
#echo "BUG cam ehrer e ", a, " <=? ", b #echo "BUG cam ehrer e ", a, " <=? ", b
if sameTree(x, x2): if sameTree(x, x2):
let ec1 = opAdd.buildCall(ec, minusOne()) let ec1 = m.o.opAdd.buildCall(ec, minusOne())
if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero(): if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero():
return impYes return impYes
@ -863,9 +872,9 @@ proc ple(m: TModel; a, b: PNode): TImplication =
# use the knowledge base: # use the knowledge base:
return pleViaModel(m, a, b) return pleViaModel(m, a, b)
#return doesImply(m, opLe.buildCall(a, b)) #return doesImply(m, o.opLe.buildCall(a, b))
type TReplacements = seq[tuple[a,b: PNode]] type TReplacements = seq[tuple[a, b: PNode]]
proc replaceSubTree(n, x, by: PNode): PNode = proc replaceSubTree(n, x, by: PNode): PNode =
if sameTree(n, x): if sameTree(n, x):
@ -883,11 +892,11 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode =
proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
# now check for inferrable facts: a <= b and b <= c implies a <= c # now check for inferrable facts: a <= b and b <= c implies a <= c
for i in 0..m.high: for i in 0..m.s.high:
let fact = m[i] let fact = m.s[i]
if fact != nil and fact.getMagic in someLe: if fact != nil and fact.getMagic in someLe:
# mark as used: # mark as used:
m[i] = nil m.s[i] = nil
# i <= len-100 # i <= len-100
# i <=? len-1 # i <=? len-1
# --> true if (len-100) <= (len-1) # --> true if (len-100) <= (len-1)
@ -919,7 +928,7 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication = proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
# compute replacements: # compute replacements:
var replacements: TReplacements = @[] var replacements: TReplacements = @[]
for fact in model: for fact in model.s:
if fact != nil and fact.getMagic in someEq: if fact != nil and fact.getMagic in someEq:
let a = fact[1] let a = fact[1]
let b = fact[2] let b = fact[2]
@ -929,12 +938,13 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
var a = aa var a = aa
var b = bb var b = bb
if replacements.len > 0: if replacements.len > 0:
m = @[] m.s = @[]
m.o = model.o
# make the other facts consistent: # make the other facts consistent:
for fact in model: for fact in model.s:
if fact != nil and fact.getMagic notin someEq: if fact != nil and fact.getMagic notin someEq:
# XXX 'canon' should not be necessary here, but it is # XXX 'canon' should not be necessary here, but it is
m.add applyReplacements(fact, replacements).canon m.s.add applyReplacements(fact, replacements).canon(m.o)
a = applyReplacements(aa, replacements) a = applyReplacements(aa, replacements)
b = applyReplacements(bb, replacements) b = applyReplacements(bb, replacements)
else: else:
@ -943,31 +953,31 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
result = pleViaModelRec(m, a, b) result = pleViaModelRec(m, a, b)
proc proveLe*(m: TModel; a, b: PNode): TImplication = proc proveLe*(m: TModel; a, b: PNode): TImplication =
let x = canon(opLe.buildCall(a, b)) let x = canon(m.o.opLe.buildCall(a, b), m.o)
#echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2]) #echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2])
result = ple(m, x[1], x[2]) result = ple(m, x[1], x[2])
if result == impUnknown: if result == impUnknown:
# try an alternative: a <= b iff not (b < a) iff not (b+1 <= a): # try an alternative: a <= b iff not (b < a) iff not (b+1 <= a):
let y = canon(opLe.buildCall(opAdd.buildCall(b, one()), a)) let y = canon(m.o.opLe.buildCall(m.o.opAdd.buildCall(b, one()), a), m.o)
result = ~ple(m, y[1], y[2]) result = ~ple(m, y[1], y[2])
proc addFactLe*(m: var TModel; a, b: PNode) = proc addFactLe*(m: var TModel; a, b: PNode) =
m.add canon(opLe.buildCall(a, b)) m.s.add canon(m.o.opLe.buildCall(a, b), m.o)
proc settype(n: PNode): PType = proc settype(n: PNode): PType =
result = newType(tySet, n.typ.owner) result = newType(tySet, n.typ.owner)
addSonSkipIntLit(result, n.typ) addSonSkipIntLit(result, n.typ)
proc buildOf(it, loc: PNode): PNode = proc buildOf(it, loc: PNode; o: Operators): PNode =
var s = newNodeI(nkCurly, it.info, it.len-1) var s = newNodeI(nkCurly, it.info, it.len-1)
s.typ = settype(loc) s.typ = settype(loc)
for i in 0..it.len-2: s.sons[i] = it.sons[i] for i in 0..it.len-2: s.sons[i] = it.sons[i]
result = newNodeI(nkCall, it.info, 3) result = newNodeI(nkCall, it.info, 3)
result.sons[0] = newSymNode(opContains) result.sons[0] = newSymNode(o.opContains)
result.sons[1] = s result.sons[1] = s
result.sons[2] = loc result.sons[2] = loc
proc buildElse(n: PNode): PNode = proc buildElse(n: PNode; o: Operators): PNode =
var s = newNodeIT(nkCurly, n.info, settype(n.sons[0])) var s = newNodeIT(nkCurly, n.info, settype(n.sons[0]))
for i in 1..n.len-2: for i in 1..n.len-2:
let branch = n.sons[i] let branch = n.sons[i]
@ -975,23 +985,23 @@ proc buildElse(n: PNode): PNode =
for j in 0..branch.len-2: for j in 0..branch.len-2:
s.add(branch.sons[j]) s.add(branch.sons[j])
result = newNodeI(nkCall, n.info, 3) result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opContains) result.sons[0] = newSymNode(o.opContains)
result.sons[1] = s result.sons[1] = s
result.sons[2] = n.sons[0] result.sons[2] = n.sons[0]
proc addDiscriminantFact*(m: var TModel, n: PNode) = proc addDiscriminantFact*(m: var TModel, n: PNode) =
var fact = newNodeI(nkCall, n.info, 3) var fact = newNodeI(nkCall, n.info, 3)
fact.sons[0] = newSymNode(opEq) fact.sons[0] = newSymNode(m.o.opEq)
fact.sons[1] = n.sons[0] fact.sons[1] = n.sons[0]
fact.sons[2] = n.sons[1] fact.sons[2] = n.sons[1]
m.add fact m.s.add fact
proc addAsgnFact*(m: var TModel, key, value: PNode) = proc addAsgnFact*(m: var TModel, key, value: PNode) =
var fact = newNodeI(nkCall, key.info, 3) var fact = newNodeI(nkCall, key.info, 3)
fact.sons[0] = newSymNode(opEq) fact.sons[0] = newSymNode(m.o.opEq)
fact.sons[1] = key fact.sons[1] = key
fact.sons[2] = value fact.sons[2] = value
m.add fact m.s.add fact
proc sameSubexprs*(m: TModel; a, b: PNode): bool = proc sameSubexprs*(m: TModel; a, b: PNode): bool =
# This should be used to check whether two *path expressions* refer to the # This should be used to check whether two *path expressions* refer to the
@ -1004,7 +1014,7 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool =
# However, nil checking requires exactly the same mechanism! But for now # However, nil checking requires exactly the same mechanism! But for now
# we simply use sameTree and live with the unsoundness of the analysis. # we simply use sameTree and live with the unsoundness of the analysis.
var check = newNodeI(nkCall, a.info, 3) var check = newNodeI(nkCall, a.info, 3)
check.sons[0] = newSymNode(opEq) check.sons[0] = newSymNode(m.o.opEq)
check.sons[1] = a check.sons[1] = a
check.sons[2] = b check.sons[2] = b
result = m.doesImply(check) == impYes result = m.doesImply(check) == impYes
@ -1012,11 +1022,11 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool =
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) = proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
let branch = n.sons[i] let branch = n.sons[i]
if branch.kind == nkOfBranch: if branch.kind == nkOfBranch:
m.add buildOf(branch, n.sons[0]) m.s.add buildOf(branch, n.sons[0], m.o)
else: else:
m.add n.buildElse.neg m.s.add n.buildElse(m.o).neg(m.o)
proc buildProperFieldCheck(access, check: PNode): PNode = proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
if check.sons[1].kind == nkCurly: if check.sons[1].kind == nkCurly:
result = copyTree(check) result = copyTree(check)
if access.kind == nkDotExpr: if access.kind == nkDotExpr:
@ -1028,10 +1038,10 @@ proc buildProperFieldCheck(access, check: PNode): PNode =
else: else:
# it is some 'not' # it is some 'not'
assert check.getMagic == mNot assert check.getMagic == mNot
result = buildProperFieldCheck(access, check.sons[1]).neg result = buildProperFieldCheck(access, check.sons[1], o).neg(o)
proc checkFieldAccess*(m: TModel, n: PNode) = proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) =
for i in 1..n.len-1: for i in 1..n.len-1:
let check = buildProperFieldCheck(n.sons[0], n.sons[i]) let check = buildProperFieldCheck(n.sons[0], n.sons[i], m.o)
if check != nil and m.doesImply(check) != impYes: if check != nil and m.doesImply(check) != impYes:
message(n.info, warnProveField, renderTree(n.sons[0])); break message(conf, n.info, warnProveField, renderTree(n.sons[0])); break

View file

@ -594,11 +594,11 @@ proc internalError*(conf: ConfigRef; errMsg: string) =
writeContext(conf, unknownLineInfo()) writeContext(conf, unknownLineInfo())
rawMessage(conf, errInternal, errMsg) rawMessage(conf, errInternal, errMsg)
template assertNotNil*(conf, e): untyped = template assertNotNil*(conf: ConfigRef; e): untyped =
if e == nil: internalError(conf, $instantiationInfo()) if e == nil: internalError(conf, $instantiationInfo())
e e
template internalAssert*(conf, e: bool) = template internalAssert*(conf: ConfigRef, e: bool) =
if not e: internalError(conf, $instantiationInfo()) if not e: internalError(conf, $instantiationInfo())
proc addSourceLine*(fileIdx: FileIndex, line: string) = proc addSourceLine*(fileIdx: FileIndex, line: string) =

View file

@ -13,7 +13,8 @@
import import
strutils, os, intsets, strtabs strutils, os, intsets, strtabs
import "../compiler" / [options, ast, astalgo, msgs, semdata, ropes, idents] import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents,
configuration]
import prettybase import prettybase
type type
@ -24,8 +25,8 @@ var
gStyleCheck*: StyleCheck gStyleCheck*: StyleCheck
gCheckExtern*, gOnlyMainfile*: bool gCheckExtern*, gOnlyMainfile*: bool
proc overwriteFiles*() = proc overwriteFiles*(conf: ConfigRef) =
let doStrip = options.getConfigVar("pretty.strip").normalize == "on" let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on"
for i in 0 .. high(gSourceFiles): for i in 0 .. high(gSourceFiles):
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
(not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex): (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex):
@ -41,7 +42,7 @@ proc overwriteFiles*() =
f.write(gSourceFiles[i].newline) f.write(gSourceFiles[i].newline)
f.close f.close
except IOError: except IOError:
rawMessage(errCannotOpenFile, newFile) rawMessage(conf, errGenerated, "cannot open file: " & newFile)
proc `=~`(s: string, a: openArray[string]): bool = proc `=~`(s: string, a: openArray[string]): bool =
for x in a: for x in a:
@ -110,30 +111,30 @@ proc replaceInFile(info: TLineInfo; newName: string) =
system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x) system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x)
gSourceFiles[info.fileIndex.int].dirty = true gSourceFiles[info.fileIndex.int].dirty = true
proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) = proc checkStyle(conf: ConfigRef; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
let beau = beautifyName(s, k) let beau = beautifyName(s, k)
if s != beau: if s != beau:
if gStyleCheck == StyleCheck.Auto: if gStyleCheck == StyleCheck.Auto:
sym.name = getIdent(beau) sym.name = getIdent(beau)
replaceInFile(info, beau) replaceInFile(info, beau)
else: else:
message(info, hintName, beau) message(conf, info, hintName, beau)
proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) = proc styleCheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
# operators stay as they are: # operators stay as they are:
if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return
if k in {skType, skGenericParam} and sfAnon in s.flags: return if k in {skType, skGenericParam} and sfAnon in s.flags: return
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern: if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
checkStyle(info, s.name.s, k, s) checkStyle(conf, info, s.name.s, k, s)
template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) = template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) =
when defined(nimfix): when defined(nimfix):
if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k) if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, info, s, k)
template styleCheckDef*(info: TLineInfo; s: PSym) = template styleCheckDef*(info: TLineInfo; s: PSym) =
styleCheckDef(info, s, s.kind) styleCheckDef(conf, info, s, s.kind)
template styleCheckDef*(s: PSym) = template styleCheckDef*(s: PSym) =
styleCheckDef(s.info, s, s.kind) styleCheckDef(conf, s.info, s, s.kind)
proc styleCheckUseImpl(info: TLineInfo; s: PSym) = proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
if info.fileIndex.int < 0: return if info.fileIndex.int < 0: return
@ -151,4 +152,4 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
template styleCheckUse*(info: TLineInfo; s: PSym) = template styleCheckUse*(info: TLineInfo; s: PSym) =
when defined(nimfix): when defined(nimfix):
if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s) if gStyleCheck != StyleCheck.None: styleCheckUseImpl(conf, info, s)

View file

@ -131,15 +131,23 @@ type
symbols*: StringTableRef ## We need to use a StringTableRef here as defined symbols*: StringTableRef ## We need to use a StringTableRef here as defined
## symbols are always guaranteed to be style ## symbols are always guaranteed to be style
## insensitive. Otherwise hell would break lose. ## insensitive. Otherwise hell would break lose.
packageCache*: StringTableRef
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
template newPackageCache*(): untyped =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
proc newConfigRef*(): ConfigRef = proc newConfigRef*(): ConfigRef =
result = ConfigRef(cppDefines: initSet[string](), result = ConfigRef(cppDefines: initSet[string](),
headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic, headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
hintQuitCalled, hintExecuting}, hintQuitCalled, hintExecuting},
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1],
symbols: newStringTable(modeStyleInsensitive)) symbols: newStringTable(modeStyleInsensitive),
packageCache: newPackageCache())
proc newPartialConfigRef*(): ConfigRef = proc newPartialConfigRef*(): ConfigRef =
## create a new ConfigRef that is only good enough for error reporting. ## create a new ConfigRef that is only good enough for error reporting.
@ -422,7 +430,7 @@ proc rawFindFile2(conf: ConfigRef; f: string): string =
template patchModule(conf: ConfigRef) {.dirty.} = template patchModule(conf: ConfigRef) {.dirty.} =
if result.len > 0 and gModuleOverrides.len > 0: if result.len > 0 and gModuleOverrides.len > 0:
let key = getPackageName(result) & "_" & splitFile(result).name let key = getPackageName(conf, result) & "_" & splitFile(result).name
if gModuleOverrides.hasKey(key): if gModuleOverrides.hasKey(key):
let ov = gModuleOverrides[key] let ov = gModuleOverrides[key]
if ov.len > 0: result = ov if ov.len > 0: result = ov

View file

@ -15,23 +15,16 @@ iterator myParentDirs(p: string): string =
if current.len == 0: break if current.len == 0: break
yield current yield current
template newPackageCache(): untyped = proc resetPackageCache*(conf: ConfigRef) =
newStringTable(when FileSystemCaseSensitive: conf.packageCache = newPackageCache()
modeCaseInsensitive
else:
modeCaseSensitive)
var packageCache = newPackageCache() proc getPackageName*(conf: ConfigRef; path: string): string =
proc resetPackageCache*() = packageCache = newPackageCache()
proc getPackageName*(path: string): string =
var parents = 0 var parents = 0
block packageSearch: block packageSearch:
for d in myParentDirs(path): for d in myParentDirs(path):
if packageCache.hasKey(d): if conf.packageCache.hasKey(d):
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d] return conf.packageCache[d]
inc parents inc parents
for file in walkFiles(d / "*.nimble"): for file in walkFiles(d / "*.nimble"):
result = file.splitFile.name result = file.splitFile.name
@ -43,12 +36,12 @@ proc getPackageName*(path: string): string =
if result.isNil: result = "" if result.isNil: result = ""
for d in myParentDirs(path): for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents #echo "set cache ", d, " |", result, "|", parents
packageCache[d] = result conf.packageCache[d] = result
dec parents dec parents
if parents <= 0: break if parents <= 0: break
proc withPackageName*(path: string): string = proc withPackageName*(conf: ConfigRef; path: string): string =
let x = path.getPackageName let x = getPackageName(conf, path)
if x.len == 0: if x.len == 0:
result = path result = path
else: else:

View file

@ -10,7 +10,8 @@
## This module implements the pattern matching features for term rewriting ## This module implements the pattern matching features for term rewriting
## macro support. ## macro support.
import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees,
options
# we precompile the pattern here for efficiency into some internal # we precompile the pattern here for efficiency into some internal
# stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that # stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that
@ -41,8 +42,8 @@ type
const const
MaxStackSize* = 64 ## max required stack size by the VM MaxStackSize* = 64 ## max required stack size by the VM
proc patternError(n: PNode) = proc patternError(n: PNode; conf: ConfigRef) =
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) localError(conf, n.info, "illformed AST: " & renderTree(n, {renderNoComments}))
proc add(code: var TPatternCode, op: TOpcode) {.inline.} = proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
add(code, chr(ord(op))) add(code, chr(ord(op)))
@ -53,34 +54,34 @@ proc whichAlias*(p: PSym): TAliasRequest =
else: else:
result = aqNone result = aqNone
proc compileConstraints(p: PNode, result: var TPatternCode) = proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) =
case p.kind case p.kind
of nkCallKinds: of nkCallKinds:
if p.sons[0].kind != nkIdent: if p.sons[0].kind != nkIdent:
patternError(p.sons[0]) patternError(p.sons[0], conf)
return return
let op = p.sons[0].ident let op = p.sons[0].ident
if p.len == 3: if p.len == 3:
if op.s == "|" or op.id == ord(wOr): if op.s == "|" or op.id == ord(wOr):
compileConstraints(p.sons[1], result) compileConstraints(p.sons[1], result, conf)
compileConstraints(p.sons[2], result) compileConstraints(p.sons[2], result, conf)
result.add(ppOr) result.add(ppOr)
elif op.s == "&" or op.id == ord(wAnd): elif op.s == "&" or op.id == ord(wAnd):
compileConstraints(p.sons[1], result) compileConstraints(p.sons[1], result, conf)
compileConstraints(p.sons[2], result) compileConstraints(p.sons[2], result, conf)
result.add(ppAnd) result.add(ppAnd)
else: else:
patternError(p) patternError(p, conf)
elif p.len == 2 and (op.s == "~" or op.id == ord(wNot)): elif p.len == 2 and (op.s == "~" or op.id == ord(wNot)):
compileConstraints(p.sons[1], result) compileConstraints(p.sons[1], result, conf)
result.add(ppNot) result.add(ppNot)
else: else:
patternError(p) patternError(p, conf)
of nkAccQuoted, nkPar: of nkAccQuoted, nkPar:
if p.len == 1: if p.len == 1:
compileConstraints(p.sons[0], result) compileConstraints(p.sons[0], result, conf)
else: else:
patternError(p) patternError(p, conf)
of nkIdent: of nkIdent:
let spec = p.ident.s.normalize let spec = p.ident.s.normalize
case spec case spec
@ -97,24 +98,24 @@ proc compileConstraints(p: PNode, result: var TPatternCode) =
of "nosideeffect": result.add(ppNoSideEffect) of "nosideeffect": result.add(ppNoSideEffect)
else: else:
# check all symkinds: # check all symkinds:
internalAssert int(high(TSymKind)) < 255 internalAssert conf, int(high(TSymKind)) < 255
for i in low(TSymKind)..high(TSymKind): for i in low(TSymKind)..high(TSymKind):
if cmpIgnoreStyle(($i).substr(2), spec) == 0: if cmpIgnoreStyle(($i).substr(2), spec) == 0:
result.add(ppSymKind) result.add(ppSymKind)
result.add(chr(i.ord)) result.add(chr(i.ord))
return return
# check all nodekinds: # check all nodekinds:
internalAssert int(high(TNodeKind)) < 255 internalAssert conf, int(high(TNodeKind)) < 255
for i in low(TNodeKind)..high(TNodeKind): for i in low(TNodeKind)..high(TNodeKind):
if cmpIgnoreStyle($i, spec) == 0: if cmpIgnoreStyle($i, spec) == 0:
result.add(ppNodeKind) result.add(ppNodeKind)
result.add(chr(i.ord)) result.add(chr(i.ord))
return return
patternError(p) patternError(p, conf)
else: else:
patternError(p) patternError(p, conf)
proc semNodeKindConstraints*(p: PNode): PNode = proc semNodeKindConstraints*(p: PNode; conf: ConfigRef): PNode =
## does semantic checking for a node kind pattern and compiles it into an ## does semantic checking for a node kind pattern and compiles it into an
## efficient internal format. ## efficient internal format.
assert p.kind == nkCurlyExpr assert p.kind == nkCurlyExpr
@ -123,11 +124,11 @@ proc semNodeKindConstraints*(p: PNode): PNode =
result.strVal.add(chr(aqNone.ord)) result.strVal.add(chr(aqNone.ord))
if p.len >= 2: if p.len >= 2:
for i in 1..<p.len: for i in 1..<p.len:
compileConstraints(p.sons[i], result.strVal) compileConstraints(p.sons[i], result.strVal, conf)
if result.strVal.len > MaxStackSize-1: if result.strVal.len > MaxStackSize-1:
internalError(p.info, "parameter pattern too complex") internalError(conf, p.info, "parameter pattern too complex")
else: else:
patternError(p) patternError(p, conf)
result.strVal.add(ppEof) result.strVal.add(ppEof)
type type

View file

@ -886,7 +886,7 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonFo
var hash = getHash(fileIdx) var hash = getHash(fileIdx)
gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles
result = rrNone result = rrNone
var rodfile = toGeneratedFile(conf, filename.withPackageName, RodExt) var rodfile = toGeneratedFile(conf, conf.withPackageName(filename), RodExt)
var r = newRodReader(rodfile, hash, fileIdx.int32, cache, conf) var r = newRodReader(rodfile, hash, fileIdx.int32, cache, conf)
if r == nil: if r == nil:
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)

View file

@ -480,7 +480,7 @@ proc writeRod(w: PRodWriter) =
processStacks(w, true) processStacks(w, true)
var f: File var f: File
if not open(f, completeGeneratedFilePath(w.config, changeFileExt( if not open(f, completeGeneratedFilePath(w.config, changeFileExt(
w.filename.withPackageName, RodExt)), withPackageName(w.config, w.filename), RodExt)),
fmWrite): fmWrite):
#echo "couldn't write rod file for: ", w.filename #echo "couldn't write rod file for: ", w.filename
return return

View file

@ -9,7 +9,7 @@
import import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, writetracking wordrecg, strutils, options, guards, writetracking, configuration
when defined(useDfa): when defined(useDfa):
import dfa import dfa
@ -52,6 +52,7 @@ type
locked: seq[PNode] # locked locations locked: seq[PNode] # locked locations
gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
maxLockLevel, currLockLevel: TLockLevel maxLockLevel, currLockLevel: TLockLevel
config: ConfigRef
PEffects = var TEffects PEffects = var TEffects
proc `<`(a, b: TLockLevel): bool {.borrow.} proc `<`(a, b: TLockLevel): bool {.borrow.}
@ -72,24 +73,23 @@ proc getLockLevel(t: PType): TLockLevel =
proc lockLocations(a: PEffects; pragma: PNode) = proc lockLocations(a: PEffects; pragma: PNode) =
if pragma.kind != nkExprColonExpr: if pragma.kind != nkExprColonExpr:
localError(pragma.info, errGenerated, "locks pragma without argument") localError(a.config, pragma.info, "locks pragma without argument")
return return
var firstLL = TLockLevel(-1'i16) var firstLL = TLockLevel(-1'i16)
for x in pragma[1]: for x in pragma[1]:
let thisLL = getLockLevel(x.typ) let thisLL = getLockLevel(x.typ)
if thisLL != 0.TLockLevel: if thisLL != 0.TLockLevel:
if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel: if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
localError(x.info, "invalid lock level: " & $thisLL) localError(a.config, x.info, "invalid lock level: " & $thisLL)
elif firstLL < 0.TLockLevel: firstLL = thisLL elif firstLL < 0.TLockLevel: firstLL = thisLL
elif firstLL != thisLL: elif firstLL != thisLL:
localError(x.info, errGenerated, localError(a.config, x.info,
"multi-lock requires the same static lock level for every operand") "multi-lock requires the same static lock level for every operand")
a.maxLockLevel = max(a.maxLockLevel, firstLL) a.maxLockLevel = max(a.maxLockLevel, firstLL)
a.locked.add x a.locked.add x
if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel: if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL: if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
localError(pragma.info, errGenerated, localError(a.config, pragma.info, "invalid nested locking")
"invalid nested locking")
a.currLockLevel = firstLL a.currLockLevel = firstLL
proc guardGlobal(a: PEffects; n: PNode; guard: PSym) = proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
@ -102,7 +102,7 @@ proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
# message(n.info, warnUnguardedAccess, renderTree(n)) # message(n.info, warnUnguardedAccess, renderTree(n))
#else: #else:
if not a.isTopLevel: if not a.isTopLevel:
localError(n.info, errGenerated, "unguarded access: " & renderTree(n)) localError(a.config, n.info, "unguarded access: " & renderTree(n))
# 'guard*' are checks which are concerned with 'guard' annotations # 'guard*' are checks which are concerned with 'guard' annotations
# (var x{.guard: y.}: int) # (var x{.guard: y.}: int)
@ -125,7 +125,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
if ty == nil: break if ty == nil: break
ty = ty.skipTypes(skipPtrs) ty = ty.skipTypes(skipPtrs)
if field == nil: if field == nil:
localError(n.info, errGenerated, "invalid guard field: " & g.name.s) localError(a.config, n.info, "invalid guard field: " & g.name.s)
return return
g = field g = field
#ri.sym.guard = field #ri.sym.guard = field
@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
for L in a.locked: for L in a.locked:
#if a.guards.sameSubexprs(dot, L): return #if a.guards.sameSubexprs(dot, L): return
if guards.sameTree(dot, L): return if guards.sameTree(dot, L): return
localError(n.info, errGenerated, "unguarded access: " & renderTree(n)) localError(a.config, n.info, "unguarded access: " & renderTree(n))
else: else:
guardGlobal(a, n, g) guardGlobal(a, n, g)
@ -167,9 +167,9 @@ proc initVarViaNew(a: PEffects, n: PNode) =
elif isLocalVar(a, s): elif isLocalVar(a, s):
makeVolatile(a, s) makeVolatile(a, s)
proc warnAboutGcUnsafe(n: PNode) = proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
#assert false #assert false
message(n.info, warnGcUnsafe, renderTree(n)) message(conf, n.info, warnGcUnsafe, renderTree(n))
proc markGcUnsafe(a: PEffects; reason: PSym) = proc markGcUnsafe(a: PEffects; reason: PSym) =
if not a.inEnforcedGcSafe: if not a.inEnforcedGcSafe:
@ -194,42 +194,42 @@ else:
a.hasSideEffect = true a.hasSideEffect = true
markGcUnsafe(a, reason) markGcUnsafe(a, reason)
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) = proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
let u = s.gcUnsafetyReason let u = s.gcUnsafetyReason
if u != nil and not cycleCheck.containsOrIncl(u.id): if u != nil and not cycleCheck.containsOrIncl(u.id):
let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
case u.kind case u.kind
of skLet, skVar: of skLet, skVar:
message(s.info, msgKind, message(conf, s.info, msgKind,
("'$#' is not GC-safe as it accesses '$#'" & ("'$#' is not GC-safe as it accesses '$#'" &
" which is a global using GC'ed memory") % [s.name.s, u.name.s]) " which is a global using GC'ed memory") % [s.name.s, u.name.s])
of routineKinds: of routineKinds:
# recursive call *always* produces only a warning so the full error # recursive call *always* produces only a warning so the full error
# message is printed: # message is printed:
listGcUnsafety(u, true, cycleCheck) listGcUnsafety(u, true, cycleCheck, conf)
message(s.info, msgKind, message(conf, s.info, msgKind,
"'$#' is not GC-safe as it calls '$#'" % "'$#' is not GC-safe as it calls '$#'" %
[s.name.s, u.name.s]) [s.name.s, u.name.s])
of skParam, skForVar: of skParam, skForVar:
message(s.info, msgKind, message(conf, s.info, msgKind,
"'$#' is not GC-safe as it performs an indirect call via '$#'" % "'$#' is not GC-safe as it performs an indirect call via '$#'" %
[s.name.s, u.name.s]) [s.name.s, u.name.s])
else: else:
message(u.info, msgKind, message(conf, u.info, msgKind,
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s) "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
proc listGcUnsafety(s: PSym; onlyWarning: bool) = proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
var cycleCheck = initIntSet() var cycleCheck = initIntSet()
listGcUnsafety(s, onlyWarning, cycleCheck) listGcUnsafety(s, onlyWarning, cycleCheck, conf)
proc useVar(a: PEffects, n: PNode) = proc useVar(a: PEffects, n: PNode) =
let s = n.sym let s = n.sym
if isLocalVar(a, s): if isLocalVar(a, s):
if s.id notin a.init: if s.id notin a.init:
if {tfNeedsInit, tfNotNil} * s.typ.flags != {}: if {tfNeedsInit, tfNotNil} * s.typ.flags != {}:
message(n.info, warnProveInit, s.name.s) message(a.config, n.info, warnProveInit, s.name.s)
else: else:
message(n.info, warnUninit, s.name.s) message(a.config, n.info, warnUninit, s.name.s)
# prevent superfluous warnings about the same variable: # prevent superfluous warnings about the same variable:
a.init.add s.id a.init.add s.id
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
@ -257,9 +257,8 @@ proc addToIntersection(inter: var TIntersection, s: int) =
proc throws(tracked, n: PNode) = proc throws(tracked, n: PNode) =
if n.typ == nil or n.typ.kind != tyError: tracked.add n if n.typ == nil or n.typ.kind != tyError: tracked.add n
proc getEbase(): PType = proc getEbase(g: ModuleGraph): PType =
result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception" result = g.sysTypeFromName"Exception"
else: sysTypeFromName"E_Base"
proc excType(n: PNode): PType = proc excType(n: PNode): PType =
# reraise is like raising E_Base: # reraise is like raising E_Base:

View file

@ -14,21 +14,21 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer, options
const const
tfInstClearedFlags = {tfHasMeta, tfUnresolved} tfInstClearedFlags = {tfHasMeta, tfUnresolved}
proc checkPartialConstructedType(info: TLineInfo, t: PType) = proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) =
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
localError(info, errInvalidPragmaX, "acyclic") localError(conf, info, "invalid pragma: acyclic")
elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
localError(info, errVarVarTypeNotAllowed) localError(conf, info, "type 'var var' is not allowed")
proc checkConstructedType*(info: TLineInfo, typ: PType) = proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
var t = typ.skipTypes({tyDistinct}) var t = typ.skipTypes({tyDistinct})
if t.kind in tyTypeClasses: discard if t.kind in tyTypeClasses: discard
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
localError(info, errInvalidPragmaX, "acyclic") localError(conf, info, "invalid pragma: acyclic")
elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
localError(info, errVarVarTypeNotAllowed) localError(conf, info, "type 'var var' is not allowed")
elif computeSize(t) == szIllegalRecursion: elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t)) localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
when false: when false:
if t.kind == tyObject and t.sons[0] != nil: if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@ -36,9 +36,8 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
proc searchInstTypes*(key: PType): PType = proc searchInstTypes*(key: PType): PType =
let genericTyp = key.sons[0] let genericTyp = key.sons[0]
internalAssert genericTyp.kind == tyGenericBody and if not (genericTyp.kind == tyGenericBody and
key.sons[0] == genericTyp and key.sons[0] == genericTyp and genericTyp.sym != nil): return
genericTyp.sym != nil
if genericTyp.sym.typeInstCache == nil: if genericTyp.sym.typeInstCache == nil:
return return
@ -195,19 +194,19 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
var branch: PNode = nil # the branch to take var branch: PNode = nil # the branch to take
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
if it == nil: illFormedAst(n) if it == nil: illFormedAst(n, cl.c.config)
case it.kind case it.kind
of nkElifBranch: of nkElifBranch:
checkSonsLen(it, 2) checkSonsLen(it, 2, cl.c.config)
var cond = prepareNode(cl, it.sons[0]) var cond = prepareNode(cl, it.sons[0])
var e = cl.c.semConstExpr(cl.c, cond) var e = cl.c.semConstExpr(cl.c, cond)
if e.kind != nkIntLit: if e.kind != nkIntLit:
internalError(e.info, "ReplaceTypeVarsN: when condition not a bool") internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
if e.intVal != 0 and branch == nil: branch = it.sons[1] if e.intVal != 0 and branch == nil: branch = it.sons[1]
of nkElse: of nkElse:
checkSonsLen(it, 1) checkSonsLen(it, 1, cl.c.config)
if branch == nil: branch = it.sons[0] if branch == nil: branch = it.sons[0]
else: illFormedAst(n) else: illFormedAst(n, cl.c.config)
if branch != nil: if branch != nil:
result = replaceTypeVarsN(cl, branch) result = replaceTypeVarsN(cl, branch)
else: else:
@ -244,14 +243,14 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
result = cl.typeMap.lookup(t) result = cl.typeMap.lookup(t)
if result == nil: if result == nil:
if cl.allowMetaTypes or tfRetType in t.flags: return if cl.allowMetaTypes or tfRetType in t.flags: return
localError(t.sym.info, errCannotInstantiateX, typeToString(t)) localError(cl.c.config, t.sym.info, "cannot instantiate: " & typeToString(t))
result = errorType(cl.c) result = errorType(cl.c)
# In order to prevent endless recursions, we must remember # In order to prevent endless recursions, we must remember
# this bad lookup and replace it with errorType everywhere. # this bad lookup and replace it with errorType everywhere.
# These code paths are only active in "nim check" # These code paths are only active in "nim check"
cl.typeMap.put(t, result) cl.typeMap.put(t, result)
elif result.kind == tyGenericParam and not cl.allowMetaTypes: elif result.kind == tyGenericParam and not cl.allowMetaTypes:
internalError(cl.info, "substitution with generic parameter") internalError(cl.c.config, cl.info, "substitution with generic parameter")
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
# XXX: relying on allowMetaTypes is a kludge # XXX: relying on allowMetaTypes is a kludge
@ -278,7 +277,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# is difficult to handle: # is difficult to handle:
const eqFlags = eqTypeFlags + {tfGcSafe} const eqFlags = eqTypeFlags + {tfGcSafe}
var body = t.sons[0] var body = t.sons[0]
if body.kind != tyGenericBody: internalError(cl.info, "no generic body") if body.kind != tyGenericBody: internalError(cl.c.config, cl.info, "no generic body")
var header: PType = t var header: PType = t
# search for some instantiation here: # search for some instantiation here:
if cl.allowMetaTypes: if cl.allowMetaTypes:
@ -351,7 +350,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# handleGenericInvocation will handle the alias-to-alias-to-alias case # handleGenericInvocation will handle the alias-to-alias-to-alias case
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
rawAddSon(result, newbody) rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, newbody) checkPartialConstructedType(cl.c.config, cl.info, newbody)
let dc = newbody.deepCopy let dc = newbody.deepCopy
if cl.allowMetaTypes == false: if cl.allowMetaTypes == false:
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags: if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
@ -417,7 +416,7 @@ proc propagateFieldFlags(t: PType, n: PNode) =
# The type must be fully instantiated! # The type must be fully instantiated!
if n.isNil: if n.isNil:
return return
internalAssert n.kind != nkRecWhen #internalAssert n.kind != nkRecWhen
case n.kind case n.kind
of nkSym: of nkSym:
propagateToOwner(t, n.sym.typ) propagateToOwner(t, n.sym.typ)
@ -454,7 +453,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result.kind = tyUserTypeClassInst result.kind = tyUserTypeClassInst
of tyGenericBody: of tyGenericBody:
localError(cl.info, errCannotInstantiateX, typeToString(t)) localError(cl.c.config, cl.info, "cannot instantiate: " & typeToString(t))
result = errorType(cl.c) result = errorType(cl.c)
#result = replaceTypeVarsT(cl, lastSon(t)) #result = replaceTypeVarsT(cl, lastSon(t))
@ -533,7 +532,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
case result.kind case result.kind
of tyArray: of tyArray:
let idx = result.sons[0] let idx = result.sons[0]
internalAssert idx.kind != tyStatic internalAssert cl.c.config, idx.kind != tyStatic
of tyObject, tyTuple: of tyObject, tyTuple:
propagateFieldFlags(result, result.n) propagateFieldFlags(result, result.n)

View file

@ -15,7 +15,7 @@
## * Computing an aliasing relation based on the assignments. This relation ## * Computing an aliasing relation based on the assignments. This relation
## is then used to compute the 'writes' and 'escapes' effects. ## is then used to compute the 'writes' and 'escapes' effects.
import intsets, idents, ast, astalgo, trees, renderer, msgs, types import intsets, idents, ast, astalgo, trees, renderer, msgs, types, options
const const
debug = false debug = false
@ -180,7 +180,7 @@ proc deps(w: var W; n: PNode) =
let last = lastSon(child) let last = lastSon(child)
if last.kind == nkEmpty: continue if last.kind == nkEmpty: continue
if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}: if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}:
internalAssert child.len-2 == last.len if child.len-2 != last.len: return
for i in 0 .. child.len-3: for i in 0 .. child.len-3:
deps(w, child.sons[i], last.sons[i], {}) deps(w, child.sons[i], last.sons[i], {})
else: else:
@ -220,7 +220,7 @@ proc possibleAliases(w: var W; result: var seq[ptr TSym]) =
# x = f(..., y, ....) # x = f(..., y, ....)
for i in 0 ..< a.srcNoTc: addNoDup a.src[i] for i in 0 ..< a.srcNoTc: addNoDup a.src[i]
proc markWriteOrEscape(w: var W) = proc markWriteOrEscape(w: var W; conf: ConfigRef) =
## Both 'writes' and 'escapes' effects ultimately only care ## Both 'writes' and 'escapes' effects ultimately only care
## about *parameters*. ## about *parameters*.
## However, due to aliasing, even locals that might not look as parameters ## However, due to aliasing, even locals that might not look as parameters
@ -249,7 +249,7 @@ proc markWriteOrEscape(w: var W) =
if p.kind == skParam and p.owner == w.owner: if p.kind == skParam and p.owner == w.owner:
incl(p.flags, sfWrittenTo) incl(p.flags, sfWrittenTo)
if w.owner.kind == skFunc and p.typ.kind != tyVar: if w.owner.kind == skFunc and p.typ.kind != tyVar:
localError(a.info, "write access to non-var parameter: " & p.name.s) localError(conf, a.info, "write access to non-var parameter: " & p.name.s)
if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}: if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}:
var destIsParam = false var destIsParam = false
@ -263,14 +263,14 @@ proc markWriteOrEscape(w: var W) =
if p.kind == skParam and p.owner == w.owner: if p.kind == skParam and p.owner == w.owner:
incl(p.flags, sfEscapes) incl(p.flags, sfEscapes)
proc trackWrites*(owner: PSym; body: PNode) = proc trackWrites*(owner: PSym; body: PNode; conf: ConfigRef) =
var w: W var w: W
w.owner = owner w.owner = owner
w.assignments = @[] w.assignments = @[]
# Phase 1: Collect and preprocess any assignments in the proc body: # Phase 1: Collect and preprocess any assignments in the proc body:
deps(w, body) deps(w, body)
# Phase 2: Compute the 'writes' and 'escapes' effects: # Phase 2: Compute the 'writes' and 'escapes' effects:
markWriteOrEscape(w) markWriteOrEscape(w, conf)
if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and
containsGarbageCollectedRef(owner.typ.sons[0]): containsGarbageCollectedRef(owner.typ.sons[0]):
incl(owner.typ.flags, tfReturnsNew) incl(owner.typ.flags, tfReturnsNew)