You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make trait constants behave like interface constants
Summary:
Trait constants were added to the language recently to obviate a workaround where traits themselves could not declare constants, but could bring in constants via interfaces. However, the semantics on conflict were to drop the conflicting constant; this is in contrast to interface conflicts, where you get a fatal at class loading time.
```
class A {
const int X = 3;
}
interface I {
const string X = "hello";
}
class C extends A implements I {} // Fatal runtime error
trait TI implements I {}
class D extends A { use TI; } // no fatal
// by extension
trait T { const bool X = false; }
class E extends A { use T; } // also no fatal
```
This flag allows the above cases to fatal, and it also fixes the behavior of defaults + makes HHVM align with Hack on member resolution order.
```
abstract class A {
abstract const type T = arraykey;
}
trait T {
const type T = int;
}
class C extends A { use T; } // C::T = int, was arraykey previously.
```
Equivalently, coeffect unsoundness given trait conflicts is resolved
```
abstract class A {
abstract const ctx C = [];
}
trait T {
const ctx C = [defaults];
public function f()[this::C]: void {
echo "impure";
}
}
class C extends A { use T; } // runtime used to think (new C())->f() is pure, now it's correctly defaults.
```
The flag also changes HHBBC to insert trait constants before inserting locally declared constants of a class, which resolves a bug with printing the conflict error message and a static analysis failure where the trait constant was expecting to conflict with a shallowly declared constant (see trait_slot_conflict_repo.php).
Reviewed By: oulgen
Differential Revision: D28887745
fbshipit-source-id: a698e1818925ba17c2608ce34d50dc1400cfabd0
0 commit comments