Skip to content

Commit

Permalink
merge require class and require this as decls
Browse files Browse the repository at this point in the history
Summary:
The first cut of `require this as` trait constraints stored `require this as` informations in a new decl field; decls thus had both `require_class` and `require_this_as` entries.  This diff merges them in only one entry named `require_constraints` (as require class and require this as might be expressed as `this = C` and `this <: C` class-level constraints).

The diff also fixes some incorrect uses of `require_class` decls where both `require_class` and `require_this_as` information should have been taken into account.

Reviewed By: andrewjkennedy

Differential Revision: D68437455

fbshipit-source-id: a70f4f4d07a8ee17cb391495b2b24de63f484596
  • Loading branch information
Francesco Zappa Nardelli authored and facebook-github-bot committed Jan 28, 2025
1 parent e95d7ac commit 0a38aa9
Show file tree
Hide file tree
Showing 166 changed files with 1,656 additions and 1,219 deletions.
29 changes: 18 additions & 11 deletions hphp/hack/src/decl/classDiff.ml
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,8 @@ type parent_changes = {
unit NamedItemsListChange.t NamedItemsListChange.t option;
req_implements_changes:
unit NamedItemsListChange.t NamedItemsListChange.t option;
req_class_changes: unit NamedItemsListChange.t NamedItemsListChange.t option;
req_this_as_changes:
unit NamedItemsListChange.t NamedItemsListChange.t option;
(* For req constraints a coarse-grained analysis is sufficient *)
req_constraints_changes: bool;
uses_changes: unit NamedItemsListChange.t NamedItemsListChange.t option;
xhp_attr_changes: unit NamedItemsListChange.t NamedItemsListChange.t option;
}
Expand Down Expand Up @@ -385,6 +384,18 @@ module ClassShellChangeCategory = struct
| ValueChange.Modified _ -> { acc with some_modified = true })
changes
{ no_change with order_change }

let of_bool b =
if b then
Some
{
some_added = true;
some_removed = true;
some_modified = true;
order_change = true;
}
else
None
end

