Test.hx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. class A {
  2. }
  3. class B extends A {
  4. function new() {
  5. init();
  6. Test.calls.push("B");
  7. }
  8. function init() {}
  9. }
  10. class C extends B {}
  11. class D extends C {
  12. var n = "D";
  13. override function init() Test.calls.push(n);
  14. }
  15. class E extends D {
  16. function new() {
  17. Test.use(this);
  18. Test.calls.push("E");
  19. super();
  20. }
  21. }
  22. class F extends E {
  23. public function new() {
  24. super();
  25. Test.calls.push("F");
  26. }
  27. }
  28. extern class ExtNoCtor {
  29. static function __init__():Void haxe.macro.Compiler.includeFile("./extern.js", "top");
  30. }
  31. class Base extends ExtNoCtor {
  32. function new() {
  33. Test.calls.push("BASE");
  34. }
  35. }
  36. class Child extends Base {
  37. public function new() {
  38. Test.use(this);
  39. Test.calls.push("CHILD");
  40. super();
  41. }
  42. }
  43. class Test {
  44. public static var calls:Array<String>;
  45. @:pure(false) public static function use(v:Any) {}
  46. static inline final hxCtor = "_hx_constructor";
  47. static inline final hxSkipCtor = "_hx_skip_constructor";
  48. static function hasCtorMethod(c:Dynamic):Bool {
  49. return c.prototype.hasOwnProperty(hxCtor);
  50. }
  51. static function hasSkip(c:Dynamic) {
  52. return c.hasOwnProperty(hxSkipCtor);
  53. }
  54. static var failures = 0;
  55. static function assert(bool:Bool, ?pos:haxe.PosInfos) {
  56. if (!bool) {
  57. (untyped process).stderr.write(haxe.Log.formatOutput("assertion failed\n", pos));
  58. failures++;
  59. }
  60. }
  61. static function main() {
  62. // A has no constructor, so it's safe to just call `super` first
  63. // even if we skip ctor in the subclasses
  64. assert(!hasCtorMethod(A));
  65. assert(!hasSkip(A));
  66. // B has an extracted ctor and also the static skip flag,
  67. // as it is the first in the hierarchy who's ctor needs to be skipped
  68. assert(hasCtorMethod(B));
  69. assert(hasSkip(B));
  70. // C and others down the chain should NOT have the static skip flag,
  71. // but it can have a hxctor (although in this case it could be optimized away)
  72. assert(!hasSkip(C));
  73. // D must have a hxctor because it accesses this before super (for field init)
  74. // it also supports skipping because it has children who want to skip
  75. assert(hasCtorMethod(D));
  76. assert(!hasSkip(D));
  77. // E also must have a hxctor because it accesses this before super
  78. // but it doesn't support skipping, because noone down the inheritance requires it
  79. assert(hasCtorMethod(E));
  80. assert(!hasSkip(E));
  81. // F should NOT have hxctor because it doesn't access this before super and
  82. // it has no children that require skipping
  83. assert(!hasCtorMethod(F));
  84. assert(!hasSkip(F));
  85. // now for the call order
  86. calls = [];
  87. new F();
  88. // E is first, because it's called before `super` in the parent class, and we call `super` before anything else
  89. // D is second, because we call `init` before pushing `B` in the first constructor. here it's important that the field `n` is set
  90. // before we call super(), so it's initialized at the point we call `init`
  91. // B is the last "super" ctor in the hierarchy
  92. // and finally F is pushed after a super call as usual
  93. assert(calls.join("") == "EDBF");
  94. // we also support skipping when inheriting from extern without constructors
  95. assert(!hasCtorMethod(ExtNoCtor));
  96. assert(!hasSkip(ExtNoCtor));
  97. assert(hasCtorMethod(Base));
  98. assert(hasSkip(Base));
  99. assert(hasCtorMethod(Child));
  100. assert(!hasSkip(Child));
  101. calls = [];
  102. new Child();
  103. assert(calls.join("|") == "CHILD|BASE");
  104. // ---
  105. (untyped process).exit(if (failures == 0) 0 else 1);
  106. }
  107. }