diff options
-rw-r--r-- | compiler/ast.nim | 1 | ||||
-rw-r--r-- | compiler/cgmeth.nim | 35 | ||||
-rw-r--r-- | compiler/msgs.nim | 4 | ||||
-rw-r--r-- | compiler/pragmas.nim | 5 | ||||
-rw-r--r-- | compiler/wordrecg.nim | 5 | ||||
-rw-r--r-- | doc/manual/procs.txt | 9 | ||||
-rw-r--r-- | tests/method/mmultim3.nim | 2 | ||||
-rw-r--r-- | tests/method/temptybody.nim | 2 | ||||
-rw-r--r-- | tests/method/tmethods1.nim | 6 | ||||
-rw-r--r-- | tests/method/tmproto.nim | 2 | ||||
-rw-r--r-- | tests/method/tmultim1.nim | 2 | ||||
-rw-r--r-- | tests/method/tmultim2.nim | 2 | ||||
-rw-r--r-- | tests/method/tmultim4.nim | 2 | ||||
-rw-r--r-- | tests/method/tmultim6.nim | 2 | ||||
-rw-r--r-- | tests/method/trecmeth.nim | 8 | ||||
-rw-r--r-- | todo.txt | 1 | ||||
-rw-r--r-- | web/news.txt | 13 |
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 ------------------ |