seminst.nim 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This module implements the instantiation of generic procs.
  10. # included from sem.nim
  11. proc addObjFieldsToLocalScope(c: PContext; n: PNode) =
  12. template rec(n) = addObjFieldsToLocalScope(c, n)
  13. case n.kind
  14. of nkRecList:
  15. for i in 0..<n.len:
  16. rec n[i]
  17. of nkRecCase:
  18. if n.len > 0: rec n[0]
  19. for i in 1..<n.len:
  20. if n[i].kind in {nkOfBranch, nkElse}: rec lastSon(n[i])
  21. of nkSym:
  22. let f = n.sym
  23. if f.kind == skField and fieldVisible(c, f):
  24. c.currentScope.symbols.strTableIncl(f, onConflictKeepOld=true)
  25. incl(f.flags, sfUsed)
  26. # it is not an error to shadow fields via parameters
  27. else: discard
  28. proc pushProcCon*(c: PContext; owner: PSym) =
  29. c.p = PProcCon(owner: owner, next: c.p)
  30. const
  31. errCannotInstantiateX = "cannot instantiate: '$1'"
  32. iterator instantiateGenericParamList(c: PContext, n: PNode, pt: LayeredIdTable): PSym =
  33. internalAssert c.config, n.kind == nkGenericParams
  34. for a in n.items:
  35. internalAssert c.config, a.kind == nkSym
  36. var q = a.sym
  37. if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses:
  38. let symKind = if q.typ.kind == tyStatic: skConst else: skType
  39. var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info)
  40. s.flags.incl {sfUsed, sfFromGeneric}
  41. var t = lookup(pt, q.typ)
  42. if t == nil:
  43. if tfRetType in q.typ.flags:
  44. # keep the generic type and allow the return type to be bound
  45. # later by semAsgn in return type inference scenario
  46. t = q.typ
  47. else:
  48. if q.typ.kind != tyCompositeTypeClass:
  49. localError(c.config, a.info, errCannotInstantiateX % s.name.s)
  50. t = errorType(c)
  51. elif t.kind in {tyGenericParam, tyConcept, tyFromExpr} or
  52. # generic body types are accepted as typedesc arguments
  53. (t.kind == tyGenericBody and q.typ.kind != tyTypeDesc):
  54. localError(c.config, a.info, errCannotInstantiateX % q.name.s)
  55. t = errorType(c)
  56. elif isUnresolvedStatic(t) and (q.typ.kind == tyStatic or
  57. (q.typ.kind == tyGenericParam and
  58. q.typ.genericParamHasConstraints and
  59. q.typ.genericConstraint.kind == tyStatic)) and
  60. c.inGenericContext == 0 and c.matchedConcept == nil:
  61. # generic/concept type bodies will try to instantiate static values but
  62. # won't actually use them
  63. localError(c.config, a.info, errCannotInstantiateX % q.name.s)
  64. t = errorType(c)
  65. elif t.kind == tyGenericInvocation:
  66. #t = instGenericContainer(c, a, t)
  67. t = generateTypeInstance(c, pt, a, t)
  68. #t = ReplaceTypeVarsT(cl, t)
  69. s.typ = t
  70. if t.kind == tyStatic: s.ast = t.n
  71. yield s
  72. proc sameInstantiation(a, b: TInstantiation): bool =
  73. if a.concreteTypes.len == b.concreteTypes.len:
  74. for i in 0..a.concreteTypes.high:
  75. if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
  76. flags = {ExactTypeDescValues,
  77. ExactGcSafety,
  78. PickyCAliases}): return
  79. result = true
  80. else:
  81. result = false
  82. proc genericCacheGet(g: ModuleGraph; genericSym: PSym, entry: TInstantiation;
  83. id: CompilesId): PSym =
  84. result = nil
  85. for inst in procInstCacheItems(g, genericSym):
  86. if (inst.compilesId == 0 or inst.compilesId == id) and sameInstantiation(entry, inst[]):
  87. return inst.sym
  88. when false:
  89. proc `$`(x: PSym): string =
  90. result = x.name.s & " " & " id " & $x.id
  91. proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var SymMapping) =
  92. # we need to create a fresh set of gensym'ed symbols:
  93. #if n.kind == nkSym and sfGenSym in n.sym.flags:
  94. # if n.sym.owner != orig:
  95. # echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner
  96. if n.kind == nkSym and sfGenSym in n.sym.flags: # and
  97. # (n.sym.owner == orig or n.sym.owner.kind in {skPackage}):
  98. let s = n.sym
  99. var x = idTableGet(symMap, s)
  100. if x != nil:
  101. n.sym = x
  102. elif s.owner == nil or s.owner.kind == skPackage:
  103. #echo "copied this ", s.name.s
  104. x = copySym(s, c.idgen)
  105. setOwner(x, owner)
  106. idTablePut(symMap, s, x)
  107. n.sym = x
  108. else:
  109. for i in 0..<n.safeLen: freshGenSyms(c, n[i], owner, orig, symMap)
  110. proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
  111. proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
  112. if n[bodyPos].kind != nkEmpty:
  113. let procParams = result.typ.n
  114. for i in 1..<procParams.len:
  115. addDecl(c, procParams[i].sym)
  116. maybeAddResult(c, result, result.ast)
  117. inc c.inGenericInst
  118. # add it here, so that recursive generic procs are possible:
  119. var b = n[bodyPos]
  120. var symMap = initSymMapping()
  121. if params != nil:
  122. for i in 1..<params.len:
  123. let param = params[i].sym
  124. if sfGenSym in param.flags:
  125. idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
  126. freshGenSyms(c, b, result, orig, symMap)
  127. if sfBorrow notin orig.flags:
  128. # We do not want to generate a body for generic borrowed procs.
  129. # As body is a sym to the borrowed proc.
  130. let resultType = # todo probably refactor it into a function
  131. if result.kind == skMacro:
  132. sysTypeFromName(c.graph, n.info, "NimNode")
  133. elif not isInlineIterator(result.typ):
  134. result.typ.returnType
  135. else:
  136. nil
  137. b = semProcBody(c, b, resultType)
  138. result.ast[bodyPos] = hloBody(c, b)
  139. excl(result.flags, sfForward)
  140. trackProc(c, result, result.ast[bodyPos])
  141. dec c.inGenericInst
  142. proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
  143. for i in 0..<c.generics.len:
  144. if c.generics[i].genericSym.id == s.id:
  145. var oldPrc = c.generics[i].inst.sym
  146. pushProcCon(c, oldPrc)
  147. pushOwner(c, oldPrc)
  148. pushInfoContext(c.config, oldPrc.info)
  149. openScope(c)
  150. var n = oldPrc.ast
  151. n[bodyPos] = copyTree(getBody(c.graph, s))
  152. instantiateBody(c, n, oldPrc.typ.n, oldPrc, s)
  153. closeScope(c)
  154. popInfoContext(c.config)
  155. popOwner(c)
  156. popProcCon(c)
  157. proc sideEffectsCheck(c: PContext, s: PSym) =
  158. when false:
  159. if {sfNoSideEffect, sfSideEffect} * s.flags ==
  160. {sfNoSideEffect, sfSideEffect}:
  161. localError(s.info, errXhasSideEffects, s.name.s)
  162. proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
  163. allowMetaTypes = false): PType =
  164. internalAssert c.config, header.kind == tyGenericInvocation
  165. var cl: TReplTypeVars = TReplTypeVars(symMap: initSymMapping(),
  166. localCache: initTypeMapping(), typeMap: LayeredIdTable(),
  167. info: info, c: c, allowMetaTypes: allowMetaTypes
  168. )
  169. cl.typeMap.topLayer = initTypeMapping()
  170. # We must add all generic params in scope, because the generic body
  171. # may include tyFromExpr nodes depending on these generic params.
  172. # XXX: This looks quite similar to the code in matchUserTypeClass,
  173. # perhaps the code can be extracted in a shared function.
  174. openScope(c)
  175. let genericTyp = header.base
  176. for i, genParam in genericBodyParams(genericTyp):
  177. var param: PSym
  178. template paramSym(kind): untyped =
  179. newSym(kind, genParam.sym.name, c.idgen, genericTyp.sym, genParam.sym.info)
  180. if genParam.kind == tyStatic:
  181. param = paramSym skConst
  182. param.ast = header[i+1].n
  183. param.typ = header[i+1]
  184. else:
  185. param = paramSym skType
  186. param.typ = makeTypeDesc(c, header[i+1])
  187. # this scope was not created by the user,
  188. # unused params shouldn't be reported.
  189. param.flags.incl sfUsed
  190. addDecl(c, param)
  191. result = replaceTypeVarsT(cl, header)
  192. closeScope(c)
  193. proc referencesAnotherParam(n: PNode, p: PSym): bool =
  194. if n.kind == nkSym:
  195. return n.sym.kind == skParam and n.sym.owner == p
  196. else:
  197. for i in 0..<n.safeLen:
  198. if referencesAnotherParam(n[i], p): return true
  199. return false
  200. proc instantiateProcType(c: PContext, pt: LayeredIdTable,
  201. prc: PSym, info: TLineInfo) =
  202. # XXX: Instantiates a generic proc signature, while at the same
  203. # time adding the instantiated proc params into the current scope.
  204. # This is necessary, because the instantiation process may refer to
  205. # these params in situations like this:
  206. # proc foo[Container](a: Container, b: a.type.Item): typeof(b.x)
  207. #
  208. # Alas, doing this here is probably not enough, because another
  209. # proc signature could appear in the params:
  210. # proc foo[T](a: proc (x: T, b: typeof(x.y))
  211. #
  212. # The solution would be to move this logic into semtypinst, but
  213. # at this point semtypinst have to become part of sem, because it
  214. # will need to use openScope, addDecl, etc.
  215. #addDecl(c, prc)
  216. pushInfoContext(c.config, info)
  217. var typeMap = shallowCopy(pt) # use previous bindings without writing to them
  218. var cl = initTypeVars(c, typeMap, info, nil)
  219. var result = instCopyType(cl, prc.typ)
  220. let originalParams = result.n
  221. result.n = originalParams.shallowCopy
  222. for i, resulti in paramTypes(result):
  223. # twrong_field_caching requires these 'resetIdTable' calls:
  224. if i > FirstParamAt:
  225. resetIdTable(cl.symMap)
  226. resetIdTable(cl.localCache)
  227. # take a note of the original type. If't a free type or static parameter
  228. # we'll need to keep it unbound for the `fitNode` operation below...
  229. var typeToFit = resulti
  230. let needsStaticSkipping = resulti.kind == tyFromExpr
  231. let needsTypeDescSkipping = resulti.kind == tyTypeDesc and tfUnresolved in resulti.flags
  232. if resulti.kind == tyFromExpr:
  233. resulti.flags.incl tfNonConstExpr
  234. result[i] = replaceTypeVarsT(cl, resulti)
  235. if needsStaticSkipping:
  236. result[i] = result[i].skipTypes({tyStatic})
  237. if needsTypeDescSkipping:
  238. result[i] = result[i].skipTypes({tyTypeDesc})
  239. typeToFit = result[i]
  240. # ...otherwise, we use the instantiated type in `fitNode`
  241. if (typeToFit.kind != tyTypeDesc or typeToFit.base.kind != tyNone) and
  242. (typeToFit.kind != tyStatic):
  243. typeToFit = result[i]
  244. internalAssert c.config, originalParams[i].kind == nkSym
  245. let oldParam = originalParams[i].sym
  246. let param = copySym(oldParam, c.idgen)
  247. setOwner(param, prc)
  248. param.typ = result[i]
  249. # The default value is instantiated and fitted against the final
  250. # concrete param type. We avoid calling `replaceTypeVarsN` on the
  251. # call head symbol, because this leads to infinite recursion.
  252. if oldParam.ast != nil:
  253. var def = oldParam.ast.copyTree
  254. if def.typ.kind == tyFromExpr:
  255. def.typ.flags.incl tfNonConstExpr
  256. if not isIntLit(def.typ):
  257. def = prepareNode(cl, def)
  258. # allow symchoice since node will be fit later
  259. # although expectedType should cover it
  260. def = semExprWithType(c, def, {efAllowSymChoice}, typeToFit)
  261. if def.referencesAnotherParam(getCurrOwner(c)):
  262. def.flags.incl nfDefaultRefsParam
  263. var converted = indexTypesMatch(c, typeToFit, def.typ, def)
  264. if converted == nil:
  265. # The default value doesn't match the final instantiated type.
  266. # As an example of this, see:
  267. # https://github.com/nim-lang/Nim/issues/1201
  268. # We are replacing the default value with an error node in case
  269. # the user calls an explicit instantiation of the proc (this is
  270. # the only way the default value might be inserted).
  271. param.ast = errorNode(c, def)
  272. # we know the node is empty, we need the actual type for error message
  273. param.ast.typ() = def.typ
  274. else:
  275. param.ast = fitNodePostMatch(c, typeToFit, converted)
  276. param.typ = result[i]
  277. result.n[i] = newSymNode(param)
  278. propagateToOwner(result, result[i])
  279. addDecl(c, param)
  280. resetIdTable(cl.symMap)
  281. resetIdTable(cl.localCache)
  282. cl.isReturnType = true
  283. result.setReturnType replaceTypeVarsT(cl, result.returnType)
  284. cl.isReturnType = false
  285. result.n[0] = originalParams[0].copyTree
  286. if result[0] != nil:
  287. propagateToOwner(result, result[0])
  288. eraseVoidParams(result)
  289. skipIntLiteralParams(result, c.idgen)
  290. prc.typ = result
  291. popInfoContext(c.config)
  292. proc instantiateOnlyProcType(c: PContext, pt: LayeredIdTable, prc: PSym, info: TLineInfo): PType =
  293. # instantiates only the type of a given proc symbol
  294. # used by sigmatch for explicit generics
  295. # wouldn't be needed if sigmatch could handle complex cases,
  296. # examples are in texplicitgenerics
  297. # might be buggy, see rest of generateInstance if problems occur
  298. let fakeSym = copySym(prc, c.idgen)
  299. incl(fakeSym.flags, sfFromGeneric)
  300. fakeSym.instantiatedFrom = prc
  301. openScope(c)
  302. for s in instantiateGenericParamList(c, prc.ast[genericParamsPos], pt):
  303. addDecl(c, s)
  304. instantiateProcType(c, pt, fakeSym, info)
  305. closeScope(c)
  306. result = fakeSym.typ
  307. proc fillMixinScope(c: PContext) =
  308. var p = c.p
  309. while p != nil:
  310. for bnd in p.localBindStmts:
  311. for n in bnd:
  312. addSym(c.currentScope, n.sym)
  313. p = p.next
  314. proc getLocalPassC(c: PContext, s: PSym): string =
  315. when defined(nimsuggest): return ""
  316. if s.ast == nil or s.ast.len == 0: return ""
  317. result = ""
  318. template extractPassc(p: PNode) =
  319. if p.kind == nkPragma and p[0][0].ident == c.cache.getIdent"localpassc":
  320. return p[0][1].strVal
  321. extractPassc(s.ast[0]) #it is set via appendToModule in pragmas (fast access)
  322. for n in s.ast:
  323. for p in n:
  324. extractPassc(p)
  325. proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
  326. info: TLineInfo): PSym =
  327. ## Generates a new instance of a generic procedure.
  328. ## The `pt` parameter is a type-unsafe mapping table used to link generic
  329. ## parameters to their concrete types within the generic instance.
  330. # no need to instantiate generic templates/macros:
  331. internalAssert c.config, fn.kind notin {skMacro, skTemplate}
  332. # generates an instantiated proc
  333. if c.instCounter > 50:
  334. globalError(c.config, info, "generic instantiation too nested")
  335. inc c.instCounter
  336. let currentTypeofContext = c.inTypeofContext
  337. c.inTypeofContext = 0
  338. defer:
  339. dec c.instCounter
  340. c.inTypeofContext = currentTypeofContext
  341. # careful! we copy the whole AST including the possibly nil body!
  342. var n = copyTree(fn.ast)
  343. # NOTE: for access of private fields within generics from a different module
  344. # we set the friend module:
  345. let producer = getModule(fn)
  346. c.friendModules.add(producer)
  347. let oldMatchedConcept = c.matchedConcept
  348. c.matchedConcept = nil
  349. let oldScope = c.currentScope
  350. while not isTopLevel(c): c.currentScope = c.currentScope.parent
  351. result = copySym(fn, c.idgen)
  352. incl(result.flags, sfFromGeneric)
  353. result.instantiatedFrom = fn
  354. if sfGlobal in result.flags and c.config.symbolFiles != disabledSf:
  355. let passc = getLocalPassC(c, producer)
  356. if passc != "": #pass the local compiler options to the consumer module too
  357. extccomp.addLocalCompileOption(c.config, passc, toFullPathConsiderDirty(c.config, c.module.info.fileIndex))
  358. setOwner(result, c.module)
  359. else:
  360. setOwner(result, fn)
  361. result.ast = n
  362. pushOwner(c, result)
  363. # mixin scope:
  364. openScope(c)
  365. fillMixinScope(c)
  366. openScope(c)
  367. let gp = n[genericParamsPos]
  368. if gp.kind != nkGenericParams:
  369. # bug #22137
  370. globalError(c.config, info, "generic instantiation too nested")
  371. n[namePos] = newSymNode(result)
  372. pushInfoContext(c.config, info, fn.detailedInfo)
  373. var entry = TInstantiation.new
  374. entry.sym = result
  375. # we need to compare both the generic types and the concrete types:
  376. # generic[void](), generic[int]()
  377. # see ttypeor.nim test.
  378. var i = 0
  379. newSeq(entry.concreteTypes, fn.typ.paramsLen+gp.len)
  380. # let param instantiation know we are in a concept for unresolved statics:
  381. c.matchedConcept = oldMatchedConcept
  382. for s in instantiateGenericParamList(c, gp, pt):
  383. addDecl(c, s)
  384. entry.concreteTypes[i] = s.typ
  385. inc i
  386. c.matchedConcept = nil
  387. pushProcCon(c, result)
  388. instantiateProcType(c, pt, result, info)
  389. for _, param in paramTypes(result.typ):
  390. entry.concreteTypes[i] = param
  391. inc i
  392. #echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " ", entry.concreteTypes.len
  393. if tfTriggersCompileTime in result.typ.flags:
  394. incl(result.flags, sfCompileTime)
  395. n[genericParamsPos] = c.graph.emptyNode
  396. var oldPrc = genericCacheGet(c.graph, fn, entry[], c.compilesContextId)
  397. if oldPrc == nil:
  398. # we MUST not add potentially wrong instantiations to the caching mechanism.
  399. # This means recursive instantiations behave differently when in
  400. # a ``compiles`` context but this is the lesser evil. See
  401. # bug #1055 (tevilcompiles).
  402. #if c.compilesContextId == 0:
  403. entry.compilesId = c.compilesContextId
  404. addToGenericProcCache(c, fn, entry)
  405. c.generics.add(makeInstPair(fn, entry))
  406. # bug #12985 bug #22913
  407. # TODO: use the context of the declaration of generic functions instead
  408. # TODO: consider fixing options as well
  409. let otherPragmas = c.optionStack[^1].otherPragmas
  410. c.optionStack[^1].otherPragmas = nil
  411. if n[pragmasPos].kind != nkEmpty:
  412. pragma(c, result, n[pragmasPos], allRoutinePragmas)
  413. if isNil(n[bodyPos]):
  414. n[bodyPos] = copyTree(getBody(c.graph, fn))
  415. instantiateBody(c, n, fn.typ.n, result, fn)
  416. c.optionStack[^1].otherPragmas = otherPragmas
  417. sideEffectsCheck(c, result)
  418. if result.magic notin {mSlice, mTypeOf}:
  419. # 'toOpenArray' is special and it is allowed to return 'openArray':
  420. paramsTypeCheck(c, result.typ)
  421. #echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- NEW PROC!", " ", entry.concreteTypes.len
  422. else:
  423. #echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- CACHED! ", typeToString(oldPrc.typ), " ", entry.concreteTypes.len
  424. result = oldPrc
  425. popProcCon(c)
  426. popInfoContext(c.config)
  427. closeScope(c) # close scope for parameters
  428. closeScope(c) # close scope for 'mixin' declarations
  429. popOwner(c)
  430. c.currentScope = oldScope
  431. discard c.friendModules.pop()
  432. c.matchedConcept = oldMatchedConcept
  433. if result.kind == skMethod: finishMethod(c, result)
  434. # inform IC of the generic
  435. #addGeneric(c.ic, result, entry.concreteTypes)