fixes #2590; methods now require a .base annotation
This commit is contained in:
parent
d2e4d6ad82
commit
dc047931bb
17 changed files with 69 additions and 32 deletions
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue