diff --git a/lang_php/analyze/foundation/ast_php_simple.ml b/lang_php/analyze/foundation/ast_php_simple.ml index 0ef06324a..2abaa8644 100644 --- a/lang_php/analyze/foundation/ast_php_simple.ml +++ b/lang_php/analyze/foundation/ast_php_simple.ml @@ -413,6 +413,7 @@ and type_def = { and type_def_kind = | Alias of hint_type | Newtype of hint_type + | ClassConstType of hint_type option (* with tarzan *) (* ------------------------------------------------------------------------- *) diff --git a/lang_php/analyze/foundation/ast_php_simple_build.ml b/lang_php/analyze/foundation/ast_php_simple_build.ml index 3cd129f53..c808e631b 100644 --- a/lang_php/analyze/foundation/ast_php_simple_build.ml +++ b/lang_php/analyze/foundation/ast_php_simple_build.ml @@ -558,6 +558,10 @@ and type_def env def = and type_def_kind env = function | Alias t -> A.Alias (hint_type env t) | Newtype t -> A.Newtype (hint_type env t) + | ClassConstType v1 -> A.ClassConstType + (match v1 with + | Some x -> Some (hint_type env x) + | None -> None) and class_def env c = @@ -707,7 +711,7 @@ and class_body env st (mets, flds) = met::mets, more_flds @ flds | ClassVariables _ | ClassConstants _ | UseTrait _ - | XhpDecl _ | TraitConstraint _ + | XhpDecl _ | TraitConstraint _ | ClassType _ -> (mets, flds) and method_def env m = diff --git a/lang_php/analyze/foundation/database_prolog_php.ml b/lang_php/analyze/foundation/database_prolog_php.ml index d63788614..cf668732a 100644 --- a/lang_php/analyze/foundation/database_prolog_php.ml +++ b/lang_php/analyze/foundation/database_prolog_php.ml @@ -303,6 +303,7 @@ let visit ~add readable ast = ) | UseTrait _ -> () + | ClassType _ -> () | TraitConstraint _ -> () ) | _ -> k x diff --git a/lang_php/analyze/foundation/graph_code_php.ml b/lang_php/analyze/foundation/graph_code_php.ml index 87d84fd7e..f6180c2ff 100644 --- a/lang_php/analyze/foundation/graph_code_php.ml +++ b/lang_php/analyze/foundation/graph_code_php.ml @@ -856,6 +856,7 @@ and type_def env def = and type_def_kind env = function | Alias t | Newtype t -> hint_type env t + | ClassConstType _t -> () (* ---------------------------------------------------------------------- *) (* Types *) diff --git a/lang_php/analyze/foundation/meta_ast_php_simple.ml b/lang_php/analyze/foundation/meta_ast_php_simple.ml index ba1065c12..25f805d8d 100644 --- a/lang_php/analyze/foundation/meta_ast_php_simple.ml +++ b/lang_php/analyze/foundation/meta_ast_php_simple.ml @@ -113,6 +113,9 @@ and vof_type_def_kind = | Alias v1 -> let v1 = vof_hint_type v1 in Ocaml.VSum (("Alias", [ v1 ])) | Newtype v1 -> let v1 = vof_hint_type v1 in Ocaml.VSum (("Newtype", [ v1 ])) + | ClassConstType v1 -> + let v1 = Ocaml.vof_option vof_hint_type v1 in + Ocaml.VSum (("ClassConstType", [v1])) and vof_case = function diff --git a/lang_php/analyze/visual/highlight_php.ml b/lang_php/analyze/visual/highlight_php.ml index 0c36e4b1a..5f5829a4f 100644 --- a/lang_php/analyze/visual/highlight_php.ml +++ b/lang_php/analyze/visual/highlight_php.ml @@ -372,7 +372,8 @@ let visit_program ~tag _prefs hentities (ast, toks) = tag info (Entity (Class, (Use2 fake_no_use2))); ); k x - | Ast.TraitConstraint (_, _kind, _ty, _) -> + | Ast.TraitConstraint (_, _, _, _) + | Ast.ClassType _ -> k x ); diff --git a/lang_php/matcher/php_vs_php.ml b/lang_php/matcher/php_vs_php.ml index e75a24ffb..ff91e923a 100644 --- a/lang_php/matcher/php_vs_php.ml +++ b/lang_php/matcher/php_vs_php.ml @@ -2599,7 +2599,7 @@ and m_class_stmt a b = B.TraitConstraint(b1, b2, b3, b4) ) )))) - + | A.ClassType _, _ | A.ClassConstants _, _ | A.ClassVariables _, _ | A.Method _, _ diff --git a/lang_php/parsing/ast_php.ml b/lang_php/parsing/ast_php.ml index 533ea7d85..2dd7a9d34 100644 --- a/lang_php/parsing/ast_php.ml +++ b/lang_php/parsing/ast_php.ml @@ -651,7 +651,7 @@ and class_def = { (* facebook-ext: 'require' can appear only in traits *) | TraitConstraint of tok (* require *) * trait_constraint_kind wrap * hint_type * tok (* ; *) - + | ClassType of type_def and class_constant = ident * static_scalar_affect option and class_variable = dname * static_scalar_affect option and class_var_modifier = @@ -742,6 +742,7 @@ and type_def = { and type_def_kind = | Alias of hint_type | Newtype of hint_type + | ClassConstType of hint_type option (* ------------------------------------------------------------------------- *) (* Other declarations *) diff --git a/lang_php/parsing/map_php.ml b/lang_php/parsing/map_php.ml index 8096a6893..c5059c166 100644 --- a/lang_php/parsing/map_php.ml +++ b/lang_php/parsing/map_php.ml @@ -932,6 +932,9 @@ and map_class_stmt = and v3 = map_hint_type v3 and v4 = map_tok v4 in TraitConstraint ((v1, v2, v3, v4)) + | ClassType ((v1)) -> + let v1 = map_type_def v1 + in ClassType ((v1)) | ClassConstants ((v1, v2, opt_ty, v3, v4)) -> let v1 = map_option map_tok v1 and v2 = map_tok v2 @@ -1198,6 +1201,8 @@ and map_type_def_kind = function | Alias v1 -> let v1 = map_hint_type v1 in Alias ((v1)) | Newtype v1 -> let v1 = map_hint_type v1 in Newtype ((v1)) + | ClassConstType v1 -> + let v1 = map_option map_hint_type v1 in ClassConstType ((v1)) and map_namespace_use_rule = function diff --git a/lang_php/parsing/meta_ast_php.ml b/lang_php/parsing/meta_ast_php.ml index 63f7f4aa6..3da269d21 100644 --- a/lang_php/parsing/meta_ast_php.ml +++ b/lang_php/parsing/meta_ast_php.ml @@ -981,6 +981,9 @@ and vof_class_stmt = and v3 = vof_hint_type v3 and v4 = vof_tok v4 in Ocaml.VSum (("TraitConstraint", [ v1; v2; v3; v4 ])) + | ClassType ((v1)) -> + let v1 = vof_type_def v1 + in Ocaml.VSum (("ClassType", [v1])) | ClassConstants ((v1, v2, opt_ty, v3, v4)) -> let v1 = vof_option vof_tok v1 and v2 = vof_tok v2 @@ -1273,6 +1276,8 @@ and vof_type_def_kind = | Alias v1 -> let v1 = vof_hint_type v1 in Ocaml.VSum (("Alias", [ v1 ])) | Newtype v1 -> let v1 = vof_hint_type v1 in Ocaml.VSum (("Newtype", [ v1 ])) + | ClassConstType v1 -> + let v1 = vof_option vof_hint_type v1 in Ocaml.VSum (("ClassConstType", [v1])) and vof_namespace_use_rule = function diff --git a/lang_php/parsing/parser_php.mly b/lang_php/parsing/parser_php.mly index 75da42b77..289c66fdc 100644 --- a/lang_php/parsing/parser_php.mly +++ b/lang_php/parsing/parser_php.mly @@ -126,7 +126,9 @@ module PI = Parse_info T_SELF T_PARENT /*(* facebook extension *)*/ T_TYPE T_NEWTYPE T_SHAPE - +%left T_TYPE +%left T_IDENT +%right T_ELLIPSIS /*(*-----------------------------------------*)*/ /*(*2 Symbol tokens *)*/ /*(*-----------------------------------------*)*/ @@ -688,6 +690,38 @@ class_statement: let const_list = [Left const] in ClassConstants(Some $1, $2, Some $3, const_list, $5) } +/*(* facebook-ext: type constants *)*/ + | T_ABSTRACT T_CONST T_TYPE T_IDENT T_AS type_php TSEMICOLON + { ClassType (* TODO (t6384084) add some fields here *) { + t_tok = $3; + t_name = Name $4; + t_tparams = None; + t_tconstraint = Some($5, $6); + t_tokeq = $5; (* doesn't exist here *) + t_kind = ClassConstType None; + t_sc = $7; } + } + | T_ABSTRACT T_CONST T_TYPE T_IDENT TSEMICOLON + { ClassType (* TODO (t6384084) add some fields here *) { + t_tok = $3; + t_name = Name $4; + t_tparams = None; + t_tconstraint = None; + t_tokeq = $5; (* doesn't exist here *) + t_kind = ClassConstType None; + t_sc = $5; } + } + | T_CONST T_TYPE T_IDENT type_constr_opt TEQ type_php_or_shape TSEMICOLON + { ClassType (* TODO (t6384084) add some fields here *) { + t_tok = $2; + t_name = Name $3; + t_tparams = None; + t_tconstraint = $4; + t_tokeq = $5; + t_kind = ClassConstType (Some $6); + t_sc = $7; } + } + /*(* class constants *)*/ | T_CONST class_constants_declaration TSEMICOLON { ClassConstants(None, $1, None, $2, $3) } diff --git a/lang_php/parsing/visitor_php.ml b/lang_php/parsing/visitor_php.ml index 08c400c32..bc5be3226 100644 --- a/lang_php/parsing/visitor_php.ml +++ b/lang_php/parsing/visitor_php.ml @@ -946,6 +946,9 @@ and v_class_stmt x = and v3 = v_hint_type v3 and v4 = v_tok v4 in () + | ClassType ((v1))-> + let v1 = v_type_def v1 + in () | ClassConstants ((v1, v2, opt_ty, v3, v4)) -> let v1 = v_option v_tok v1 and v2 = v_tok v2 @@ -1146,6 +1149,7 @@ and v_type_def_kind = function | Alias v1 -> let v1 = v_hint_type v1 in () | Newtype v1 -> let v1 = v_hint_type v1 in () + | ClassConstType v1 -> let v1 = v_option v_hint_type v1 in () and v_namespace_use_rule = function | ImportNamespace v1 -> let v1 = v_qualified_ident v1 in () diff --git a/lang_php/pretty/ast_pp_build.ml b/lang_php/pretty/ast_pp_build.ml index c7e0f582f..6f1a1bf10 100644 --- a/lang_php/pretty/ast_pp_build.ml +++ b/lang_php/pretty/ast_pp_build.ml @@ -740,6 +740,7 @@ and class_body env st acc = | XhpDecl _ -> acc (* TODO xhp decl *) | UseTrait _ -> raise (TodoConstruct "UseTrait") | TraitConstraint _ -> raise (TodoConstruct "TraitConstraint") + | ClassType _ -> raise (TodoConstruct "ConstType") and method_def env m = let acc = [] in diff --git a/tests/php/parsing/good_tconst_decl.php b/tests/php/parsing/good_tconst_decl.php new file mode 100644 index 000000000..ac4530766 --- /dev/null +++ b/tests/php/parsing/good_tconst_decl.php @@ -0,0 +1,66 @@ +id; + } + + public function testA(Aint::me::me::me::Aint $x): void {} +} + +interface I { + abstract const type abs_class_by_class; +} + +class Aint extends A { + const type abs_class_by_class = int; + const type me as Aint = Aint; + const type Aint = self::hop; + const type hop = int; + const type vec = ConstVector; + + public function test(): void { + $this->testA(101); + } + + public function overriding(): ImmVector { + return ImmVector {}; + } +} + +class Astr extends A { + const type abs_class_by_class = string; +} + +abstract class B { + abstract const type AType as A; + abstract public static function getAID(): this::AType::abs_class_by_class; +} + +class Bint extends B { + const type AType = Aint; + public static function getAID(): this::AType::abs_class_by_class { + return 0; + } +} + +class Bstr extends B { + const type AType = Astr; + public static function getAID(): this::AType::abs_class_by_class { + return ''; + } +} + +function test(Aint $x): int { + return $x->getID(); +}