diff --git a/compiler/ast.nim b/compiler/ast.nim index cba23c02c..aa6af7e3f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1668,5 +1668,5 @@ template hasDestructor*(t: PType): bool = tfHasAsgn in t.flags template incompleteType*(t: PType): bool = t.sym != nil and {sfForward, sfNoForward} * t.sym.flags == {sfForward} -template typeCompleted*(t: PType) = - incl t.sym.flags, sfNoForward +template typeCompleted*(s: PSym) = + incl s.flags, sfNoForward diff --git a/compiler/lookups.nim b/compiler/lookups.nim index eddfeea56..8d89b7c0d 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -155,7 +155,7 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) = var s = initTabIter(it, scope.symbols) var missingImpls = 0 while s != nil: - if sfForward in s.flags: + if sfForward in s.flags and s.kind != skType: # too many 'implementation of X' errors are annoying # and slow 'suggest' down: if missingImpls == 0: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index ab896716d..87c62312f 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -55,7 +55,7 @@ const wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, - wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain, wForward} + wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain, wPackage} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, @@ -799,7 +799,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, noVal(it) if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it) else: incl(sym.typ.flags, tfInheritable) - of wForward: + of wPackage: noVal(it) if sym.typ == nil: invalidPragma(it) else: incl(sym.flags, sfForward) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 1993504d7..e2ee9ac67 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -775,21 +775,52 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = checkSonsLen(a, 3) let name = a.sons[0] var s: PSym - if name.kind == nkDotExpr: - s = qualifiedLookUp(c, name, {checkUndeclared, checkModule}) - if s.kind != skType or - s.typ.skipTypes(abstractPtrs).kind != tyObject or - tfPartial notin s.typ.skipTypes(abstractPtrs).flags: - localError(name.info, "only .partial objects can be extended") + if name.kind == nkDotExpr and a[2].kind == nkObjectTy: + let pkgName = considerQuotedIdent(name[0]) + let typName = considerQuotedIdent(name[1]) + let pkg = c.graph.packageSyms.strTableGet(pkgName) + if pkg.isNil or pkg.kind != skPackage: + localError(name.info, "unknown package name: " & pkgName.s) + else: + let typsym = pkg.tab.strTableGet(typName) + if typsym.isNil: + s = semIdentDef(c, name[1], skType) + s.typ = newTypeS(tyObject, c) + s.typ.sym = s + s.flags.incl sfForward + pkg.tab.strTableAdd s + addInterfaceDecl(c, s) + elif typsym.kind == skType and sfForward in typsym.flags: + s = typsym + addInterfaceDecl(c, s) + else: + localError(name.info, typsym.name.s & " is not a type that can be forwarded") + s = typsym + when false: + s = qualifiedLookUp(c, name, {checkUndeclared, checkModule}) + if s.kind != skType or + s.typ.skipTypes(abstractPtrs).kind != tyObject or + tfPartial notin s.typ.skipTypes(abstractPtrs).flags: + localError(name.info, "only .partial objects can be extended") else: s = semIdentDef(c, name, skType) s.typ = newTypeS(tyForward, c) s.typ.sym = s # process pragmas: if name.kind == nkPragmaExpr: pragma(c, s, name.sons[1], typePragmas) - if sfForward in s.flags: strTableAdd(c.graph.forwardedTypes, s) + if sfForward in s.flags: + # check if the symbol already exists: + let pkg = c.module.owner + if not isTopLevel(c) or pkg.isNil: + localError(name.info, "only top level types in a package can be 'forward'") + else: + let typsym = pkg.tab.strTableGet(s.name) + if typsym != nil: + typeCompleted(typsym) + s = typsym # add it here, so that recursive types are possible: if sfGenSym notin s.flags: addInterfaceDecl(c, s) + a.sons[0] = newSymNode(s) proc checkCovariantParamsUsages(genericType: PType) = diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 2d6817b06..19e182942 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -55,7 +55,7 @@ type wFloatchecks, wNanChecks, wInfChecks, wAssertions, wPatterns, wWarnings, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, - wDeadCodeElim, wSafecode, wForward, wNoForward, wReorder, wNoRewrite, + wDeadCodeElim, wSafecode, wPackage, wNoForward, wReorder, wNoRewrite, wPragma, wCompileTime, wNoInit, wPassc, wPassl, wBorrow, wDiscardable, @@ -143,7 +143,7 @@ const "assertions", "patterns", "warnings", "hints", "optimization", "raises", "writes", "reads", "size", "effects", "tags", - "deadcodeelim", "safecode", "forward", "noforward", "reorder", "norewrite", + "deadcodeelim", "safecode", "package", "noforward", "reorder", "norewrite", "pragma", "compiletime", "noinit", "passc", "passl", "borrow", "discardable", "fieldchecks", diff --git a/tests/misc/tupcomingfeatures.nim b/tests/misc/tupcomingfeatures.nim index cf07b06df..d37ce85cf 100644 --- a/tests/misc/tupcomingfeatures.nim +++ b/tests/misc/tupcomingfeatures.nim @@ -6,12 +6,8 @@ discard """ {.this: self.} type - Foo {.partial.} = object - a, b: int - -type - tupcomingfeatures.Foo = object - x: int + Foo = object + a, b, x: int proc yay(self: Foo) = echo a, " ", b, " ", x diff --git a/todo.txt b/todo.txt index 7c35b851d..b0ea449f4 100644 --- a/todo.txt +++ b/todo.txt @@ -23,7 +23,6 @@ Not critical for 1.0 - make '--implicitStatic:on' the default; then we can also clean up the 'static[T]' mess in the compiler! - ``not`` or ``~`` for the effects system -- document and stress test ``.partial`` object declarations - figure out why C++ bootstrapping is so much slower - The bitwise 'not' operator cold be renamed to 'bnot' to prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!