summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/options.nim3
-rw-r--r--compiler/pragmas.nim23
-rw-r--r--compiler/sighashes.nim12
-rw-r--r--doc/manual.rst154
-rw-r--r--lib/system/hti.nim12
-rw-r--r--tests/ccgbugs/t8964.nim10
-rw-r--r--tests/misc/tnoforward.nim3
-rw-r--r--tests/modules/treorder.nim3
-rw-r--r--tests/pragmas/treorder.nim5
9 files changed, 152 insertions, 73 deletions
diff --git a/compiler/options.nim b/compiler/options.nim
index 02f284676..a95d9930a 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -121,7 +121,8 @@ type
     notnil,
     dynamicBindSym,
     forLoopMacros,
-    caseStmtMacros
+    caseStmtMacros,
+    codeReordering,
 
   SymbolFilesOption* = enum
     disabledSf, writeOnlySf, readOnlySf, v2Sf
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index e6e4eff38..b8dae8123 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -231,8 +231,17 @@ proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
   else: resOptions = resOptions - op
 
 proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
-  if isTurnedOn(c, n): incl(c.module.flags, flag)
-  else: excl(c.module.flags, flag)
+  if isTurnedOn(c, n):
+    incl(c.module.flags, flag)
+    c.features.incl codeReordering
+  else:
+    excl(c.module.flags, flag)
+    # c.features.excl codeReordering
+
+  # deprecated as of 0.18.1
+  message(c.config, n.info, warnDeprecated,
+          "use {.experimental: \"codeReordering.\".} instead; " &
+          (if flag == sfNoForward: "{.noForward.}" else: "{.reorder.}"))
 
 proc processCallConv(c: PContext, n: PNode) =
   if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
@@ -351,7 +360,13 @@ proc processExperimental(c: PContext; n: PNode) =
     case n[1].kind
     of nkStrLit, nkRStrLit, nkTripleStrLit:
       try:
-        c.features.incl parseEnum[Feature](n[1].strVal)
+        let feature = parseEnum[Feature](n[1].strVal)
+        c.features.incl feature
+        if feature == codeReordering:
+          if not isTopLevel(c):
+              localError(c.config, n.info,
+                         "Code reordering experimental pragma only valid at toplevel")
+          c.module.flags.incl sfReorder
       except ValueError:
         localError(c.config, n[1].info, "unknown experimental feature")
     else:
@@ -817,7 +832,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         incl(sym.flags, {sfThread, sfGlobal})
       of wDeadCodeElimUnused: discard  # deprecated, dead code elim always on
       of wNoForward: pragmaNoForward(c, it)
-      of wReorder: pragmaNoForward(c, it, sfReorder)
+      of wReorder: pragmaNoForward(c, it, flag = sfReorder)
       of wMagic: processMagic(c, it, sym)
       of wCompileTime:
         noVal(c, it)
diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim
index 222a0d66e..218011b1d 100644
--- a/compiler/sighashes.nim
+++ b/compiler/sighashes.nim
@@ -68,6 +68,8 @@ else:
     toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
   proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
   proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1)
+  proc `&=`(c: var MD5Context, r: Rope) =
+    for l in leaves(r): md5Update(c, l, l.len)
   proc `&=`(c: var MD5Context, i: BiggestInt) =
     md5Update(c, cast[cstring](unsafeAddr i), sizeof(i))
 
@@ -185,11 +187,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
     # Every cyclic type in Nim need to be constructed via some 't.sym', so this
     # is actually safe without an infinite recursion check:
     if t.sym != nil:
-      #if "Future:" in t.sym.name.s and t.typeInst == nil:
-      #  writeStackTrace()
-      #  echo "yes ", t.sym.name.s
-      #  #quit 1
-      if CoOwnerSig in flags:
+      if {sfCompilerProc} * t.sym.flags != {}:
+        doAssert t.sym.loc.r != nil
+        # The user has set a specific name for this type
+        c &= t.sym.loc.r
+      elif CoOwnerSig in flags:
         c.hashTypeSym(t.sym)
       else:
         c.hashSym(t.sym)
diff --git a/doc/manual.rst b/doc/manual.rst
index 6dc6794f1..7946e88dd 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -6534,6 +6534,111 @@ iterator in which case the overloading resolution takes place:
   var x = 4
   write(stdout, x) # not ambiguous: uses the module C's x
 
