From 9f5227fad14dcbf9e1f8e9e3cffd5db96aaaecf7 Mon Sep 17 00:00:00 2001 From: Dwayne Reeves Date: Sun, 5 Jun 2016 08:21:59 -0700 Subject: [PATCH] Correctly instantiate generic attributes for XHP Summary: We weren't properly instantiating the `this` type or generics for XHP literals because we fetched the type directly from `class_type.tc_prop`. There is a lot of logic involved in properly resolving these types, so the easiest thing to do was to get the types of the individual attributes via `Typing.obj_get` to make sure expression dependent types and generics are instantiated correctly. Reviewed By: andrewjkennedy Differential Revision: D3375690 fbshipit-source-id: 76f160ff39a56bbf3a9822bdb5ce0b79421c9204 --- hphp/hack/src/typing/typing.ml | 24 +++++----------------- .../test/h2tp/convert_hack_test_inputs_base.py | 1 + hphp/hack/test/typecheck/xhp/generic_attr1.php | 11 ++++++++++ hphp/hack/test/typecheck/xhp/generic_attr1.php.exp | 6 ++++++ hphp/hack/test/typecheck/xhp/generic_attr2.php | 9 ++++++++ hphp/hack/test/typecheck/xhp/generic_attr2.php.exp | 8 ++++++++ hphp/hack/test/typecheck/xhp/generic_attr3.php | 14 +++++++++++++ hphp/hack/test/typecheck/xhp/generic_attr3.php.exp | 1 + .../test/typecheck/xhp/generic_attr_constraint.php | 9 ++++++++ .../typecheck/xhp/generic_attr_constraint.php.exp | 8 ++++++++ hphp/hack/test/typecheck/xhp/this_type_attr.php | 9 ++++++++ .../hack/test/typecheck/xhp/this_type_attr.php.exp | 12 +++++++++++ hphp/hack/test/typecheck/xhp_attr_23.php.exp | 2 +- 13 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr1.php create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr1.php.exp create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr2.php create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr2.php.exp create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr3.php create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr3.php.exp create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr_constraint.php create mode 100644 hphp/hack/test/typecheck/xhp/generic_attr_constraint.php.exp create mode 100644 hphp/hack/test/typecheck/xhp/this_type_attr.php create mode 100644 hphp/hack/test/typecheck/xhp/this_type_attr.php.exp diff --git a/hphp/hack/src/typing/typing.ml b/hphp/hack/src/typing/typing.ml index 7fbe5f1510c..b2d82d2f087 100644 --- a/hphp/hack/src/typing/typing.ml +++ b/hphp/hack/src/typing/typing.ml @@ -1326,10 +1326,6 @@ and expr_ if TypecheckerOptions.unsafe_xhp (Env.get_options env) then env, obj else begin - (* Check that the declared type of the XHP attribute matches the - * expression type *) - let attrdec = - SMap.filter (fun _ prop -> prop.ce_is_xhp_attr) class_.tc_props in let env = List.fold_left attr_ptyl ~f:begin fun env attr -> let namepstr, valpty = attr in let valp, valty = valpty in @@ -1338,21 +1334,11 @@ and expr_ * * This converts the member name to an attribute name. *) let name = ":" ^ (snd namepstr) in - let elt_option = SMap.get name attrdec in - (match elt_option with - | Some elt -> - let env, declty = Phase.localize_with_self env elt.ce_type in - let ureason = Reason.URxhp (class_.tc_name, snd namepstr) in - let env = Type.sub_type valp ureason env declty valty in - env - | None when SN.Members.is_special_xhp_attribute name -> env - (* Special attributes are valid even if they're not declared - eg - * any 'data-' attribute *) - | None -> - let r = (Reason.Rwitness p) in - member_not_found (fst namepstr) ~is_method:false class_ name r; - env - ); + let env, declty = + obj_get ~is_method:false ~nullsafe:None env obj cid + (fst namepstr, name) (fun x -> x) in + let ureason = Reason.URxhp (class_.tc_name, snd namepstr) in + Type.sub_type valp ureason env declty valty end ~init:env in env, obj end diff --git a/hphp/hack/test/h2tp/convert_hack_test_inputs_base.py b/hphp/hack/test/h2tp/convert_hack_test_inputs_base.py index 2e17286a353..a266a652a7e 100644 --- a/hphp/hack/test/h2tp/convert_hack_test_inputs_base.py +++ b/hphp/hack/test/h2tp/convert_hack_test_inputs_base.py @@ -111,6 +111,7 @@ UNSUPPORTED_FILES_UNPARSER = { 'xhp_attr_23.php', 'xhp_attr_24.php', 'xhp_hint.php', + 'xhp/*.php', ], "XhpAttr": [ 'lexing_stack_fail.php', diff --git a/hphp/hack/test/typecheck/xhp/generic_attr1.php b/hphp/hack/test/typecheck/xhp/generic_attr1.php new file mode 100644 index 00000000000..2e22eb90028 --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr1.php @@ -0,0 +1,11 @@ + { + attribute Vector foo @required; +} + +function test(): int { + $x = ; + + return $x->:foo[0]; +} diff --git a/hphp/hack/test/typecheck/xhp/generic_attr1.php.exp b/hphp/hack/test/typecheck/xhp/generic_attr1.php.exp new file mode 100644 index 00000000000..ff05b816ba3 --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr1.php.exp @@ -0,0 +1,6 @@ +File "generic_attr1.php", line 10, characters 10-20: +Invalid return type (Typing[4110]) +File "generic_attr1.php", line 7, characters 18-20: +This is an int +File "generic_attr1.php", line 8, characters 29-31: +It is incompatible with a string diff --git a/hphp/hack/test/typecheck/xhp/generic_attr2.php b/hphp/hack/test/typecheck/xhp/generic_attr2.php new file mode 100644 index 00000000000..3bd5a3c2d47 --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr2.php @@ -0,0 +1,9 @@ + { + attribute T foo @required; +} + +function test(int $x): :my-xhp { + return ; +} diff --git a/hphp/hack/test/typecheck/xhp/generic_attr2.php.exp b/hphp/hack/test/typecheck/xhp/generic_attr2.php.exp new file mode 100644 index 00000000000..e843ff7d0f6 --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr2.php.exp @@ -0,0 +1,8 @@ +File "generic_attr2.php", line 8, characters 11-28: +Invalid return type (Typing[4110]) +File "generic_attr2.php", line 7, characters 32-37: +This is a string +File "generic_attr2.php", line 7, characters 15-17: +It is incompatible with an int +File "generic_attr2.php", line 7, characters 32-37: +Considering that this type argument is invariant with respect to :my-xhp diff --git a/hphp/hack/test/typecheck/xhp/generic_attr3.php b/hphp/hack/test/typecheck/xhp/generic_attr3.php new file mode 100644 index 00000000000..fcd84071faa --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr3.php @@ -0,0 +1,14 @@ + { + attribute Vector foo @required; +} + +function test(T $x): :my-xhp { + return ; +} + +function test2(): Vector { + $xhp = test(10); + return $xhp->:foo; +} diff --git a/hphp/hack/test/typecheck/xhp/generic_attr3.php.exp b/hphp/hack/test/typecheck/xhp/generic_attr3.php.exp new file mode 100644 index 00000000000..4269126fceb --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr3.php.exp @@ -0,0 +1 @@ +No errors diff --git a/hphp/hack/test/typecheck/xhp/generic_attr_constraint.php b/hphp/hack/test/typecheck/xhp/generic_attr_constraint.php new file mode 100644 index 00000000000..8517535343a --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr_constraint.php @@ -0,0 +1,9 @@ + { + attribute T foo @required; +} + +function test(): void { + ; +} diff --git a/hphp/hack/test/typecheck/xhp/generic_attr_constraint.php.exp b/hphp/hack/test/typecheck/xhp/generic_attr_constraint.php.exp new file mode 100644 index 00000000000..9a55ecf48b8 --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/generic_attr_constraint.php.exp @@ -0,0 +1,8 @@ +File "generic_attr_constraint.php", line 7, characters 10-13: +Some type constraint(s) here are violated (Typing[4110]) +File "generic_attr_constraint.php", line 4, characters 13-13: +'T' is a constrained type +File "generic_attr_constraint.php", line 3, characters 20-22: +This is a num (int/float) +File "generic_attr_constraint.php", line 8, characters 15-17: +It is incompatible with a string diff --git a/hphp/hack/test/typecheck/xhp/this_type_attr.php b/hphp/hack/test/typecheck/xhp/this_type_attr.php new file mode 100644 index 00000000000..38cba9215db --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/this_type_attr.php @@ -0,0 +1,9 @@ +; +} diff --git a/hphp/hack/test/typecheck/xhp/this_type_attr.php.exp b/hphp/hack/test/typecheck/xhp/this_type_attr.php.exp new file mode 100644 index 00000000000..145d499010c --- /dev/null +++ b/hphp/hack/test/typecheck/xhp/this_type_attr.php.exp @@ -0,0 +1,12 @@ +File "this_type_attr.php", line 8, characters 22-23: +Invalid xhp value for attribute me in :my-xhp (Typing[4110]) +File "this_type_attr.php", line 4, characters 13-16: +This is an object of type :my-xhp (known to be exactly the class ':my-xhp') +File "this_type_attr.php", line 8, characters 11-16: + where the class ':my-xhp' was referenced here +File "this_type_attr.php", line 7, characters 15-21: +It is incompatible with an object of type :my-xhp +File "this_type_attr.php", line 8, characters 11-16: +This requires the late-bound type to be exactly :my-xhp +File "this_type_attr.php", line 7, characters 15-21: +Since :my-xhp is not final this might be an instance of a child class diff --git a/hphp/hack/test/typecheck/xhp_attr_23.php.exp b/hphp/hack/test/typecheck/xhp_attr_23.php.exp index f758c378fd1..0d488f0fc68 100644 --- a/hphp/hack/test/typecheck/xhp_attr_23.php.exp +++ b/hphp/hack/test/typecheck/xhp_attr_23.php.exp @@ -1,6 +1,6 @@ File "xhp_attr_23.php", line 6, characters 13-15: Could not find member :bar in an object of type :foo (Typing[4053]) -File "xhp_attr_23.php", line 6, characters 9-24: +File "xhp_attr_23.php", line 6, characters 9-11: This is why I think it is an object of type :foo File "xhp_attr_23.php", line 3, characters 7-10: Declaration of :foo is here -- 2.11.4.GIT