diff options
Diffstat (limited to 'compiler/semdata.nim')
-rw-r--r-- | compiler/semdata.nim | 472 |
1 files changed, 350 insertions, 122 deletions
diff --git a/compiler/semdata.nim b/compiler/semdata.nim index c858b6839..ca35ddc53 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -9,12 +9,16 @@ ## This module contains the data structures for the semantic checking phase. +import std/[tables, intsets, sets] + +when defined(nimPreviewSlimSystem): + import std/assertions + import - strutils, intsets, options, lexer, ast, astalgo, trees, treetab, - wordrecg, - ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, - magicsys, nversion, nimsets, parser, times, passes, vmdef, - modulegraphs, lineinfos + options, ast, astalgo, msgs, idents, renderer, + magicsys, vmdef, modulegraphs, lineinfos, pathutils + +import ic / ic type TOptionEntry* = object # entries to put on a stack for pragma parsing @@ -22,22 +26,24 @@ type defaultCC*: TCallingConvention dynlib*: PLib notes*: TNoteKinds + features*: set[Feature] otherPragmas*: PNode # every pragma can be pushed + warningAsErrors*: TNoteKinds POptionEntry* = ref TOptionEntry PProcCon* = ref TProcCon - TProcCon* = object # procedure context; also used for top-level - # statements + TProcCon* {.acyclic.} = object # procedure context; also used for top-level + # statements owner*: PSym # the symbol this context belongs to resultSym*: PSym # the result symbol (if we are in a proc) - selfSym*: PSym # the 'self' symbol (if available) nestedLoopCounter*: int # whether we are in a loop or not nestedBlockCounter*: int # whether we are in a block or not - inTryStmt*: int # whether we are in a try statement; works also - # in standalone ``except`` and ``finally`` + breakInLoop*: bool # whether we are in a loop without block next*: PProcCon # used for stacking procedure contexts - wasForwarded*: bool # whether the current proc has a separate header - mapping*: TIdTable + mappingExists*: bool + mapping*: Table[ItemId, PSym] + caseContext*: seq[tuple[n: PNode, idx: int]] + localBindStmts*: seq[PNode] TMatchedConcept* = object candidateType*: PType @@ -49,7 +55,7 @@ type inst*: PInstantiation TExprFlag* = enum - efLValue, efWantIterator, efInTypeof, + efLValue, efWantIterator, efWantIterable, efInTypeof, efNeedStatic, # Use this in contexts where a static value is mandatory efPreferStatic, @@ -62,57 +68,80 @@ type # you may be in position to supply a better error message # to the user. efWantStmt, efAllowStmt, efDetermineType, efExplain, - efAllowDestructor, efWantValue, efOperand, efNoSemCheck, - efNoEvaluateGeneric, efInCall, efFromHlo + efWantValue, efOperand, efNoSemCheck, + efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check, + efNoUndeclared, efIsDotCall, efCannotBeDotCall, + # Use this if undeclared identifiers should not raise an error during + # overload resolution. + efTypeAllowed # typeAllowed will be called after + efWantNoDefaults + efIgnoreDefaults # var statements without initialization + efAllowSymChoice # symchoice node should not be resolved TExprFlags* = set[TExprFlag] - TTypeAttachedOp* = enum - attachedAsgn, - attachedSink, - attachedDeepCopy, - attachedDestructor + ImportMode* = enum + importAll, importSet, importExcept + ImportedModule* = object + m*: PSym + case mode*: ImportMode + of importAll: discard + of importSet: + imported*: IntSet # of PIdent.id + of importExcept: + exceptSet*: IntSet # of PIdent.id PContext* = ref TContext - TContext* = object of TPassContext # a context represents a module + TContext* = object of TPassContext # a context represents the module + # that is currently being compiled enforceVoidContext*: PType + # for `if cond: stmt else: foo`, `foo` will be evaluated under + # enforceVoidContext != nil + voidType*: PType # for typeof(stmt) module*: PSym # the module sym belonging to the context currentScope*: PScope # current scope - importTable*: PScope # scope for all imported symbols + moduleScope*: PScope # scope for modules + imports*: seq[ImportedModule] # scope for all imported symbols topLevelScope*: PScope # scope for all top-level symbols p*: PProcCon # procedure context + intTypeCache*: array[-5..32, PType] # cache some common integer types + # to avoid type allocations + nilTypeCache*: PType matchedConcept*: ptr TMatchedConcept # the current concept being matched friendModules*: seq[PSym] # friend modules; may access private data; # this is used so that generic instantiations # can access private object fields instCounter*: int # to prevent endless instantiations - - ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot - # store this info in the syms themselves!) + templInstCounter*: ref int # gives every template instantiation a unique id inGenericContext*: int # > 0 if we are in a generic type inStaticContext*: int # > 0 if we are inside a static: block inUnrolledContext*: int # > 0 if we are unrolling a loop compilesContextId*: int # > 0 if we are in a ``compiles`` magic compilesContextIdGenerator*: int inGenericInst*: int # > 0 if we are instantiating a generic - converters*: TSymSeq # sequence of converters - patterns*: TSymSeq # sequence of pattern matchers + converters*: seq[PSym] + patterns*: seq[PSym] # sequence of pattern matchers optionStack*: seq[POptionEntry] - symMapping*: TIdTable # every gensym'ed symbol needs to be mapped - # to some new symbol in a generic instantiation libs*: seq[PLib] # all libs used by this module - semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas - semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} + semConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.} # for the pragmas + semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.} + semExprWithType*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.} semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} - semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} + semTryConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.} + computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.} + hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool + semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, - filter: TSymKinds, flags: TExprFlags): PNode {.nimcall.} + filter: TSymKinds, flags: TExprFlags, expectedType: PType = nil): PNode {.nimcall.} semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.} - semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode - semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable, + semInferredLambda*: proc(c: PContext, pt: Table[ItemId, PType], n: PNode): PNode + semGenerateInstance*: proc (c: PContext, fn: PSym, pt: Table[ItemId, PType], info: TLineInfo): PSym + instantiateOnlyProcType*: proc (c: PContext, pt: TypeMapping, + prc: PSym, info: TLineInfo): PType + # used by sigmatch for explicit generic instantiations includedFiles*: IntSet # used to detect recursive include files pureEnumFields*: TStrTable # pure enum fields that can be used unambiguously userPragmas*: TStrTable @@ -126,30 +155,78 @@ type inParallelStmt*: int instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo; op: TTypeAttachedOp; col: int): PSym {.nimcall.} - selfName*: PIdent cache*: IdentCache graph*: ModuleGraph signatures*: TStrTable recursiveDep*: string suggestionsMade*: bool + isAmbiguous*: bool # little hack features*: set[Feature] - inTypeContext*: int - typesWithOps*: seq[(PType, PType)] #\ - # We need to instantiate the type bound ops lazily after - # the generic type has been constructed completely. See - # tests/destructor/topttree.nim for an example that - # would otherwise fail. - runnableExamples*: PNode + inTypeContext*, inConceptDecl*: int + unusedImports*: seq[(PSym, TLineInfo)] + exportIndirections*: HashSet[(int, int)] # (module.id, symbol.id) + importModuleMap*: Table[int, int] # (module.id, module.id) + lastTLineInfo*: TLineInfo + sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index + inUncheckedAssignSection*: int + importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id]) + skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies. + inTypeofContext*: int + TBorrowState* = enum + bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch template config*(c: PContext): ConfigRef = c.graph.config +proc getIntLitType*(c: PContext; literal: PNode): PType = + # we cache some common integer literal types for performance: + let value = literal.intVal + if value >= low(c.intTypeCache) and value <= high(c.intTypeCache): + result = c.intTypeCache[value.int] + if result == nil: + let ti = getSysType(c.graph, literal.info, tyInt) + result = copyType(ti, c.idgen, ti.owner) + result.n = literal + c.intTypeCache[value.int] = result + else: + let ti = getSysType(c.graph, literal.info, tyInt) + result = copyType(ti, c.idgen, ti.owner) + result.n = literal + +proc setIntLitType*(c: PContext; result: PNode) = + let i = result.intVal + case c.config.target.intSize + of 8: result.typ = getIntLitType(c, result) + of 4: + if i >= low(int32) and i <= high(int32): + result.typ = getIntLitType(c, result) + else: + result.typ = getSysType(c.graph, result.info, tyInt64) + of 2: + if i >= low(int16) and i <= high(int16): + result.typ = getIntLitType(c, result) + elif i >= low(int32) and i <= high(int32): + result.typ = getSysType(c.graph, result.info, tyInt32) + else: + result.typ = getSysType(c.graph, result.info, tyInt64) + of 1: + # 8 bit CPUs are insane ... + if i >= low(int8) and i <= high(int8): + result.typ = getIntLitType(c, result) + elif i >= low(int16) and i <= high(int16): + result.typ = getSysType(c.graph, result.info, tyInt16) + elif i >= low(int32) and i <= high(int32): + result.typ = getSysType(c.graph, result.info, tyInt32) + else: + result.typ = getSysType(c.graph, result.info, tyInt64) + else: + internalError(c.config, result.info, "invalid int size") + proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = - result.genericSym = s - result.inst = inst + result = TInstantiationPair(genericSym: s, inst: inst) proc filename*(c: PContext): string = # the module's filename - return toFilename(c.config, FileIndex c.module.position) + result = toFilename(c.config, FileIndex c.module.position) proc scopeDepth*(c: PContext): int {.inline.} = result = if c.currentScope != nil: c.currentScope.depthLevel @@ -163,11 +240,10 @@ proc getCurrOwner*(c: PContext): PSym = result = c.graph.owners[^1] proc pushOwner*(c: PContext; owner: PSym) = - add(c.graph.owners, owner) + c.graph.owners.add(owner) proc popOwner*(c: PContext) = - var length = len(c.graph.owners) - if length > 0: setLen(c.graph.owners, length - 1) + if c.graph.owners.len > 0: setLen(c.graph.owners, c.graph.owners.len - 1) else: internalError(c.config, "popOwner") proc lastOptionEntry*(c: PContext): POptionEntry = @@ -176,13 +252,15 @@ proc lastOptionEntry*(c: PContext): POptionEntry = proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc put*(p: PProcCon; key, val: PSym) = - if p.mapping.data == nil: initIdTable(p.mapping) + if not p.mappingExists: + p.mapping = initTable[ItemId, PSym]() + p.mappingExists = true #echo "put into table ", key.info - p.mapping.idTablePut(key, val) + p.mapping[key.itemId] = val proc get*(p: PProcCon; key: PSym): PSym = - if p.mapping.data == nil: return nil - result = PSym(p.mapping.idTableGet(key)) + if not p.mappingExists: return nil + result = p.mapping.getOrDefault(key.itemId) proc getGenSym*(c: PContext; s: PSym): PSym = if sfGenSym notin s.flags: return s @@ -196,71 +274,138 @@ proc getGenSym*(c: PContext; s: PSym): PSym = result = s proc considerGenSyms*(c: PContext; n: PNode) = - if n.kind == nkSym: + if n == nil: + discard "can happen for nkFormalParams/nkArgList" + elif n.kind == nkSym: let s = getGenSym(c, n.sym) if n.sym != s: n.sym = s else: for i in 0..<n.safeLen: - considerGenSyms(c, n.sons[i]) + considerGenSyms(c, n[i]) proc newOptionEntry*(conf: ConfigRef): POptionEntry = new(result) result.options = conf.options - result.defaultCC = ccDefault + result.defaultCC = ccNimCall result.dynlib = nil result.notes = conf.notes + result.warningAsErrors = conf.warningAsErrors + +proc pushOptionEntry*(c: PContext): POptionEntry = + new(result) + var prev = c.optionStack[^1] + result.options = c.config.options + result.defaultCC = prev.defaultCC + result.dynlib = prev.dynlib + result.notes = c.config.notes + result.warningAsErrors = c.config.warningAsErrors + result.features = c.features + c.optionStack.add(result) + +proc popOptionEntry*(c: PContext) = + c.config.options = c.optionStack[^1].options + c.config.notes = c.optionStack[^1].notes + c.config.warningAsErrors = c.optionStack[^1].warningAsErrors + c.features = c.optionStack[^1].features + c.optionStack.setLen(c.optionStack.len - 1) proc newContext*(graph: ModuleGraph; module: PSym): PContext = new(result) - result.enforceVoidContext = PType(kind: tyStmt) - result.ambiguousSymbols = initIntSet() - result.optionStack = @[] + result.optionStack = @[newOptionEntry(graph.config)] result.libs = @[] - result.optionStack.add(newOptionEntry(graph.config)) result.module = module result.friendModules = @[module] result.converters = @[] result.patterns = @[] result.includedFiles = initIntSet() - initStrTable(result.pureEnumFields) - initStrTable(result.userPragmas) + result.pureEnumFields = initStrTable() + result.userPragmas = initStrTable() result.generics = @[] result.unknownIdents = initIntSet() result.cache = graph.cache result.graph = graph - initStrTable(result.signatures) - result.typesWithOps = @[] + result.signatures = initStrTable() result.features = graph.config.features - -proc inclSym(sq: var TSymSeq, s: PSym) = - var L = len(sq) - for i in countup(0, L - 1): - if sq[i].id == s.id: return - setLen(sq, L + 1) - sq[L] = s - -proc addConverter*(c: PContext, conv: PSym) = - inclSym(c.converters, conv) - -proc addPattern*(c: PContext, p: PSym) = - inclSym(c.patterns, p) + if graph.config.symbolFiles != disabledSf: + let id = module.position + if graph.config.cmd != cmdM: + assert graph.packed[id].status in {undefined, outdated} + graph.packed[id].status = storing + graph.packed[id].module = module + initEncoder graph, module + +template packedRepr*(c): untyped = c.graph.packed[c.module.position].fromDisk +template encoder*(c): untyped = c.graph.encoders[c.module.position] + +proc addIncludeFileDep*(c: PContext; f: FileIndex) = + if c.config.symbolFiles != disabledSf: + addIncludeFileDep(c.encoder, c.packedRepr, f) + +proc addImportFileDep*(c: PContext; f: FileIndex) = + if c.config.symbolFiles != disabledSf: + addImportFileDep(c.encoder, c.packedRepr, f) + +proc addPragmaComputation*(c: PContext; n: PNode) = + if c.config.symbolFiles != disabledSf: + addPragmaComputation(c.encoder, c.packedRepr, n) + +proc inclSym(sq: var seq[PSym], s: PSym): bool = + for i in 0..<sq.len: + if sq[i].id == s.id: return false + sq.add s + result = true + +proc addConverter*(c: PContext, conv: LazySym) = + assert conv.sym != nil + if inclSym(c.converters, conv.sym): + add(c.graph.ifaces[c.module.position].converters, conv) + +proc addConverterDef*(c: PContext, conv: LazySym) = + addConverter(c, conv) + if c.config.symbolFiles != disabledSf: + addConverter(c.encoder, c.packedRepr, conv.sym) + +proc addPureEnum*(c: PContext, e: LazySym) = + assert e.sym != nil + add(c.graph.ifaces[c.module.position].pureEnums, e) + if c.config.symbolFiles != disabledSf: + addPureEnum(c.encoder, c.packedRepr, e.sym) + +proc addPattern*(c: PContext, p: LazySym) = + assert p.sym != nil + if inclSym(c.patterns, p.sym): + add(c.graph.ifaces[c.module.position].patterns, p) + if c.config.symbolFiles != disabledSf: + addTrmacro(c.encoder, c.packedRepr, p.sym) + +proc exportSym*(c: PContext; s: PSym) = + strTableAdds(c.graph, c.module, s) + if c.config.symbolFiles != disabledSf: + addExported(c.encoder, c.packedRepr, s) + +proc reexportSym*(c: PContext; s: PSym) = + strTableAdds(c.graph, c.module, s) + if c.config.symbolFiles != disabledSf: + addReexport(c.encoder, c.packedRepr, s) proc newLib*(kind: TLibKind): PLib = new(result) - result.kind = kind #initObjectSet(result.syms) + result.kind = kind #result.syms = initObjectSet() proc addToLib*(lib: PLib, sym: PSym) = #if sym.annex != nil and not isGenericRoutine(sym): # LocalError(sym.info, errInvalidPragma) sym.annex = lib -proc newTypeS*(kind: TTypeKind, c: PContext): PType = - result = newType(kind, getCurrOwner(c)) +proc newTypeS*(kind: TTypeKind; c: PContext; son: sink PType = nil): PType = + result = newType(kind, c.idgen, getCurrOwner(c), son = son) + +proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType = + result = newType(tyPtr, idgen, owner, skipIntLit(baseType, idgen)) proc makePtrType*(c: PContext, baseType: PType): PType = - result = newTypeS(tyPtr, c) - addSonSkipIntLit(result, baseType) + makePtrType(getCurrOwner(c), baseType, c.idgen) proc makeTypeWithModifier*(c: PContext, modifier: TTypeKind, @@ -270,65 +415,62 @@ proc makeTypeWithModifier*(c: PContext, if modifier in {tyVar, tyLent, tyTypeDesc} and baseType.kind == modifier: result = baseType else: - result = newTypeS(modifier, c) - addSonSkipIntLit(result, baseType) + result = newTypeS(modifier, c, skipIntLit(baseType, c.idgen)) proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType = if baseType.kind == kind: result = baseType else: - result = newTypeS(kind, c) - addSonSkipIntLit(result, baseType) - -proc makeTypeDesc*(c: PContext, typ: PType): PType = - if typ.kind == tyTypeDesc: - result = typ - else: - result = newTypeS(tyTypeDesc, c) - result.addSonSkipIntLit(typ) + result = newTypeS(kind, c, skipIntLit(baseType, c.idgen)) proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = - let typedesc = makeTypeDesc(c, typ) - let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info, + let typedesc = newTypeS(tyTypeDesc, c) + incl typedesc.flags, tfCheckedForDestructor + internalAssert(c.config, typ != nil) + typedesc.addSonSkipIntLit(typ, c.idgen) + let sym = newSym(skType, c.cache.idAnon, c.idgen, getCurrOwner(c), info, c.config.options).linkTo(typedesc) - return newSymNode(sym, info) + result = newSymNode(sym, info) proc makeTypeFromExpr*(c: PContext, n: PNode): PType = result = newTypeS(tyFromExpr, c) assert n != nil result.n = n -proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]): PType = - result = newType(kind, owner) - result.sons = sons +when false: + proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]; + idgen: IdGenerator): PType = + result = newType(kind, idgen, owner, sons = sons) -proc newTypeWithSons*(c: PContext, kind: TTypeKind, - sons: seq[PType]): PType = - result = newType(kind, getCurrOwner(c)) - result.sons = sons + proc newTypeWithSons*(c: PContext, kind: TTypeKind, + sons: seq[PType]): PType = + result = newType(kind, c.idgen, getCurrOwner(c), sons = sons) proc makeStaticExpr*(c: PContext, n: PNode): PNode = result = newNodeI(nkStaticExpr, n.info) result.sons = @[n] result.typ = if n.typ != nil and n.typ.kind == tyStatic: n.typ - else: newTypeWithSons(c, tyStatic, @[n.typ]) + else: newTypeS(tyStatic, c, n.typ) proc makeAndType*(c: PContext, t1, t2: PType): PType = result = newTypeS(tyAnd, c) - result.sons = @[t1, t2] + result.rawAddSon t1 + result.rawAddSon t2 propagateToOwner(result, t1) propagateToOwner(result, t2) result.flags.incl((t1.flags + t2.flags) * {tfHasStatic}) result.flags.incl tfHasMeta proc makeOrType*(c: PContext, t1, t2: PType): PType = - result = newTypeS(tyOr, c) if t1.kind != tyOr and t2.kind != tyOr: - result.sons = @[t1, t2] + result = newTypeS(tyOr, c) + result.rawAddSon t1 + result.rawAddSon t2 else: + result = newTypeS(tyOr, c) template addOr(t1) = if t1.kind == tyOr: - for x in t1.sons: result.rawAddSon x + for x in t1.kids: result.rawAddSon x else: result.rawAddSon t1 addOr(t1) @@ -339,26 +481,22 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType = result.flags.incl tfHasMeta proc makeNotType*(c: PContext, t1: PType): PType = - result = newTypeS(tyNot, c) - result.sons = @[t1] + result = newTypeS(tyNot, c, son = t1) propagateToOwner(result, t1) result.flags.incl(t1.flags * {tfHasStatic}) result.flags.incl tfHasMeta proc nMinusOne(c: PContext; n: PNode): PNode = - result = newNode(nkCall, n.info, @[ - newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n]) + result = newTreeI(nkCall, n.info, newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n) # Remember to fix the procs below this one when you make changes! proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType = let intType = getSysType(c.graph, n.info, tyInt) - result = newTypeS(tyRange, c) - result.sons = @[intType] + result = newTypeS(tyRange, c, son = intType) if n.typ != nil and n.typ.n == nil: result.flags.incl tfUnresolved - result.n = newNode(nkRange, n.info, @[ - newIntTypeNode(nkIntLit, 0, intType), - makeStaticExpr(c, nMinusOne(c, n))]) + result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType), + makeStaticExpr(c, nMinusOne(c, n))) template rangeHasUnresolvedStatic*(t: PType): bool = tfUnresolved in t.flags @@ -366,11 +504,31 @@ template rangeHasUnresolvedStatic*(t: PType): bool = proc errorType*(c: PContext): PType = ## creates a type representing an error state result = newTypeS(tyError, c) + result.flags.incl tfCheckedForDestructor proc errorNode*(c: PContext, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) result.typ = errorType(c) +# These mimic localError +template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode = + liMessage(c.config, info, msg, arg, doNothing, instLoc()) + errorNode(c, n) + +template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, arg: string): PNode = + liMessage(c.config, info, errGenerated, arg, doNothing, instLoc()) + errorNode(c, n) + +template localErrorNode*(c: PContext, n: PNode, msg: TMsgKind, arg: string): PNode = + let n2 = n + liMessage(c.config, n2.info, msg, arg, doNothing, instLoc()) + errorNode(c, n2) + +template localErrorNode*(c: PContext, n: PNode, arg: string): PNode = + let n2 = n + liMessage(c.config, n2.info, errGenerated, arg, doNothing, instLoc()) + errorNode(c, n2) + proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind dest.owner = getCurrOwner(c) @@ -380,11 +538,32 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt; info: TLineInfo; intType: PType = nil): PType = let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt) var n = newNodeI(nkRange, info) - addSon(n, newIntTypeNode(nkIntLit, first, intType)) - addSon(n, newIntTypeNode(nkIntLit, last, intType)) + n.add newIntTypeNode(first, intType) + n.add newIntTypeNode(last, intType) result = newTypeS(tyRange, c) result.n = n - addSonSkipIntLit(result, intType) # basetype of range + addSonSkipIntLit(result, intType, c.idgen) # basetype of range + +proc isSelf*(t: PType): bool {.inline.} = + ## Is this the magical 'Self' type from concepts? + t.kind == tyTypeDesc and tfPacked in t.flags + +proc makeTypeDesc*(c: PContext, typ: PType): PType = + if typ.kind == tyTypeDesc and not isSelf(typ): + result = typ + else: + result = newTypeS(tyTypeDesc, c, skipIntLit(typ, c.idgen)) + incl result.flags, tfCheckedForDestructor + +proc symFromType*(c: PContext; t: PType, info: TLineInfo): PSym = + if t.sym != nil: return t.sym + result = newSym(skType, getIdent(c.cache, "AnonType"), c.idgen, t.owner, info) + result.flags.incl sfAnon + result.typ = t + +proc symNodeFromType*(c: PContext, t: PType, info: TLineInfo): PNode = + result = newSymNode(symFromType(c, t, info), info) + result.typ = makeTypeDesc(c, t) proc markIndirect*(c: PContext, s: PSym) {.inline.} = if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}: @@ -398,10 +577,59 @@ proc illFormedAstLocal*(n: PNode; conf: ConfigRef) = localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) = - if sonsLen(n) != length: illFormedAst(n, conf) + if n.len != length: illFormedAst(n, conf) proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) = - if sonsLen(n) < length: illFormedAst(n, conf) + if n.len < length: illFormedAst(n, conf) proc isTopLevel*(c: PContext): bool {.inline.} = result = c.currentScope.depthLevel <= 2 + +proc isTopLevelInsideDeclaration*(c: PContext, sym: PSym): bool {.inline.} = + # for routeKinds the scope isn't closed yet: + c.currentScope.depthLevel <= 2 + ord(sym.kind in routineKinds) + +proc pushCaseContext*(c: PContext, caseNode: PNode) = + c.p.caseContext.add((caseNode, 0)) + +proc popCaseContext*(c: PContext) = + discard pop(c.p.caseContext) + +proc setCaseContextIdx*(c: PContext, idx: int) = + c.p.caseContext[^1].idx = idx + +template addExport*(c: PContext; s: PSym) = + ## convenience to export a symbol from the current module + addExport(c.graph, c.module, s) + +proc storeRodNode*(c: PContext, n: PNode) = + if c.config.symbolFiles != disabledSf: + toPackedNodeTopLevel(n, c.encoder, c.packedRepr) + +proc addToGenericProcCache*(c: PContext; s: PSym; inst: PInstantiation) = + c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add LazyInstantiation(module: c.module.position, inst: inst) + if c.config.symbolFiles != disabledSf: + storeInstantiation(c.encoder, c.packedRepr, s, inst) + +proc addToGenericCache*(c: PContext; s: PSym; inst: PType) = + c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add LazyType(typ: inst) + if c.config.symbolFiles != disabledSf: + storeTypeInst(c.encoder, c.packedRepr, s, inst) + +proc sealRodFile*(c: PContext) = + if c.config.symbolFiles != disabledSf: + if c.graph.vm != nil: + for (m, n) in PCtx(c.graph.vm).vmstateDiff: + if m == c.module: + addPragmaComputation(c, n) + c.idgen.sealed = true # no further additions are allowed + +proc rememberExpansion*(c: PContext; info: TLineInfo; expandedSym: PSym) = + ## Templates and macros are very special in Nim; these have + ## inlining semantics so after semantic checking they leave no trace + ## in the sem'checked AST. This is very bad for IDE-like tooling + ## ("find all usages of this template" would not work). We need special + ## logic to remember macro/template expansions. This is done here and + ## delegated to the "rod" file mechanism. + if c.config.symbolFiles != disabledSf: + storeExpansion(c.encoder, c.packedRepr, info, expandedSym) |