Merge branch 'devel' of https://github.com/Araq/Nimrod into devel

This commit is contained in:
Araq 2014-02-17 23:59:48 +01:00
commit 9b63fccf16
53 changed files with 1124 additions and 473 deletions

View file

@ -409,7 +409,9 @@ type
# efficiency
nfTransf, # node has been transformed
nfSem # node has been checked for semantics
nfDelegate # the call can use a delegator
nfDotField # the call can use a dot operator
nfDotSetter # the call can use a setter dot operarator
nfExplicitCall # x.y() was used instead of x.y
nfExprCall # this is an attempt to call a regular expression
nfIsRef # this node is a 'ref' node; used for the VM
@ -843,7 +845,8 @@ const
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
nfAllConst, nfDelegate, nfIsRef}
nfDotSetter, nfDotField,
nfAllConst,nfIsRef}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@ -1044,6 +1047,10 @@ proc newStrNode(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind)
result.strVal = strVal
proc withInfo*(n: PNode, info: TLineInfo): PNode =
n.info = info
return n
proc newIdentNode(ident: PIdent, info: TLineInfo): PNode =
result = newNode(nkIdent)
result.ident = ident

View file

@ -540,7 +540,7 @@ proc typeAtom(p: var TParser): PNode =
if p.tok.s == "unsigned":
isUnsigned = true
elif p.tok.s == "signed" or p.tok.s == "int":
nil
discard
else:
add(x, p.tok.s)
getTok(p, nil)
@ -746,7 +746,7 @@ proc directDeclarator(p: var TParser, a: PNode, ident: ptr PNode): PNode =
result = declarator(p, a, ident)
eat(p, pxParRi, result)
else:
nil
discard
return parseTypeSuffix(p, a)
proc declarator(p: var TParser, a: PNode, ident: ptr PNode): PNode =
@ -1165,7 +1165,7 @@ proc enumSpecifier(p: var TParser): PNode =
proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base
of base10: nil
of base10: discard
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
@ -1686,7 +1686,7 @@ proc switchStatement(p: var TParser): PNode =
break
of "case", "default":
break
else: nil
else: discard
addSon(result, statement(p))
if sonsLen(result) == 0:
# translate empty statement list to Nimrod's ``nil`` statement

View file

@ -103,7 +103,7 @@ proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
m.body.add(tok)
of pxDirConc:
# just ignore this token: this implements token merging correctly
nil
discard
else:
m.body.add(p.tok)
# we do not want macro expansion here:
@ -166,7 +166,7 @@ proc parseStmtList(p: var TParser): PNode =
of pxDirectiveParLe, pxDirective:
case p.tok.s
of "else", "endif", "elif": break
else: nil
else: discard
addSon(result, statement(p))
proc eatEndif(p: var TParser) =

View file

@ -65,6 +65,7 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
setLen(p.blocks, result + 1)
p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
proc assignLabel(b: var TBlock): PRope {.inline.} =
b.label = con("LA", b.id.toRope)
@ -260,14 +261,22 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
else: internalError(n.info, "genIf()")
if sonsLen(n) > 1: fixLabel(p, lend)
proc blockLeaveActions(p: BProc, howMany: int) =
var L = p.nestedTryStmts.len
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# This is called by return and break stmts.
# When jumping out of try/except/finally stmts,
# we need to pop safe points from try statements,
# execute finally-stmts, and pop exceptions
# from except stmts
let L = p.nestedTryStmts.len
# danger of endless recursion! we workaround this here by a temp stack
var stack: seq[PNode]
newSeq(stack, howMany)
for i in countup(1, howMany):
newSeq(stack, howManyTrys)
for i in countup(1, howManyTrys):
stack[i-1] = p.nestedTryStmts[L-i]
setLen(p.nestedTryStmts, L-howMany)
setLen(p.nestedTryStmts, L-howManyTrys)
var alreadyPoppedCnt = p.inExceptBlock
for tryStmt in items(stack):
@ -276,21 +285,26 @@ proc blockLeaveActions(p: BProc, howMany: int) =
dec alreadyPoppedCnt
else:
linefmt(p, cpsStmts, "#popSafePoint();$n")
# Find finally-stmts for this try-stmt
# and generate a copy of the finally stmts here
var finallyStmt = lastSon(tryStmt)
if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0])
# push old elements again:
for i in countdown(howMany-1, 0):
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if gCmd != cmdCompileToCpp:
for i in countdown(p.inExceptBlock-1, 0):
# Pop exceptions that was handled by the
# except-blocks we are in
for i in countdown(howManyExcepts-1, 0):
linefmt(p, cpsStmts, "#popCurrentException();$n")
proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true
genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
blockLeaveActions(p, min(1, p.nestedTryStmts.len))
blockLeaveActions(p, min(1, p.nestedTryStmts.len), p.inExceptBlock)
lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
proc genComputedGoto(p: BProc; n: PNode) =
@ -450,7 +464,9 @@ proc genBreakStmt(p: BProc, t: PNode) =
if idx < 0 or not p.blocks[idx].isLoop:
internalError(t.info, "no loop to break")
let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label])

