Introduce the ConstFun attribute
commitf96315bdabf429e6433bccc3d51d01c5e9a8c15b
authorJames Wu <jjwu@fb.com>
Wed, 3 Mar 2021 05:03:51 +0000 (2 21:03 -0800)
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>
Wed, 3 Mar 2021 05:08:49 +0000 (2 21:08 -0800)
treec939f6428176cc6f94b27b2fca1fad712af7b86b
parent503b76a7052248a122969909ae5b531f68fd0b75
Introduce the ConstFun attribute

Summary:
Before this diff, I was using `<<__Const>>` as the attribute for lambdas with constness, but afterwards I decided that `<<__ConstFun>>` was a better choice, since `<<__Const>>` can also be used on parameters to a constructor to mean that the property should be const, and I didn't want to confuse the concepts.It also allows us to enforce that `<<__ConstFun>>` only appear under the unstable feature.

<<__ConstFun>> is an attribute which, when placed on a function, method, or closure, enforces the following:
1. All parameters are automatically treated as readonly (without having to specify)
2. The $this type on a method is considered readonly, and the method is readonly
3. All values captured by a closure are readonly.

Implementation detail:

Note that <<__ConstFun>> is implemented as an attribute on parameters and on lambdas, but NOT on closure type specifiers. This is because we don't have an appropriate way to allow attributes on closure type specifiers in Hack, and adding new parsing syntax seems worse when we don't know what that syntax will look like. Instead, we adopt the following semantics:

<<__ConstFun>> on a lambda changes the function types' flag of is_const to true.

<<__ConstFun>> on a parameter is *only* valid when the parameter has a function typehint. We will enforce this with a NastCheck in the diff above.

If a function typehint is also annotated with `<<__ConstFun>>`, we only accept functions with `<<__ConstFun>>` on them(i.e.,`Typing_defs_flags.get_ft_is_const = true`) as input.

I know that this is kind of confusing from the implementation perspective, and once we decide on a valid syntax we should be able to get rid of it. For the prototype though, I think this will be fine.

Note that this means we do not allow properties that are function types to be marked `<<__ConstFun>>` (or function types in any other location besides on a parameter, for that matter). This is not unsound, since any ConstFun function is a subtype of a regular function of the same type, but it is incomplete. I do not know of any use cases where having a property function type be ConstFun would be useful, so I doubt this will matter. In the future, it may be helpful to allow a `<<__ConstFunReturn>>` attribute as well to return a const function, but something like that would need to be enforced like readonly as well, so it's not exactly easy to do.

Reviewed By: zilberstein

Differential Revision: D26562108

