isolation_check.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2020 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Implementation of the check that `recover` needs, see
  10. ## https://github.com/nim-lang/RFCs/issues/244 for more details.
  11. import
  12. ast, types, renderer, idents, intsets
  13. proc canAlias(arg, ret: PType; marker: var IntSet): bool
  14. proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
  15. case n.kind
  16. of nkRecList:
  17. for i in 0..<n.len:
  18. result = canAliasN(arg, n[i], marker)
  19. if result: return
  20. of nkRecCase:
  21. assert(n[0].kind == nkSym)
  22. result = canAliasN(arg, n[0], marker)
  23. if result: return
  24. for i in 1..<n.len:
  25. case n[i].kind
  26. of nkOfBranch, nkElse:
  27. result = canAliasN(arg, lastSon(n[i]), marker)
  28. if result: return
  29. else: discard
  30. of nkSym:
  31. result = canAlias(arg, n.sym.typ, marker)
  32. else: discard
  33. proc canAlias(arg, ret: PType; marker: var IntSet): bool =
  34. if containsOrIncl(marker, ret.id):
  35. return false
  36. if ret.kind in {tyPtr, tyPointer}:
  37. # unsafe so we don't care:
  38. return false
  39. if compareTypes(arg, ret, dcEqIgnoreDistinct):
  40. return true
  41. case ret.kind
  42. of tyObject:
  43. if isFinal(ret):
  44. result = canAliasN(arg, ret.n, marker)
  45. if not result and ret.len > 0 and ret[0] != nil:
  46. result = canAlias(arg, ret[0], marker)
  47. else:
  48. result = true
  49. of tyTuple:
  50. for i in 0..<ret.len:
  51. result = canAlias(arg, ret[i], marker)
  52. if result: break
  53. of tyArray, tySequence, tyDistinct, tyGenericInst,
  54. tyAlias, tyInferred, tySink, tyLent, tyOwned, tyRef:
  55. result = canAlias(arg, ret.lastSon, marker)
  56. of tyProc:
  57. result = ret.callConv == ccClosure
  58. else:
  59. result = false
  60. proc canAlias*(arg, ret: PType): bool =
  61. var marker = initIntSet()
  62. result = canAlias(arg, ret, marker)
  63. proc checkIsolate*(n: PNode): bool =
  64. if types.containsTyRef(n.typ):
  65. # XXX Maybe require that 'n.typ' is acyclic. This is not much
  66. # worse than the already exisiting inheritance and closure restrictions.
  67. case n.kind
  68. of nkCharLit..nkNilLit:
  69. result = true
  70. of nkCallKinds:
  71. if n[0].typ.flags * {tfGcSafe, tfNoSideEffect} == {}:
  72. return false
  73. for i in 1..<n.len:
  74. if checkIsolate(n[i]):
  75. discard "fine, it is isolated already"
  76. else:
  77. let argType = n[i].typ
  78. if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
  79. if argType.canAlias(n.typ):
  80. return false
  81. result = true
  82. of nkIfStmt, nkIfExpr:
  83. for it in n:
  84. result = checkIsolate(it.lastSon)
  85. if not result: break
  86. of nkCaseStmt, nkObjConstr:
  87. for i in 1..<n.len:
  88. result = checkIsolate(n[i].lastSon)
  89. if not result: break
  90. of nkBracket, nkTupleConstr, nkPar:
  91. for it in n:
  92. result = checkIsolate(it)
  93. if not result: break
  94. of nkHiddenStdConv, nkHiddenSubConv, nkCast, nkConv:
  95. result = checkIsolate(n[1])
  96. of nkObjUpConv, nkObjDownConv, nkDotExpr:
  97. result = checkIsolate(n[0])
  98. of nkStmtList, nkStmtListExpr:
  99. if n.len > 0:
  100. result = checkIsolate(n[^1])
  101. else:
  102. result = false
  103. else:
  104. # unanalysable expression:
  105. result = false
  106. else:
  107. # no ref, no cry:
  108. result = true