View file

@ -58,6 +58,7 @@ type
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
nestedTryStmts*: int16 # how many try statements is it nested into
nestedExceptStmts*: int16 # how many except statements is it nested into
frameLen*: int16
TCProc{.final.} = object # represents C proc that is currently generated

View file

@ -88,7 +88,8 @@ type
errTemplateInstantiationTooNested, errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
errMainModuleMustBeSpecified,
errXExpected,
errXExpected,
errTIsNotAConcreteType,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
@ -312,6 +313,7 @@ const
errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
errXExpected: "\'$1\' expected",
errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",

View file

@ -281,7 +281,7 @@ proc parseSymbol(p: var TParser): PNode =
add(result, newIdentNodeP(getIdent"{}", p))
getTok(p)
eat(p, tkCurlyRi)
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDotDot:
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot:
add(result, newIdentNodeP(p.tok.ident, p))
getTok(p)
of tkIntLit..tkCharLit:

View file

@ -342,7 +342,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
h = h +% ord(c)
h = h +% h shl 10
h = h xor (h shr 6)
of '_': nil
of '_': discard
else: break
inc(pos)
h = h +% h shl 3

View file

@ -335,7 +335,7 @@ proc exprColonEqExprList(p: var TParser, kind, elemKind: TNodeKind,
proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base
of base10: nil
of base10: discard
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
@ -466,7 +466,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
eat(p, pxCurlyDirRi)
opNode.ident = getIdent("&")
else:
nil
discard
of pxMinus:
if p.tok.xkind == pxPer:
getTok(p)
@ -477,7 +477,7 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
of pxNeq:
opNode.ident = getIdent("!=")
else:
nil
discard
skipCom(p, opNode) # read sub-expression with higher priority
nextop = lowestExprAux(p, v2, opPred)
addSon(node, opNode)
@ -505,7 +505,7 @@ proc fixExpr(n: PNode): PNode =
(n.sons[2].kind in {nkCharLit, nkStrLit}):
n.sons[0].ident = getIdent("&") # fix operator
else:
nil
discard
if not (n.kind in {nkEmpty..nkNilLit}):
for i in countup(0, sonsLen(n) - 1): result.sons[i] = fixExpr(n.sons[i])
@ -603,7 +603,7 @@ proc parseStmtList(p: var TParser): PNode =
of pxCurlyDirLe, pxStarDirLe:
if not isHandledDirective(p): break
else:
nil
discard
addSon(result, parseStmt(p))
if sonsLen(result) == 1: result = result.sons[0]
@ -732,7 +732,7 @@ proc parseRepeat(p: var TParser): PNode =
addSon(b, c)
addSon(a, b)
if b.sons[0].kind == nkIdent and b.sons[0].ident.id == getIdent("false").id:
nil
discard
else:
addSon(s, a)
addSon(result, s)
@ -840,7 +840,7 @@ proc parseParam(p: var TParser): PNode =
getTok(p)
v = newNodeP(nkVarTy, p)
else:
nil
discard
while true:
case p.tok.xkind
of pxSymbol: a = createIdentNodeP(p.tok.ident, p)
@ -1133,7 +1133,7 @@ proc parseRecordPart(p: var TParser): PNode =
proc exSymbol(n: var PNode) =
case n.kind
of nkPostfix:
nil
discard
of nkPragmaExpr:
exSymbol(n.sons[0])
of nkIdent, nkAccQuoted:
@ -1154,7 +1154,7 @@ proc fixRecordDef(n: var PNode) =
for i in countup(0, sonsLen(n) - 1): fixRecordDef(n.sons[i])
of nkIdentDefs:
for i in countup(0, sonsLen(n) - 3): exSymbol(n.sons[i])
of nkNilLit, nkEmpty: nil
of nkNilLit, nkEmpty: discard
else: internalError(n.info, "fixRecordDef(): " & $n.kind)
proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
@ -1191,7 +1191,7 @@ proc parseRecordBody(p: var TParser, result, definition: PNode) =
if definition != nil: addPragmaToIdent(definition.sons[0], parseCommand(p))
else: internalError(result.info, "anonymous record is not supported")
else:
nil
discard
opt(p, pxSemicolon)
skipCom(p, result)
@ -1399,7 +1399,7 @@ proc fixVarSection(p: var TParser, counter: PNode) =
proc exSymbols(n: PNode) =
case n.kind
of nkEmpty..nkNilLit: nil
of nkEmpty..nkNilLit: discard
of nkProcDef..nkIteratorDef: exSymbol(n.sons[namePos])
of nkWhenStmt, nkStmtList:
for i in countup(0, sonsLen(n) - 1): exSymbols(n.sons[i])
@ -1410,7 +1410,7 @@ proc exSymbols(n: PNode) =
exSymbol(n.sons[i].sons[0])
if n.sons[i].sons[2].kind == nkObjectTy:
fixRecordDef(n.sons[i].sons[2])
else: nil
else: discard
proc parseBegin(p: var TParser, result: PNode) =
getTok(p)

View file

@ -333,6 +333,7 @@ proc myOpen(module: PSym): PPassContext =
c.semOperand = semOperand
c.semConstBoolExpr = semConstBoolExpr
c.semOverloadedCall = semOverloadedCall
c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode
pushProcCon(c, module)

View file

@ -82,7 +82,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
# fail fast:
globalError(n.info, errTypeMismatch, "")
var result = msgKindToString(errTypeMismatch)
add(result, describeArgs(c, n, 1 + ord(nfDelegate in n.flags)))
add(result, describeArgs(c, n, 1 + ord(nfDotField in n.flags)))
add(result, ')')
var candidates = ""
@ -138,17 +138,35 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
let overloadsState = result.state
if overloadsState != csMatch:
if nfDelegate in n.flags:
internalAssert f.kind == nkIdent
let calleeName = newStrNode(nkStrLit, f.ident.s)
calleeName.info = n.info
if nfDotField in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen >= 2
let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info)
let callOp = newIdentNode(idDelegator, n.info)
n.sons[0..0] = [callOp, calleeName]
orig.sons[0..0] = [callOp, calleeName]
# leave the op head symbol empty,
# we are going to try multiple variants
n.sons[0..1] = [nil, n[1], calleeName]
orig.sons[0..1] = [nil, orig[1], calleeName]
template tryOp(x) =
let op = newIdentNode(getIdent(x), n.info)
n.sons[0] = op
orig.sons[0] = op
pickBest(op)
if nfExplicitCall in n.flags:
tryOp ".()"
if result.state in {csEmpty, csNoMatch}:
tryOp "."
elif nfDotSetter in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen == 3
let calleeName = newStrNode(nkStrLit, f.ident.s[0.. -2]).withInfo(n.info)
let callOp = newIdentNode(getIdent".=", n.info)
n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName]
pickBest(callOp)
if overloadsState == csEmpty and result.state == csEmpty:
localError(n.info, errUndeclaredIdentifier, considerAcc(f).s)
return

