diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 8b0a8e9bb5..037594e899 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -921,6 +921,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope = app(result, x) app(result, "\\n\"\n") else: + res.add(tnl) result = res.toRope proc genAsmStmt(p: BProc, t: PNode) = diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 948541302c..d881226d4d 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -11,7 +11,7 @@ import intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, - sempass2 + sempass2, strutils proc genConv(n: PNode, d: PType, downcast: bool): PNode = var dest = skipTypes(d, abstractPtrs) @@ -44,7 +44,8 @@ proc methodCall*(n: PNode): PNode = result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true) # save for incremental compilation: -var gMethods: seq[TSymSeq] = @[] +var + gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[] proc sameMethodBucket(a, b: PSym): bool = result = false @@ -80,31 +81,70 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) = else: s.ast.add(dispatcher) +proc createDispatcher(s: PSym): PSym = + var disp = copySym(s) + incl(disp.flags, sfDispatcher) + excl(disp.flags, sfExported) + disp.typ = copyType(disp.typ, disp.typ.owner, false) + # we can't inline the dispatcher itself (for now): + if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault + disp.ast = copyTree(s.ast) + disp.ast.sons[bodyPos] = ast.emptyNode + disp.loc.r = nil + if s.typ.sons[0] != nil: + if disp.ast.sonsLen > resultPos: + disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym) + else: + # We've encountered a method prototype without a filled-in + # resultPos slot. We put a placeholder in there that will + # be updated in fixupDispatcher(). + disp.ast.addSon(ast.emptyNode) + attachDispatcher(s, newSymNode(disp)) + # attach to itself to prevent bugs: + attachDispatcher(disp, newSymNode(disp)) + return disp + +proc fixupDispatcher(meth, disp: PSym) = + # We may have constructed the dispatcher from a method prototype + # and need to augment the incomplete dispatcher with information + # from later definitions, particularly the resultPos slot. Also, + # the lock level of the dispatcher needs to be updated/checked + # against that of the method. + if disp.ast.sonsLen > resultPos and meth.ast.sonsLen > resultPos and + disp.ast.sons[resultPos] == ast.emptyNode: + disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos]) + + # The following code works only with lock levels, so we disable + # it when they're not available. + when declared(TLockLevel): + proc `<`(a, b: TLockLevel): bool {.borrow.} + proc `==`(a, b: TLockLevel): bool {.borrow.} + if disp.typ.lockLevel == UnspecifiedLockLevel: + disp.typ.lockLevel = meth.typ.lockLevel + elif meth.typ.lockLevel != UnspecifiedLockLevel and + meth.typ.lockLevel != disp.typ.lockLevel: + message(meth.info, warnLockLevel, + "method has lock level $1, but another method has $2" % + [$meth.typ.lockLevel, $disp.typ.lockLevel]) + # XXX The following code silences a duplicate warning in + # checkMethodeffects() in sempass2.nim for now. + if disp.typ.lockLevel < meth.typ.lockLevel: + disp.typ.lockLevel = meth.typ.lockLevel + proc methodDef*(s: PSym, fromCache: bool) = var L = len(gMethods) for i in countup(0, L - 1): - let disp = gMethods[i][0] + var disp = gMethods[i].dispatcher if sameMethodBucket(disp, s): - add(gMethods[i], s) + add(gMethods[i].methods, s) attachDispatcher(s, lastSon(disp.ast)) + fixupDispatcher(s, disp) when useEffectSystem: checkMethodEffects(disp, s) return - add(gMethods, @[s]) # create a new dispatcher: - if not fromCache: - var disp = copySym(s) - incl(disp.flags, sfDispatcher) - excl(disp.flags, sfExported) - disp.typ = copyType(disp.typ, disp.typ.owner, false) - # we can't inline the dispatcher itself (for now): - if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault - disp.ast = copyTree(s.ast) - disp.ast.sons[bodyPos] = ast.emptyNode - if s.typ.sons[0] != nil: - disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym) - attachDispatcher(s, newSymNode(disp)) - # attach to itself to prevent bugs: - attachDispatcher(disp, newSymNode(disp)) + add(gMethods, (methods: @[s], dispatcher: createDispatcher(s))) + if fromCache: + internalError(s.info, "no method dispatcher found") proc relevantCol(methods: TSymSeq, col: int): bool = # returns true iff the position is relevant @@ -194,8 +234,9 @@ proc generateMethodDispatchers*(): PNode = result = newNode(nkStmtList) for bucket in countup(0, len(gMethods) - 1): var relevantCols = initIntSet() - for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1): - if relevantCol(gMethods[bucket], col): incl(relevantCols, col) - sortBucket(gMethods[bucket], relevantCols) - addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols))) + for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1): + if relevantCol(gMethods[bucket].methods, col): incl(relevantCols, col) + sortBucket(gMethods[bucket].methods, relevantCols) + addSon(result, + newSymNode(genDispatcher(gMethods[bucket].methods, relevantCols))) diff --git a/compiler/commands.nim b/compiler/commands.nim index 87e94d9c9d..cea965f5c3 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -393,7 +393,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info) of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info) of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info) - of "threads": processOnOffSwitchG({optThreads}, arg, pass, info) + of "threads": + processOnOffSwitchG({optThreads}, arg, pass, info) + if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe) of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info) of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info) of "implicitstatic": diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4c98034013..434e2a65b1 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -383,6 +383,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = var seeSrcRope: PRope = nil let docItemSeeSrc = getConfigVar("doc.item.seesrc") if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0: + # XXX toFilename doesn't really work. We need to ensure that this keeps + # returning a relative path. let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl, ["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)]) dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc, diff --git a/compiler/importer.nim b/compiler/importer.nim index b4cae017e4..33ed7e0555 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -92,7 +92,7 @@ proc rawImportSymbol(c: PContext, s: PSym) = if s.kind == skConverter: addConverter(c, s) if hasPattern(s): addPattern(c, s) -proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = +proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = let ident = lookups.considerQuotedIdent(n) let s = strTableGet(fromMod.tab, ident) if s == nil: @@ -153,12 +153,14 @@ proc importModuleAs(n: PNode, realModule: PSym): PSym = localError(n.info, errGenerated, "module alias must be an identifier") elif n.sons[1].ident.id != realModule.name.id: # some misguided guy will write 'import abc.foo as foo' ... - result = createModuleAlias(realModule, n.sons[1].ident, n.sons[1].info) + result = createModuleAlias(realModule, n.sons[1].ident, realModule.info) -proc myImportModule(c: PContext, n: PNode): PSym = +proc myImportModule(c: PContext, n: PNode): PSym = var f = checkModuleName(n) if f != InvalidFileIDX: result = importModuleAs(n, gImportModule(c.module, f)) + if result.info.fileIndex == n.info.fileIndex: + localError(n.info, errGenerated, "A module cannot import itself") if sfDeprecated in result.flags: message(n.info, warnDeprecated, result.name.s) @@ -171,7 +173,7 @@ proc evalImport(c: PContext, n: PNode): PNode = # ``addDecl`` needs to be done before ``importAllSymbols``! addDecl(c, m) # add symbol to symbol table of module importAllSymbolsExcept(c, m, emptySet) - importForwarded(c, m.ast, emptySet) + #importForwarded(c, m.ast, emptySet) proc evalFrom(c: PContext, n: PNode): PNode = result = n @@ -196,4 +198,4 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode = let ident = lookups.considerQuotedIdent(n.sons[i]) exceptSet.incl(ident.id) importAllSymbolsExcept(c, m, exceptSet) - importForwarded(c, m.ast, exceptSet) + #importForwarded(c, m.ast, exceptSet) diff --git a/compiler/nimrod.ini b/compiler/nimrod.ini index ae1c6053f1..7135b3490f 100644 --- a/compiler/nimrod.ini +++ b/compiler/nimrod.ini @@ -126,7 +126,7 @@ Files: "start.bat" BinPath: r"bin;dist\mingw\bin;dist" ; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry -Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip" +Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|doc\overview.html" Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip" Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.1.3.zip|aporia\bin\aporia.exe" ; for now only NSIS supports optional downloads diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 46e6f1ab3c..58cef36f9c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1935,11 +1935,13 @@ proc semExport(c: PContext, n: PNode): PNode = while s != nil: if s.kind in ExportableSymKinds+{skModule}: x.add(newSymNode(s, a.info)) + strTableAdd(c.module.tab, s) s = nextOverloadIter(o, c, a) - if c.module.ast.isNil: - c.module.ast = newNodeI(nkStmtList, n.info) - assert c.module.ast.kind == nkStmtList - c.module.ast.add x + when false: + if c.module.ast.isNil: + c.module.ast = newNodeI(nkStmtList, n.info) + assert c.module.ast.kind == nkStmtList + c.module.ast.add x result = n proc setGenericParams(c: PContext, n: PNode) = diff --git a/compiler/transf.nim b/compiler/transf.nim index b9b06675ed..1ec31d605c 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -624,6 +624,9 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = # bugfix: check after 'transformSons' if it's still a method call: # use the dispatcher for the call: if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod: + let t = lastSon(s.sons[0].sym.ast) + if t.kind != nkSym or sfDispatcher notin t.sym.flags: + methodDef(s.sons[0].sym, false) result = methodCall(s).PTransNode else: result = s.PTransNode diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index dc241db500..975c7c06af 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -41,7 +41,6 @@ doc.item = """
$header