module ParentsChangeCategory = struct
Expand All @@ -393,8 +404,7 @@ module ClassShellChangeCategory = struct
implements_changes_category: ListChange.t option;
req_extends_changes_category: ListChange.t option;
req_implements_changes_category: ListChange.t option;
req_class_changes_category: ListChange.t option;
req_this_as_changes_category: ListChange.t option;
req_constraints_changes_category: ListChange.t option;
uses_changes_category: ListChange.t option;
xhp_attr_changes_category: ListChange.t option;
}
Expand All @@ -406,8 +416,7 @@ module ClassShellChangeCategory = struct
implements_changes;
req_extends_changes;
req_implements_changes;
req_class_changes;
req_this_as_changes;
req_constraints_changes;
uses_changes;
xhp_attr_changes;
} =
Expand All @@ -420,10 +429,8 @@ module ClassShellChangeCategory = struct
Option.map ListChange.of_list_change_map req_extends_changes;
req_implements_changes_category =
Option.map ListChange.of_list_change_map req_implements_changes;
req_class_changes_category =
Option.map ListChange.of_list_change_map req_class_changes;
req_this_as_changes_category =
Option.map ListChange.of_list_change_map req_this_as_changes;
req_constraints_changes_category =
ListChange.of_bool req_constraints_changes;
uses_changes_category =
Option.map ListChange.of_list_change_map uses_changes;
xhp_attr_changes_category =
Expand Down
4 changes: 1 addition & 3 deletions hphp/hack/src/decl/classDiff.mli
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ type parent_changes = {
unit NamedItemsListChange.t NamedItemsListChange.t option;
req_implements_changes:
unit NamedItemsListChange.t NamedItemsListChange.t option;
req_class_changes: unit NamedItemsListChange.t NamedItemsListChange.t option;
req_this_as_changes:
unit NamedItemsListChange.t NamedItemsListChange.t option;
req_constraints_changes: bool;
uses_changes: unit NamedItemsListChange.t NamedItemsListChange.t option;
xhp_attr_changes: unit NamedItemsListChange.t NamedItemsListChange.t option;
}
Expand Down
18 changes: 6 additions & 12 deletions hphp/hack/src/decl/decl_defs.ml
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,11 @@ type decl_class_type = {
possibly inherited from interface or trait ancestors,
plus some extends and other ancestors of these.
Does not include `require class` *)
dc_req_class_ancestors: requirement list;
(** dc_req_class_ancestors gathers all the `require class`
requirements declared in ancestors. Remark that `require class`
requirements are _not_ stored in `dc_req_ancestors` or
`dc_req_ancestors_extends` fields. *)
dc_req_this_as_ancestors: requirement list;
(** dc_req_this_as_ancestors gathers all the `require this as`
requirements declared in ancestors. Remark that `require this as`
requirements are _not_ stored in `dc_req_ancestors` or
`dc_req_ancestors_extends` fields. *)
dc_req_constraints_ancestors: constraint_requirement list;
(** dc_req_constraints_ancestors gathers all the `require class` and
`require this as` requirements declared in ancestors. Remark that
`require class` and `require this as` requirements are _not_ stored
in `dc_req_ancestors` or `dc_req_ancestors_extends` fields. *)
dc_extends: SSet.t;
dc_sealed_whitelist: SSet.t option;
dc_xhp_attr_deps: SSet.t;
Expand All @@ -174,8 +169,7 @@ type decl_class_type = {
type class_requirements = {
cr_req_ancestors: Typing_defs.requirement list;
cr_req_ancestors_extends: SSet.t;
cr_req_class_ancestors: Typing_defs.requirement list;
cr_req_this_as_ancestors: Typing_defs.requirement list;
cr_req_constraints_ancestors: Typing_defs.constraint_requirement list;
}
[@@deriving show]

Expand Down
6 changes: 2 additions & 4 deletions hphp/hack/src/decl/decl_folded_class.ml
Original file line number Diff line number Diff line change
Expand Up @@ -941,8 +941,7 @@ and class_decl
let {
cr_req_ancestors;
cr_req_ancestors_extends;
cr_req_class_ancestors;
cr_req_this_as_ancestors;
cr_req_constraints_ancestors;
} =
Decl_requirements.get_class_requirements env parents c
in
Expand Down Expand Up @@ -1043,8 +1042,7 @@ and class_decl
dc_xhp_marked_empty = c.sc_xhp_marked_empty;
dc_req_ancestors = cr_req_ancestors;
dc_req_ancestors_extends = cr_req_ancestors_extends;
dc_req_class_ancestors = cr_req_class_ancestors;
dc_req_this_as_ancestors = cr_req_this_as_ancestors;
dc_req_constraints_ancestors = cr_req_constraints_ancestors;
dc_enum_type = enum;
dc_decl_errors = decl_errors;
dc_docs_url = c.sc_docs_url;
Expand Down
4 changes: 3 additions & 1 deletion hphp/hack/src/decl/decl_inherit.ml
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,9 @@ end = struct
* used in decl_folded_class.ml *)
[
(Parent, parents_which_provide_members c |> List.rev);
(Requirement, c.sc_req_class @ c.sc_req_extends);
( Requirement,
List.map c.sc_req_constraints ~f:(fun dcr -> to_decl_constraint dcr)
@ c.sc_req_extends );
(Trait, c.sc_uses);
]

Expand Down
19 changes: 14 additions & 5 deletions hphp/hack/src/decl/decl_pos_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,8 @@ struct
dc_xhp_marked_empty = dc.dc_xhp_marked_empty;
dc_req_ancestors = List.map dc.dc_req_ancestors ~f:requirement;
dc_req_ancestors_extends = dc.dc_req_ancestors_extends;
dc_req_class_ancestors = List.map dc.dc_req_class_ancestors ~f:requirement;
dc_req_this_as_ancestors =
List.map dc.dc_req_this_as_ancestors ~f:requirement;
dc_req_constraints_ancestors =
List.map dc.dc_req_constraints_ancestors ~f:constraint_requirement;
dc_tparams = List.map dc.dc_tparams ~f:type_param;
dc_substs =
SMap.map
Expand Down Expand Up @@ -214,6 +213,11 @@ struct

and requirement (p, t) = (pos_or_decl p, ty t)

and constraint_requirement cr =
match cr with
| CR_Equal r -> CR_Equal (requirement r)
| CR_Subtype r -> CR_Subtype (requirement r)

and enum_type te =
{
te_base = ty te.te_base;
Expand Down Expand Up @@ -260,8 +264,8 @@ struct
sc_xhp_marked_empty = sc.sc_xhp_marked_empty;
sc_req_extends = List.map sc.sc_req_extends ~f:ty;
sc_req_implements = List.map sc.sc_req_implements ~f:ty;
sc_req_class = List.map sc.sc_req_class ~f:ty;
sc_req_this_as = List.map sc.sc_req_this_as ~f:ty;
sc_req_constraints =
List.map sc.sc_req_constraints ~f:shallow_req_constraint;
sc_implements = List.map sc.sc_implements ~f:ty;
sc_support_dynamic_type = sc.sc_support_dynamic_type;
sc_consts = List.map sc.sc_consts ~f:shallow_class_const;
Expand Down Expand Up @@ -315,6 +319,11 @@ struct
sm_attributes = sm.sm_attributes;
sm_sort_text = sm.sm_sort_text;
}