View file

@ -81,6 +81,7 @@ type
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
includedFiles*: TIntSet # used to detect recursive include files
@ -213,7 +214,6 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let typedesc = makeTypeDesc(c, typ)
rawAddSon(typedesc, newTypeS(tyNone, c))
let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
return newSymNode(sym, info)

View file

@ -55,7 +55,9 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
useSym(destructableT.destructor),
n.sons[paramsPos][1][0]]))
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode
proc destroySym(c: PContext, field: PSym, holder: PNode): PNode =
let destructableT = instantiateDestructor(c, field.typ)
if destructableT != nil:
result = newNode(nkCall, field.info, @[
@ -70,56 +72,49 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
for i in countup(1, n.len - 1):
# of A, B:
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
let recList = n[i].lastSon
var destroyRecList = newNode(nkStmtList, n[i].info, @[])
template addField(f: expr): stmt =
let stmt = destroyField(c, f, holder)
if stmt != nil:
destroyRecList.addSon(stmt)
inc nonTrivialFields
case recList.kind
of nkSym:
addField(recList.sym)
of nkRecList:
for j in countup(0, recList.len - 1):
addField(recList[j].sym)
let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
if stmt == nil:
caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
else:
internalAssert false
caseBranch.addSon(destroyRecList)
caseBranch.addSon(stmt)
nonTrivialFields += stmt.len
result.addSon(caseBranch)
# maybe no fields were destroyed?
if nonTrivialFields == 0:
result = nil
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
template maybeAddLine(e: expr): stmt =
let stmt = e
if stmt != nil:
if result == nil: result = newNode(nkStmtList)
result.addSon(stmt)
case field.kind
of nkRecCase:
maybeAddLine destroyCase(c, field, holder)
of nkSym:
maybeAddLine destroySym(c, field.sym, holder)
of nkRecList:
for son in field:
maybeAddLine destroyFieldOrFields(c, son, holder)
else:
internalAssert false
proc generateDestructor(c: PContext, t: PType): PNode =
## generate a destructor for a user-defined object or tuple type
## returns nil if the destructor turns out to be trivial
template addLine(e: expr): stmt =
if result == nil: result = newNode(nkStmtList)
result.addSon(e)
# XXX: This may be true for some C-imported types such as
# Tposix_spawnattr
if t.n == nil or t.n.sons == nil: return
internalAssert t.n.kind == nkRecList
let destructedObj = newIdentNode(destructorParam, unknownLineInfo())
# call the destructods of all fields
for s in countup(0, t.n.sons.len - 1):
case t.n.sons[s].kind
of nkRecCase:
let stmt = destroyCase(c, t.n.sons[s], destructedObj)
if stmt != nil: addLine(stmt)
of nkSym:
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
if stmt != nil: addLine(stmt)
else:
# XXX just skip it for now so that the compiler doesn't crash, but
# please zahary fix it! arbitrary nesting of nkRecList/nkRecCase is
# possible. Any thread example seems to trigger this.
discard
result = destroyFieldOrFields(c, t.n, destructedObj)
# base classes' destructors will be automatically called by
# semProcAux for both auto-generated and user-defined destructors

View file

@ -346,22 +346,21 @@ proc semIs(c: PContext, n: PNode): PNode =
result = n
n.typ = getSysType(tyBool)
n.sons[1] = semExprWithType(c, n[1], {efDetermineType})
n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
let t2 = semTypeNode(c, n[2], nil)
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
if n[1].typ.kind != tyTypeDesc:
n.sons[1] = makeTypeSymNode(c, n[1].typ, n[1].info)
elif n[1].typ.sonsLen == 0:
let lhsType = n[1].typ
if lhsType.kind != tyTypeDesc:
n.sons[1] = makeTypeSymNode(c, lhsType, n[1].info)
elif lhsType.base.kind == tyNone:
# this is a typedesc variable, leave for evals
return
let t1 = n[1].typ.sons[0]
# BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(t1): result = isOpImpl(c, n)
if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n)
proc semOpAux(c: PContext, n: PNode) =
const flags = {efDetermineType}
@ -683,20 +682,21 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
incl(c.p.owner.flags, sfSideEffect)
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil
checkMinSonsLen(n, 1)
var prc = n.sons[0]
if n.sons[0].kind == nkDotExpr:
if n.sons[0].kind == nkDotExpr:
checkSonsLen(n.sons[0], 2)
n.sons[0] = semFieldAccess(c, n.sons[0])
if n.sons[0].kind == nkDotCall:
if n.sons[0].kind == nkDotCall:
# it is a static call!
result = n.sons[0]
result.kind = nkCall
result.flags.incl nfExplicitCall
for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
return semExpr(c, result, flags)
else:
else:
n.sons[0] = semExpr(c, n.sons[0])
let nOrig = n.copyTree
semOpAux(c, n)
@ -917,8 +917,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
var ty = n.sons[0].typ
var f: PSym = nil
result = nil
if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.len == 1:
if ty.kind == tyTypeDesc: ty = ty.sons[0]
if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.base.kind != tyNone:
if ty.kind == tyTypeDesc: ty = ty.base
case ty.kind
of tyEnum:
# look up if the identifier belongs to the enum:
@ -999,7 +999,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
else:
var i = considerAcc(n.sons[1])
result = newNodeI(nkDotCall, n.info)
result.flags.incl nfDelegate
result.flags.incl nfDotField
addSon(result, newIdentNode(i, n[1].info))
addSon(result, copyTree(n[0]))
@ -1082,12 +1082,13 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerAcc(a[1])
let setterId = newIdentNode(getIdent(id.s & '='), n.info)
var setterId = newIdentNode(getIdent(id.s & '='), n.info)
# a[0] is already checked for semantics, that does ``builtinFieldAccess``
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes?
let aOrig = nOrig[0]
result = newNode(nkCall, n.info, sons = @[setterId, a[0], semExpr(c, n[1])])
result.flags.incl nfDotSetter
let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
@ -1777,22 +1778,6 @@ proc semBlock(c: PContext, n: PNode): PNode =
closeScope(c)
dec(c.p.nestedBlockCounter)
proc buildCall(n: PNode): PNode =
if n.kind == nkDotExpr and n.len == 2:
# x.y --> y(x)
result = newNodeI(nkCall, n.info, 2)
result.sons[0] = n.sons[1]
result.sons[1] = n.sons[0]
elif n.kind in nkCallKinds and n.sons[0].kind == nkDotExpr:
# x.y(a) -> y(x, a)
let a = n.sons[0]
result = newNodeI(nkCall, n.info, n.len+1)
result.sons[0] = a.sons[1]
result.sons[1] = a.sons[0]
for i in 1 .. <n.len: result.sons[i+1] = n.sons[i]
else:
result = n
proc doBlockIsStmtList(n: PNode): bool =
result = n.kind == nkDo and
n[paramsPos].sonsLen == 1 and
@ -1844,8 +1829,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = symChoice(c, n, s, scClosed)
if result.kind == nkSym:
markIndirect(c, result.sym)
if isGenericRoutine(result.sym):
localError(n.info, errInstantiateXExplicitely, s.name.s)
# if isGenericRoutine(result.sym):
# localError(n.info, errInstantiateXExplicitely, s.name.s)
of nkSym:
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
@ -1901,7 +1886,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1)
let mode = if nfDelegate in n.flags: {} else: {checkUndeclared}
let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
var s = qualifiedLookUp(c, n.sons[0], mode)
if s != nil:
if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
@ -1940,7 +1925,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# the 'newSeq[T](x)' bug
setGenericParams(c, n.sons[0])
result = semDirectOp(c, n, flags)
elif isSymChoice(n.sons[0]) or nfDelegate in n.flags:
elif isSymChoice(n.sons[0]) or nfDotField in n.flags:
result = semDirectOp(c, n, flags)
else:
result = semIndirectOp(c, n, flags)

