semgnrc.nim 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This implements the first pass over the generic body; it resolves some
  10. # symbols. Thus for generics there is a two-phase symbol lookup just like
  11. # in C++.
  12. # A problem is that it cannot be detected if the symbol is introduced
  13. # as in ``var x = ...`` or used because macros/templates can hide this!
  14. # So we have to eval templates/macros right here so that symbol
  15. # lookup can be accurate.
  16. # included from sem.nim
  17. proc getIdentNode(c: PContext; n: PNode): PNode =
  18. case n.kind
  19. of nkPostfix: result = getIdentNode(c, n[1])
  20. of nkPragmaExpr: result = getIdentNode(c, n[0])
  21. of nkIdent, nkAccQuoted, nkSym: result = n
  22. else:
  23. illFormedAst(n, c.config)
  24. result = n
  25. type
  26. GenericCtx = object
  27. toMixin, toBind: IntSet
  28. cursorInBody: bool # only for nimsuggest
  29. bracketExpr: PNode
  30. TSemGenericFlag = enum
  31. withinBind,
  32. withinTypeDesc,
  33. withinMixin,
  34. withinConcept
  35. TSemGenericFlags = set[TSemGenericFlag]
  36. proc semGenericStmt(c: PContext, n: PNode,
  37. flags: TSemGenericFlags, ctx: var GenericCtx): PNode
  38. proc semGenericStmtScope(c: PContext, n: PNode,
  39. flags: TSemGenericFlags,
  40. ctx: var GenericCtx): PNode =
  41. openScope(c)
  42. result = semGenericStmt(c, n, flags, ctx)
  43. closeScope(c)
  44. template isMixedIn(sym): bool =
  45. let s = sym
  46. s.name.id in ctx.toMixin or (withinConcept in flags and
  47. s.magic == mNone and
  48. s.kind in OverloadableSyms)
  49. template canOpenSym(s): bool =
  50. {withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind
  51. proc newOpenSym*(n: PNode): PNode {.inline.} =
  52. result = newTreeI(nkOpenSym, n.info, n)
  53. proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
  54. ctx: var GenericCtx; flags: TSemGenericFlags,
  55. fromDotExpr=false): PNode =
  56. result = nil
  57. semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
  58. incl(s.flags, sfUsed)
  59. template maybeDotChoice(c: PContext, n: PNode, s: PSym, fromDotExpr: bool) =
  60. if fromDotExpr:
  61. result = symChoice(c, n, s, scForceOpen)
  62. if result.kind == nkOpenSymChoice and result.len == 1:
  63. result.transitionSonsKind(nkClosedSymChoice)
  64. else:
  65. result = symChoice(c, n, s, scOpen)
  66. if canOpenSym(s):
  67. if genericsOpenSym in c.features:
  68. result = newOpenSym(result)
  69. else:
  70. result.flags.incl nfDisabledOpenSym
  71. result.typ = nil
  72. case s.kind
  73. of skUnknown:
  74. # Introduced in this pass! Leave it as an identifier.
  75. result = n
  76. of skProc, skFunc, skMethod, skIterator, skConverter, skModule, skEnumField:
  77. maybeDotChoice(c, n, s, fromDotExpr)
  78. of skTemplate, skMacro:
  79. # alias syntax, see semSym for skTemplate, skMacro
  80. if sfNoalias notin s.flags and not fromDotExpr:
  81. onUse(n.info, s)
  82. case s.kind
  83. of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck})
  84. of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck})
  85. else: discard # unreachable
  86. c.friendModules.add(s.owner.getModule)
  87. result = semGenericStmt(c, result, {}, ctx)
  88. discard c.friendModules.pop()
  89. else:
  90. maybeDotChoice(c, n, s, fromDotExpr)
  91. of skGenericParam:
  92. if s.typ != nil and s.typ.kind == tyStatic:
  93. if s.typ.n != nil:
  94. result = s.typ.n
  95. else:
  96. result = n
  97. else:
  98. result = newSymNodeTypeDesc(s, c.idgen, n.info)
  99. if canOpenSym(result.sym):
  100. if genericsOpenSym in c.features:
  101. result = newOpenSym(result)
  102. else:
  103. result.flags.incl nfDisabledOpenSym
  104. result.typ = nil
  105. onUse(n.info, s)
  106. of skParam:
  107. result = n
  108. onUse(n.info, s)
  109. of skType:
  110. if (s.typ != nil) and
  111. (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
  112. result = newSymNodeTypeDesc(s, c.idgen, n.info)
  113. if canOpenSym(result.sym):
  114. if genericsOpenSym in c.features:
  115. result = newOpenSym(result)
  116. else:
  117. result.flags.incl nfDisabledOpenSym
  118. result.typ = nil
  119. else:
  120. result = n
  121. onUse(n.info, s)
  122. else:
  123. result = newSymNode(s, n.info)
  124. if canOpenSym(result.sym):
  125. if genericsOpenSym in c.features:
  126. result = newOpenSym(result)
  127. else:
  128. result.flags.incl nfDisabledOpenSym
  129. result.typ = nil
  130. onUse(n.info, s)
  131. proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
  132. ctx: var GenericCtx): PNode =
  133. result = n
  134. let ident = considerQuotedIdent(c, n)
  135. var amb = false
  136. var s = searchInScopes(c, ident, amb)
  137. if s == nil:
  138. s = strTableGet(c.pureEnumFields, ident)
  139. #if s != nil and contains(c.ambiguousSymbols, s.id):
  140. # s = nil
  141. if s == nil:
  142. if ident.id notin ctx.toMixin and withinMixin notin flags:
  143. errorUndeclaredIdentifier(c, n.info, ident.s)
  144. else:
  145. if withinBind in flags or s.id in ctx.toBind:
  146. result = symChoice(c, n, s, scClosed)
  147. elif s.isMixedIn:
  148. result = symChoice(c, n, s, scForceOpen)
  149. else:
  150. result = semGenericStmtSymbol(c, n, s, ctx, flags)
  151. # else: leave as nkIdent
  152. proc newDot(n, b: PNode): PNode =
  153. result = newNodeI(nkDotExpr, n.info)
  154. result.add(n[0])
  155. result.add(b)
  156. proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
  157. ctx: var GenericCtx; isMacro: var bool;
  158. inCall = false): PNode =
  159. assert n.kind == nkDotExpr
  160. semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
  161. let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
  162. var s = qualifiedLookUp(c, n, luf)
  163. if s != nil:
  164. isMacro = s.kind in {skTemplate, skMacro}
  165. result = semGenericStmtSymbol(c, n, s, ctx, flags)
  166. else:
  167. n[0] = semGenericStmt(c, n[0], flags, ctx)
  168. result = n
  169. let n = n[1]
  170. let ident = considerQuotedIdent(c, n)
  171. # could be type conversion if like a.T and not a.T()
  172. let symKinds = if inCall: routineKinds else: routineKinds+{skType}
  173. var candidates = searchInScopesFilterBy(c, ident, symKinds)
  174. if candidates.len > 0:
  175. let s = candidates[0] # XXX take into account the other candidates!
  176. isMacro = s.kind in {skTemplate, skMacro}
  177. if withinBind in flags or s.id in ctx.toBind:
  178. if s.kind == skType: # don't put types in sym choice
  179. result = newDot(result, semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true))
  180. else:
  181. result = newDot(result, symChoice(c, n, s, scClosed))
  182. elif s.isMixedIn:
  183. result = newDot(result, symChoice(c, n, s, scForceOpen))
  184. else:
  185. if s.kind == skType and candidates.len > 1:
  186. var ambig = false
  187. let s2 = searchInScopes(c, ident, ambig)
  188. if ambig:
  189. # this is a type conversion like a.T where T is ambiguous with
  190. # other types or routines
  191. # in regular code, this never considers a type conversion and
  192. # skips to routine overloading
  193. # so symchoices are used which behave similarly with type symbols
  194. result = newDot(result, symChoice(c, n, s, scForceOpen))
  195. return
  196. let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)
  197. result = newDot(result, syms)
  198. proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
  199. let s = newSymS(skUnknown, getIdentNode(c, n), c)
  200. addPrelimDecl(c, s)
  201. styleCheckDef(c, n.info, s, kind)
  202. onDef(n.info, s)
  203. proc addTempDeclToIdents(c: PContext; n: PNode; kind: TSymKind; inCall: bool) =
  204. case n.kind
  205. of nkIdent:
  206. if inCall:
  207. addTempDecl(c, n, kind)
  208. of nkCallKinds:
  209. for s in n:
  210. addTempDeclToIdents(c, s, kind, true)
  211. else:
  212. for s in n:
  213. addTempDeclToIdents(c, s, kind, inCall)
  214. proc semGenericStmt(c: PContext, n: PNode,
  215. flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
  216. result = n
  217. when defined(nimsuggest):
  218. if withinTypeDesc in flags: inc c.inTypeContext
  219. #if conf.cmd == cmdIdeTools: suggestStmt(c, n)
  220. semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
  221. case n.kind
  222. of nkIdent, nkAccQuoted:
  223. result = lookup(c, n, flags, ctx)
  224. if result != nil and result.kind == nkSym:
  225. assert result.sym != nil
  226. markUsed(c, n.info, result.sym)
  227. of nkDotExpr:
  228. #let luf = if withinMixin notin flags: {checkUndeclared} else: {}
  229. #var s = qualifiedLookUp(c, n, luf)
  230. #if s != nil: result = semGenericStmtSymbol(c, n, s)
  231. # XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
  232. var dummy: bool = false
  233. result = fuzzyLookup(c, n, flags, ctx, dummy)
  234. of nkSym:
  235. let a = n.sym
  236. let b = getGenSym(c, a)
  237. if b != a: n.sym = b
  238. of nkEmpty, succ(nkSym)..nkNilLit, nkComesFrom:
  239. # see tests/compile/tgensymgeneric.nim:
  240. # We need to open the gensym'ed symbol again so that the instantiation
  241. # creates a fresh copy; but this is wrong the very first reason for gensym
  242. # is that scope rules cannot be used! So simply removing 'sfGenSym' does
  243. # not work. Copying the symbol does not work either because we're already
  244. # the owner of the symbol! What we need to do is to copy the symbol
  245. # in the generic instantiation process...
  246. discard
  247. of nkBind:
  248. result = semGenericStmt(c, n[0], flags+{withinBind}, ctx)
  249. of nkMixinStmt:
  250. result = semMixinStmt(c, n, ctx.toMixin)
  251. of nkBindStmt:
  252. result = semBindStmt(c, n, ctx.toBind)
  253. of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
  254. # check if it is an expression macro:
  255. checkMinSonsLen(n, 1, c.config)
  256. let fn = n[0]
  257. var s = qualifiedLookUp(c, fn, {})
  258. if s == nil and
  259. {withinMixin, withinConcept}*flags == {} and
  260. fn.kind in {nkIdent, nkAccQuoted} and
  261. considerQuotedIdent(c, fn).id notin ctx.toMixin:
  262. errorUndeclaredIdentifier(c, n.info, fn.renderTree)
  263. var first = int ord(withinConcept in flags)
  264. var mixinContext = false
  265. if s != nil:
  266. incl(s.flags, sfUsed)
  267. mixinContext = s.magic in {mDefined, mDeclared, mDeclaredInScope, mCompiles, mAstToStr}
  268. let whichChoice = if s.id in ctx.toBind: scClosed
  269. elif s.isMixedIn: scForceOpen
  270. else: scOpen
  271. let sc = symChoice(c, fn, s, whichChoice)
  272. case s.kind
  273. of skMacro, skTemplate:
  274. # unambiguous macros/templates are expanded if all params are untyped
  275. if sfAllUntyped in s.flags and sc.safeLen <= 1:
  276. onUse(fn.info, s)
  277. case s.kind
  278. of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck})
  279. of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck})
  280. else: discard # unreachable
  281. c.friendModules.add(s.owner.getModule)
  282. result = semGenericStmt(c, result, flags, ctx)
  283. discard c.friendModules.pop()
  284. else:
  285. n[0] = sc
  286. result = n
  287. # BUGFIX: we must not return here, we need to do first phase of
  288. # symbol lookup. Also since templates and macros can do scope injections
  289. # we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
  290. # the famous "undeclared identifier: it" bug:
  291. mixinContext = true
  292. of skUnknown, skParam:
  293. # Leave it as an identifier.
  294. discard
  295. of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
  296. result[0] = sc
  297. first = 1
  298. # We're not interested in the example code during this pass so let's
  299. # skip it
  300. if s.magic == mRunnableExamples:
  301. first = result.safeLen # see trunnableexamples.fun3
  302. of skGenericParam:
  303. result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info)
  304. onUse(fn.info, s)
  305. first = 1
  306. of skType:
  307. # bad hack for generics:
  308. if (s.typ != nil) and (s.typ.kind != tyGenericParam):
  309. result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info)
  310. onUse(fn.info, s)
  311. first = 1
  312. else:
  313. result[0] = newSymNode(s, fn.info)
  314. onUse(fn.info, s)
  315. first = 1
  316. elif fn.kind == nkDotExpr:
  317. result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext, inCall = true)
  318. first = 1
  319. # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
  320. # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
  321. # is not exported and yet the generic 'threadProcWrapper' works correctly.
  322. let flags = if mixinContext: flags+{withinMixin} else: flags
  323. for i in first..<result.safeLen:
  324. result[i] = semGenericStmt(c, result[i], flags, ctx)
  325. of nkCurlyExpr:
  326. result = newNodeI(nkCall, n.info)
  327. result.add newIdentNode(getIdent(c.cache, "{}"), n.info)
  328. for i in 0..<n.len: result.add(n[i])
  329. result = semGenericStmt(c, result, flags, ctx)
  330. of nkBracketExpr:
  331. result = newNodeI(nkCall, n.info)
  332. result.add newIdentNode(getIdent(c.cache, "[]"), n.info)
  333. for i in 0..<n.len: result.add(n[i])
  334. result = semGenericStmt(c, result, flags, ctx)
  335. of nkAsgn, nkFastAsgn, nkSinkAsgn:
  336. checkSonsLen(n, 2, c.config)
  337. let a = n[0]
  338. let b = n[1]
  339. let k = a.kind
  340. case k
  341. of nkCurlyExpr:
  342. result = newNodeI(nkCall, n.info)
  343. result.add newIdentNode(getIdent(c.cache, "{}="), n.info)
  344. for i in 0..<a.len: result.add(a[i])
  345. result.add(b)
  346. result = semGenericStmt(c, result, flags, ctx)
  347. of nkBracketExpr:
  348. result = newNodeI(nkCall, n.info)
  349. result.add newIdentNode(getIdent(c.cache, "[]="), n.info)
  350. for i in 0..<a.len: result.add(a[i])
  351. result.add(b)
  352. result = semGenericStmt(c, result, flags, ctx)
  353. else:
  354. for i in 0..<n.len:
  355. result[i] = semGenericStmt(c, n[i], flags, ctx)
  356. of nkIfStmt:
  357. for i in 0..<n.len:
  358. n[i] = semGenericStmtScope(c, n[i], flags, ctx)
  359. of nkWhenStmt:
  360. for i in 0..<n.len:
  361. # bug #8603: conditions of 'when' statements are not
  362. # in a 'mixin' context:
  363. let it = n[i]
  364. if it.kind in {nkElifExpr, nkElifBranch}:
  365. n[i][0] = semGenericStmt(c, it[0], flags, ctx)
  366. n[i][1] = semGenericStmt(c, it[1], flags+{withinMixin}, ctx)
  367. else:
  368. n[i] = semGenericStmt(c, it, flags+{withinMixin}, ctx)
  369. of nkWhileStmt:
  370. openScope(c)
  371. for i in 0..<n.len:
  372. n[i] = semGenericStmt(c, n[i], flags, ctx)
  373. closeScope(c)
  374. of nkCaseStmt:
  375. openScope(c)
  376. n[0] = semGenericStmt(c, n[0], flags, ctx)
  377. for i in 1..<n.len:
  378. var a = n[i]
  379. checkMinSonsLen(a, 1, c.config)
  380. for j in 0..<a.len-1:
  381. a[j] = semGenericStmt(c, a[j], flags+{withinMixin}, ctx)
  382. addTempDeclToIdents(c, a[j], skVar, false)
  383. a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
  384. closeScope(c)
  385. of nkForStmt, nkParForStmt:
  386. openScope(c)
  387. n[^2] = semGenericStmt(c, n[^2], flags, ctx)
  388. for i in 0..<n.len - 2:
  389. if (n[i].kind == nkVarTuple):
  390. for s in n[i]:
  391. if (s.kind == nkIdent):
  392. addTempDecl(c,s,skForVar)
  393. else:
  394. addTempDecl(c, n[i], skForVar)
  395. openScope(c)
  396. n[^1] = semGenericStmt(c, n[^1], flags, ctx)
  397. closeScope(c)
  398. closeScope(c)
  399. of nkBlockStmt, nkBlockExpr, nkBlockType:
  400. checkSonsLen(n, 2, c.config)
  401. openScope(c)
  402. if n[0].kind != nkEmpty:
  403. addTempDecl(c, n[0], skLabel)
  404. n[1] = semGenericStmt(c, n[1], flags, ctx)
  405. closeScope(c)
  406. of nkTryStmt, nkHiddenTryStmt:
  407. checkMinSonsLen(n, 2, c.config)
  408. n[0] = semGenericStmtScope(c, n[0], flags, ctx)
  409. for i in 1..<n.len:
  410. var a = n[i]
  411. checkMinSonsLen(a, 1, c.config)
  412. openScope(c)
  413. for j in 0..<a.len-1:
  414. if a[j].isInfixAs():
  415. addTempDecl(c, getIdentNode(c, a[j][2]), skLet)
  416. a[j][1] = semGenericStmt(c, a[j][1], flags+{withinTypeDesc}, ctx)
  417. else:
  418. a[j] = semGenericStmt(c, a[j], flags+{withinTypeDesc}, ctx)
  419. a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
  420. closeScope(c)
  421. of nkVarSection, nkLetSection, nkConstSection:
  422. let varKind =
  423. case n.kind
  424. of nkVarSection: skVar
  425. of nkLetSection: skLet
  426. else: skConst
  427. for i in 0..<n.len:
  428. var a = n[i]
  429. case a.kind:
  430. of nkCommentStmt: continue
  431. of nkIdentDefs, nkVarTuple, nkConstDef:
  432. checkMinSonsLen(a, 3, c.config)
  433. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  434. a[^1] = semGenericStmt(c, a[^1], flags, ctx)
  435. for j in 0..<a.len-2:
  436. addTempDecl(c, getIdentNode(c, a[j]), varKind)
  437. else:
  438. illFormedAst(a, c.config)
  439. of nkGenericParams:
  440. for i in 0..<n.len:
  441. var a = n[i]
  442. if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
  443. checkMinSonsLen(a, 3, c.config)
  444. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  445. # do not perform symbol lookup for default expressions
  446. for j in 0..<a.len-2:
  447. addTempDecl(c, getIdentNode(c, a[j]), skType)
  448. of nkTypeSection:
  449. for i in 0..<n.len:
  450. var a = n[i]
  451. if a.kind == nkCommentStmt: continue
  452. if (a.kind != nkTypeDef): illFormedAst(a, c.config)
  453. checkSonsLen(a, 3, c.config)
  454. addTempDecl(c, getIdentNode(c, a[0]), skType)
  455. for i in 0..<n.len:
  456. var a = n[i]
  457. if a.kind == nkCommentStmt: continue
  458. if (a.kind != nkTypeDef): illFormedAst(a, c.config)
  459. checkSonsLen(a, 3, c.config)
  460. if a[1].kind != nkEmpty:
  461. openScope(c)
  462. a[1] = semGenericStmt(c, a[1], flags, ctx)
  463. a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx)
  464. closeScope(c)
  465. else:
  466. a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx)
  467. of nkEnumTy:
  468. if n.len > 0:
  469. if n[0].kind != nkEmpty:
  470. n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx)
  471. for i in 1..<n.len:
  472. var a: PNode = nil
  473. case n[i].kind
  474. of nkEnumFieldDef: a = n[i][0]
  475. of nkIdent: a = n[i]
  476. else: illFormedAst(n, c.config)
  477. addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c))
  478. of nkTupleTy:
  479. for i in 0..<n.len:
  480. var a = n[i]
  481. case a.kind:
  482. of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
  483. of nkIdentDefs:
  484. checkMinSonsLen(a, 3, c.config)
  485. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  486. a[^1] = semGenericStmt(c, a[^1], flags, ctx)
  487. for j in 0..<a.len-2:
  488. addTempDecl(c, getIdentNode(c, a[j]), skField)
  489. else:
  490. illFormedAst(a, c.config)
  491. of nkObjectTy:
  492. if n.len > 0:
  493. openScope(c)
  494. for i in 0..<n.len:
  495. result[i] = semGenericStmt(c, n[i], flags, ctx)
  496. closeScope(c)
  497. of nkRecList:
  498. for i in 0..<n.len:
  499. var a = n[i]
  500. case a.kind:
  501. of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
  502. of nkIdentDefs:
  503. checkMinSonsLen(a, 3, c.config)
  504. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  505. a[^1] = semGenericStmt(c, a[^1], flags, ctx)
  506. for j in 0..<a.len-2:
  507. addTempDecl(c, getIdentNode(c, a[j]), skField)
  508. of nkRecCase, nkRecWhen:
  509. n[i] = semGenericStmt(c, a, flags, ctx)
  510. else:
  511. illFormedAst(a, c.config)
  512. of nkRecCase:
  513. checkSonsLen(n[0], 3, c.config)
  514. n[0][^2] = semGenericStmt(c, n[0][^2], flags+{withinTypeDesc}, ctx)
  515. n[0][^1] = semGenericStmt(c, n[0][^1], flags, ctx)
  516. addTempDecl(c, getIdentNode(c, n[0][0]), skField)
  517. for i in 1..<n.len:
  518. n[i] = semGenericStmt(c, n[i], flags, ctx)
  519. of nkFormalParams:
  520. checkMinSonsLen(n, 1, c.config)
  521. for i in 1..<n.len:
  522. var a = n[i]
  523. if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
  524. checkMinSonsLen(a, 3, c.config)
  525. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  526. a[^1] = semGenericStmt(c, a[^1], flags, ctx)
  527. for j in 0..<a.len-2:
  528. addTempDecl(c, getIdentNode(c, a[j]), skParam)
  529. # XXX: last change was moving this down here, search for "1.." to keep
  530. # going from this file onward
  531. if n[0].kind != nkEmpty:
  532. n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx)
  533. of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
  534. nkFuncDef, nkIteratorDef, nkLambdaKinds:
  535. checkSonsLen(n, bodyPos + 1, c.config)
  536. if n[namePos].kind != nkEmpty:
  537. addTempDecl(c, getIdentNode(c, n[0]), skProc)
  538. openScope(c)
  539. n[genericParamsPos] = semGenericStmt(c, n[genericParamsPos],
  540. flags, ctx)
  541. if n[paramsPos].kind != nkEmpty:
  542. if n[paramsPos][0].kind != nkEmpty:
  543. addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), c.idgen, nil, n.info))
  544. n[paramsPos] = semGenericStmt(c, n[paramsPos], flags, ctx)
  545. n[pragmasPos] = semGenericStmt(c, n[pragmasPos], flags, ctx)
  546. var body: PNode
  547. if n[namePos].kind == nkSym:
  548. let s = n[namePos].sym
  549. if sfGenSym in s.flags and s.ast == nil:
  550. body = n[bodyPos]
  551. else:
  552. body = getBody(c.graph, s)
  553. else: body = n[bodyPos]
  554. n[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
  555. closeScope(c)
  556. of nkPragma, nkPragmaExpr: discard
  557. of nkExprColonExpr, nkExprEqExpr:
  558. checkMinSonsLen(n, 2, c.config)
  559. result[1] = semGenericStmt(c, n[1], flags, ctx)
  560. of nkObjConstr:
  561. for i in 0..<n.len:
  562. result[i] = semGenericStmt(c, n[i], flags, ctx)
  563. if result[0].kind == nkSym:
  564. let fmoduleId = getModule(result[0].sym).id
  565. var isVisable = false
  566. for module in c.friendModules:
  567. if module.id == fmoduleId:
  568. isVisable = true
  569. break
  570. if isVisable:
  571. for i in 1..<result.len:
  572. if result[i].kind == nkExprColonExpr:
  573. result[i][1].flags.incl nfSkipFieldChecking
  574. else:
  575. for i in 0..<n.len:
  576. result[i] = semGenericStmt(c, n[i], flags, ctx)
  577. when defined(nimsuggest):
  578. if withinTypeDesc in flags: dec c.inTypeContext
  579. proc semGenericStmt(c: PContext, n: PNode): PNode =
  580. var ctx = GenericCtx(
  581. toMixin: initIntSet(),
  582. toBind: initIntSet()
  583. )
  584. result = semGenericStmt(c, n, {}, ctx)
  585. semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
  586. proc semConceptBody(c: PContext, n: PNode): PNode =
  587. var ctx = GenericCtx(
  588. toMixin: initIntSet(),
  589. toBind: initIntSet()
  590. )
  591. result = semGenericStmt(c, n, {withinConcept}, ctx)
  592. semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)