diff options
Diffstat (limited to 'compiler/sem.nim')
-rw-r--r-- | compiler/sem.nim | 440 |
1 files changed, 321 insertions, 119 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim index 6b3f0c80d..2cf93d365 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -10,28 +10,35 @@ # This module implements the semantic checking pass. import - ast, strutils, options, astalgo, trees, - wordrecg, ropes, msgs, idents, renderer, types, platform, math, + ast, options, astalgo, trees, + wordrecg, ropes, msgs, idents, renderer, types, platform, magicsys, nversion, nimsets, semfold, modulepaths, importer, - procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, - intsets, transf, vmdef, vm, aliases, cgmeth, lambdalifting, + procfind, lookups, pragmas, semdata, semtypinst, sigmatch, + transf, vmdef, vm, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - lowerings, plugins/active, lineinfos, strtabs, int128, - isolation_check, typeallowed, modulegraphs, enumtostr, concepts + lowerings, plugins/active, lineinfos, int128, + isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs, + extccomp -when defined(nimfix): - import nimfix/prettybase +import vtables +import std/[strtabs, math, tables, intsets, strutils, packedsets] when not defined(leanCompiler): import spawn +when defined(nimPreviewSlimSystem): + import std/[ + formatfloat, + assertions, + ] + # implementation -proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode -proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode +proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode +proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode proc semExprNoType(c: PContext, n: PNode): PNode proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode -proc semProcBody(c: PContext, n: PNode): PNode +proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode proc changeType(c: PContext; n: PNode, newType: PType, check: bool) @@ -48,7 +55,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode proc finishMethod(c: PContext, s: PSym) proc evalAtCompileTime(c: PContext, n: PNode): PNode proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode -proc semStaticExpr(c: PContext, n: PNode): PNode +proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType proc semTypeOf(c: PContext; n: PNode): PNode proc computeRequiresInit(c: PContext, t: PType): bool @@ -77,7 +84,8 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode; proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode = let x = arg.skipConv - if x.kind in {nkPar, nkTupleConstr, nkCurly} and formal.kind != tyUntyped: + if (x.kind == nkCurly and formal.kind == tySet and formal.base.kind != tyGenericParam) or + (x.kind in {nkPar, nkTupleConstr}) and formal.kind notin {tyUntyped, tyBuiltInTypeClass, tyAnything}: changeType(c, x, formal, check=true) result = arg result = skipHiddenSubConv(result, c.graph, c.idgen) @@ -90,6 +98,13 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = # error correction: result = copyTree(arg) result.typ = formal + elif arg.kind in nkSymChoices and formal.skipTypes(abstractInst).kind == tyEnum: + # Pick the right 'sym' from the sym choice by looking at 'formal' type: + result = nil + for ch in arg: + if sameType(ch.typ, formal): + return ch + typeMismatch(c.config, info, formal, arg.typ, arg) else: result = indexTypesMatch(c, formal, arg.typ, arg) if result == nil: @@ -100,6 +115,16 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = else: result = fitNodePostMatch(c, formal, result) +proc fitNodeConsiderViewType(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = + let a = fitNode(c, formal, arg, info) + if formal.kind in {tyVar, tyLent}: + #classifyViewType(formal) != noView: + result = newNodeIT(nkHiddenAddr, a.info, formal) + result.add a + formal.flags.incl tfVarIsPtr + else: + result = a + proc inferWithMetatype(c: PContext, formal: PType, arg: PNode, coerceDistincts = false): PNode @@ -119,26 +144,26 @@ proc commonType*(c: PContext; x, y: PType): PType = elif b.kind == tyTyped: result = b elif a.kind == tyTypeDesc: # turn any concrete typedesc into the abstract typedesc type - if a.len == 0: result = a + if not a.hasElementType: result = a else: - result = newType(tyTypeDesc, nextTypeId(c.idgen), a.owner) - rawAddSon(result, newType(tyNone, nextTypeId(c.idgen), a.owner)) + result = newType(tyTypeDesc, c.idgen, a.owner) + rawAddSon(result, newType(tyNone, c.idgen, a.owner)) elif b.kind in {tyArray, tySet, tySequence} and a.kind == b.kind: # check for seq[empty] vs. seq[int] let idx = ord(b.kind == tyArray) if a[idx].kind == tyEmpty: return y - elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len: - var nt: PType - for i in 0..<a.len: - let aEmpty = isEmptyContainer(a[i]) - let bEmpty = isEmptyContainer(b[i]) + elif a.kind == tyTuple and b.kind == tyTuple and sameTupleLengths(a, b): + var nt: PType = nil + for i, aa, bb in tupleTypePairs(a, b): + let aEmpty = isEmptyContainer(aa) + let bEmpty = isEmptyContainer(bb) if aEmpty != bEmpty: if nt.isNil: - nt = copyType(a, nextTypeId(c.idgen), a.owner) + nt = copyType(a, c.idgen, a.owner) copyTypeProps(c.graph, c.idgen.module, nt, a) - nt[i] = if aEmpty: b[i] else: a[i] + nt[i] = if aEmpty: bb else: aa if not nt.isNil: result = nt #elif b[idx].kind == tyEmpty: return x elif a.kind == tyRange and b.kind == tyRange: @@ -159,14 +184,20 @@ proc commonType*(c: PContext; x, y: PType): PType = result = b #.skipIntLit elif a.kind in IntegralTypes and a.n != nil: result = a #.skipIntLit + elif a.kind == tyProc and b.kind == tyProc: + if a.callConv == ccClosure and b.callConv != ccClosure: + result = x + elif compatibleEffects(a, b) != efCompat or + (b.flags * {tfNoSideEffect, tfGcSafe}) < (a.flags * {tfNoSideEffect, tfGcSafe}): + result = y else: var k = tyNone if a.kind in {tyRef, tyPtr}: k = a.kind if b.kind != a.kind: return x # bug #7601, array construction of ptr generic - a = a.lastSon.skipTypes({tyGenericInst}) - b = b.lastSon.skipTypes({tyGenericInst}) + a = a.elementType.skipTypes({tyGenericInst}) + b = b.elementType.skipTypes({tyGenericInst}) if a.kind == tyObject and b.kind == tyObject: result = commonSuperclass(a, b) # this will trigger an error later: @@ -176,16 +207,22 @@ proc commonType*(c: PContext; x, y: PType): PType = # ill-formed AST, no need for additional tyRef/tyPtr if k != tyNone and x.kind != tyGenericInst: let r = result - result = newType(k, nextTypeId(c.idgen), r.owner) + result = newType(k, c.idgen, r.owner) result.addSonSkipIntLit(r, c.idgen) -proc endsInNoReturn(n: PNode): bool = - # check if expr ends in raise exception or call of noreturn proc - var it = n - while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: - it = it.lastSon - result = it.kind in nkLastBlockStmts or - it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags +const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool} +proc shouldCheckCaseCovered(caseTyp: PType): bool = + result = false + case caseTyp.kind + of shouldChckCovered: + result = true + of tyRange: + if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered: + result = true + else: + discard + +proc endsInNoReturn(n: PNode): bool proc commonType*(c: PContext; x: PType, y: PNode): PType = # ignore exception raising branches in case/if expressions @@ -193,7 +230,7 @@ proc commonType*(c: PContext; x: PType, y: PNode): PType = commonType(c, x, y.typ) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info) when defined(nimsuggest): suggestDecl(c, n, result) @@ -216,7 +253,9 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # template; we must fix it here: see #909 result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info) + if find(result.name.s, '`') >= 0: + result.flags.incl sfWasGenSym #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) when defined(nimsuggest): @@ -226,7 +265,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym # identifier with visibility proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, - allowed: TSymFlags): PSym + allowed: TSymFlags, fromTopLevel = false): PSym proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind; flags: TTypeAllowedFlags = {}) = @@ -246,22 +285,12 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = typeAllowedCheck(c, typ.n.info, typ, skProc) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym -proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode +proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode proc semTemplateExpr(c: PContext, n: PNode, s: PSym, - flags: TExprFlags = {}): PNode + flags: TExprFlags = {}; expectedType: PType = nil): PNode proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, - flags: TExprFlags = {}): PNode - -proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym = - if t.sym != nil: return t.sym - result = newSym(skType, getIdent(c.cache, "AnonType"), nextSymId 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) + flags: TExprFlags = {}; expectedType: PType = nil): PNode when false: proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext = @@ -279,6 +308,7 @@ when false: result = isOpImpl(c, n) proc hasCycle(n: PNode): bool = + result = false incl n.flags, nfNone for i in 0..<n.safeLen: if nfNone in n[i].flags or hasCycle(n[i]): @@ -296,8 +326,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = result = evaluated let expectedType = eOrig.typ.skipTypes({tyStatic}) if hasCycle(result): - globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further") - result = errorNode(c, eOrig) + result = localErrorNode(c, eOrig, "the resulting AST is cyclic and cannot be processed further") else: semmacrosanity.annotateType(result, expectedType, c.config) else: @@ -312,8 +341,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = isArrayConstr(arg): arg.typ = eOrig.typ -proc tryConstExpr(c: PContext, n: PNode): PNode = - var e = semExprWithType(c, n) +proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode = + var e = semExprWithType(c, n, expectedType = expectedType) if e == nil: return result = getConstExpr(c.module, e, c.idgen, c.graph) @@ -326,6 +355,11 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = c.config.m.errorOutputs = {} c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here + when defined(nimsuggest): + # Remove the error hook so nimsuggest doesn't report errors there + let tempHook = c.graph.config.structuredErrorHook + c.graph.config.structuredErrorHook = nil + try: result = evalConstExpr(c.module, c.idgen, c.graph, e) if result == nil or result.kind == nkEmpty: @@ -336,6 +370,10 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = except ERecoverableError: result = nil + when defined(nimsuggest): + # Restore the error hook + c.graph.config.structuredErrorHook = tempHook + c.config.errorCounter = oldErrorCount c.config.errorMax = oldErrorMax c.config.m.errorOutputs = oldErrorOutputs @@ -343,11 +381,13 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = const errConstExprExpected = "constant expression expected" -proc semConstExpr(c: PContext, n: PNode): PNode = - var e = semExprWithType(c, n) +proc semConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode = + var e = semExprWithType(c, n, expectedType = expectedType) if e == nil: localError(c.config, n.info, errConstExprExpected) return n + if e.kind in nkSymChoices and e[0].typ.skipTypes(abstractInst).kind == tyEnum: + return e result = getConstExpr(c.module, e, c.idgen, c.graph) if result == nil: #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) @@ -364,32 +404,32 @@ proc semConstExpr(c: PContext, n: PNode): PNode = else: result = fixupTypeAfterEval(c, result, e) -proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode = +proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode = if efNeedStatic in flags: if efPreferNilResult in flags: - return tryConstExpr(c, n) + return tryConstExpr(c, n, expectedType) else: - return semConstExpr(c, n) + return semConstExpr(c, n, expectedType) else: - result = semExprWithType(c, n, flags) + result = semExprWithType(c, n, flags, expectedType) if efPreferStatic in flags: var evaluated = getConstExpr(c.module, result, c.idgen, c.graph) if evaluated != nil: return evaluated evaluated = evalAtCompileTime(c, result) if evaluated != nil: return evaluated -when not defined(nimHasSinkInference): - {.pragma: nosinks.} +proc semGenericStmt(c: PContext, n: PNode): PNode include hlo, seminst, semcall proc resetSemFlag(n: PNode) = - excl n.flags, nfSem - for i in 0..<n.safeLen: - resetSemFlag(n[i]) + if n != nil: + excl n.flags, nfSem + for i in 0..<n.safeLen: + resetSemFlag(n[i]) proc semAfterMacroCall(c: PContext, call, macroResult: PNode, - s: PSym, flags: TExprFlags): PNode = + s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode = ## Semantically check the output of a macro. ## This involves processes such as re-checking the macro output for type ## coherence, making sure that variables declared with 'let' aren't @@ -401,22 +441,22 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, c.friendModules.add(s.owner.getModule) result = macroResult resetSemFlag result - if s.typ[0] == nil: + if s.typ.returnType == nil: result = semStmt(c, result, flags) else: - var retType = s.typ[0] + var retType = s.typ.returnType if retType.kind == tyTypeDesc and tfUnresolved in retType.flags and - retType.len == 1: + retType.hasElementType: # bug #11941: template fails(T: type X, v: auto): T # does not mean we expect a tyTypeDesc. - retType = retType[0] + retType = retType.skipModifier case retType.kind - of tyUntyped: + of tyUntyped, tyAnything: # Not expecting a type here allows templates like in ``tmodulealias.in``. - result = semExpr(c, result, flags) + result = semExpr(c, result, flags, expectedType) of tyTyped: # More restrictive version. - result = semExprWithType(c, result, flags) + result = semExprWithType(c, result, flags, expectedType) of tyTypeDesc: if result.kind == nkStmtList: result.transitionSonsKind(nkStmtListType) var typ = semTypeNode(c, result, nil) @@ -433,25 +473,34 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, # e.g. template foo(T: typedesc): seq[T] # We will instantiate the return type here, because # we now know the supplied arguments - var paramTypes = newIdTable() + var paramTypes = initTypeMapping() for param, value in genericParamsInMacroCall(s, call): - idTablePut(paramTypes, param.typ, value.typ) + var givenType = value.typ + # the sym nodes used for the supplied generic arguments for + # templates and macros leave type nil so regular sem can handle it + # in this case, get the type directly from the sym + if givenType == nil and value.kind == nkSym and value.sym.typ != nil: + givenType = value.sym.typ + idTablePut(paramTypes, param.typ, givenType) retType = generateTypeInstance(c, paramTypes, macroResult.info, retType) - result = semExpr(c, result, flags) - result = fitNode(c, retType, result, result.info) - #globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0])) + if retType.kind == tyVoid: + result = semStmt(c, result, flags) + else: + result = semExpr(c, result, flags, expectedType) + result = fitNode(c, retType, result, result.info) + #globalError(s.info, errInvalidParamKindX, typeToString(s.typ.returnType)) dec(c.config.evalTemplateCounter) discard c.friendModules.pop() const errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters" - errFloatToString = "cannot convert '$1' to '$2'" proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, - flags: TExprFlags = {}): PNode = + flags: TExprFlags = {}; expectedType: PType = nil): PNode = + rememberExpansion(c, nOrig.info, sym) pushInfoContext(c.config, nOrig.info, sym.detailedInfo) let info = getCallLineInfo(n) @@ -470,7 +519,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, # c.evalContext = c.createEvalContext(emStatic) result = evalMacroCall(c.module, c.idgen, c.graph, c.templInstCounter, n, nOrig, sym) if efNoSemCheck notin flags: - result = semAfterMacroCall(c, n, result, sym, flags) + result = semAfterMacroCall(c, n, result, sym, flags, expectedType) if c.config.macrosToExpand.hasKey(sym.name.s): message(c.config, nOrig.info, hintExpandMacro, renderTree(result)) result = wrapInComesFrom(nOrig.info, sym, result) @@ -481,11 +530,9 @@ proc forceBool(c: PContext, n: PNode): PNode = if result == nil: result = n proc semConstBoolExpr(c: PContext, n: PNode): PNode = - result = forceBool(c, semConstExpr(c, n)) + result = forceBool(c, semConstExpr(c, n, getSysType(c.graph, n.info, tyBool))) if result.kind != nkIntLit: localError(c.config, n.info, errConstExprExpected) - -proc semGenericStmt(c: PContext, n: PNode): PNode proc semConceptBody(c: PContext, n: PNode): PNode include semtypes @@ -509,6 +556,147 @@ proc setGenericParamsMisc(c: PContext; n: PNode) = else: n[miscPos][1] = orig +proc caseBranchMatchesExpr(branch, matched: PNode): bool = + result = false + for i in 0 ..< branch.len-1: + if branch[i].kind == nkRange: + if overlap(branch[i], matched): return true + elif exprStructuralEquivalent(branch[i], matched): + return true + +proc pickCaseBranchIndex(caseExpr, matched: PNode): int = + result = 0 + let endsWithElse = caseExpr[^1].kind == nkElse + for i in 1..<caseExpr.len - endsWithElse.int: + if caseExpr[i].caseBranchMatchesExpr(matched): + return i + if endsWithElse: + return caseExpr.len - 1 + +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode +proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode + +const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink} + +proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, checkDefault: bool): seq[PNode] = + result = @[] + case recNode.kind + of nkRecList: + for field in recNode: + result.add defaultFieldsForTuple(c, field, hasDefault, checkDefault) + of nkSym: + let field = recNode.sym + let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) + if field.ast != nil: #Try to use default value + hasDefault = true + result.add newTree(nkExprColonExpr, recNode, field.ast) + else: + if recType.kind in {tyObject, tyArray, tyTuple}: + let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault) + if asgnExpr != nil: + hasDefault = true + asgnExpr.flags.incl nfSkipFieldChecking + result.add newTree(nkExprColonExpr, recNode, asgnExpr) + return + + let asgnType = newType(tyTypeDesc, c.idgen, recNode.typ.owner) + rawAddSon(asgnType, recNode.typ) + let asgnExpr = newTree(nkCall, + newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)), + newNodeIT(nkType, recNode.info, asgnType) + ) + asgnExpr.flags.incl nfSkipFieldChecking + asgnExpr.typ = recNode.typ + result.add newTree(nkExprColonExpr, recNode, asgnExpr) + else: + raiseAssert "unreachable" + +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] = + result = @[] + case recNode.kind + of nkRecList: + for field in recNode: + result.add defaultFieldsForTheUninitialized(c, field, checkDefault) + of nkRecCase: + let discriminator = recNode[0] + var selectedBranch: int + var defaultValue = discriminator.sym.ast + if defaultValue == nil: + # None of the branches were explicitly selected by the user and no value + # was given to the discrimator. We can assume that it will be initialized + # to zero and this will select a particular branch as a result: + if checkDefault: # don't add defaults when checking whether a case branch has default fields + return + defaultValue = newIntNode(nkIntLit#[c.graph]#, 0) + defaultValue.typ = discriminator.typ + selectedBranch = recNode.pickCaseBranchIndex defaultValue + defaultValue.flags.incl nfSkipFieldChecking + result.add newTree(nkExprColonExpr, discriminator, defaultValue) + result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1], checkDefault) + of nkSym: + let field = recNode.sym + let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) + if field.ast != nil: #Try to use default value + result.add newTree(nkExprColonExpr, recNode, field.ast) + elif recType.kind in {tyObject, tyArray, tyTuple}: + let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault) + if asgnExpr != nil: + asgnExpr.typ = recNode.typ + asgnExpr.flags.incl nfSkipFieldChecking + result.add newTree(nkExprColonExpr, recNode, asgnExpr) + else: + raiseAssert "unreachable" + +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode = + let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes) + case aTypSkip.kind + of tyObject: + let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault) + if child.len > 0: + var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp)) + asgnExpr.typ = aTyp + asgnExpr.sons.add child + result = semExpr(c, asgnExpr) + else: + result = nil + of tyArray: + let child = defaultNodeField(c, a, aTypSkip[1], checkDefault) + + if child != nil: + let node = newNode(nkIntLit) + node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip)) + result = semExpr(c, newTree(nkCall, newSymNode(getSysSym(c.graph, a.info, "arrayWith"), a.info), + semExprWithType(c, child), + node + )) + result.typ = aTyp + else: + result = nil + of tyTuple: + var hasDefault = false + if aTypSkip.n != nil: + let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault) + if hasDefault and children.len > 0: + result = newNodeI(nkTupleConstr, a.info) + result.typ = aTyp + result.sons.add children + result = semExpr(c, result) + else: + result = nil + else: + result = nil + of tyRange: + if c.graph.config.isDefined("nimPreviewRangeDefault"): + result = firstRange(c.config, aTypSkip) + else: + result = nil + else: + result = nil + +proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode = + result = defaultNodeField(c, a, a.typ, checkDefault) + include semtempl, semgnrc, semstmts, semexprs proc addCodeForGenerics(c: PContext, n: PNode) = @@ -521,53 +709,63 @@ proc addCodeForGenerics(c: PContext, n: PNode) = n.add prc.ast c.lastGenericIdx = c.generics.len -proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = - var c = newContext(graph, module) - c.idgen = idgen - c.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil) - - if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") - c.semConstExpr = semConstExpr - c.semExpr = semExpr - c.semTryExpr = tryExpr - c.semTryConstExpr = tryConstExpr - c.computeRequiresInit = computeRequiresInit - c.semOperand = semOperand - c.semConstBoolExpr = semConstBoolExpr - c.semOverloadedCall = semOverloadedCall - c.semInferredLambda = semInferredLambda - c.semGenerateInstance = generateInstance - c.semTypeNode = semTypeNode - c.instTypeBoundOp = sigmatch.instTypeBoundOp - c.hasUnresolvedArgs = hasUnresolvedArgs - c.templInstCounter = new int - - pushProcCon(c, module) - pushOwner(c, c.module) - - c.moduleScope = openScope(c) - c.moduleScope.addSym(module) # a module knows itself +proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PContext = + result = newContext(graph, module) + result.idgen = idgen + result.enforceVoidContext = newType(tyTyped, idgen, nil) + result.voidType = newType(tyVoid, idgen, nil) + + if result.p != nil: internalError(graph.config, module.info, "sem.preparePContext") + result.semConstExpr = semConstExpr + result.semExpr = semExpr + result.semExprWithType = semExprWithType + result.semTryExpr = tryExpr + result.semTryConstExpr = tryConstExpr + result.computeRequiresInit = computeRequiresInit + result.semOperand = semOperand + result.semConstBoolExpr = semConstBoolExpr + result.semOverloadedCall = semOverloadedCall + result.semInferredLambda = semInferredLambda + result.semGenerateInstance = generateInstance + result.instantiateOnlyProcType = instantiateOnlyProcType + result.semTypeNode = semTypeNode + result.instTypeBoundOp = sigmatch.instTypeBoundOp + result.hasUnresolvedArgs = hasUnresolvedArgs + result.templInstCounter = new int + + pushProcCon(result, module) + pushOwner(result, result.module) + + result.moduleScope = openScope(result) + result.moduleScope.addSym(module) # a module knows itself if sfSystemModule in module.flags: graph.systemModule = module - c.topLevelScope = openScope(c) - result = c + result.topLevelScope = openScope(result) proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool = if g.systemModule == nil: return false + var n = n + if n.kind == nkStmtList: + for i in 0..<n.len-1: + if n[i].kind notin {nkCommentStmt, nkEmpty}: + n = n[i] + break case n.kind of nkImportStmt: + result = false for x in n: if x.kind == nkIdent: let f = checkModuleName(g.config, x, false) if f == g.systemModule.info.fileIndex: return true of nkImportExceptStmt, nkFromStmt: + result = false if n[0].kind == nkIdent: let f = checkModuleName(g.config, n[0], false) if f == g.systemModule.info.fileIndex: return true - else: discard + else: result = false proc isEmptyTree(n: PNode): bool = case n.kind @@ -610,6 +808,13 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = if c.config.cmd == cmdIdeTools: appendToModule(c.module, result) trackStmt(c, c.module, result, isTopLevel = true) + if optMultiMethods notin c.config.globalOptions and + c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and + Feature.vtables in c.config.features: + sortVTableDispatchers(c.graph) + + if sfMainModule in c.module.flags: + collectVTableDispatchers(c.graph) proc recoverContext(c: PContext) = # clean up in case of a semantic error: We clean up the stacks, etc. This is @@ -619,8 +824,7 @@ proc recoverContext(c: PContext) = while getCurrOwner(c).kind != skModule: popOwner(c) while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next -proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = - var c = PContext(context) +proc semWithPContext*(c: PContext, n: PNode): PNode = # no need for an expensive 'try' if we stop after the first error anyway: if c.config.errorMax <= 1: result = semStmtAndGenerateGenerics(c, n) @@ -641,13 +845,14 @@ proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} = #if c.config.cmd == cmdIdeTools: findSuggest(c, n) storeRodNode(c, result) + proc reportUnusedModules(c: PContext) = + if c.config.cmd == cmdM: return for i in 0..high(c.unusedImports): if sfUsed notin c.unusedImports[i][0].flags: message(c.config, c.unusedImports[i][1], warnUnusedImportX, c.unusedImports[i][0].name.s) -proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = - var c = PContext(context) +proc closePContext*(graph: ModuleGraph; c: PContext, n: PNode): PNode = if c.config.cmd == cmdIdeTools and not c.suggestionsMade: suggestSentinel(c) closeScope(c) # close module's scope @@ -662,6 +867,3 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = popOwner(c) popProcCon(c) sealRodFile(c) - -const semPass* = makePass(myOpen, myProcess, myClose, - isFrontend = true) |