+Code reordering
+~~~~~~~~~~~~~~~
+
+**Note**: Code reordering is experimental and must be enabled via the
+``{.experimental.}`` pragma.
+
+The code reordering feature can implicitly rearrange procedure, template, and
+macro definitions along with variable declarations and initializations at the top
+level scope so that, to a large extent, a programmer should not have to worry
+about ordering definitions correctly or be forced to use forward declarations to
+preface definitions inside a module.
+
+..
+   NOTE: The following was documentation for the code reordering precursor,
+   which was {.noForward.}.
+   
+   In this mode, procedure definitions may appear out of order and the compiler
+   will postpone their semantic analysis and compilation until it actually needs
+   to generate code using the definitions. In this regard, this mode is similar
+   to the modus operandi of dynamic scripting languages, where the function
+   calls are not resolved until the code is executed. Here is the detailed
+   algorithm taken by the compiler:
+
+   1. When a callable symbol is first encountered, the compiler will only note
+   the symbol callable name and it will add it to the appropriate overload set
+   in the current scope. At this step, it won't try to resolve any of the type
+   expressions used in the signature of the symbol (so they can refer to other
+   not yet defined symbols).
+
+   2. When a top level call is encountered (usually at the very end of the
+   module), the compiler will try to determine the actual types of all of the
+   symbols in the matching overload set. This is a potentially recursive process
+   as the signatures of the symbols may include other call expressions, whose
+   types will be resolved at this point too.
+
+   3. Finally, after the best overload is picked, the compiler will start
+   compiling the body of the respective symbol. This in turn will lead the
+   compiler to discover more call expressions that need to be resolved and steps
+   2 and 3 will be repeated as necessary.
+
+   Please note that if a callable symbol is never used in this scenario, its
+   body will never be compiled. This is the default behavior leading to best
+   compilation times, but if exhaustive compilation of all definitions is
+   required, using ``nim check`` provides this option as well.
+
+Example:
+
+.. code-block:: nim
+
+  {.experimental: "codeReordering".}
+
+  proc foo(x: int) =
+    bar(x)
+
+  proc bar(x: int) =
+    echo(x)
+
+  foo(10)
+
+Variables can also be reordered as well. Variables that are *initialized* (i.e.
+variables that have their declaration and assignment combined in a single
+statement) can have their entire initialization statement reordered. Be wary of
+what code is executed at the top level:
+
+.. code-block:: nim
+  {.experimental: "codeReordering".}
+
+  proc a() =
+    echo(foo)
+
+  var foo = 5
+
+  a() # outputs: "5"
+
+..
+   TODO: Let's table this for now. This is an *experimental feature* and so the
+   specific manner in which ``declared`` operates with it can be decided in
+   eventuality, because right now it works a bit weirdly.
+
+   The values of expressions involving ``declared`` are decided *before* the
+   code reordering process, and not after. As an example, the output of this
+   code is the same as it would be with code reordering disabled.
+
+   .. code-block:: nim
+     {.experimental: "codeReordering".}
+
+     proc x() =
+       echo(declared(foo))
+
+     var foo = 4
+
+     x() # "false"
+
+It is important to note that reordering *only* works for symbols at top level
+scope. Therefore, the following will *fail to compile:*
+
+.. code-block:: nim
+  {.experimental: "codeReordering".}
+
+  proc a() =
+    b()
+    proc b() =
+      echo("Hello!")
+
+  a()
 
 Compiler Messages
 =================
@@ -6943,55 +7048,6 @@ the created global variables within a module is not defined, but all of them
 will be initialized after any top-level variables in their originating module
 and before any variable in a module that imports it.
 
