Test.hx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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 RootNoArgs {
  44. public function new() {}
  45. }
  46. class ChildOneArg extends RootNoArgs {
  47. public var x:Int;
  48. public function new(x) {
  49. super();
  50. this.x = x;
  51. }
  52. }
  53. class GrandChildNoArgs extends ChildOneArg {
  54. public function new() {
  55. Test.use(this);
  56. super(42);
  57. }
  58. }
  59. class Issue9426_1 {
  60. static function __init__() {
  61. var sameName = Std.random(10);
  62. Test.use(sameName);
  63. Test.use(sameName);
  64. }
  65. }
  66. class Issue9426_2 {
  67. static function __init__() {
  68. var sameName = Std.random(10);
  69. Test.use(sameName);
  70. Test.use(sameName);
  71. }
  72. }
  73. class Test {
  74. public static var calls:Array<String>;
  75. @:pure(false) public static function use(v:Any) {}
  76. static inline final hxCtor = "_hx_constructor";
  77. static inline final hxSkipCtor = "_hx_skip_constructor";
  78. static function hasCtorMethod(c:Dynamic):Bool {
  79. return c.prototype.hasOwnProperty(hxCtor);
  80. }
  81. static function hasSkip(c:Dynamic) {
  82. return c.hasOwnProperty(hxSkipCtor);
  83. }
  84. static var failures = 0;
  85. static function assert(bool:Bool, ?pos:haxe.PosInfos) {
  86. if (!bool) {
  87. (untyped process).stderr.write(haxe.Log.formatOutput("assertion failed\n", pos));
  88. failures++;
  89. }
  90. }
  91. static function main() {
  92. // A has no constructor, so it's safe to just call `super` first
  93. // even if we skip ctor in the subclasses
  94. assert(!hasCtorMethod(A));
  95. assert(!hasSkip(A));
  96. // B has an extracted ctor and also the static skip flag,
  97. // as it is the first in the hierarchy who's ctor needs to be skipped
  98. assert(hasCtorMethod(B));
  99. assert(hasSkip(B));
  100. // C and others down the chain should NOT have the static skip flag,
  101. // but it can have a hxctor (although in this case it could be optimized away)
  102. assert(!hasSkip(C));
  103. // D must have a hxctor because it accesses this before super (for field init)
  104. // it also supports skipping because it has children who want to skip
  105. assert(hasCtorMethod(D));
  106. assert(!hasSkip(D));
  107. // E also must have a hxctor because it accesses this before super
  108. // but it doesn't support skipping, because noone down the inheritance requires it
  109. assert(hasCtorMethod(E));
  110. assert(!hasSkip(E));
  111. // F should NOT have hxctor because it doesn't access this before super and
  112. // it has no children that require skipping
  113. assert(!hasCtorMethod(F));
  114. assert(!hasSkip(F));
  115. // now for the call order
  116. calls = [];
  117. new F();
  118. // E is first, because it's called before `super` in the parent class, and we call `super` before anything else
  119. // D is second, because we call `init` before pushing `B` in the first constructor. here it's important that the field `n` is set
  120. // before we call super(), so it's initialized at the point we call `init`
  121. // B is the last "super" ctor in the hierarchy
  122. // and finally F is pushed after a super call as usual
  123. assert(calls.join("") == "EDBF");
  124. // we also support skipping when inheriting from extern without constructors
  125. assert(!hasCtorMethod(ExtNoCtor));
  126. assert(!hasSkip(ExtNoCtor));
  127. assert(hasCtorMethod(Base));
  128. assert(hasSkip(Base));
  129. assert(hasCtorMethod(Child));
  130. assert(!hasSkip(Child));
  131. calls = [];
  132. new Child();
  133. assert(calls.join("|") == "CHILD|BASE");
  134. assert(new ChildOneArg(42).x == 42); // #7988
  135. // ---
  136. (untyped process).exit(if (failures == 0) 0 else 1);
  137. }
  138. }