Skip to content

Commit

Permalink
Fix order for closures in nested anon classes
Browse files Browse the repository at this point in the history
Reviewed By: kmeht

Differential Revision: D8740549

fbshipit-source-id: 7da053927c989b5875fd92ae1005296aeb2f7268
  • Loading branch information
oulgen authored and fredemmott committed Jul 12, 2018
1 parent 572d75b commit 1ec607a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 9 deletions.
36 changes: 27 additions & 9 deletions hphp/hack/src/hhbc/closure_convert.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ type env = {
defined_function_count : int;
(* if we are immediately in using statement *)
in_using: bool;
(* how many nested anonymous classes we are in *)
anonclass_depth: int;
}

type per_function_state = {
Expand Down Expand Up @@ -156,7 +158,7 @@ let initial_state =
}

let total_class_count env st =
List.length st.hoisted_classes + env.defined_class_count
List.length st.hoisted_classes + env.defined_class_count + env.anonclass_depth

let set_in_using env =
if env.in_using then env else { env with in_using = true }
Expand Down Expand Up @@ -295,7 +297,11 @@ let rec make_scope_name ns scope =
| Some cd -> make_class_name cd ^ "::" ^ fname
end
| ScopeItem.Method md :: scope ->
make_scope_name ns scope ^ "::" ^ strip_id md.m_name
let scope_name = make_scope_name ns scope in
let scope_name =
scope_name ^
(if String_utils.string_ends_with scope_name "::" then "" else "::") in
scope_name ^ strip_id md.m_name
| ScopeItem.Class cd :: _ ->
let n = make_class_name cd in
if Hhbc_string_utils.Classes.is_anonymous_class_name n then n ^ "::" else n
Expand All @@ -312,12 +318,14 @@ let env_toplevel class_count function_count defs =
~is_closure_body:false
[]
defs in
{ scope = scope;
pos = Pos.none;
variable_scopes = [{ all_vars; parameter_names = SSet.empty }];
defined_class_count = class_count;
defined_function_count = function_count;
in_using = false }
{ scope = scope
; pos = Pos.none
; variable_scopes = [{ all_vars; parameter_names = SSet.empty }]
; defined_class_count = class_count
; defined_function_count = function_count
; in_using = false
; anonclass_depth = 0
}

let env_with_method env md =
env_with_function_like_
Expand Down Expand Up @@ -685,10 +693,20 @@ let rec convert_expr env st (p, expr_ as expr) =
let cls = { cls with
c_extends = List.map cls.c_extends add_ns_to_hint;
c_implements = List.map cls.c_implements add_ns_to_hint } in
let prev_anonclass_depth = env.anonclass_depth in
let env = { env with anonclass_depth = prev_anonclass_depth + 1 } in
let num_hoisted_classes = List.length st.hoisted_classes in
let st, cls = convert_class env st cls in
let env = { env with anonclass_depth = prev_anonclass_depth } in
let re_ordered_hoisted_classes =
let new_classes, old_classes =
List.split_n st.hoisted_classes
(List.length st.hoisted_classes - num_hoisted_classes) in
new_classes @ (cls :: old_classes)
in
let st = { st with
anon_cls_cnt_per_fun = st.anon_cls_cnt_per_fun + 1;
hoisted_classes = cls :: st.hoisted_classes } in
hoisted_classes = re_ordered_hoisted_classes } in
let env = env_with_class env cls in
let st, args = convert_exprs env st args in
let st, varargs = convert_exprs env st varargs in
Expand Down
17 changes: 17 additions & 0 deletions hphp/test/slow/anon_class/lambda_in_nested_anon_class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

$a = new class {
function func() {
$b = new class {
function func2() {
$closure = function () {
echo "done\n";
};

$closure();
}
};
$b->func2();
}
};
$a->func();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
done

0 comments on commit 1ec607a

Please sign in to comment.