View file

@ -764,6 +764,29 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
s.ast = a
popOwner()
proc checkForMetaFields(n: PNode) =
template checkMeta(t) =
if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
localError(n.info, errTIsNotAConcreteType, t.typeToString)
case n.kind
of nkRecList, nkRecCase:
for s in n: checkForMetaFields(s)
of nkOfBranch, nkElse:
checkForMetaFields(n.lastSon)
of nkSym:
let t = n.sym.typ
case t.kind
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
tyProc, tyGenericInvokation, tyGenericInst:
let start = ord(t.kind in {tyGenericInvokation, tyGenericInst})
for i in start .. <t.sons.len:
checkMeta(t.sons[i])
else:
checkMeta(t)
else:
internalAssert false
proc typeSectionFinalPass(c: PContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
@ -780,6 +803,8 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
assignType(s.typ, t)
s.typ.id = t.id # same id
checkConstructedType(s.info, s.typ)
if s.typ.kind in {tyObject, tyTuple}:
checkForMetaFields(s.typ.n)
let aa = a.sons[2]
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
aa.sons[0].kind == nkObjectTy:
@ -883,12 +908,19 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
s = n[namePos].sym
pushOwner(s)
openScope(c)
if n.sons[genericParamsPos].kind != nkEmpty:
illFormedAst(n) # process parameters:
var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty:
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
gp = n.sons[genericParamsPos]
else:
gp = newNodeI(nkGenericParams, n.info)
if n.sons[paramsPos].kind != nkEmpty:
var gp = newNodeI(nkGenericParams, n.info)
semParamList(c, n.sons[paramsPos], gp, s)
paramsTypeCheck(c, s.typ)
# paramsTypeCheck(c, s.typ)
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
# we have a list of implicit type parameters:
n.sons[genericParamsPos] = gp
else:
s.typ = newTypeS(tyProc, c)
rawAddSon(s.typ, nil)
@ -900,12 +932,13 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
#if efDetermineType notin flags:
# XXX not good enough; see tnamedparamanonproc.nim
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c)
if n.sons[genericParamsPos].kind == nkEmpty:
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c)
sideEffectsCheck(c, s)
else:
localError(n.info, errImplOfXexpected, s.name.s)
@ -913,6 +946,34 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
popOwner()
result.typ = s.typ
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
var n = n
n = replaceTypesInBody(c, pt, n)
result = n
n.sons[genericParamsPos] = emptyNode
n.sons[paramsPos] = n.typ.n
openScope(c)
var s = n.sons[namePos].sym
addParams(c, n.typ.n, skProc)
pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
addResultNode(c, n)
popProcCon(c)
closeScope(c)
s.ast = result
# alternative variant (not quite working):
# var prc = arg[0].sym
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
# result = inferred.ast
# result.kind = arg.kind
proc activate(c: PContext, n: PNode) =
# XXX: This proc is part of my plan for getting rid of
# forward declarations. stay tuned.
@ -1263,8 +1324,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
let (outer, inner) = insertDestructors(c, n.sons[i])
if outer != nil:
n.sons[i] = outer
for j in countup(i+1, length-1):
inner.addSon(semStmt(c, n.sons[j]))
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:

