new feature: package level objects

This commit is contained in:
Andreas Rumpf
2017-10-29 07:54:39 +01:00
parent 7889692523
commit c17f6c7837
9 changed files with 93 additions and 11 deletions

View File

@@ -16,3 +16,7 @@
module.
- The overloading rules changed slightly so that constrained generics are
preferred over unconstrained generics. (Bug #6526)
- It is now possible to forward declare object types so that mutually
recursive types can be created across module boundaries. See
[package level objects](https://nim-lang.org/docs/manual.html#package-level-objects)
for more information.

View File

@@ -981,7 +981,10 @@ proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
if sonsLen(typ) > 0 and typ.lastSon != nil:
var x = typ.lastSon
if typ.kind == tyObject: x = x.skipTypes(skipPtrs)
base = genTypeInfo(m, x, info)
if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x):
base = rope("0")
else:
base = genTypeInfo(m, x, info)
else:
base = rope("0")
genTypeInfoAuxBase(m, typ, origType, name, base, info)

View File

@@ -796,12 +796,6 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
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)
@@ -812,11 +806,16 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
# 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'")
localError(name.info, "only top level types in a package can be 'package'")
else:
let typsym = pkg.tab.strTableGet(s.name)
if typsym != nil:
typeCompleted(typsym)
if sfForward notin typsym.flags or sfNoForward notin typsym.flags:
typeCompleted(typsym)
typsym.info = s.info
else:
localError(name.info, "cannot complete type '" & s.name.s & "' twice; " &
"previous type completion was here: " & $typsym.info)
s = typsym
# add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s)

View File

@@ -698,6 +698,44 @@ branch switch ``system.reset`` has to be used. Also, when the fields of a
particular branch are specified during object construction, the correct value
for the discriminator must be supplied at compile-time.
Package level objects
---------------------
Every Nim module resides in a (nimble) package. An object type can be attached
to the package it resides in. If that is done, the type can be referenced from
other modules as an `incomplete`:idx: object type. This features allows to
break up recursive type dependencies accross module boundaries. Incomplete
object types are always passed ``byref`` and can only be used in pointer like
contexts (``var/ref/ptr IncompleteObject``) in general since the compiler does
not yet know the size of the object. To complete an incomplete object
the ``package`` pragma has to be used. ``package`` implies ``byref``.
As long as a type ``T`` is incomplete ``sizeof(T)`` or "runtime type
information" for ``T`` is not available.
Example:
.. code-block:: nim
# module A (in an arbitrary package)
type
Pack.SomeObject = object ## declare as incomplete object of package 'Pack'
Triple = object
a, b, c: ref SomeObject ## pointers to incomplete objects are allowed
## Incomplete objects can be used as parameters:
proc myproc(x: SomeObject) = discard
.. code-block:: nim
# module B (in package "Pack")
type
SomeObject* {.package.} = object ## Use 'package' to complete the object
s, t: string
x, y: int
Set type
--------

View File

@@ -0,0 +1,3 @@
type
Foo* {.package.} = object
x, y: int

View File

@@ -0,0 +1,16 @@
discard """
output: '''@[(x: 3, y: 4)]'''
"""
type
mypackage.Foo = object
Other = proc (inp: Foo)
import definefoo
# after this import, Foo is a completely resolved type, so
# we can create a sequence of it:
var s: seq[Foo] = @[]
s.add Foo(x: 3, y: 4)
echo s

View File

@@ -0,0 +1,19 @@
discard """
output: '''compiles'''
"""
# Test that the object type does not need to be resolved at all:
type
mypackage.Foo = object
Other = proc (inp: Foo)
Node = ref object
external: ptr Foo
data: string
var x: Node
new(x)
x.data = "compiles"
echo x.data

View File

@@ -1,8 +1,8 @@
version 1.0 battle plan
=======================
- implement a way to forward object type declarations across module
boundaries; C++ style
- make nimresolve part of the Nim compiler and add support for
'import staticExec()'
- deprecate unary '<'
- remove 'mod x' type rule
- implement x[^1] differently, no compiler magic