Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental typeImports #8660

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions compiler/importer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ proc rawImportSymbol(c: PContext, s: PSym) =
if s.kind == skConverter: addConverter(c, s)
if hasPattern(s): addPattern(c, s)

proc maybeImportForType(c: PContext, s: PSym, t: PType) =
## Imports a symbol only if it has a strict relation with a type:
##
## - Proc refers to the type on any of its input or output values.
##
## TODO: generics are not matched currently.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this should be done though. Requires a bit more code, will show you how to do that later.

##
case s.kind
of skProcKinds:
for tt in s.typ.sons.items:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: shall I avoid using iterators in the compiler code? maybe they are not as efficient as countup loops?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to avoid them, they are zero-cost.

if t == tt:
rawImportSymbol(c, s)
break
else:
discard

proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
let ident = lookups.considerQuotedIdent(c, n)
let s = strTableGet(fromMod.tab, ident)
Expand All @@ -88,6 +104,19 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
rawImportSymbol(c, e)
e = nextIdentIter(it, fromMod.tab)

of skType:
# import the type as expected
rawImportSymbol(c, s)

# types can bring attached their related symbols too
if typeImports in c.features:
var i: TTabIter
var ss = initTabIter(i, fromMod.tab)
while ss != nil:
maybeImportForType(c, ss, s.typ)
ss = nextIter(i, fromMod.tab)

else: rawImportSymbol(c, s)

proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
Expand Down
3 changes: 2 additions & 1 deletion compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ type
notnil,
dynamicBindSym,
forLoopMacros,
caseStmtMacros
caseStmtMacros,
typeImports

SymbolFilesOption* = enum
disabledSf, writeOnlySf, readOnlySf, v2Sf
Expand Down
18 changes: 18 additions & 0 deletions doc/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6333,6 +6333,24 @@ It's also possible to use ``from module import nil`` if one wants to import
the module but wants to enforce fully qualified access to every symbol
in ``module``.

By using the experimental feature ``typeImports`` it's possible to bring
all the symbols directly related to a type. Any callable that has the imported
type as one of its arguments or return type gets automatically included with the
import.

.. code-block:: nim
:test: "nim c $1"

{.experimental: "typeImports".}

from colors import Color

# to string and proc imported
let pink = rgb(255, 192, 203)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this example shows that it's not enough the type is the return type of rgb.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, I don't understand, could you rephrase?

Maybe it should demonstrate what's going on more explicitly let pink: Color = rgb(255, 192, 203)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that rgb should not be imported implicitly as the connection to Color is invisible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, yeah, you're right. I implemented it initially without taking into account the return type but it forced to include the factory function from m import T, initT which I found a pity... and then it occurred to me that one very simple way to teach this is:

Automatically include any symbol that references the imported type on its signature

I think it balances for the implicity on factories, specially since many times it's kind of obvious that they are creating the type.

echo $pink
# color constants are not imported though, this would fail:
# echo $colBlue


Export statement
~~~~~~~~~~~~~~~~
Expand Down
11 changes: 11 additions & 0 deletions tests/modules/ttypeimport.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
discard """
output: "#FFC0CB"
"""

{.experimental: "typeImports".}

from colors import Color

# to string and proc imported
let pink = rgb(255, 192, 203)
echo $pink
11 changes: 11 additions & 0 deletions tests/modules/ttypeimportfail.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
discard """
file: "ttypeimportfail.nim"
errormsg: "undeclared identifier: 'colBlue'"
"""

{.experimental: "typeImports".}

from colors import Color

# constants of the type not imported
discard colBlue