diff options
Diffstat (limited to 'compiler/semgnrc.nim')
-rw-r--r-- | compiler/semgnrc.nim | 591 |
1 files changed, 382 insertions, 209 deletions
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index cc03db1c2..2639aba6c 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -19,8 +19,8 @@ proc getIdentNode(c: PContext; n: PNode): PNode = case n.kind - of nkPostfix: result = getIdentNode(c, n.sons[1]) - of nkPragmaExpr: result = getIdentNode(c, n.sons[0]) + of nkPostfix: result = getIdentNode(c, n[1]) + of nkPragmaExpr: result = getIdentNode(c, n[0]) of nkIdent, nkAccQuoted, nkSym: result = n else: illFormedAst(n, c.config) @@ -28,13 +28,16 @@ proc getIdentNode(c: PContext; n: PNode): PNode = type GenericCtx = object - toMixin: IntSet + toMixin, toBind: IntSet cursorInBody: bool # only for nimsuggest bracketExpr: PNode -type TSemGenericFlag = enum - withinBind, withinTypeDesc, withinMixin, withinConcept + withinBind, + withinTypeDesc, + withinMixin, + withinConcept + TSemGenericFlags = set[TSemGenericFlag] proc semGenericStmt(c: PContext, n: PNode, @@ -47,120 +50,214 @@ proc semGenericStmtScope(c: PContext, n: PNode, result = semGenericStmt(c, n, flags, ctx) closeScope(c) -template macroToExpand(s): untyped = - s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags) +template isMixedIn(sym): bool = + let s = sym + s.name.id in ctx.toMixin or (withinConcept in flags and + s.magic == mNone and + s.kind in OverloadableSyms) -template macroToExpandSym(s): untyped = - s.kind in {skMacro, skTemplate} and (s.typ.len == 1) and not fromDotExpr +template canOpenSym(s): bool = + {withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, - ctx: var GenericCtx; fromDotExpr=false): PNode = + ctx: var GenericCtx; flags: TSemGenericFlags, + isAmbiguous: bool, + fromDotExpr=false): PNode = + result = nil semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody) incl(s.flags, sfUsed) + template maybeDotChoice(c: PContext, n: PNode, s: PSym, fromDotExpr: bool) = + if fromDotExpr: + result = symChoice(c, n, s, scForceOpen) + if result.kind == nkOpenSymChoice and result.len == 1: + result.transitionSonsKind(nkClosedSymChoice) + else: + result = symChoice(c, n, s, scOpen) + if canOpenSym(s): + if openSym in c.features: + if result.kind == nkSym: + result = newOpenSym(result) + else: + result.typ = nil + else: + result.flags.incl nfDisabledOpenSym + result.typ = nil case s.kind of skUnknown: # Introduced in this pass! Leave it as an identifier. result = n - of skProc, skFunc, skMethod, skIterator, skConverter, skModule: - result = symChoice(c, n, s, scOpen) - of skTemplate: - if macroToExpandSym(s): - styleCheckUse(n.info, s) - result = semTemplateExpr(c, n, s, {efNoSemCheck}) - result = semGenericStmt(c, result, {}, ctx) - else: - result = symChoice(c, n, s, scOpen) - of skMacro: - if macroToExpandSym(s): - styleCheckUse(n.info, s) - result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + of skProc, skFunc, skMethod, skIterator, skConverter, skModule, skEnumField: + maybeDotChoice(c, n, s, fromDotExpr) + of skTemplate, skMacro: + # alias syntax, see semSym for skTemplate, skMacro + if sfNoalias notin s.flags and not fromDotExpr: + onUse(n.info, s) + case s.kind + of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck}) + of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + else: discard # unreachable + c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, {}, ctx) + discard c.friendModules.pop() else: - result = symChoice(c, n, s, scOpen) + maybeDotChoice(c, n, s, fromDotExpr) of skGenericParam: if s.typ != nil and s.typ.kind == tyStatic: if s.typ.n != nil: result = s.typ.n + elif c.inGenericContext > 0 and withinConcept notin flags: + # don't leave generic param as identifier node in generic type, + # sigmatch will try to instantiate generic type AST without all params + # fine to give a symbol node a generic type here since + # we are in a generic context and `prepareNode` will be called + result = newSymNodeTypeDesc(s, c.idgen, n.info) + if canOpenSym(result.sym): + if openSym in c.features: + result = newOpenSym(result) + else: + result.flags.incl nfDisabledOpenSym + result.typ = nil else: result = n else: - result = newSymNodeTypeDesc(s, n.info) - styleCheckUse(n.info, s) + result = newSymNodeTypeDesc(s, c.idgen, n.info) + if canOpenSym(result.sym): + if openSym in c.features: + result = newOpenSym(result) + else: + result.flags.incl nfDisabledOpenSym + result.typ = nil + onUse(n.info, s) of skParam: result = n - styleCheckUse(n.info, s) + onUse(n.info, s) of skType: if (s.typ != nil) and (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}): - result = newSymNodeTypeDesc(s, n.info) + if isAmbiguous: + # ambiguous types should be symchoices since lookup behaves + # differently for them in regular expressions + maybeDotChoice(c, n, s, fromDotExpr) + return + result = newSymNodeTypeDesc(s, c.idgen, n.info) + if canOpenSym(result.sym): + if openSym in c.features: + result = newOpenSym(result) + else: + result.flags.incl nfDisabledOpenSym + result.typ = nil + elif c.inGenericContext > 0 and withinConcept notin flags: + # don't leave generic param as identifier node in generic type, + # sigmatch will try to instantiate generic type AST without all params + # fine to give a symbol node a generic type here since + # we are in a generic context and `prepareNode` will be called + result = newSymNodeTypeDesc(s, c.idgen, n.info) + if canOpenSym(result.sym): + if openSym in c.features: + result = newOpenSym(result) + else: + result.flags.incl nfDisabledOpenSym + result.typ = nil else: result = n - styleCheckUse(n.info, s) + onUse(n.info, s) else: result = newSymNode(s, n.info) - styleCheckUse(n.info, s) + if canOpenSym(result.sym): + if openSym in c.features: + result = newOpenSym(result) + else: + result.flags.incl nfDisabledOpenSym + result.typ = nil + onUse(n.info, s) proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = result = n let ident = considerQuotedIdent(c, n) - var s = searchInScopes(c, ident).skipAlias(n, c.config) + var amb = false + var s = searchInScopes(c, ident, amb) if s == nil: s = strTableGet(c.pureEnumFields, ident) - if s != nil and contains(c.ambiguousSymbols, s.id): - s = nil + #if s != nil and contains(c.ambiguousSymbols, s.id): + # s = nil if s == nil: if ident.id notin ctx.toMixin and withinMixin notin flags: errorUndeclaredIdentifier(c, n.info, ident.s) else: - if withinBind in flags: + if withinBind in flags or s.id in ctx.toBind: result = symChoice(c, n, s, scClosed) - elif s.name.id in ctx.toMixin: + elif s.isMixedIn: result = symChoice(c, n, s, scForceOpen) else: - result = semGenericStmtSymbol(c, n, s, ctx) + result = semGenericStmtSymbol(c, n, s, ctx, flags, amb) # else: leave as nkIdent proc newDot(n, b: PNode): PNode = result = newNodeI(nkDotExpr, n.info) - result.add(n.sons[0]) + result.add(n[0]) result.add(b) proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var GenericCtx; isMacro: var bool): PNode = + ctx: var GenericCtx; isMacro: var bool; + inCall = false): PNode = assert n.kind == nkDotExpr semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody) let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule} + c.isAmbiguous = false var s = qualifiedLookUp(c, n, luf) if s != nil: - result = semGenericStmtSymbol(c, n, s, ctx) + isMacro = s.kind in {skTemplate, skMacro} + result = semGenericStmtSymbol(c, n, s, ctx, flags, c.isAmbiguous) else: - n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) + n[0] = semGenericStmt(c, n[0], flags, ctx) result = n let n = n[1] let ident = considerQuotedIdent(c, n) - var s = searchInScopes(c, ident).skipAlias(n, c.config) - if s != nil and s.kind in routineKinds: + # could be type conversion if like a.T and not a.T() + let symKinds = if inCall: routineKinds else: routineKinds+{skType} + var candidates = searchInScopesFilterBy(c, ident, symKinds) + if candidates.len > 0: + let s = candidates[0] # XXX take into account the other candidates! isMacro = s.kind in {skTemplate, skMacro} - if withinBind in flags: - result = newDot(result, symChoice(c, n, s, scClosed)) - elif s.name.id in ctx.toMixin: + if withinBind in flags or s.id in ctx.toBind: + if s.kind == skType: # don't put types in sym choice + var ambig = false + if candidates.len > 1: + let s2 = searchInScopes(c, ident, ambig) + result = newDot(result, semGenericStmtSymbol(c, n, s, ctx, flags, + isAmbiguous = ambig, fromDotExpr = true)) + else: + result = newDot(result, symChoice(c, n, s, scClosed)) + elif s.isMixedIn: result = newDot(result, symChoice(c, n, s, scForceOpen)) else: - let syms = semGenericStmtSymbol(c, n, s, ctx, fromDotExpr=true) - if syms.kind == nkSym: - let choice = symChoice(c, n, s, scForceOpen) - choice.kind = nkClosedSymChoice - result = newDot(result, choice) - else: - result = newDot(result, syms) + var ambig = false + if s.kind == skType and candidates.len > 1: + discard searchInScopes(c, ident, ambig) + let syms = semGenericStmtSymbol(c, n, s, ctx, flags, + isAmbiguous = ambig, fromDotExpr = true) + result = newDot(result, syms) proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = let s = newSymS(skUnknown, getIdentNode(c, n), c) addPrelimDecl(c, s) - styleCheckDef(c.config, n.info, s, kind) + styleCheckDef(c, n.info, s, kind) + onDef(n.info, s) + +proc addTempDeclToIdents(c: PContext; n: PNode; kind: TSymKind; inCall: bool) = + case n.kind + of nkIdent: + if inCall: + addTempDecl(c, n, kind) + of nkCallKinds: + for s in n: + addTempDeclToIdents(c, s, kind, true) + else: + for s in n: + addTempDeclToIdents(c, s, kind, inCall) proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = @@ -175,12 +272,15 @@ proc semGenericStmt(c: PContext, n: PNode, case n.kind of nkIdent, nkAccQuoted: result = lookup(c, n, flags, ctx) + if result != nil and result.kind == nkSym: + assert result.sym != nil + markUsed(c, n.info, result.sym) of nkDotExpr: #let luf = if withinMixin notin flags: {checkUndeclared} else: {} #var s = qualifiedLookUp(c, n, luf) #if s != nil: result = semGenericStmtSymbol(c, n, s) # XXX for example: ``result.add`` -- ``add`` needs to be looked up here... - var dummy: bool + var dummy: bool = false result = fuzzyLookup(c, n, flags, ctx, dummy) of nkSym: let a = n.sym @@ -196,15 +296,19 @@ proc semGenericStmt(c: PContext, n: PNode, # in the generic instantiation process... discard of nkBind: - result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx) + result = semGenericStmt(c, n[0], flags+{withinBind}, ctx) of nkMixinStmt: result = semMixinStmt(c, n, ctx.toMixin) + of nkBindStmt: + result = semBindStmt(c, n, ctx.toBind) of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1, c.config) - let fn = n.sons[0] + let fn = n[0] + c.isAmbiguous = false var s = qualifiedLookUp(c, fn, {}) - if s == nil and + let ambig = c.isAmbiguous + if s == nil and {withinMixin, withinConcept}*flags == {} and fn.kind in {nkIdent, nkAccQuoted} and considerQuotedIdent(c, fn).id notin ctx.toMixin: @@ -214,26 +318,25 @@ proc semGenericStmt(c: PContext, n: PNode, var mixinContext = false if s != nil: incl(s.flags, sfUsed) - mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles} - let sc = symChoice(c, fn, s, - if s.name.id in ctx.toMixin: scForceOpen else: scOpen) + mixinContext = s.magic in {mDefined, mDeclared, mDeclaredInScope, mCompiles, mAstToStr} + let whichChoice = if s.id in ctx.toBind: scClosed + elif s.isMixedIn: scForceOpen + else: scOpen + let sc = symChoice(c, fn, s, whichChoice) case s.kind - of skMacro: - if macroToExpand(s) and sc.safeLen <= 1: - styleCheckUse(fn.info, s) - result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + of skMacro, skTemplate: + # unambiguous macros/templates are expanded if all params are untyped + if sfAllUntyped in s.flags and sc.safeLen <= 1: + onUse(fn.info, s) + case s.kind + of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck}) + else: discard # unreachable + c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, flags, ctx) + discard c.friendModules.pop() else: - n.sons[0] = sc - result = n - mixinContext = true - of skTemplate: - if macroToExpand(s) and sc.safeLen <= 1: - styleCheckUse(fn.info, s) - result = semTemplateExpr(c, n, s, {efNoSemCheck}) - result = semGenericStmt(c, result, flags, ctx) - else: - n.sons[0] = sc + n[0] = sc result = n # BUGFIX: we must not return here, we need to do first phase of # symbol lookup. Also since templates and macros can do scope injections @@ -244,243 +347,313 @@ proc semGenericStmt(c: PContext, n: PNode, # Leave it as an identifier. discard of skProc, skFunc, skMethod, skIterator, skConverter, skModule: - result.sons[0] = sc - # do not check of 's.magic==mRoof' here because it might be some - # other '^' but after overload resolution the proper one: - if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^": - result.add ctx.bracketExpr + result[0] = sc first = 1 + # We're not interested in the example code during this pass so let's + # skip it + if s.magic == mRunnableExamples: + first = result.safeLen # see trunnableexamples.fun3 of skGenericParam: - result.sons[0] = newSymNodeTypeDesc(s, fn.info) - styleCheckUse(fn.info, s) + result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info) + onUse(fn.info, s) first = 1 of skType: # bad hack for generics: if (s.typ != nil) and (s.typ.kind != tyGenericParam): - result.sons[0] = newSymNodeTypeDesc(s, fn.info) - styleCheckUse(fn.info, s) + if ambig: + # ambiguous types should be symchoices since lookup behaves + # differently for them in regular expressions + result[0] = sc + else: + result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info) + onUse(fn.info, s) first = 1 else: - result.sons[0] = newSymNode(s, fn.info) - styleCheckUse(fn.info, s) + result[0] = newSymNode(s, fn.info) + onUse(fn.info, s) first = 1 elif fn.kind == nkDotExpr: - result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext) + result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext, inCall = true) first = 1 # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which # is not exported and yet the generic 'threadProcWrapper' works correctly. let flags = if mixinContext: flags+{withinMixin} else: flags - for i in countup(first, sonsLen(result) - 1): - result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx) + for i in first..<result.safeLen: + result[i] = semGenericStmt(c, result[i], flags, ctx) of nkCurlyExpr: result = newNodeI(nkCall, n.info) result.add newIdentNode(getIdent(c.cache, "{}"), n.info) - for i in 0 ..< n.len: result.add(n[i]) + for i in 0..<n.len: result.add(n[i]) result = semGenericStmt(c, result, flags, ctx) of nkBracketExpr: result = newNodeI(nkCall, n.info) result.add newIdentNode(getIdent(c.cache, "[]"), n.info) - for i in 0 ..< n.len: result.add(n[i]) - withBracketExpr ctx, n.sons[0]: - result = semGenericStmt(c, result, flags, ctx) - of nkAsgn, nkFastAsgn: + for i in 0..<n.len: result.add(n[i]) + result = semGenericStmt(c, result, flags, ctx) + of nkAsgn, nkFastAsgn, nkSinkAsgn: checkSonsLen(n, 2, c.config) - let a = n.sons[0] - let b = n.sons[1] + let a = n[0] + let b = n[1] let k = a.kind case k of nkCurlyExpr: result = newNodeI(nkCall, n.info) result.add newIdentNode(getIdent(c.cache, "{}="), n.info) - for i in 0 ..< a.len: result.add(a[i]) + for i in 0..<a.len: result.add(a[i]) result.add(b) result = semGenericStmt(c, result, flags, ctx) of nkBracketExpr: result = newNodeI(nkCall, n.info) result.add newIdentNode(getIdent(c.cache, "[]="), n.info) - for i in 0 ..< a.len: result.add(a[i]) + for i in 0..<a.len: result.add(a[i]) result.add(b) - withBracketExpr ctx, a.sons[0]: - result = semGenericStmt(c, result, flags, ctx) + result = semGenericStmt(c, result, flags, ctx) else: - for i in countup(0, sonsLen(n) - 1): - result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) + for i in 0..<n.len: + result[i] = semGenericStmt(c, n[i], flags, ctx) of nkIfStmt: - for i in countup(0, sonsLen(n)-1): - n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx) + for i in 0..<n.len: + n[i] = semGenericStmtScope(c, n[i], flags, ctx) of nkWhenStmt: - for i in countup(0, sonsLen(n)-1): - n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx) + for i in 0..<n.len: + # bug #8603: conditions of 'when' statements are not + # in a 'mixin' context: + let it = n[i] + if it.kind in {nkElifExpr, nkElifBranch}: + n[i][0] = semGenericStmt(c, it[0], flags, ctx) + n[i][1] = semGenericStmt(c, it[1], flags+{withinMixin}, ctx) + else: + n[i] = semGenericStmt(c, it, flags+{withinMixin}, ctx) of nkWhileStmt: openScope(c) - for i in countup(0, sonsLen(n)-1): - n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) + for i in 0..<n.len: + n[i] = semGenericStmt(c, n[i], flags, ctx) closeScope(c) of nkCaseStmt: openScope(c) - n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) - for i in countup(1, sonsLen(n)-1): - var a = n.sons[i] + n[0] = semGenericStmt(c, n[0], flags, ctx) + for i in 1..<n.len: + var a = n[i] checkMinSonsLen(a, 1, c.config) - var L = sonsLen(a) - for j in countup(0, L-2): - a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx) - a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx) + for j in 0..<a.len-1: + a[j] = semGenericStmt(c, a[j], flags+{withinMixin}, ctx) + addTempDeclToIdents(c, a[j], skVar, false) + + a[^1] = semGenericStmtScope(c, a[^1], flags, ctx) closeScope(c) of nkForStmt, nkParForStmt: - var L = sonsLen(n) openScope(c) - n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx) - for i in countup(0, L - 3): - addTempDecl(c, n.sons[i], skForVar) + n[^2] = semGenericStmt(c, n[^2], flags, ctx) + for i in 0..<n.len - 2: + if (n[i].kind == nkVarTuple): + for s in n[i]: + if (s.kind == nkIdent): + addTempDecl(c,s,skForVar) + else: + addTempDecl(c, n[i], skForVar) openScope(c) - n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx) + n[^1] = semGenericStmt(c, n[^1], flags, ctx) closeScope(c) closeScope(c) of nkBlockStmt, nkBlockExpr, nkBlockType: checkSonsLen(n, 2, c.config) openScope(c) - if n.sons[0].kind != nkEmpty: - addTempDecl(c, n.sons[0], skLabel) - n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) + if n[0].kind != nkEmpty: + addTempDecl(c, n[0], skLabel) + n[1] = semGenericStmt(c, n[1], flags, ctx) closeScope(c) - of nkTryStmt: + of nkTryStmt, nkHiddenTryStmt: checkMinSonsLen(n, 2, c.config) - n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx) - for i in countup(1, sonsLen(n)-1): - var a = n.sons[i] + n[0] = semGenericStmtScope(c, n[0], flags, ctx) + for i in 1..<n.len: + var a = n[i] checkMinSonsLen(a, 1, c.config) - var L = sonsLen(a) openScope(c) - for j in countup(0, L-2): - if a.sons[j].isInfixAs(): - addTempDecl(c, getIdentNode(c, a.sons[j][2]), skLet) - a.sons[j].sons[1] = semGenericStmt(c, a.sons[j][1], flags+{withinTypeDesc}, ctx) + for j in 0..<a.len-1: + if a[j].isInfixAs(): + addTempDecl(c, getIdentNode(c, a[j][2]), skLet) + a[j][1] = semGenericStmt(c, a[j][1], flags+{withinTypeDesc}, ctx) else: - a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx) - a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx) + a[j] = semGenericStmt(c, a[j], flags+{withinTypeDesc}, ctx) + a[^1] = semGenericStmtScope(c, a[^1], flags, ctx) closeScope(c) - of nkVarSection, nkLetSection: - for i in countup(0, sonsLen(n) - 1): - var a = n.sons[i] - if a.kind == nkCommentStmt: continue - if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config) - checkMinSonsLen(a, 3, c.config) - var L = sonsLen(a) - a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) - a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) - for j in countup(0, L-3): - addTempDecl(c, getIdentNode(c, a.sons[j]), skVar) + of nkVarSection, nkLetSection, nkConstSection: + let varKind = + case n.kind + of nkVarSection: skVar + of nkLetSection: skLet + else: skConst + for i in 0..<n.len: + var a = n[i] + case a.kind: + of nkCommentStmt: continue + of nkIdentDefs, nkVarTuple, nkConstDef: + checkMinSonsLen(a, 3, c.config) + a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx) + a[^1] = semGenericStmt(c, a[^1], flags, ctx) + for j in 0..<a.len-2: + addTempDecl(c, getIdentNode(c, a[j]), varKind) + else: + illFormedAst(a, c.config) of nkGenericParams: - for i in countup(0, sonsLen(n) - 1): - var a = n.sons[i] + for i in 0..<n.len: + var a = n[i] if (a.kind != nkIdentDefs): illFormedAst(a, c.config) checkMinSonsLen(a, 3, c.config) - var L = sonsLen(a) - a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) + a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx) # do not perform symbol lookup for default expressions - for j in countup(0, L-3): - addTempDecl(c, getIdentNode(c, a.sons[j]), skType) - of nkConstSection: - for i in countup(0, sonsLen(n) - 1): - var a = n.sons[i] - if a.kind == nkCommentStmt: continue - if (a.kind != nkConstDef): illFormedAst(a, c.config) - checkSonsLen(a, 3, c.config) - addTempDecl(c, getIdentNode(c, a.sons[0]), skConst) - a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx) - a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx) + for j in 0..<a.len-2: + addTempDecl(c, getIdentNode(c, a[j]), skType) of nkTypeSection: - for i in countup(0, sonsLen(n) - 1): - var a = n.sons[i] + for i in 0..<n.len: + var a = n[i] if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): illFormedAst(a, c.config) checkSonsLen(a, 3, c.config) - addTempDecl(c, getIdentNode(c, a.sons[0]), skType) - for i in countup(0, sonsLen(n) - 1): - var a = n.sons[i] + addTempDecl(c, getIdentNode(c, a[0]), skType) + for i in 0..<n.len: + var a = n[i] if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): illFormedAst(a, c.config) checkSonsLen(a, 3, c.config) - if a.sons[1].kind != nkEmpty: + if a[1].kind != nkEmpty: openScope(c) - a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx) - a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx) + a[1] = semGenericStmt(c, a[1], flags, ctx) + a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx) closeScope(c) else: - a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx) + a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx) of nkEnumTy: - if n.sonsLen > 0: - if n.sons[0].kind != nkEmpty: - n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) - for i in countup(1, sonsLen(n) - 1): - var a: PNode - case n.sons[i].kind - of nkEnumFieldDef: a = n.sons[i].sons[0] - of nkIdent: a = n.sons[i] + if n.len > 0: + if n[0].kind != nkEmpty: + n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx) + for i in 1..<n.len: + var a: PNode = nil + case n[i].kind + of nkEnumFieldDef: a = n[i][0] + of nkIdent: a = n[i] else: illFormedAst(n, c.config) addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c)) - of nkObjectTy, nkTupleTy, nkTupleClassTy: - discard + of nkTupleTy: + for i in 0..<n.len: + var a = n[i] + case a.kind: + of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue + of nkIdentDefs: + checkMinSonsLen(a, 3, c.config) + a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx) + a[^1] = semGenericStmt(c, a[^1], flags, ctx) + for j in 0..<a.len-2: + addTempDecl(c, getIdentNode(c, a[j]), skField) + else: + illFormedAst(a, c.config) + of nkObjectTy: + if n.len > 0: + openScope(c) + for i in 0..<n.len: + result[i] = semGenericStmt(c, n[i], flags, ctx) + closeScope(c) + of nkRecList: + for i in 0..<n.len: + var a = n[i] + case a.kind: + of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue + of nkIdentDefs: + checkMinSonsLen(a, 3, c.config) + a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx) + a[^1] = semGenericStmt(c, a[^1], flags, ctx) + for j in 0..<a.len-2: + addTempDecl(c, getIdentNode(c, a[j]), skField) + of nkRecCase, nkRecWhen: + n[i] = semGenericStmt(c, a, flags, ctx) + else: + illFormedAst(a, c.config) + of nkRecCase: + checkSonsLen(n[0], 3, c.config) + n[0][^2] = semGenericStmt(c, n[0][^2], flags+{withinTypeDesc}, ctx) + n[0][^1] = semGenericStmt(c, n[0][^1], flags, ctx) + addTempDecl(c, getIdentNode(c, n[0][0]), skField) + for i in 1..<n.len: + n[i] = semGenericStmt(c, n[i], flags, ctx) of nkFormalParams: checkMinSonsLen(n, 1, c.config) - if n.sons[0].kind != nkEmpty: - n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) - for i in countup(1, sonsLen(n) - 1): - var a = n.sons[i] + for i in 1..<n.len: + var a = n[i] if (a.kind != nkIdentDefs): illFormedAst(a, c.config) checkMinSonsLen(a, 3, c.config) - var L = sonsLen(a) - a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) - a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) - for j in countup(0, L-3): - addTempDecl(c, getIdentNode(c, a.sons[j]), skParam) + a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx) + a[^1] = semGenericStmt(c, a[^1], flags, ctx) + for j in 0..<a.len-2: + addTempDecl(c, getIdentNode(c, a[j]), skParam) + # XXX: last change was moving this down here, search for "1.." to keep + # going from this file onward + if n[0].kind != nkEmpty: + n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx) of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkFuncDef, nkIteratorDef, nkLambdaKinds: checkSonsLen(n, bodyPos + 1, c.config) - if n.sons[namePos].kind != nkEmpty: - addTempDecl(c, getIdentNode(c, n.sons[0]), skProc) + if n[namePos].kind != nkEmpty: + addTempDecl(c, getIdentNode(c, n[0]), skProc) openScope(c) - n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], + n[genericParamsPos] = semGenericStmt(c, n[genericParamsPos], flags, ctx) - if n.sons[paramsPos].kind != nkEmpty: - if n.sons[paramsPos].sons[0].kind != nkEmpty: - addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info)) - n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx) - n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx) + if n[paramsPos].kind != nkEmpty: + if n[paramsPos][0].kind != nkEmpty: + addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), c.idgen, nil, n.info)) + n[paramsPos] = semGenericStmt(c, n[paramsPos], flags, ctx) + n[pragmasPos] = semGenericStmt(c, n[pragmasPos], flags, ctx) var body: PNode - if n.sons[namePos].kind == nkSym: - let s = n.sons[namePos].sym + if n[namePos].kind == nkSym: + let s = n[namePos].sym if sfGenSym in s.flags and s.ast == nil: - body = n.sons[bodyPos] + body = n[bodyPos] else: - body = s.getBody - else: body = n.sons[bodyPos] - n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx) + body = getBody(c.graph, s) + else: body = n[bodyPos] + let bodyFlags = if n.kind == nkTemplateDef: flags + {withinMixin} else: flags + n[bodyPos] = semGenericStmtScope(c, body, bodyFlags, ctx) closeScope(c) of nkPragma, nkPragmaExpr: discard of nkExprColonExpr, nkExprEqExpr: checkMinSonsLen(n, 2, c.config) - result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) + result[1] = semGenericStmt(c, n[1], flags, ctx) + of nkObjConstr: + for i in 0..<n.len: + result[i] = semGenericStmt(c, n[i], flags, ctx) + if result[0].kind == nkSym: + let fmoduleId = getModule(result[0].sym).id + var isVisable = false + for module in c.friendModules: + if module.id == fmoduleId: + isVisable = true + break + if isVisable: + for i in 1..<result.len: + if result[i].kind == nkExprColonExpr: + result[i][1].flags.incl nfSkipFieldChecking else: - for i in countup(0, sonsLen(n) - 1): - result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) + for i in 0..<n.len: + result[i] = semGenericStmt(c, n[i], flags, ctx) when defined(nimsuggest): if withinTypeDesc in flags: dec c.inTypeContext - proc semGenericStmt(c: PContext, n: PNode): PNode = - var ctx: GenericCtx - ctx.toMixin = initIntset() + var ctx = GenericCtx( + toMixin: initIntSet(), + toBind: initIntSet() + ) result = semGenericStmt(c, n, {}, ctx) semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody) proc semConceptBody(c: PContext, n: PNode): PNode = - var ctx: GenericCtx - ctx.toMixin = initIntset() + var ctx = GenericCtx( + toMixin: initIntSet(), + toBind: initIntSet() + ) result = semGenericStmt(c, n, {withinConcept}, ctx) semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody) + |