mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-18 08:58:39 +00:00
fixes #2590; methods now require a .base annotation
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.} =
|
||||
|
||||
@@ -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*() =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.} =
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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.} =
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
1
todo.txt
1
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
|
||||
|
||||
13
web/news.txt
13
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
|
||||
------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user