seminst.nim 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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 countup(0, len(n)-1):
  16. rec n[i]
  17. of nkRecCase:
  18. if n.len > 0: rec n.sons[0]
  19. for i in countup(1, len(n)-1):
  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 rawPushProcCon(c: PContext, owner: PSym) =
  29. var x: PProcCon
  30. new(x)
  31. x.owner = owner
  32. x.next = c.p
  33. c.p = x
  34. proc rawHandleSelf(c: PContext; owner: PSym) =
  35. const callableSymbols = {skProc, skFunc, skMethod, skConverter, skIterator, skMacro}
  36. if c.selfName != nil and owner.kind in callableSymbols and owner.typ != nil:
  37. let params = owner.typ.n
  38. if params.len > 1:
  39. let arg = params[1].sym
  40. if arg.name.id == c.selfName.id:
  41. c.p.selfSym = arg
  42. arg.flags.incl sfIsSelf
  43. var t = c.p.selfSym.typ.skipTypes(abstractPtrs)
  44. while t.kind == tyObject:
  45. addObjFieldsToLocalScope(c, t.n)
  46. if t.sons[0] == nil: break
  47. t = t.sons[0].skipTypes(skipPtrs)
  48. proc pushProcCon*(c: PContext; owner: PSym) =
  49. rawPushProcCon(c, owner)
  50. rawHandleSelf(c, owner)
  51. const
  52. errCannotInstantiateX = "cannot instantiate: '$1'"
  53. iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
  54. internalAssert c.config, n.kind == nkGenericParams
  55. for i, a in n.pairs:
  56. internalAssert c.config, a.kind == nkSym
  57. var q = a.sym
  58. if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses:
  59. continue
  60. let symKind = if q.typ.kind == tyStatic: skConst else: skType
  61. var s = newSym(symKind, q.name, getCurrOwner(c), q.info)
  62. s.flags = s.flags + {sfUsed, sfFromGeneric}
  63. var t = PType(idTableGet(pt, q.typ))
  64. if t == nil:
  65. if tfRetType in q.typ.flags:
  66. # keep the generic type and allow the return type to be bound
  67. # later by semAsgn in return type inference scenario
  68. t = q.typ
  69. else:
  70. localError(c.config, a.info, errCannotInstantiateX % s.name.s)
  71. t = errorType(c)
  72. elif t.kind == tyGenericParam:
  73. localError(c.config, a.info, errCannotInstantiateX % q.name.s)
  74. t = errorType(c)
  75. elif t.kind == tyGenericInvocation:
  76. #t = instGenericContainer(c, a, t)
  77. t = generateTypeInstance(c, pt, a, t)
  78. #t = ReplaceTypeVarsT(cl, t)
  79. s.typ = t
  80. if t.kind == tyStatic: s.ast = t.n
  81. yield s
  82. proc sameInstantiation(a, b: TInstantiation): bool =
  83. if a.concreteTypes.len == b.concreteTypes.len:
  84. for i in 0..a.concreteTypes.high:
  85. if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
  86. flags = {ExactTypeDescValues,
  87. ExactGcSafety}): return
  88. result = true
  89. proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
  90. id: CompilesId): PSym =
  91. for inst in genericSym.procInstCache:
  92. if inst.compilesId == id and sameInstantiation(entry, inst[]):
  93. return inst.sym
  94. when false:
  95. proc `$`(x: PSym): string =
  96. result = x.name.s & " " & " id " & $x.id
  97. proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
  98. # we need to create a fresh set of gensym'ed symbols:
  99. #if n.kind == nkSym and sfGenSym in n.sym.flags:
  100. # if n.sym.owner != orig:
  101. # echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner
  102. if n.kind == nkSym and sfGenSym in n.sym.flags: # and
  103. # (n.sym.owner == orig or n.sym.owner.kind in {skPackage}):
  104. let s = n.sym
  105. var x = PSym(idTableGet(symMap, s))
  106. if x != nil:
  107. n.sym = x
  108. elif s.owner == nil or s.owner.kind == skPackage:
  109. #echo "copied this ", s.name.s
  110. x = copySym(s)
  111. x.owner = owner
  112. idTablePut(symMap, s, x)
  113. n.sym = x
  114. else:
  115. for i in 0 ..< safeLen(n): freshGenSyms(n.sons[i], owner, orig, symMap)
  116. proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
  117. proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
  118. if n.sons[bodyPos].kind != nkEmpty:
  119. let procParams = result.typ.n
  120. for i in 1 ..< procParams.len:
  121. addDecl(c, procParams[i].sym)
  122. maybeAddResult(c, result, result.ast)
  123. inc c.inGenericInst
  124. # add it here, so that recursive generic procs are possible:
  125. var b = n.sons[bodyPos]
  126. var symMap: TIdTable
  127. initIdTable symMap
  128. if params != nil:
  129. for i in 1 ..< params.len:
  130. let param = params[i].sym
  131. if sfGenSym in param.flags:
  132. idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
  133. freshGenSyms(b, result, orig, symMap)
  134. b = semProcBody(c, b)
  135. result.ast[bodyPos] = hloBody(c, b)
  136. trackProc(c.graph, result, result.ast[bodyPos])
  137. excl(result.flags, sfForward)
  138. dec c.inGenericInst
  139. proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
  140. for i in countup(0, c.generics.len - 1):
  141. if c.generics[i].genericSym.id == s.id:
  142. var oldPrc = c.generics[i].inst.sym
  143. pushProcCon(c, oldPrc)
  144. pushOwner(c, oldPrc)
  145. pushInfoContext(c.config, oldPrc.info)
  146. openScope(c)
  147. var n = oldPrc.ast
  148. n.sons[bodyPos] = copyTree(s.getBody)
  149. instantiateBody(c, n, oldPrc.typ.n, oldPrc, s)
  150. closeScope(c)
  151. popInfoContext(c.config)
  152. popOwner(c)
  153. popProcCon(c)
  154. proc sideEffectsCheck(c: PContext, s: PSym) =
  155. when false:
  156. if {sfNoSideEffect, sfSideEffect} * s.flags ==
  157. {sfNoSideEffect, sfSideEffect}:
  158. localError(s.info, errXhasSideEffects, s.name.s)
  159. proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
  160. allowMetaTypes = false): PType =
  161. internalAssert c.config, header.kind == tyGenericInvocation
  162. var
  163. typeMap: LayeredIdTable
  164. cl: TReplTypeVars
  165. initIdTable(cl.symMap)
  166. initIdTable(cl.localCache)
  167. initIdTable(typeMap.topLayer)
  168. cl.typeMap = addr(typeMap)
  169. cl.info = info
  170. cl.c = c
  171. cl.allowMetaTypes = allowMetaTypes
  172. # We must add all generic params in scope, because the generic body
  173. # may include tyFromExpr nodes depending on these generic params.
  174. # XXX: This looks quite similar to the code in matchUserTypeClass,
  175. # perhaps the code can be extracted in a shared function.
  176. openScope(c)
  177. let genericTyp = header.base
  178. for i in 0 .. (genericTyp.len - 2):
  179. let genParam = genericTyp[i]
  180. var param: PSym
  181. template paramSym(kind): untyped =
  182. newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
  183. if genParam.kind == tyStatic:
  184. param = paramSym skConst
  185. param.ast = header[i+1].n
  186. param.typ = header[i+1]
  187. else:
  188. param = paramSym skType
  189. param.typ = makeTypeDesc(c, header[i+1])
  190. # this scope was not created by the user,
  191. # unused params shoudn't be reported.
  192. param.flags.incl sfUsed
  193. addDecl(c, param)
  194. result = replaceTypeVarsT(cl, header)
  195. closeScope(c)
  196. proc referencesAnotherParam(n: PNode, p: PSym): bool =
  197. if n.kind == nkSym:
  198. return n.sym.kind == skParam and n.sym.owner == p
  199. else:
  200. for i in 0..<n.safeLen:
  201. if referencesAnotherParam(n[i], p): return true
  202. return false
  203. proc instantiateProcType(c: PContext, pt: TIdTable,
  204. prc: PSym, info: TLineInfo) =
  205. # XXX: Instantiates a generic proc signature, while at the same
  206. # time adding the instantiated proc params into the current scope.
  207. # This is necessary, because the instantiation process may refer to
  208. # these params in situations like this:
  209. # proc foo[Container](a: Container, b: a.type.Item): type(b.x)
  210. #
  211. # Alas, doing this here is probably not enough, because another
  212. # proc signature could appear in the params:
  213. # proc foo[T](a: proc (x: T, b: type(x.y))
  214. #
  215. # The solution would be to move this logic into semtypinst, but
  216. # at this point semtypinst have to become part of sem, because it
  217. # will need to use openScope, addDecl, etc.
  218. #addDecl(c, prc)
  219. pushInfoContext(c.config, info)
  220. var typeMap = initLayeredTypeMap(pt)
  221. var cl = initTypeVars(c, addr(typeMap), info, nil)
  222. var result = instCopyType(cl, prc.typ)
  223. let originalParams = result.n
  224. result.n = originalParams.shallowCopy
  225. for i in 1 ..< result.len:
  226. # twrong_field_caching requires these 'resetIdTable' calls:
  227. if i > 1:
  228. resetIdTable(cl.symMap)
  229. resetIdTable(cl.localCache)
  230. # take a note of the original type. If't a free type or static parameter
  231. # we'll need to keep it unbound for the `fitNode` operation below...
  232. var typeToFit = result[i]
  233. let needsStaticSkipping = result[i].kind == tyFromExpr
  234. result[i] = replaceTypeVarsT(cl, result[i])
  235. if needsStaticSkipping:
  236. result[i] = result[i].skipTypes({tyStatic})
  237. # ...otherwise, we use the instantiated type in `fitNode`
  238. if (typeToFit.kind != tyTypeDesc or typeToFit.base.kind != tyNone) and
  239. (typeToFit.kind != tyStatic):
  240. typeToFit = result[i]
  241. internalAssert c.config, originalParams[i].kind == nkSym
  242. let oldParam = originalParams[i].sym
  243. let param = copySym(oldParam)
  244. param.owner = prc
  245. param.typ = result[i]
  246. # The default value is instantiated and fitted against the final
  247. # concrete param type. We avoid calling `replaceTypeVarsN` on the
  248. # call head symbol, because this leads to infinite recursion.
  249. if oldParam.ast != nil:
  250. var def = oldParam.ast.copyTree
  251. if def.kind == nkCall:
  252. for i in 1 ..< def.len:
  253. def[i] = replaceTypeVarsN(cl, def[i])
  254. def = semExprWithType(c, def)
  255. if def.referencesAnotherParam(getCurrOwner(c)):
  256. def.flags.incl nfDefaultRefsParam
  257. var converted = indexTypesMatch(c, typeToFit, def.typ, def)
  258. if converted == nil:
  259. # The default value doesn't match the final instantiated type.
  260. # As an example of this, see:
  261. # https://github.com/nim-lang/Nim/issues/1201
  262. # We are replacing the default value with an error node in case
  263. # the user calls an explicit instantiation of the proc (this is
  264. # the only way the default value might be inserted).
  265. param.ast = errorNode(c, def)
  266. else:
  267. param.ast = fitNodePostMatch(c, typeToFit, converted)
  268. param.typ = result[i]
  269. result.n[i] = newSymNode(param)
  270. propagateToOwner(result, result[i])
  271. addDecl(c, param)
  272. resetIdTable(cl.symMap)
  273. resetIdTable(cl.localCache)
  274. result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
  275. result.n.sons[0] = originalParams[0].copyTree
  276. if result.sons[0] != nil:
  277. propagateToOwner(result, result.sons[0])
  278. eraseVoidParams(result)
  279. skipIntLiteralParams(result)
  280. prc.typ = result
  281. popInfoContext(c.config)
  282. proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
  283. info: TLineInfo): PSym =
  284. ## Generates a new instance of a generic procedure.
  285. ## The `pt` parameter is a type-unsafe mapping table used to link generic
  286. ## parameters to their concrete types within the generic instance.
  287. # no need to instantiate generic templates/macros:
  288. internalAssert c.config, fn.kind notin {skMacro, skTemplate}
  289. # generates an instantiated proc
  290. if c.instCounter > 50:
  291. globalError(c.config, info, "generic instantiation too nested")
  292. inc(c.instCounter)
  293. # careful! we copy the whole AST including the possibly nil body!
  294. var n = copyTree(fn.ast)
  295. # NOTE: for access of private fields within generics from a different module
  296. # we set the friend module:
  297. c.friendModules.add(getModule(fn))
  298. let oldMatchedConcept = c.matchedConcept
  299. c.matchedConcept = nil
  300. let oldScope = c.currentScope
  301. while not isTopLevel(c): c.currentScope = c.currentScope.parent
  302. result = copySym(fn)
  303. incl(result.flags, sfFromGeneric)
  304. result.owner = fn
  305. result.ast = n
  306. pushOwner(c, result)
  307. openScope(c)
  308. let gp = n.sons[genericParamsPos]
  309. internalAssert c.config, gp.kind != nkEmpty
  310. n.sons[namePos] = newSymNode(result)
  311. pushInfoContext(c.config, info, fn.detailedInfo)
  312. var entry = TInstantiation.new
  313. entry.sym = result
  314. # we need to compare both the generic types and the concrete types:
  315. # generic[void](), generic[int]()
  316. # see ttypeor.nim test.
  317. var i = 0
  318. newSeq(entry.concreteTypes, fn.typ.len+gp.len-1)
  319. for s in instantiateGenericParamList(c, gp, pt):
  320. addDecl(c, s)
  321. entry.concreteTypes[i] = s.typ
  322. inc i
  323. rawPushProcCon(c, result)
  324. instantiateProcType(c, pt, result, info)
  325. for j in 1 .. result.typ.len-1:
  326. entry.concreteTypes[i] = result.typ.sons[j]
  327. inc i
  328. if tfTriggersCompileTime in result.typ.flags:
  329. incl(result.flags, sfCompileTime)
  330. n.sons[genericParamsPos] = c.graph.emptyNode
  331. var oldPrc = genericCacheGet(fn, entry[], c.compilesContextId)
  332. if oldPrc == nil:
  333. # we MUST not add potentially wrong instantiations to the caching mechanism.
  334. # This means recursive instantiations behave differently when in
  335. # a ``compiles`` context but this is the lesser evil. See
  336. # bug #1055 (tevilcompiles).
  337. #if c.compilesContextId == 0:
  338. rawHandleSelf(c, result)
  339. entry.compilesId = c.compilesContextId
  340. fn.procInstCache.add(entry)
  341. c.generics.add(makeInstPair(fn, entry))
  342. if n.sons[pragmasPos].kind != nkEmpty:
  343. pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
  344. if isNil(n.sons[bodyPos]):
  345. n.sons[bodyPos] = copyTree(fn.getBody)
  346. if c.inGenericContext == 0:
  347. instantiateBody(c, n, fn.typ.n, result, fn)
  348. sideEffectsCheck(c, result)
  349. if result.magic != mSlice:
  350. # 'toOpenArray' is special and it is allowed to return 'openArray':
  351. paramsTypeCheck(c, result.typ)
  352. else:
  353. result = oldPrc
  354. popProcCon(c)
  355. popInfoContext(c.config)
  356. closeScope(c) # close scope for parameters
  357. popOwner(c)
  358. c.currentScope = oldScope
  359. discard c.friendModules.pop()
  360. dec(c.instCounter)
  361. c.matchedConcept = oldMatchedConcept
  362. if result.kind == skMethod: finishMethod(c, result)