Permalink
Browse files

Adding new decl for redeclared method

Summary:
Adds a redeclared method to the decl map as if it were a normal method declaration in the class. In the test case, note that `C::f` ends up with `T2::f`'s type, while `C::g` gets `T::f`'s type.

The effect is similar to having two traits with a name conflict and a class method to override them, but stronger in the sense that method redeclaration removes the inherited method too.

Typing is still unaware of this removal, so another diff is required to clean up the error message in the test case.

Reviewed By: jamesjwu

Differential Revision: D13071433

fbshipit-source-id: eeac21d05799253a07525f63ea9c1b39a52c4fb4
  • Loading branch information...
vassilmladenov authored and hhvm-bot committed Dec 4, 2018
1 parent bcdf613 commit 05ca8729d645c85f155efc96a3e7dcd7b0758262
@@ -360,7 +360,10 @@ and class_decl tcopt c =
let inherited = Decl_inherit.make env c in
let props = inherited.Decl_inherit.ih_props in
let props = List.fold_left ~f:(prop_decl c) ~init:props c.sc_props in
let redecl_smethods, redecl_methods =
List.partition_tf ~f:(fun x -> x.smr_static) c.sc_method_redeclarations in
let m = inherited.Decl_inherit.ih_methods in
let m = List.fold_left ~f:(method_redecl_acc c) ~init:m redecl_methods in
let m, condition_types = List.fold_left
~f:(method_decl_acc ~is_static:false c )
~init:(m, SSet.empty) c.sc_methods in
@@ -375,6 +378,7 @@ and class_decl tcopt c =
let sprops = inherited.Decl_inherit.ih_sprops in
let sprops = List.fold_left c.sc_sprops ~f:sclass_var ~init:sprops in
let sm = inherited.Decl_inherit.ih_smethods in
let sm = List.fold_left ~f:(method_redecl_acc c) ~init:sm redecl_smethods in
let sm, condition_types = List.fold_left c.sc_static_methods
~f:(method_decl_acc ~is_static:true c )
~init:(sm, condition_types) in
@@ -704,6 +708,36 @@ and method_check_override c m acc =
false
| None -> false
and method_redecl_acc c acc m =
let ft = m.smr_type in
let _, id = m.smr_name in
let vis =
match SMap.get id acc, m.smr_visibility with
| Some { elt_visibility = Vprotected _ as parent_vis; _ }, Protected ->
parent_vis
| _ -> visibility (snd c.sc_name) m.smr_visibility
in
let elt = {
elt_final = m.smr_final;
elt_is_xhp_attr = false;
elt_const = false;
elt_lateinit = false;
elt_lsb = false;
elt_abstract = ft.ft_abstract;
elt_override = false;
elt_memoizelsb = false;
elt_synthesized = false;
elt_visibility = vis;
elt_origin = snd (c.sc_name);
elt_reactivity = None;
} in
let add_meth = if m.smr_static
then Decl_heap.StaticMethods.add
else Decl_heap.Methods.add
in
add_meth (elt.elt_origin, id) ft;
SMap.add id elt acc
and method_decl_acc ~is_static c (acc, condition_types) m =
let check_override = method_check_override c m acc in
let has_memoizelsb = m.sm_memoizelsb in
@@ -0,0 +1,25 @@
<?hh // strict
trait T {
public function f(): int {
return 4;
}
}
trait T2 {
public function f(): string {
return "4";
}
}
class C {
use T, T2;
public function g(): int = T::f;
}
function f(): void {
$c = new C();
hh_show($c->f());
hh_show($c->g());
}
@@ -0,0 +1,19 @@
File "method_redeclaration_renamed.php", line 23, characters 3-18:
string
File "method_redeclaration_renamed.php", line 24, characters 3-18:
int
File "method_redeclaration_renamed.php", line 15, characters 7-7:
Class C does not correctly implement all required members (Typing[4285])
File "method_redeclaration_renamed.php", line 16, characters 7-7:
Some members are incompatible with those declared in type T
Read the following to see why:
File "method_redeclaration_renamed.php", line 10, characters 19-19:
Member f has the wrong type
File "method_redeclaration_renamed.php", line 10, characters 19-19:
T2 and T both declare ambiguous implementations of f.
File "method_redeclaration_renamed.php", line 10, characters 19-19:
T2's definition is here.
File "method_redeclaration_renamed.php", line 4, characters 19-19:
T's definition is here.
File "method_redeclaration_renamed.php", line 10, characters 19-19:
Redeclare f in C with a compatible signature.
@@ -0,0 +1,24 @@
<?hh // strict
trait T {
public function f(): int {
return 4;
}
}
trait T2 {
public function f(): string {
return "4";
}
}
class C {
use T, T2;
public function f(): arraykey = T::f;
}
function f(): void {
$c = new C();
hh_show($c->f());
}
@@ -0,0 +1,13 @@
File "method_redeclaration_same_name.php", line 23, characters 3-18:
arraykey
File "method_redeclaration_same_name.php", line 15, characters 7-7:
Class C does not correctly implement all required members (Typing[4110])
File "method_redeclaration_same_name.php", line 16, characters 7-7:
Some members are incompatible with those declared in type T
Read the following to see why:
File "method_redeclaration_same_name.php", line 18, characters 19-19:
Member f has the wrong type
File "method_redeclaration_same_name.php", line 4, characters 24-26:
This is an int
File "method_redeclaration_same_name.php", line 18, characters 24-31:
It is incompatible with an array key (int/string)
@@ -1,15 +1 @@
File "methodish_trait_resolution.php", line 15, characters 7-7:
Class C does not correctly implement all required members (Typing[4285])
File "methodish_trait_resolution.php", line 16, characters 7-8:
Some members are incompatible with those declared in type T1
Read the following to see why:
File "methodish_trait_resolution.php", line 10, characters 19-24:
Member animal has the wrong type
File "methodish_trait_resolution.php", line 10, characters 19-24:
T2 and T1 both declare ambiguous implementations of animal.
File "methodish_trait_resolution.php", line 10, characters 19-24:
T2's definition is here.
File "methodish_trait_resolution.php", line 4, characters 19-24:
T1's definition is here.
File "methodish_trait_resolution.php", line 10, characters 19-24:
Redeclare animal in C with a compatible signature.
No errors

0 comments on commit 05ca872

Please sign in to comment.