semgnrc.nim 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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 macroToExpand(s): untyped =
  45. s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
  46. template macroToExpandSym(s): untyped =
  47. sfCustomPragma notin s.flags and s.kind in {skMacro, skTemplate} and
  48. (s.typ.len == 1) and not fromDotExpr
  49. template isMixedIn(sym): bool =
  50. let s = sym
  51. s.name.id in ctx.toMixin or (withinConcept in flags and
  52. s.magic == mNone and
  53. s.kind in OverloadableSyms)
  54. proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
  55. ctx: var GenericCtx; flags: TSemGenericFlags,
  56. fromDotExpr=false): PNode =
  57. semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
  58. incl(s.flags, sfUsed)
  59. case s.kind
  60. of skUnknown:
  61. # Introduced in this pass! Leave it as an identifier.
  62. result = n
  63. of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
  64. result = symChoice(c, n, s, scOpen)
  65. of skTemplate:
  66. if macroToExpandSym(s):
  67. onUse(n.info, s)
  68. result = semTemplateExpr(c, n, s, {efNoSemCheck})
  69. result = semGenericStmt(c, result, {}, ctx)
  70. else:
  71. result = symChoice(c, n, s, scOpen)
  72. of skMacro:
  73. if macroToExpandSym(s):
  74. onUse(n.info, s)
  75. result = semMacroExpr(c, n, n, s, {efNoSemCheck})
  76. result = semGenericStmt(c, result, {}, ctx)
  77. else:
  78. result = symChoice(c, n, s, scOpen)
  79. of skGenericParam:
  80. if s.typ != nil and s.typ.kind == tyStatic:
  81. if s.typ.n != nil:
  82. result = s.typ.n
  83. else:
  84. result = n
  85. else:
  86. result = newSymNodeTypeDesc(s, c.idgen, n.info)
  87. onUse(n.info, s)
  88. of skParam:
  89. result = n
  90. onUse(n.info, s)
  91. of skType:
  92. if (s.typ != nil) and
  93. (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
  94. result = newSymNodeTypeDesc(s, c.idgen, n.info)
  95. else:
  96. result = n
  97. onUse(n.info, s)
  98. else:
  99. result = newSymNode(s, n.info)
  100. onUse(n.info, s)
  101. proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
  102. ctx: var GenericCtx): PNode =
  103. result = n
  104. let ident = considerQuotedIdent(c, n)
  105. var s = searchInScopes(c, ident).skipAlias(n, c.config)
  106. if s == nil:
  107. s = strTableGet(c.pureEnumFields, ident)
  108. if s != nil and contains(c.ambiguousSymbols, s.id):
  109. s = nil
  110. if s == nil:
  111. if ident.id notin ctx.toMixin and withinMixin notin flags:
  112. errorUndeclaredIdentifier(c, n.info, ident.s)
  113. else:
  114. if withinBind in flags or s.id in ctx.toBind:
  115. result = symChoice(c, n, s, scClosed)
  116. elif s.isMixedIn:
  117. result = symChoice(c, n, s, scForceOpen)
  118. else:
  119. result = semGenericStmtSymbol(c, n, s, ctx, flags)
  120. # else: leave as nkIdent
  121. proc newDot(n, b: PNode): PNode =
  122. result = newNodeI(nkDotExpr, n.info)
  123. result.add(n[0])
  124. result.add(b)
  125. proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
  126. ctx: var GenericCtx; isMacro: var bool): PNode =
  127. assert n.kind == nkDotExpr
  128. semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
  129. let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
  130. var s = qualifiedLookUp(c, n, luf)
  131. if s != nil:
  132. result = semGenericStmtSymbol(c, n, s, ctx, flags)
  133. else:
  134. n[0] = semGenericStmt(c, n[0], flags, ctx)
  135. result = n
  136. let n = n[1]
  137. let ident = considerQuotedIdent(c, n)
  138. var s = searchInScopes(c, ident, routineKinds).skipAlias(n, c.config)
  139. if s != nil:
  140. isMacro = s.kind in {skTemplate, skMacro}
  141. if withinBind in flags or s.id in ctx.toBind:
  142. result = newDot(result, symChoice(c, n, s, scClosed))
  143. elif s.isMixedIn:
  144. result = newDot(result, symChoice(c, n, s, scForceOpen))
  145. else:
  146. let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)
  147. if syms.kind == nkSym:
  148. let choice = symChoice(c, n, s, scForceOpen)
  149. choice.transitionSonsKind(nkClosedSymChoice)
  150. result = newDot(result, choice)
  151. else:
  152. result = newDot(result, syms)
  153. proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
  154. let s = newSymS(skUnknown, getIdentNode(c, n), c)
  155. addPrelimDecl(c, s)
  156. styleCheckDef(c.config, n.info, s, kind)
  157. onDef(n.info, s)
  158. proc semGenericStmt(c: PContext, n: PNode,
  159. flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
  160. result = n
  161. when defined(nimsuggest):
  162. if withinTypeDesc in flags: inc c.inTypeContext
  163. #if conf.cmd == cmdIdeTools: suggestStmt(c, n)
  164. semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
  165. case n.kind
  166. of nkIdent, nkAccQuoted:
  167. result = lookup(c, n, flags, ctx)
  168. of nkDotExpr:
  169. #let luf = if withinMixin notin flags: {checkUndeclared} else: {}
  170. #var s = qualifiedLookUp(c, n, luf)
  171. #if s != nil: result = semGenericStmtSymbol(c, n, s)
  172. # XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
  173. var dummy: bool
  174. result = fuzzyLookup(c, n, flags, ctx, dummy)
  175. of nkSym:
  176. let a = n.sym
  177. let b = getGenSym(c, a)
  178. if b != a: n.sym = b
  179. of nkEmpty, succ(nkSym)..nkNilLit, nkComesFrom:
  180. # see tests/compile/tgensymgeneric.nim:
  181. # We need to open the gensym'ed symbol again so that the instantiation
  182. # creates a fresh copy; but this is wrong the very first reason for gensym
  183. # is that scope rules cannot be used! So simply removing 'sfGenSym' does
  184. # not work. Copying the symbol does not work either because we're already
  185. # the owner of the symbol! What we need to do is to copy the symbol
  186. # in the generic instantiation process...
  187. discard
  188. of nkBind:
  189. result = semGenericStmt(c, n[0], flags+{withinBind}, ctx)
  190. of nkMixinStmt:
  191. result = semMixinStmt(c, n, ctx.toMixin)
  192. of nkBindStmt:
  193. result = semBindStmt(c, n, ctx.toBind)
  194. of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
  195. # check if it is an expression macro:
  196. checkMinSonsLen(n, 1, c.config)
  197. let fn = n[0]
  198. var s = qualifiedLookUp(c, fn, {})
  199. if s == nil and
  200. {withinMixin, withinConcept}*flags == {} and
  201. fn.kind in {nkIdent, nkAccQuoted} and
  202. considerQuotedIdent(c, fn).id notin ctx.toMixin:
  203. errorUndeclaredIdentifier(c, n.info, fn.renderTree)
  204. var first = int ord(withinConcept in flags)
  205. var mixinContext = false
  206. if s != nil:
  207. incl(s.flags, sfUsed)
  208. mixinContext = s.magic in {mDefined, mDeclared, mDeclaredInScope, mCompiles, mAstToStr}
  209. let whichChoice = if s.id in ctx.toBind: scClosed
  210. elif s.isMixedIn: scForceOpen
  211. else: scOpen
  212. let sc = symChoice(c, fn, s, whichChoice)
  213. case s.kind
  214. of skMacro:
  215. if macroToExpand(s) and sc.safeLen <= 1:
  216. onUse(fn.info, s)
  217. result = semMacroExpr(c, n, n, s, {efNoSemCheck})
  218. result = semGenericStmt(c, result, flags, ctx)
  219. else:
  220. n[0] = sc
  221. result = n
  222. mixinContext = true
  223. of skTemplate:
  224. if macroToExpand(s) and sc.safeLen <= 1:
  225. onUse(fn.info, s)
  226. result = semTemplateExpr(c, n, s, {efNoSemCheck})
  227. result = semGenericStmt(c, result, flags, ctx)
  228. else:
  229. n[0] = sc
  230. result = n
  231. # BUGFIX: we must not return here, we need to do first phase of
  232. # symbol lookup. Also since templates and macros can do scope injections
  233. # we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
  234. # the famous "undeclared identifier: it" bug:
  235. mixinContext = true
  236. of skUnknown, skParam:
  237. # Leave it as an identifier.
  238. discard
  239. of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
  240. result[0] = sc
  241. first = 1
  242. # We're not interested in the example code during this pass so let's
  243. # skip it
  244. if s.magic == mRunnableExamples:
  245. first = result.safeLen # see trunnableexamples.fun3
  246. of skGenericParam:
  247. result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info)
  248. onUse(fn.info, s)
  249. first = 1
  250. of skType:
  251. # bad hack for generics:
  252. if (s.typ != nil) and (s.typ.kind != tyGenericParam):
  253. result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info)
  254. onUse(fn.info, s)
  255. first = 1
  256. else:
  257. result[0] = newSymNode(s, fn.info)
  258. onUse(fn.info, s)
  259. first = 1
  260. elif fn.kind == nkDotExpr:
  261. result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
  262. first = 1
  263. # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
  264. # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
  265. # is not exported and yet the generic 'threadProcWrapper' works correctly.
  266. let flags = if mixinContext: flags+{withinMixin} else: flags
  267. for i in first..<result.safeLen:
  268. result[i] = semGenericStmt(c, result[i], flags, ctx)
  269. of nkCurlyExpr:
  270. result = newNodeI(nkCall, n.info)
  271. result.add newIdentNode(getIdent(c.cache, "{}"), n.info)
  272. for i in 0..<n.len: result.add(n[i])
  273. result = semGenericStmt(c, result, flags, ctx)
  274. of nkBracketExpr:
  275. result = newNodeI(nkCall, n.info)
  276. result.add newIdentNode(getIdent(c.cache, "[]"), n.info)
  277. for i in 0..<n.len: result.add(n[i])
  278. withBracketExpr ctx, n[0]:
  279. result = semGenericStmt(c, result, flags, ctx)
  280. of nkAsgn, nkFastAsgn:
  281. checkSonsLen(n, 2, c.config)
  282. let a = n[0]
  283. let b = n[1]
  284. let k = a.kind
  285. case k
  286. of nkCurlyExpr:
  287. result = newNodeI(nkCall, n.info)
  288. result.add newIdentNode(getIdent(c.cache, "{}="), n.info)
  289. for i in 0..<a.len: result.add(a[i])
  290. result.add(b)
  291. result = semGenericStmt(c, result, flags, ctx)
  292. of nkBracketExpr:
  293. result = newNodeI(nkCall, n.info)
  294. result.add newIdentNode(getIdent(c.cache, "[]="), n.info)
  295. for i in 0..<a.len: result.add(a[i])
  296. result.add(b)
  297. withBracketExpr ctx, a[0]:
  298. result = semGenericStmt(c, result, flags, ctx)
  299. else:
  300. for i in 0..<n.len:
  301. result[i] = semGenericStmt(c, n[i], flags, ctx)
  302. of nkIfStmt:
  303. for i in 0..<n.len:
  304. n[i] = semGenericStmtScope(c, n[i], flags, ctx)
  305. of nkWhenStmt:
  306. for i in 0..<n.len:
  307. # bug #8603: conditions of 'when' statements are not
  308. # in a 'mixin' context:
  309. let it = n[i]
  310. if it.kind in {nkElifExpr, nkElifBranch}:
  311. n[i][0] = semGenericStmt(c, it[0], flags, ctx)
  312. n[i][1] = semGenericStmt(c, it[1], flags+{withinMixin}, ctx)
  313. else:
  314. n[i] = semGenericStmt(c, it, flags+{withinMixin}, ctx)
  315. of nkWhileStmt:
  316. openScope(c)
  317. for i in 0..<n.len:
  318. n[i] = semGenericStmt(c, n[i], flags, ctx)
  319. closeScope(c)
  320. of nkCaseStmt:
  321. openScope(c)
  322. n[0] = semGenericStmt(c, n[0], flags, ctx)
  323. for i in 1..<n.len:
  324. var a = n[i]
  325. checkMinSonsLen(a, 1, c.config)
  326. for j in 0..<a.len-1:
  327. a[j] = semGenericStmt(c, a[j], flags, ctx)
  328. a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
  329. closeScope(c)
  330. of nkForStmt, nkParForStmt:
  331. openScope(c)
  332. n[^2] = semGenericStmt(c, n[^2], flags, ctx)
  333. for i in 0..<n.len - 2:
  334. if (n[i].kind == nkVarTuple):
  335. for s in n[i]:
  336. if (s.kind == nkIdent):
  337. addTempDecl(c,s,skForVar)
  338. else:
  339. addTempDecl(c, n[i], skForVar)
  340. openScope(c)
  341. n[^1] = semGenericStmt(c, n[^1], flags, ctx)
  342. closeScope(c)
  343. closeScope(c)
  344. of nkBlockStmt, nkBlockExpr, nkBlockType:
  345. checkSonsLen(n, 2, c.config)
  346. openScope(c)
  347. if n[0].kind != nkEmpty:
  348. addTempDecl(c, n[0], skLabel)
  349. n[1] = semGenericStmt(c, n[1], flags, ctx)
  350. closeScope(c)
  351. of nkTryStmt, nkHiddenTryStmt:
  352. checkMinSonsLen(n, 2, c.config)
  353. n[0] = semGenericStmtScope(c, n[0], flags, ctx)
  354. for i in 1..<n.len:
  355. var a = n[i]
  356. checkMinSonsLen(a, 1, c.config)
  357. openScope(c)
  358. for j in 0..<a.len-1:
  359. if a[j].isInfixAs():
  360. addTempDecl(c, getIdentNode(c, a[j][2]), skLet)
  361. a[j][1] = semGenericStmt(c, a[j][1], flags+{withinTypeDesc}, ctx)
  362. else:
  363. a[j] = semGenericStmt(c, a[j], flags+{withinTypeDesc}, ctx)
  364. a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
  365. closeScope(c)
  366. of nkVarSection, nkLetSection:
  367. for i in 0..<n.len:
  368. var a = n[i]
  369. if a.kind == nkCommentStmt: continue
  370. if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config)
  371. checkMinSonsLen(a, 3, c.config)
  372. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  373. a[^1] = semGenericStmt(c, a[^1], flags, ctx)
  374. for j in 0..<a.len-2:
  375. addTempDecl(c, getIdentNode(c, a[j]), skVar)
  376. of nkGenericParams:
  377. for i in 0..<n.len:
  378. var a = n[i]
  379. if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
  380. checkMinSonsLen(a, 3, c.config)
  381. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  382. # do not perform symbol lookup for default expressions
  383. for j in 0..<a.len-2:
  384. addTempDecl(c, getIdentNode(c, a[j]), skType)
  385. of nkConstSection:
  386. for i in 0..<n.len:
  387. var a = n[i]
  388. if a.kind == nkCommentStmt: continue
  389. if (a.kind != nkConstDef): illFormedAst(a, c.config)
  390. checkSonsLen(a, 3, c.config)
  391. addTempDecl(c, getIdentNode(c, a[0]), skConst)
  392. a[1] = semGenericStmt(c, a[1], flags+{withinTypeDesc}, ctx)
  393. a[2] = semGenericStmt(c, a[2], flags, ctx)
  394. of nkTypeSection:
  395. for i in 0..<n.len:
  396. var a = n[i]
  397. if a.kind == nkCommentStmt: continue
  398. if (a.kind != nkTypeDef): illFormedAst(a, c.config)
  399. checkSonsLen(a, 3, c.config)
  400. addTempDecl(c, getIdentNode(c, a[0]), skType)
  401. for i in 0..<n.len:
  402. var a = n[i]
  403. if a.kind == nkCommentStmt: continue
  404. if (a.kind != nkTypeDef): illFormedAst(a, c.config)
  405. checkSonsLen(a, 3, c.config)
  406. if a[1].kind != nkEmpty:
  407. openScope(c)
  408. a[1] = semGenericStmt(c, a[1], flags, ctx)
  409. a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx)
  410. closeScope(c)
  411. else:
  412. a[2] = semGenericStmt(c, a[2], flags+{withinTypeDesc}, ctx)
  413. of nkEnumTy:
  414. if n.len > 0:
  415. if n[0].kind != nkEmpty:
  416. n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx)
  417. for i in 1..<n.len:
  418. var a: PNode
  419. case n[i].kind
  420. of nkEnumFieldDef: a = n[i][0]
  421. of nkIdent: a = n[i]
  422. else: illFormedAst(n, c.config)
  423. addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c))
  424. of nkObjectTy, nkTupleTy, nkTupleClassTy:
  425. discard
  426. of nkFormalParams:
  427. checkMinSonsLen(n, 1, c.config)
  428. if n[0].kind != nkEmpty:
  429. n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx)
  430. for i in 1..<n.len:
  431. var a = n[i]
  432. if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
  433. checkMinSonsLen(a, 3, c.config)
  434. a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
  435. a[^1] = semGenericStmt(c, a[^1], flags, ctx)
  436. for j in 0..<a.len-2:
  437. addTempDecl(c, getIdentNode(c, a[j]), skParam)
  438. of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
  439. nkFuncDef, nkIteratorDef, nkLambdaKinds:
  440. checkSonsLen(n, bodyPos + 1, c.config)
  441. if n[namePos].kind != nkEmpty:
  442. addTempDecl(c, getIdentNode(c, n[0]), skProc)
  443. openScope(c)
  444. n[genericParamsPos] = semGenericStmt(c, n[genericParamsPos],
  445. flags, ctx)
  446. if n[paramsPos].kind != nkEmpty:
  447. if n[paramsPos][0].kind != nkEmpty:
  448. addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextId c.idgen, nil, n.info))
  449. n[paramsPos] = semGenericStmt(c, n[paramsPos], flags, ctx)
  450. n[pragmasPos] = semGenericStmt(c, n[pragmasPos], flags, ctx)
  451. var body: PNode
  452. if n[namePos].kind == nkSym:
  453. let s = n[namePos].sym
  454. if sfGenSym in s.flags and s.ast == nil:
  455. body = n[bodyPos]
  456. else:
  457. body = s.getBody
  458. else: body = n[bodyPos]
  459. n[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
  460. closeScope(c)
  461. of nkPragma, nkPragmaExpr: discard
  462. of nkExprColonExpr, nkExprEqExpr:
  463. checkMinSonsLen(n, 2, c.config)
  464. result[1] = semGenericStmt(c, n[1], flags, ctx)
  465. else:
  466. for i in 0..<n.len:
  467. result[i] = semGenericStmt(c, n[i], flags, ctx)
  468. when defined(nimsuggest):
  469. if withinTypeDesc in flags: dec c.inTypeContext
  470. proc semGenericStmt(c: PContext, n: PNode): PNode =
  471. var ctx: GenericCtx
  472. ctx.toMixin = initIntSet()
  473. ctx.toBind = initIntSet()
  474. result = semGenericStmt(c, n, {}, ctx)
  475. semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
  476. proc semConceptBody(c: PContext, n: PNode): PNode =
  477. var ctx: GenericCtx
  478. ctx.toMixin = initIntSet()
  479. ctx.toBind = initIntSet()
  480. result = semGenericStmt(c, n, {withinConcept}, ctx)
  481. semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)