mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 22:10:33 +00:00
new feature: package level objects
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
3
tests/package_level_objects/definefoo.nim
Normal file
3
tests/package_level_objects/definefoo.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
type
|
||||
Foo* {.package.} = object
|
||||
x, y: int
|
||||
0
tests/package_level_objects/mypackage.nimble
Normal file
0
tests/package_level_objects/mypackage.nimble
Normal file
16
tests/package_level_objects/tusefoo.nim
Normal file
16
tests/package_level_objects/tusefoo.nim
Normal 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
|
||||
19
tests/package_level_objects/tusefoo2.nim
Normal file
19
tests/package_level_objects/tusefoo2.nim
Normal 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
|
||||
4
todo.txt
4
todo.txt
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user