summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/cgmeth.nim35
-rw-r--r--compiler/msgs.nim4
-rw-r--r--compiler/pragmas.nim5
-rw-r--r--compiler/wordrecg.nim5
-rw-r--r--doc/manual/procs.txt9
-rw-r--r--tests/method/mmultim3.nim2
-rw-r--r--tests/method/temptybody.nim2
-rw-r--r--tests/method/tmethods1.nim6
-rw-r--r--tests/method/tmproto.nim2
-rw-r--r--tests/method/tmultim1.nim2
-rw-r--r--tests/method/tmultim2.nim2
-rw-r--r--tests/method/tmultim4.nim2
-rw-r--r--tests/method/tmultim6.nim2
-rw-r--r--tests/method/trecmeth.nim8
-rw-r--r--todo.txt1
-rw-r--r--web/news.txt13
17 files changed, 69 insertions, 32 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index aafe503dc..177b5c5c7 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -297,6 +297,7 @@ const
   sfGoto* = sfOverriden               # var is used for 'goto' code generation
   sfWrittenTo* = sfBorrow             # param is assigned to
   sfEscapes* = sfProcvar              # param escapes
+  sfBase* = sfDiscriminant
 
 const
   # getting ready for the future expr/stmt merge
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index adb4f1f92..d2358b84a 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -47,8 +47,10 @@ proc methodCall*(n: PNode): PNode =
 var
   gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[]
 
-proc sameMethodBucket(a, b: PSym): bool =
-  result = false
+type
+  MethodResult = enum No, Invalid, Yes
+
+proc sameMethodBucket(a, b: PSym): MethodResult =
   if a.name.id != b.name.id: return
   if sonsLen(a.typ) != sonsLen(b.typ):
     return                    # check for return type:
@@ -64,13 +66,15 @@ proc sameMethodBucket(a, b: PSym): bool =
         bb = bb.lastSon
       else:
         break
-    if sameType(aa, bb) or
-        (aa.kind == tyObject) and (bb.kind == tyObject) and
-        (inheritanceDiff(bb, aa) < 0):
-      discard
+    if sameType(aa, bb): discard
+    elif aa.kind == tyObject and bb.kind == tyObject:
+      let diff = inheritanceDiff(bb, aa)
+      if diff < 0: discard "Ok"
+      elif diff != high(int):
+        result = Invalid
     else:
-      return
-  result = true
+      return No
+  if result != Invalid: result = Yes
 
 proc attachDispatcher(s: PSym, dispatcher: PNode) =
   var L = s.ast.len-1
@@ -133,18 +137,31 @@ proc fixupDispatcher(meth, disp: PSym) =
 
 proc methodDef*(s: PSym, fromCache: bool) =
   var L = len(gMethods)
+  var witness: PSym
   for i in countup(0, L - 1):
     var disp = gMethods[i].dispatcher
-    if sameMethodBucket(disp, s):
+    case sameMethodBucket(disp, s)
+    of Yes:
       add(gMethods[i].methods, s)
       attachDispatcher(s, lastSon(disp.ast))
       fixupDispatcher(s, disp)
       when useEffectSystem: checkMethodEffects(disp, s)
+      if sfBase in s.flags and gMethods[i].methods[0] != s:
+        # already exists due to forwarding definition?
+        localError(s.info, "method is not a base")
       return
+    of No: discard
+    of Invalid:
+      if witness.isNil: witness = gMethods[i].methods[0]
   # create a new dispatcher:
   add(gMethods, (methods: @[s], dispatcher: createDispatcher(s)))
   if fromCache:
     internalError(s.info, "no method dispatcher found")
+  if witness != nil:
+    localError(s.info, "invalid declaration order; cannot attach '" & s.name.s &
+                       "' to method defined here: " & $witness.info)
+  elif sfBase notin s.flags:
+    message(s.info, warnUseBase)
 
 proc relevantCol(methods: TSymSeq, col: int): bool =
   # returns true iff the position is relevant
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 1b1f0a76e..c815e0277 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -118,7 +118,7 @@ type
     warnUnknownSubstitutionX, warnLanguageXNotSupported,
     warnFieldXNotSupported, warnCommentXIgnored,
     warnNilStatement, warnTypelessParam,
-    warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
+    warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
     warnEachIdentIsTuple, warnShadowIdent,
     warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
     warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
@@ -391,7 +391,7 @@ const
     warnCommentXIgnored: "comment \'$1\' ignored",
     warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead",
     warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
-    warnDifferentHeaps: "possible inconsistency of thread local heaps",
+    warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
     warnWriteToForeignHeap: "write to foreign heap",
     warnUnsafeCode: "unsafe code: '$1'",
     warnEachIdentIsTuple: "each identifier is a tuple",
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 5f317ed24..1c51251fe 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -27,7 +27,7 @@ const
     wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
     wOverride, wConstructor}
   converterPragmas* = procPragmas