View file

@ -1030,9 +1030,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.kind != skError: localError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
assert s.typ.len > 0
internalAssert prev == nil
result = s.typ.sons[0]
internalAssert s.typ.base.kind != tyNone and prev == nil
result = s.typ.base
elif prev == nil:
result = s.typ
else:

View file

@ -29,6 +29,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
localError(info, errVarVarTypeNotAllowed)
elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t))
when false:
if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@ -409,14 +410,22 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
else: discard
proc initTypeVars(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
initIdTable(result.symMap)
copyIdTable(result.typeMap, pt)
initIdTable(result.localCache)
result.info = info
result.c = p
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode =
var cl = initTypeVars(p, pt, n.info)
pushInfoContext(n.info)
result = replaceTypeVarsN(cl, n)
popInfoContext()
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType =
var cl: TReplTypeVars
initIdTable(cl.symMap)
copyIdTable(cl.typeMap, pt)
initIdTable(cl.localCache)
cl.info = info
cl.c = p
var cl = initTypeVars(p, pt, info)
pushInfoContext(info)
result = replaceTypeVarsT(cl, t)
popInfoContext()

View file

@ -343,53 +343,57 @@ proc allowsNil(f: PType): TTypeRelation {.inline.} =
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
proc procParamTypeRel(c: var TCandidate, f, a: PType,
result: var TTypeRelation) =
var
m: TTypeRelation
f = f
proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
var f = f
if a.isMetaType:
if f.isMetaType:
# we are matching a generic proc (as proc param)
# We are matching a generic proc (as proc param)
# to another generic type appearing in the proc
# sigunature. there is a change that the target
# signature. There is a change that the target
# type is already fully-determined, so we are
# going to try resolve it
f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
if f == nil or f.isMetaType:
# no luck resolving the type, so the inference fails
result = isNone
return
return isNone
let reverseRel = typeRel(c, a, f)
if reverseRel == isGeneric:
m = isInferred
result = isInferred
inc c.genericMatches
else:
m = typeRel(c, f, a)
result = typeRel(c, f, a)
if m <= isSubtype or inconsistentVarTypes(f, a):
if result <= isSubtype or inconsistentVarTypes(f, a):
result = isNone
return
else:
result = minRel(m, result)
if result == isEqual:
inc c.exactMatches
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
case a.kind
of tyProc:
if sonsLen(f) != sonsLen(a): return
# Note: We have to do unification for the parameters before the
# return type!
result = isEqual # start with maximum; also correct for no
# params at all
for i in countup(1, sonsLen(f)-1):
procParamTypeRel(c, f.sons[i], a.sons[i], result)
template checkParam(f, a) =
result = minRel(result, procParamTypeRel(c, f, a))
if result == isNone: return
# Note: We have to do unification for the parameters before the
# return type!
for i in 1 .. <f.sonsLen:
checkParam(f.sons[i], a.sons[i])
if f.sons[0] != nil:
if a.sons[0] != nil:
procParamTypeRel(c, f.sons[0], a.sons[0], result)
checkParam(f.sons[0], a.sons[0])
else:
return isNone
elif a.sons[0] != nil:
return isNone
if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
return isNone
elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {}:
@ -866,7 +870,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else:
internalAssert a.sons != nil and a.sons.len > 0
c.typedescMatched = true
result = typeRel(c, f.sons[0], a.sons[0])
result = typeRel(c, f.base, a.base)
else:
result = isNone
else:
@ -896,22 +900,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = isNone
of tyTypeDesc:
if a.kind != tyTypeDesc: return isNone
var prev = PType(idTableGet(c.bindings, f))
if prev == nil:
if a.kind == tyTypeDesc:
if f.sons[0].kind == tyNone:
result = isGeneric
else:
result = typeRel(c, f.sons[0], a.sons[0])
if result != isNone:
put(c.bindings, f, a)
if f.base.kind == tyNone:
result = isGeneric
else:
result = isNone
result = typeRel(c, f.base, a.base)
if result != isNone:
put(c.bindings, f, a)
else:
internalAssert prev.sonsLen == 1
let toMatch = if tfUnresolved in f.flags: a
else: a.sons[0]
result = typeRel(c, prev.sons[0], toMatch)
else: a.base
result = typeRel(c, prev.base, toMatch)
of tyStmt:
result = isGeneric
@ -1015,7 +1017,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
argType = arg.typ
var
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc})
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
else: argType
r = typeRel(m, f, a)
@ -1037,10 +1039,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
#result = copyTree(arg)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isInferred, isInferredConvertible:
var prc = if arg.kind in nkLambdaKinds: arg[0].sym
else: arg.sym
let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
result = c.semInferredLambda(c, m.bindings, arg)
else:
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
if r == isInferredConvertible:
result = implicitConv(nkHiddenStdConv, f, result, m, c)
of isGeneric:
@ -1103,6 +1106,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
# incorrect to simply use the first fitting match. However, to implement
# this correctly is inefficient. We have to copy `m` here to be able to
# roll back the side effects of the unification algorithm.
let c = m.c
var x, y, z: TCandidate
initCandidate(c, x, m.callee)
@ -1124,10 +1128,10 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
x.state = csMatch
of csMatch:
var cmp = cmpCandidates(x, z)
if cmp < 0:
if cmp < 0:
best = i
x = z
elif cmp == 0:
elif cmp == 0:
y = z # z is as good as x
if x.state == csEmpty:
result = nil

