procfind.nim 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2013 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 searching for procs and iterators.
  10. # This is needed for proper handling of forward declarations.
  11. import
  12. ast, astalgo, msgs, semdata, types, trees, lookups
  13. import std/strutils
  14. proc equalGenericParams(procA, procB: PNode): bool =
  15. if procA.len != procB.len: return false
  16. for i in 0..<procA.len:
  17. if procA[i].kind != nkSym:
  18. return false
  19. if procB[i].kind != nkSym:
  20. return false
  21. let a = procA[i].sym
  22. let b = procB[i].sym
  23. if a.name.id != b.name.id or
  24. not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
  25. if a.ast != nil and b.ast != nil:
  26. if not exprStructuralEquivalent(a.ast, b.ast): return
  27. result = true
  28. proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
  29. const flags = {ExactGenericParams, ExactTypeDescValues,
  30. ExactConstraints, IgnoreCC}
  31. var it: TIdentIter = default(TIdentIter)
  32. result = initIdentIter(it, scope.symbols, fn.name)
  33. while result != nil:
  34. if result.kind == fn.kind: #and sameType(result.typ, fn.typ, flags):
  35. case equalParams(result.typ.n, fn.typ.n)
  36. of paramsEqual:
  37. if (sfExported notin result.flags) and (sfExported in fn.flags):
  38. let message = ("public implementation '$1' has non-public " &
  39. "forward declaration at $2") %
  40. [getProcHeader(c.config, result, getDeclarationPath = false), c.config$result.info]
  41. localError(c.config, fn.info, message)
  42. return
  43. of paramsIncompatible:
  44. localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s)
  45. return
  46. of paramsNotEqual:
  47. discard
  48. result = nextIdentIter(it, scope.symbols)
  49. proc searchForProc*(c: PContext, scope: PScope, fn: PSym): tuple[proto: PSym, comesFromShadowScope: bool] =
  50. var scope = scope
  51. result = (searchForProcAux(c, scope, fn), false)
  52. while result.proto == nil and scope.isShadowScope:
  53. scope = scope.parent
  54. result.proto = searchForProcAux(c, scope, fn)
  55. result.comesFromShadowScope = true
  56. when false:
  57. proc paramsFitBorrow(child, parent: PNode): bool =
  58. result = false
  59. if child.len == parent.len:
  60. for i in 1..<child.len:
  61. var m = child[i].sym
  62. var n = parent[i].sym
  63. assert((m.kind == skParam) and (n.kind == skParam))
  64. if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return
  65. if not compareTypes(child[0].typ, parent[0].typ,
  66. dcEqOrDistinctOf): return
  67. result = true
  68. proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
  69. # Searches for the fn in the symbol table. If the parameter lists are suitable
  70. # for borrowing the sym in the symbol table is returned, else nil.
  71. var it: TIdentIter = default(TIdentIter)
  72. for scope in walkScopes(startScope):
  73. result = initIdentIter(it, scope.symbols, fn.Name)
  74. while result != nil:
  75. # watchout! result must not be the same as fn!
  76. if (result.Kind == fn.kind) and (result.id != fn.id):
  77. if equalGenericParams(result.ast[genericParamsPos],
  78. fn.ast[genericParamsPos]):
  79. if paramsFitBorrow(fn.typ.n, result.typ.n): return
  80. result = NextIdentIter(it, scope.symbols)