and shallow_req_constraint src =
match src with
| DCR_Equal cr -> DCR_Equal (ty cr)
| DCR_Subtype cr -> DCR_Subtype (ty cr)
end

(*****************************************************************************)
Expand Down
75 changes: 36 additions & 39 deletions hphp/hack/src/decl/decl_requirements.ml
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,26 @@ let declared_class_req env class_cache acc req_ty =
in
(requirements, req_extends)

let declared_class_req_non_strict required_classes req_ty =
let (_, (req_pos, _), _) = Decl_utils.unwrap_class_type req_ty in
(req_pos, req_ty) :: required_classes
let declared_class_req_non_strict env class_cache required_classes req =
let elab req_ty =
let (_, (req_pos, req_name), _) = Decl_utils.unwrap_class_type req_ty in
let _ =
(* ensure we add a dependecy even if we don't need the class itself *)
Decl_env.get_class_and_add_dep
~cache:class_cache
~shmem_fallback:false
~fallback:Decl_env.no_fallback
env
req_name
in
(req_pos, req_ty)
in
match req with
| DCR_Equal req_ty -> CR_Equal (elab req_ty) :: required_classes
| DCR_Subtype req_ty -> CR_Subtype (elab req_ty) :: required_classes

let flatten_parent_class_reqs_non_strict
env class_cache get_requirements req_classes_ancestors parent_ty =
env class_cache req_constraints_ancestors parent_ty =
let (_, (parent_pos, parent_name), parent_params) =
Decl_utils.unwrap_class_type parent_ty
in
Expand All @@ -113,15 +127,20 @@ let flatten_parent_class_reqs_non_strict
match parent_type with
| None ->
(* The class lives in PHP *)
req_classes_ancestors
req_constraints_ancestors
| Some parent_type ->
let subst = make_substitution parent_type parent_params in
List.rev_map_append
(get_requirements parent_type)
req_classes_ancestors
~f:(fun (_p, ty) ->
let ty = Inst.instantiate subst ty in
(parent_pos, ty))
parent_type.dc_req_constraints_ancestors
req_constraints_ancestors
~f:(fun cr ->
let elab (_p, ty) =
let ty = Inst.instantiate subst ty in
(parent_pos, ty)
in
match cr with
| CR_Equal req_ty -> CR_Equal (elab req_ty)
| CR_Subtype req_ty -> CR_Subtype (elab req_ty))

(* Cheap hack: we cannot do unification / subtyping in the decl phase because
* the type arguments of the types that we are trying to unify may not have
Expand Down Expand Up @@ -189,42 +208,20 @@ let get_class_requirements env class_cache shallow_class =
let (req_extends, req_ancestors_extends) = acc in
let req_extends = naive_dedup req_extends in

let req_classes =
let req_constraints =
List.fold_left
~f:declared_class_req_non_strict
~f:(declared_class_req_non_strict env class_cache)
~init:[]
shallow_class.sc_req_class
shallow_class.sc_req_constraints
in
let req_classes =
let req_constraints =
List.fold_left
~f:
(flatten_parent_class_reqs_non_strict env class_cache (fun t ->
t.dc_req_class_ancestors))
~init:req_classes
~f:(flatten_parent_class_reqs_non_strict env class_cache)
~init:req_constraints
shallow_class.sc_uses
in
let req_classes = naive_dedup req_classes in

let req_this_as =
List.fold_left
~f:declared_class_req_non_strict
~init:[]
shallow_class.sc_req_this_as
in
let req_this_as =
List.fold_left
~f:
(flatten_parent_class_reqs_non_strict env class_cache (fun t ->
t.dc_req_this_as_ancestors))
(* FIXME *)
~init:req_this_as
shallow_class.sc_uses
in
let req_this_as = naive_dedup req_this_as in

{
cr_req_ancestors = req_extends;
cr_req_ancestors_extends = req_ancestors_extends;
cr_req_class_ancestors = req_classes;
cr_req_this_as_ancestors = req_this_as;
cr_req_constraints_ancestors = req_constraints;
}
31 changes: 15 additions & 16 deletions hphp/hack/src/decl/direct_decl_smart_constructors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use oxidized_by_ref::relative_path::RelativePath;
use oxidized_by_ref::s_map::SMap;
use oxidized_by_ref::shallow_decl_defs;
use oxidized_by_ref::shallow_decl_defs::Decl;
use oxidized_by_ref::shallow_decl_defs::DeclConstraintRequirement;
use oxidized_by_ref::shallow_decl_defs::ShallowClassConst;
use oxidized_by_ref::shallow_decl_defs::ShallowMethod;
use oxidized_by_ref::shallow_decl_defs::ShallowProp;
Expand Down Expand Up @@ -4589,8 +4590,7 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
let mut xhp_marked_empty = false;
let mut req_extends_len = 0;
let mut req_implements_len = 0;
let mut req_class_len = 0;
let mut req_this_as_len = 0;
let mut req_constraints_len = 0;
let mut consts_len = 0;
let mut typeconsts_len = 0;
let mut props_len = 0;
Expand Down Expand Up @@ -4628,11 +4628,11 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
Node::RequireClause(require) => match require.require_type.token_kind() {
Some(TokenKind::Extends) => req_extends_len += 1,
Some(TokenKind::Implements) => req_implements_len += 1,
Some(TokenKind::Class) => req_class_len += 1,
Some(TokenKind::Class) => req_constraints_len += 1,
_ => {}
},
Node::RequireClauseConstraint(_) => {
req_this_as_len += 1;
req_constraints_len += 1;
}
Node::List(consts @ [Node::Const(..), ..]) => consts_len += consts.len(),
Node::Property(&PropertyNode { decls, is_static }) => {
Expand Down Expand Up @@ -4662,8 +4662,7 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
let mut xhp_attr_uses = bump::Vec::with_capacity_in(xhp_attr_uses_len, self.arena);
let mut req_extends = bump::Vec::with_capacity_in(req_extends_len, self.arena);
let mut req_implements = bump::Vec::with_capacity_in(req_implements_len, self.arena);
let mut req_class = bump::Vec::with_capacity_in(req_class_len, self.arena);
let mut req_this_as = bump::Vec::with_capacity_in(req_this_as_len, self.arena);
let mut req_constraints = bump::Vec::with_capacity_in(req_constraints_len, self.arena);
let mut consts = bump::Vec::with_capacity_in(consts_len, self.arena);
let mut typeconsts = bump::Vec::with_capacity_in(typeconsts_len, self.arena);
let mut props = bump::Vec::with_capacity_in(props_len, self.arena);
Expand Down Expand Up @@ -4722,12 +4721,16 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
req_implements.extend(self.node_to_ty(require.name).iter())
}
Some(TokenKind::Class) => {
req_class.extend(self.node_to_ty(require.name).iter())
if let Some(ty) = self.node_to_ty(require.name) {
req_constraints.push(DeclConstraintRequirement::DCREqual(ty))
}
}
_ => {}
},
Node::RequireClauseConstraint(require) => {
req_this_as.extend(self.node_to_ty(require.name).iter())
if let Some(ty) = self.node_to_ty(require.name) {
req_constraints.push(DeclConstraintRequirement::DCRSubtype(ty))
}
}
Node::List(&const_nodes @ [Node::Const(..), ..]) => {
for node in const_nodes {
Expand Down Expand Up @@ -4806,8 +4809,7 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
let xhp_enum_values = xhp_enum_values;
let req_extends = req_extends.into_bump_slice();
let req_implements = req_implements.into_bump_slice();
let req_class = req_class.into_bump_slice();
let req_this_as = req_this_as.into_bump_slice();
let req_constraints = req_constraints.into_bump_slice();
let consts = consts.into_bump_slice();
let typeconsts = typeconsts.into_bump_slice();
let props = props.into_bump_slice();
Expand Down Expand Up @@ -4842,8 +4844,7 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
xhp_marked_empty,
req_extends,
req_implements,
req_class,
req_this_as,
req_constraints,
implements,
support_dynamic_type,
consts,
Expand Down Expand Up @@ -5320,8 +5321,7 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
xhp_marked_empty: false,
req_extends: &[],
req_implements: &[],
req_class: &[],
req_this_as: &[],
req_constraints: &[],
implements: &[],
support_dynamic_type: parsed_attributes.support_dynamic_type,
consts,
Expand Down Expand Up @@ -5540,8 +5540,7 @@ impl<'a, 'o, 't, S: SourceTextAllocator<'t, 'a>> FlattenSmartConstructors
xhp_marked_empty: false,
req_extends: &[],
req_implements: &[],
req_class: &[],
req_this_as: &[],
req_constraints: &[],
implements: &[],
support_dynamic_type,
consts,
Expand Down
Loading

0 comments on commit 0a38aa9

Please sign in to comment.