-  methodPragmas* = procPragmas
+  methodPragmas* = procPragmas+{wBase}
   templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
     wDelegator}
   macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
@@ -867,6 +867,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           localError(it.info, "'experimental' pragma only valid as toplevel statement")
       of wNoRewrite:
         noVal(it)
+      of wBase:
+        noVal(it)
+        sym.flags.incl sfBase
       else: invalidPragma(it)
     else: invalidPragma(it)
 
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index deb12536f..23f012ea5 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -45,7 +45,7 @@ type
     wImportc, wExportc, wIncompleteStruct, wRequiresInit,
     wAlign, wNodecl, wPure, wSideeffect, wHeader,
     wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
-    wCompilerproc, wProcVar,
+    wCompilerproc, wProcVar, wBase,
     wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
     wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
     wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
@@ -128,7 +128,8 @@ const
     "importcompilerproc", "importc", "exportc", "incompletestruct",
     "requiresinit", "align", "nodecl", "pure", "sideeffect",
     "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
-    "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
+    "compilerproc", "procvar", "base",
+    "fatal", "error", "warning", "hint", "line",
     "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
     "link", "compile", "linksys", "deprecated", "varargs",
     "callconv", "breakpoint", "debugger", "nimcall", "stdcall",
diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt
index bd86e4651..9d00b7e3c 100644
--- a/doc/manual/procs.txt
+++ b/doc/manual/procs.txt
@@ -385,7 +385,7 @@ dispatch.
     PlusExpr = ref object of Expression
       a, b: Expression
 
-  method eval(e: Expression): int =
+  method eval(e: Expression): int {.base.} =
     # override this base method
     quit "to override!"
 
@@ -410,6 +410,11 @@ In the example the constructors ``newLit`` and ``newPlus`` are procs
 because they should use static binding, but ``eval`` is a method because it
 requires dynamic binding.
 
+As can be seen in the example, base methods have to be annotated with
+the `base`:idx: pragma. The ``base`` pragma also acts as a reminder for the
+programmer that a base method ``m`` is used as the foundation to determine all
+the effects that a call to ``m`` might cause.
+
 In a multi-method all parameters that have an object type are used for the
 dispatching:
 
@@ -419,7 +424,7 @@ dispatching:
     Unit = ref object of Thing
       x: int
 
-  method collide(a, b: Thing) {.inline.} =
+  method collide(a, b: Thing) {.base, inline.} =
     quit "to override!"
 
   method collide(a: Thing, b: Unit) {.inline.} =
diff --git a/tests/method/mmultim3.nim b/tests/method/mmultim3.nim
index 3139a8089..b391731be 100644
--- a/tests/method/mmultim3.nim
+++ b/tests/method/mmultim3.nim
@@ -3,7 +3,7 @@ type
 
 var myObj* : ref TObj
 
-method test123(a : ref TObj) =
+method test123(a : ref TObj) {.base.} =
     echo("Hi base!")
 
 proc testMyObj*() =
diff --git a/tests/method/temptybody.nim b/tests/method/temptybody.nim
index 26285d05b..aad945f81 100644
--- a/tests/method/temptybody.nim
+++ b/tests/method/temptybody.nim
@@ -2,7 +2,7 @@
 
 type MyClass = ref object of RootObj
 
-method HelloWorld*(obj: MyClass) =
+method HelloWorld*(obj: MyClass) {.base.} =
   when defined(myPragma):
     echo("Hello World")
   # discard # with this line enabled it works
diff --git a/tests/method/tmethods1.nim b/tests/method/tmethods1.nim
index 461e2cb5e..cb4da5ef2 100644
--- a/tests/method/tmethods1.nim
+++ b/tests/method/tmethods1.nim
@@ -2,7 +2,7 @@ discard """
   output: "do nothing"
 """
 
-method somethin(obj: TObject) =
+method somethin(obj: RootObj) {.base.} =
   echo "do nothing"
 
 type
@@ -14,9 +14,9 @@ type
   TSomethingElse = object
   PSomethingElse = ref TSomethingElse
 
-method foo(a: PNode, b: PSomethingElse) = discard
+method foo(a: PNode, b: PSomethingElse) {.base.} = discard
 method foo(a: PNodeFoo, b: PSomethingElse) = discard
 
-var o: TObject
+var o: RootObj
 o.somethin()
 
diff --git a/tests/method/tmproto.nim b/tests/method/tmproto.nim
index 5d75cff1a..087666ea0 100644
--- a/tests/method/tmproto.nim
+++ b/tests/method/tmproto.nim
@@ -2,7 +2,7 @@ type
   Obj1 = ref object {.inheritable.}
   Obj2 = ref object of Obj1
 
-method beta(x: Obj1): int
+method beta(x: Obj1): int {.base.}
 
 proc delta(x: Obj2): int =
   beta(x)
