diff options
author | Araq <rumpf_a@web.de> | 2014-02-17 23:59:48 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-02-17 23:59:48 +0100 |
commit | 9b63fccf16048121d79fc825107ea7433faa25e7 (patch) | |
tree | 7786c489c36b5ba58d90ab4d52a798c0362fed12 /compiler | |
parent | 420d4197f139c277f7b7d0eaf462ed0fe9e00745 (diff) | |
parent | eaab22089da855163485949d8bd6a6ae9c1d25c8 (diff) | |
download | Nim-9b63fccf16048121d79fc825107ea7433faa25e7.tar.gz |
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 11 | ||||
-rw-r--r-- | compiler/c2nim/cparse.nim | 8 | ||||
-rw-r--r-- | compiler/c2nim/cpp.nim | 4 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 34 | ||||
-rw-r--r-- | compiler/cgendata.nim | 1 | ||||
-rw-r--r-- | compiler/msgs.nim | 4 | ||||
-rw-r--r-- | compiler/parser.nim | 2 | ||||
-rw-r--r-- | compiler/pas2nim/paslex.nim | 2 | ||||
-rw-r--r-- | compiler/pas2nim/pasparse.nim | 24 | ||||
-rw-r--r-- | compiler/sem.nim | 1 | ||||
-rw-r--r-- | compiler/semcall.nim | 38 | ||||
-rw-r--r-- | compiler/semdata.nim | 2 | ||||
-rw-r--r-- | compiler/semdestruct.nim | 67 | ||||
-rw-r--r-- | compiler/semexprs.nim | 57 | ||||
-rw-r--r-- | compiler/semstmts.nim | 85 | ||||
-rw-r--r-- | compiler/semtypes.nim | 5 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 21 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 86 | ||||
-rw-r--r-- | compiler/types.nim | 12 |
19 files changed, 281 insertions, 183 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index cd002eef1..fe724f4dd 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim index ffab05788..e4abe11a0 100644 --- a/compiler/c2nim/cparse.nim +++ b/compiler/c2nim/cparse.nim @@ -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 diff --git a/compiler/c2nim/cpp.nim b/compiler/c2nim/cpp.nim index 1707b75db..84b4c4dfb 100644 --- a/compiler/c2nim/cpp.nim +++ b/compiler/c2nim/cpp.nim @@ -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) = diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index af0d657f1..443d845f6 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -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]) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 0e1148343..71479abdd 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -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 diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 61336aa87..268205361 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -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", diff --git a/compiler/parser.nim b/compiler/parser.nim index ff3324b47..5a5bfb574 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -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: diff --git a/compiler/pas2nim/paslex.nim b/compiler/pas2nim/paslex.nim index 67473e71f..f24b0c420 100644 --- a/compiler/pas2nim/paslex.nim +++ b/compiler/pas2nim/paslex.nim @@ -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 diff --git a/compiler/pas2nim/pasparse.nim b/compiler/pas2nim/pasparse.nim index 928896338..a6f8363f6 100644 --- a/compiler/pas2nim/pasparse.nim +++ b/compiler/pas2nim/pasparse.nim @@ -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) diff --git a/compiler/sem.nim b/compiler/sem.nim index 140687721..09b2511f1 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 6b19dc359..0cd27a443 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -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] - - pickBest(callOp) + # 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 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 0bc52d6b7..df58c896f 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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) diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index fb05826cb..791bef823 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -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 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 3fe1367ec..c271911ab 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0871b7fb7..503ea4bc1 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 44e414e9c..184aca4f8 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 73b618f46..f08214f1e 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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() diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 227228f6e..5fe474ef3 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 diff --git a/compiler/types.nim b/compiler/types.nim index bb9f18dc3..d7148f110 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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 |