-
-..
-  NoForward pragma
-  ----------------
-  The ``noforward`` pragma can be used to turn on and off a special compilation
-  mode that to large extent eliminates the need for forward declarations. In this
-  mode, the proc definitions may appear out of order and the compiler will postpone
-  their semantic analysis and compilation until it actually needs to generate code
-  using the definitions. In this regard, this mode is similar to the modus operandi
-  of dynamic scripting languages, where the function calls are not resolved until
-  the code is executed. Here is the detailed algorithm taken by the compiler:
-
-  1. When a callable symbol is first encountered, the compiler will only note the
-  symbol callable name and it will add it to the appropriate overload set in the
-  current scope. At this step, it won't try to resolve any of the type expressions
-  used in the signature of the symbol (so they can refer to other not yet defined
-  symbols).
-
-  2. When a top level call is encountered (usually at the very end of the module),
-  the compiler will try to determine the actual types of all of the symbols in the
-  matching overload set. This is a potentially recursive process as the signatures
-  of the symbols may include other call expressions, whose types will be resolved
-  at this point too.
-
-  3. Finally, after the best overload is picked, the compiler will start
-  compiling the body of the respective symbol. This in turn will lead the
-  compiler to discover more call expressions that need to be resolved and steps
-  2 and 3 will be repeated as necessary.
-
-  Please note that if a callable symbol is never used in this scenario, its body
-  will never be compiled. This is the default behavior leading to best compilation
-  times, but if exhaustive compilation of all definitions is required, using
-  ``nim check`` provides this option as well.
-
-  Example:
-
-  .. code-block:: nim
-
-    {.noforward: on.}
-
-    proc foo(x: int) =
-      bar x
-
-    proc bar(x: int) =
-      echo x
-
-    foo(10)
-
-
 pragma pragma
 -------------
 
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
index 9931fa11e..c7b52bbdf 100644
--- a/lib/system/hti.nim
+++ b/lib/system/hti.nim
@@ -7,12 +7,6 @@
 #    distribution, for details about the copyright.
 #
 
-when declared(ThisIsSystem):
-  # we are in system module:
-  {.pragma: codegenType, compilerproc.}
-else:
-  {.pragma: codegenType.}
-
 type
   # This should be the same as ast.TTypeKind
   # many enum fields are not used at runtime
@@ -79,7 +73,7 @@ type
     tyVoidHidden
 
   TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
-  TNimNode {.codegenType.} = object
+  TNimNode {.compilerProc.} = object
     kind: TNimNodeKind
     offset: int
     typ: ptr TNimType
@@ -92,7 +86,7 @@ type
     ntfAcyclic = 1,    # type cannot form a cycle
     ntfEnumHole = 2    # enum has holes and thus `$` for them needs the slow
                        # version
-  TNimType {.codegenType.} = object
+  TNimType {.compilerProc.} = object
     size: int
     kind: TNimKind
     flags: set[TNimTypeFlag]
@@ -109,6 +103,6 @@ type
   PNimType = ptr TNimType
 
 when defined(nimTypeNames):
-  var nimTypeRoot {.codegenType.}: PNimType
+  var nimTypeRoot {.compilerProc.}: PNimType
 
 # node.len may be the ``first`` element of a set
diff --git a/tests/ccgbugs/t8964.nim b/tests/ccgbugs/t8964.nim
new file mode 100644
index 000000000..5b41e8bdb
--- /dev/null
+++ b/tests/ccgbugs/t8964.nim
@@ -0,0 +1,10 @@
+discard """
+  targets: "c cpp"
+"""
+
+from json import JsonParsingError
+import marshal
+
+const nothing = ""
+doAssertRaises(JsonParsingError):
+  var bar = marshal.to[int](nothing)
diff --git a/tests/misc/tnoforward.nim b/tests/misc/tnoforward.nim
index 342e757b8..3e96e3489 100644
--- a/tests/misc/tnoforward.nim
+++ b/tests/misc/tnoforward.nim
@@ -2,7 +2,8 @@ discard """
   disabled: true
 """
 
-{. noforward: on .}
+# {. noforward: on .}
+{.experimental: "codeReordering".}
 
 proc foo(x: int) =
   bar x
diff --git a/tests/modules/treorder.nim b/tests/modules/treorder.nim
index 8715e4548..c81715cd8 100644
--- a/tests/modules/treorder.nim
+++ b/tests/modules/treorder.nim
@@ -6,8 +6,7 @@ defined
 3'''
 """
 
-{.reorder: on.}
-{.experimental.}
+{.experimental: "codeReordering".}
 
 proc bar(x: T)
 
diff --git a/tests/pragmas/treorder.nim b/tests/pragmas/treorder.nim
index 1006af527..659a6f644 100644
--- a/tests/pragmas/treorder.nim
+++ b/tests/pragmas/treorder.nim
@@ -6,7 +6,8 @@ output:'''0
 """
 
 import macros
-{.reorder: on .}
+# {.reorder: on .}
+{.experimental: "codeReordering".}
 
 echo foo(-1)
 echo callWithFoo(0)
@@ -71,4 +72,4 @@ macro make(arg: untyped): untyped =
 proc first(i: int): void =
   make(second)
 
-var ss {.compileTime.}: string = ""
\ No newline at end of file
+var ss {.compileTime.}: string = ""