fbshipit-source-id: 80e0b060c92213cc5bbca0bde5ea2f2d0b423bd0
102 files changed:
hphp/hack/src/decl/decl_fun_utils.ml
hphp/hack/src/decl/decl_fun_utils.mli
hphp/hack/src/decl/decl_hint.ml
hphp/hack/src/decl/decl_nast.ml
hphp/hack/src/decl/direct_decl_smart_constructors.rs
hphp/hack/src/decl/shallow_decl.ml
hphp/hack/src/naming/naming_special_names.ml
hphp/hack/src/naming/naming_special_names.rs
hphp/hack/src/oxidized_by_ref/manual/typing_defs_flags.rs
hphp/hack/src/parser/rust_parser_errors.rs
hphp/hack/src/typing/tast_check/readonly_check.ml
hphp/hack/src/typing/tast_check/type_serialization_identity_check.ml
hphp/hack/src/typing/typing.ml
hphp/hack/src/typing/typing_defs_core.ml
hphp/hack/src/typing/typing_defs_core.mli
hphp/hack/src/typing/typing_defs_flags.ml
hphp/hack/src/typing/typing_print.ml
hphp/hack/src/typing/typing_utils.ml
hphp/hack/test/decl/abstract_method.php.exp
hphp/hack/test/decl/accept_disposable.php.exp
hphp/hack/test/decl/array_typehints.php.exp
hphp/hack/test/decl/async_and_generator_functions.php.exp
hphp/hack/test/decl/at_most_rx_as_func.php.exp
hphp/hack/test/decl/at_most_rx_as_func_with_optional_func.php.exp
hphp/hack/test/decl/atom.php.exp
hphp/hack/test/decl/auto_ns_use.php.exp
hphp/hack/test/decl/cipp.php.exp
hphp/hack/test/decl/class_in_namespace.php.exp
hphp/hack/test/decl/classes.php.exp
hphp/hack/test/decl/classes_consistent_construct.php.exp
hphp/hack/test/decl/classes_inferred_constant_types.php.exp
hphp/hack/test/decl/classes_inheritance.php.exp
hphp/hack/test/decl/classes_require.php.exp
hphp/hack/test/decl/classes_typeconst.php.exp
hphp/hack/test/decl/const_attribute.php.exp
hphp/hack/test/decl/constraints_mentioning_tparams_in_same_list.php.exp
hphp/hack/test/decl/denotable_unions.php.exp
hphp/hack/test/decl/deprecated.php.exp
hphp/hack/test/decl/deprecated_string_concat.php.exp
hphp/hack/test/decl/deprecated_string_escaping.php.exp
hphp/hack/test/decl/duplicate_fun_attributes.php.exp
hphp/hack/test/decl/dynamically_callable.php.exp
hphp/hack/test/decl/empty_method_name.php.exp
hphp/hack/test/decl/explicit_type_collection.php.exp
hphp/hack/test/decl/file_mode.php.exp
hphp/hack/test/decl/final_method.php.exp
hphp/hack/test/decl/function_where_constraints.php.exp
hphp/hack/test/decl/functions.php.exp
hphp/hack/test/decl/generic_classes.php.exp
hphp/hack/test/decl/generic_method_tparam_scope.php.exp
hphp/hack/test/decl/hhi.hhi.exp
hphp/hack/test/decl/higher_kinded.php.exp
hphp/hack/test/decl/ifc_policied.php.exp
hphp/hack/test/decl/inout.php.exp
hphp/hack/test/decl/interface.php.exp
hphp/hack/test/decl/interfaces.php.exp
hphp/hack/test/decl/like_types.php.exp
hphp/hack/test/decl/memoize_lsb.php.exp
hphp/hack/test/decl/missing_function_typehints.php.exp
hphp/hack/test/decl/mutable.php.exp
hphp/hack/test/decl/mutable_as_hint1.php.exp
hphp/hack/test/decl/namespace_body_plus_declarations_outside_body.php.exp
hphp/hack/test/decl/namespace_elaboration.php.exp
hphp/hack/test/decl/namespace_global_body_plus_declarations_outside_body.php.exp
hphp/hack/test/decl/namespace_import.php.exp
hphp/hack/test/decl/namespace_self.php.exp
hphp/hack/test/decl/namespace_unscoped.php.exp
hphp/hack/test/decl/only_rx_if_impl_method.php.exp
hphp/hack/test/decl/override_attribute.php.exp
hphp/hack/test/decl/php_std_lib.hhi.exp
hphp/hack/test/decl/property_declarations.php.exp
hphp/hack/test/decl/property_needs_init.hhi.exp
hphp/hack/test/decl/pure.php.exp
hphp/hack/test/decl/qualified_name_in_attribute_arg.php.exp
hphp/hack/test/decl/readonly.php.exp
hphp/hack/test/decl/ret_from_kind.php.exp
hphp/hack/test/decl/return_disposable.php.exp
hphp/hack/test/decl/returns_void_to_rx.php.exp
hphp/hack/test/decl/rewritten_tparams.php.exp
hphp/hack/test/decl/rx.php.exp
hphp/hack/test/decl/self_in_type_constant.php.exp
hphp/hack/test/decl/self_param_mutability.php.exp
hphp/hack/test/decl/shapes.php.exp
hphp/hack/test/decl/soft_reified.php.exp
hphp/hack/test/decl/soft_type_hint.php.exp
hphp/hack/test/decl/static_method_call_with_explicit_targ.php.exp
hphp/hack/test/decl/tparams_on_class_and_method.php.exp
hphp/hack/test/decl/traits.php.exp
hphp/hack/test/decl/tuples.php.exp
hphp/hack/test/decl/type_param_attrs.php.exp
hphp/hack/test/decl/typeconst_property_promotion.php.exp
hphp/hack/test/decl/unnamed_variadic_method_parameter.php.exp
hphp/hack/test/decl/use_type.php.exp
hphp/hack/test/decl/variadic_parameter.php.exp
hphp/hack/test/decl/wildcard_invalid.php.exp
hphp/hack/test/decl/wildcard_invalid_targ.php.exp
hphp/hack/test/decl/xhp.php.exp
hphp/hack/test/decl/xhp_self.php.exp
hphp/hack/test/decl/yield_deeper.php.exp
hphp/hack/test/typecheck/readonly/constfun_without_unstable.php [new file with mode: 0644]
hphp/hack/test/typecheck/readonly/constfun_without_unstable.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/readonly/lambda.php