diff --git a/tests/method/tmultim1.nim b/tests/method/tmultim1.nim
index c7027f4c0..010468a5b 100644
--- a/tests/method/tmultim1.nim
+++ b/tests/method/tmultim1.nim
@@ -11,7 +11,7 @@ type
   PlusExpr = ref object of Expression
     a, b: Expression
 
-method eval(e: Expression): int = quit "to override!"
+method eval(e: Expression): int {.base.} = quit "to override!"
 method eval(e: Literal): int = return e.x
 method eval(e: PlusExpr): int = return eval(e.a) + eval(e.b)
 
diff --git a/tests/method/tmultim2.nim b/tests/method/tmultim2.nim
index e695dd19b..98a08b1cb 100644
--- a/tests/method/tmultim2.nim
+++ b/tests/method/tmultim2.nim
@@ -14,7 +14,7 @@ type
   TParticle = object of TThing
     a, b: int
 
-method collide(a, b: TThing) {.inline.} =
+method collide(a, b: TThing) {.base, inline.} =
   echo "collide: thing, thing"
 
 method collide(a: TThing, b: TUnit) {.inline.} =
diff --git a/tests/method/tmultim4.nim b/tests/method/tmultim4.nim
index 54630fb41..eabf8d126 100644
--- a/tests/method/tmultim4.nim
+++ b/tests/method/tmultim4.nim
@@ -5,7 +5,7 @@ discard """
 type
   Test = object of TObject
 
-method doMethod(a: ref TObject) {.raises: [EIO].} =
+method doMethod(a: ref TObject) {.base, raises: [EIO].} =
   quit "override"
 
 method doMethod(a: ref Test) =
diff --git a/tests/method/tmultim6.nim b/tests/method/tmultim6.nim
index 6c21f80d2..97ed2845c 100644
--- a/tests/method/tmultim6.nim
+++ b/tests/method/tmultim6.nim
@@ -10,7 +10,7 @@ type
   TParticle = object of TThing
     a, b: int
 
-method collide(a, b: TThing) {.inline.} =
+method collide(a, b: TThing) {.base, inline.} =
   quit "to override!"
 
 method collide[T](a: TThing, b: TUnit[T]) {.inline.} =
diff --git a/tests/method/trecmeth.nim b/tests/method/trecmeth.nim
index 32f620f15..ac0a1e977 100644
--- a/tests/method/trecmeth.nim
+++ b/tests/method/trecmeth.nim
@@ -2,12 +2,12 @@
 # for recursive methods works, no code is being executed
 
 type
-  Obj = ref object of TObject
+  Obj = ref object of RootObj
 
 # Mutual recursion
 
-method alpha(x: Obj)
-method beta(x: Obj)
+method alpha(x: Obj) {.base.}
+method beta(x: Obj) {.base.}
 
 method alpha(x: Obj) =
   beta(x)
@@ -17,6 +17,6 @@ method beta(x: Obj) =
 
 # Simple recursion
 
-method gamma(x: Obj) =
+method gamma(x: Obj) {.base.} =
   gamma(x)
 
diff --git a/todo.txt b/todo.txt
index 66a9d1f0f..1160000b0 100644
--- a/todo.txt
+++ b/todo.txt
@@ -13,7 +13,6 @@ version 0.11.4
 
 - add "all threads are blocked" detection to 'spawn'
 - Deprecate ``immediate`` for templates and macros
-- make people annotate .anchor methods
 
 
 version 1.0
diff --git a/web/news.txt b/web/news.txt
index 823a10dfa..80983d33d 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -50,6 +50,9 @@ News
     and are now deprecated and will be removed from the language. Instead you
     have to insert type conversions
     like ``(proc (a, b: int) {.closure.})(myToplevelProc)`` if necessary.
+  - The modules ``libffi``, ``sdl``, ``windows``, ``zipfiles``, ``libzip``,
+    ``zlib``, ``zzip``, ``dialogs``, ``expat``, ``graphics``, ``libcurl``,
+    ``sphinx`` have been moved out of the stdlib and are Nimble packages now.
   - The constant fights between 32 and 64 bit DLLs on Windows have been put to
     an end: The standard distribution now ships with 32 and 64 bit versions
     of all the DLLs the standard library needs. This means that the following
@@ -66,9 +69,11 @@ News
     was previously. Macros that generate nkPar nodes when object is expected are
     likely to break. Macros that expect nkPar nodes to which objects are passed
     are likely to break as well.
+  - Base methods now need to be annotated with the ``base`` pragma. This makes
+    multi methods less error-prone to use with the effect system.
 
 
-  Library additions
+  Library Additions
   -----------------
 
   - The nre module has been added, providing a better interface to PCRE than re.
@@ -81,6 +86,12 @@ News
     locale anymore and now take an optional ``decimalSep = '.'`` parameter.
 
 
+  Compiler Additions
+  ------------------
+
+  - The compiler now supports a new configuration system based on ``NimScript``.
+
+
   Language Additions
   ------------------