View file

@ -431,8 +431,8 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
add(result, typeToString(t.sons[i]))
add(result, ']')
of tyTypeDesc:
if t.len == 0: result = "typedesc"
else: result = "typedesc[" & typeToString(t.sons[0]) & "]"
if t.base.kind == tyNone: result = "typedesc"
else: result = "typedesc[" & typeToString(t.base) & "]"
of tyStatic:
internalAssert t.len > 0
result = "static[" & typeToString(t.sons[0]) & "]"
@ -1042,7 +1042,8 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
of tyEmpty:
result = taField in flags
of tyTypeClasses:
result = true
result = tfGenericTypeParam in t.flags or
taField notin flags
of tyGenericBody, tyGenericParam, tyGenericInvokation,
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
result = false
@ -1231,8 +1232,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
result = computeSizeAux(lastSon(typ), a)
of tyTypeDesc:
result = if typ.len == 1: computeSizeAux(typ.sons[0], a)
else: szUnknownSize
result = computeSizeAux(typ.base, a)
of tyForward: return szIllegalRecursion
else:
#internalError("computeSizeAux()")
@ -1258,7 +1258,7 @@ proc containsGenericTypeIter(t: PType, closure: PObject): bool =
return true
if t.kind == tyTypeDesc:
if t.sons[0].kind == tyNone: return true
if t.base.kind == tyNone: return true
if containsGenericTypeIter(t.base, closure): return true
return false