# # # The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module implements code generation for methods. import options, ast, msgs, idents, renderer, types, magicsys, sempass2, modulegraphs, lineinfos, astalgo import std/intsets when defined(nimPreviewSlimSystem): import std/assertions import std/[tables] proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode = var dest = skipTypes(d, abstractPtrs) var source = skipTypes(n.typ, abstractPtrs) if (source.kind == tyObject) and (dest.kind == tyObject): var diff = inheritanceDiff(dest, source) if diff == high(int): # no subtype relation, nothing to do result = n elif diff < 0: result = newNodeIT(nkObjUpConv, n.info, d) result.add n if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed") elif diff > 0: result = newNodeIT(nkObjDownConv, n.info, d) result.add n if not downcast: internalError(conf, n.info, "cgmeth.genConv: no downcast allowed") else: result = n else: result = n proc getDispatcher*(s: PSym): PSym = ## can return nil if is has no dispatcher. if dispatcherPos < s.ast.len: result = s.ast[dispatcherPos].sym doAssert sfDispatcher in result.flags else: result = nil proc methodCall*(n: PNode; conf: ConfigRef): PNode = result = n # replace ordinary method by dispatcher method: let disp = getDispatcher(result[0].sym) if disp != nil: result[0].typ = disp.typ result[0].sym = disp # change the arguments to up/downcasts to fit the dispatcher's parameters: for i in 1.. resultPos: disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen) else: # We've encountered a method prototype without a filled-in # resultPos slot. We put a placeholder in there that will # be updated in fixupDispatcher(). disp.ast.add newNodeI(nkEmpty, s.info) attachDispatcher(s, newSymNode(disp)) # attach to itself to prevent bugs: attachDispatcher(disp, newSymNode(disp)) return disp proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) = # We may have constructed the dispatcher from a method prototype # and need to augment the incomplete dispatcher with information # from later definitions, particularly the resultPos slot. Also, # the lock level of the dispatcher needs to be updated/checked # against that of the method. if disp.ast.len > resultPos and meth.ast.len > resultPos and disp.ast[resultPos].kind == nkEmpty: disp.ast[resultPos] = copyTree(meth.ast[resultPos]) proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) = var witness: PSym = nil if s.typ.firstParamType.owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"): localError(g.config, s.info, errGenerated, "method `" & s.name.s & "` can be defined only in the same module with its type (" & s.typ.firstParamType.typeToString() & ")") if sfImportc in s.flags: localError(g.config, s.info, errGenerated, "method `" & s.name.s & "` is not allowed to have 'importc' pragmas") for i in 0.. n: break while true: h = h div 3 for i in h..= 0: a[j] = a[j - h] j = j - h if j < h: break a[j] = v if h == 1: break proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym = var base = methods[0].ast[dispatcherPos].sym result = base var paramLen = base.typ.signatureLen var nilchecks = newNodeI(nkStmtList, base.info) var disp = newNodeI(nkIfStmt, base.info) var ands = getSysMagic(g, unknownLineInfo, "and", mAnd) var iss = getSysMagic(g, unknownLineInfo, "of", mOf) let boolType = getSysType(g, unknownLineInfo, tyBool) for col in FirstParamAt..