Full Code of hhvm/hack-langspec for AI

master 007011a2dd06 cached
528 files
1.5 MB
472.4k tokens
1335 symbols
1 requests
Download .txt
Showing preview only (1,677K chars total). Download the full file or copy to clipboard to get everything.
Repository: hhvm/hack-langspec
Branch: master
Commit: 007011a2dd06
Files: 528
Total size: 1.5 MB

Directory structure:
gitextract_tmng50ms/

├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FORMATTING.md
├── LICENSE
├── README.md
├── spec/
│   ├── 00-specification-for-hack.md
│   ├── 01-introduction.md
│   ├── 02-conformance.md
│   ├── 03-terms-and-definitions.md
│   ├── 04-basic-concepts.md
│   ├── 05-types.md
│   ├── 06-constants.md
│   ├── 07-variables.md
│   ├── 08-conversions.md
│   ├── 09-lexical-structure.md
│   ├── 10-expressions.md
│   ├── 11-statements.md
│   ├── 12-script-inclusion.md
│   ├── 13-enums.md
│   ├── 14-generic-types-methods-and-functions.md
│   ├── 15-functions.md
│   ├── 16-classes.md
│   ├── 17-interfaces.md
│   ├── 18-traits.md
│   ├── 19-exception-handling.md
│   ├── 20-namespaces.md
│   ├── 21-attributes.md
│   ├── 22-grammar.md
│   ├── 23-differences-from-php.md
│   ├── 24-bibliography.md
│   └── hack-spec-draft.md
├── tests/
│   ├── .hhconfig
│   ├── Attributes/
│   │   ├── .hhconfig
│   │   ├── __ConsistentConstruct.php
│   │   ├── __ConsistentConstruct.php.expect
│   │   ├── __Memoize.php
│   │   ├── __Memoize.php.expect
│   │   ├── __Override.php
│   │   ├── __Override.php.expect
│   │   ├── attributes.php
│   │   └── attributes.php.expect
│   ├── Basic_Concepts/
│   │   ├── .hhconfig
│   │   ├── program_structure.php
│   │   ├── program_structure.php.expectf
│   │   ├── top_level_stuff.php
│   │   └── top_level_stuff.php.expect
│   ├── Classes/
│   │   ├── .hhconfig
│   │   ├── Aircraft.php
│   │   ├── Aircraft.php.expect
│   │   ├── Closure_call.php
│   │   ├── Closure_call.php.expectf
│   │   ├── Generator_getReturn.php
│   │   ├── Generator_getReturn.php.expectf
│   │   ├── MathLibrary.php
│   │   ├── MathLibrary.php.expect
│   │   ├── MathLibrary_test1.php
│   │   ├── MathLibrary_test1.php.expect
│   │   ├── MyCollection.php
│   │   ├── MyCollection.php.expect
│   │   ├── MyList.php
│   │   ├── MyList.php.expect
│   │   ├── PassengerJet.php
│   │   ├── PassengerJet.php.expect
│   │   ├── Point.php
│   │   ├── Point.php.expect
│   │   ├── Point2.php
│   │   ├── Point2.php.expect
│   │   ├── Point_test1.php
│   │   ├── Point_test1.php.expect
│   │   ├── Serializable.php
│   │   ├── Serializable.php.expectf
│   │   ├── Serializable_with_untrusted_data.php
│   │   ├── Serializable_with_untrusted_data.php.expectf
│   │   ├── Vehicle.php
│   │   ├── Vehicle.php.expect
│   │   ├── Vehicle_test1.php
│   │   ├── Vehicle_test1.php.expect
│   │   ├── __PHP_Incomplete_Class.php
│   │   ├── __PHP_Incomplete_Class.php.expect
│   │   ├── abstract_constants.php
│   │   ├── abstract_constants.php.expect
│   │   ├── cc.php
│   │   ├── cc.php.expectf
│   │   ├── classes.php
│   │   ├── classes.php.expect
│   │   ├── cloning.php
│   │   ├── cloning.php.expect
│   │   ├── constructors.php
│   │   ├── constructors.php.expect
│   │   ├── destructors.php
│   │   ├── destructors.php.expect
│   │   ├── dynamic_methods.php
│   │   ├── dynamic_methods.php.expect
│   │   ├── invoke.php
│   │   ├── invoke.php.expect
│   │   ├── property_initializer.php
│   │   ├── property_initializer.php.expect
│   │   ├── require_extends_implements.php
│   │   ├── require_extends_implements.php.expectf
│   │   ├── sleep_and_wakeup.php
│   │   ├── sleep_and_wakeup.php.expectf
│   │   ├── test_for_new_types.php
│   │   ├── test_for_new_types.php.expectf
│   │   ├── type_constants.php
│   │   ├── type_constants.php.expect
│   │   ├── visibility.php
│   │   └── visibility.php.expect
│   ├── Collections/
│   │   ├── .hhconfig
│   │   ├── collections_intrinsics_list.php
│   │   ├── collections_intrinsics_list.php.expect
│   │   ├── collections_operations.php
│   │   ├── collections_operations.php.expect
│   │   ├── vector.php
│   │   └── vector.php.expect
│   ├── Constants/
│   │   ├── .hhconfig
│   │   ├── Testfile.txt
│   │   ├── constants.php
│   │   ├── constants.php.expect
│   │   ├── context_dependent_constants.php
│   │   ├── context_dependent_constants.php.expectf
│   │   ├── core_predefined_constants.php
│   │   └── core_predefined_constants.php.expect
│   ├── Enums/
│   │   ├── .hhconfig
│   │   ├── enum_constraints.php
│   │   ├── enum_constraints.php.expect
│   │   ├── enums.php
│   │   ├── enums.php.expect
│   │   ├── enums_ops.php
│   │   ├── enums_ops.php.expect
│   │   ├── string_int_equality_problem.php
│   │   └── string_int_equality_problem.php.expectf
│   ├── Exception_Handling/
│   │   ├── .hhconfig
│   │   ├── Exception_class.php
│   │   ├── Exception_class.php.expectf
│   │   ├── MyRangeException.php
│   │   ├── MyRangeException.php.expect
│   │   ├── MyRangeException_test1.php
│   │   ├── MyRangeException_test1.php.expectf
│   │   ├── hierarchy_of_exception_classes.php
│   │   ├── hierarchy_of_exception_classes.php.expect
│   │   ├── jump_from_catch_or_finally_clause.php
│   │   ├── jump_from_catch_or_finally_clause.php.expect
│   │   ├── odds_and_ends.php
│   │   ├── odds_and_ends.php.expect
│   │   ├── set_exception_handler.php
│   │   └── set_exception_handler.php.expectf
│   ├── Expressions/
│   │   ├── .hhconfig
│   │   ├── Additive_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── addition_subtraction_concatenation.php
│   │   │   ├── addition_subtraction_concatenation.php.expect
│   │   │   ├── array_concatenation.php
│   │   │   └── array_concatenation.php.expect
│   │   ├── Binary_Logical_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── binary_logical_operators.php
│   │   │   └── binary_logical_operators.php.expect
│   │   ├── Bitwise_Shift_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── bitwise_shift.php
│   │   │   └── bitwise_shift.php.expect
│   │   ├── Bitwise_and_or_xor_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── bitwise_and_or_xor.php
│   │   │   └── bitwise_and_or_xor.php.expect
│   │   ├── Coalesce Operator/
│   │   │   ├── coalesce.php
│   │   │   └── coalesce.php.expect
│   │   ├── Conditional_Operator/
│   │   │   ├── .hhconfig
│   │   │   ├── conditional.php
│   │   │   └── conditional.php.expect
│   │   ├── Equality_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── Testfile1.txt
│   │   │   ├── Testfile2.txt
│   │   │   ├── comparisons.php
│   │   │   ├── comparisons.php.expect
│   │   │   ├── equality_comparison_of_objects.php
│   │   │   └── equality_comparison_of_objects.php.expect
│   │   ├── Instanceof_Operator/
│   │   │   ├── .hhconfig
│   │   │   ├── instanceof.php
│   │   │   └── instanceof.php.expect
│   │   ├── Lambda_Expressions/
│   │   │   ├── .hhconfig
│   │   │   ├── lambdas.php
│   │   │   └── lambdas.php.expectf
│   │   ├── Multiplicative_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── multiplication_division_modulus.php
│   │   │   └── multiplication_division_modulus.php.expect
│   │   ├── Null_safe_method_call/
│   │   │   ├── .hhconfig
│   │   │   ├── null_safe_calls.php
│   │   │   └── null_safe_calls.php.expect
│   │   ├── Pipe_Operator/
│   │   │   ├── pipe.php
│   │   │   └── pipe.php.expect
│   │   ├── Postfix_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── array_creation.php
│   │   │   ├── array_creation.php.expect
│   │   │   ├── exponentiation.php
│   │   │   ├── exponentiation.php.expect
│   │   │   ├── function_call.php
│   │   │   ├── function_call.php.expect
│   │   │   ├── function_call_with_strict_checking.php
│   │   │   ├── function_call_with_strict_checking.php.expectf
│   │   │   ├── member_selection_operator.php
│   │   │   ├── member_selection_operator.php.expect
│   │   │   ├── new.php
│   │   │   ├── new.php.expect
│   │   │   ├── new_anonymous_classes.php
│   │   │   ├── new_anonymous_classes.php.expectf
│   │   │   ├── nullable_and_arithmetic.php
│   │   │   ├── nullable_and_arithmetic.php.expect
│   │   │   ├── nullsafe_member_selection.php
│   │   │   ├── nullsafe_member_selection.php.expect
│   │   │   ├── post-increment_and_decrement_integer_edge_cases.php
│   │   │   ├── post-increment_and_decrement_integer_edge_cases.php.expect
│   │   │   ├── post_increment_and_decrement.php
│   │   │   ├── post_increment_and_decrement.php.expect
│   │   │   ├── scope_resolution_operator.php
│   │   │   ├── scope_resolution_operator.php.expectf
│   │   │   ├── subscripting.php
│   │   │   ├── subscripting.php.expect
│   │   │   ├── subscripting_2.php
│   │   │   ├── subscripting_2.php.expect
│   │   │   └── subscripting_2.php.expectf
│   │   ├── Primary_Expressions/
│   │   │   ├── .hhconfig
│   │   │   ├── Point.php
│   │   │   ├── Point.php.expect
│   │   │   ├── Point2.php
│   │   │   ├── Point2.php.expect
│   │   │   ├── intrinsics_echo.php
│   │   │   ├── intrinsics_echo.php.expect
│   │   │   ├── intrinsics_exit.php
│   │   │   ├── intrinsics_exit.php.expect
│   │   │   ├── intrinsics_invariant.php
│   │   │   ├── intrinsics_invariant.php.expect
│   │   │   ├── intrinsics_list.php
│   │   │   ├── intrinsics_list.php.expect
│   │   │   ├── listPHP.php
│   │   │   ├── listPHP.php.expect
│   │   │   ├── primary.php
│   │   │   └── primary.php.expect
│   │   ├── Relational_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── Testfile1.txt
│   │   │   ├── Testfile2.txt
│   │   │   ├── combined_comparison.php
│   │   │   ├── combined_comparison.php.expectf
│   │   │   ├── comparisons.php
│   │   │   ├── comparisons.php.expect
│   │   │   ├── relational_comparison_of_objects.php
│   │   │   └── relational_comparison_of_objects.php.expect
│   │   ├── Testfile.txt
│   │   ├── Unary_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── cast.php
│   │   │   ├── cast.php.expect
│   │   │   ├── error_control.php
│   │   │   ├── error_control.php.expectf
│   │   │   ├── pre-increment_and_decrement.php
│   │   │   ├── pre-increment_and_decrement.php.expect
│   │   │   ├── pre-increment_and_decrement_integer_edge_cases.php
│   │   │   ├── pre-increment_and_decrement_integer_edge_cases.php.expect
│   │   │   ├── unary_arithmetic_operators.php
│   │   │   └── unary_arithmetic_operators.php.expect
│   │   ├── Yield_Operator/
│   │   │   ├── .hhconfig
│   │   │   ├── yield.php
│   │   │   ├── yield.php.expectf
│   │   │   ├── yield_from.php
│   │   │   └── yield_from.php.expectf
│   │   ├── conversions.php
│   │   ├── conversions.php.expectf
│   │   ├── limits_on_types_in_arithmetic.php
│   │   ├── limits_on_types_in_arithmetic.php.expect
│   │   ├── yield.php
│   │   └── yield.php.expectf
│   ├── Functions/
│   │   ├── .hhconfig
│   │   ├── TestInc.php
│   │   ├── TestInc.php.expect
│   │   ├── anonymous_function_name.php
│   │   ├── anonymous_function_name.php.expect
│   │   ├── anonymous_functions.php
│   │   ├── anonymous_functions.php.expectf
│   │   ├── anonymous_functions2.php
│   │   ├── anonymous_functions2.php.expect
│   │   ├── async_functions.php
│   │   ├── async_functions.php.expectf
│   │   ├── async_functions2.php
│   │   ├── async_functions2.php.expect
│   │   ├── basics.php
│   │   ├── basics.php.expectf
│   │   ├── callable_typehint.php
│   │   ├── callable_typehint.php.expect
│   │   ├── conditionally_defined_function.php
│   │   ├── conditionally_defined_function.php.expectf
│   │   ├── default_arguments.php
│   │   ├── default_arguments.php.expect
│   │   ├── noreturn.php
│   │   ├── noreturn.php.expect
│   │   ├── override_on_return_type.php
│   │   ├── override_on_return_type.php.expect
│   │   ├── recursion.php
│   │   ├── recursion.php.expect
│   │   ├── this_play.php
│   │   ├── this_play.php.expect
│   │   ├── variable_functions.php
│   │   └── variable_functions.php.expect
│   ├── Generics/
│   │   ├── .hhconfig
│   │   ├── Complex.php
│   │   ├── Complex.php.expect
│   │   ├── Complex_test.php
│   │   ├── Complex_test.php.expect
│   │   ├── Interface_Support.php
│   │   ├── Interface_Support.php.expect
│   │   ├── MyVector.php
│   │   ├── MyVector.php.expect
│   │   ├── MyVector_test.php
│   │   ├── MyVector_test.php.expect
│   │   ├── Stack.php
│   │   ├── Stack.php.expect
│   │   ├── Stack_test.php
│   │   ├── Stack_test.php.expect
│   │   ├── constraints.php
│   │   ├── constraints.php.expect
│   │   ├── contravariance_example.php
│   │   ├── contravariance_example.php.expect
│   │   ├── covariance_example.php
│   │   ├── covariance_example.php.expect
│   │   ├── generic_function.php
│   │   ├── generic_function.php.expect
│   │   ├── generics.php
│   │   └── generics.php.expect
│   ├── Interfaces/
│   │   ├── .hhconfig
│   │   ├── MyCollection.php
│   │   ├── MyCollection.php.expect
│   │   ├── MyList.php
│   │   ├── MyList.php.expect
│   │   ├── MyQueue.php
│   │   ├── MyQueue.php.expect
│   │   ├── interface_requirements.php
│   │   ├── interface_requirements.php.expect
│   │   ├── interfaces.php
│   │   ├── interfaces.php.expect
│   │   ├── qq.php
│   │   └── qq.php.expect
│   ├── Lexical_Structure/
│   │   ├── .hhconfig
│   │   ├── Tokens/
│   │   │   ├── .hhconfig
│   │   │   ├── array_literals.php
│   │   │   ├── array_literals.php.expect
│   │   │   ├── heredoc_string_literals.php
│   │   │   ├── heredoc_string_literals.php.expect
│   │   │   ├── integer_literals_edge_cases.php
│   │   │   ├── integer_literals_edge_cases.php.expect
│   │   │   ├── name_case_sensitivity.php
│   │   │   ├── name_case_sensitivity.php.expectf
│   │   │   ├── names.php
│   │   │   ├── names.php.expect
│   │   │   ├── nowdoc_string_literals.php
│   │   │   ├── nowdoc_string_literals.php.expect
│   │   │   ├── string_literals.php
│   │   │   ├── string_literals.php.expect
│   │   │   ├── unicode_escape_sequences.php
│   │   │   └── unicode_escape_sequences.php.expect
│   │   ├── comments.php
│   │   ├── comments.php.expect
│   │   ├── keywords.php
│   │   └── keywords.php.expect
│   ├── Namespaces/
│   │   ├── .hhconfig
│   │   ├── Circle.php
│   │   ├── Circle.php.expect
│   │   ├── Point.php
│   │   ├── Point.php.expect
│   │   ├── namespaces1.php
│   │   ├── namespaces1.php.expect
│   │   ├── namespaces2.php
│   │   ├── namespaces2.php.expectf
│   │   ├── namespaces2_test.php
│   │   ├── namespaces2_test.php.expectf
│   │   ├── use_groups.php
│   │   ├── use_groups.php.expectf
│   │   ├── use_groups_require_file.php
│   │   ├── use_groups_require_file.php.expect
│   │   ├── using_namespaces_1.php
│   │   ├── using_namespaces_1.php.expect
│   │   ├── using_namespaces_3.php
│   │   ├── using_namespaces_3.php.expect
│   │   ├── using_namespaces_3_test.php
│   │   └── using_namespaces_3_test.php.expect
│   ├── Nullable_Types/
│   │   ├── .hhconfig
│   │   ├── conversions.php
│   │   ├── conversions.php.expectf
│   │   ├── nullables.php
│   │   └── nullables.php.expect
│   ├── Script_Inclusion/
│   │   ├── .hhconfig
│   │   ├── Circle.php
│   │   ├── Circle.php.expect
│   │   ├── Point.php
│   │   ├── Point.php.expect
│   │   ├── Positions.php
│   │   ├── Positions.php.expect
│   │   ├── limits.php
│   │   ├── limits.php.expect
│   │   ├── mycolors.php
│   │   ├── mycolors.php.expect
│   │   ├── require.php
│   │   ├── require.php.expectf
│   │   ├── require_once.php
│   │   ├── require_once.php.expectf
│   │   ├── return_none.php
│   │   ├── return_none.php.expect
│   │   ├── return_with_value.php
│   │   └── return_with_value.php.expect
│   ├── Serialization/
│   │   ├── .hhconfig
│   │   ├── Point.php
│   │   ├── Point.php.expectf
│   │   ├── serialize.php
│   │   └── serialize.php.expectf
│   ├── Shapes/
│   │   ├── .hhconfig
│   │   ├── shapes.php
│   │   ├── shapes.php.expect
│   │   ├── shapes_rf.php
│   │   └── shapes_rf.php.expect
│   ├── Statements/
│   │   ├── .hhconfig
│   │   ├── Iteration/
│   │   │   ├── .hhconfig
│   │   │   ├── do.php
│   │   │   ├── do.php.expect
│   │   │   ├── for.php
│   │   │   ├── for.php.expect
│   │   │   ├── foreach.php
│   │   │   ├── foreach.php.expect
│   │   │   ├── while.php
│   │   │   └── while.php.expect
│   │   ├── Jump/
│   │   │   ├── .hhconfig
│   │   │   ├── break.php
│   │   │   ├── break.php.expect
│   │   │   ├── continue.php
│   │   │   └── continue.php.expect
│   │   ├── Selection/
│   │   │   ├── .hhconfig
│   │   │   ├── if.php
│   │   │   ├── if.php.expectf
│   │   │   ├── switch.php
│   │   │   └── switch.php.expect
│   │   ├── expression_statement.php
│   │   └── expression_statement.php.expect
│   ├── Traits/
│   │   ├── .hhconfig
│   │   ├── trait_implements_interface.php
│   │   ├── trait_implements_interface.php.expect
│   │   ├── trait_requirements.php
│   │   ├── trait_requirements.php.expect
│   │   ├── traits.php
│   │   └── traits.php.expect
│   ├── Tuples/
│   │   ├── .hhconfig
│   │   ├── tuples.php
│   │   └── tuples.php.expect
│   ├── Types/
│   │   ├── .hhconfig
│   │   ├── Issue_109.php
│   │   ├── Issue_109.php.expectf
│   │   ├── Issue_110.php
│   │   ├── Issue_110.php.expect
│   │   ├── Testfile.txt
│   │   ├── arraykey.php
│   │   ├── arraykey.php.expect
│   │   ├── arrays.php
│   │   ├── arrays.php.expectf
│   │   ├── arrays2.php
│   │   ├── arrays2.php.expectf
│   │   ├── bool.php
│   │   ├── bool.php.expect
│   │   ├── classname.php
│   │   ├── classname.php.expect
│   │   ├── closure.php
│   │   ├── closure.php.expect
│   │   ├── determined_type.php
│   │   ├── determined_type.php.expect
│   │   ├── enum.php
│   │   ├── enum.php.expect
│   │   ├── float.php
│   │   ├── float.php.expect
│   │   ├── int.php
│   │   ├── int.php.expect
│   │   ├── mixed.php
│   │   ├── mixed.php.expect
│   │   ├── nullables.php
│   │   ├── nullables.php.expect
│   │   ├── num.php
│   │   ├── num.php.expect
│   │   ├── numeric_like_strings.php
│   │   ├── numeric_like_strings.php.expect
│   │   ├── numeric_strings.php
│   │   ├── numeric_strings.php.expect
│   │   ├── resources.php
│   │   ├── resources.php.expectf
│   │   ├── scalar_general.php
│   │   ├── scalar_general.php.expectf
│   │   ├── shape_specific_functions.php
│   │   ├── shape_specific_functions.php.expect
│   │   ├── shape_subtyping.php
│   │   ├── shape_subtyping.php.expect
│   │   ├── shapes.php
│   │   ├── shapes.php.expect
│   │   ├── shapes.php.expectf
│   │   ├── shapes2.php
│   │   ├── shapes2.php.expectf
│   │   ├── shapes_rf.php
│   │   ├── shapes_rf.php.expect
│   │   ├── string.php
│   │   ├── string.php.expect
│   │   ├── this.php
│   │   ├── this.php.expectf
│   │   ├── tuple.php
│   │   ├── tuple.php.expect
│   │   ├── type_aliases.php
│   │   ├── type_aliases.php.expectf
│   │   ├── type_aliases_rf.php
│   │   ├── type_aliases_rf.php.expectf
│   │   ├── type_inferencing.php
│   │   ├── type_inferencing.php.expect
│   │   ├── type_side_effects.php
│   │   ├── type_side_effects.php.expect
│   │   ├── void.php
│   │   └── void.php.expect
│   └── Variables/
│       ├── .hhconfig
│       ├── placeholder_variable.php
│       ├── placeholder_variable.php.expect
│       ├── predefined_variables.php
│       ├── predefined_variables.php.expect
│       ├── variable_kinds.php
│       └── variable_kinds.php.expect
└── tools/
    ├── README.md
    ├── add_hh_fixme_to_tests.php
    ├── add_language_to_code_blocks.php
    ├── create_test_expect_files.php
    ├── split.php
    ├── toc.php
    └── xreference/
        ├── README.md
        ├── section_map.csv
        └── xreference.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
www.pid
.commit-template
*.php.diff
*.php.out


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated.

================================================
FILE: CONTRIBUTING.md
================================================
## Contributing to the Specification for Hack

We'd love your help in improving, correcting, adding to the specification.
Please [file an issue](https://github.com/hhvm/hack-langspec/issues/) or submit a 
pull request at the [spec git repo](https://github.com/hhvm/hack-langspec).

## License for your Contributions

Any contribution you provide to the Specification for Hack must adhere to the
same license as stated in the [LICENSE](LICENSE).


================================================
FILE: FORMATTING.md
================================================
# Formatting rules

1. The format of the Hack Language Specification is
   [Markdown](http://daringfireball.net/projects/markdown/).
2. Everything in the actual specification document must be ASCII only.
3. The only allowed extensions to original Markdown are tables and code blocks
   (indicated by three backticks).
4. Style
  * Use spaces to indent, not tabs.
  * For headings, use prefixed hash symbols `# Example`, not underlining it
    with `===`.
  * Use of *inline* links `[example](http://example.org)` is preferred over
    *reference* links `[example][xmpl]` unless used multiple times in a
    paragraph or section. This is to allow for easier splitting and
    reorganization of the document.
  * Try to stick to 80 chars wide, if possible. This is not as strict as
    in coding standard rules, but still easier to read most of the times.
    This does only apply to text, not to code examples or tables.


================================================
FILE: LICENSE
================================================
Facebook has dedicated all copyright to this specification to the public 
domain worldwide under the CC0 Public Domain Dedication located at 
<http://creativecommons.org/publicdomain/zero/1.0/>. 

The first draft of this specification was initially written in 2015 by
Facebook, Inc.

This specification is distributed without any warranty.



================================================
FILE: README.md
================================================
## Deprecated, Unmaintained

This repo contains the Hack Language Specification, a modified version
of the PHP specification. It is no longer maintained and does not
reflect the current version of Hack.

# Hack Language Specification

The easiest way to navigate the specification is
via the [table of contents](https://github.com/hhvm/hack-langspec/blob/master/spec/00-specification-for-hack.md).

The latest official release of the specification is [1.1](https://github.com/hhvm/hack-langspec/releases/tag/v1.1).

You can run the specification tests with [HHVM](https://docs.hhvm.com/hhvm/) via its
[test runner](https://github.com/facebook/hhvm/blob/master/hphp/test/README.md) and the
[Hack typechecker](https://docs.hhvm.com/hack/typechecker/introduction) via `hh_client`.

Pull requests, issue filings and comments are extremely welcome.

Make sure you understand the [*contribution process*](CONTRIBUTING.md).


================================================
FILE: spec/00-specification-for-hack.md
================================================
<!-- This file is autogenerated, do not edit it manually -->
<!-- Run tools/toc.php instead -->

# Specification for Hack
Facebook has dedicated all copyright to this specification to the public
domain worldwide under the CC0 Public Domain Dedication located at
<http://creativecommons.org/publicdomain/zero/1.0/>. This specification
is distributed without any warranty.

(Initially written by Facebook, Inc., February 2015)

**Table of Contents**
- [Introduction](01-introduction.md#introduction)
- [Conformance](02-conformance.md#conformance)
- [Terms and Definitions](03-terms-and-definitions.md#terms-and-definitions)
- [Basic Concepts](04-basic-concepts.md#basic-concepts)
  - [Program Structure](04-basic-concepts.md#program-structure)
  - [Program Start-Up](04-basic-concepts.md#program-start-up)
  - [Program Termination](04-basic-concepts.md#program-termination)
  - [The Memory Model](04-basic-concepts.md#the-memory-model)
    - [General](04-basic-concepts.md#general)
    - [Reclamation and Automatic Memory Management](04-basic-concepts.md#reclamation-and-automatic-memory-management)
    - [Assignment](04-basic-concepts.md#assignment)
      - [General](04-basic-concepts.md#general-1)
      - [Value Assignment of Scalar Types to a Local Variable](04-basic-concepts.md#value-assignment-of-scalar-types-to-a-local-variable)
      - [Value Assignment of Object and Resource Types to a Local Variable](04-basic-concepts.md#value-assignment-of-object-and-resource-types-to-a-local-variable)
      - [ByRef Assignment for Scalar Types with Local Variables](04-basic-concepts.md#byref-assignment-for-scalar-types-with-local-variables)
      - [Byref Assignment of Non-Scalar Types with Local Variables](04-basic-concepts.md#byref-assignment-of-non-scalar-types-with-local-variables)
      - [Value Assignment of Array Types to Local Variables](04-basic-concepts.md#value-assignment-of-array-types-to-local-variables)
      - [Deferred Array Copying](04-basic-concepts.md#deferred-array-copying)
      - [General Value Assignment](04-basic-concepts.md#general-value-assignment)
      - [General ByRef Assignment](04-basic-concepts.md#general-byref-assignment)
    - [Argument Passing](04-basic-concepts.md#argument-passing)
    - [Value Returning](04-basic-concepts.md#value-returning)
    - [Cloning objects](04-basic-concepts.md#cloning-objects)
  - [Scope](04-basic-concepts.md#scope)
  - [Storage Duration](04-basic-concepts.md#storage-duration)
- [Types](05-types.md#types)
  - [General](05-types.md#general)
  - [The Boolean Type](05-types.md#the-boolean-type)
  - [The Integer Type](05-types.md#the-integer-type)
  - [The Floating-Point Type](05-types.md#the-floating-point-type)
  - [The Numeric Type](05-types.md#the-numeric-type)
  - [The String Type](05-types.md#the-string-type)
  - [The Array Key Type](05-types.md#the-array-key-type)
  - [The Null Type](05-types.md#the-null-type)
  - [Enumerated Types](05-types.md#enumerated-types)
  - [The Void Type](05-types.md#the-void-type)
  - [Array Types](05-types.md#array-types)
  - [Class Types](05-types.md#class-types)
  - [Interface Types](05-types.md#interface-types)
  - [Trait Types](05-types.md#trait-types)
  - [The `this` Type](05-types.md#the-this-type)
  - [Tuple Types](05-types.md#tuple-types)
  - [Shape Types](05-types.md#shape-types)
  - [Closure Types](05-types.md#closure-types)
  - [Resource Types](05-types.md#resource-types)
  - [Nullable Types](05-types.md#nullable-types)
  - [Generic Types](05-types.md#generic-types)
  - [The Classname Type](05-types.md#the-classname-type)
  - [Type Aliases](05-types.md#type-aliases)
  - [Supertypes and Subtypes](05-types.md#supertypes-and-subtypes)
  - [Type Side Effects](05-types.md#type-side-effects)
  - [Type Inferencing](05-types.md#type-inferencing)
- [Constants](06-constants.md#constants)
  - [General](06-constants.md#general)
  - [Context-Dependent Constants](06-constants.md#context-dependent-constants)
  - [Core Predefined Constants](06-constants.md#core-predefined-constants)
  - [User-Defined Constants](06-constants.md#user-defined-constants)
- [Variables](07-variables.md#variables)
  - [General](07-variables.md#general)
  - [Kinds of Variables](07-variables.md#kinds-of-variables)
    - [Local Variables](07-variables.md#local-variables)
    - [Array Elements](07-variables.md#array-elements)
    - [Function Statics](07-variables.md#function-statics)
    - [Instance Properties](07-variables.md#instance-properties)
    - [Static Properties](07-variables.md#static-properties)
    - [Class and Interface Constants](07-variables.md#class-and-interface-constants)
- [Conversions](08-conversions.md#conversions)
  - [General](08-conversions.md#general)
  - [Converting to Boolean Type](08-conversions.md#converting-to-boolean-type)
  - [Converting to Integer Type](08-conversions.md#converting-to-integer-type)
  - [Converting to Floating-Point Type](08-conversions.md#converting-to-floating-point-type)
  - [Converting to Number Type](08-conversions.md#converting-to-number-type)
  - [Converting to String Type](08-conversions.md#converting-to-string-type)
  - [Converting to Array Key Type](08-conversions.md#converting-to-array-key-type)
  - [Converting to Array Type](08-conversions.md#converting-to-array-type)
  - [Converting to Object Type](08-conversions.md#converting-to-object-type)
  - [Converting to Interface Type](08-conversions.md#converting-to-interface-type)
  - [Converting to Resource Type](08-conversions.md#converting-to-resource-type)
  - [Converting to Mixed Type](08-conversions.md#converting-to-mixed-type)
- [Lexical Structure](09-lexical-structure.md#lexical-structure)
  - [Scripts](09-lexical-structure.md#scripts)
  - [Grammars](09-lexical-structure.md#grammars)
  - [Grammar ambiguities](09-lexical-structure.md#grammar-ambiguities)
  - [Lexical Analysis](09-lexical-structure.md#lexical-analysis)
    - [General](09-lexical-structure.md#general)
    - [Comments](09-lexical-structure.md#comments)
    - [White Space](09-lexical-structure.md#white-space)
    - [Tokens](09-lexical-structure.md#tokens)
      - [General](09-lexical-structure.md#general-1)
      - [Names](09-lexical-structure.md#names)
      - [Keywords](09-lexical-structure.md#keywords)
      - [Literals](09-lexical-structure.md#literals)
        - [General](09-lexical-structure.md#general-2)
        - [Boolean Literals](09-lexical-structure.md#boolean-literals)
        - [Integer Literals](09-lexical-structure.md#integer-literals)
        - [Floating-Point Literals](09-lexical-structure.md#floating-point-literals)
        - [String Literals](09-lexical-structure.md#string-literals)
          - [Single-Quoted String Literals](09-lexical-structure.md#single-quoted-string-literals)
          - [Double-Quoted String Literals](09-lexical-structure.md#double-quoted-string-literals)
          - [Heredoc String Literals](09-lexical-structure.md#heredoc-string-literals)
          - [Nowdoc String Literals](09-lexical-structure.md#nowdoc-string-literals)
        - [The Null Literal](09-lexical-structure.md#the-null-literal)
      - [Operators and Punctuators](09-lexical-structure.md#operators-and-punctuators)
- [Expressions](10-expressions.md#expressions)
  - [General](10-expressions.md#general)
  - [Restrictions on Arithmetic Operations](10-expressions.md#restrictions-on-arithmetic-operations)
  - [Operations on Operands Having One or More Subtypes](10-expressions.md#operations-on-operands-having-one-or-more-subtypes)
  - [Primary Expressions](10-expressions.md#primary-expressions)
    - [General](10-expressions.md#general-1)
    - [Intrinsics](10-expressions.md#intrinsics)
      - [General](10-expressions.md#general-2)
      - [array](10-expressions.md#array)
      - [echo](10-expressions.md#echo)
      - [exit](10-expressions.md#exit)
      - [invariant](10-expressions.md#invariant)
      - [list](10-expressions.md#list)
    - [Collection Literals](10-expressions.md#collection-literals)
    - [Tuple Literals](10-expressions.md#tuple-literals)
    - [Shape Literals](10-expressions.md#shape-literals)
    - [Anonymous Function-Creation](10-expressions.md#anonymous-function-creation)
    - [Async Blocks](10-expressions.md#async-blocks)
  - [Postfix Operators](10-expressions.md#postfix-operators)
    - [General](10-expressions.md#general-3)
    - [The `clone` Operator](10-expressions.md#the-clone-operator)
    - [The `new` Operator](10-expressions.md#the-new-operator)
    - [Array Creation Operator](10-expressions.md#array-creation-operator)
    - [Subscript Operator](10-expressions.md#subscript-operator)
    - [Function Call Operator](10-expressions.md#function-call-operator)
    - [Member-Selection Operator](10-expressions.md#member-selection-operator)
    - [Null-Safe Member-Selection Operator](10-expressions.md#null-safe-member-selection-operator)
    - [Postfix Increment and Decrement Operators](10-expressions.md#postfix-increment-and-decrement-operators)
    - [Scope-Resolution Operator](10-expressions.md#scope-resolution-operator)
    - [Exponentiation Operator](10-expressions.md#exponentiation-operator)
  - [Unary Operators](10-expressions.md#unary-operators)
    - [General](10-expressions.md#general-4)
    - [Prefix Increment and Decrement Operators](10-expressions.md#prefix-increment-and-decrement-operators)
    - [Unary Arithmetic Operators](10-expressions.md#unary-arithmetic-operators)
    - [Error Control Operator](10-expressions.md#error-control-operator)
    - [Cast Operator](10-expressions.md#cast-operator)
    - [Await Operator](10-expressions.md#await-operator)
  - [`instanceof` Operator](10-expressions.md#instanceof-operator)
  - [Multiplicative Operators](10-expressions.md#multiplicative-operators)
  - [Additive Operators](10-expressions.md#additive-operators)
  - [Bitwise Shift Operators](10-expressions.md#bitwise-shift-operators)
  - [Relational Operators](10-expressions.md#relational-operators)
  - [Equality Operators](10-expressions.md#equality-operators)
  - [Bitwise AND Operator](10-expressions.md#bitwise-and-operator)
  - [Bitwise Exclusive OR Operator](10-expressions.md#bitwise-exclusive-or-operator)
  - [Bitwise Inclusive OR Operator](10-expressions.md#bitwise-inclusive-or-operator)
  - [Logical AND Operator](10-expressions.md#logical-and-operator)
  - [Logical Inclusive OR Operator](10-expressions.md#logical-inclusive-or-operator)
  - [Conditional Operator](10-expressions.md#conditional-operator)
  - [Coalesce Operator](10-expressions.md#coalesce-operator)
  - [Pipe Operator](10-expressions.md#pipe-operator)
  - [Lambda Expressions](10-expressions.md#lambda-expressions)
  - [Assignment Operators](10-expressions.md#assignment-operators)
    - [General](10-expressions.md#general-5)
    - [Simple Assignment](10-expressions.md#simple-assignment)
    - [Compound Assignment](10-expressions.md#compound-assignment)
  - [`yield` Operator](10-expressions.md#yield-operator)
  - [Constant Expressions](10-expressions.md#constant-expressions)
- [Statements](11-statements.md#statements)
  - [General](11-statements.md#general)
  - [Compound Statements](11-statements.md#compound-statements)
  - [Labeled Statements](11-statements.md#labeled-statements)
  - [Expression Statements](11-statements.md#expression-statements)
  - [Selection Statements](11-statements.md#selection-statements)
    - [General](11-statements.md#general-1)
    - [The `if` Statement](11-statements.md#the-if-statement)
    - [The `switch` Statement](11-statements.md#the-switch-statement)
  - [Iteration Statements](11-statements.md#iteration-statements)
    - [General](11-statements.md#general-2)
    - [The `while` Statement](11-statements.md#the-while-statement)
    - [The `do` Statement](11-statements.md#the-do-statement)
    - [The `for` Statement](11-statements.md#the-for-statement)
    - [The `foreach` Statement](11-statements.md#the-foreach-statement)
  - [Jump Statements](11-statements.md#jump-statements)
    - [General](11-statements.md#general-3)
    - [The `continue` Statement](11-statements.md#the-continue-statement)
    - [The `break` Statement](11-statements.md#the-break-statement)
    - [The `return` Statement](11-statements.md#the-return-statement)
    - [The `throw` Statement](11-statements.md#the-throw-statement)
  - [The `try` Statement](11-statements.md#the-try-statement)
- [Script Inclusion Operators](12-script-inclusion.md#script-inclusion-operators)
  - [General](12-script-inclusion.md#general)
  - [The `require` Directive](12-script-inclusion.md#the-require-directive)
  - [The `require_once` Directive](12-script-inclusion.md#the-require_once-directive)
- [Enums](13-enums.md#enums)
  - [General](13-enums.md#general)
  - [Enum Declarations](13-enums.md#enum-declarations)
  - [The Predefined Enumerated Type Methods](13-enums.md#the-predefined-enumerated-type-methods)
- [Generic Types, Methods, and Functions](14-generic-types-methods-and-functions.md#generic-types-methods-and-functions)
  - [General](14-generic-types-methods-and-functions.md#general)
  - [Type Parameters](14-generic-types-methods-and-functions.md#type-parameters)
  - [Type Constraints](14-generic-types-methods-and-functions.md#type-constraints)
  - [Type Arguments](14-generic-types-methods-and-functions.md#type-arguments)
  - [Open and Closed Generic Types](14-generic-types-methods-and-functions.md#open-and-closed-generic-types)
  - [Type Inferencing Revisited](14-generic-types-methods-and-functions.md#type-inferencing-revisited)
- [Functions](15-functions.md#functions)
  - [General](15-functions.md#general)
  - [Function Calls](15-functions.md#function-calls)
  - [Function Definitions](15-functions.md#function-definitions)
  - [Anonymous Functions](15-functions.md#anonymous-functions)
  - [Asynchronous Functions](15-functions.md#asynchronous-functions)
- [Classes](16-classes.md#classes)
  - [General](16-classes.md#general)
  - [Class Declarations](16-classes.md#class-declarations)
  - [Class Members](16-classes.md#class-members)
  - [Dynamic Methods](16-classes.md#dynamic-methods)
  - [Constants](16-classes.md#constants)
  - [Properties](16-classes.md#properties)
  - [Methods](16-classes.md#methods)
  - [Constructors](16-classes.md#constructors)
  - [Destructors](16-classes.md#destructors)
  - [Type Constants](16-classes.md#type-constants)
  - [Methods with Special Semantics](16-classes.md#methods-with-special-semantics)
    - [General](16-classes.md#general-1)
    - [Method `__call`](16-classes.md#method-__call)
    - [Method `__callStatic`](16-classes.md#method-__callstatic)
    - [Method `__clone`](16-classes.md#method-__clone)
    - [Method `__sleep`](16-classes.md#method-__sleep)
    - [Method `__toString`](16-classes.md#method-__tostring)
    - [Method `__wakeup`](16-classes.md#method-__wakeup)
  - [Serialization](16-classes.md#serialization)
  - [Predefined Classes](16-classes.md#predefined-classes)
    - [Class `AsyncGenerator`](16-classes.md#class-asyncgenerator)
    - [Class `Generator`](16-classes.md#class-generator)
    - [Class `__PHP_Incomplete_Class`](16-classes.md#class-__php_incomplete_class)
    - [Class `Shapes`](16-classes.md#class-shapes)
    - [Class `stdClass`](16-classes.md#class-stdclass)
- [Interfaces](17-interfaces.md#interfaces)
  - [General](17-interfaces.md#general)
  - [Interface Declarations](17-interfaces.md#interface-declarations)
  - [Interface Members](17-interfaces.md#interface-members)
  - [Constants](17-interfaces.md#constants)
  - [Methods](17-interfaces.md#methods)
  - [Predefined Interfaces](17-interfaces.md#predefined-interfaces)
    - [Interface `ArrayAccess`](17-interfaces.md#interface-arrayaccess)
    - [Interface `AsyncIterator`](17-interfaces.md#interface-asynciterator)
    - [Interface `AsyncKeyedIterator`](17-interfaces.md#interface-asynckeyediterator)
    - [Interface `Awaitable`](17-interfaces.md#interface-awaitable)
    - [Interface `Container`](17-interfaces.md#interface-container)
    - [Interface `IMemoizeParam`](17-interfaces.md#interface-imemoizeparam)
    - [Interface `Iterator`](17-interfaces.md#interface-iterator)
    - [Interface `IteratorAggregate`](17-interfaces.md#interface-iteratoraggregate)
    - [Interface `KeyedContainer`](17-interfaces.md#interface-keyedcontainer)
    - [Interface `KeyedTraversable`](17-interfaces.md#interface-keyedtraversable)
    - [Interface  `Serializable`](17-interfaces.md#interface--serializable)
    - [Interface `Stringish`](17-interfaces.md#interface-stringish)
    - [Interface `Traversable`](17-interfaces.md#interface-traversable)
- [Traits](18-traits.md#traits)
  - [General](18-traits.md#general)
  - [Trait Declarations](18-traits.md#trait-declarations)
  - [Trait Members](18-traits.md#trait-members)
- [Exception Handling](19-exception-handling.md#exception-handling)
  - [General](19-exception-handling.md#general)
  - [Class `Exception`](19-exception-handling.md#class-exception)
  - [Tracing Exceptions](19-exception-handling.md#tracing-exceptions)
  - [User-Defined Exception Classes](19-exception-handling.md#user-defined-exception-classes)
- [Namespaces](20-namespaces.md#namespaces)
  - [General](20-namespaces.md#general)
  - [Name Lookup](20-namespaces.md#name-lookup)
  - [Defining Namespaces](20-namespaces.md#defining-namespaces)
  - [Namespace Use Declarations**](20-namespaces.md#namespace-use-declarations)
- [Attributes](21-attributes.md#attributes)
  - [General](21-attributes.md#general)
  - [Attribute Specification](21-attributes.md#attribute-specification)
  - [Predefined Attributes](21-attributes.md#predefined-attributes)
    - [General](21-attributes.md#general-1)
    - [Attribute `__ConsistentConstruct`](21-attributes.md#attribute-__consistentconstruct)
    - [Attribute `__Memoize`](21-attributes.md#attribute-__memoize)
    - [Attribute `__Override`](21-attributes.md#attribute-__override)
- [Grammar](22-grammar.md#grammar)
  - [General](22-grammar.md#general)
  - [Lexical Grammar](22-grammar.md#lexical-grammar)
    - [General](22-grammar.md#general-1)
    - [Comments](22-grammar.md#comments)
    - [White Space](22-grammar.md#white-space)
    - [Tokens](22-grammar.md#tokens)
      - [General](22-grammar.md#general-2)
      - [Names](22-grammar.md#names)
    - [Keywords](22-grammar.md#keywords)
    - [Literals](22-grammar.md#literals)
      - [General](22-grammar.md#general-3)
      - [Boolean Literals](22-grammar.md#boolean-literals)
      - [Integer Literals](22-grammar.md#integer-literals)
      - [Floating-Point Literals](22-grammar.md#floating-point-literals)
      - [String Literals](22-grammar.md#string-literals)
      - [The Null Literal](22-grammar.md#the-null-literal)
    - [Operators and Punctuators](22-grammar.md#operators-and-punctuators)
  - [Syntactic Grammar](22-grammar.md#syntactic-grammar)
    - [Program Structure](22-grammar.md#program-structure)
    - [Types](22-grammar.md#types)
      - [General](22-grammar.md#general-4)
      - [Array Types](22-grammar.md#array-types)
      - [Tuple Types](22-grammar.md#tuple-types)
      - [Shape Types](22-grammar.md#shape-types)
      - [Closure Types](22-grammar.md#closure-types)
      - [Nullable Types](22-grammar.md#nullable-types)
      - [The Classname Type](22-grammar.md#the-classname-type)
      - [Type Aliases](22-grammar.md#type-aliases)
    - [Variables](22-grammar.md#variables)
    - [Expressions](22-grammar.md#expressions)
      - [Primary Expressions](22-grammar.md#primary-expressions)
      - [Postfix Operators](22-grammar.md#postfix-operators)
      - [Unary Operators](22-grammar.md#unary-operators)
      - [instanceof Operator](22-grammar.md#instanceof-operator)
      - [Multiplicative Operators](22-grammar.md#multiplicative-operators)
      - [Additive Operators](22-grammar.md#additive-operators)
      - [Bitwise Shift Operators](22-grammar.md#bitwise-shift-operators)
      - [Relational Operators](22-grammar.md#relational-operators)
      - [Equality Operators](22-grammar.md#equality-operators)
      - [Bitwise Logical Operators](22-grammar.md#bitwise-logical-operators)
      - [Logical Operators](22-grammar.md#logical-operators)
      - [Conditional Operator](22-grammar.md#conditional-operator)
      - [Pipe Operator](22-grammar.md#pipe-operator)
      - [Lambda Expressions](22-grammar.md#lambda-expressions)
      - [Assignment Operators](22-grammar.md#assignment-operators)
      - [yield Operator](22-grammar.md#yield-operator)
      - [Constant Expressions](22-grammar.md#constant-expressions)
    - [Statements](22-grammar.md#statements)
      - [General](22-grammar.md#general-5)
      - [Compound Statements](22-grammar.md#compound-statements)
      - [Labeled Statements](22-grammar.md#labeled-statements)
      - [Expression Statements](22-grammar.md#expression-statements)
      - [Iteration Statements](22-grammar.md#iteration-statements)
      - [Jump Statements](22-grammar.md#jump-statements)
      - [The try Statement](22-grammar.md#the-try-statement)
    - [Script Inclusion](22-grammar.md#script-inclusion)
    - [Enums](22-grammar.md#enums)
    - [Generic Types, Methods and Functions](22-grammar.md#generic-types-methods-and-functions)
    - [Functions](22-grammar.md#functions)
    - [Classes](22-grammar.md#classes)
    - [Interfaces](22-grammar.md#interfaces)
    - [Traits](22-grammar.md#traits)
    - [Namespaces](22-grammar.md#namespaces)
    - [Attributes](22-grammar.md#attributes)
- [Differences from PHP](23-differences-from-php.md#differences-from-php)
  - [General](23-differences-from-php.md#general)
  - [Program Start-Up](23-differences-from-php.md#program-start-up)
  - [Constants](23-differences-from-php.md#constants)
  - [Variables](23-differences-from-php.md#variables)
  - [Conversions](23-differences-from-php.md#conversions)
  - [Lexical Structure](23-differences-from-php.md#lexical-structure)
    - [Comments](23-differences-from-php.md#comments)
    - [Names](23-differences-from-php.md#names)
    - [Keywords](23-differences-from-php.md#keywords)
  - [Expressions](23-differences-from-php.md#expressions)
    - [Primary Expressions](23-differences-from-php.md#primary-expressions)
      - [General](23-differences-from-php.md#general-1)
      - [Intrinsics](23-differences-from-php.md#intrinsics)
      - [Anonymous Function-Creation](23-differences-from-php.md#anonymous-function-creation)
    - [Postfix Operators](23-differences-from-php.md#postfix-operators)
      - [The `new` Operator](23-differences-from-php.md#the-new-operator)
      - [Array Creation Operator](23-differences-from-php.md#array-creation-operator)
      - [Function call operator](23-differences-from-php.md#function-call-operator)
      - [Member-Selection Operator](23-differences-from-php.md#member-selection-operator)
      - [Postfix Increment and Decrement Operators](23-differences-from-php.md#postfix-increment-and-decrement-operators)
      - [Exponentiation Operator](23-differences-from-php.md#exponentiation-operator)
    - [Unary Operators](23-differences-from-php.md#unary-operators)
      - [Prefix Increment and Decrement Operators](23-differences-from-php.md#prefix-increment-and-decrement-operators)
      - [Unary Arithmetic Operators](23-differences-from-php.md#unary-arithmetic-operators)
      - [Shell Command Operator](23-differences-from-php.md#shell-command-operator)
      - [Cast Operator](23-differences-from-php.md#cast-operator)
      - [Variable-Name Creation Operator](23-differences-from-php.md#variable-name-creation-operator)
    - [`instanceof` Operator](23-differences-from-php.md#instanceof-operator)
    - [Multiplicative Operators](23-differences-from-php.md#multiplicative-operators)
    - [Bitwise Shift Operators](23-differences-from-php.md#bitwise-shift-operators)
    - [Bitwise `AND` Operator](23-differences-from-php.md#bitwise-and-operator)
    - [Bitwise Exclusive `OR` Operator](23-differences-from-php.md#bitwise-exclusive-or-operator)
    - [Bitwise Inclusive `OR` Operator](23-differences-from-php.md#bitwise-inclusive-or-operator)
    - [Assignment Operators](23-differences-from-php.md#assignment-operators)
      - [byRef Assignment](23-differences-from-php.md#byref-assignment)
    - [Logical `AND`, `OR`, `XOR` Operators (Alternate Forms)](23-differences-from-php.md#logical-and-or-xor-operators-alternate-forms)
    - [String Literals](23-differences-from-php.md#string-literals)
  - [Statements](23-differences-from-php.md#statements)
    - [General](23-differences-from-php.md#general-2)
    - [Labeled Statements](23-differences-from-php.md#labeled-statements)
    - [The `if` Statement](23-differences-from-php.md#the-if-statement)
    - [The `switch` Statement](23-differences-from-php.md#the-switch-statement)
    - [The `while` Statement](23-differences-from-php.md#the-while-statement)
    - [The `for` Statement](23-differences-from-php.md#the-for-statement)
    - [The `foreach` Statement](23-differences-from-php.md#the-foreach-statement)
    - [The `goto` Statement](23-differences-from-php.md#the-goto-statement)
    - [The `continue` Statement](23-differences-from-php.md#the-continue-statement)
    - [The `break` Statement](23-differences-from-php.md#the-break-statement)
    - [The `return` Statement](23-differences-from-php.md#the-return-statement)
    - [The declare Statement](23-differences-from-php.md#the-declare-statement)
  - [Script Inclusion](23-differences-from-php.md#script-inclusion)
  - [Functions](23-differences-from-php.md#functions)
  - [Classes](23-differences-from-php.md#classes)
    - [Class Members](23-differences-from-php.md#class-members)
    - [Dynamic Members](23-differences-from-php.md#dynamic-members)
    - [Properties](23-differences-from-php.md#properties)
    - [Methods](23-differences-from-php.md#methods)
    - [Constructors](23-differences-from-php.md#constructors)
    - [Methods with Special Semantics](23-differences-from-php.md#methods-with-special-semantics)
      - [General](23-differences-from-php.md#general-3)
      - [Method `__call`](23-differences-from-php.md#method-__call)
      - [Method `__get`](23-differences-from-php.md#method-__get)
      - [Method `__invoke`](23-differences-from-php.md#method-__invoke)
      - [Method __isset](23-differences-from-php.md#method-__isset)
      - [Method __set](23-differences-from-php.md#method-__set)
      - [Method __set_state](23-differences-from-php.md#method-__set_state)
      - [Method __unset](23-differences-from-php.md#method-__unset)
    - [Predefined Classes](23-differences-from-php.md#predefined-classes)
      - [Class Closure](23-differences-from-php.md#class-closure)
  - [Interfaces](23-differences-from-php.md#interfaces)
    - [Interface Members](23-differences-from-php.md#interface-members)
    - [Methods](23-differences-from-php.md#methods-1)
    - [Predefined Interfaces](23-differences-from-php.md#predefined-interfaces)
  - [Traits](23-differences-from-php.md#traits)
    - [Trait Declarations](23-differences-from-php.md#trait-declarations)
  - [Namespaces](23-differences-from-php.md#namespaces)
    - [Namespace Use Declarations](23-differences-from-php.md#namespace-use-declarations)
- [Bibliography](24-bibliography.md#bibliography)


================================================
FILE: spec/01-introduction.md
================================================
# Introduction
This specification is intended to provide a complete and concise
definition of the syntax and semantics of the Hack language, suitable for
use by the following:

-   Developers of a Hack implementation
-   Implementers of a test suite for the Hack language
-   Programmers writing Hack code

For now, the runtime library has been excluded, as that is documented at [www.php.net](http://www.php.net) and [docs.hhvm.com](http://docs.hhvm.com). As such, all forward references to library facilities have placeholders of the form (§xx).


================================================
FILE: spec/02-conformance.md
================================================
# Conformance
In this specification, "must" is to be interpreted as a requirement on
an implementation or on a program; conversely, "must not" is to be
interpreted as a prohibition.

If a "must" or "must not" requirement that appears outside of a
constraint is violated, the behavior is undefined. Undefined behavior is
otherwise indicated in this specification by the words "undefined
behavior" or by the omission of any explicit definition of behavior.
There is no difference in emphasis among these three; they all describe
"behavior that is undefined".

The word "may" indicates "permission", and is never used to mean
"might".

A *strictly conforming program* must use only those features of the
language described in this specification. In particular, it must not
produce output dependent on any unspecified, undefined, or
implementation-defined behavior.

A *conforming implementation* must accept any strictly conforming
program. A conforming implementation may have extensions, provided they
do not alter the behavior of any strictly conforming program.

A *conforming program* is one that is acceptable to a conforming
implementation.

A conforming implementation must be accompanied by a document that
defines all implementation-defined characteristics and all extensions.

Some Syntax sections are followed by a Constraints section, which
further restricts the grammar. After issuing a diagnostic for a
constraint violation, a conforming implementation may continue program
execution. In some cases, such continuation behavior is documented.
Making such things constraint violations simply forces the issuance of a
diagnostic; it does not require that program execution terminate.

This specification contains explanatory material—called *informative* or
*non-normative* text—that, strictly speaking, is not necessary in a
formal language specification. Examples are provided to illustrate
possible forms of the constructions described. References are used to
refer to related clauses. Notes and Implementer Notes are provided to
give advice or guidance to implementers or programmers. Informative
annexes provide additional information and summarize the information
contained in this specification. All text not marked as informative is
*normative*.

Certain features are marked as *deprecated*. While these are normative
for the current edition of this specification, they are not guaranteed
to exist in future revisions. Usually, they are old approaches that have
been superseded by new ones, and use of the old approach is discouraged.
(Examples of this include the use of braces ({ }) for subscripting.)



================================================
FILE: spec/03-terms-and-definitions.md
================================================
# Terms and Definitions
For the purposes of this document, the following terms and definitions
apply:

<pre>

  <b>argument:</b>
    a value passed to a function, that is intended to map to a
    corresponding parameter.
      
  <b>behavior:</b>
    external appearance or action.

  <b>behavior, implementation-defined:</b>
    behavior specific to an implementation, where that implementation
    must document that behavior.

  <b>behavior, undefined:</b>
    behavior which is not guaranteed to
    produce any specific result. Usually follows an erroneous program
    construct or data.

  <b>behavior, unspecified:</b>
    behavior for which this specification provides no requirements.

  <b>case-preserved:</b>
    a construct which is case-insensitive upon declaration, but
    case-sensitive upon subsequent usage.

  <b>constraint:</b>
    restriction, either syntactic or semantic, on how language elements
    can be used.

  <b>error, fatal:</b>
    a translation or runtime condition from which the translator or
    engine cannot recover.

  <b>error, fatal, catchable:</b>
    a fatal error that can be caught by a user-defined handler.

  <b>error, non-fatal:</b>
    an error that is not fatal.

  <b>lvalue:</b>
    an expression that designates a memory location having a type.

  <b>lvalue, modifiable:</b>
    an lvalue whose value can be changed.

  <b>lvalue, non-modifiable:</b>
    an lvalue whose value cannot be changed.

  <b>parameter:</b>
    a variable declared in the parameter list of a function that is
    intended to map to a corresponding argument in a call to that
    function.

  <b>Hack Run-Time Engine:</b>
    the machinery that executes a Hack program. Referred to as *the
    Engine* throughout this specification.

  <b>value:</b>
    precise meaning of the contents of a memory location when
    interpreted as having a specific type.
</pre>

Other terms are defined throughout this specification, as needed, with
the first usage being typeset *like this*.


================================================
FILE: spec/04-basic-concepts.md
================================================
# Basic Concepts
## Program Structure
A Hack *program* consists of one or more source files, known formally as
*scripts*.

<pre>
<i>script:
  </i>&lt;?hh // strict
  <i>declaration-list<sub>opt</sub></i>

<i>declaration-list:</i>
  <i>declaration</i>
  <i>declaration-list</i> <i>declaration</i>

<i>declaration:</i>
  <i>inclusion-directive</i>
  <i>enum-declaration</i>
  <i>function-definition</i>
  <i>class-declaration</i>
  <i>interface-declaration</i>
  <i>trait-declaration</i>
  <i>namespace-definition</i>
  <i>namespace-use-declaration</i>
  <i>alias-declaration</i>
</pre>

**Defined elsewhere**

* [*alias-declaration*](05-types.md#type-aliases)
* [*class-declaration*](16-classes.md#class-declarations)
* [*enum-declaration*](13-enums.md#enum-declarations)
* [*function-definition*](15-functions.md#function-definitions)
* [*inclusion-directive*](12-script-inclusion.md#general)
* [*interface-declaration*](17-interfaces.md#interface-declarations)
* [*namespace-definition*](20-namespaces.md#defining-namespaces)
* [*namespace-use-declaration*](20-namespaces.md#namespace-use-declarations)
* [*trait-declaration*](18-traits.md#trait-declarations)

A Hack script can be processed in any one of a number of *modes*, of which
`strict` is one. This mode is specified in a [*special single-line-comment*](09-lexical-structure.md#comments), on the first source line, as shown. This comment may be separated
from the preceding &lt;?hh by an arbitrary amount of [horizontal white space](09-lexical-structure.md#white-space), which must not include any [*delimited-comments*](09-lexical-structure.md#comments). This
specification is written from the perspective of strict mode only. A
conforming implementation may provide modes other than `strict`, but they are
outside the scope of this specification.

A script can import another script via [script inclusion](12-script-inclusion.md#script-inclusion-operators).

The top level of a script is simply referred to as the *top level*.

## Program Start-Up
Once the start-up function begins execution, it is implementation-defined as
to whether it has access to things like command-line arguments and environment
variables. [PHP's global variables `$argc` and `$argv` are not available in
`strict` mode.]

## Program Termination
A program may terminate normally in the following ways:

-   A [`return` statement](11-statements.md#the-return-statement) in the start-up function is executed.
-   The intrinsic [`exit`](10-expressions.md#exit) is called explicitly.

The behavior of the first case is equivalent to corresponding calls
to `exit`.

A program may terminate abnormally under various circumstances, such as
the detection of an uncaught exception, or the lack of memory or other
critical resource. If execution reaches the end of the start-up script
via a fatal error, or via an uncaught exception and there is no uncaught
exception handler registered by `set_exception_handler`, that is
equivalent to `exit(255)`. If execution reaches the end of the start-up
script via an uncaught exception and an uncaught exception handler was
registered by `set_exception_handler`, that is equivalent to exit(0). It
is unspecified whether [object destructors](16-classes.md#destructors) are run. In all other cases,
the behavior is unspecified.

## The Memory Model
### General
This section and those immediately following it describe the abstract
memory model used by Hack for storing variables. A conforming
implementation may use whatever approach is desired as long as from any
testable viewpoint it appears to behave as if it follows this abstract
model. The abstract model makes no explicit or implied restrictions or
claims about performance, memory consumption, and machine resource
usage.

The abstract model presented here defines three kinds of abstract memory
locations:

-   A *value storage location* (VStore) is used to represent a program
    value, and is created by the Engine as needed. A VStore can contain
    a scalar value such as an integer or a Boolean, or it can contain a
    handle pointing to an HStore (see below).
-   A *variable slot* (VSlot) is used to represent a variable named by
    the programmer in the source code, such as a local variable, an
    array element, an instance property of an object, or a static
    property of a class. A VSlot comes into being based on explicit
    usage of a variable in the source code. A VSlot contains a pointer
    to a VStore.
-   A *heap storage location* (HStore) is used to represent the contents
    of any non-scalar value, and is created by the Engine as needed.

Each existing variable has its own VSlot, which at any time contains a
pointer to a VStore. A VSlot cannot contain a null pointer. A VSlot can
be changed to point to different VStores over time. Multiple VSlots may
simultaneously point to the same VStore. When a new VSlot is created, a
new VStore is also created and the VSlot is initially set to point to
the new VStore.

A VStore can be changed to contain different scalar values and handles
over time. Multiple VStores may simultaneously contain handles that
point to the same HStore. When a VStore is created it initially contains
the scalar value `null` unless specified otherwise. In addition to
containing a value, VStores also carry a *type tag* that indicates the [type](05-types.md#types) of the VStore’s value. A VStore’s type tag can be changed over
time. At any given time a VStore’s type tag may be one of the following:
`Null`, `Bool`, `Int`, `Float`, `Str`, `Arr`, `Arr-D` (see [§§](#deferred-array-copying)), `Obj`, or `Res`.

An HStore represents the contents of a non-scalar value, and it may
contain zero or more VSlots. At run time, the Engine may add new VSlots
and it may remove and destroy existing VSlots as needed to support
adding/removing array elements (for arrays) and to support
adding/removing instance properties (for objects). HStores that
represent the contents of arrays and objects have some unspecified way
to identify and retrieve a contained VSlot using a dictionary scheme
(such as having values with integer keys or case-sensitive string keys).
Whether an HStore is a fixed-size during its whole lifetime or whether
it can change size, is unspecified. Whether it allocates auxiliary
chunks of memory or not, is unspecified. Whether it organizes it's
contained VSlots in a linked list or some other manner is unspecified.

An HStore’s VSlots (i.e., the VSlots contained within the HStore) point
to VStores, and each VStore contains a scalar value or a handle to an
HStore, and so on through arbitrary levels, allowing arbitrarily complex
data structures to be represented. For example, a singly linked list
might consist of a variable called `$root`, which is represented by a
VSlot pointing to a VStore containing a handle to the first node. Each
node is represented by an HStore that contains the data for that node in
one or more VSlots, as well as a VSlot pointing to VStore containing a
handle to the next node. Similarly, a binary tree might consist of a
variable called `$root`, which is represented by a VSlot pointing to a
VStore containing a handle to the root node. Each node is represented by
an HStore that contains the data for that node in one or more VSlots, as
well as a pair of VSlots pointing to VStores containing the handles to
the left and right branch nodes. The leaves of the tree would be VStores
or HStores, as needed.

VSlots cannot contain pointers to VSlots or handles to HStores. VStores
cannot contain pointers to VSlots or VStores. HStores cannot directly
contain any pointers or handles to any abstract memory location; HStores
can only directly contain VSlots.

Here is an example demonstrating one possible arrangement of VSlots,
VStores, and HStores:

<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                        |            |
                                                        V            V
                                                [VStore Int 1]  [VStore Int 3]
</pre>

In this picture the VSlot in the upper left corner represents the
variable `$a`, and it points to a VStore that represents `$a`’s current
value. This VStore contains a handle to an HStore which represents the
contents of an object of type Point with two instance properties `$x`
and `$y`. This HStore contains two VSlots representing instance
properties `$x` and `$y`, and each of these VSlots points to a distinct
VStore which contains an integer value. 

***Implementation Notes*** A concrete implementation of Hack may be mapped roughly
onto the abstract memory model as follows: `zval pointer => VSlot, zval
=> VStore, HashTable => HStore`, and
`zend_object/zend_object_handlers => HStore`. Note, however, that the
abstract memory model is not intended to exactly match any specific
implementation’s model, and for generality and simplicity there may be some
superficial differences between the described model and an implementation's model.

For most operations, the mapping between VSlots and VStores remains the
same. Only the following program constructs can change a VSlot to point
to different VStore: the use of `&` in a [`foreach` statement](11-statements.md#the-foreach-statement).

### Reclamation and Automatic Memory Management
The Engine is required to manage the lifetimes of VStores and HStores
using some form of automatic memory management.

When dealing with VStores and HStores, the Engine is required to implement
some form of automatic memory management. When a VStore or HStore
is created, memory is allocated for it, and for an HStore that represents
an [object](05-types.md#class-types), its [constructor](16-classes.md#constructors) is invoked.

Later, if a VStore or HStore becomes unreachable through any existing
variable, they become eligible for reclamation to release the memory
they occupy. The engine may reclaim a VStore or HStore at any time
between when it becomes eligible for reclamation and when the script
exits. Before reclaiming an HStore that represents an [object](05-types.md#class-types),
the Engine will invoke the object’s [destructor](16-classes.md#destructors) if one is defined.

The Engine must reclaim each VSlot when the [storage duration](#storage-duration) of its
corresponding variable ends, when the variable is explicitly unset by the
programmer, or when the script exits, whichever comes first. In the case where
a VSlot is contained within an HStore (i.e. an array element or an object
instance property), the engine must immediate reclaim the VSlot when it is
explicitly unset by the programmer, when the containing HStore is reclaimed,
or when the script exits, whichever comes first.

The precise form of automatic memory management used by the Engine is
unspecified, which means that the time and order of the reclamation of
VStores and HStores is unspecified.

A VStore’s refcount is defined as the number of unreclaimed VSlots that point
to the VStore. Because the precise form of automatic memory management is not
specified, a VStore’s refcount at a given time may differ between
conforming implementations due to VSlots, VStores, and HStores being
reclaimed at different times. Despite the use of the term refcount,
conforming implementations are not required to use a reference
counting-based implementation for automatic memory management.

### Assignment
#### General
This section and those immediately following it describe the abstract
model’s implementation of *value assignment* and *byRef assignment*.
Value assignment of non-array types to local variables is described
first, followed by byRef assignment with local variables, followed by
value assignment of array types to local variables, and ending with
value assignment with complex left-hand side expressions, and byRef
assignment with complex expressions on the left- or right-hand side.

Value assignment and byRef assignment are core to HHVM, the Engine which
supports the  PHP and Hack languages. Many other operations in the PHP and
Hack specification are described in terms of value assignment. On the other
hand, byRef assignment is used only by PHP, not by Hack. However, a discussion
of such assignment has been retained here for historical reference.

#### Value Assignment of Scalar Types to a Local Variable
Value assignment is the primary means by which the programmer can create
local variables. If a local variable appears on the left-hand side of
value assignment does not exist, the engine will bring a new local
variable into existence and create a VSlot and initial VStore for
storing the local variable’s value.

Consider the following example of [value assignment](10-expressions.md#simple-assignment) of scalar
values to local variables:

```Hack
$a = 123;

$b = false;
```
<pre>
[VSlot $a *]-->[VStore Int 123]

[VSlot $b *]-->[VStore Bool false]
</pre>

Variable `$a` comes into existence and is represented by a newly created
VSlot pointing to a newly created VStore. Then the integer value 123 is
written to the VStore. Next, `$b` comes into existence represented by a
VSlot and corresponding VStore, and the Boolean value false is written
to the VStore.

Next consider the value assignment `$b = $a`:

<pre>
[VSlot $a *]-->[VStore Int 123]

[VSlot $b *]-->[VStore Int 123 (Bool false was overwritten)]
</pre>

The integer value 123 is read from `$a`’s VStore and is written into
`$b`’s VStore, overwriting its previous contents. As we can see, the two
variables are completely self-contained; each has its own VStore
containing a separate copy of the integer value 123. Value assignment
reads the contents of one VStore and overwrites the contents of the
other VStore, but the relationship of VSlots to VStores remains
unchanged. Changing the value of `$b` has no effect on `$a`, and vice
versa.

Using literals or arbitrarily complex expressions on the right hand side
of value assignment value works the same as it does for variables,
except that the literals or expressions don’t have their own VSlots or
VStores. The scalar value or handle produced by the literal or
expression is written into the VStore of the left hand side, overwriting
its previous contents.

***Implementation Notes*** For simplicity, the abstract model’s
definition of value assignment never changes the mapping from VSlots to
VStores. This aspect of the abstract model is superficially different
from the php.net implementation’s model, which in some cases will set
two variable slots to point to the same zval when performing value
assignment. Despite this superficial difference, php.net’s
implementation produces the same observable behavior as the abstract
model presented here.

To illustrate the semantics of value assignment further, consider `++$b`:

<pre>
[VSlot $a *]-->[VStore Int 123]

[VSlot $b *]-->[VStore Int 124 (123 was overwritten)]
</pre>

Now consider `$a = 99`:

<pre>
[VSlot $a *]-->[VStore Int 99 (123 was overwritten)]

[VSlot $b *]-->[VStore Int 124]
</pre>

In both of these examples, one variable’s value is changed without
affecting the other variable’s value. While the above examples only
demonstrate value assignment for integer and Boolean values, the same
mechanics apply for all scalar types.

Note that strings are also considered scalar values for the purposes of
the abstract memory model. Unlike non-scalar types which are represented
using a VStore pointing to an HStore containing the non-scalar value’s
contents, the abstract model assumes that a string’s entire contents
(i.e., the string’s characters and its length) can be stored in a VStore
and that value assignment for a string eagerly copies a string’s entire
contents to the VStore being written to. Consider the following example:

```Hack
$a = 'gg';

$b = $a;
```

<pre>
[VSlot $a *]-->[VStore Str 'gg']

[VSlot $b *]-->[VStore Str 'gg']
</pre>

`$a`’s string value and `$b`’s string values are distinct from each other,
and mutating `$a`’s string will not affect `$b`. Consider `++$b`, for
example:

<pre>
[VSlot $a *]-->[VStore Str 'gg']

[VSlot $b *]-->[VStore Str 'gh']
</pre>

***Implementation Notes*** For simplicity, the abstract model represents
a string as a scalar value that can be entirely contained within VStore.
This aspect of the abstract model is superficially different from the
php.net implementation’s model, where a zval points to a separate buffer
in memory containing a string’s characters and in the common case
multiple slots point to the same zval that holds the string. Despite
this superficial difference, php.net’s implementation produces the same
observable behavior (excluding performance and resource consumption) as
the abstract model presented here.

Because a string’s content can be arbitrarily large, copying a string’s
entire contents for value assignment can be expensive. In practice an
application written in Hack may rely on value assignment of strings being
relatively inexpensive (in order to deliver acceptable performance), and
as such it is common for an implementation to use a deferred copy
mechanism to reduce the cost of value assignment for strings. Deferred
copy mechanisms work by not copying a string during value assignment and
instead allowing multiple variables to share the string’s contents
indefinitely until a mutating operation (such as the increment operator)
is about to be executed on the string, at which time some or all of the
string’s contents are copied. A conforming implementation may choose to
defer copying a string’s contents for value assignment so long as it has
no observable effect on behavior from any testable viewpoint (excluding
performance and resource consumption).

#### Value Assignment of Object and Resource Types to a Local Variable

To demonstrate value assignment of objects to local variables, consider
the case in which we have a Point class that supports a two-dimensional
Cartesian system. An instance of Point contains two instance properties,
`$x` and `$y`, that store the x- and y-coordinates, respectively. A
[constructor call](14-classes.md#constructors) of the form `Point(x, y)` used with [operator `new`](10-expressions.md#the-new-operator)
creates a new point at the given location, and a method call
of the form `move(newX, newY)` moves a `Point` to the new location.

With the `Point` class, let us consider the value assignment `$a = new
Point(1, 3)`:

<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                        |            |
                                                        V            V
                                                 [VStore Int 1]  [VStore Int 3]
</pre>

Variable `$a` is given its own VSlot, which points to a VStore that
contains a handle pointing to an HStore allocated by [`new`](10-expressions.md#the-new-operator) and
that is initialized by `Point`'s constructor.

Now consider the value assignment `$b = $a`:

<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                  ^                     |            |
                                  |                     V            V
[VSlot $b *]-->[VStore Obj *]-----+             [VStore Int 1] [VStore Int 3]
</pre>

`$b`‘s VStore contains a handle that points to the same object as does
`$a`‘s VStore’s handle. Note that the Point object itself was not copied,
and note that `$a`’s and `$b`’s VSlots point to distinct VStores.

Let's modify the value of the Point whose handle is stored in `$b` using
`$b->move(4, 6)`:

<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                  ^                     |            |
                                  |                     V            V
[VSlot $b *]-->[VStore Obj *]-----+         [VStore Int 4] [VStore Int 6]
                                       (1 was overwritten) (3 was overwritten)
</pre>

As we can see, changing `$b`'s Point changes `$a`'s as well.

Now, let's make `$a` point to a different object using `$a = new Point(2,
1)`:

<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                        |            |
[VSlot $b *]-->[VStore Obj *]-----+                     V            V
                                  |             [VStore Int 2] [VStore Int 1]
                                  V
                                [HStore Point [VSlot $x *] [VSlot $y *]]
                                                        |            |
                                                        V            V
                                                [VStore Int 4] [VStore Int 6]
</pre>

Before `$a` can take on the handle of the new `Point`, its handle to the
old `Point` must be removed, which leaves the handles of `$a` and `$b`
pointing to different Points.

We can remove all these handles using `$a = null` and `$b = null`:
<pre>
[VSlot $a *]-->[VStore Null]    [HStore Point [VSlot $x *] [VSlot $y *] (dead)]
                                                        |            |
[VSlot $b *]-->[VStore Null]    [VStore Int 2 (dead)]&lt;--+            V
                                                          [VStore Int 1 (dead)]
                                                          
                                [HStore Point [VSlot $x *] [VSlot $y *] (dead)]
                                                        |            |
                                [VStore Int 4 (dead)]&lt;--+            V
                                                        [VStore Int 6 (dead)]
</pre>

By assigning null to `$a`, we remove the only handle to `Point(2,1)`, which
allows that object's [destructor](14-classes.md#destructors) to run. A similar thing happens
with `$b`, as it too is the only handle to its Point.

Although the examples above only show with only two instance properties,
the same mechanics apply for value assignment of all object types, even
though they can have an arbitrarily large number of instance properties
of arbitrary type. Likewise, the same mechanics apply to value
assignment of all resource types.

#### ByRef Assignment for Scalar Types with Local Variables
Let's begin with the same [value assignment](10-expressions.md#simple-assignment) as in the previous
section, `$a = 123` and `$b = false`:

<pre>
[VSlot $a *]-->[VStore Int 123]

[VSlot $b *]-->[VStore Bool false]
</pre>

Now consider the [byRef assignment](10-expressions.md#byref-assignment) `$b =& $a`, which has byRef
semantics:
<pre>
[VSlot $a *]-->[VStore Int 123]
                 ^
                 |
[VSlot $b *]-----+     [VStore Bool false (dead)]
</pre>

In this example, byRef assignment changes `$b`’s VSlot point to the same
VStore that `$a`’s VSlot points to. The old VStore that `$b`’s VSlot used
to point to is now unreachable. As stated in [§§](#general), it is not possible for a VSlot to point to another VSlot, so `$b`‘s VSlot cannot point to `$a`‘s VSlot. When multiple variables’ VSlots point to the same VStore,
the variables are said to be *aliases* of each other or they are said to
have an *alias relationship*. In the example above, after the byRef
assignment executes the variables `$a` and `$b` will be aliases of each
other.

Now, let's observe what happens when we change the value of `$b` using
`++$b`:
<pre>
[VSlot $a *]-->[VStore Int 124 (123 was overwritten)]
                 ^
                 |
[VSlot $b *]-----+
</pre>

`$b`‘s value, which is stored in the VStore that `$b`’s VSlot points, is
changed to 124. And as that VStore is also aliased by `$a`’s VSlot, the
value of `$a` is also 124. Indeed, any variable’s VSlot that is aliased
to that VStore will have the value 124.

Now consider the value assignment `$a = 99`:
<pre>
[VSlot $a *]-->[VStore Int 99 (124 was overwritten)]
                 ^
                 |
[VSlot $b *]-----+
</pre>

The alias relationship between `$a` and `$b` can be broken explicitly by
using `unset` on variable `$a` or variable `$b`. For example, consider
`unset($a)`:
<pre>
[VSlot $a (dead)]      [VStore Int 99]
                         ^
                         |
[VSlot $b *]-------------+
</pre>

Unsetting `$a` causes variable `$a` to be destroyed and its corresponding
alias to the VStore to be removed, leaving `$b`’s VSlot as the only
pointer remaining to the VStore.

Other operations can also break an alias relationship between two or
more variables. For example, `$a = 123` and `$b =& $a`, and `$c = 'hi'`:
<pre>
[VSlot $a *]-->[VStore Int 123]
                 ^
                 |
[VSlot $b *]-----+

[VSlot $c *]-->[VStore Str 'hi']
</pre>

After the byRef assignment, `$a` and `$b` now have an alias relationship.
Next, let's observe what happens for `$b =& $c`:
<pre>
[VSlot $a *]-->[VStore Int 123]

[VSlot $b *]-----+
                 |
                 V
[VSlot $c *]-->[VStore Str 'hi']
</pre>

As we can see, the byRef assignment above breaks the alias relationship
between `$a` and `$b`, and now `$b` and `$c` are aliases of each other. When
byRef assignment changes a VSlot to point to a different VStore, it
breaks any existing alias relationship the left hand side variable had
before the assignment operation.

It is also possible to use byRef assignment to make three or more VSlots
point to the same VStore. Consider the following example:

```Hack
$b =& $a;
$c =& $b;
$a = 123;
```
<pre>
[VSlot $a *]-->[VStore Int 123]
                 ^   ^
                 |   |
[VSlot $b *]-----+   |
                     |
[VSlot $c *]---------+
</pre>

Like value assignment, byRef assignment provides a means for the
programmer to created variables. If the local variables that appear on
the left- or right-hand side of byRef assignment do not exist, the
engine will bring new local variables into existence and create a VSlot
and initial VStore for storing the local variable’s value.

Note that literals, constants, and other expressions that don’t
designate a modifiable lvalue cannot be used on the left- or right-hand
side of byRef assignment.

#### Byref Assignment of Non-Scalar Types with Local Variables
byRef assignment of non-scalar types works using the same mechanism as
byRef assignment for scalar types. Nevertheless, it is worthwhile to
describe a few examples to clarify the semantics of byRef assignment.
Recall the example from [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable)) using the `Point` class:

`$a = new Point(1, 3);`
<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                        |            |
                                                        V            V
                                               [VStore Int 1]  [VStore Int 3]
</pre>

Now consider the [byRef assignment](10-expressions.md#byref-assignment) `$b =& $a`, which has byRef
semantics:
<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *][VSlot $y *]]
                 ^                                      |           |
                 |                                      V           V
[VSlot $b *]-----+                               [VStore Int 1] [VStore Int 3]
</pre>
`$a` and `$b` now aliases of each other. Note that byRef assignment
produces a different result than `$b = $a` where `$a` and `$b` would point
to distinct VStores pointing to the same HStore.

Let's modify the value of the `Point` aliased by `$a` using `$a->move(4,
6)`:
<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] VSlot $y *]]
                 ^                                      |           |
                 |                                      V           V
[VSlot $b *]-----+                           [VStore Int 4] [VStore Int 6]
                                        (1 was overwritten) (3 was overwritten)
</pre>

Now, let's change `$a` itself using the value assignment `$a = new
Point(2, 1)`:
<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *][VSlot $y *]]
                 ^                                      |           |
                 |                                      V           V
[VSlot $b *]-----+                             [VStore Int 2] [VStore Int 1]

                               [HStore Point [VSlot $x *]   [VSlot $y *] (dead)]
                                                       |              |
                                                       V              V
                                     [VStore Int 4 (dead)] [VStore Int 6 (dead)]
</pre>

As we can see, `$b` continues to have an alias relationship with `$a`.
Here's what's involved in that assignment: `$a` and `$b`'s VStore’s handle
pointing to `Point(4,6)` is removed, `Point(2,1)` is created, and `$a` and
`$b`’s VStore is overwritten to contain a handle pointing to that new
`Point`. As there are now no VStores pointing to `Point(4,6)`, its
[destructor](14-classes.md#destructors) can run.

We can remove these aliases using `unset($a, $b)`:
<pre>
[VSlot $a (dead)]       [HStore Point [VSlot $x *] [VSlot $y *] (dead)]
                                                |            |
                                                V            V
[VSlot $b (dead)]             [VStore Int 2 (dead)]  [VStore Int 1 (dead)]
</pre>

Once all the aliases to the VStores are gone, the VStores can be
destroyed, in which case, there are no more pointers to the HStore, and
its [destructor](16-classes.md#destructors) can be run.

#### Value Assignment of Array Types to Local Variables
The semantics of value assignment of array types is different from value
assignment of other types. Recall the `Point` class from the examples in [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), and consider the following [value assignments](10-expressions.md#simple-assignment) and their abstract implementation:

`$a = array(10, 'B' => new Point(1, 3));`
<pre>
[VSlot $a *]-->[VStore Arr *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]]
                                                       |             |
                                                       V             V
                                             [VStore Int 10]   [VStore Obj *]
                                                                           |
                                [HStore Point [VSlot $x *] [VSlot $y *]]&lt;--+
                                                        |            |
                                                        V            V
                                            [VStore Int 1]  [VStore Int 3]
</pre>

In the example above, `$a`‘s VStore is initialized to contain a handle to
an HStore for an array containing two elements, where one element is an
integer and the other is a handle to an HStore for an object.

Now consider the following value assignment `$b = $a`. A conforming
implementation must implement value assignment of arrays in one of the
following ways: (1) eager copying, where the implementation makes a copy
of `$a`’s array during value assignment and changes `$b`’s VSlot to point
to the copy; or (2) deferred copying, where the implementation uses a
deferred copy mechanism that meets certain requirements. This section
describes eager copying, and the section that immediately follows ([§§](#deferred-array-copying))
describes deferred copying.

To describe the semantics of eager copying, let’s begin by considering
the value assignment `$b = $a`:
<pre>
[VSlot $a *]-->[VStore Arr *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]]
                                                       |             |
[VSlot $b *]-->[VStore Arr *]                          V             V
                           |                    [VStore Int 10]  [VStore Obj *]
                           V                                                 |
[HStore Array [VSlot 0 *] [VSlot 'B' *]]                                     |
                       |             |                                       |
             +---------+   +---------+                                       |
             V             V                                                 |
[VStore Int 10] [VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]&lt;---+
                                                         |            |
                                                         V            V
                                                 [VStore Int 1]  [VStore Int 3]
</pre>

The value assignment `$b = $a` made a copy of `$a`’s array. Note how
`$b`’s VSlot points to a different VStore than `$a`’s VSlot, and `$b`’s
VStore points to a different HStore than `$b`’s VStore. Each source array
element is copied using *member-copy assignment* `=*`, which is defined
as follows:

```Hack
   $destination =* $source
```
-   If `$source`’s VStore has a refcount equal to 1, the Engine copies the
    array element using  value assignment (`destination = $source`).
-   If `$source`’s VStore has a refcount that is greater than 1, the Engine
    uses an implementation-defined algorithm to decide whether to copy the element
    using value assignment (`$destination = $source`) or byRef
    assignment (`$destination =& $source`).

Note the member-copy assignment `=*` is **not** an operator or language
construct in the Hack language, but instead it is used internally to
describe behavior for the engine for array copying and other operations

For the particular example above, member-copy assignment exhibits the
same semantics as value assignment for all conforming implementations
because all of the array elements’ VStores have a refcount equal to 1.
The first element VSlots in `$a`’s array and `$b`’s array point
to distinct VStores, each of which contain a distinct copy of the
integer value 10. The second element VSlots in `$a`’s array and `$b`’s
array point to distinct VStores, each of which contain a handle to the
same object HStore.

Let’s consider another example:
```Hack
$x = 123;
$a = array(array(&$x, 'hi'));
$b = $a;
```

Eager copying can produce two possible outcomes depending on the
implementation. Here is the first possible outcome:
<pre>
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]]
                                                           |
[VSlot $x *]-------------------------+   [VStore Arr *]&lt;---+
                                     |               |
[VSlot $b *]-->[VStore Arr *]        |               V
                           |         |  [HStore Array [VSlot 0 *][VSlot 1 *]]
                           V         |                          |          |
         [HStore Array [VSlot 0 *]]  |                          V          |
                                |    +---------------->[VStore Int 123]    |
                                V                          ^               V
                     [VStore Arr *]                        |   [VStore Str 'hi']
                                 |          +--------------+
                                 V          |
                     [HStore Array [VSlot 0 *] [VSlot 1 *]]
                                                        |
                                                        V
                                                     [VStore Str 'hi']
</pre>

Here is the second possible outcome:
<pre>
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]]
                                                           |
[VSlot $x *]-------------------------+  [VStore Arr *]&lt;----+
                                     |               |
[VSlot $b *]-->[VStore Arr *]        |               V
                           |         |  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                           V         |                         |           |
         [HStore Array [VSlot 0 *]]  |                         V           |
                                |    +---------------->[VStore Int 123]    |
                                V                                          V
                     [VStore Arr *]                            [VStore Str 'hi']
                                 |
                                 V
                    [HStore Array [VSlot 0 *] [VSlot 1 *]]
                                           |           |
                                           V           V 
                                  [VStore Int 123]  [VStore Str 'hi']
</pre>

In both possible outcomes, value assignment with eager copying makes a
copy of `$a`’s array, copying the array’s single element using
member-copy assignment (which in this case will exhibit the same
semantics of value assignment for all implementations), which in turn
makes a copy of the inner array inside `$a`’s array, copying the inner
array’s elements using member-copy assignment. The inner array’s first
element VSlot points to a VStore that has a refcount that is greater than 1,
so an implementation-defined algorithm is used to decide whether to use value
assignment or byRef assignment. The first possible outcome shown above
demonstrates what happens if the implementation chooses to do byRef
assignment, and the second possible outcome shown above demonstrates
what happens if the implementation chooses to do value assignment. The
inner array’s second element VSlot points to a VStore that has a refcount
equal to 1, so value assignment is used to copy the inner array’s second
element for all conforming implementations that use eager copying.

Although the examples in this section only use arrays with one
element or two elements, the model works equally well for all
arrays even though they can have an arbitrarily large number
of elements. As to how an HStore accommodates all of them, is
unspecified and unimportant to the abstract model.

#### Deferred Array Copying
As mentioned in the previous section ([§§](#value-assignment-of-array-types-to-local-variables)), an implementation may
choose to use a deferred copy mechanism instead of eagerly making a copy
for value assignment of arrays. An implementation may use any deferred
copy mechanism desired so long as it conforms to the abstract model’s
description of deferred array copy mechanisms presented in this
section.

Because an array’s contents can be arbitrarily large, eagerly copying an
array’s entire contents for value assignment can be expensive. In
practice an application written in Hack may rely on value assignment of
arrays being relatively inexpensive for the common case (in order to deliver
acceptable performance), and as such it is common for an implementation
to use a deferred array copy mechanism in order to reduce the cost of
value assignment for arrays.

Unlike conforming deferred string copy mechanisms discussed in [§§](#value-assignment-of-scalar-types-to-a-local-variable)
that must produce the same observable behavior as eager string copying,
deferred array copy mechanisms are allowed in some cases to exhibit
observably different behavior than eager array copying. Thus, for
completeness this section describes how deferred array copies can be
modeled in the abstract memory model and how conforming deferred array
copy mechanisms must behave.

Conforming deferred array copy mechanisms work by not making an array
copy during value assignment, by allowing the destination VStore to
share an array HStore with the source VStore, and by making a copy of
the array HStore at a later time if or when it is necessary. The
abstract model represents a deferred array copy relationship by marking
the destination VStore with a special “Arr-D” type tag and by sharing
the same array HStore between the source and destination VStores. Note
that the source VStore’s type tag remains unchanged. For the purposes of
this abstract model, the “Arr-D” type tag is considered identical to the
“Arr” type in all respects except when specified otherwise.

To illustrate this, let’s see how the previous example would be
represented under the abstract model assuming the implementation defers
the copying the array:

```Hack
$x = 123;
$a = array(array(&$x, ‘hi’));
$b = $a;
```
<pre>
[VSlot $a *]--->[VStore Arr *]--->[HStore Array [VSlot 0 *]]
                                    ^                    |
                                    |   [VStore Arr *]&lt;--+
[VSlot $b *]--->[VStore Arr-D *]----+               |
                                                    V
                                        [HStore Array [VSlot 0 *] [VSlot 1 *]]
                                                               |           |
                                                               V           |
[VSlot $x *]------------------------------------------>[VStore Int 123]    |
                                                                           V
                                                               [VStore Str 'hi']
</pre>

As we can see, both `$a`’s VStore (the source VStore) and `$b`’s VStore
(the destination VStore) point to the same array HStore. Note the
asymmetric nature of how deferred array copies are represented in the
abstract model. In the above example the source VStore’s type tag
remains unchanged after value assignment, whereas the destination
VStore’s type tag was changed to “Arr-D”.

When the engine is about to perform an array-mutating operation on a
VStore tagged “Arr” that participates in a deferred array copy
relationship or on a VStore tagged “Arr-D”, the engine must first take
certain actions that involve making a copy of the array (described in
the next paragraph) before performing the array-mutating operation. An
array-mutating operation is any operation can add or remove array
elements, overwrite existing array elements, change the state of the
array’s internal cursor, or cause the refcount of one or more of the
array’s element VStores or subelement VStores to increase from 1 to
a value greater than 1. This requirement to take certain actions before
performing an array-mutation operation on a VStore participating in a
deferred array copy relationship is commonly referred to as the
copy-on-write requirement.

When an array-mutating operation is about to be performed on a given
VStore X with an “Arr” type tag that participates in a deferred array
copy relationship, the engine must find all of the VStores tagged
“Arr-D” that point to the same array HStore that VStore X points to,
make a copy of the array (using member-copy assignment to copy the
array’s elements as described in [§§](#value-assignment-of-array-types-to-local-variables)), and update all of these
VStores tagged “Arr-D” to point to the newly created copy (note that
VStore X remains unchanged). When an array-mutation operation is about
to be performed on a given VStore X with an “Arr-D” type tag, the engine
must make a copy of the array (as described in [§§](#value-assignment-of-array-types-to-local-variables)), update VStore
X to point to the newly created copy, and change VStore X’s type tag to
“Arr”. These specific actions that the engine must perform on VStore at
certain times to satisfy the copy-on-write requirement are collectively
referred to as “array-separation” or “array-separating the VStore”. An
array-mutation operation is said to “trigger” an array-separation.

Note that for any VStore with an “Arr” type tag that participates in a
deferred array copy relationship, or for any VStore with an “Arr-D” type
tag, a conforming implementation may choose to array-separate the VStore
at any time for any reason as long as the copy-on-write requirement is
upheld.

Continuing with the previous example, consider the array-mutating
operation `$b[1]++`. Depending on the implementation, this can produce
one of three possible outcomes. Here is the one of the possible
outcomes:
<pre>
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]]
                                                           |
[VSlot $b *]-->[VStore Arr *]            [VStore Arr *]&lt;---+
                             |                       |
      +----------------------+              +--------+
      V                                     V
  [HStore Array [VSlot 0 *] [VSlot 1 *]]  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                         |           |       ^                  |          |
                         |           V       |                  V          |
                         |   [VStore Int 1]  |            [VStore Int 123] |
                         V                   |             ^               V
                       [VStore Arr-D *]-----+              |   [VStore Str 'hi']
                                                           |
 [VSlot $x *]----------------------------------------------+
</pre>

As we can see in the outcome shown above, `$b`’s VStore was
array-separated and now `$a`’s VStore and `$b`’s VStore point to distinct
array HStores. Performing array-separation on `$b`’s VStore was necessary
to satisfy the copy-on-write requirement. `$a`’s array remains unchanged
and that `$x` and `$a[0][0]` still have an alias relationship with each
other. For this particular example, conforming implementations are
required to preserve `$a`’s array’s contents and to preserve the alias
relationship between `$x` and `$a[0][0]`. Finally, note that `$a[0]` and
`$b[0]` have a deferred copy relationship with each other in the outcome
shown above. For this particular example, a conforming implementation is
not required to array-separate `$b[0]`’s VStore, and the outcome shown
above demonstrates what happens when `$b[0]`’s VStore is not
array-separated. However, an implementation can choose to array-separate
`$b[0]`’s VStore at any time if desired. The other two possible outcomes
shown below demonstrate what can possibly happen if the implementation
choose to array-separate `$b[0]`’s VStore as well. Here is the second
possible outcome:
<pre>
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]]
                                                           |
[VSlot $b *]-->[VStore Arr *]            [VStore Arr *]&lt;---+
                          |                          |
                          V                          V
  [HStore Array [VSlot 0 *] [VSlot 1 *]]  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                         |           |                           |           |
       +-----------------+           V                           |           |
       |                     [VStore Int 1]                  +---+           |
       V                                                     |               V
  [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore Str 'hi']
                                            |           |   |
                                    +-------+           |   |
                                    |                   V   |
                                    |    [VStore Str ‘hi’]  |
                                    V                       |
 [VSlot $x *]--------------------->[VStore Int 123]&lt;--------+
</pre>

Here is the third possible outcome:
<pre>
[VSlot $a *]---->[VStore Arr *-]---->[HStore Array [VSlot 0 *]]
                                                            |
[VSlot $b *]-->[VStore Arr *]             [VStore Arr *]&lt;---+
                            |                          |
                            V                          V
 [HStore Array [VSlot 0 *] [VSlot 1 *]]  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                         |           |                           |           |
       +-----------------+           V                           |           |
       |                     [VStore Int 1]                  +---+           |
       V                                                     |               V
   [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore Str 'hi']
                                             |           |   |
                     [VStore Int 123]&lt;-------+           |   |
                                                         V   |
                                          [VStore Str 'hi']  |
                                                             |
 [VSlot $x *]--------------------->[VStore Int 123]&lt;--------+
</pre>

The second and third possible outcomes show what can possibly happen if
the implementation chooses to array-separate `$b[0]`’s VStore. In the
second outcome, `$b[0][0]` has an alias relationship with `$x` and
`$a[0][0]`. In the third outcome, `$b[0][0]` does not have an alias
relationship, though `$x` and `$a[0][0]` still have an alias relationship
with each other. The differences between the second and third outcome
are reflect that different possibilities when the engine uses
member-copy assignment to copy `$a[0]`’s arrays’s elements into `$b[0]`’s
array.

Finally, let’s briefly consider one more example:
```Hack
$x = 0;
$a = array(&$x);
$b = $a;
$x = 2;
unset($x);
$b[1]++;
$b[0]++;
echo $a[0], ' ', $b[0];
```

For the example above, a conforming implementation could output “2 1”,
“2 3”, or “3 3” depending on how it implements value assignment for
arrays.

For portability, it is generally recommended that programs written in
Hack should avoid performing value assignment with a right-hand side that
is an array with one or more elements or sub-elements that have an alias
relationship.

***Implementation Notes*** For generality and for simplicity, the
abstract model represents deferred array copy mechanisms in a manner
that is more open-ended and superficially different than the php.net
implementation’s model, which uses a symmetric deferred copy mechanism
where a single zval contains the sole pointer to a given Hashtable and
deferred array copies are represented as multiple slots pointing to the
same single zval that holds the array. Despite this superficial
difference, php.net’s implementation produces behavior that is
compatible with the abstract model’s definition of deferred array copy
mechanisms.

#### General Value Assignment
The sections above thus far have described the mechanics of value assignment
to a local variable. This section describes how value assignment works
when general modifiable lvalue expressions are used on the left hand side.

For example, assuming `Point` definition as in previous sections and further
assuming all instance properties are public, this code:

```Hack
$a = new Point(1, 3);
$b = 123;
$a->x = $b;
```

will result in:
<pre>
[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                           |            |
                                                           V            V
                                                  [VStore int 123] [VStore int 3]
[VSlot $b *]-->[VStore int 123]
</pre>

If needed, new VSlots are created as part of the containing VStore, for example:

```Hack
$a = new Point(1, 3);
$b = 123;
$a->z = $b;
```

will result in:
<pre>
[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *] [VSlot $z *]]
                                                           |            |            |
                                                           V            V            V
                                                  [VStore int 1] [VStore int 3] [VStore int 123]
[VSlot $b *]-->[VStore int 123]
</pre>

The same holds for array elements:
```Hack
$a = array('hello', 'world');
$b = 'hack';
$a[1] = $b;
$a[2] = 'World!';
```

will result in:
<pre>
[VSlot $a *]-->[VStore array *]-->[HStore Array [VSlot 0 *]  [VSlot 1 *]  [VSlot 2 *]]
                                                         |            |            |
                                                         V            V            V
                                    [VStore string 'hello'] [VStore string 'hack'] [VStore string 'World!']
[VSlot $b *]-->[VStore string 'hack']
</pre>

where the third VSlot with index 2 was created by the assignment.

Note that any array element and instance property, including a designation of non-existing ones,
is considered a modifiable lvalue, and the VSlot will be created by the engine and added
to the appropriate HStore automatically. Static class properties are considered modifiable lvalues too,
though new ones would not be created automatically.

#### General ByRef Assignment
The sections above thus far have described the mechanics of byref assignment
with local variables. This section describes how byref assignment works when
general modifiable lvalue expressions are used on the left hand side and/or
the right hand side.

For example:

```Hack
$a = new Point(1, 3);
$b = 123;
$a->z =& $b;
```

will result in:
<pre>
[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *] [VSlot $z *]]
                                                           |            |            |
                                                           V            V            |
                                                  [VStore int 1] [VStore int 3]      |
[VSlot $b *]---------------->[VStore int 123]&lt;---------------------------------------+
</pre>

### Argument Passing
Argument passing is defined in terms of simple assignment[§§](#value-assignment-of-scalar-types-to-a-local-variable), [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), [§§](#value-assignment-of-array-types-to-local-variables), and [§§](10-expressions.md#simple-assignment)). 
That is, passing an argument to a function having a corresponding
parameter is like assigning that argument to that parameter.

### Value Returning
Returning a value from a function is defined in terms of simple
assignment ([§§](#value-assignment-of-scalar-types-to-a-local-variable), [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), [§§](#value-assignment-of-array-types-to-local-variables), and [§§](10-expressions.md#simple-assignment)).  That is, returning a value from a function to its
caller is like assigning that value to the user of the caller's return
value.


### Cloning objects
When an instance is allocated, [operator `new`](10-expressions.md#the-new-operator) returns a handle
that points to that object. (As described in [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable)), value assignment of a handle to an object does not copy the object HStore itself. Instead, it creates a copy of the handle. How then to make a copy of the object itself? Our only access to it is
via the handle. The Hack language allows us to do this via [operator `clone`](10-expressions.md#the-clone-operator).

To demonstrate how the `clone` operator works, consider the case in which
an instance of class `Widget` contains two instance properties: `$p1` has
the integer value 10, and `$p2` is a handle to an array of elements of
some type(s) or to an instance of some other type.
<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]]
                                                          |          |
                                                          V          V
                                               [VStore Int 10] [VStore Obj *]
                                                                         |
                                                                         V
                                                                 [HStore ...]
</pre>

Let us consider the result of `$b = clone $a`:
<pre>
[VSlot $a *]-->[VStore Obj *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]]
                                                          |            |
[VSlot $b *]-->[VStore Obj *]                             V            V
                             |                  [VStore Int 10] [VStore Obj *]
     +-----------------------+                                              |
     V                                                                      V
   [HStore Widget [VSlot $p1 *] [VSlot $p2 *]]              +--->[HStore ...]
                             |             |                |
                             V             V                |
                 [VStore Int 10] [VStore Obj *]-------------+
</pre>

The clone operator will create another object HStore of the same class
as the original, copy `$a`’s object’s instance properties using
member-copy [assignment `=*`](#value-assignment-of-array-types-to-local-variables). For the example shown above, the
handle to the newly created HStore stored into `$b` using value
assignment. Note that the clone operator will not recursively clone
objects held in `$a`’s instance properties; hence the object copying
performed by the clone operator is often referred to as a *shallow
copy*. If a *deep copy* of an object is desired, the programmer must
achieve this manually by using the method [`__clone`](16-classes.md#method-__clone) or by
other means.

## Scope

The same name can designate different things at different places in a
program. For each different thing that a name designates, that name is
visible only within a part of the program called that name's *scope*.
The following distinct scopes exist:

-   Script, which means from the point of declaration/first
    initialization through to the end of that script, including any
    [included scripts](12-script-inclusion.md#script-inclusion-operators).
-   Function, which means from the point of declaration/first
    initialization through to the end of that [function](15-functions.md#function-definitions).
-   Class, which means the body of that class and any classes derived
    from it ([§§](16-classes.md#class-declarations)).
-   Interface, which means the body of that interface, any interfaces
    derived from it, and any classes that implement it ([§§](17-interfaces.md#interface-declarations)).
-   Namespace, which means from the point of declaration/first
    initialization through to the end of that [namespace](20-namespaces.md#general).

A variable declared or first initialized inside a function has function scope.

Each function has its own function scope. An [anonymous function](15-functions.md#anonymous-functions)
has its own scope separate from that of any function inside which that
anonymous function is defined.

The scope of a parameter is the body of the function in which the
parameter is declared. For the purposes of scope, a [catch-block](11-statements.md#the-try-statement)
is treated like a function body, in which case, the *variable-name* in
*parameter-declaration-list* is treated like a parameter.

The scope of a class member `m` ([§§](16-classes.md#class-members)) declared in, or inherited by, a
class type `C` is the body of `C`.

The scope of an interface member `m` ([§§](17-interfaces.md#interface-members)) declared in, or inherited by,
an interface type `I` is the body of `I`.

When a [trait](18-traits.md#general) is used by a class or an interface, the [trait's
members](16-classes.md#class-members) take on the scope of a member of that class or
interface.

## Storage Duration

The lifetime of a variable is the time during program execution that
storage for that variable is guaranteed to exist. This lifetime is
referred to as the variable's *storage duration*, of which there are
three kinds: automatic, static, and allocated.

A variable having *automatic storage duration* comes into being and is
initialized at its declaration or on its first use, if it has no
declaration. Its lifetime is delimited by an enclosing [scope](#scope). The
automatic variable's lifetime ends at the end of that scope. Automatic
variables lend themselves to being stored on a stack where they can help
support argument passing and recursion. [Local variables](07-variables.md#local-variables), which
include [function parameters](15-functions.md#function-definitions), have automatic storage duration.

A variable having *static storage duration* comes into being and is
initialized before its first use, and lives until program shutdown. The
following kinds of variables have static storage duration: [function statics](07-variables.md#function-statics), [static properties](07-variables.md#static-properties), and [class and interface constants](07-variables.md#class-and-interface-constants).

A variable having *allocated storage duration* comes into being based on
program logic by use of the [`new` operator](10-expressions.md#the-new-operator). Ordinarily, once
such storage is no longer needed, it is reclaimed automatically by the
Engine via its garbage-collection process and the use of
[destructors](16-classes.md#destructors). The following kinds of variables have allocated
storage duration: [array elements](07-variables.md#array-elements) and [instance properties](07-variables.md#instance-properties).

The following example demonstrates the three storage durations:

```Hack
class Point { ... }

function doit($p1) {
  $av2 = ...;           // auto variable $av2 created and initialized
  static $sv2 = ...;    // static variable $sv2 created and initialized
  if ($p1) {
    $av3 = ...;         // auto variable $av3 created and initialized
    static $sv3 = ...;  // static variable $sv3 created and initialized
    ...
  }
  global $av1;
  $av1 = new Point(2, 3);   // Point(0,1) is eligible for destruction
  ...
}                       // $av2 and $av3 are eligible for destruction

function main($p1): void {
  $av1 = new Point();   // auto variable $av1 created and initialized
  static $sv1 = ...;    // static variable $sv1 created and initialized
  doit(true);
}

// At end of script, $sv1, $sv2, and $sv3 are eligible for destruction
```

The comments indicate the beginning and end of lifetimes for each
variable.

If function `doit` is called multiple times, each time it is called, its
automatic variables are created and initialized, whereas its static
variables retain their values from previous calls.

Consider the following recursive function: 

```Hack
function factorial(int $i): int {
  if ($i > 1) return $i * factorial($i - 1);
  else if ($i == 1) return $i;
  else return 0;
}
```

When `factorial` is first called, the local variable parameter `$i` is
created and initialized with the value of the argument in the call.
Then, if this function calls itself, the same process is repeated each
call. Specifically, each time `factorial` calls itself, a new local
variable parameter `$i` is created and initialized with the value of the
argument in the call.

The lifetime of any [VStore](#general) or [HStore](#general) can be extended by
the Engine as long as needed. Conceptually, the lifetime of a VStore ends
when it is no longer pointed to by any [VSlots](#general). Conceptually, the
lifetime of an HStore ends when no VStores have a handle to it.


================================================
FILE: spec/05-types.md
================================================
# Types

## General

The meaning of a value is decided by its *type*. Hack's types are
categorized as *scalar types* and *composite types*. The scalar types
are [Boolean](#the-boolean-type), [integer](#the-integer-type), [floating-point](#the-floating-point-type), [numeric](05-types.md#the-numeric-type), [string](#the-string-type), [array key](05-types.md#the-array-key-type), [null](#the-null-type), and
[enumerated](05-types.md#enumerated-types). The non-scalar types are [array](05-types.md#array-types), [class](05-types.md#class-types), [interface](05-types.md#interface-types), [tuple](05-types.md#tuple-types), [shape](05-types.md#shape-types), [closure](05-types.md#closure-types), [resource](05-types.md#resource-types), and [nullable](05-types.md#nullable-types). The [void type](05-types.md#the-void-type) is neither scalar nor
non-scalar.

The integer, floating-point, and numeric types are known collectively as
arithmetic types. (Note carefully, that the library function [is_numeric](http://www.php.net/is_numeric) indicates if a given value is an int, a float, or a [numeric string](05-types.md#the-string-type).)

The scalar types are *value types*. That is, a variable of scalar type
behaves as though it contains its own value. On the
other hand, the non-scalar types are *handles*. A variable of
non-scalar type contains information—in a *handle*—that leads to the
value. The differences between value types and handles become apparent
when it comes to understanding the semantics of assignment, and passing
arguments to, and returning values from, functions ([§§](04-basic-concepts.md#the-memory-model)). That said,
array types really are a hybrid; on the one hand, an array may contain
an arbitrary number of elements separate from the array variable itself,
yet on the other hand, certain array operations do have value semantics.

**Note**: One could differentiate value types and handles in the same way that pass-by-value and pass-by-reference types are distinguished.

Variables are not declared to have a particular type. Instead, a
variable's type is decided at runtime by the context in which it is
used.

A *type constraint* indicates a requirement that a type must fulfill in order to be accepted in a given context. Type constraints are used in [type aliasing](05-types.md#type-aliases), [enum declarations](13-enums.md#enum-declarations), [type parameters](14-generic-types-methods-and-functions.md#type-parameters), and [type constants](16-classes.md#type-constants).

The library function [`is_scalar`](http://www.php.net/is_scalar) indicates if a given value has a scalar
type. However, that function does not consider `null` to be scalar. To test
for `null`, use [`is_null`](http://www.php.net/is_null). Useful library functions for interrogating and using type information include [`gettype`](http://www.php.net/gettype), [`is_type`](http://www.php.net/is_type), [`settype`](http://www.php.net/settype), and [`var_dump`](http://www.php.net/var_dump).

**Syntax**
<pre>
<i>type-specifier:</i>
  arraykey
  bool
  float
  int
  num
  resource
  string
  this
  void
  <i>alias-type-specifier</i>
  <i>class-interface-trait-specifier</i>
  <i>classname-type-specifier</i>
  <i>closure-type-specifier</i>
  <i>enum-specifier</i>
  <i>generic-type-parameter-name</i>
  <i>map-like-array-type-specifier</i>
  <i>nullable-type-specifier</i>
  <i>shape-specifier</i>
  <i>tuple-type-specifier</i>
  <i>type-constant-type-name</i>
  <i>vector-like-array-type-specifier</i>

<i>alias-type-specifier:</i>
  <i>qualified-name</i>

<i>enum-specifier:</i>
  <i>qualified-name</i>

<i>class-interface-trait-specifier:</i>
  <i>qualified-name generic-type-argument-list<sub>opt</sub></i>

<i>type-specifier-list:</i>
  <i>type-specifiers</i>  ,<sub>opt</sub>

<i>type-specifiers</i>
  <i>type-specifier</i>
  <i>type-specifiers</i> , <i>type-specifier</i>

<i>type-constraint:</i>
  as  <i>type-specifier</i>

<i>type-constant-type-name:</i>
  <i>name</i>  ::  <i>name</i>
  self  ::  <i>name</i>
  this  ::  <i>name</i>
  <i>type-constant-type-name</i>  ::  <i>name</i>
</pre>

**Defined elsewhere**

* [*classname-type-specifier*](05-types.md#the-classname-type)
* [*closure-type-specifier*](05-types.md#closure-types)
* [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-arguments)
* [*generic-type-parameter-name*](14-generic-types-methods-and-functions.md#type-parameters)
* [*map-like-array-type-specifier*](05-types.md#array-types)
* [*name*](09-lexical-structure.md#names)
* [*nullable-type-specifier*](05-types.md#nullable-types)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
* [*shape-type-specifier*](05-types.md#shape-types)
* [*tuple-type-specifier*](05-types.md#tuple-types)
* [*vector-like-array-type-specifier*](05-types.md#array-types)

**Constraints**

The *qualified-name* in *alias-type-specifier* must qualify the *name* of a
type alias declared in an [*alias-declaration*](05-types.md#type-aliases).

The *qualified-name* in *enum-specifier* must qualify the *name* of an enumerated type declared in an [*enum-declaration*](13-enums.md#enum-declarations).

The *qualified-name* in *class-interface-trait-specifier* must qualify the
*name* of a class type declared in a [*class-declaration*](16-classes.md#class-declarations), of an
interface type declared in an [*interface-declaration*](17-interfaces.md#interface-declarations), or of a trait
type declared in a [*trait-declaration*](18-traits.md#trait-declarations).

The *name* of a trait type declared in a *trait-declaration* can only be used
as a type-specifier in the context of a [*trait-use-clauses*](18-traits.md#trait-declarations).

For *name* `::` *name*, the left-hand *name* must be the name of a class or interface that directly or indirectly has a [type-constant member](16-classes.md#type-constants) whose name is the right-hand *name*.

For `self` `::` *name*, *name* must be the name of a type-constant member in the current class (including any implemented interfaces).

For `this` `::` *name*, *name* must be the name of a type-constant member in the current class/interface hierarchy.

A *type-constant-type-name* beginning with `self` or `this` must be used in the context of a class or interface to which `self` or `this`, respectively, can apply.

**Semantics**

A *type-constant-type-name* specifies a type, as follows:

*	For *name* `::` *name*, the type is that designated by the type-constant having the right-hand *name*, in the class or interface having the left-hand *name*.
*	For `self` `::` *name*, used within a class, the type is that designated by the type-constant named *name*, in the enclosing class, ignoring any overrides.
*	For `this` `::` *name*, used within a class, the type is that designated by the type-constant named *name*, in the enclosing class’s hierarchy resolved in a late-bound context. For a non-static member, this designates the class of the `$this` object; for a static member, this designates the current class. `this` is recommended when accessing abstract type constant names.
*	In cases of *type-constant-type-name* having the form `x::y::z`, the type is resolved left-to-right.

A given type constant can be referenced via multiple names; for example:

```Hack
interface I {
  const type T = int;
}

class C1 implements I {}
class C2 extends C1 {}
```

Here, `I::T`, `C1::T`, and `C2::T`, all refer to the same type constant.

Consider the following:

```Hack
interface I {
  const type this = int;    // this is a name, NOT a keyword
}

class C {
  const type self = I;      // self is a name, NOT a keyword
}

function test10(C::self::this $x): void {}
```

For some examples, see [§§](16-classes.md#type-constants).

## The Boolean Type

The Boolean type is `bool`. This
type is capable of storing two distinct values, which correspond to the
Boolean values `true` and `false`, respectively. The representation of
this type and its values is unspecified.

The library function [`is_bool`](http://www.php.net/is_bool) indicates if a given value has type
`bool`.

## The Integer Type

There is one integer type, `int`.
This type is binary, signed, and uses twos-complement representation for
negative values. The range of values that can be stored is
implementation-defined; however, the range [-9223372036854775808, 9223372036854775807],
must be supported.

Certain operations on integer values produce a mathematical result that
cannot be represented as an integer. Examples include the following:

-   Incrementing the largest value or decrementing the smallest value
-   Applying the unary minus to the smallest value
-   Multiplying, adding, or subtracting two values

In such cases, the resulting type and value is implementation-defined,
but must be one of the following:

-   The result type is int and the value reflects wrap-around (for
    example adding 1 to the largest value results in the smallest value)
-   The computation is done as though the type had some unspecified,
    arithmetic-like object type with the result being mathematically
    correct

The constants [`PHP_INT_SIZE`, `PHP_INT_MIN` and `PHP_INT_MAX`](06-constants.md#core-predefined-constants) define certain
characteristics about type `int`.

The library function [`is_int`](http://www.php.net/is_int) indicates if a given value has type
int.

## The Floating-Point Type

There is one floating-point type, `float`. The `float` type must support at least the range and
precision of IEEE 754 64-bit double-precision representation.

The library function [`is_float`](http://www.php.net/is_float) indicates if a given value has type
`float`. The library function [`is_finite`](http://www.php.net/is_finite) indicates if a given
floating-point value is finite. The library function [`is_infinite`](http://www.php.net/is_infinite)
indicates if a given floating-point value is infinite. The library
function [`is_nan`](http://www.php.net/is_nan) indicates if a given floating-point value is a
`NaN`.

## The Numeric Type

The type `num` can represent any integer or floating-point value.

See the discussion of [type side effects](05-types.md#type-side-effects).

## The String Type

There is one string type, `string`.

A string is a set of contiguous bytes that represents a sequence of zero
or more characters.

Conceptually, a string can be considered as an [array](05-types.md#array-types) of
bytes—the *elements*—whose keys are the `int` values starting at zero. The
type of each element is `string`. However, a string is *not* considered a
collection, so it cannot be iterated over.

A string whose length is zero is an *empty string*.

As to how the bytes in a string translate into characters is
unspecified.

Although a user of a string might choose to ascribe special semantics to
bytes having the value `U+0000`, from Hack's perspective, such *null bytes*
are simply just bytes! Hack does not assume strings contain any specific
data or assign special values to any bytes or sequences. However, many
library functions assume the strings they receive as arguments are UTF-8
encoded, often without explicitly mentioning that fact.

A *numeric string* is a string whose content exactly matches the pattern
defined by the *str-numeric* production below. A *leading-numeric string* is a string whose initial characters follow
the requirements of a numeric string, and whose trailing characters are
non-numeric. A *non-numeric string* is a string that is not a numeric
string.

<pre>
  <i>str-numeric::</i>
    <i>str-whitespace<sub>opt</sub>   sign<sub>opt</sub>   str-number</i>

  <i>str-whitespace::</i>
    <i>str-whitespace<sub>opt</sub>   str-whitespace-char</i>

  <i>str-whitespace-char::</i>
    <i>new-line</i>
    Space character (U+0020)
    Horizontal-tab character (U+0009)
    Vertical-tab character (U+000B)
    Form-feed character (U+000C)

  <i>str-number::</i>
    <i>digit-sequence</i>
    <i>floating-literal</i>
</pre>

**Defined elsewhere**

* [*digit-sequence*](09-lexical-structure.md#floating-point-literals)
* [*floating-literal*](09-lexical-structure.md#floating-point-literals)
* [*new-line*](09-lexical-structure.md#comments)
* [*sign*](09-lexical-structure.md#floating-point-literals)

Note that *digit-sequence* is interpreted as having base-10 (so `"0377"` is treated as 377 decimal with a redundant
leading zero, rather than as octal 377).

Only one mutation operation may be performed on a string, offset
assignment, which involves the [simple assignment operator `=`](10-expressions.md#simple-assignment).

The library function [`is_string`](http://www.php.net/is_string) indicates if a given value has
type `string`.

## The Array Key Type
The type `arraykey` can represent any integer or string value.

See the discussion of [type side effects](05-types.md#type-side-effects).

## The Null Type

The null type has only one possible value, [`null`](06-constants.md#core-predefined-constants). The representation
of this type and its value is unspecified.

The library function [`is_null`](http://www.php.net/is_null) indicates if a given value is `null`.

## Enumerated Types

Enumerated types are described in [§§](13-enums.md#enums).

## The Void Type

The type `void` indicates the absence of a value. Its primary use is as the
return type of a function.

## Array Types

**Syntax**
<pre>
<i>vector-like-array-type-specifier:</i>
  array &lt; <i>array-value-type-specifier</i> &gt;

<i>map-like-array-type-specifier:</i>
  array &lt; <i>array-value-type-specifier</i> , <i>array-value-type-specifier</i> &gt;

<i>array-value-type-specifier:</i>
  <i>type-specifier</i>

<i>array-key-type-specifier:</i>
  <i>type-specifier</i>
</pre>

**Defined elsewhere**

* [*type-specifier*](05-types.md#general).

**Constraints**

This is not currently a syntax constraint, but ... Although
*array-key-type-specifier* can really be any type,
behind the scenes, the key is actually represented as an `int` or `string`,
so (possibly surprising, or at least, unexpected) conversions occur when other
key types are specified. Similarly, *array-value-type-specifier* can really be
any type. Programmers are
strongly advised to avoid using key types other than `int` or `string`.

**Semantics**

An *array* is a data structure that contains a collection of zero or more elements each of which is accessed through a corresponding key. As the number
of elements in an array can change at runtime, the *type-specifier* for an
array does not include an element count.

For a *vector-like-array-type-specifier*, the array has an implicit key type
of `int`, and an explicit value type as indicated by
*array-value-type-specifier*.

For a *map-like-array-type-specifier*, the array has an explicit key type as
indicated by *array-key-type-specifier*, and an explicit value type as
indicated by *array-value-type-specifier*.

Each element in an array must have a type that is the exact type indicated by
*array-value-type-specifier*, or a [subtype](05-types.md#supertypes-and-subtypes) of that type. For example,
an array of `num` can contain a mixture of `int` elements and `float` elements.

An array element can have any type (which allows for arrays of arrays).

An array is represented as an ordered map in which each entry is a key/value
pair that represents an element. Duplicate keys are not permitted. The order
of the elements in the map is the order in which the elements were inserted
into the array. An element is said to *exist* once it has been inserted into
the array with a corresponding key. An array is *extended* by initializing a
previously non-existent element using a new key. Elements cannot be removed
from an array.

The [`foreach` statement](11-statements.md#the-foreach-statement) can be used to iterate over the collection
of elements in an array, in the order in which the elements were inserted.
This statement provides a way to access the key and value for each element.

Each array has its own current element pointer that designates the current
array element. When an array is created, the current element is the first
element inserted into the array.

[Note: Arrays in Hack are quite different to arrays in numerous mainstream
languages. Specifically, in Hack, array elements need not have the same type,
the subscript index need not be an integer (so there is no concept of a base
index of zero or 1), and there is no concept of consecutive elements occupying
physically adjacent memory locations.]

An array is created and initialized by one of two equivalent ways: via the [array-creation operator `[]`](10-expressions.md#array-creation-operator) or the intrinsic [`array`](10-expressions.md#array).

The value (and possibly the type) of an existing element is obtained or
changed, and new elements are inserted, using the [subscript operator `[]`](10-expressions.md#subscript-operator).

The library function [`is_array`](http://www.php.net/is_array) indicates if a given value is an array.
Numerous other library functions are available to create and/or manipulate
arrays.

**Examples**
```Hack
private array<string> $colorsVect;
private array<int, string> $colorsMap;
private array<num> $measurements = array(10, 25.55);
private array<int, mixed> $items = array(true, 123, ‘red’, null);
private array<array<int>> $valueSets = array(array(10,20,30,40), array(1,2));
function f(array<?Button> $buttons): void { … }
function getProcesses(): array<?(function (string): int)> { … }
```

## Class Types

Class types are described in [§§](16-classes.md#classes).

See the discussion of [type side effects](05-types.md#type-side-effects).

The library function [`is_object`] (http://www.php.net/is_object) indicates if a given value is an
instance of any class, and the library function
[`get_class`](http://docs.hhvm.com/manual/en/function.get-class.php)
(§xx) indicates the name of an object's class. See also the [`instanceof`
operator](10-expressions.md#instanceof-operator).

## Interface Types

Interface types are described in [§§](17-interfaces.md#interfaces).

See the discussion of [type side effects](05-types.md#type-side-effects).

## Trait Types

Trait types are described in [§§](18-traits.md#traits).

Although traits are used to declare class and interface types, a trait type
cannot be used in the usual context of a type name (see [Constraints](05-types.md#general).
That said, for the purposes of [subtyping](05-types.md#supertypes-and-subtypes), traits are considered types.

## The `this` Type

The type name `this` refers to “the current class type at run time”. As such, it can only be used from within a class, an interface, or a trait. (`this` should not be confused with [`$this`](10-expressions.md#primary-expressions), which refers to “the current instance”, whose type is `this`.)

## Tuple Types

**Syntax**
<pre>
<i>tuple-type-specifier:</i>
  ( <i>type-specifier</i>  ,  <i>type-specifier-list</i>  )
</pre>

**Defined elsewhere**

* [*type-specifier*](05-types.md#general)
* [*type-specifier-list*](05-types.md#general)

**Semantics**

A *tuple* is a sequence of one or more elements the number of which is fixed
at the time of tuple creation. After a tuple has been created, no elements can
be added or removed, and the type of an existing element cannot be changed.
However, the value of any existing element can be changed. Each element can
have any type, and each unique, lexically ordered combination of element types
designates a distinct tuple type.

A tuple can be indexed with the [subscript operator](10-expressions.md#subscript-operator). The index of the
first element is zero, with subsequent elements having index values one more
than their predecessor. Specifically, for a tuple having n elements, their
indices are 0–*n*-1.

Note: Although a tuple of only one element can be created using a [tuple
literal](10-expressions.md#tuple-literals), a *tuple-type-specifier* must contain at least two elements.
While this disallows a function to take an argument or to return a value of
type (*T*), for example, one could simply declare that function to take or
return a value of type *T* directly instead.

**Examples**

```Hack
function f1((int, string) $p): void { … }
// -----------------------------------------
function f2(): (bool, array<int>, float) {
  return tuple(true, array(99, 88, 77), 10.5);
}
// -----------------------------------------
private ?(int, (string, float)) $prop = null;
```

## Shape Types

**Syntax**
<pre>
<i>shape-specifier:</i>
  shape ( <i>field-specifier-list<sub>opt</sub></i> )

<i>field-specifier-list:</i>
  <i>field-specifier</i>
  <i>field-specifier-list</i>  ,  <i>field-specifier</i>

<i>field-specifier:</i>
  <i>single-quoted-string-literal</i>  =>  <i>type-specifier</i>
  <i>qualified-name</i>  =>  <i>type-specifier</i>
  <i>scope-resolution-expression</i>  =>  <i>type-specifier</i>
</pre>

**Defined elsewhere**

* [*qualified-name*](20-namespaces.md#defining-namespaces)
* [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator)
* [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals)
* [*type-specifier*](05-types.md#general)

**Constraints**
The *qualified-name* or *scope-resolution-expression* must designate 
a [class constant](16-classes.md#constants) of type `int` or `string`.

Each string in the set of strings designated by all the
*single-quoted-string-literals*, *qualified-names* and
*scope-resolution-expressions* in a
*field-specifier-list* must have a distinct value.

Each integer in the set of all the *qualified-names* and 
*scope-resolution-expressions* 
in a *field-specifier-list* must have a distinct value.

The *field-specifiers* in a *field-specifier-list* must all have the
*single-quoted-string-literal* form, or all
have the *qualified-name* or *scope-resolution-expression* form; 
the forms must not be mixed.

**Semantics**

A *shape* consists of a group of zero or more data *fields* taken together as
a whole. [It takes on the role of what C and C# call a struct.] Such a
construct is sometimes referred to as a "lightweight class".

A *shape-specifier* defines a shape type as having an unordered set of fields
each of which has a name (indicated by *single-quoted-string-literal*, 
*qualified-name* or *scope-resolution-operator*) and a type (indicated by
*type-specifier*). A field in a shape is accessed using its name as the key in
a [*subscript-expression*](10-expressions.md#subscript-operator) that operates on a shape of the
corresponding shape type.

A field that has a [nullable type](05-types.md#nullable-types) need not be mentioned in any initializer of, or assignment to, a variable of that type; however, until its value is set explicitly, that field does not actually exist in the shape. Consider the following:

```Hack
function f3(shape('a' => int, 'n' => ?string) $p): void {
  echo "\$p['a']: " . $p['a'] . "\n";
  echo "\$p['n']: " . $p['n'] . "\n";  // only permitted if n exists
}
```

Given the call `f3(shape('a' => 10, 'n' => null))`, field `n` has its value set explicitly, and `f3` works fine. However, given the call `f3(shape('a' => 10))`, field `n` does not have its value set explicitly, in which case, attempting to access that field using `$p['n']` results in an “undefined index” error at runtime. To be certain such accesses succeed, first call [`Shapes::keyExists`](16-classes.md#class-shapes).

Consider a shape type *S2* whose field set is a superset of that in shape type *S1*. As such, *S2* is a subtype of *S1*. (See the banking example below.) However, when an *S2* is used as an *S1*, only the *S1* fields in that *S2* are accessible.

**Examples**

```Hack
shape('x' => int, 'y' => int)
shape('real' => float, 'imag' => float)
shape('id' => string, 'url' => string, 'count' => int)
shape('name' => string, 'address' => shape('street' => string, 'city' => string, 'state' => string, 'postcode' => int));
type APoint<T> = shape('x' => T, 'y' => T);
// -----------------------------------------
enum Bank: int {
  INVALID = 0;
  DEPOSIT = 1;
  WITHDRAWAL = 2;
  TRANSFER = 3;
}

type Transaction = shape('trtype' => Bank);
type Deposit = shape('trtype' => Bank, 'toaccnum' => int, 'amount' => float);
type Withdrawal = shape('trtype' => Bank, 'fromaccnum' => int, 'amount' => float);
type Transfer = shape('trtype' => Bank, 'fromaccnum' => int, 'toaccnum' => int, 'amount' => float);

function main(): void {
  processTransaction(shape('trtype' => Bank::DEPOSIT, 'toaccnum' => 23456, 'amount' => 100.00));
  processTransaction(shape('trtype' => Bank::WITHDRAWAL, 'fromaccnum' => 3157, 'amount' => 100.00));
  processTransaction(shape('trtype' => Bank::TRANSFER, 'fromaccnum' => 23456, 'toaccnum' => 3157, 'amount' => 100.00));
}

function processTransaction(Transaction $t): void {
  $ary = Shapes::toArray($t);
  switch ($t['trtype']) {
  case Bank::TRANSFER:
    echo "Transfer: " . ((string)$ary['amount'])
      . " from Account " . ((string)$ary['fromaccnum'])
      . " to Account " . ((string)$ary['toaccnum']) . "\n";
    break;

  case Bank::DEPOSIT:
    …
  }
}
```

Note carefully, that inside function `processTransaction`, even though the transaction passed in might have been a `Deposit`, a `Withdrawal`, or a `Transfer`, it always appears as a `Transaction`, so the only field you can access in `$t` is `trtype`. However, using `Shapes::toArray`, we can convert the `Transaction` to an array, and then get read-access to the field values we know that array must contain by indexing it using the field names, as shown.

## Closure Types

**Syntax**
<pre>
<i>closure-type-specifier:</i>
( function ( <i>type-specifier-list<sub>opt</sub></i> ) : <i>type-specifier</i> )
</pre>

**Defined elsewhere**

* [*type-specifier*](05-types.md#general)
* [*type-specifier-list*](05-types.md#general)

**Semantics**

A *closure* is an object that encapsulates a function with a given argument
list and return type. The function can then be called through that object by
using the [function-call operator](10-expressions.md#function-call-operator).

Note: The library functions [`class_meth`](http://www.php.net/class_meth), [`fun1](http://www.php.net/fun), [`inst_meth`](http://www.php.net/inst_meth), and [`meth_caller`](http://www.php.net/meth_caller) allow a string constant containing the name of
a function to be turned into a closure.

**Examples**

```Hack
private (function (): void) $prop;
public function setProcess1((function (int): (int, int)) $val): void { … }
public function getProcess2(): (function (): ?array<int>) { … }
// -----------------------------------------
function doit(int $iValue, (function (int): int) $process): int {
  return $process($iValue);
}
$result = doit(5, function (int $p) { return $p * 2; });    // doubles 5
$result = doit(5, function (int $p) { return $p * $p; });   // squares 5
```

## Resource Types

A [*resource*](http://docs.hhvm.com/manual/en/language.types.resource.php)
is a descriptor to some sort of external entity. (Examples include
files, databases, and sockets.)

A resource is an abstract entity whose representation is unspecified.
Resources are only created or consumed by the implementation; they are
never created or consumed by Hack code.

Each distinct resource has a unique ID of some unspecified form.

When scripts execute in a mode having a command-line interface, the
following predefined resource-like constants that correspond to file streams
are automatically opened at program start-up:

-   STDIN, which maps to standard input (php://stdin)
-   STDOUT, which maps to standard output (php://stdout)
-   STDERR, which maps to standard error (php://stderr)

These constants have some unspecified type, which behaves like a subtype of
type `resource`.

The library function [`is_resource`](http://www.php.net/is_resource) indicates if a given value is a
resource, and the library function
[`get_resource_type`](http://docs.hhvm.com/manual/en/function.get-resource-type.php)
(§xx) indicates the type of a resource.

## Nullable Types

**Syntax**
<pre>
  <i>nullable-type-specifier:</i>
  ? <i>type-specifier</i>
  mixed
</pre>

**Defined elsewhere**

* [*type-specifier*](05-types.md#general)

**Constraints**

*type-specifier* must not be `void` or `mixed`.

**Semantics**
Except for the type `mixed`, a *nullable* type can represent all of the values
of its underlying type, plus an additional value, `null`. In such cases, a
nullable type is written *?T*, where *T* is the underlying type. For example, a
variable of type `?bool` can contain the values `true`, `false`, or `null`.

A variable of type `mixed` can represent the values of any other type, including any nullable type, which makes mixed a nullable type. (As such,
there is no type `?mixed`.)

See the discussion of [type side effects](05-types.md#type-side-effects).

**Examples**
```Hack
private ?bool $pr_nbool;
private mixed $pr_mixed;
private array<?int> $a_nint = array(3, null);   // array of nullable int
private ?Button $pr_nButton;                    // nullable class
private ?MyCollection $pr_nMyCollection;        // nullable interface
private ?(int, ?string, ?(bool, int)) $pr;      // nullable tuple whose
    // second element has type "nullable string", and whose third element
    // has type "nullable tuple of bool and int"
```

## Generic Types
Hack contains a mechanism to define generic (that is, type-less) classes,
interfaces, and traits, and to create type-specific instances of them via
parameters. See [§§](14-generic-types-methods-and-functions.md#generic-types-methods-and-functions).

## The Classname Type

**Syntax**
<pre>
<i>classname-type-specifier:</i>
  classname  <  <i>qualified-name</i>  <i>generic-type-argument-list<sub>opt</sub></i>  >
</pre>

**Defined elsewhere**

* [*qualified-name*](20-namespaces.md#defining-namespaces)

**Constraints**

*qualified-name* must be the name of a class or interface type.

**Semantics**

This type gets around some limitations Hack has that its ancestor, PHP, does not. Specifically, the use of type-name strings as operands to [`new`](10-expressions.md#the-new-operator), [`instanceof`](10-expressions.md#instanceof-operator), and [`::`](10-expressions.md#scope-resolution-operator), is prohibited in Hack. However, equivalent functionality is possible via an instance of this type (which can only be created via `::`).

The value of an expression of the classname type can be converted implicitly or explicitly to type [`string`](08-conversions.md#converting-to-string-type). The classname type is not assignment-compatible with any other type.

The representation of a value having the classname type is unspecified.

**Examples**

```Hack
namespace NS_cn;
class C1 { … }
class C2 {
  public static classname<\NS_cn\C1> $p1 = \NS_cn\C1::class;
  public static function f(?classname<C1> $p) : classname<C1> { … }
  public static array<classname<C1>> $p2 = array(C1::class);
}
```

## Type Aliases

**Syntax**
<pre>
<i>alias-declaration:</i>
  <i>attribute-specification<sub>opt</sub>  type  <i>name</i>  <i>generic-type-parameter-list</i><sub>opt</sub>  =  <i>type-specifier</i>  ;
  <i>attribute-specification<sub>opt</sub>  newtype  <i>name</i>  <i>generic-type-parameter-list</i><sub>opt</sub>  <i>type-constraint<sub>opt</sub></i>  =  <i>type-specifier</i>  ;
</pre>

**Defined elsewhere**

* [*attribute-specification*](21-attributes.md#attribute-specification)
* [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*name*](09-lexical-structure.md#names)
* [*type-constraint*](05-types.md#general)
* [*type-specifier*](05-types.md#general)

**Constraints**

The *type-specifier* in the optional *type-constraint* must be a subtype 
of the *type-specifier* to the right of the equals.

**Semantics**

An *alias-declaration* creates an alias *name* for the specified type.
Once such a type alias has been defined, that alias can
be used in any context in which a *type-specifier* is permitted.

Any given type can have multiple aliases, and a type alias can itself have
aliases.

An alias created using `type` is a *transparent type alias*. For a given type,
that type and all transparent aliases to that type are all the same type, and
can be freely interchanged. There are no restrictions on where a transparent
type alias can be defined or which source code can access its underlying
implementation.

An alias created using `newtype` is an *opaque type alias*. In the absence of
a *type-constraint*, each opaque alias type is distinct from its
underlying type and from any other types aliasing it or its underlying type. 
Only source code in the file that contains the definition of the opaque type 
alias is allowed access to the underlying implementation. As such, opaque type 
aliasing is an abstraction mechanism. Consider the following file, which 
contains an opaque alias definition:

```Hack
newtype Point = (int, int);

function create_point(int $x, int $y): Point {
  return tuple($x, $y);
}

function distance(Point $p1, Point $p2): float {
  $dx = $p1[0] - $p2[0];
  $dy = $p1[1] - $p2[1];
  return sqrt($dx*$dx + $dy*$dy);
}
```

Being in the same file as the alias definition, the functions `create_point`
and distance have direct access to the integer fields in any `Point`'s tuple.
However, any file that includes this file does not.

Similarly, if a file defines the following alias:

`newtype Widget = int;`

any file that includes this file has no knowledge that a `Widget` is really an
integer, so that the including file cannot perform any integer-like operations
on a `Widget`.

The presence of a *type-constraint* allows an opaque type alias to be treated
as if it had the type specified by *type-specifier* in *type-constraint*, which removes some
of the alias' opaqueness. Note: Although the presence of a constraint allows
the alias type to be converted implicitly to that constraint type, there is no
conversion in the opposite direction.

**Examples**

```Hack
type Counter = int;
newtype NameList = array<string>;
// -----------------------------------------
class Fullname {
  private string $firstName = '';
  private string $lastName = '';
}
type Name = Fullname;
class C1 {
  private ?Name $pr = null;
  public static function fa(Name $p1, array<Name> $p2): void {}
}
// -----------------------------------------
type Complex = shape('real' => float, 'imag' => float);
type PropList = (int, string, int);
newtype Matrix<T> = Vector<Vector<T>>;
type Serialized<T> = string;    // T is not used
```

## Supertypes and Subtypes

The set of built-in and user-defined types in Hack can be represented as a
directed graph in which each vertex designates a distinct type. Each directed
edge connects one vertex with another, with the starting vertex of an edge
being a *supertype* of the *subtype* designated by the ending vertex of that edge.

A supertype can have one or more subtypes, and a subtype can have one or more
supertypes. A supertype can be a subtype of some other supertype, and a
subtype can be a supertype of some other subtype. If T1 is a supertype of T2,
and T2 is, in turn, a supertype of T3, then T1 is a supertype of T3, and T3 is
a subtype of T1.

The relationship between a supertype and any of its subtypes involves the
notion of substitutability. Specifically, if T2 is a subtype of T1, program
elements designed to operate on T1 can also operate on T2.

For types in Hack, the following rules apply:

1.  The source vertex of the graph is the type `mixed`; as such, every type is a subtype of that type.
2.  Any type is a subtype of itself.
3.  `int` and `float` are subtypes of `num`.
4.  `int` and `string` are subtypes of `arraykey`.
5.  For each type T, T is a subtype of the nullable type ?T.
6.  For each type T, the null type is a subtype of all nullable types ?T.
7.  string is a subtype of `Stringish`.
8.  The predefined types `Vector`, `ImmVector`, `Map`, `ImmMap`, `Set`, `ImmSet`, and `Pair` and all array types are subtypes of `Container`, `KeyedTraversable`, and `Traversable`.
9.  The predefined types `Vector`, `ImmVector`, `Map`, `ImmMap`, and `Pair` and all array types are subtypes of `KeyedContainer`.
10. If A is an alias for a type T created using type, then A is a subtype of T, and T is a subtype of A.
11. If A is an alias for a type T created using `newtype`, inside the file containing the `newtype` definition, A is a subtype of T, and T is a subtype of A. Outside that file, A and T have no relationship, except that given `newtype` A as C = T, outside the file with the `newtype` definition, A is a subtype of C.
12. Any class, interface, or trait having a public instance method `__toString` taking no arguments and returning string, is a subtype of `Stringish`.
13. A class type is a subtype of all its direct and indirect base-class types, including those resulting from [*require-extends-clauses*](17-interfaces.md#interface-members).
14. A class type is a subtype of all the interfaces it and its direct and indirect base-class types implement, including those resulting from [*require-implements-clauses*](18-traits.md#trait-members).
15. An interface type is a subtype of all its direct and indirect base interfaces.
16. A shape type *S2* whose field set is a superset of that in shape type *S1*, is a subtype of *S1*.
17. Although this specification doesn’t treat the *return-type* [`noreturn`](15-functions.md#function-definitions) as a type, per se, `noreturn` is regarded as a subtype of all other types, and a supertype of none.

## Type Side Effects

As stated in [§§](05-types.md#supertypes-and-subtypes), a supertype has one or more subtypes, and while any
operation permitted on a value of some supertype is also permitted on a value
of any of its subtypes, the reverse is not true. For example, the type `num`
is a supertype of `int` and `float`, and while addition and subtraction are
well defined for all three types, bit shifting requires integer operands. As
such, a `num` cannot be bit-shifted directly. (Similar situations occur with
`arraykey` and its subtypes `int` and `string`, with nullable types and their subtypes, and with `mixed` and its subtypes.)

Certain program elements are capable of changing the type of an expression
using what is called a *type side effect* (which is not to be confused with a
[*value side effect*](10-expressions.md#general).

Consider the following function:

```Hack
function F_n_int(?int $p1): void {
  $x = $p1 % 3;         // rejected; % not defined for ?int
  if (is_int($p1)) {    // type side effect occurs; $p1 has type int
    $x = $p1 % 3;       // accepted; % defined for int
  }
```

On entry, `$p1` contains `null` or some `int`. However, the type of the
expression `$p1` is not known to be `int`, so it is not safe to allow the `%`
operator to be applied. When the library function `is_int` is applied to `$p1`
, a type side effect occurs in which the type of the expression `$p1` is changed to `int` **for the true path of the `if` statement only**. As such,
the `%` operator can be applied. However, once execution flows out of the `if`
statement, the type of the expression `$p1` is `?int`.

Consider the following code:

```Hack
  if (is_null($p1)) {   // type side effect occurs; $p1 has type null
    $x = $p1 % 3;         // rejected; % not defined for null
  } else {              // type side effect occurs; $p1 has type int
    $x = $p1 % 3;         // accepted; % defined for int
  }
```

The first assignment is rejected, not because we don’t know `$p1`'s type, but
because we know its type is not `int`. See how an opposite type side effect
occurs with the `else`.

Similarly, we can write the following:

```Hack
  if (!is_null($p1)) {// type side effect occurs; $p1 has type int
    $x = $p1 % 3;   // accepted; % defined for int
  }

  if ($p1 !== null) {   // type side effect occurs; $p1 has type int
    $x = $p1 % 3;   // accepted; % defined for int
  }
}
```

Consider the following example that contains non-trivial selection criteria:

```Hack
function F_n_num(?num $p1): void {
  if (is_int($p1) || is_float($p1)) {
    $x = $p1**2;    // rejected
  }
  …
}
```

An implementation is **not** required to produce the correct type side effect when
using multiple criteria directly.

The following example shows type side effects in the context of a nullable
class type that involves inheritance:

```Hack
function F_Button(Button $p1): void {}
function F_CustomButton(CustomButton $p1): void {}
function F_n_class_hier(?Button $p1): void {
  if (!is_null($p1)) {      // type side effect occurs; $p1 has type Button
    F_Button($p1);          // call permitted; argument has type Button
    F_CustomButton($p1);    // call rejected; not necessarily a CustomButton
    if ($p1 instanceof CustomButton) {  // type side effect occurs
      F_CustomButton($p1);  // call permitted; argument has type CustomButton
    }
  }
}
```

The following constructs involve type side effects:

* When used as the controlling expression in an `if`, `while`, or `for`statement, the operators [`==`, `!=`, `===`, and `!==`](10-expressions.md#equality-operators) when used with one operand of `null`, [`instanceof`](10-expressions.md#instanceof-operator), and [simple assignment `=`](10-expressions.md#simple-assignment). [Note that if `$x` is an expression of some nullable type, the logical test `if ($x)` is equivalent to `if ($x !== null)`.]
* The operators `&&`, `||`, and `?:`.
* The intrinsic [`invariant`](10-expressions.md#invariant).
* The library functions `is_array`, `is_bool`, `is_float`, `is_int`, `is_null`, `is_resource`, and `is_string`.

Thus far, all the examples use the value of an expression that designates a
parameter (which is a local variable). Consider the following case, which
involves a property instead:

```Hack
class C {
  private ?int $p1 = 8;     // holds an int, but type is ?int
  public function m(): void {
    if (is_int($this->p1)) {    // type side effect occurs; $this->p1 is int
      $x = $this->p1 << 2;      // allowed; type is int
      $this->n();           // could involve a type side effect on $p1
      $x = $this->p1 << 2;      // disallowed; might no longer be int
    }
  }
  public function n(): void { … }
}
```

Inside the true path of the `if` statement, even though we know that
`$this->p1` is an `int` to begin with, once any method in this class is
called, the implementation must assume that method could have caused a type side
effect on anything currently in scope. As a result, the second attempt to left
shift is rejected.

## Type Inferencing

While certain kinds of variables must have their type declared explicitly, others can have their type inferred by having the implementation perform static analysis of the context in which those variables are used. Specifically,
* Types **must be declared** for [properties](16-classes.md#properties) and for the parameters and the return type of a [named  function](15-functions.md#function-definitions).
* Types **must be inferred** for [local variables](07-variables.md#local-variables), which includes [function statics](07-variables.md#function-statics) and parameters.
* Types **can be declared or inferred** for [constants](16-classes.md#constants) and for the parameters and return type of an [unnamed function](15-functions.md#anonymous-functions).

The process of type inferencing does not cross function boundaries.

Here's an example involving a local variable:

```Hack
function f(): void {
  $v = 'acb';       // $v has type string
  …
  $v = true;        // $v has type bool
  …
  $v = array('red' => 10; 'green' => 15); // $v has type map-like array of int
  …
  $v = new C();     // $v has type C
}
```

For each assignment, the type of `$v` is inferred from the type of the
expression on the right-hand side, as shown in the comments. The type of
function statics is inferred in the same manner, as are function parameters.

For example:

```Hack
function g(int $p1 = -1): void
{
  // on entry to the function, $p1 has the declared type int
  …
  $p1 = 23.56;      // $p1 has type float
  …
}
```

As a parameter, `$p1` is required to have a declared type, in this case,
`int`. However, when used as an expression, `$p1`'s type can change, as shown.

In the case of a class constant, if the type is omitted, it is inferred from
the initializer:

```Hack
class C {
  const C1 = 10;            // type int inferred from initializer
  const string C2 = "red";  // type string declared
}
```

Let's consider types in anonymous functions:

```Hack
$doubler = (function ($p) { return $p * 2; });
$doubler(3);
$doubler(4.2);
```

The type of the parameter `$p` and the function's return type have been
omitted. These types are inferred each time the anonymous function is called
through the variable `$doubler`. When `3` is passed, as that has type `int`,
that is inferred as the type of `$p`. The literal `2` also has type `int`, so
the type of the value returned is the type of `$p * 2`, which is `int`, and
that becomes the function's return type. When `4.2` is passed, as that has
type `float`, that is inferred as the type of `$p`. The literal `2` has type
`int`, so the type of the value returned is the type of `$p * 2`, which is
`float`, and that becomes the function's return type.

Consider the following, subtly different, version (note the literal 2.0
instead of 2):

`$doubler = (function ($p) { return $p * 2.0; });`

Whether an `int` or `float` value is passed, it matters not, as when either is multiplied by a `float`, the result is `float`, so that becomes the function's return type.

We can add partial explicit type information; the following all result in the same behavior:

```Hack
$doubler = (function (int $p) { return $p * 2; });
$doubler = (function ($p = 0) { return $p * 2; });
$doubler = (function ($p): int { return $p * 2; });
```

In the first case, as `$p` has the declared type `int`, and `int * int` gives
`int`, the return type is inferred as `int`. In the second case, as the
default value `0` has type `int`, `$p` is inferred to also have that type, and
`int * int` gives `int`, so the return type is inferred as `int`. In the third
case, as the return type is declared as `int`, and `$p * 2` must have that
type, the type of `$p` is inferred as `int`, so that must also be the type of
the parameter.

While all three of these cases allow a call such as `$doubler(3)`, none of
them allows a call such as `$doubler(4.2)`. So, the fact that type information
can be provided explicitly in these cases doesn’t mean it's necessarily a good idea to do so.

Other considerations apply to type inferencing in the context of [generic types](14-generic-types-methods-and-functions.md#type-inferencing-revisited).


================================================
FILE: spec/06-constants.md
================================================
# Constants

## General

A *constant* is a [named](09-lexical-structure.md#names) value. Once defined, the value
of the constant can not be changed.

A constant can be defined in one of two ways: as a *c-constant* using a [*const-declaration*](16-classes.md#constants) or via a [string literal](09-lexical-structure.md#string-literals), or as a *d-constant* by calling the library function [`define`](http://www.php.net/define). However, the two approaches differ slightly. Specifically:

-   The name of a c-constant must comply with the lexical grammar for a
    name while that for a d-constant can contain any source character.
-   The name of a c-constant is case-insensitive while that for a
    d-constant can be case-sensitive or case-insensitive based on the
    value of the third argument passed to `define`.
-   If `define` is able to define the given name, it returns `true`;
    otherwise, it returns `false`.

The library function [`defined`](http://www.php.net/defined) reports if a given name (specified as a string) is defined as a constant. The library function [`constant`](http://www.php.net/constant) returns the value of a given constant whose name is specified as a string.

**Examples**

```Hack
class C {
  const float MAX_HEIGHT = 10.5;            // define two (case-insensitive) c-constants
  const float UPPER_LIMIT = MAX_HEIGHT;
}
define('COEFFICIENT_1', 2.345, true); // define a case-insensitive d-constant
define('FAILURE', true, false);       // define a case-sensitive d-constant
```

## Context-Dependent Constants

The following constants—sometimes referred to as *magic constants*—are
automatically available to all scripts; their values are not fixed:

 Constant Name                    | Description                     
 -----------------                | ---------                            
 `__CLASS__`                        | `string`; The name of the current class. From within a trait method, the name of the class in which that trait is used. If the current namespace is other than the default, the namespace name and "\\" are prepended, in that order. If used outside all classes, the value is the empty string. 
`__DIR__`                            | `string`; The directory name of the script. A directory separator is only appended for the root directory.
`__FILE__`                           | `string`; The full name of the script.
`__FUNCTION__`                       | `string`; Inside a function, the name of the current function exactly as it was declared, with the following prepended: If a named namespace exists, that namespace name followed by "\". If used outside all functions, the result is the empty string. For a method, no parent-class prefix is present. (See `__METHOD__` and [anonymous functions](15-functions.md#anonymous-functions).)
`__LINE__`                           | `int`; the number of the current source line
`__METHOD__`                         | `string`; Inside a method, the name of the current method exactly as it was declared, with the following prepended, in order: If a named namespace exists, that namespace name followed by "\"; the parent class name or trait name followed by `::`. If used outside all methods, the result is the same as for `__FUNCTION__`.
`__NAMESPACE__`                      | `string`; The name of the current namespace exactly as it was declared. For the default namespace, the result is the empty string.
`__TRAIT__`                          | `string`; The name of the current trait. From within a trait method, the name of the current trait. If used outside all traits, the result is the empty string.

Constant names beginning with __ are reserved for future use by the Engine.

## Core Predefined Constants

The following constants are automatically available to all scripts:

Constant Name | Description
-------------   | -----------  
`E_ALL` | `int`; All errors and warnings, as supported.
`E_COMPILE_ERROR` | `int`; Fatal compile-time errors. This is like an `E_ERROR`, except that `E_COMPILE_ERROR` is generated by the scripting engine.
`E_COMPILE_WARNING` | `int`; Compile-time warnings (non-fatal errors). This is like an `E_WARNING`, except that `E_COMPILE_WARNING` is generated by the scripting engine.
`E_CORE_ERROR` | `int`; Fatal errors that occur during Hack's initial start-up. This is like an `E_ERROR`, except that `E_CORE_ERROR` is generated by the core of Hack.
`E_CORE_WARNING` | `int`; Warnings (non-fatal errors) that occur during Hack's initial start-up. This is like an `E_WARNING`, except that `E_CORE_WARNING` is generated by the core of Hack.
`E_DEPRECATED` | `int`; Deprecation notices. Enable this to receive warnings about code that will not work in future versions.
`E_ERROR` | `int`; Fatal run-time errors. These indicate errors that cannot be recovered from, such as a memory allocation problem. Execution of the script is halted.
`E_NOTICE` | `int`; Run-time notices. Indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script.
`E_PARSE` | `int`; Compile-time parse errors.
`E_RECOVERABLE_ERROR` | `int`; Catchable fatal error. It indicates that a probably dangerous error occurred, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handler (see the library function [`set_error_handler`](http://www.php.net/set_error_handler)), the application aborts as it was an `E_ERROR`.
`E_STRICT` | `int`; Have Hack suggest changes to the source code to ensure the best interoperability.
`E_USER_DEPRECATED` | `int`; User-generated error message. This is like an `E_DEPRECATED`, except that `E_USER_DEPRECATED` is generated in Hack code by using the library function [`trigger_error`](http://www.php.net/trigger_error).
`E_USER_ERROR` | `int`; User-generated error message. This is like an `E_ERROR`, except that `E_USER_ERROR` is generated in Hack code by using the library function [`trigger_error`](http://www.php.net/trigger_error).
`E_USER_NOTICE` | `int`; User-generated warning message. This is like an `E_NOTICE`, except that `E_USER_NOTICE` is generated in Hack code by using the library function [`trigger_error`](http://www.php.net/trigger_error).
`E_USER_WARNING` | `int`; User-generated warning message. This is like an `E_WARNING`, except that  `E_USER_WARNING` is generated in Hack code by using the library function [`trigger_error`](http://www.php.net/trigger_error).
`E_WARNING` | `int`; Run-time warnings (non-fatal errors). Execution of the script is not halted.
`E_USER_DEPRECATED` | `int`; User-generated warning message. This is like an `E_DEPRECATED`, except that  `E_USER_DEPRECATED` is generated in Hack code by using the library function [`trigger_error`](http://www.php.net/trigger_error).
`INF` | `float`; Infinity
`M_E` | `float`; e
`M_PI` | `float`; Pi
`NAN` | `float`; Not-a-Number
`PHP_EOL` | `string`; the end-of-line terminator for this platform.
`PHP_INT_MAX` | `int`; the maximum representable value for an integer.
`PHP_INT_MIN` | `int`; the minimum representable value for an integer. 
`PHP_INT_SIZE` | `int`; the number of bytes used to represent an integer.

The members of the `E_*` family have values that are powers of 2, so
they can be combined meaningfully using bitwise operators.

## User-Defined Constants

A constant may be defined inside a [class](16-classes.md#constants) or inside an [interface](17-interfaces.md#constants).





================================================
FILE: spec/07-variables.md
================================================
# Variables

## General

A *variable* is a named area of data storage that has a type and a
value. A variable is represented by a 
[VSlot](04-basic-concepts.md#general). A variable is created by [assigning a value to it](10-expressions.md#simple-assignment). A variable that somehow becomes defined, but is not initialized starts out with the value `null`.

Variables have [names](09-lexical-structure.md#names). Distinct variables may have
the same name provided they are in different [scopes](04-basic-concepts.md#scope).

A [constant](06-constants.md#general) is a variable that, once initialized, its value cannot
be changed. 

Based on the context in which it is declared, a variable has a 
[scope](04-basic-concepts.md#scope) and a [storage duration](04-basic-concepts.md#storage-duration).

The following kinds of variable may exist in a script:

-   [Local variable](07-variables.md#local-variables)
-   [Array element](07-variables.md#array-elements)
-   [Function static](07-variables.md#function-statics)
-   [Instance property](07-variables.md#instance-properties)
-   [Static property](07-variables.md#static-properties)
-   [Class and interface constant](07-variables.md#class-and-interface-constants)

## Kinds of Variables

### Local Variables

**Syntax**

See Semantics below.

**Semantics**

Except for a [function parameter](15-functions.md#general), a local variable is never defined explicitly; instead, it is created when it is first assigned a value. A local variable can be assigned to as a parameter in the parameter list of a [function definition](15-functions.md#function-definitions) or inside any [compound statement](11-statements.md#compound-statements). It has [function scope](04-basic-concepts.md#scope) and [automatic storage duration](04-basic-concepts.md#storage-duration). A local variable is a modifiable lvalue.

**Examples**

```Hack
function doit(bool $p1): void {  // assigned the value true when called
  $count = 10;
    ...
  if ($p1)
  {
    $message = "Can't open master file.";
    ...
  }
  ...
}
doit(true);
// -----------------------------------------
function f(): void
{
  $lv = 1;
  echo "\$lv = $lv\n";
  ++$lv;
}
for ($i = 1; $i <= 3; ++$i)
  f();
```

Unlike the [function static equivalent](07-variables.md#function-statics), function `f` outputs
"`$lv = 1`" each time.

See the [recursive function example](04-basic-concepts.md#storage-duration).

### Array Elements

**Syntax**

[Arrays](05-types.md#array-types) are created via the [array-creation operator](10-expressions.md#array-creation-operator) or
the intrinsic [`array`](10-expressions.md#array). At the same time, one or more elements
may be created for that array. New elements are inserted into an
existing array via the [simple-assignment operator](10-expressions.md#simple-assignment) in
conjunction with the [subscript operator `[]`](10-expressions.md#subscript-operator).

**Semantics**

The [scope](04-basic-concepts.md#scope) of an array element is the same as the scope of that
array's name. An array element has [allocated storage duration](04-basic-concepts.md#storage-duration).

**Examples**

```Hack
$colors = ["red", "white", "blue"]; // create array with 3 elements
$colors[] = "green";                // insert a new element
```

### Function Statics

**Syntax:**

<pre>
  <i>function-static-declaration:</i>
    static <i>static-declarator-list</i>  ;
  <i>static-declarator-list:</i>
    <i>static-declarator</i>  
    <i>static-declarator-list</i>  ,  <i>static-declarator</i> 
  <i>static-declarator:</i> 
    <i>variable-name</i>  <i>function-static-initializer<sub>opt</sub></i>
  <i>function-static-initializer:</i>
    = <i>const-expression</i>
</pre>

**Defined elsewhere**

* [*variable-name*](09-lexical-structure.md#names)
* [*constant-expression*](10-expressions.md#constant-expressions)

**Semantics**

A function static may be defined inside any [compound statement](11-statements.md#compound-statements).
It is a modifiable lvalue.

A function static has [function scope](04-basic-concepts.md#scope) and 
[static storage duration](04-basic-concepts.md#storage-duration).

The value of a function static is retained across calls to its parent
function. Each time the function containing a function static
declaration is called, that execution is dealing with an [alias](04-basic-concepts.md#general)
to that static variable. The next time that function
is called, a new alias is created.

**Examples**

```Hack
function f(): void {
  static $fs = 1;
  echo "\$fs = $fs\n";
  ++$fs;
}
for ($i = 1; $i <= 3; ++$i)
  f();
```

Unlike the [local variable equivalent](07-variables.md#local-variables), function `f` outputs "`$fs
= 1`", "`$fs = 2`", and "`$fs = 3`", as `$fs` retains its value across
calls.

### Instance Properties

These are described in [class instance properties section](16-classes.md#properties). They have [class scope](04-basic-concepts.md#scope) and [allocated storage duration](04-basic-concepts.md#storage-duration).

### Static Properties

These are described in [class static properties section](16-classes.md#properties). They have [class scope](04-basic-concepts.md#scope) and [static storage duration](04-basic-concepts.md#storage-duration).

### Class and Interface Constants

These are described in [class constants section](16-classes.md#constants) and [interface constants section](17-interfaces.md#constants). They have [class or interface scope](04-basic-concepts.md#scope) and [static storage duration](04-basic-concepts.md#storage-duration).


================================================
FILE: spec/08-conversions.md
================================================
# Conversions

## General

Some operators implicitly convert automatically the values of operands
from one type to another. Explicit conversion is performed using the
[cast operator](10-expressions.md#cast-operator).

If an expression is converted to its own type, the type and value of the
result are the same as the type and value of the expression.

When an expression of type `num` is converted, if that expression is currently 
an `int`, then `int` conversion rules apply; otherwise, `float` conversion rules apply.

When an expression of type `arraykey` is converted, if that expression is 
currently an `int`, then `int` conversion rules apply; otherwise, `string` 
conversion rules apply.

## Converting to Boolean Type

No non-`bool` type can be converted implicitly to `bool`. All other conversions 
must be explicit.

The [result type](http://docs.hhvm.com/manual/en/language.types.boolean.php#language.types.boolean.casting) is `bool`.

If the source type is `int` or `float`, then if the source value tests equal
to 0, the result value is `false`; otherwise, the result value is `true`.

If the source value is `null`, the result value is `false`.

If the source is an empty string or the string "0", the result value is
`false`; otherwise, the result value is `true`.

If the source is an array with zero elements, the result value is `false`;
otherwise, the result value is `true`.

If the source is an object, the result value is `true`.

If the source is a resource, the result value is `false`.

The library function [`boolval`](http://www.php.net/boolval) allows values to be converted to
`bool`.

## Converting to Integer Type

No non-`int` type can be converted implicitly to `int`. All other conversions must be explicit.

The [result type](http://docs.hhvm.com/manual/en/language.types.integer.php#language.types.integer.casting) is `int`.

If the source type is `bool`, then if the source value is `false`, the
result value is 0; otherwise, the result value is 1.

If the source type is `float`, for the values `INF`, `-INF`, and `NAN`, the
result value is implementation-defined. For all other values, if the
precision can be preserved, the fractional part is rounded towards zero
and the result is well defined; otherwise, the result is undefined.

If the source value is `null`, the result value is 0.

If the source is a [numeric string or leading-numeric string](05-types.md#the-string-type)
having integer format, if the precision can be preserved the result
value is that string's integer value; otherwise, the result is
undefined. If the source is a numeric string or leading-numeric string
having floating-point format, the string's floating-point value is
treated as described above for a conversion from `float`. The trailing
non-numeric characters in leading-numeric strings are ignored.  For any
other string, the result value is 0.

If the source is an array with zero elements, the result value is 0;
otherwise, the result value is 1.

If the source is a resource, the result is the resource's unique ID.

The library function [`intval`](http://docs.hhvm.com/manual/en/function.intval.php) allows values
to be converted to `int`.

## Converting to Floating-Point Type

No non-`float` type can be converted implicitly to `float`. All other 
conversions must be explicit.

The [result type](http://docs.hhvm.com/manual/en/language.types.float.php#language.types.float.casting) is `float`.

If the source type is `int`, if the precision can be preserved the result
value is the closest approximation to the source value; otherwise, the
result is undefined.

If the source is a [numeric string or leading-numeric string](05-types.md#the-string-type)
having integer format, the string's integer value is treated as
described above for a conversion from `int`. If the source is a numeric
string or leading-numeric string having floating-point format, the
result value is the closest approximation to the string's floating-point
value. The trailing non-numeric characters in leading-numeric strings
are ignored. For any other string, the result value is 0.

If the source is an array with zero elements, the result value is 0.0; 
otherwise, the result value is 1.0.

If the source is a resource, the result is the resource's unique ID.

The library function [`floatval`](http://www.php.net/floatval) allows values to be converted to
float.

## Converting to Number Type

The only implicit conversions to type `num` are from the types `int` and
`float`. There is no change in representation during such conversions. There are no explicit conversions.

The result type is `num`.

## Converting to String Type

Except for the [`classname` type](05-types.md#the-classname-type), no non-`string` type can be converted implicitly to `string`. All other conversions must be explicit.

The [result type](http://docs.hhvm.com/manual/en/language.types.string.php#language.types.string.casting) is `string`.

If the source type is `bool`, then if the source value is `false`, the
result value is the empty string; otherwise, the result value is "1".

If the source type is `int` or `float`, then the result value is a string
containing the textual representation of the source value (as specified
by the library function [`sprintf`](http://www.php.net/sprintf).

If the source value is `null`, the result value is an empty string.

If the source is an object, then if that object's class has a
[`__toString` method](16-classes.md#method-__tostring), the result value is the string returned
by that method; otherwise, the conversion is invalid.

If the source is a resource, the result value is an
implementation-defined string.

If the source type is the [`classname` type](05-types.md#the-classname-type), the result value is a string containing the corresponding fully qualified class or interface name without any leading `\`.

The library function [`strval`](http://www.php.net/strval) allows values to be converted to
`string`.

## Converting to Array Key Type

The only implicit conversions to type `arraykey` are from the types `int` 
and `string`. There is no change in representation during such conversions. 
There are no explicit conversions.

The result type is `arraykey`.

## Converting to Array Type

For arrays of different types, no implicit conversions exist. There are no 
explicit conversions.

## Converting to Object Type

An object type can be converted implicitly to any object type from which the first object type is derived directly or indirectly. There are no other implicit or explicit conversions.

## Converting to Interface Type

An object type can be converted implicitly to any interface type that object 
type implements directly or indirectly.

An interface type can be converted implicitly to any interface type from which 
the first interface type is derived directly or indirectly.

There are no other implicit or explicit conversions.

## Converting to Resource Type

The [predefined resource-like constants](05-types.md#resource-types)) `STDIN`, `STDOUT`, and 
`STDERR`, can be converted implicitly to resource. No other non-resource type 
can be so converted. No explicit conversions exist.

## Converting to Mixed Type

Any type can be converted implicitly to [`mixed`](05-types.md#nullable-types). No explicit conversions
exist.


================================================
FILE: spec/09-lexical-structure.md
================================================
# Lexical Structure

## Scripts

A [script](04-basic-concepts.md#program-structure) is an ordered sequence of characters. Typically, a
script has a one-to-one correspondence with a file in a file system, but
this correspondence is not required.

Conceptually, a script is translated using the following steps:

1.  Transformation, which converts a script from a particular character
    repertoire and encoding scheme into a sequence of 8-bit characters.

2.  Lexical analysis, which translates a stream of input characters into
    a stream of tokens. 

3.  Syntactic analysis, which translates the stream of tokens into
    executable code.

Conforming implementations must accept scripts encoded with the UTF-8
encoding form (as defined by the Unicode standard), and transform them
into a sequence of characters. Implementations can choose to accept and
transform additional character encoding schemes.

## Grammars

This specification shows the syntax of the Hack programming language
using two grammars. The *lexical grammar* defines how source
characters are combined to form white space, comments, and tokens. The
*syntactic grammar* defines how the resulting tokens are combined to
form Hack programs.

The grammars are presented using *grammar productions*, with each one
defining a non-terminal symbol and the possible expansions of that
non-terminal symbol into sequences of non-terminal or terminal symbols.
In productions, non-terminal symbols are shown in slanted type *like
this*, and terminal symbols are shown in a fixed-width font `like this`. 

The first line of a grammar production is the name of the non-terminal
symbol being defined, followed by one colon for a syntactic grammar
production, and two colons for a lexical grammar production. Each
successive indented line contains a possible expansion of the
non-terminal given as a sequence of non-terminal or terminal symbols.
For example, the production:

<pre>
  <i>single-line-comment::</i>
    // input-characters<sub>opt</sub>
    #  input-characters<sub>opt</sub>
</pre>

defines the lexical grammar production *single-line-comment* as being
the terminals `//` or `#`, followed by an optional *input-characters*. Each
expansion is listed on a separate line.

Although alternatives are usually listed on separate lines, when there
is a large number, the shorthand phrase “one of” may precede a list of
expansions given on a single line. For example,

<pre>
  <i>hexadecimal-digit:: one of</i>
    0   1   2   3   4   5   6   7   8   9
    a   b   c   d   e   f
    A   B   C   D   E   F
</pre>

## Grammar ambiguities

In general, lexical processing results in the creation of the longest possible
lexical element. However, in certain cases involving generic type specifiers
(and array specifiers, which use generic type notation), this is not the case.
For example, in type specifiers like `X<Y<int>>` and `array<array<int>>`, the
source characters `>` and `>` are treated as two separate tokens rather than
as the right-shift operator `>>`.

## Lexical Analysis

### General

The production *input-file* is the root of the lexical structure for a
script. Each script must conform to this production.

**Syntax**

<pre>
  <i>input-file::</i>
    <i>input-element</i>
    <i>input-file   input-element</i>
  <i>input-element::</i>
    <i>comment</i>
    <i>white-space</i>
    <i>token</i>
</pre>

**Defined elsewhere**

* [*comment*](09-lexical-structure.md#comments)
* [*token*](09-lexical-structure.md#general-1)
* [*white-space*](09-lexical-structure.md#white-space)

**Semantics:**

The basic elements of a script are comments, white space, and tokens.

The lexical processing of a script involves the reduction of that script
into a sequence of [tokens](09-lexical-structure.md#tokens) that becomes the input to the
syntactic analysis. Tokens can be separated by [white space](09-lexical-structure.md#white-space) and
[delimited comments](09-lexical-structure.md#comments).

Apart from the exception noted in [§§](09-lexical-structure.md#grammar-ambiguities), lexical processing always results in the creation of the longest
possible lexical element. (For example, `$a+++++$b` must be parsed as
`$a++ ++ +$b`, which syntactically is invalid.)

### Comments

Two forms of comments are supported: *delimited comments* and
*single-line comments*. 

**Syntax**

<pre>
  <i>comment::</i>
    <i>single-line-comment</i>
    <i>delimited-comment</i>

  <i>single-line-comment::</i>
    //   <i>input-characters<sub>opt</sub></i>
    #    <i>input-characters<sub>opt</sub></i>

  <i>input-characters::</i>
    <i>input-character</i>
    <i>input-characters   input-character</i>

  <i>input-character::</i>
    Any source character except new-line

  <i>new-line::</i>
    Carriage-return character (U+000D)
    Line-feed character (U+000A)
    Carriage-return character (U+000D) followed by line-feed character (U+000A)

  <i>delimited-comment::</i>
    /*   No characters or any source character sequence except /*   */
</pre>

**Semantics**

Except within a string literal or a comment, the characters /\* start a
delimited comment, which ends with the characters \*/. Except within a
string literal or a comment, the characters // or \# start a single-line
comment, which ends with a new line. That new line is not part of the
comment. However, if the single-line comment is the last source element
in an embedded script, the trailing new line can be omitted. (Note: this
allows for uses like `<?hh ... // ... ?>`.)

A delimited comment can occur in any place in a script in which [white
space](09-lexical-structure.md#white-space) can occur. (For example;
`/*...*/$c/*...*/=/*...*/567/*...*/;/*...*/` is parsed as `$c=567;`, and
`$k = $i+++/*...*/++$j;` is parsed as `$k = $i+++ ++$j;`.)

A number of single-line, so-called special comments are recognized by a
conforming implementation; they are:

* [`// FALLTHROUGH`](11-statements.md#the-switch-statement)
* [`// strict`](04-basic-concepts.md#program-structure)

where horizontal white space is permitted between the `//` and the start of
the comment text.

**Implementation Notes**

During tokenizing, an implementation can treat a delimited comment as
though it was white space.

### White Space

White space consists of an arbitrary combination of one or more
new-line, space, and horizontal tab characters.

**Syntax**

<pre>
  <i>white-space::</i>
    <i>white-space-character</i>
    <i>white-space   white-space-character</i>

  <i>white-space-character::</i>
    <i>new-line</i>
    Space character (U+0020)
    Horizontal-tab character (U+0009)
</pre>

**Defined elsewhere**

* [*new-line*](09-lexical-structure.md#comments)

**Semantics**

The space and horizontal tab characters are considered *horizontal
white-space characters*.

### Tokens

#### General

There are several kinds of source tokens:

**Syntax**

<pre>
  <i>token::</i>
    <i>variable-name</i>
    <i>name</i>
    <i>keyword</i>
    <i>literal</i>
    <i>operator-or-punctuator</i>
</pre>

**Defined elsewhere**

* [*keyword*](09-lexical-structure.md#keywords)
* [*literal*](09-lexical-structure.md#general-2)
* [*name*](09-lexical-structure.md#names)
* [*operator-or-punctuator*](09-lexical-structure.md#operators-and-punctuators)
* [*variable-name*](09-lexical-structure.md#names)

#### Names

**Syntax**

<pre>
  <i>variable-name::</i>
    $   <i>name</i>

  <i>name::</i>
    <i>name-nondigit</i>
    <i>name   name-nondigit</i>
    <i>name   digit</i>

  <i>name-nondigit::</i>
    <i>nondigit</i>
    one of the characters U+007f–U+00ff

  <i>nondigit::</i> one of
    _
    a   b   c   d   e   f   g   h   i   j   k   l   m
    n   o   p   q   r   s   t   u   v   w   x   y   z
    A   B   C   D   E   F   G   H   I   J   K   L   M
    N   O   P   Q   R   S   T   U   V   W   X   Y   Z
</pre>

**Defined elsewhere**

* [*digit*](09-lexical-structure.md#integer-literals)

**Semantics:**

Names are used to identify the following: [constants](06-constants.md#general), [variables](07-variables.md#general), [labels](11-statements.md#labeled-statements), [enumerated types](13-enums.md#enum-declarations), [functions](15-functions.md#function-definitions), [classes](16-classes.md#class-declarations), [class members](16-classes.md#class-members), [interfaces](17-interfaces.md#interface-declarations), [traits](18-traits.md#general), [type aliases](05-types.md#type-aliases), [namespaces](20-namespaces.md#general),
names in [heredoc comments](09-lexical-structure.md#heredoc-string-literals) and [nowdoc comments](09-lexical-structure.md#nowdoc-string-literals); and [attributes](21-attributes.md#attributes).

A *name* begins with an underscore (_), *name-nondigit*, or extended
name character in the range U+007f–U+00ff. Subsequent characters can
also include *digit*s. A *variable name* is a name with a leading
dollar ($).

The name `$_`, referred to as the *placeholder variable*, is reserved for use in the ([`list` intrinsic](§10-expressions.md#list)) and the ([`foreach` statement](§11-statements.md#The-foreach-Statement)). This name does not actually designate any storage; instead, it’s an indication that the value that would otherwise be stored in a variable in that context, is ignored.

Unless stated otherwise ([§§](14-generic-types-methods-and-functions.md#type-parameters), [§§](15-functions.md#function-calls), [§§](16-classes.md#class-declarations), [§§](18-traits.md#trait-members)),
names are case-sensitive, and every character in a name is significant.

Function and method names beginning with two underscores (__) are
reserved by the Hack language.

**Examples**

```Hack
const int MAX_VALUE = 100;
public function getData(): array<string> { ... }
class Point { ... }
interface ICollection { ... }
```

**Implementation Notes**

An implementation is discouraged from placing arbitrary restrictions on
name length or length of significance.

#### Keywords

A *keyword* is a name-like sequence of characters that is reserved, and
cannot be used as a name.

**Syntax**

<pre>
  <i>keyword::</i> one of
    abstract   arraykey   as   async   await   break   case   catch   class   classname   clone   const   continue   default   do
    echo   else   elseif   enum   extends   final   finally   for   foreach   function   if   implements
    instanceof   insteadof   interface   mixed   namespace   new   newtype   noreturn   num   parent   private
    protected   public   require   require_once   return   self   shape   static   switch   throw   trait   try
    tuple   type   use   while   yield
</pre>

**Semantics**

Keywords are case-sensitive.

Note: Strictly speaking, `false`, `null`, and `true` are not keywords;
however, they do have predefined meanings, and can be thought of as keywords.
Likewise for the names of the [intrinsics](10-expressions.md#general-2).

#### Literals

##### General

The source code representation of a value is called a *literal*.

**Syntax**

<pre>
  <i>literal::
    <i>boolean-literal</i>
    <i>integer-literal</i>
    <i>floating-literal</i>
    <i>string-literal</i>
    <i>null-literal</i>
</pre>

**Defined elsewhere**

* [*boolean-literal*](09-lexical-structure.md#boolean-literals)
* [*floating-literal*](09-lexical-structure.md#floating-point-literals)
* [*integer-literal*](09-lexical-structure.md#integer-literals)
* [*null-literal*](09-lexical-structure.md#the-null-literal)
* [*string-literal*](09-lexical-structure.md#string-literals)

##### Boolean Literals

**Syntax**

<pre>
  <i>boolean-literal::</i>
    true
    false
</pre>

**Semantics**

The type of a *boolean-literal* is bool. The values `true` and `false`
represent the Boolean values True and False, respectively.

**Examples**

```Hack
$done = false;
computeValues($table, true);
```

##### Integer Literals

**Syntax**

<pre>
  <i>integer-literal::</i>
    <i>decimal-literal</i>
    <i>octal-literal</i>
    <i>hexadecimal-literal</i>
    <i>binary-literal</i>

    <i>decimal-literal::</i>
      <i>nonzero-digit</i>
      <i>decimal-literal   digit</i>

    <i>octal-literal::</i>
      0
      <i>octal-literal   octal-digit</i>

    <i>hexadecimal-literal::</i>
      <i>hexadecimal-prefix   hexadecimal-digit</i>
      <i>hexadecimal-literal   hexadecimal-digit</i>

    <i>hexadecimal-prefix:: one of</i>
      0x  0X

    <i>binary-literal::</i>
      <i>binary-prefix   binary-digit</i>
      <i>binary-literal   binary-digit</i>

    <i>binary-prefix:: one of</i>
      0b  0B

    <i>digit:: one of</i>
      0  1  2  3  4  5  6  7  8  9

    <i>nonzero-digit:: one of</i>
      1  2  3  4  5  6  7  8  9

    <i>octal-digit:: one of</i>
      0  1  2  3  4  5  6  7

    <i>hexadecimal-digit:: one of</i>
      0  1  2  3  4  5  6  7  8  9
            a  b  c  d  e  f
            A  B  C  D  E  F

    <i>binary-digit:: one of</i>
        0  1
</pre>

**Constraints**

The value of an integer literal must be representable by its type.

**Semantics**

The value of a decimal integer literal is computed using base 10; that
of an octal integer literal, base 8; that of a hexadecimal integer
literal, base 16; and that of a binary integer literal, base 2.

The type of an *integer-literal* is `int`.

Using a twos-complement system, can the smallest negative value
(-9223372036854775808 for 64 bits) be
represented as a decimal integer literal? No. Consider the
expression -5. This is made up of two tokens: a unary minus followed by
the integer literal 5. As such, **there is no such thing as a
negative-valued decimal integer literal in Hack**. Instead, there is the
non-negative value, which is then negated. Literals written using hexadecimal, octal, or binary
notations are considered to have non-negative values.

**Examples**

```Hack
$count = 10      // decimal 10

0b101010 >> 4    // binary 101010 and decimal 4

0XAF << 023      // hexadecimal AF and octal 23
```

##### Floating-Point Literals

**Syntax**

<pre>
  <i>floating-literal::</i>
    <i>fractional-literal   exponent-part<sub>opt</sub></i>
    <i>digit-sequence   exponent-part</i>

  <i>fractional-literal::</i>
    <i>digit-sequence<sub>opt</sub></i> . <i>digit-sequence</i>
    <i>digit-sequence</i> .

  <i>exponent-part::</i>
    e  <i>sign<sub>opt</sub>   digit-sequence</i>
    E  <i>sign<sub>opt</sub>   digit-sequence</i>

  <i>sign:: one of</i>
    +  -

  <i>digit-sequence::</i>
    <i>digit</i>
    <i>digit-sequence   digit</i>
</pre>

**Defined elsewhere**

* [*digit*](09-lexical-structure.md#integer-literals)

**Constraints**

The value of a floating-point literal must be representable by its type.

**Semantics**

The type of a *floating-literal* is `float`.

The constants [`INF`](06-constants.md#core-predefined-constants) and [`NAN`](06-constants.md#core-predefined-constants) provide access to the floating-
point values for infinity and Not-a-Number, respectively.

**Examples**

```Hack
$values = array(1.23, 3e12, 543.678E-23);
```

##### String Literals

**Syntax**

<pre>
  <i>string-literal::</i>
    <i>single-quoted-string-literal</i>
    <i>double-quoted-string-literal</i>
    <i>heredoc-string-literal</i>
    <i>nowdoc-string-literal</i>
</pre>

**Defined elsewhere**

* [*double-quoted-string-literal*](09-lexical-structure.md#double-quoted-string-literals)
* [*heredoc-string-literal*](09-lexical-structure.md#heredoc-string-literals)
* [*nowdoc-string-literal*](09-lexical-structure.md#nowdoc-string-literals)
* [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals)

Note: By conventional standards, calling [*heredoc-string-literal*s](#heredoc-string-literals)
and [*nowdoc-string-literal*s](#nowdoc-string-literals)) literals is a stretch, as
each is hardly a single token. And given the variable substitution permitted in *double-quote-string-literals*, they are not really literals either.

**Semantics**

A string literal is a sequence of zero or more characters delimited in
some fashion. The delimiters are not part of the literal's content.

The type of a string literal is `string`.

###### Single-Quoted String Literals

**Syntax**

<pre>
  <i>single-quoted-string-literal::</i>
    ' <i>sq-char-sequence<sub>opt</sub></i>  '

  <i>sq-char-sequence::</i>
    <i>sq-char</i>
    <i>sq-char-sequence   sq-char</i>

  <i>sq-char::</i>
    <i>sq-escape-sequence</i>
    \<i><sub>opt</sub></i>   any member of the source character set except single-quote (') or backslash (\)

  <i>sq-escape-sequence:: one of</i>
    \'  \\
</pre>

**Semantics**

A single-quoted string literal is a string literal delimited by
single-quotes ('). The literal can contain any source character except
single-quote (') and backslash (\\), which can only be represented by
their corresponding escape sequence.

A single-quoted string literal is a [c-constant](06-constants.md#general).

**Examples**

```Hack
'This text is taken verbatim'

'Can embed a single quote (\') and a backslash (\\) like this'
```

###### Double-Quoted String Literals

**Syntax**

<pre>
  <i>double-quoted-string-literal::</i>
    " <i>dq-char-sequence<sub>opt</sub></i>  "

  <i>dq-char-sequence::</i>
    <i>dq-char</i>
    <i>dq-char-sequence   dq-char</i>

  <i>dq-char::</i>
    <i>dq-escape-sequence</i>
    any member of the source character set except double-quote (") or backslash (\)
    \  any member of the source character set except "\$efnrtvxX or octal-digit

  <i>dq-escape-sequence::</i>
    <i>dq-simple-escape-sequence</i>
    <i>dq-octal-escape-sequence</i>
    <i>dq-hexadecimal-escape-sequence</i>
    <i>dq-unicode-escape-sequence</i>

  <i>dq-simple-escape-sequence:: one of</i>
    \"   \\   \$   \e   \f   \n   \r   \t   \v

  <i>dq-octal-escape-sequence::</i>
    \   <i>octal-digit</i>
    \   <i>octal-digit   octal-digit</i>
    \   <i>octal-digit   octal-digit   octal-digit</i>

  <i>dq-hexadecimal-escape-sequence::</i>
    \x  <i>hexadecimal-digit   hexadecimal-digit<sub>opt</sub></i>
    \X  <i>hexadecimal-digit   hexadecimal-digit<sub>opt</sub></i>

  <i>dq-unicode-escape-sequence::</i>
    \u{  codepoint-digits  }

  <i>codepoint-digits::</i>
     <i>hexadecimal-digit</i>
     <i>hexadecimal-digit   codepoint-digits</i>
</pre>

**Defined elsewhere**

* [*hexadecimal-digit*](09-lexical-structure.md#integer-literals)
* [*octal-digit*](09-lexical-structure.md#integer-literals)

**Semantics**

A double-quoted string literal is a string literal delimited by
double-quotes ("). The literal can contain any source character except
double-quote (") and backslash (\\), which can only be represented by
their corresponding escape sequence. Certain other (and sometimes
non-printable) characters can also be expressed as escape sequences.

An escape sequence represents a single-character encoding, as described
in the table below:

Escape sequence | Character name | Unicode character
--------------- | --------------| ------
\$  | Dollar sign | U+0024
\"  | Double quote | U+0022
\\  | Backslash | U+005C
\e  | Escape | U+001B
\f  | Form feed | U+000C
\n  | New line | U+000A
\r  | Carriage Return | U+000D
\t  | Horizontal Tab | U+0009
\v  | Vertical Tab | U+000B
\ooo |  1–3-digit octal digit value ooo |
\xhh or \Xhh  | 1–2-digit hexadecimal digit value hh | U+00hh
\u{xxxxxx} | UTF-8 encoding of Unicode codepoint U+xxxxxx | U+xxxxxx

Within a double-quoted string literal, except when recognized as the
start of an escape sequence, a backslash (\\) is retained verbatim.

Within a double-quoted string literal a dollar ($) character not
escaped by a backslash (\\) is handled using a variable substitution rules
described below.

The `\u{xxxxxx}` escape sequence produces the UTF-8 encoding of the Unicode
codepoint with the hexadecimal number specified within the curly braces.
Implementations MUST NOT allow Unicode codepoints beyond U+10FFFF as this is
outside the range UTF-8 can encode (see
[RFC 3629](http://tools.ietf.org/html/rfc3629#section-3)). If a codepoint
larger than U+10FFFF is specified, implementations MUST error.
Implementations MUST pass through `\u` verbatim and not interpret it as an
escape sequence if it is not followed by an opening `{`, but if it is,
implementations MUST produce an error if there is no terminating `}` or the
contents are not a valid codepoint. Implementations MUST support leading zeroes,
but MUST NOT support leading or trailing whitespace for the codepoint between
the opening and terminating braces. Implementations MUST allow Unicode
codepoints that are not Unicode scalar values, such as high and low surrogates.

A Unicode escape sequence cannot be created by variable substitution. For example, given `$v = "41"`,
`"\u{$v}"` results in `"\u41"`, a string of length 4, while `"\u{0$v}"` and `"\u{{$v}}"` contain
ill-formed Unicode escape sequences.

**Variable substitution**

The variable substitution accepts the following syntax:

<pre>
    <i>string-variable::</i>
        <i>variable-name</i>   <i>offset-or-property<sub>opt</sub></i>

    <i>offset-or-property::</i>
        <i>offset-in-string</i>
        <i>property-in-string</i>

    <i>offset-in-string::</i>
        [   <i>name</i>   ]
        [   <i>variable-name</i>   ]
        [   <i>integer-literal</i>   ]

    <i>property-in-string::</i>
        ->   <i>name</i>

</pre>

**Defined elsewhere**

* [*expression*](10-expressions.md#general-6)
* [*integer-literal*](#integer-literals)
* [*name*](#names)
* [*variable-name*](#names)

After the variable defined by the syntax above is evaluated, its value is converted
to string according to the rules of [string conversion](08-conversions.md#converting-to-string-type)
and is substituted into the string in place of the variable substitution expression.

Subscript or property access defined by *offset-in-string* and *property-in-string*
is resolved according to the rules of the [subscript operator](10-expressions.md#subscript-operator)
and [member selection operator](10-expressions.md#member-selection-operator) respectively.
The exception is that *name* inside *offset-in-string* is interpreted as a string literal even if it is not
quoted.

If the character sequence following the `$` does not parse as *name* then the `$` character
is instead interpreted verbatim and no variable substitution is performed.

A double-quoted string literal is a [c-constant](06-constants.md#general) if it does not
contain any variable substitution.

**Examples**

```Hack
$x = 123;
echo ">\$x.$x"."<"; // → >$x.123<
// -----------------------------------------
$colors = array("red", "white", "blue");
$index = 2;
echo "\$colors[$index] contains >$colors[$index]<\n";
  // → $colors[2] contains >blue<
// -----------------------------------------
class C {
    public $p1 = 2;
}
$myC = new C();
echo "\$myC->p1 = >$myC->p1<\n";  // → $myC->p1 = >2<
```

###### Heredoc String Literals

**Syntax**

<pre>
  <i>heredoc-string-literal::</i>
    &lt;&lt;&lt;  <i>hd-start-identifier   new-line   hd-char-sequence<sub>opt</sub>  new-line hd-end-identifier</i>  ;<i><sub>opt</sub>   new-line</i>

  <i>hd-start-identifier::</i>
    <i>name</i>

  <i>hd-end-identifier::</i>
    <i>name</i>

  <i>hd-char-sequence::</i>
    <i>hd-char</i>
    <i>hd-char-sequence   hd-char</i>

  <i>hd-char::</i>
    <i>hd-escape-sequence</i>
    any member of the source character set except backslash (\)
    \  any member of the source character set except \$efnrtvxX or
octal-digit

  <i>hd-escape-sequence::</i>
    <i>hd-simple-escape-sequence</i>
    <i>dq-octal-escape-sequence</i>
    <i>dq-hexadecimal-escape-sequence</i>
    <i>dq-unicode-escape-sequence</i>

  <i>hd-simple-escape-sequence:: one of</i>
    \\   \$   \e   \f   \n   \r   \t   \v
</pre>

**Defined elsewhere**

* [*dq-hexadecimal-escape-sequence*](09-lexical-structure.md#double-quoted-string-literals)
* [*dq-octal-escape-sequence*](09-lexical-structure.md#double-quoted-string-literals)
* [*dq-unicode-escape-sequence*](09-lexical-structure.md#double-quoted-string-literals)
* [*name*](09-lexical-structure.md#names)
* [*new-line*](09-lexical-structure.md#comments)

**Constraints**

The start and end identifier must be the same. Only horizontal white
space is permitted between `<<<` and the start identifier. No white
space is permitted between the start identifier and the new-line that
follows. No white space is permitted between the new-line and the end
identifier that follows. Except for an optional semicolon (`;`), no
characters—not even comments or white space—are permitted between the
end identifier and the new-line that terminates that source line.

**Semantics**

A heredoc string literal is a string literal delimited by
"`<<< name`" and "`name`". The literal can contain any source
character. Certain other (and sometimes non-printable) characters can
also be expressed as escape sequences.

A heredoc literal supports variable substitution as defined for
[double-quoted string literals](09-lexical-structure.md#double-quoted-string-literals).

A heredoc string literal is a [c-constant](06-constants.md#general) if it does not contain
any variable substitution.

**Examples**

```Hack
$v = 123;
$s = <<<    ID
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<";
→ >S'o'me "\"t e  xt; $v = 123"
Some more text<
```

###### Nowdoc String Literals

**Syntax**

<pre>
  <i>nowdoc-string-literal::</i>
    &lt;&lt;&lt;  '  <i>hd-start-identifier</i>  '  <i>new-line  hd-char-sequence<sub>opt</sub>   new-line hd-end-identifier</i>  ;<i><sub>opt</sub>   new-line</i>
</pre>

**Defined elsewhere**

* [*hd-char-sequence*](09-lexical-structure.md#heredoc-string-literals)
* [*hd-end-identifier*](09-lexical-structure.md#heredoc-string-literals)
* [*hd-start-identifier*](09-lexical-structure.md#heredoc-string-literals)
* [*new-line*](09-lexical-structure.md#comments)

**Constraints**

No white space is permitted between the start identifier and its
enclosing single quotes ('). See also [§§](09-lexical-structure.md#heredoc-string-literals).

**Semantics**

A nowdoc string literal looks like a [heredoc string literal](09-lexical-structure.md#heredoc-string-literals) except that in the former the start identifier name is
enclosed in single quotes ('). The two forms of string literal have the
same semantics and constraints except that a nowdoc string literal is
not subject to variable substitution.

A nowdoc string literal is a [c-constant](06-constants.md#general).

**Examples**

```Hack
$v = 123;
$s = <<<    'ID'
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<\n\n";
→ >S'o'me "\"t e\txt; \$v = $v"
Some more text<
```

##### The Null Literal

<pre>
  <i>null-literal::</i>
    null
</pre>

**Semantics**

There is one null-literal value, `null`.

A *null-literal* has the null type.

#### Operators and Punctuators

**Syntax**

<pre>
  <i>operator-or-punctuator:: one of</i>
    [   ]    (   )   {    }   .   ->   ++   --   **   *   +   -   ~   !
    $   /   %   &lt;&lt;   >>   &lt;   >   &lt;=   >=   ==   ===   !=   !==   ^   |
    &amp;   &amp;&amp;   ||   ?   ??   :   ; =   **=   *=   /=   %=   +=   -=   .=   &lt;&lt;=
    >>=   &amp;=   ^=   |=   ,   @   ::   =>   ==>   ?->   \   ...    |>   $$
</pre>

**Semantics**

Operators and punctuators are symbols that have independent syntactic
and semantic significance. *Operators* are used in expressions to
describe operations involving one or more *operands*, and that yield a
resulting value, produce a side effect, or some combination thereof.
*Punctuators* are used for grouping and separating.


================================================
FILE: spec/10-expressions.md
================================================
# Expressions

## General

An *expression* involves one or more terms and zero or more operators.

A *full expression* is an expression that is not part of another
expression.

A *value side effect* is an action that changes the state of the execution
environment. (Examples of such actions are modifying a variable, writing
to a device or file, or calling a function that performs such
operations.) Throughout this specification, this term is shortened to
*side effect*, which should not be confused with [*type side effect*](05-types.md#type-side-effects).

When an expression is evaluated, it produces a result. It might also
produce a side effect. Only a few operators produce side effects. (For
example, given the [expression statement](11-statements.md#expression-statements) `$v = 10`; the
expression 10 is evaluated to the result 10, and there is no side
effect. Then the assignment operator is executed, which results in the
side effect of `$v` being modified. The result of the whole expression is
the value of `$v` after the assignment has taken place. However, that
result is never used. Similarly, given the expression statement `++$v`;
the expression is evaluated to the result incremented-value-of-`$v`, and
the side effect is that `$v` is actually incremented. Again, the result
is never used.)

The occurrence of value computation and side effects is delimited by
*sequence points*, places in a program's execution at which all the
computations and side effects previously promised are complete, and no
computations or side effects of future operations have yet begun. There
is a sequence point at the end of each full expression. The [logical and](10-expressions.md#logical-and-operator), [logical or](10-expressions.md#logical-inclusive-or-operator), [conditional](10-expressions.md#conditional-operator), and [function-call](#function-call-operator) operators each contain a sequence point. (For example, in the
following series of expression statements, `$a = 10; ++$a; $b = $a;`,
there is sequence point at the end of each full expression, so the
assignment to $a is completed before `$a` is incremented, and the
increment is completed before the assignment to `$b`.)

When an expression contains multiple operators, the *precedence* of
those operators controls the order in which those operators are applied.
(For example, the expression `$a - $b / $c` is evaluated as
`$a - ($b / $c)` because the / operator has higher precedence than the
binary - operator.) The precedence of an operator is defined by the
definition of its associated grammar production.

If an operand occurs between two operators having the same precedence,
the order in which the operations are performed is defined by those
operators' *associativity*. With *left-associative* operators,
operations are performed left-to-right. (For example, `$a + $b - $c` is
evaluated as `($a + $b) - $c.`) With *right-associative* operators,
operations are performed right-to-left. (For example, `$a = $b = $c` is
evaluated as `$a = ($b = $c)`.)

Precedence and associativity can be controlled using *grouping
parentheses*. (For example, in the expression `($a - $b) / $c`, the
subtraction is done before the division. Without the grouping
parentheses, the division would take place first.)

While precedence, associativity, and grouping parentheses control the
order in which operators are applied, they do *not* control the order of
evaluation of the terms themselves. Unless stated explicitly in this
specification, the order in which the operands in an expression are
evaluated relative to each other is unspecified. See the discussion
above about the operators that contain sequence points. (For example, in
the full expression `$list1[$i] = $list2[$i++]`, whether the value
of `$i` on the left-hand side is the old or new `$i`, is unspecified.
Similarly, in the full expression `$j = $i + $i++`, whether the value
of `$i` is the old or new `$i`, is unspecified. Finally, in the full
expression `f() + g() * h()`, the order in which the three functions are
called, is unspecified.)

**Implementation Notes**

An expression that contains no side effects and whose resulting value is
not used need not be evaluated. For example, the expression statements
`6;, $i + 6;`, and `$i/$j`; are well formed, but they contain no side
effects and their results are not used.

A side effect need not be executed if it can be defined that no other
program code relies on its having happened. (For example, in the cases
of return `$a++`; and return `++$a`;, it is obvious what value must be
returned in each case, but if `$a` is a variable local to the enclosing
function, `$a` need not actually be incremented.

## Restrictions on Arithmetic Operations

No arithmetic operation can be performed on the value `null` or on a value of
type `bool`, `string` (not even if the string is numeric), or any nullable type (including nullable arithmetic types).

## Operations on Operands Having One or More Subtypes

None of the subclauses in this Expressions clause discuss the use of operands
of supertypes such as `num`, `arraykey`, or `?int`. Refer to [§§](05-types.md#type-side-effects) for a discussion of type side effects.

## Primary Expressions

### General

**Syntax**

<pre>
  <i>primary-expression:</i>
    <i>variable-name</i>
    <i>qualified-name</i>
    <i>literal</i>
    <i>const-expression</i>
    <i>intrinsic</i>
    <i>collection-literal</i>
    <i>tuple-literal</i>
    <i>shape-literal</i>
    <i>anonymou
Download .txt
gitextract_tmng50ms/

├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FORMATTING.md
├── LICENSE
├── README.md
├── spec/
│   ├── 00-specification-for-hack.md
│   ├── 01-introduction.md
│   ├── 02-conformance.md
│   ├── 03-terms-and-definitions.md
│   ├── 04-basic-concepts.md
│   ├── 05-types.md
│   ├── 06-constants.md
│   ├── 07-variables.md
│   ├── 08-conversions.md
│   ├── 09-lexical-structure.md
│   ├── 10-expressions.md
│   ├── 11-statements.md
│   ├── 12-script-inclusion.md
│   ├── 13-enums.md
│   ├── 14-generic-types-methods-and-functions.md
│   ├── 15-functions.md
│   ├── 16-classes.md
│   ├── 17-interfaces.md
│   ├── 18-traits.md
│   ├── 19-exception-handling.md
│   ├── 20-namespaces.md
│   ├── 21-attributes.md
│   ├── 22-grammar.md
│   ├── 23-differences-from-php.md
│   ├── 24-bibliography.md
│   └── hack-spec-draft.md
├── tests/
│   ├── .hhconfig
│   ├── Attributes/
│   │   ├── .hhconfig
│   │   ├── __ConsistentConstruct.php
│   │   ├── __ConsistentConstruct.php.expect
│   │   ├── __Memoize.php
│   │   ├── __Memoize.php.expect
│   │   ├── __Override.php
│   │   ├── __Override.php.expect
│   │   ├── attributes.php
│   │   └── attributes.php.expect
│   ├── Basic_Concepts/
│   │   ├── .hhconfig
│   │   ├── program_structure.php
│   │   ├── program_structure.php.expectf
│   │   ├── top_level_stuff.php
│   │   └── top_level_stuff.php.expect
│   ├── Classes/
│   │   ├── .hhconfig
│   │   ├── Aircraft.php
│   │   ├── Aircraft.php.expect
│   │   ├── Closure_call.php
│   │   ├── Closure_call.php.expectf
│   │   ├── Generator_getReturn.php
│   │   ├── Generator_getReturn.php.expectf
│   │   ├── MathLibrary.php
│   │   ├── MathLibrary.php.expect
│   │   ├── MathLibrary_test1.php
│   │   ├── MathLibrary_test1.php.expect
│   │   ├── MyCollection.php
│   │   ├── MyCollection.php.expect
│   │   ├── MyList.php
│   │   ├── MyList.php.expect
│   │   ├── PassengerJet.php
│   │   ├── PassengerJet.php.expect
│   │   ├── Point.php
│   │   ├── Point.php.expect
│   │   ├── Point2.php
│   │   ├── Point2.php.expect
│   │   ├── Point_test1.php
│   │   ├── Point_test1.php.expect
│   │   ├── Serializable.php
│   │   ├── Serializable.php.expectf
│   │   ├── Serializable_with_untrusted_data.php
│   │   ├── Serializable_with_untrusted_data.php.expectf
│   │   ├── Vehicle.php
│   │   ├── Vehicle.php.expect
│   │   ├── Vehicle_test1.php
│   │   ├── Vehicle_test1.php.expect
│   │   ├── __PHP_Incomplete_Class.php
│   │   ├── __PHP_Incomplete_Class.php.expect
│   │   ├── abstract_constants.php
│   │   ├── abstract_constants.php.expect
│   │   ├── cc.php
│   │   ├── cc.php.expectf
│   │   ├── classes.php
│   │   ├── classes.php.expect
│   │   ├── cloning.php
│   │   ├── cloning.php.expect
│   │   ├── constructors.php
│   │   ├── constructors.php.expect
│   │   ├── destructors.php
│   │   ├── destructors.php.expect
│   │   ├── dynamic_methods.php
│   │   ├── dynamic_methods.php.expect
│   │   ├── invoke.php
│   │   ├── invoke.php.expect
│   │   ├── property_initializer.php
│   │   ├── property_initializer.php.expect
│   │   ├── require_extends_implements.php
│   │   ├── require_extends_implements.php.expectf
│   │   ├── sleep_and_wakeup.php
│   │   ├── sleep_and_wakeup.php.expectf
│   │   ├── test_for_new_types.php
│   │   ├── test_for_new_types.php.expectf
│   │   ├── type_constants.php
│   │   ├── type_constants.php.expect
│   │   ├── visibility.php
│   │   └── visibility.php.expect
│   ├── Collections/
│   │   ├── .hhconfig
│   │   ├── collections_intrinsics_list.php
│   │   ├── collections_intrinsics_list.php.expect
│   │   ├── collections_operations.php
│   │   ├── collections_operations.php.expect
│   │   ├── vector.php
│   │   └── vector.php.expect
│   ├── Constants/
│   │   ├── .hhconfig
│   │   ├── Testfile.txt
│   │   ├── constants.php
│   │   ├── constants.php.expect
│   │   ├── context_dependent_constants.php
│   │   ├── context_dependent_constants.php.expectf
│   │   ├── core_predefined_constants.php
│   │   └── core_predefined_constants.php.expect
│   ├── Enums/
│   │   ├── .hhconfig
│   │   ├── enum_constraints.php
│   │   ├── enum_constraints.php.expect
│   │   ├── enums.php
│   │   ├── enums.php.expect
│   │   ├── enums_ops.php
│   │   ├── enums_ops.php.expect
│   │   ├── string_int_equality_problem.php
│   │   └── string_int_equality_problem.php.expectf
│   ├── Exception_Handling/
│   │   ├── .hhconfig
│   │   ├── Exception_class.php
│   │   ├── Exception_class.php.expectf
│   │   ├── MyRangeException.php
│   │   ├── MyRangeException.php.expect
│   │   ├── MyRangeException_test1.php
│   │   ├── MyRangeException_test1.php.expectf
│   │   ├── hierarchy_of_exception_classes.php
│   │   ├── hierarchy_of_exception_classes.php.expect
│   │   ├── jump_from_catch_or_finally_clause.php
│   │   ├── jump_from_catch_or_finally_clause.php.expect
│   │   ├── odds_and_ends.php
│   │   ├── odds_and_ends.php.expect
│   │   ├── set_exception_handler.php
│   │   └── set_exception_handler.php.expectf
│   ├── Expressions/
│   │   ├── .hhconfig
│   │   ├── Additive_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── addition_subtraction_concatenation.php
│   │   │   ├── addition_subtraction_concatenation.php.expect
│   │   │   ├── array_concatenation.php
│   │   │   └── array_concatenation.php.expect
│   │   ├── Binary_Logical_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── binary_logical_operators.php
│   │   │   └── binary_logical_operators.php.expect
│   │   ├── Bitwise_Shift_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── bitwise_shift.php
│   │   │   └── bitwise_shift.php.expect
│   │   ├── Bitwise_and_or_xor_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── bitwise_and_or_xor.php
│   │   │   └── bitwise_and_or_xor.php.expect
│   │   ├── Coalesce Operator/
│   │   │   ├── coalesce.php
│   │   │   └── coalesce.php.expect
│   │   ├── Conditional_Operator/
│   │   │   ├── .hhconfig
│   │   │   ├── conditional.php
│   │   │   └── conditional.php.expect
│   │   ├── Equality_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── Testfile1.txt
│   │   │   ├── Testfile2.txt
│   │   │   ├── comparisons.php
│   │   │   ├── comparisons.php.expect
│   │   │   ├── equality_comparison_of_objects.php
│   │   │   └── equality_comparison_of_objects.php.expect
│   │   ├── Instanceof_Operator/
│   │   │   ├── .hhconfig
│   │   │   ├── instanceof.php
│   │   │   └── instanceof.php.expect
│   │   ├── Lambda_Expressions/
│   │   │   ├── .hhconfig
│   │   │   ├── lambdas.php
│   │   │   └── lambdas.php.expectf
│   │   ├── Multiplicative_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── multiplication_division_modulus.php
│   │   │   └── multiplication_division_modulus.php.expect
│   │   ├── Null_safe_method_call/
│   │   │   ├── .hhconfig
│   │   │   ├── null_safe_calls.php
│   │   │   └── null_safe_calls.php.expect
│   │   ├── Pipe_Operator/
│   │   │   ├── pipe.php
│   │   │   └── pipe.php.expect
│   │   ├── Postfix_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── array_creation.php
│   │   │   ├── array_creation.php.expect
│   │   │   ├── exponentiation.php
│   │   │   ├── exponentiation.php.expect
│   │   │   ├── function_call.php
│   │   │   ├── function_call.php.expect
│   │   │   ├── function_call_with_strict_checking.php
│   │   │   ├── function_call_with_strict_checking.php.expectf
│   │   │   ├── member_selection_operator.php
│   │   │   ├── member_selection_operator.php.expect
│   │   │   ├── new.php
│   │   │   ├── new.php.expect
│   │   │   ├── new_anonymous_classes.php
│   │   │   ├── new_anonymous_classes.php.expectf
│   │   │   ├── nullable_and_arithmetic.php
│   │   │   ├── nullable_and_arithmetic.php.expect
│   │   │   ├── nullsafe_member_selection.php
│   │   │   ├── nullsafe_member_selection.php.expect
│   │   │   ├── post-increment_and_decrement_integer_edge_cases.php
│   │   │   ├── post-increment_and_decrement_integer_edge_cases.php.expect
│   │   │   ├── post_increment_and_decrement.php
│   │   │   ├── post_increment_and_decrement.php.expect
│   │   │   ├── scope_resolution_operator.php
│   │   │   ├── scope_resolution_operator.php.expectf
│   │   │   ├── subscripting.php
│   │   │   ├── subscripting.php.expect
│   │   │   ├── subscripting_2.php
│   │   │   ├── subscripting_2.php.expect
│   │   │   └── subscripting_2.php.expectf
│   │   ├── Primary_Expressions/
│   │   │   ├── .hhconfig
│   │   │   ├── Point.php
│   │   │   ├── Point.php.expect
│   │   │   ├── Point2.php
│   │   │   ├── Point2.php.expect
│   │   │   ├── intrinsics_echo.php
│   │   │   ├── intrinsics_echo.php.expect
│   │   │   ├── intrinsics_exit.php
│   │   │   ├── intrinsics_exit.php.expect
│   │   │   ├── intrinsics_invariant.php
│   │   │   ├── intrinsics_invariant.php.expect
│   │   │   ├── intrinsics_list.php
│   │   │   ├── intrinsics_list.php.expect
│   │   │   ├── listPHP.php
│   │   │   ├── listPHP.php.expect
│   │   │   ├── primary.php
│   │   │   └── primary.php.expect
│   │   ├── Relational_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── Testfile1.txt
│   │   │   ├── Testfile2.txt
│   │   │   ├── combined_comparison.php
│   │   │   ├── combined_comparison.php.expectf
│   │   │   ├── comparisons.php
│   │   │   ├── comparisons.php.expect
│   │   │   ├── relational_comparison_of_objects.php
│   │   │   └── relational_comparison_of_objects.php.expect
│   │   ├── Testfile.txt
│   │   ├── Unary_Operators/
│   │   │   ├── .hhconfig
│   │   │   ├── cast.php
│   │   │   ├── cast.php.expect
│   │   │   ├── error_control.php
│   │   │   ├── error_control.php.expectf
│   │   │   ├── pre-increment_and_decrement.php
│   │   │   ├── pre-increment_and_decrement.php.expect
│   │   │   ├── pre-increment_and_decrement_integer_edge_cases.php
│   │   │   ├── pre-increment_and_decrement_integer_edge_cases.php.expect
│   │   │   ├── unary_arithmetic_operators.php
│   │   │   └── unary_arithmetic_operators.php.expect
│   │   ├── Yield_Operator/
│   │   │   ├── .hhconfig
│   │   │   ├── yield.php
│   │   │   ├── yield.php.expectf
│   │   │   ├── yield_from.php
│   │   │   └── yield_from.php.expectf
│   │   ├── conversions.php
│   │   ├── conversions.php.expectf
│   │   ├── limits_on_types_in_arithmetic.php
│   │   ├── limits_on_types_in_arithmetic.php.expect
│   │   ├── yield.php
│   │   └── yield.php.expectf
│   ├── Functions/
│   │   ├── .hhconfig
│   │   ├── TestInc.php
│   │   ├── TestInc.php.expect
│   │   ├── anonymous_function_name.php
│   │   ├── anonymous_function_name.php.expect
│   │   ├── anonymous_functions.php
│   │   ├── anonymous_functions.php.expectf
│   │   ├── anonymous_functions2.php
│   │   ├── anonymous_functions2.php.expect
│   │   ├── async_functions.php
│   │   ├── async_functions.php.expectf
│   │   ├── async_functions2.php
│   │   ├── async_functions2.php.expect
│   │   ├── basics.php
│   │   ├── basics.php.expectf
│   │   ├── callable_typehint.php
│   │   ├── callable_typehint.php.expect
│   │   ├── conditionally_defined_function.php
│   │   ├── conditionally_defined_function.php.expectf
│   │   ├── default_arguments.php
│   │   ├── default_arguments.php.expect
│   │   ├── noreturn.php
│   │   ├── noreturn.php.expect
│   │   ├── override_on_return_type.php
│   │   ├── override_on_return_type.php.expect
│   │   ├── recursion.php
│   │   ├── recursion.php.expect
│   │   ├── this_play.php
│   │   ├── this_play.php.expect
│   │   ├── variable_functions.php
│   │   └── variable_functions.php.expect
│   ├── Generics/
│   │   ├── .hhconfig
│   │   ├── Complex.php
│   │   ├── Complex.php.expect
│   │   ├── Complex_test.php
│   │   ├── Complex_test.php.expect
│   │   ├── Interface_Support.php
│   │   ├── Interface_Support.php.expect
│   │   ├── MyVector.php
│   │   ├── MyVector.php.expect
│   │   ├── MyVector_test.php
│   │   ├── MyVector_test.php.expect
│   │   ├── Stack.php
│   │   ├── Stack.php.expect
│   │   ├── Stack_test.php
│   │   ├── Stack_test.php.expect
│   │   ├── constraints.php
│   │   ├── constraints.php.expect
│   │   ├── contravariance_example.php
│   │   ├── contravariance_example.php.expect
│   │   ├── covariance_example.php
│   │   ├── covariance_example.php.expect
│   │   ├── generic_function.php
│   │   ├── generic_function.php.expect
│   │   ├── generics.php
│   │   └── generics.php.expect
│   ├── Interfaces/
│   │   ├── .hhconfig
│   │   ├── MyCollection.php
│   │   ├── MyCollection.php.expect
│   │   ├── MyList.php
│   │   ├── MyList.php.expect
│   │   ├── MyQueue.php
│   │   ├── MyQueue.php.expect
│   │   ├── interface_requirements.php
│   │   ├── interface_requirements.php.expect
│   │   ├── interfaces.php
│   │   ├── interfaces.php.expect
│   │   ├── qq.php
│   │   └── qq.php.expect
│   ├── Lexical_Structure/
│   │   ├── .hhconfig
│   │   ├── Tokens/
│   │   │   ├── .hhconfig
│   │   │   ├── array_literals.php
│   │   │   ├── array_literals.php.expect
│   │   │   ├── heredoc_string_literals.php
│   │   │   ├── heredoc_string_literals.php.expect
│   │   │   ├── integer_literals_edge_cases.php
│   │   │   ├── integer_literals_edge_cases.php.expect
│   │   │   ├── name_case_sensitivity.php
│   │   │   ├── name_case_sensitivity.php.expectf
│   │   │   ├── names.php
│   │   │   ├── names.php.expect
│   │   │   ├── nowdoc_string_literals.php
│   │   │   ├── nowdoc_string_literals.php.expect
│   │   │   ├── string_literals.php
│   │   │   ├── string_literals.php.expect
│   │   │   ├── unicode_escape_sequences.php
│   │   │   └── unicode_escape_sequences.php.expect
│   │   ├── comments.php
│   │   ├── comments.php.expect
│   │   ├── keywords.php
│   │   └── keywords.php.expect
│   ├── Namespaces/
│   │   ├── .hhconfig
│   │   ├── Circle.php
│   │   ├── Circle.php.expect
│   │   ├── Point.php
│   │   ├── Point.php.expect
│   │   ├── namespaces1.php
│   │   ├── namespaces1.php.expect
│   │   ├── namespaces2.php
│   │   ├── namespaces2.php.expectf
│   │   ├── namespaces2_test.php
│   │   ├── namespaces2_test.php.expectf
│   │   ├── use_groups.php
│   │   ├── use_groups.php.expectf
│   │   ├── use_groups_require_file.php
│   │   ├── use_groups_require_file.php.expect
│   │   ├── using_namespaces_1.php
│   │   ├── using_namespaces_1.php.expect
│   │   ├── using_namespaces_3.php
│   │   ├── using_namespaces_3.php.expect
│   │   ├── using_namespaces_3_test.php
│   │   └── using_namespaces_3_test.php.expect
│   ├── Nullable_Types/
│   │   ├── .hhconfig
│   │   ├── conversions.php
│   │   ├── conversions.php.expectf
│   │   ├── nullables.php
│   │   └── nullables.php.expect
│   ├── Script_Inclusion/
│   │   ├── .hhconfig
│   │   ├── Circle.php
│   │   ├── Circle.php.expect
│   │   ├── Point.php
│   │   ├── Point.php.expect
│   │   ├── Positions.php
│   │   ├── Positions.php.expect
│   │   ├── limits.php
│   │   ├── limits.php.expect
│   │   ├── mycolors.php
│   │   ├── mycolors.php.expect
│   │   ├── require.php
│   │   ├── require.php.expectf
│   │   ├── require_once.php
│   │   ├── require_once.php.expectf
│   │   ├── return_none.php
│   │   ├── return_none.php.expect
│   │   ├── return_with_value.php
│   │   └── return_with_value.php.expect
│   ├── Serialization/
│   │   ├── .hhconfig
│   │   ├── Point.php
│   │   ├── Point.php.expectf
│   │   ├── serialize.php
│   │   └── serialize.php.expectf
│   ├── Shapes/
│   │   ├── .hhconfig
│   │   ├── shapes.php
│   │   ├── shapes.php.expect
│   │   ├── shapes_rf.php
│   │   └── shapes_rf.php.expect
│   ├── Statements/
│   │   ├── .hhconfig
│   │   ├── Iteration/
│   │   │   ├── .hhconfig
│   │   │   ├── do.php
│   │   │   ├── do.php.expect
│   │   │   ├── for.php
│   │   │   ├── for.php.expect
│   │   │   ├── foreach.php
│   │   │   ├── foreach.php.expect
│   │   │   ├── while.php
│   │   │   └── while.php.expect
│   │   ├── Jump/
│   │   │   ├── .hhconfig
│   │   │   ├── break.php
│   │   │   ├── break.php.expect
│   │   │   ├── continue.php
│   │   │   └── continue.php.expect
│   │   ├── Selection/
│   │   │   ├── .hhconfig
│   │   │   ├── if.php
│   │   │   ├── if.php.expectf
│   │   │   ├── switch.php
│   │   │   └── switch.php.expect
│   │   ├── expression_statement.php
│   │   └── expression_statement.php.expect
│   ├── Traits/
│   │   ├── .hhconfig
│   │   ├── trait_implements_interface.php
│   │   ├── trait_implements_interface.php.expect
│   │   ├── trait_requirements.php
│   │   ├── trait_requirements.php.expect
│   │   ├── traits.php
│   │   └── traits.php.expect
│   ├── Tuples/
│   │   ├── .hhconfig
│   │   ├── tuples.php
│   │   └── tuples.php.expect
│   ├── Types/
│   │   ├── .hhconfig
│   │   ├── Issue_109.php
│   │   ├── Issue_109.php.expectf
│   │   ├── Issue_110.php
│   │   ├── Issue_110.php.expect
│   │   ├── Testfile.txt
│   │   ├── arraykey.php
│   │   ├── arraykey.php.expect
│   │   ├── arrays.php
│   │   ├── arrays.php.expectf
│   │   ├── arrays2.php
│   │   ├── arrays2.php.expectf
│   │   ├── bool.php
│   │   ├── bool.php.expect
│   │   ├── classname.php
│   │   ├── classname.php.expect
│   │   ├── closure.php
│   │   ├── closure.php.expect
│   │   ├── determined_type.php
│   │   ├── determined_type.php.expect
│   │   ├── enum.php
│   │   ├── enum.php.expect
│   │   ├── float.php
│   │   ├── float.php.expect
│   │   ├── int.php
│   │   ├── int.php.expect
│   │   ├── mixed.php
│   │   ├── mixed.php.expect
│   │   ├── nullables.php
│   │   ├── nullables.php.expect
│   │   ├── num.php
│   │   ├── num.php.expect
│   │   ├── numeric_like_strings.php
│   │   ├── numeric_like_strings.php.expect
│   │   ├── numeric_strings.php
│   │   ├── numeric_strings.php.expect
│   │   ├── resources.php
│   │   ├── resources.php.expectf
│   │   ├── scalar_general.php
│   │   ├── scalar_general.php.expectf
│   │   ├── shape_specific_functions.php
│   │   ├── shape_specific_functions.php.expect
│   │   ├── shape_subtyping.php
│   │   ├── shape_subtyping.php.expect
│   │   ├── shapes.php
│   │   ├── shapes.php.expect
│   │   ├── shapes.php.expectf
│   │   ├── shapes2.php
│   │   ├── shapes2.php.expectf
│   │   ├── shapes_rf.php
│   │   ├── shapes_rf.php.expect
│   │   ├── string.php
│   │   ├── string.php.expect
│   │   ├── this.php
│   │   ├── this.php.expectf
│   │   ├── tuple.php
│   │   ├── tuple.php.expect
│   │   ├── type_aliases.php
│   │   ├── type_aliases.php.expectf
│   │   ├── type_aliases_rf.php
│   │   ├── type_aliases_rf.php.expectf
│   │   ├── type_inferencing.php
│   │   ├── type_inferencing.php.expect
│   │   ├── type_side_effects.php
│   │   ├── type_side_effects.php.expect
│   │   ├── void.php
│   │   └── void.php.expect
│   └── Variables/
│       ├── .hhconfig
│       ├── placeholder_variable.php
│       ├── placeholder_variable.php.expect
│       ├── predefined_variables.php
│       ├── predefined_variables.php.expect
│       ├── variable_kinds.php
│       └── variable_kinds.php.expect
└── tools/
    ├── README.md
    ├── add_hh_fixme_to_tests.php
    ├── add_language_to_code_blocks.php
    ├── create_test_expect_files.php
    ├── split.php
    ├── toc.php
    └── xreference/
        ├── README.md
        ├── section_map.csv
        └── xreference.php
Download .txt
SYMBOL INDEX (1335 symbols across 212 files)

FILE: tests/Attributes/__ConsistentConstruct.php
  function make (line 14) | function make(): this {
  class Derived (line 20) | class Derived extends Base {
    method __construct (line 21) | public function __construct(...) {
  function make (line 36) | function make(): this {
  function __construct (line 44) | function __construct(int $p1, float $p2, ...) {
  function main (line 82) | function main(): void {

FILE: tests/Attributes/__Memoize.php
  class Item (line 7) | class Item {
    method getNameFromProductCode (line 9) | public static function getNameFromProductCode(int $productCode): string {
    method getNameFromStorage (line 14) | private static function getNameFromStorage(int $productCode): string {
  type T (line 23) | trait T {
    method getNameFromProductCode (line 25) | public function getNameFromProductCode(int $productCode): string {
    method getNameFromStorage (line 30) | private function getNameFromStorage(int $productCode): string {
  class C1 (line 37) | class C1 {
  type I (line 45) | interface I {
    method getNameFromProductCode (line 47) | public function getNameFromProductCode(int $productCode): string;
  class C2 (line 50) | class C2 implements I {
    method getNameFromProductCode (line 51) | public function getNameFromProductCode(int $productCode): string {
    method getNameFromStorage (line 56) | private function getNameFromStorage(int $productCode): string {
  function getNameFromStorage (line 71) | function getNameFromStorage(int $productCode): string {
  class C3 (line 94) | class C3 implements IMemoizeParam {
    method getInstanceKey (line 95) | public function getInstanceKey(): string {
  class C4 (line 100) | class C4 {}
  function getNameFromStorage2 (line 125) | function getNameFromStorage2(int $productCode): string {
  function getNameFromStorage3 (line 141) | function getNameFromStorage3(int $productCode): string {
  function main (line 149) | function main(): void {

FILE: tests/Attributes/__Override.php
  class Button (line 7) | class Button {
    method draw (line 8) | public function draw(): void { /* ... */ }
    method sf (line 9) | public static function sf(): void { /* ... */ }
  class CustomButton (line 16) | class CustomButton extends Button {
    method draw (line 18) | public function draw(): void { /* ... */ }
    method sf (line 20) | public static function sf(): void { /* ... */ }
  type T1 (line 25) | trait T1 {
    method foo (line 27) | public function foo(): void {}
  class C1 (line 30) | class C1 {
  class C2 (line 34) | class C2 {
    method foo (line 35) | public function foo(): void {}
  class C3 (line 38) | class C3 extends C2 {
  type I1 (line 44) | interface I1 {
    method f (line 45) | public function f(): void;
  type I2 (line 52) | interface I2 extends I1 {
    method f (line 54) | public function f(): void;
  class C (line 57) | class C implements I2 {
    method f (line 58) | public function f(): void {}
  function main (line 67) | function main(): void {

FILE: tests/Attributes/attributes.php
  function f2 (line 81) | function f2(<<X>> int $p1): void { echo "Inside " . __FUNCTION__ . "\n"; }
  class C2 (line 95) | class C2 {}
  class X (line 119) | class X {

FILE: tests/Basic_Concepts/top_level_stuff.php
  class C (line 5) | class C {}
  type I (line 6) | interface I {}
  type T (line 7) | trait T {}
  function f1 (line 8) | function f1(): void {}

FILE: tests/Classes/Aircraft.php
  class Aircraft (line 7) | abstract class Aircraft extends Vehicle {
    method getMaxAltitude (line 8) | public abstract function getMaxAltitude(): int;

FILE: tests/Classes/Closure_call.php
  class Value (line 11) | class Value {
    method __construct (line 14) | public function __construct(int $value) {
    method getValue (line 18) | public function getValue(): int {
  function main (line 23) | function main(): void {

FILE: tests/Classes/Generator_getReturn.php
  function foo (line 11) | function foo(): \Generator<int, int, void> {
  function main (line 17) | function main(): void {

FILE: tests/Classes/MathLibrary.php
  class MathLibrary (line 5) | final class MathLibrary {
    method __construct (line 6) | private function __construct(): void {}
    method sin (line 8) | public static function sin(float $p): float { return 0.0; /* ... */ }
    method cos (line 9) | public static function cos(float $p): float { return 0.0; /* ... */ }
    method tan (line 10) | public static function tan(float $p): float { return 0.0; /* ... */ }

FILE: tests/Classes/MathLibrary_test1.php
  function main (line 7) | function main(): void {

FILE: tests/Classes/MyCollection.php
  type MyCollection (line 5) | interface MyCollection {
    method put (line 6) | public function put(int $item): void;
    method get (line 7) | public function get(): int;

FILE: tests/Classes/MyList.php
  class MyList (line 7) | class MyList implements \NS_MyCollections\MyCollection {
    method put (line 8) | public function put(int $item): void {
    method get (line 12) | public function get(): int {

FILE: tests/Classes/PassengerJet.php
  class PassengerJet (line 7) | class PassengerJet extends Aircraft {
    method __construct (line 8) | public function __construct(...) {}
    method getMaxSpeed (line 10) | public function getMaxSpeed(): int {
    method getMaxAltitude (line 15) | public function getMaxAltitude(): int {

FILE: tests/Classes/Point.php
  class Point (line 5) | class Point {
    method getX (line 14) | public function getX(): float  { return $this->x; }
    method setX (line 15) | public function setX(num $x):void 	{ $this->x = (float)$x;   }
    method getY (line 16) | public function getY(): float  { return $this->y; }
    method setY (line 17) | public function setY(num $y): void   { $this->y = (float)$y;   }
    method getPointCount (line 19) | public static function getPointCount(): int {
    method __construct (line 23) | public function __construct(num $x = 0, num $y = 0) {
    method __destruct (line 31) | public function __destruct() {
    method move (line 36) | public function move(num $x, num $y): void {
    method translate (line 41) | public function translate(num $x, num $y): void {
    method __toString (line 46) | public function __toString(): string {
    method __clone (line 50) | public function __clone(): void {
    method __call (line 55) | public function __call(string $name, array<mixed> $arguments) : mixed	{
    method __callStatic (line 60) | public static function __callStatic(string $name, array<mixed> $argume...
    method __get (line 65) | public function __get(string $name): mixed {
    method __set (line 76) | public function __set(string $name, mixed $value): void {
    method __isset (line 83) | public function __isset(string $name): bool {
    method __unset (line 89) | public function __unset(string $name): void {
    method __invoke (line 95) | public function __invoke(...): mixed {
    method __set_state (line 102) | static public function __set_state(array<string,mixed> $properties): P...
    method __sleep (line 112) | public function __sleep(): array<string> {
    method __wakeup (line 118) | public function __wakeup(): void {

FILE: tests/Classes/Point2.php
  class Point2 (line 5) | class Point2 {
    method getPointCount (line 11) | public static function getPointCount(): int {
    method __construct (line 15) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method __destruct (line 21) | public function __destruct() {
    method __clone (line 25) | public function __clone(): void {
    method __toString (line 32) | public function __toString(): string {

FILE: tests/Classes/Point_test1.php
  function main (line 6) | function main(): void {

FILE: tests/Classes/Serializable.php
  class Point (line 5) | class Point implements \Serializable {
    method __construct (line 12) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method __toString (line 20) | public function __toString(): string {
    method serialize (line 24) | public function serialize(): string {
    method unserialize (line 30) | public function unserialize(string $data): void {
  class ColoredPoint (line 40) | class ColoredPoint extends Point implements \Serializable {
    method __construct (line 46) | public function __construct(float $x = 0.0, float $y = 0.0, int $color...
    method __toString (line 53) | public function __toString(): string {
    method serialize (line 57) | public function serialize(): string {
    method unserialize (line 66) | public function unserialize(string $data): void {
  function main (line 75) | function main(): void {

FILE: tests/Classes/Serializable_with_untrusted_data.php
  class Point (line 11) | class Point implements \Serializable {
    method __construct (line 18) | public function __construct(int $x = 0, int $y = 0) {
    method __toString (line 26) | public function __toString(): string {
    method serialize (line 30) | public function serialize(): string {
    method unserialize (line 36) | public function unserialize(string $data): void {
  class ColoredPoint (line 46) | class ColoredPoint extends Point implements \Serializable {
    method __construct (line 52) | public function __construct(int $x = 0, int $y = 0, int $color = Color...
    method __toString (line 59) | public function __toString(): string {
    method serialize (line 63) | public function serialize(): string {
    method unserialize (line 72) | public function unserialize(string $data): void {
  function main (line 81) | function main(): void {

FILE: tests/Classes/Vehicle.php
  class Vehicle (line 5) | abstract class Vehicle {
    method getMaxSpeed (line 6) | public abstract function getMaxSpeed(): int;

FILE: tests/Classes/Vehicle_test1.php
  function main (line 7) | function main(): void {

FILE: tests/Classes/__PHP_Incomplete_Class.php
  class Point (line 5) | class Point {
    method __construct (line 9) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method __toString (line 16) | public function __toString(): string {
  function main (line 21) | function main(): void {

FILE: tests/Classes/abstract_constants.php
  type I1 (line 5) | interface I1 {
  type I2 (line 10) | interface I2 extends I1 {
  class C1 (line 15) | abstract class C1 implements I2 {
  class C2 (line 20) | class C2 implements I2 {
  class C3 (line 25) | class C3 extends C1 {
  function main (line 30) | function main(): void {

FILE: tests/Classes/cc.php
  class Value (line 11) | class Value {
    method __construct (line 14) | public function __construct($value) {
    method getValue (line 18) | public function getValue() {

FILE: tests/Classes/classes.php
  type I1 (line 5) | interface I1 {}
  type I2 (line 6) | interface I2 {}
  class C1 (line 7) | class C1 {}
  class C2 (line 8) | class C2 extends C1 implements I1, I2 {}
  function main (line 10) | function main(): void {

FILE: tests/Classes/cloning.php
  class C (line 8) | class C {
    method __construct (line 10) | public function __construct(int $p1) {
    method __clone (line 15) | public function __clone(): void {
  class Employee (line 21) | class Employee {
    method __construct (line 24) | public function __construct(string $name) {
    method __clone (line 28) | public function __clone(): void {
  class Manager (line 35) | class Manager extends Employee {
    method __construct (line 38) | public function __construct(string $name, int $level) {
    method __clone (line 43) | public function __clone(): void {
  function main (line 52) | function main(): void {

FILE: tests/Classes/constructors.php
  class D1 (line 5) | class D1 {
    method __construct (line 6) | public function __construct(int $p1) {
  class D2 (line 11) | class D2 extends D1 {
    method __construct (line 12) | public function __construct(int $p1, int $p2) {
  class D3 (line 18) | class D3 extends D2 {
    method __construct (line 19) | public function __construct(int $p1, int $p2, int $p3) {
  class D4 (line 25) | class D4 extends D3 {
    method __construct (line 26) | public function __construct() {
  function f4 (line 57) | function f4(): void {
  type I1 (line 66) | interface I1 {
  type T1 (line 75) | trait T1 {
  class C1 (line 84) | class C1 {
  class C2 (line 92) | class C2 {
    method __construct (line 97) | public function __construct(int $p1, private int $p2, int $p3, protect...
  class C3 (line 108) | class C3 {
    method __construct (line 113) | public function __construct(private int $p1, protected float $p2, publ...
  function main (line 117) | function main(): void {

FILE: tests/Classes/destructors.php
  class D1 (line 5) | class D1 {
    method __destruct (line 6) | private function __destruct() {
  class D2 (line 11) | class D2 extends D1 {
    method __destruct (line 12) | public function __destruct() {
  class D3 (line 18) | class D3 extends D2 {
    method __destruct (line 19) | public function __destruct() {
  class D4 (line 25) | class D4 extends D3 {
    method __destruct (line 26) | public function __destruct() {
  function main (line 32) | function main(): void {

FILE: tests/Classes/dynamic_methods.php
  class Widget (line 5) | class Widget {
    method __call (line 6) | public function __call(string $name, array<mixed> $arguments): int {
    method __callStatic (line 13) | public static function __callStatic(string $name, array<mixed> $argume...
  function main (line 21) | function main(): void {

FILE: tests/Classes/invoke.php
  class C (line 5) | class C {
    method __invoke (line 6) | public function __invoke(): void {
  function main (line 11) | function main(): void {

FILE: tests/Classes/property_initializer.php
  class Point (line 5) | class Point {
    method __construct (line 9) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method __toString (line 14) | public function __toString(): string {
  function main (line 19) | function main(): void {

FILE: tests/Classes/require_extends_implements.php
  class B (line 5) | class B {
  class C (line 8) | class C extends B {
  type I (line 15) | interface I {
  class D (line 25) | class D extends C implements I {
  type J (line 28) | interface J {
  type K (line 31) | interface K {
  type T (line 34) | trait T {
  class E (line 49) | class E extends C implements J, K {
  function main (line 53) | function main (): void

FILE: tests/Classes/sleep_and_wakeup.php
  class Point (line 5) | class Point {
    method getPointCount (line 13) | public static function getPointCount(): int {
    method __construct (line 17) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method move (line 26) | public function move(float $x, float $y): void {
    method translate (line 31) | public function translate(float $x, float $y): void {
    method __destruct (line 36) | public function __destruct() {
    method __toString (line 42) | public function __toString(): string {
    method __sleep (line 46) | public function __sleep(): array<string> {
    method __wakeup (line 52) | public function __wakeup(): void {
  class ColoredPoint (line 60) | class ColoredPoint extends Point {
    method __construct (line 66) | public function __construct(float $x = 0.0, float $y = 0.0, int $color...
    method __toString (line 73) | public function __toString(): string {
    method __sleep (line 83) | public function __sleep(): array<string> {
  function main (line 94) | function main(): void {

FILE: tests/Classes/test_for_new_types.php
  function main (line 5) | function main(): void {

FILE: tests/Classes/type_constants.php
  class User (line 9) | abstract class User {
  class WebUser (line 30) | class WebUser extends User implements IUser {
  class OtherUser (line 35) | class OtherUser extends User implements IUser {
  class Ctc1 (line 59) | abstract class Ctc1 {
  function ftc1 (line 68) | function ftc1(Ctc1::T $p): Ctc1::T { return $p; }
  class Ctc2 (line 75) | abstract class Ctc2 {
    method __construct (line 76) | abstract const type T1;
    method getID (line 78) | abstract const type T2;
  class Ctc3a (line 89) | abstract class Ctc3a {
  class Ctc3b (line 98) | class Ctc3b {
  class Ctc4 (line 109) | abstract class Ctc4 {
  class Ctc5 (line 127) | class Ctc5 {
  type Itc1a (line 146) | interface Itc1a {
  type Itc1b (line 153) | interface Itc1b {
    method getID2 (line 154) | abstract const type T2;
  type Itc1c (line 162) | interface Itc1c extends Itc1b {
    method f (line 163) | public function f(this::T2 $p): void;
  class Ctc6 (line 168) | class Ctc6 implements Itc1a, Itc1b {
    method __construct (line 170) | public function __construct(private this::T1 $id) {}
    method getID1 (line 171) | public function getID1(): this::T1 {
    method getID2 (line 176) | public function getID2(this::T2 $p): void {}
    method f (line 180) | public function f(this::T4a $p1, this::T4c $p2): void {}
  type Ttc1 (line 187) | trait Ttc1 {
  class Ctc7a (line 196) | abstract class Ctc7a {
  class Ctc7b (line 203) | abstract class Ctc7b extends Ctc7a {
  class Ctc7c (line 209) | class Ctc7c extends Ctc7b {
  type Itc2a (line 215) | interface Itc2a {
  type Itc2b (line 222) | interface Itc2b extends Itc2a {
  type Itc2c (line 228) | interface Itc2c extends Itc2b {
  class Ctc7d (line 234) | class Ctc7d extends Ctc7c implements Itc2a {
  type Itc8 (line 242) | interface Itc8 {
  class Ctc8a (line 246) | class Ctc8a implements Itc8 {}
  class Ctc8b (line 247) | class Ctc8b extends Ctc8a {}
  function ftc8a (line 249) | function ftc8a(Itc8::T $p): void {}
  function ftc8b (line 250) | function ftc8b(Ctc8a::T $p): void {}
  function ftc8c (line 251) | function ftc8c(Ctc8b::T $p): void {}
  function ftcx (line 253) | function ftcx(Itc8::T $p1, Ctc8a::T $p2, Ctc8b::T $p3): void {
  type Ix (line 265) | interface Ix {
  type Iy (line 269) | interface Iy extends Ix {
  class Cw (line 273) | class Cw {
  class Cx (line 277) | class Cx extends Cw {
  type I1 (line 289) | interface I1 {
  type I2 (line 293) | interface I2 extends I1 {
  class AC1 (line 297) | abstract class AC1 {
  class AC2 (line 301) | abstract class AC2 extends AC1 implements I1, I2 {
  type Itc9a (line 309) | interface Itc9a {
  type Itc9b (line 313) | interface Itc9b extends Itc9a {
  class Ctc9 (line 317) | abstract class Ctc9 implements Itc9b {
    method ftc9 (line 319) | abstract public function ftc9(
  function f9a (line 325) | function f9a(array<Ctc9::T2, bool> $p): void {}
  function f9b (line 327) | function f9b(array<Ctc9::T1> $p1, array<Itc9b::T0> $p2): void {}
  type I10 (line 332) | interface I10 {
  class C10 (line 336) | class C10 {
  function test10 (line 340) | function test10(C10::self::this $x): void {}
  class CBase (line 347) | abstract class CBase {
    method __construct (line 348) | abstract const type T;
  class Cstring (line 352) | class Cstring extends CBase {
    method getString (line 354) | public function getString(): string {
  class Cint (line 359) | class Cint extends CBase {
    method getInt (line 361) | public function getInt(): int {
  function main (line 366) | function main(): void {

FILE: tests/Classes/visibility.php
  class C (line 5) | class C {
    method f1 (line 42) | public function f1(): void {}
    method f2 (line 43) | public function f2(): void {}
    method f3 (line 44) | protected function f3(): void {}
    method f4 (line 45) | private function f4(): void {}
    method sf1 (line 47) | static function sf1(): void {}
    method sf2 (line 48) | public static function sf2(): void {}
    method sf3 (line 49) | static protected function sf3(): void {}
    method sf4 (line 50) | private static function sf4(): void {}
    method __construct (line 54) | public function __construct() {}
    method __destruct (line 65) | public function __destruct() {}
  class D1 (line 75) | abstract class D1 {
    method paf1 (line 76) | public abstract function paf1(int $p1): void;
    method paf2 (line 77) | abstract protected  function paf2(): void;
    method pasf1 (line 79) | public static abstract  function pasf1(): void;
    method pasf2 (line 80) | protected abstract static function pasf2(int $p1): void;
  class D2 (line 83) | class D2 extends D1 {
    method paf1 (line 85) | public function paf1(int $q1): void {}
    method paf2 (line 91) | protected function paf2(): void {}
    method pasf1 (line 94) | public static function pasf1(): void {}
    method pasf2 (line 100) | static protected function pasf2(int $q1): void {}
  function main (line 105) | function main(): void {

FILE: tests/Collections/collections_operations.php
  class C (line 5) | class C {}
  function main (line 7) | function main(int $idx): void {

FILE: tests/Collections/vector.php
  class C (line 5) | class C {
    method __construct (line 7) | public function __construct() {
  function main (line 22) | function main(): void {

FILE: tests/Constants/constants.php
  function trace (line 5) | function trace(string $name, mixed $value, bool $b = false): void {
  function getValue (line 14) | function getValue(): int { return 250; }
  class C (line 16) | class C {}
  class MyClass (line 18) | class MyClass {
  class C3 (line 30) | class C3 {
  function main (line 37) | function main(): void {

FILE: tests/Constants/context_dependent_constants.php
  function ComputeResult (line 5) | function ComputeResult(): void {
  class Date (line 14) | class Date {
    method __construct (line 18) | public function __construct() {
    method __destruct (line 31) | public function __destruct() {
    method setDay (line 38) | public function setDay(int $day): void {
    method priv1 (line 49) | private function priv1(): void {
    method spf1 (line 54) | static public function spf1(): void {
  class DatePlus (line 61) | class DatePlus extends Date {
    method xx (line 62) | public function xx(): void {
  function main (line 69) | function main(): void {

FILE: tests/Constants/core_predefined_constants.php
  function main (line 5) | function main(): void {

FILE: tests/Enums/enum_constraints.php
  function main (line 42) | function main(): void {

FILE: tests/Enums/enums.php
  function main (line 181) | function main(ControlStatus $p1, ControlStatus2 $p2, E4a $p3, E6a $p5): ...
  function takes_int (line 368) | function takes_int(int $x): void { var_dump($x); }
  function takes_string (line 369) | function takes_string(string $x): void { var_dump($x); }
  function takes_mixed (line 370) | function takes_mixed(mixed $x): void { var_dump($x); }

FILE: tests/Enums/enums_ops.php
  function main (line 19) | function main(): void {
  function opsOnEnums (line 24) | function opsOnEnums(

FILE: tests/Exception_Handling/Exception_class.php
  function displayExceptionObject (line 5) | function displayExceptionObject(\Exception $e): void {
  function fL1 (line 33) | function fL1(int $p1 = -10): void {
  function fL2 (line 56) | function fL2(float $p1, float $p2 = -100.0): void {
  function fL3 (line 79) | function fL3(string $p1, ?int $p2, bool $p3 = false): void {
  function main (line 98) | function main(): void {

FILE: tests/Exception_Handling/MyRangeException.php
  class MyRangeException (line 5) | class MyRangeException extends \Exception {
    method __construct (line 10) | public function __construct(string $message, int $badValue, int $lower...
    method getBadValue (line 18) | public function getBadValue(): int   { return $this->badValue; }
    method getLowerValue (line 19) | public function getLowerValue(): int { return $this->lowerValue; }
    method getUpperValue (line 20) | public function getUpperValue(): int { return $this->upperValue; }
    method __toString (line 22) | public function __toString(): string {

FILE: tests/Exception_Handling/MyRangeException_test1.php
  function main (line 7) | function main(): void {

FILE: tests/Exception_Handling/hierarchy_of_exception_classes.php
  class DeviceException (line 5) | class DeviceException extends \Exception { /*...*/ }
  class DiskException (line 6) | class DiskException extends DeviceException { /*...*/ }
  class RemovableDiskException (line 7) | class RemovableDiskException extends DiskException { /*...*/ }
  class FloppyDiskException (line 8) | class FloppyDiskException extends RemovableDiskException { /*...*/ }
  function process (line 10) | function process(): void {
  function main (line 15) | function main(): void {

FILE: tests/Exception_Handling/jump_from_catch_or_finally_clause.php
  function msg (line 5) | function msg(): int {
  function f (line 10) | function f(): int {
  function main (line 34) | function main(): void {

FILE: tests/Exception_Handling/odds_and_ends.php
  class X (line 5) | class X {}
  class Except (line 7) | class Except extends \Exception {
  function main (line 11) | function main(): void {

FILE: tests/Exception_Handling/set_exception_handler.php
  function displayExceptionObject (line 5) | function displayExceptionObject(\Exception $e): void {
  function MyDefExHandler (line 32) | function MyDefExHandler(\Exception $e): void {
  function f (line 38) | function f(int $p1, bool $p2): void {
  function main (line 54) | function main(): void {

FILE: tests/Expressions/Additive_Operators/addition_subtraction_concatenation.php
  function doit (line 5) | function doit(num $p1_num): void {
  function main (line 34) | function main(): void {

FILE: tests/Expressions/Additive_Operators/array_concatenation.php
  class Button (line 5) | class Button {}
  class CustomButton (line 6) | class CustomButton extends Button {}
  function array_proc (line 8) | function array_proc(
  function main (line 60) | function main(): void {

FILE: tests/Expressions/Binary_Logical_Operators/binary_logical_operators.php
  function f (line 5) | function f(int $a): int { echo "inside f(int $a)\n"; return 10;}
  function g (line 6) | function g(int $a): int { echo "inside g(int $a)\n"; return 0;}
  function main (line 8) | function main(): void {

FILE: tests/Expressions/Bitwise_Shift_Operators/bitwise_shift.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Bitwise_and_or_xor_Operators/bitwise_and_or_xor.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Coalesce Operator/coalesce.php
  function foo (line 11) | function foo(): void {
  function main (line 15) | function main(): void {

FILE: tests/Expressions/Conditional_Operator/conditional.php
  function f (line 5) | function f(int $a): int { echo "inside f(int $a)\n"; return 0;}
  function main (line 7) | function main(): void {

FILE: tests/Expressions/Equality_Operators/comparisons.php
  function doit1 (line 5) | function doit1(num $p1_num, ?int $p2_nint): void {
  class Button (line 134) | class Button {}
  class CustomButton (line 135) | class CustomButton extends Button {}
  function array_proc (line 137) | function array_proc(
  function main (line 199) | function main(): void {

FILE: tests/Expressions/Equality_Operators/equality_comparison_of_objects.php
  class C1 (line 5) | class C1 {}
  class C2 (line 6) | class C2 {}
  class C3 (line 7) | class C3 { public int $x = -1; }
  class C4 (line 8) | class C4 { public int $y = -10; public int $x = -11; }
  function main (line 10) | function main(): void {

FILE: tests/Expressions/Instanceof_Operator/instanceof.php
  class C1 (line 5) | class C1 {}
  class C2 (line 6) | class C2 {}
  class D (line 7) | class D extends C1 {}
  function f1 (line 9) | function f1(): D { return new D(); }
  type I1 (line 11) | interface I1 {}
  type I2 (line 12) | interface I2 {}
  class E1 (line 13) | class E1 implements I1, I2 {}
  class C11 (line 15) | class C11 {}
  class C21 (line 16) | class C21 {}
  class D1 (line 17) | class D1 extends C11 {}
  type I11 (line 19) | interface I11 {}
  type I21 (line 20) | interface I21 {}
  class E11 (line 21) | class E11 implements I11, I21 {}
  function main (line 23) | function main(): void {

FILE: tests/Expressions/Lambda_Expressions/lambdas.php
  function lam1 (line 12) | function lam1(int $b): int {
  function main (line 31) | function main(): void {

FILE: tests/Expressions/Multiplicative_Operators/multiplication_division_modulus.php
  function doit (line 5) | function doit(num $p1_num): void {
  function main (line 49) | function main(): void {

FILE: tests/Expressions/Null_safe_method_call/null_safe_calls.php
  class D (line 5) | class D {}
  class C (line 7) | class C {
    method f1 (line 8) | public function f1(int $m, int $n): D {
    method f2 (line 13) | public function f2(int $m, int $n): ?D {
    method f3 (line 18) | public function f3(int $m, int $n): void {
  function hello (line 35) | function hello(int $j): int {
  function test (line 40) | function test(?C $x): void {
  function main (line 59) | function main(): void {

FILE: tests/Expressions/Pipe_Operator/pipe.php
  function fint (line 5) | function fint(int $p): int {
  function gint (line 10) | function gint(int $p): int {
  function hint (line 15) | function hint(int $p): int {
  function fvoid (line 20) | function fvoid(): void {
  class Widget (line 24) | class Widget {
    method getNumber (line 25) | public function getNumber(): int { return -1; }
  function pipe_operator_example (line 28) | function pipe_operator_example(array<Widget> $arr): int {
  function main (line 35) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/array_creation.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/exponentiation.php
  class C (line 5) | class C {
  function f (line 9) | function f(): int { return 3; }
  function main (line 11) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/function_call.php
  function f (line 5) | function f(): void {
  function f2 (line 9) | function f2(int $p1, int $p2 = -100): void {}
  function f3 (line 11) | function f3(int $p2 = -100, ...): void {}
  function fx (line 13) | function fx(int $p1, int $p2, int $p3, int $p4, int $p5): void { }
  function fy (line 14) | function fy(int $p1, int $p2, int $p3, int $p4, int $p5): void {
  function fz (line 17) | function fz(int $p1, int $p2, int $p3, int $p4, int $p5): void { }
  function main (line 19) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/function_call_with_strict_checking.php
  function doubler (line 11) | function doubler(int $p) : int
  function main (line 16) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/member_selection_operator.php
  class Point (line 5) | class Point {
    method getX (line 9) | public function getX(): float 	{ return $this->x; }
    method setX (line 10) | public function setX(float $x): void	{ $this->x = $x;   }
    method getY (line 11) | public function getY(): float		{ return $this->y; }
    method setY (line 12) | public function setY(float $y): void	{ $this->y = $y;   }
    method __construct (line 14) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method move (line 21) | public function move(float $x, float $y): void {
    method translate (line 26) | public function translate(float $x, float $y): void {
    method __toString (line 31) | public function __toString(): string {
    method psf (line 36) | public static function psf(): int { return 123; }
  class K (line 41) | class K {
    method __construct (line 43) | public function __construct(L $p1) {
  class L (line 48) | class L {
    method f (line 49) | public function f(): void { echo "Hello from f\n"; }
  function main (line 52) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/new.php
  class C (line 5) | class C {}
  function main (line 7) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/new_anonymous_classes.php
  class C1 (line 11) | class C1 {}
  type I1 (line 12) | interface I1 {
    method f (line 13) | public function f(): void;
    method g (line 14) | public function g(): void;
  type I2 (line 16) | interface I2 {}
  function main (line 18) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/nullable_and_arithmetic.php
  class C (line 5) | class C {
  function f (line 9) | function f(?int $p1, C $p2): void {
  function main (line 24) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/nullsafe_member_selection.php
  class Bar1 (line 7) | class Bar1 {
    method baz1 (line 8) | public function baz1(): int {
    method sbaz1 (line 11) | public static function sbaz1(): int {
  function get_Bar1 (line 16) | function get_Bar1(): ?Bar1 {
  function foo1 (line 23) | function foo1(): ?int {
  class Bar2 (line 34) | class Bar2 {
    method __construct (line 35) | public function __construct(public string $str = "") {}
  function get_Bar2 (line 39) | function get_Bar2(): ?Bar2 {
  function foo2 (line 46) | function foo2(): ?string {
  function main (line 57) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/post-increment_and_decrement_integer_edge_cases.php
  function incdec (line 5) | function incdec(int $x): void {
  function incdecrev (line 33) | function incdecrev(int $x): void {
  function main (line 61) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/post_increment_and_decrement.php
  class C (line 5) | class C {
  function main (line 9) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/scope_resolution_operator.php
  class M (line 5) | class M {
    method psf (line 8) | public static function psf(): string { return "red"; }
    method b1 (line 15) | public function b1(): void {
    method b2 (line 27) | public function b2(): void {
    method __construct (line 31) | public function __construct() { }
  class N (line 34) | class N extends M {
    method b2 (line 35) | public function b2(): void	// overrides base::b2() {
  class P (line 40) | class P extends N {
    method __construct (line 47) | public function __construct(int $p1) {
    method gi (line 69) | public function gi(): void {
    method gs (line 74) | public static function gs(): void {
    method f1 (line 80) | public static function f1(): void {
    method b2 (line 92) | public function b2(): void	// overrides base::b2() {
  function psf (line 98) | function psf(): int { return 123; }
  class Base (line 105) | class Base {
    method b (line 106) | public function b(): void {
    method f (line 112) | public function f(): void {
  class Derived (line 117) | class Derived extends Base {
    method f (line 118) | public function f(): void {
  type I1 (line 123) | interface I1 {
    method f (line 127) | public function f(): void;
  type I2 (line 130) | interface I2 extends I1 {
  class X (line 134) | class X implements I2 { public function f(): void {} }
    method f (line 134) | public function f(): void {}
  class W1 (line 136) | class W1 {}
  class W2 (line 138) | class W2 extends W1 {
    method M (line 141) | public function M(): void {
  function main (line 151) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/subscripting.php
  function f (line 5) | function f(): array<int> {
  function main (line 12) | function main(): void {

FILE: tests/Expressions/Postfix_Operators/subscripting_2.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Primary_Expressions/Point.php
  class Point (line 5) | class Point {
    method getX (line 9) | public function getX(): float 	{ return $this->x; }
    method setX (line 10) | public function setX(float $x): void	{ $this->x = $x;   }
    method getY (line 11) | public function getY(): float		{ return $this->y; }
    method setY (line 12) | public function setY(float $y): void	{ $this->y = $y;   }
    method __construct (line 14) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method move (line 19) | public function move(float $x, float $y): void {
    method translate (line 24) | public function translate(float $x, float $y): void {
    method __toString (line 29) | public function __toString(): string {

FILE: tests/Expressions/Primary_Expressions/Point2.php
  class Point2 (line 5) | class Point2 {
    method getPointCount (line 11) | public static function getPointCount(): int {
    method __construct (line 15) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method __destruct (line 21) | public function __destruct() {
    method __toString (line 25) | public function __toString(): string {

FILE: tests/Expressions/Primary_Expressions/intrinsics_echo.php
  function main (line 7) | function main(): void {

FILE: tests/Expressions/Primary_Expressions/intrinsics_exit.php
  function cleanup1 (line 7) | function cleanup1(): void {
  function cleanup2 (line 11) | function cleanup2(): void {
  function main (line 15) | function main(): void {

FILE: tests/Expressions/Primary_Expressions/intrinsics_invariant.php
  type I (line 5) | interface I {
    method foo (line 6) | public function foo(): void;
  class A (line 9) | class A implements I {
    method foo (line 10) | public function foo(): void {
  class B (line 15) | class B implements I {
    method foo (line 16) | public function foo(): void {
    method yay (line 20) | public function yay(): void {
  function baz (line 25) | function baz(int $a): I {
  function bar (line 29) | function bar(): B {
  function main (line 36) | function main(?int $p): void {

FILE: tests/Expressions/Primary_Expressions/intrinsics_list.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Primary_Expressions/listPHP.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Primary_Expressions/primary.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Relational_Operators/combined_comparison.php
  function main (line 11) | function main(): void {

FILE: tests/Expressions/Relational_Operators/comparisons.php
  function doit1 (line 5) | function doit1(num $p1_num, ?int $p2_nint): void {
  function doit2 (line 124) | function doit2(array<int> $p1, array<int> $p2, array<float> $p3): void {
  function doit3 (line 145) | function doit3(array<string, int> $p1, array<string, int> $p2): void {
  function main (line 164) | function main(): void {

FILE: tests/Expressions/Relational_Operators/relational_comparison_of_objects.php
  class C1 (line 5) | class C1 {}
  class C2 (line 6) | class C2 {}
  class C3 (line 7) | class C3 { public int $x = -1; }
  class C4 (line 8) | class C4 { public int $y = -10; public int $x = -11; }
  function main (line 10) | function main(): void {

FILE: tests/Expressions/Unary_Operators/cast.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Unary_Operators/error_control.php
  function main (line 5) | function main(): void {

FILE: tests/Expressions/Unary_Operators/pre-increment_and_decrement.php
  class C (line 5) | class C {
  function main (line 9) | function main(): void {

FILE: tests/Expressions/Unary_Operators/pre-increment_and_decrement_integer_edge_cases.php
  function incdec (line 5) | function incdec(int $x): void {
  function incdecrev (line 33) | function incdecrev(int $x): void {
  function main (line 61) | function main(): void {

FILE: tests/Expressions/Unary_Operators/unary_arithmetic_operators.php
  function DoItInt (line 5) | function DoItInt(int $a): void {
  function DoItFloat (line 23) | function DoItFloat(float $a): void {
  function DoItBool (line 33) | function DoItBool(bool $a): void {
  function DoItString (line 45) | function DoItString(string $a): void {
  function main (line 57) | function main(): void {

FILE: tests/Expressions/Yield_Operator/yield.php
  function series (line 8) | function series(int $start, int $end): Continuation<int> {
  function series2 (line 16) | function series2(int $start, int $end, string $keyPrefix = ""): Generato...
  function getTextFileLines (line 25) | function getTextFileLines(string $filename): Continuation<string> {
  function main (line 44) | function main(): void {

FILE: tests/Expressions/Yield_Operator/yield_from.php
  function gen (line 9) | function gen(): Generator<int, int, void> {
  function gen2 (line 15) | function gen2(): Generator<int, int, void> {
  function g (line 20) | function g(): Generator<int, int, void> {
  function main (line 26) | function main(): void {

FILE: tests/Expressions/conversions.php
  class Button (line 5) | class Button {
    method __construct (line 7) | public function __construct(string $label = '??') {
    method __toString (line 10) | public function __toString(): string {
  class CustomButton (line 15) | class CustomButton extends Button {
    method __construct (line 16) | public function __construct(string $label = '??') {
    method __toString (line 19) | public function __toString(): string {
  type MyCollection (line 24) | interface MyCollection {}
  class MyList (line 26) | class MyList implements MyCollection {
    method __toString (line 27) | public function __toString(): string {
  class MyQueue (line 32) | class MyQueue implements MyCollection {
    method __toString (line 33) | public function __toString(): string {
  function get_resource (line 38) | function get_resource(): resource {
  class C1 (line 42) | class C1 {
    method __construct (line 66) | public function __construct() {
  function main (line 697) | function main(): void {

FILE: tests/Expressions/limits_on_types_in_arithmetic.php
  function doit (line 5) | function doit(num $p1_num, ?int $p2_nint, ?float $p3_nfloat, ?num $p4_nn...
  function main (line 19) | function main(): void {

FILE: tests/Expressions/yield.php
  function series (line 12) | function series(int $start, int $end): Continuation<int> {
  function series2 (line 20) | function series2(int $start, int $end, string $keyPrefix = ""): Generato...
  function getTextFileLines (line 29) | function getTextFileLines(string $filename): Continuation<string> {
  function main (line 48) | function main(): void {

FILE: tests/Functions/TestInc.php
  function f2 (line 5) | function f2(): void {

FILE: tests/Functions/anonymous_function_name.php
  class C (line 5) | class C {
    method f (line 6) | public function f(): void {
  function main (line 19) | function main(): void {

FILE: tests/Functions/anonymous_functions.php
  class Cz (line 5) | class Cz {
    method __construct (line 18) | public function __construct() {
  type I (line 27) | interface I {}
  class C (line 28) | class C implements I {}
  function double (line 30) | function double(int $p): int {
  function square (line 34) | function square(int $p): int {
  function compute (line 44) | function compute(array<int> $values): void {
  class D (line 59) | class D {
    method f (line 60) | private function f(): void {
    method compute (line 64) | public function compute(array<string, int> $values): void {
    method stcompute (line 103) | public static function stcompute(array<string, int> $values): void {
  function main_closure_example (line 135) | function main_closure_example(): void {
  function f2 (line 152) | function f2(): string {
  function main (line 165) | function main(): void {

FILE: tests/Functions/anonymous_functions2.php
  function main (line 5) | function main(num $p1): void

FILE: tests/Functions/async_functions.php
  type I1 (line 7) | interface I1 {
    method f1 (line 8) | public function f1(): Awaitable<string>;
  class C1 (line 11) | class C1 implements I1 {
    method f1 (line 12) | public async function f1(): Awaitable<string> { return "abc"; }
  function calc (line 17) | function calc(): Awaitable<int> {
  function control (line 22) | function control(): Awaitable<void> {
  function dbq1 (line 34) | function dbq1(): Awaitable<int> {
  function dbq2 (line 39) | function dbq2(): Awaitable<int> {
  function countdown1 (line 46) | function countdown1(int $start): AsyncIterator<int> {
  function use_countdown1 (line 53) | function use_countdown1(): Awaitable<void> {
  function countdown2 (line 61) | function countdown2(int $start): AsyncKeyedIterator<int, string> {
  function use_countdown2 (line 68) | function use_countdown2(): Awaitable<void> {
  function doit (line 78) | function doit(): Awaitable<void> {

FILE: tests/Functions/async_functions2.php
  function f (line 5) | function f(): Awaitable<int> {
  function g (line 19) | function g(): Awaitable<int> {
  function main (line 29) | function main (): void {

FILE: tests/Functions/basics.php
  function f (line 7) | function f(): void { echo "f\n"; }
  function f1 (line 12) | function f1(...): void {
  function f2 (line 23) | function f2(int $p1, int $p2): void {
  function square (line 30) | function square(num $v): num {
  function addVector (line 34) | function addVector(Vector<int> $v1, Vector<int> $v2): Vector<int> {

FILE: tests/Functions/callable_typehint.php
  function hello (line 5) | function hello(): void {
  function f5 (line 10) | function f5((function (): void) $p1): void {
  function main (line 17) | function main(): void {

FILE: tests/Functions/conditionally_defined_function.php
  function ucf1 (line 7) | function ucf1(): void {
  function main (line 23) | function main(): void {

FILE: tests/Functions/default_arguments.php
  function f1 (line 5) | function f1(int $p1 = 10, float $p2 = 1.23, bool $p3 = true, mixed $p4 =...
  function f4 (line 27) | function f4(int $p1, int $p2 = -100, int $p3 = -200): void {
  function f3 (line 37) | function f3(int $p1 = -1, float $p2 = 99.99, string $p3 = '??'): void {
  function main (line 41) | function main(): void {

FILE: tests/Functions/noreturn.php
  class ExceptionA (line 5) | class ExceptionA extends \Exception {}
  class ExceptionB (line 6) | class ExceptionB extends \Exception {}
  function f6 (line 24) | function f6(int $p): noreturn {
  function f7b (line 50) | function f7b(int $p): noreturn {
  function f7c (line 54) | function f7c(int $p): noreturn {
  function f7d (line 58) | function f7d(int $p): noreturn {
  class C1 (line 65) | class C1 {
    method f6 (line 80) | public function f6(int $p): noreturn {
  class C2 (line 89) | class C2 {
    method f6 (line 104) | public static function f6(int $p): noreturn {

FILE: tests/Functions/override_on_return_type.php
  class C1 (line 5) | class C1 {}
  class C2 (line 6) | class C2 extends C1 {}
  type I (line 8) | interface I {}
  class C3 (line 9) | class C3 implements I {}
  class C4 (line 10) | class C4 implements I {}
  class B (line 12) | class B {
    method f1 (line 13) | public function f1(): int { return 0; }
    method f2 (line 14) | public function f2(): int { return 0; }
    method f3 (line 15) | public function f3(): num { return 0; }
    method f4 (line 16) | public function f4(): num { return 0; }
    method f5 (line 17) | public function f5(): arraykey { return 0; }
    method f6 (line 18) | public function f6(): arraykey { return 0; }
    method f7 (line 19) | public function f7(): ?int { return 0; }
    method f8 (line 20) | public function f8(): ?int { return 0; }
    method f9 (line 21) | public function f9(): C1 { return new C1(); }
    method f10 (line 22) | public function f10(): C1 { return new C1(); }
    method f11 (line 23) | public function f11(): I { return new C3(); }
    method f12 (line 24) | public function f12(): I { return new C3(); }
  class D (line 27) | class D extends B {
    method f1 (line 28) | public function f1(): int { return 100; }
    method f3 (line 30) | public function f3(): int { return 0; }
    method f4 (line 31) | public function f4(): float { return 1.2; }
    method f5 (line 32) | public function f5(): int { return 0; }
    method f6 (line 33) | public function f6(): string { return 'xxx'; }
    method f7 (line 34) | public function f7(): ?int { return null; }
    method f8 (line 35) | public function f8(): int { return 0; }
    method f9 (line 36) | public function f9(): C1 { return new C1(); }
    method f10 (line 37) | public function f10(): C2 { return new C2(); }
    method f11 (line 38) | public function f11(): I { return new C3(); }
    method f12 (line 39) | public function f12(): I { return new C4(); }
  class GB (line 43) | class GB<T> {
  function main (line 49) | function main(): void {

FILE: tests/Functions/recursion.php
  function main (line 5) | function main(): void {
  function factorial (line 14) | function factorial(int $int): int {

FILE: tests/Functions/this_play.php
  class Base (line 5) | class Base {
    method f2 (line 15) | public function f2(): this {
    method setX (line 26) | public function setX(int $new_x): this {
  class Derived (line 56) | class Derived extends Base {}
  class Child (line 58) | final class Child {
    method newChild (line 59) | public function newChild(): this {
  function main (line 67) | function main(): void {

FILE: tests/Functions/variable_functions.php
  function f1 (line 7) | function f1(): void {
  function main (line 11) | function main(): void {

FILE: tests/Generics/Complex.php
  class Complex (line 5) | class Complex<T as num> {
    method __construct (line 9) | public function __construct(T $real, T $imag) {
    method getReal (line 14) | public function getReal(): T {
    method setReal (line 18) | public function setReal(T $real): void {
    method getImag (line 22) | public function getImag(): T {
    method setImag (line 26) | public function setImag(T $imag): void {
    method add (line 30) | public static function add(Complex<T> $z1, Complex<T> $z2): Complex<T> {
    method subtract (line 34) | public static function subtract(Complex<T> $z1, Complex<T> $z2): Compl...
    method __toString (line 38) | public function __toString(): string {

FILE: tests/Generics/Complex_test.php
  function main (line 7) | function main(): void {

FILE: tests/Generics/Interface_Support.php
  function main (line 5) | function main (): void

FILE: tests/Generics/MyVector.php
  class MyVector (line 5) | class MyVector<T> {
    method getLength (line 9) | public function getLength(): int {
    method setLength (line 13) | private function setLength(int $newLength): void {
    method getElement (line 17) | public function getElement(int $index): T {
    method setElement (line 22) | public function setElement(int $index, T $newValue): void {
    method __construct (line 28) | public function __construct(int $vectorLength, T $initValue) {
    method __toString (line 36) | public function __toString(): string {

FILE: tests/Generics/MyVector_test.php
  function main (line 7) | function main(): void {

FILE: tests/Generics/Stack.php
  class StackUnderflowException (line 5) | class StackUnderflowException extends \Exception {}
  class Stack (line 7) | class Stack<T> {
    method __construct (line 11) | public function __construct() {
    method __destruct (line 18) | public function __destruct() {
    method push (line 22) | public function push(T $value): void {
    method pop (line 28) | public function pop(): T {
    method getStackDepth (line 38) | public function getStackDepth(): int {

FILE: tests/Generics/Stack_test.php
  function main2 (line 7) | function main2(\NS_Stack\Stack<int> $stInt, \NS_Stack\Stack<float> $stFl...
  function process (line 24) | function process(\NS_Stack\Stack<int> $p1): void {}
  function main (line 29) | function main(): \NS_Stack\Stack<num> {

FILE: tests/Generics/constraints.php
  class C (line 6) | class C {}
    method __construct (line 31) | public function __construct(T1 $p1, T2 $p2) {
  class CX (line 7) | class CX extends C {}
  type I (line 8) | interface I {}
  class D1 (line 9) | class D1 implements I {}
  class D2 (line 10) | class D2 implements I {}
  class C1a (line 13) | class C1a<T as bool> { public function __construct(private T $p1) {} }
    method __construct (line 13) | public function __construct(private T $p1) {}
  class C1b (line 14) | class C1b<T as int> {}
  class C1c (line 15) | class C1c<T as float> {}
  class num (line 16) | class C1d<T as num> {}
  class C1e (line 17) | class C1e<T as string> {}
  class arraykey (line 18) | class C1f<T as arraykey> {}
  class C1g (line 19) | class C1g<T as E1> {}
  class C1h (line 20) | class C1h<T as array<int>> {}
  class C1i (line 21) | class C1i<T as C> {}
  class C1j (line 22) | class C1j<T as I> {}
  class C1k (line 23) | class C1k<T as (int, bool, string)> {}
  class Point (line 24) | class C1l<T as Point> {}
  class C1o (line 27) | class C1o<T as ?string> {}
  class C1p (line 28) | class C1p<T as array<int, int>> {}
  class C (line 30) | class C2<T1 as I, T2 as C> {
    method __construct (line 31) | public function __construct(T1 $p1, T2 $p2) {
  function main (line 40) | function main(): void {

FILE: tests/Generics/contravariance_example.php
  function __construct (line 12) | function __construct(private T $t) {}
  class Animal (line 15) | class Animal {}
  class Cat (line 16) | class Cat extends Animal {}
  function f (line 18) | function f(C<Cat> $p1): void { var_dump($p1); }
  function main (line 20) | function main(): void {

FILE: tests/Generics/covariance_example.php
  function __construct (line 7) | function __construct(private T $t) {}
  class Animal (line 10) | class Animal {}
  class Cat (line 11) | class Cat extends Animal {}
  function f (line 13) | function f(C<Animal> $p1): void { var_dump($p1); }
  function g (line 15) | function g(array<Animal> $p1): void { var_dump($p1); }
  function main (line 17) | function main(): void {

FILE: tests/Generics/generic_function.php
  class Box (line 31) | class Box<T> {
    method __construct (line 34) | public function __construct(T $v) {
  function main (line 49) | function main(): void {

FILE: tests/Generics/generics.php
  function doit (line 5) | function doit(): void { echo "Hi from doit\n"; }
  class T2 (line 13) | class C1<T1, T2> {}
  class TC2 (line 26) | class TC2 {}
  type TI2 (line 27) | interface TI2 {}
  method T (line 37) | public function T(): void { echo "Hi from T\n"; }
  method f (line 40) | public function f(): void {
  type Y (line 51) | interface Y<T> {
    method T (line 53) | public function T(): void;
  method T (line 68) | public function T(): void { echo "Hi from T\n"; }
  method f (line 71) | public function f(): void {
  class C2c (line 92) | class C2c<T2> {
  function main (line 98) | function main(): void {

FILE: tests/Interfaces/MyCollection.php
  type MyCollection (line 5) | interface MyCollection<T> {
    method put (line 8) | public function put(T $item): void;
    method get (line 9) | public function get(): T;

FILE: tests/Interfaces/MyList.php
  class MyList (line 7) | class MyList<T> implements MyCollection<T> {
    method put (line 10) | public function put(T $item): void {
    method get (line 14) | public function get(): T {

FILE: tests/Interfaces/MyQueue.php
  class MyQueue (line 7) | class MyQueue<T> implements MyCollection<T> {
    method put (line 10) | public function put(T $item): void {
    method get (line 14) | public function get(): T {

FILE: tests/Interfaces/interface_requirements.php
  class C1 (line 5) | class C1 {
    method cf1 (line 6) | public function cf1(): void { }
  class C2 (line 15) | class C2 extends C1 implements I1 {
    method if1 (line 16) | public function if1(): void { }

FILE: tests/Interfaces/interfaces.php
  type iX (line 13) | interface iX {
    method f0 (line 17) | public function f0(): void;
    method f3 (line 21) | public static function f3(): void;
  type iY (line 24) | interface iY {
    method f1 (line 29) | public function f1(int $p1): void;
    method f2 (line 30) | public function f2(int $p1, int $p2): void;
  type iZ (line 33) | interface iZ extends iX, iY {
    method f2 (line 37) | public function f2(int $p1, int $p2): void;
  class C (line 40) | abstract class C implements iZ {}
  class D (line 42) | class D implements iZ {
    method f0 (line 44) | public function f0(): void {}
    method f1 (line 45) | public function f1(int $p1): void {}
    method f2 (line 46) | public function f2(int $p1, int $p2): void {}
    method f3 (line 47) | public static function f3(): void {}
  function main (line 50) | function main(): void {

FILE: tests/Interfaces/qq.php
  class Machine (line 5) | abstract class Machine {
    method openDoors (line 6) | public function openDoors(): void {
    method closeDoors (line 9) | public function closeDoors(): void {
  class AirBus (line 19) | class AirBus extends Machine implements Fliers {
    method takeOff (line 20) | public function takeOff(): bool {
    method fly (line 26) | public function fly(): bool {
  function main (line 42) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/array_literals.php
  class X (line 5) | class X {
  function main (line 15) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/heredoc_string_literals.php
  function main (line 5) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/integer_literals_edge_cases.php
  function main (line 5) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/name_case_sensitivity.php
  function F (line 5) | function F(): void {}
  class C (line 8) | class C {
    method F (line 9) | public function F(): void {}
    method f (line 10) | public function f(): void {}
  type I (line 14) | interface I {}
  type T (line 17) | trait T {}
  function main (line 29) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/names.php
  class enum (line 30) | class enum {}
  class newtype (line 47) | class newtype {}
  class tuple (line 62) | class tuple {}
  class type (line 63) | class type {}
  function arraykey (line 76) | function arraykey(): void {}
  function async (line 78) | function async(): void {}
  function bool (line 79) | function bool(): void {}
  function enum (line 92) | function enum(): void {}
  function float (line 96) | function float(): void {}
  function int (line 104) | function int(): void {}
  function mixed (line 106) | function mixed(): void {}
  function newtype (line 109) | function newtype(): void {}
  function num (line 110) | function num(): void {}
  function string (line 119) | function string(): void {}
  function type (line 125) | function type(): void {}
  function void (line 127) | function void(): void {}
  function null (line 133) | function null(): void {}
  function true (line 134) | function true(): void {}
  function false (line 135) | function false(): void {}
  class C1 (line 137) | class C1 {
    method abstract (line 138) | public function abstract(): void {}
    method arraykey (line 139) | public function arraykey(): void {}
    method as (line 140) | public function as(): void {}
    method async (line 141) | public function async(): void {}
    method bool (line 142) | public function bool(): void {}
    method break (line 143) | public function break(): void {}
    method case (line 144) | public function case(): void {}
    method catch (line 145) | public function catch(): void {}
    method class (line 146) | public function class(): void {}
    method clone (line 147) | public function clone(): void {}
    method const (line 148) | public function const(): void {}
    method continue (line 149) | public function continue(): void {}
    method default (line 150) | public function default(): void {}
    method do (line 151) | public function do(): void {}
    method echo (line 152) | public function echo(): void {}
    method else (line 153) | public function else(): void {}
    method elseif (line 154) | public function elseif(): void {}
    method enum (line 155) | public function enum(): void {}
    method extends (line 156) | public function extends(): void {}
    method final (line 157) | public function final(): void {}
    method finally (line 158) | public function finally(): void {}
    method float (line 159) | public function float(): void {}
    method for (line 160) | public function for(): void {}
    method foreach (line 161) | public function foreach(): void {}
    method function (line 162) | public function function(): void {}
    method if (line 163) | public function if(): void {}
    method implements (line 164) | public function implements(): void {}
    method instanceof (line 165) | public function instanceof(): void {}
    method insteadof (line 166) | public function insteadof(): void {}
    method int (line 167) | public function int(): void {}
    method interface (line 168) | public function interface(): void {}
    method mixed (line 169) | public function mixed(): void {}
    method namespace (line 170) | public function namespace(): void {}
    method new (line 171) | public function new(): void {}
    method newtype (line 172) | public function newtype(): void {}
    method num (line 173) | public function num(): void {}
    method private (line 174) | public function private(): void {}
    method protected (line 175) | public function protected(): void {}
    method public (line 176) | public function public(): void {}
    method require (line 177) | public function require(): void {}
    method require_once (line 178) | public function require_once(): void {}
    method return (line 179) | public function return(): void {}
    method static (line 181) | public function static(): void {}
    method string (line 182) | public function string(): void {}
    method switch (line 183) | public function switch(): void {}
    method throw (line 184) | public function throw(): void {}
    method trait (line 185) | public function trait(): void {}
    method try (line 186) | public function try(): void {}
    method tuple (line 187) | public function tuple(): void {}
    method type (line 188) | public function type(): void {}
    method use (line 189) | public function use(): void {}
    method void (line 190) | public function void(): void {}
    method while (line 191) | public function while(): void {}
    method yield (line 192) | public function yield(): void {}
    method array (line 194) | public function array(): void {}
    method null (line 196) | public function null(): void {}
    method true (line 197) | public function true(): void {}
    method false (line 198) | public function false(): void {}
  function main (line 263) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/nowdoc_string_literals.php
  function main (line 5) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/string_literals.php
  class C (line 5) | class C {
  function main (line 9) | function main(): void {

FILE: tests/Lexical_Structure/Tokens/unicode_escape_sequences.php
  function main (line 14) | function main(): void {

FILE: tests/Lexical_Structure/comments.php
  function main (line 5) | function main(): void {

FILE: tests/Lexical_Structure/keywords.php
  function main (line 5) | function main(): void {

FILE: tests/Namespaces/Circle.php
  class Circle (line 8) | class Circle {
    method __construct (line 12) | public function __construct(float $x = 0.0, float $y = 0.0, float $rad...
    method __toString (line 17) | public function __toString(): string {

FILE: tests/Namespaces/Point.php
  class Point (line 5) | class Point {
    method getX (line 9) | public function getX(): float	 	{ return $this->x; }
    method setX (line 10) | public function setX(float $x): void	{ $this->x = $x;   }
    method getY (line 11) | public function getY(): float		{ return $this->y; }
    method setY (line 12) | public function setY(float $y): void	{ $this->y = $y;   }
    method __construct (line 14) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method move (line 19) | public function move(float $x, float $y): void {
    method translate (line 24) | public function translate(float $x, float $y): void {
    method __toString (line 29) | public function __toString(): string {

FILE: tests/Namespaces/namespaces1.php
  function f1 (line 5) | function f1(): void {
  function f2 (line 11) | function f2(): void {
  function f3 (line 17) | function f3(): void {
  function f4 (line 25) | function f4(): void {
  class C1 (line 29) | class C1 {
    method f (line 32) | public function f(): void {
  type I1 (line 37) | interface I1 {}
  function f5 (line 39) | function f5(): void {
  function main (line 45) | function main(): void {

FILE: tests/Namespaces/namespaces2.php
  function f10 (line 4) | function f10(): void {
  function f20 (line 12) | function f20(): void {
  function f30 (line 20) | function f30(): void {
  function main_namespaces2 (line 28) | function main_namespaces2(): void {

FILE: tests/Namespaces/namespaces2_test.php
  function main (line 7) | function main(): void {

FILE: tests/Namespaces/use_groups.php
  class CC (line 12) | class CC implements I1 {}
  function main (line 14) | function main(): void {

FILE: tests/Namespaces/use_groups_require_file.php
  class C1 (line 10) | class C1 {}
  class C2 (line 11) | class C2 {}
  class C3 (line 12) | class C3 {}
  class C4 (line 13) | class C4 {}
  class C5 (line 14) | class C5 {}
  class C6 (line 15) | class C6 {}
  class C7 (line 16) | class C7 {}
  type I1 (line 17) | interface I1 {}
  function f1 (line 23) | function f1(): void { echo "Inside f1\n"; }
  function f2 (line 24) | function f2(): void { echo "Inside f2\n"; }
  function f3 (line 25) | function f3(): void { echo "Inside f3\n"; }

FILE: tests/Namespaces/using_namespaces_1.php
  function main (line 13) | function main(): void {

FILE: tests/Namespaces/using_namespaces_3.php
  function f (line 6) | function f(): void {
  class C (line 10) | class C {
    method f (line 12) | public function f(): void {
  type I (line 17) | interface I {
  type T (line 21) | trait T {
    method f (line 22) | public function f(): void {
  class D (line 31) | class D extends C implements I {
  function f (line 35) | function f(): void {

FILE: tests/Namespaces/using_namespaces_3_test.php
  function main (line 7) | function main(): void {

FILE: tests/Nullable_Types/conversions.php
  class Button (line 5) | class Button {
    method __construct (line 8) | public function __construct(string $label = '??') {
    method __toString (line 12) | public function __toString(): string {
  class CustomButton (line 17) | class CustomButton extends Button {
    method __construct (line 18) | public function __construct(string $label = '??') {
    method __toString (line 22) | public function __toString(): string {
  type MyCollection (line 27) | interface MyCollection {}
  class MyList (line 29) | class MyList implements MyCollection {
    method __toString (line 30) | public function __toString(): string {
  class MyQueue (line 35) | class MyQueue implements MyCollection {
    method __toString (line 36) | public function __toString(): string {
  class C1 (line 41) | class C1 {
    method __construct (line 64) | public function __construct() {
  function main (line 684) | function main(): void {

FILE: tests/Nullable_Types/nullables.php
  class Button (line 5) | class Button {}
  class CustomButton (line 6) | class CustomButton extends Button {}
  type MyCollection (line 8) | interface MyCollection {}
  class MyList (line 9) | class MyList implements MyCollection {}
  class MyQueue (line 10) | class MyQueue implements MyCollection {}
  class C1 (line 12) | class C1 {
    method __construct (line 39) | public function __construct() {
  function main (line 77) | function main(): void {

FILE: tests/Script_Inclusion/Circle.php
  class Circle (line 7) | class Circle {
    method __construct (line 8) | public function __construct(float $newX, float $newY, float $newR) {

FILE: tests/Script_Inclusion/Point.php
  class Point (line 5) | class Point {
    method __construct (line 6) | public function __construct(float $newX = 0.0, float $newY = 0.0) {

FILE: tests/Script_Inclusion/require.php
  function main (line 11) | function main(): void {

FILE: tests/Script_Inclusion/require_once.php
  function main (line 10) | function main(): void {

FILE: tests/Serialization/Point.php
  class Point (line 5) | class Point implements \Serializable {	// note the interface
    method __construct (line 12) | public function __construct(float $x = 0.0, float $y = 0.0) {
    method __toString (line 18) | public function __toString(): string {
    method serialize (line 22) | public function serialize(): string {
    method unserialize (line 26) | public function unserialize(string $sdata): void {

FILE: tests/Serialization/serialize.php
  function main (line 7) | function main(): void {

FILE: tests/Shapes/shapes.php
  function f1 (line 7) | function f1(\NS_shapes_rf\st2a $p1): void {
  function main (line 13) | function main(): void {

FILE: tests/Shapes/shapes_rf.php
  class C (line 7) | class C {
  function CYf1 (line 29) | function CYf1(Point $p1): void {}
  function CYf2 (line 30) | function CYf2(): Point { return shape('x' => 10, 'y' => 12); }
  class CY (line 32) | class CY {
  function Point_toString (line 36) | function Point_toString(Point $p): string {
  function CYf4 (line 46) | function CYf4(): Point { return shape('y' => 12, 'x' => 10); }
  function PointNT_toString (line 56) | function PointNT_toString(PointNT $p): string {
  function PointNT_getOrigin (line 60) | function PointNT_getOrigin(): PointNT {
  function st3a_test (line 102) | function st3a_test(): st3a { return shape(C::KEY1 => 88); }
  function st4b_test2 (line 118) | function st4b_test2(): st4b { return shape(C::KEY2 => 99); }
  function getY (line 142) | function getY(): int { return 123; }
  function get_Point3 (line 143) | function get_Point3(): Point3 {
  function get_IdSet (line 149) | function get_IdSet(): IdSet {

FILE: tests/Statements/Iteration/do.php
  function main (line 5) | function main(): void {

FILE: tests/Statements/Iteration/for.php
  function main (line 5) | function main(): void {

FILE: tests/Statements/Iteration/while.php
  function main (line 5) | function main(): void {

FILE: tests/Statements/Jump/break.php
  function main (line 5) | function main(): void {

FILE: tests/Statements/Jump/continue.php
  function main (line 5) | function main(): void {

FILE: tests/Statements/Selection/if.php
  function processTransaction (line 5) | function processTransaction(): void { echo "Inside processTransaction\n"; }
  function postMessage (line 6) | function postMessage(): void { echo "Inside postMessage\n"; }
  class Name (line 8) | class Name {
  function main (line 13) | function main(): void {

FILE: tests/Statements/Selection/switch.php
  function main (line 5) | function main(): void {

FILE: tests/Statements/expression_statement.php
  function DoIt (line 5) | function DoIt(): int { return 20; }
  function main (line 7) | function main(): void {

FILE: tests/Traits/trait_implements_interface.php
  type I1 (line 5) | interface I1 {
    method f (line 6) | public function f(): void;
  type I2 (line 9) | interface I2 {
    method g (line 10) | public function g(): void;
    method h (line 14) | public function h(): void { $this->f(); }
  type I2 (line 13) | trait T implements I1, I2 {
    method g (line 10) | public function g(): void;
    method h (line 14) | public function h(): void { $this->f(); }
  class C (line 17) | class C {			// implicit implements clause
    method f (line 19) | public function f(): void {}
    method g (line 20) | public function g(): void {}
  class C2 (line 23) | class C2 implements I1, I2 {	// explicit implements clause
    method f (line 25) | public function f(): void {}
    method g (line 26) | public function g(): void {}

FILE: tests/Traits/trait_requirements.php
  class C1 (line 5) | class C1 {
    method cf1 (line 6) | public function cf1(): void { }
  type I1 (line 9) | interface I1 {
    method if1 (line 10) | public function if1(): void;
  function f (line 16) | function f(): void {
  class C2 (line 22) | class C2 extends C1 implements I1 {
    method if1 (line 24) | public function if1(): void { }
  type T2 (line 27) | trait T2 {
    method f (line 28) | public function f(): void {
  class C3 (line 36) | class C3 extends C1 implements I1 {
    method if1 (line 38) | public function if1(): void { }
  type I2 (line 47) | interface I2 {
    method if2 (line 48) | public function if2(): void;
  class C4 (line 60) | class C4 extends C3 implements I1, I2 {
    method if1 (line 62) | public function if1(): void { }
    method if2 (line 63) | public function if2(): void { }

FILE: tests/Traits/traits.php
  type T1 (line 6) | trait T1 {}
  class C1 (line 8) | class C1 { use T1; }
  type T2a (line 10) | trait T2a {
    method f (line 11) | public function f(): void {
  type T2b (line 20) | trait T2b {
    method f (line 21) | public function f(): void {
  class C2Base (line 30) | class C2Base {
    method f (line 31) | public function f(): void { echo "Inside " . __METHOD__ . "\n"; }
  type T3 (line 50) | trait T3 {
    method m1 (line 51) | public function m1(): void { echo "Inside " . __METHOD__ . "\n"; }
    method m2 (line 52) | protected function m2(): void { echo "Inside " . __METHOD__ . "\n"; }
    method m3 (line 53) | private function m3(): void { echo "Inside " . __METHOD__ . "\n"; }
    method m4 (line 54) | public function m4(): void { echo "Inside " . __METHOD__ . "\n"; }
  type Tx1 (line 72) | trait Tx1 {
    method k (line 73) | public function k(): void {
  type Tx2 (line 82) | trait Tx2 {
    method m (line 83) | public function m(): void {
  type T5 (line 111) | trait T5 {
  class C5a (line 117) | class C5a {
  class C5b (line 123) | class C5b {
  type T6 (line 129) | trait T6 {
    method f (line 130) | public function f(): void {
  class C6a (line 140) | class C6a {
  class C6b (line 146) | class C6b {
  type T7 (line 152) | trait T7 {
    method f (line 155) | public function f(): void {
    method g (line 162) | public static function g(): void {
  type T9a (line 171) | trait T9a {
    method compute (line 172) | public function compute(): void { }
  type T9b (line 177) | trait T9b {
    method compute (line 178) | public function compute(): void { }
  type T9c (line 183) | trait T9c {
    method sort (line 184) | public function sort(): void { }
  type T10 (line 202) | trait T10 {
    method compute (line 206) | public function compute(): void {}
    method getData (line 207) | public static function getData(): void {}
  function main (line 211) | function main(): void {

FILE: tests/Tuples/tuples.php
  class C (line 5) | class C {
  function main (line 20) | function main(?int $p1 = 123): void {

FILE: tests/Types/Issue_109.php
  class C (line 5) | class C {}
  function test (line 7) | function test(): void {

FILE: tests/Types/Issue_110.php
  class C (line 5) | class C {
    method sf1 (line 9) | public static function sf1(): void {
    method sf2 (line 12) | public static function sf2(): void {
  function main (line 17) | function main(): void {

FILE: tests/Types/arraykey.php
  class C (line 5) | class C {
    method setProp (line 9) | public function setProp(arraykey $val): void {
    method getProp (line 13) | public function getProp(): arraykey {
    method __construct (line 17) | public function __construct() {
  function main (line 28) | function main (): void {

FILE: tests/Types/arrays.php
  class C2a (line 5) | class C2a {}
  class C2b (line 6) | class C2b extends C2a {}
  class C2c (line 7) | class C2c extends C2b {}
  class C3 (line 9) | class C3 {}
  type I (line 11) | interface I {}
  class C4a (line 12) | class C4a implements I {}
  class C4b (line 13) | class C4b implements I {}
  class Button (line 15) | class Button {}
  class CustomButton (line 16) | class CustomButton extends Button {}
  type MyCollection (line 18) | interface MyCollection {}
  class MyList (line 19) | class MyList implements MyCollection {}
  class MyQueue (line 20) | class MyQueue implements MyCollection {}
  class C1 (line 22) | class C1 {
    method __construct (line 99) | public function __construct() {
    method f (line 154) | private function f(): void {
    method test_conversions (line 163) | public function test_conversions(
    method test_intrinsics (line 201) | public function test_intrinsics(array<int> $p): void {
    method array_proc (line 209) | public function array_proc(
  function main (line 289) | function main(): void {
  class C5 (line 334) | class C5 {
    method __construct (line 349) | public function __construct() {

FILE: tests/Types/arrays2.php
  function v (line 5) | function v(): void {}
  class C1 (line 7) | class C1 {}
  class C2 (line 8) | class C2 {
    method __construct (line 97) | public function __construct() {
  function main (line 138) | function main(): void {

FILE: tests/Types/bool.php
  class C (line 5) | class C {
    method setProp (line 9) | public function setProp(bool $val): void {
    method getProp (line 13) | public function getProp(): bool {

FILE: tests/Types/classname.php
  class C0 (line 13) | class C0 {
  function f0a (line 19) | function f0a(C0::classname $p): C0::classname { return $p; }
  function f0b (line 20) | function f0b(classname<C0::classname> $p): void { var_dump($p); }
  class C0B (line 30) | class C0B {
    method sf0 (line 34) | public static function sf0(): void { var_dump(C0B::$p101, C0B::$p102, ...
    method sf1 (line 38) | public static function sf1(): void { echo "sf1: " . ((C0B::$str === C0...
    method sf2 (line 39) | public static function sf2(): void { echo "sf2: " . ((C0B::$str == C0B...
    method f (line 41) | public static function f(classname<C0> $p) : classname<C0> { return C0...
  class C0 (line 50) | class Cj1<T as classname<C0>> {}
  class Cj2 (line 51) | class Cj2 extends Cj1<classname<C0>> {}
  class C1 (line 55) | abstract class C1 {
    method __construct (line 56) | public abstract function __construct();
    method hello (line 57) | public static function hello(): void { echo "Inside method " . __METHO...
  class C2 (line 60) | class C2 extends C1 {
    method __construct (line 61) | public function __construct() {}
    method hello (line 62) | public static function hello(): void { echo "Inside method " . __METHO...
  class C3 (line 65) | class C3 extends C2 {
    method __construct (line 66) | public function __construct() { parent::__construct(); }
    method hello (line 67) | public static function hello(): void { echo "Inside method " . __METHO...
  function test2 (line 70) | function test2(classname<C2> $clsname): void {
  function test3 (line 103) | function test3(classname<C3> $clsname): void {
  class C4 (line 107) | class C4 {
  class C5a (line 117) | class C5a implements I5 {
    method hello (line 118) | public static function hello(): void { echo "Inside method " . __METHO...
  class C5b (line 121) | class C5b implements I5 {
    method hello (line 122) | public static function hello(): void { echo "Inside method " . __METHO...
  function test5 (line 125) | function test5(classname<I5> $clsname): void {
  class C8a (line 151) | abstract class C8a {
    method __construct (line 152) | abstract public function __construct();
  class C8b (line 155) | class C8b {
    method __construct (line 156) | final public function __construct() {}
  function f8b (line 167) | function f8b(classname<C8b> $p): void {
  function f8c (line 171) | function f8c(classname<C8c> $p): void {
  function main (line 177) | function main(): void {

FILE: tests/Types/closure.php
  class C (line 5) | class C {
    method setProp (line 10) | public function setProp((function (): void) $val): void {
    method getProp (line 14) | public function getProp(): (function (): void) {
    method __construct (line 18) | public function __construct() {
  function main (line 27) | function main(): void {

FILE: tests/Types/determined_type.php
  function main (line 5) | function main(?int $p1_nint, num $p2_num, ?num $p3_nnum, mixed $p4_mixed...

FILE: tests/Types/enum.php
  class C (line 12) | class C {
    method setProp (line 16) | public function setProp(ControlStatus $val): void {
    method getProp (line 20) | public function getProp(): ControlStatus {
  function main (line 25) | function main(): void {

FILE: tests/Types/float.php
  class C (line 5) | class C {
    method setProp (line 9) | public function setProp(float $val): void {
    method getProp (line 13) | public function getProp(): float {

FILE: tests/Types/int.php
  class C (line 5) | class C {
    method setProp (line 9) | public function setProp(int $val): void {
    method getProp (line 13) | public function getProp(): int {
  function main (line 18) | function main(): void {

FILE: tests/Types/mixed.php
  class C (line 5) | class C {
    method setProp (line 9) | public function setProp(mixed $val): void {
    method getProp (line 13) | public function getProp(): mixed {

FILE: tests/Types/nullables.php
  class Button (line 5) | class Button {}
  class CustomButton (line 6) | class CustomButton extends Button {}
  type MyCollection (line 8) | interface MyCollection {}
  class MyList (line 9) | class MyList implements MyCollection {}
  class MyQueue (line 10) | class MyQueue implements MyCollection {}
  class C1 (line 12) | class C1 {
    method __construct (line 39) | public function __construct() {
  function main (line 77) | function main(): void {

FILE: tests/Types/num.php
  class C (line 5) | class C {
    method setProp (line 9) | public function setProp(num $val): void {
    method getProp (line 13) | public function getProp(): num {
    method __construct (line 17) | public function __construct() {
  function main (line 43) | function main (): void {

FILE: tests/Types/numeric_like_strings.php
  function main (line 5) | function main(): void {

FILE: tests/Types/numeric_strings.php
  function main (line 5) | function main(): void {

FILE: tests/Types/resources.php
  class C (line 5) | class C {
    method __construct (line 9) | public function __construct() {
    method setProp (line 13) | public function setProp(resource $val): void {
    method getProp (line 17) | public function getProp(): resource {
  function main (line 22) | function main(): void {

FILE: tests/Types/scalar_general.php
  class C (line 5) | class C {}
  function main (line 7) | function main(): void {

FILE: tests/Types/shape_specific_functions.php
  class C (line 5) | class C {
  function main (line 13) | function main(): void {

FILE: tests/Types/shapes.php
  function f1 (line 7) | function f1(\NS_shapes_rf_in_types_dir\st2a $p1): void {
  function main (line 13) | function main(): void {

FILE: tests/Types/shapes2.php
  method main (line 24) | public static (int, string) $p7 = tuple(10, 'x');
  method f1 (line 90) | function f1(S2 $p): void {
  method f2 (line 100) | function f2(S1 $p): void {
  method f3 (line 110) | function f3(shape('a' => int, 'n' => ?string) $p): void {

FILE: tests/Types/shapes_rf.php
  class C (line 7) | class C {
  function CXf1 (line 16) | function CXf1(shape('x' => int, 'y' => int) $p1): void {}
  function CXf2 (line 17) | function CXf2(): shape('x' => int, 'y' => int) { return shape('x' => 3, ...
  class CX (line 18) | class CX {
  function CYf1 (line 25) | function CYf1(Point $p1): void {}
  function CYf2 (line 26) | function CYf2(): Point { return shape('x' => 10, 'y' => 12); }
  class CY (line 27) | class CY {
  function Point_toString (line 31) | function Point_toString(Point $p): string {
  function CYf4 (line 39) | function CYf4(): Point { return shape('y' => 12, 'x' => 10); }
  function PointNT_toString (line 48) | function PointNT_toString(PointNT $p): string {
  function PointNT_getOrigin (line 52) | function PointNT_getOrigin(): PointNT {
  function st3a_test (line 93) | function st3a_test(): st3a { return shape(C::KEY1 => 88); }
  function st4b_test2 (line 107) | function st4b_test2(): st4b { return shape(C::KEY2 => 99); }
  function getY (line 131) | function getY(): int { return 123; }
  function get_Point3 (line 132) | function get_Point3(): Point3 {
  function get_IdSet (line 138) | function get_IdSet(): IdSet {

FILE: tests/Types/string.php
  class C (line 5) | class C {
    method setProp (line 9) | public function setProp(string $val): void {
    method getProp (line 13) | public function getProp(): string {

FILE: tests/Types/this.php
  type TR (line 5) | trait TR {
    method TRf (line 14) | abstract public function TRf(this $val): this;
  type I (line 17) | interface I {
    method inf (line 26) | public function inf(this $val): this;
  class C (line 33) | abstract class C implements I {
    method __construct (line 55) | public function __construct(string $name) {
    method setProp (line 66) | public function setProp(this $val): void {
    method getProp (line 72) | public function getProp(): ?this {
    method privf (line 78) | private function privf(this $val): this { return $val; }
    method privsf (line 79) | private static function privsf(this $val): this { return $val; }
    method protf (line 80) | protected function protf(this $val): this { return $val; }
    method protsf (line 81) | protected static function protsf(this $val): this { return $val; }
    method pubf (line 82) | public function pubf(this $val): this { return $val; }
    method pubsf (line 83) | public static function pubsf(this $val): this {
    method inf (line 88) | public function inf(this $val): this { return $val; }
  class E (line 101) | class E extends D {}
  function main (line 106) | function main(): void {

FILE: tests/Types/tuple.php
  class C (line 5) | class C {
    method setProp (line 7) | private (int, string) $prop = tuple(12, 'green');

FILE: tests/Types/type_aliases.php
  function f1 (line 15) | function f1(TTA_n_bool $p1, TTA_n_bool $p2): void {
  function f2 (line 27) | function f2(Counter $p1, Counter $p2): void {
  class C_bool (line 34) | class C_bool {
    method fa (line 35) | public static function fa(bool $p1, TTA_bool1 $p2, TTA_bool2 $p3, TTA_...
    method fc (line 36) | public static function fc(bool $p1, OTA_bool1 $p2, OTA_bool2 $p3, OTA_...
    method fb (line 37) | public static function fb(bool $p1, TTA_bool1 $p2, OTA_bool1 $p3): void {
    method fz (line 48) | public static function fz(?TTA_bool1 $p1, array<TTA_bool2> $p2, Vector...
  class C_enum_Modes (line 53) | class C_enum_Modes {
    method fa (line 54) | public static function fa(Modes $p1, TTA_enum_Modes $p2, OTA_enum_Mode...
    method fb (line 55) | public static function fb(Modes $p1, TTA_enum_Modes $p2, OTA_enum_Mode...
  class C_arrays (line 79) | class C_arrays {
    method fa (line 80) | public static function fa(TTA_array_string $p1, TTA_array_array_string...
    method fb (line 81) | public static function fb(TTA_array_string $p1): void {
  class C_Fullname (line 88) | class C_Fullname {
    method fa (line 90) | public static function fa(TTA_class_Fullname $p1, array<TTA_class_Full...
    method fb (line 95) | public static function fb(OTA_class_Fullname $p1, array<OTA_class_Full...
  class C_MyCollection (line 103) | class C_MyCollection {
    method fa (line 104) | public static function fa(TTA_interface_MyCollection1 $p1, TTA_interfa...
    method fb (line 105) | public static function fb(TTA_interface_MyCollection1 $p1, TTA_interfa...
  class C_tuple (line 112) | class C_tuple {
    method fa (line 114) | public static function fa(TTA_tuple $p1, array<TTA_tuple> $p2): void {}
  class C_closure (line 119) | class C_closure {
    method fa (line 121) | public static function fa(TTA_closure $p1, array<TTA_closure> $p2): vo...
  function CYf1 (line 129) | function CYf1(TTA_shape_point $p1): void {}
  function CYf2 (line 130) | function CYf2(): TTA_shape_point { return shape('x' => 10, 'y' => 12); }
  class CY (line 131) | class CY {
  function addComplex (line 135) | function addComplex(TTA_shape_complex $c1, TTA_shape_complex $c2): TTA_s...
  function main (line 143) | function main(): void {

FILE: tests/Types/type_aliases_rf.php
  class Fullname (line 64) | class Fullname {
  type MyCollection (line 73) | interface MyCollection<T> {
    method put (line 74) | public function put(T $item): void;
    method get (line 75) | public function get(): T;
  type TR1 (line 83) | trait TR1 { public function compute(): void {} }
    method compute (line 83) | public function compute(): void {}
  type TR2 (line 84) | trait TR2 { public function compute(): void {} }
    method compute (line 84) | public function compute(): void {}
  type TR3 (line 85) | trait TR3 { public function sort(): void {} }
    method sort (line 85) | public function sort(): void {}
  type TR4a (line 86) | trait TR4a {

FILE: tests/Types/type_inferencing.php
  class C (line 5) | class C {
  function f (line 10) | function f(int $p1 = -1): void {
  function main (line 26) | function main (): void {

FILE: tests/Types/type_side_effects.php
  class Cx (line 5) | class Cx {
    method m (line 8) | public function m(): void {
    method n (line 23) | public function n(): void {
  function F_bool (line 30) | function F_bool(bool $p1): void {}
  function F_n_bool (line 31) | function F_n_bool(?bool $p1): void {
  function F_n_int (line 61) | function F_n_int(?int $p1): void {
  function F_n_float (line 102) | function F_n_float(?float $p1): void {
  function F_n_num (line 129) | function F_n_num(?num $p1): void {
  function F_num (line 158) | function F_num(num $p1): void {
  function F_string (line 165) | function F_string(string $p1): void {}
  function F_n_string (line 166) | function F_n_string(?string $p1): void {
  function F_n_arraykey (line 190) | function F_n_arraykey(?arraykey $p1): void {
  function F_arraykey (line 208) | function F_arraykey(arraykey $p1): void {
  function F_array (line 221) | function F_array(array<int> $p1): void {}
  function F_n_array (line 222) | function F_n_array(?array<int> $p1): void {
  function F_resource (line 246) | function F_resource(resource $p1): void {}
  function F_n_resource (line 247) | function F_n_resource(?resource $p1): void {
  class C (line 271) | class C {
    method f (line 272) | public function f(): void {}
  function F_n_classC (line 275) | function F_n_classC(?C $p1): void {
  function F_shape (line 322) | function F_shape(MyPoint $p1): void {}
  function F_n_shape (line 323) | function F_n_shape(?MyPoint $p1): void {
  function F_closure (line 341) | function F_closure((function (int): int) $p1): void {}
  class Button (line 369) | class Button {
    method f (line 370) | public function f(): void {}
  class CustomButton (line 373) | class CustomButton extends Button {
    method g (line 374) | public function g(): void {}
  function F_Button (line 377) | function F_Button(Button $p1): void {}
  function F_CustomButton (line 378) | function F_CustomButton(CustomButton $p1): void {}
  function F_n_class_hier (line 379) | function F_n_class_hier(?Button $p1): void {
  function getValue (line 410) | function getValue(): ?int {
  function main (line 415) | function main(): void {

FILE: tests/Types/void.php
  function v (line 5) | function v(): void {}
  class C (line 7) | class C {
    method getProp (line 23) | public function getProp(): void {
  function main (line 27) | function main(): void {

FILE: tests/Variables/placeholder_variable.php
  function f (line 5) | function f(mixed $p): void {
  function g (line 12) | function g(int $_): void {	// checker accepts $_ as a parameter name, bu...
  class C (line 16) | class C {
  type T (line 20) | trait T {
  function main (line 24) | function main(): void {

FILE: tests/Variables/predefined_variables.php
  function main (line 5) | function main(): void {

FILE: tests/Variables/variable_kinds.php
  function localConst (line 11) | function localConst(bool $p): void {
  function doit (line 29) | function doit(bool $p1): void {	// assigned the value true when called
  function f (line 37) | function f(): void {
  function factorial (line 62) | function factorial(int $i): int {
  class Point (line 85) | class Point {
    method __construct (line 93) | public function __construct(float $newX = 0.0, float $newY = 0.0) {
    method __toString (line 98) | public function __toString(): string {
  function main (line 103) | function main(): void {

FILE: tools/add_hh_fixme_to_tests.php
  function main (line 7) | function main(): void {

FILE: tools/add_language_to_code_blocks.php
  function main (line 18) | function main(array<string> $argv): void {

FILE: tools/create_test_expect_files.php
  function check_output (line 5) | function check_output(array<string> $output, string $test_file): array<s...
  function main (line 18) | function main(?string $replace_option = null): void {

FILE: tools/xreference/xreference.php
  function get_section_map (line 3) | function get_section_map(string $section_map_file): array<string, string> {
  function insert_cross_references (line 14) | function insert_cross_references(string $md_file,
  function map_word_sections_to_markdown_sections (line 57) | function map_word_sections_to_markdown_sections(string $section_map_file,
  function usage (line 86) | function usage(): string {
  function main (line 98) | function main(array<string> $argv): void {
Condensed preview — 528 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,681K chars).
[
  {
    "path": ".gitignore",
    "chars": 56,
    "preview": ".DS_Store\nwww.pid\n.commit-template\n*.php.diff\n*.php.out\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 241,
    "preview": "# Code of Conduct\nFacebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 445,
    "preview": "## Contributing to the Specification for Hack\n\nWe'd love your help in improving, correcting, adding to the specification"
  },
  {
    "path": "FORMATTING.md",
    "chars": 920,
    "preview": "# Formatting rules\n\n1. The format of the Hack Language Specification is\n   [Markdown](http://daringfireball.net/projects"
  },
  {
    "path": "LICENSE",
    "chars": 341,
    "preview": "Facebook has dedicated all copyright to this specification to the public \ndomain worldwide under the CC0 Public Domain D"
  },
  {
    "path": "README.md",
    "chars": 917,
    "preview": "## Deprecated, Unmaintained\n\nThis repo contains the Hack Language Specification, a modified version\nof the PHP specifica"
  },
  {
    "path": "spec/00-specification-for-hack.md",
    "chars": 27117,
    "preview": "<!-- This file is autogenerated, do not edit it manually -->\n<!-- Run tools/toc.php instead -->\n\n# Specification for Hac"
  },
  {
    "path": "spec/01-introduction.md",
    "chars": 548,
    "preview": "# Introduction\nThis specification is intended to provide a complete and concise\ndefinition of the syntax and semantics o"
  },
  {
    "path": "spec/02-conformance.md",
    "chars": 2622,
    "preview": "# Conformance\nIn this specification, \"must\" is to be interpreted as a requirement on\nan implementation or on a program; "
  },
  {
    "path": "spec/03-terms-and-definitions.md",
    "chars": 2007,
    "preview": "# Terms and Definitions\nFor the purposes of this document, the following terms and definitions\napply:\n\n<pre>\n\n  <b>argum"
  },
  {
    "path": "spec/04-basic-concepts.md",
    "chars": 62767,
    "preview": "# Basic Concepts\n## Program Structure\nA Hack *program* consists of one or more source files, known formally as\n*scripts*"
  },
  {
    "path": "spec/05-types.md",
    "chars": 46658,
    "preview": "# Types\n\n## General\n\nThe meaning of a value is decided by its *type*. Hack's types are\ncategorized as *scalar types* and"
  },
  {
    "path": "spec/06-constants.md",
    "chars": 7453,
    "preview": "# Constants\n\n## General\n\nA *constant* is a [named](09-lexical-structure.md#names) value. Once defined, the value\nof the "
  },
  {
    "path": "spec/07-variables.md",
    "chars": 5529,
    "preview": "# Variables\n\n## General\n\nA *variable* is a named area of data storage that has a type and a\nvalue. A variable is represe"
  },
  {
    "path": "spec/08-conversions.md",
    "chars": 7294,
    "preview": "# Conversions\n\n## General\n\nSome operators implicitly convert automatically the values of operands\nfrom one type to anoth"
  },
  {
    "path": "spec/09-lexical-structure.md",
    "chars": 27441,
    "preview": "# Lexical Structure\n\n## Scripts\n\nA [script](04-basic-concepts.md#program-structure) is an ordered sequence of characters"
  },
  {
    "path": "spec/10-expressions.md",
    "chars": 108776,
    "preview": "# Expressions\n\n## General\n\nAn *expression* involves one or more terms and zero or more operators.\n\nA *full expression* i"
  },
  {
    "path": "spec/11-statements.md",
    "chars": 25135,
    "preview": "# Statements\n\n## General\n\n**Syntax**\n\n<pre>\n  <i>statement:</i>\n    <i>function-static-declaration</i>\n    <i>compound-s"
  },
  {
    "path": "spec/12-script-inclusion.md",
    "chars": 3502,
    "preview": "# Script Inclusion Operators\n\n## General\n\n**Syntax**\n\n<pre>\n  <i>inclusion-directive:</i>\n    <i>require-multiple-direct"
  },
  {
    "path": "spec/13-enums.md",
    "chars": 5109,
    "preview": "# Enums\n\n## General\n\nAn *enumeration* consists of a set of zero or more named, constant values called *enumeration* cons"
  },
  {
    "path": "spec/14-generic-types-methods-and-functions.md",
    "chars": 14429,
    "preview": "# Generic Types, Methods, and Functions\n\n## General\n\nCertain types (classes, interfaces, and traits) and their methods c"
  },
  {
    "path": "spec/15-functions.md",
    "chars": 13436,
    "preview": "# Functions\n\n## General\n\nWhen a function is called, information may be passed to it by the caller\nvia an *argument list*"
  },
  {
    "path": "spec/16-classes.md",
    "chars": 53676,
    "preview": "# Classes\n\n## General\n\nA class is a type that may contain zero or more explicitly declared\n*members*, which can be any c"
  },
  {
    "path": "spec/17-interfaces.md",
    "chars": 12192,
    "preview": "# Interfaces\n\n## General\n\nA class can implement a set of capabilities—herein called a\n*contract*—through what is called "
  },
  {
    "path": "spec/18-traits.md",
    "chars": 6732,
    "preview": "# Traits\n\n## General\n\nHack's class model allows [single inheritance](16-classes.md#general) with contracts\nbeing enforce"
  },
  {
    "path": "spec/19-exception-handling.md",
    "chars": 8533,
    "preview": "# Exception Handling\n\n## General\n\nAn *exception* is some unusual condition in that it is outside the\nordinary expected b"
  },
  {
    "path": "spec/20-namespaces.md",
    "chars": 8610,
    "preview": "# Namespaces\n\n## General\n\nA problem encountered when managing large projects is that of avoiding\nthe use of the same nam"
  },
  {
    "path": "spec/21-attributes.md",
    "chars": 6109,
    "preview": "# Attributes\n\n## General\n\nProgrammers can invent a new kind of declarative information, called an *attribute*. Attribute"
  },
  {
    "path": "spec/22-grammar.md",
    "chars": 38592,
    "preview": "# Grammar\n\n## General\n\nThe grammar notation is described in [§§](09-lexical-structure.md#grammars).\n\n## Lexical Grammar\n"
  },
  {
    "path": "spec/23-differences-from-php.md",
    "chars": 10213,
    "preview": "# Differences from PHP\n\n## General\nThis annex identifies the PHP features that are either not supported in Hack or that "
  },
  {
    "path": "spec/24-bibliography.md",
    "chars": 483,
    "preview": "# Bibliography\n\nThe following documents are useful references for implementers and users\nof this specification:\n\nIEC 605"
  },
  {
    "path": "spec/hack-spec-draft.md",
    "chars": 414282,
    "preview": "# Specification for PHP\nFacebook has dedicated all copyright to this specification to the public\ndomain worldwide under "
  },
  {
    "path": "tests/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Attributes/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Attributes/__ConsistentConstruct.php",
    "chars": 2509,
    "preview": "<?hh // strict\n\nnamespace NS_ConsistentConstruct;\n\n// --------------------------------------------------------\n// test w"
  },
  {
    "path": "tests/Attributes/__ConsistentConstruct.php.expect",
    "chars": 752,
    "preview": "\n============== on constructor =====================\n\nmaking a new object\nIn NS_ConsistentConstruct\\Base::__construct\nob"
  },
  {
    "path": "tests/Attributes/__Memoize.php",
    "chars": 6916,
    "preview": "<?hh // strict\n\nnamespace NS_Memoize;\n\n// --------------------------------------------------------\n\nclass Item {\n  <<__M"
  },
  {
    "path": "tests/Attributes/__Memoize.php.expect",
    "chars": 1730,
    "preview": "\n============== in class =====================\n\nInside getNameFromStorage\nstring(7) \"cabinet\"\nInside getNameFromStorage\n"
  },
  {
    "path": "tests/Attributes/__Override.php",
    "chars": 1933,
    "preview": "<?hh // strict\n\nnamespace NS_Override;\n\n// --------------------------------------------------------\n\nclass Button {\n  pu"
  },
  {
    "path": "tests/Attributes/__Override.php.expect",
    "chars": 160,
    "preview": "\n============== top-level function =====================\n\nInside NS_Override\\f1\narray(1) {\n  [0]=>\n  int(3)\n}\narray(2) {"
  },
  {
    "path": "tests/Attributes/attributes.php",
    "chars": 7051,
    "preview": "<?hh // strict\n\nnamespace NS_attrib1;\n\n// --------------------------------------------------------\n\n// example for spec\n"
  },
  {
    "path": "tests/Attributes/attributes.php.expect",
    "chars": 2533,
    "preview": "\n============== top-level function =====================\n\nInside NS_attrib1\\f1\narray(0) {\n}\narray(4) {\n  [0]=>\n  int(3)\n"
  },
  {
    "path": "tests/Basic_Concepts/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Basic_Concepts/program_structure.php",
    "chars": 46,
    "preview": "<?hh // strict\n\n// ?> closing tag not allowed\n"
  },
  {
    "path": "tests/Basic_Concepts/program_structure.php.expectf",
    "chars": 168,
    "preview": "\nFatal error: HH mode: ?> not allowed (Line: 3, Char: 30)\nsyntax error, unexpected T_HH_ERROR, expecting $end in %s/test"
  },
  {
    "path": "tests/Basic_Concepts/top_level_stuff.php",
    "chars": 326,
    "preview": "<?hh // strict\n\nnamespace NS_top_level_stuff;\nuse NS2\\X;\nclass C {}\ninterface I {}\ntrait T {}\nfunction f1(): void {}\n\n//"
  },
  {
    "path": "tests/Basic_Concepts/top_level_stuff.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/Aircraft.php",
    "chars": 172,
    "preview": "<?hh // strict\n\nnamespace NS_Vehicles;\n\nrequire_once 'Vehicle.php';\n\nabstract class Aircraft extends Vehicle {\n  public "
  },
  {
    "path": "tests/Classes/Aircraft.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/Closure_call.php",
    "chars": 744,
    "preview": "// NOT YET IMPLEMENTED IN CHECKER OR ENGINE <?hh // strict\n\nnamespace NS_Closure_call;\n\n/*\n   +-------------------------"
  },
  {
    "path": "tests/Classes/Closure_call.php.expectf",
    "chars": 161,
    "preview": "\nFatal error: HH mode: content before <?hh (Line: 1, Char: 44)\nsyntax error, unexpected T_HH_ERROR, expecting $end in %s"
  },
  {
    "path": "tests/Classes/Generator_getReturn.php",
    "chars": 743,
    "preview": "// NOT YET IMPLEMENTED   <?hh // strict\n\nnamespace NS_Generator_getReturn;\n\n/*\n   +-------------------------------------"
  },
  {
    "path": "tests/Classes/Generator_getReturn.php.expectf",
    "chars": 168,
    "preview": "\nFatal error: HH mode: content before <?hh (Line: 1, Char: 25)\nsyntax error, unexpected T_HH_ERROR, expecting $end in %s"
  },
  {
    "path": "tests/Classes/MathLibrary.php",
    "chars": 366,
    "preview": "<?hh // strict\n\nnamespace NS_MathLibrary;\n\nfinal class MathLibrary {\n  private function __construct(): void {}\t// disall"
  },
  {
    "path": "tests/Classes/MathLibrary.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/MathLibrary_test1.php",
    "chars": 366,
    "preview": "<?hh // strict\n\nnamespace NS_MathLibrary_test1;\n\nrequire_once 'MathLibrary.php';\n\nfunction main(): void {\n//  $m = new \\"
  },
  {
    "path": "tests/Classes/MathLibrary_test1.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/MyCollection.php",
    "chars": 142,
    "preview": "<?hh // strict\n\nnamespace NS_MyCollections;\n\ninterface MyCollection {\n  public function put(int $item): void;\n  public f"
  },
  {
    "path": "tests/Classes/MyCollection.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/MyList.php",
    "chars": 262,
    "preview": "<?hh // strict\n\nnamespace NS_MyList;\n\nrequire_once 'MyCollection.php';\n\nclass MyList implements \\NS_MyCollections\\MyColl"
  },
  {
    "path": "tests/Classes/MyList.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/PassengerJet.php",
    "chars": 331,
    "preview": "<?hh // strict\n\nnamespace NS_Vehicles;\n\nrequire_once 'Aircraft.php';\n\nclass PassengerJet extends Aircraft {\n  public fun"
  },
  {
    "path": "tests/Classes/PassengerJet.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/Point.php",
    "chars": 3371,
    "preview": "<?hh // strict\n\nnamespace NS_Point;\n\nclass Point {\n  private static int $nextId = 1;\n  private array<string,mixed> $dyna"
  },
  {
    "path": "tests/Classes/Point.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/Point2.php",
    "chars": 718,
    "preview": "<?hh // strict\n\nnamespace NS_Point2;\n\nclass Point2 {\n  private static int $pointCount = 0;\n\n  public float $x;\t\t// Carte"
  },
  {
    "path": "tests/Classes/Point2.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/Point_test1.php",
    "chars": 3724,
    "preview": "<?hh // strict\n\nrequire_once 'Point.php';\nuse NS_Point\\Point;\n\nfunction main(): void {\n  error_reporting(-1);\n\n  echo \"\\"
  },
  {
    "path": "tests/Classes/Serializable.php",
    "chars": 2377,
    "preview": "<?hh // strict\n\nnamespace NS_Serializable;\n\nclass Point implements \\Serializable {\n  private static int $nextId = 1;\n\n  "
  },
  {
    "path": "tests/Classes/Serializable.php.expectf",
    "chars": 172,
    "preview": "\nFatal error: Declaration of NS_Serializable\\Point::unserialize() must be compatible with that of Serializable::unserial"
  },
  {
    "path": "tests/Classes/Serializable_with_untrusted_data.php",
    "chars": 2912,
    "preview": "// NOT YET IMPLEMENTED IN CHECKER OR ENGINE <?hh // strict\n\nnamespace NS_Serializable_with_untrusted_data;\n\n/*\n   +-----"
  },
  {
    "path": "tests/Classes/Serializable_with_untrusted_data.php.expectf",
    "chars": 181,
    "preview": "\nFatal error: HH mode: content before <?hh (Line: 1, Char: 44)\nsyntax error, unexpected T_HH_ERROR, expecting $end in %s"
  },
  {
    "path": "tests/Classes/Vehicle.php",
    "chars": 124,
    "preview": "<?hh // strict\n\nnamespace NS_Vehicles;\n\nabstract class Vehicle {\n  public abstract function getMaxSpeed(): int;\n\n  // .."
  },
  {
    "path": "tests/Classes/Vehicle.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Classes/Vehicle_test1.php",
    "chars": 353,
    "preview": "<?hh // strict\n\nnamespace NS_Vehicle_test1;\n\nrequire_once 'PassengerJet.php';\n\nfunction main(): void {\n  $pj = new \\NS_V"
  },
  {
    "path": "tests/Classes/Vehicle_test1.php.expect",
    "chars": 54,
    "preview": "$pj's maximum speed: 550\n$pj's maximum altitude: 30000"
  },
  {
    "path": "tests/Classes/__PHP_Incomplete_Class.php",
    "chars": 1003,
    "preview": "<?hh // strict\n\nnamespace NS___PHP_Incomplete_Class;\n\nclass Point {\n  private float $x;\n  private float $y;\n\n  public fu"
  },
  {
    "path": "tests/Classes/abstract_constants.php",
    "chars": 537,
    "preview": "<?hh // strict\n\nnamespace NS_abstract_constants;\n\ninterface I1 {\n  abstract const int CI;\n  abstract const int CI2;\n}\n\ni"
  },
  {
    "path": "tests/Classes/abstract_constants.php.expect",
    "chars": 85,
    "preview": "object(NS_abstract_constants\\C2)#1 (0) {\n}\nobject(NS_abstract_constants\\C3)#1 (0) {\n}"
  },
  {
    "path": "tests/Classes/cc.php",
    "chars": 601,
    "preview": "<?php\n\n/*\n   +-------------------------------------------------------------+\n   | Copyright (c) 2014, 2015 Facebook, Inc"
  },
  {
    "path": "tests/Classes/cc.php.expectf",
    "chars": 14,
    "preview": "int(7)\nint(8)\n"
  },
  {
    "path": "tests/Classes/classes.php",
    "chars": 237,
    "preview": "<?hh // strict\n\nnamespace NS_classes;\n\ninterface I1 {}\ninterface I2 {}\nclass C1 {}\nclass C2 extends C1 implements I1, I2"
  },
  {
    "path": "tests/Classes/classes.php.expect",
    "chars": 31,
    "preview": "object(NS_classes\\C2)#1 (0) {\n}"
  },
  {
    "path": "tests/Classes/cloning.php",
    "chars": 1744,
    "preview": "<?hh // strict\n\nnamespace NS_cloning;\n\nrequire_once 'Point2.php';\nuse NS_Point2\\Point2;\n\nclass C {\n  private int $m;\n  p"
  },
  {
    "path": "tests/Classes/cloning.php.expect",
    "chars": 1251,
    "preview": "object(NS_cloning\\C)#1 (1) {\n  [\"m\":\"NS_cloning\\C\":private]=>\n  int(10)\n}\nInside NS_cloning\\C::__clone\nobject(NS_cloning"
  },
  {
    "path": "tests/Classes/constructors.php",
    "chars": 3816,
    "preview": "<?hh // strict\n\nnamespace NS_constructors;\n\nclass D1 {\n  public function __construct(int $p1) {\n    echo \"In D1 construc"
  },
  {
    "path": "tests/Classes/constructors.php.expect",
    "chars": 350,
    "preview": "In D1 constructor, 1\nIn D2 constructor, 1, 2\nIn D3 constructor, 1, 2, 3\nIn D4 constructor\nobject(NS_constructors\\C2)#2 ("
  },
  {
    "path": "tests/Classes/destructors.php",
    "chars": 675,
    "preview": "<?hh // strict\n\nnamespace NS_destructors;\n\nclass D1 {\n  private function __destruct() {\n    echo \"In D1 destructor\\n\";\n "
  },
  {
    "path": "tests/Classes/destructors.php.expect",
    "chars": 50,
    "preview": "In D4 destructor\nIn D3 destructor\nIn D2 destructor"
  },
  {
    "path": "tests/Classes/dynamic_methods.php",
    "chars": 757,
    "preview": "<?hh // strict\n\nnamespace NS_dynamic_methods;\n\nclass Widget {\n  public function __call(string $name, array<mixed> $argum"
  },
  {
    "path": "tests/Classes/dynamic_methods.php.expect",
    "chars": 319,
    "preview": "Calling instance method >iMethod<\narray(3) {\n  [0]=>\n  int(10)\n  [1]=>\n  bool(true)\n  [2]=>\n  string(3) \"abc\"\n}\nCalling "
  },
  {
    "path": "tests/Classes/invoke.php",
    "chars": 318,
    "preview": "<?hh // strict\n\nnamespace NS_invoke;\n\nclass C {\n  public function __invoke(): void {\n    echo \"Inside \" . __METHOD__ . \""
  },
  {
    "path": "tests/Classes/invoke.php.expect",
    "chars": 10,
    "preview": "bool(true)"
  },
  {
    "path": "tests/Classes/property_initializer.php",
    "chars": 620,
    "preview": "<?hh // strict\n\nnamespace NS_property_initializer;\n\nclass Point {\n  public float $x = -10.0;\t// gets applied before cons"
  },
  {
    "path": "tests/Classes/property_initializer.php.expect",
    "chars": 25,
    "preview": "(0,0)\n(100,0)\n(1000,2000)"
  },
  {
    "path": "tests/Classes/require_extends_implements.php",
    "chars": 1037,
    "preview": "<?hh // strict\n\nnamespace NS_require_extends_implements;\n\nclass B {\n}\n\nclass C extends B {\n}\n\n/* While multiple class ty"
  },
  {
    "path": "tests/Classes/require_extends_implements.php.expectf",
    "chars": 104,
    "preview": "\nFatal error: Traits cannot have constants in %s/tests/Classes/require_extends_implements.php on line 35"
  },
  {
    "path": "tests/Classes/sleep_and_wakeup.php",
    "chars": 3542,
    "preview": "<?hh // strict\n\nnamespace NS_sleep_and_wakeup;\n\nclass Point {\n  private static int $pointCount = 0;\n  private static int"
  },
  {
    "path": "tests/Classes/test_for_new_types.php",
    "chars": 339,
    "preview": "<?hh // strict\n\nnamespace NS_test_for_new_types;\n\nfunction main(): void {\n//  new \\ArithmeticError();\n//  new \\Assertion"
  },
  {
    "path": "tests/Classes/test_for_new_types.php.expectf",
    "chars": 145,
    "preview": "\nFatal error: syntax error, unexpected T_LNUMBER, expecting T_VARIABLE or T_PIPE_VAR or '$' in %s/tests/Classes/test_for"
  },
  {
    "path": "tests/Classes/type_constants.php",
    "chars": 9702,
    "preview": "<?hh // strict\n\nnamespace NS_type_constants;\n\n// ---------------------------------------------------------------------\n\n"
  },
  {
    "path": "tests/Classes/type_constants.php.expect",
    "chars": 24,
    "preview": "string(3) \"abc\"\nint(123)"
  },
  {
    "path": "tests/Classes/visibility.php",
    "chars": 4570,
    "preview": "<?hh // strict\n\nnamespace NS_visibility;\n\nclass C {\n// constants\n\n  const int CON1 = 123;\t\t// implicitly static, and can"
  },
  {
    "path": "tests/Classes/visibility.php.expect",
    "chars": 16,
    "preview": "CON1: 123\nint(0)"
  },
  {
    "path": "tests/Collections/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Collections/collections_intrinsics_list.php",
    "chars": 2199,
    "preview": "<?hh // strict\n\nnamespace NS_intrinsics;\n\nfunction main(): void {\n  echo \"--------- test with full and omitted LHS vars "
  },
  {
    "path": "tests/Collections/collections_intrinsics_list.php.expect",
    "chars": 1369,
    "preview": "--------- test with full and omitted LHS vars -------------\n$min: 0, $max: 100, $avg: 67\nHH\\Vector Object\n(\n    [0] => 0"
  },
  {
    "path": "tests/Collections/collections_operations.php",
    "chars": 12300,
    "preview": "<?hh // strict\n\nnamespace NS_collections_operations;\n\nclass C {}\n\nfunction main(int $idx): void {\n//  $str = \"Hello\";\n//"
  },
  {
    "path": "tests/Collections/collections_operations.php.expect",
    "chars": 3808,
    "preview": "========================== Vector =======================\n$v1[1] = 10\nobject(HH\\Vector)#1 (4) {\n  [0]=>\n  int(-5)\n  [1]="
  },
  {
    "path": "tests/Collections/vector.php",
    "chars": 2038,
    "preview": "<?hh // strict\n\nnamespace NS_vector;\n\nclass C {\n  public array<int> $pr1;\n  public function __construct() {\n    $this->p"
  },
  {
    "path": "tests/Collections/vector.php.expect",
    "chars": 1388,
    "preview": "object(HH\\Vector)#1 (0) {\n}\n$v1 = is empty\nobject(HH\\Vector)#2 (0) {\n}\n$v1's element count = 0\nobject(HH\\Vector)#3 (0) {"
  },
  {
    "path": "tests/Constants/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Constants/Testfile.txt",
    "chars": 90,
    "preview": "Once upon a time,\nin a land\nfar,   \nfar away,  \nthere lived an ogre called Big Bad Bruce.\n"
  },
  {
    "path": "tests/Constants/constants.php",
    "chars": 3622,
    "preview": "<?hh // strict\n\nnamespace NS_constants;\n\nfunction trace(string $name, mixed $value, bool $b = false): void {\n  $r = defi"
  },
  {
    "path": "tests/Constants/constants.php.expect",
    "chars": 492,
    "preview": "define CON1 succeeded; value is >35.3<\ndefine CON2 succeeded; value is >15<\ndefine CON3 succeeded; value is >15<\ndefine "
  },
  {
    "path": "tests/Constants/context_dependent_constants.php",
    "chars": 2625,
    "preview": "<?hh // strict\n\nnamespace NS_context_dependent_constants;\n\nfunction ComputeResult(): void {\n  echo \"Inside ComputeResult"
  },
  {
    "path": "tests/Constants/context_dependent_constants.php.expectf",
    "chars": 1892,
    "preview": "__LINE__: int(70)\n__FILE__: string(%d) \"%s/tests/Constants/context_dependent_constants.php\"\n__DIR__: string(%d) \"%s/test"
  },
  {
    "path": "tests/Constants/core_predefined_constants.php",
    "chars": 1645,
    "preview": "<?hh // strict\n\nnamespace NS_core_predefined_constants;\n\nfunction main(): void {\n//  $v = __COMPILER_HALT_OFFSET__;\n//  "
  },
  {
    "path": "tests/Constants/core_predefined_constants.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Enums/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Enums/enum_constraints.php",
    "chars": 1321,
    "preview": "<?hh // strict\n\nnamespace NS_enum_constraints;\n\nenum E2: int { Z = 12; }\nenum E3: string { X = 'aa'; }\n\n//enum E: int as"
  },
  {
    "path": "tests/Enums/enum_constraints.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Enums/enums.php",
    "chars": 9780,
    "preview": "<?hh // strict\n\nnamespace NS_enum;\n\nenum BitFlags: int as int {\n  F2 = BitFlags::F1 << 1;\n  F3 = BitFlags::F2 << 1;\n  F1"
  },
  {
    "path": "tests/Enums/enums.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Enums/enums_ops.php",
    "chars": 3208,
    "preview": "<?hh // strict\n\nnamespace NS_enum_ops;\n\nenum Status: int {\n  Stopped = 0;\n  Stopping = 1;\n  Starting = 2;\n  Started = 3;"
  },
  {
    "path": "tests/Enums/enums_ops.php.expect",
    "chars": 235,
    "preview": "\n====== various operations on int and string enums  ======\n\n\n______ <\nbool(true)\n______ >=\nbool(false)\n\n______ <\nbool(fa"
  },
  {
    "path": "tests/Enums/string_int_equality_problem.php",
    "chars": 1190,
    "preview": "<?hh // strict\n\nnamespace NS_string_int_equality_problem;\n\n/* *** mixed enums no longer allowed\n\nenum E5: mixed {\n  Read"
  },
  {
    "path": "tests/Enums/string_int_equality_problem.php.expectf",
    "chars": 139,
    "preview": "\nFatal error: Call to undefined function NS_string_int_equality_problem\\main() in %s/tests/Enums/string_int_equality_pro"
  },
  {
    "path": "tests/Exception_Handling/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Exception_Handling/Exception_class.php",
    "chars": 3178,
    "preview": "<?hh // strict\n\nnamespace NS_Exception_class;\n\nfunction displayExceptionObject(\\Exception $e): void {\n  echo \"\\$e = >$e<"
  },
  {
    "path": "tests/Exception_Handling/Exception_class.php.expectf",
    "chars": 7811,
    "preview": "L0: In try-block\nL0: In catch-block\n$e = >exception 'Exception' with message 'L0 Message' in %s/tests/Exception_Handling"
  },
  {
    "path": "tests/Exception_Handling/MyRangeException.php",
    "chars": 835,
    "preview": "<?hh // strict\n\nnamespace NS_MyRangeException;\n\nclass MyRangeException extends \\Exception {\n  private int $badValue;\n  p"
  },
  {
    "path": "tests/Exception_Handling/MyRangeException.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Exception_Handling/MyRangeException_test1.php",
    "chars": 303,
    "preview": "<?hh // strict\n\nnamespace NS_MyRangeException_test1;\n\nrequire_once 'MyRangeException.php';\n\nfunction main(): void {\n  $r"
  },
  {
    "path": "tests/Exception_Handling/MyRangeException_test1.php.expectf",
    "chars": 1201,
    "preview": "object(NS_MyRangeException\\MyRangeException)#1 (10) {\n  [\"badValue\":\"NS_MyRangeException\\MyRangeException\":private]=>\n  "
  },
  {
    "path": "tests/Exception_Handling/hierarchy_of_exception_classes.php",
    "chars": 1344,
    "preview": "<?hh // strict\n\nnamespace NS_hierarchy_of_exception_classes;\n\nclass DeviceException extends \\Exception { /*...*/ }\nclass"
  },
  {
    "path": "tests/Exception_Handling/hierarchy_of_exception_classes.php.expect",
    "chars": 47,
    "preview": "In handler for DeviceException\nIn finally block"
  },
  {
    "path": "tests/Exception_Handling/jump_from_catch_or_finally_clause.php",
    "chars": 750,
    "preview": "<?hh // strict\n\nnamespace NS_jump_from_catch_or_finally_clause;\n\nfunction msg(): int {\n  echo \"In msg\\n\";\n  return 999;\n"
  },
  {
    "path": "tests/Exception_Handling/jump_from_catch_or_finally_clause.php.expect",
    "chars": 90,
    "preview": "In handler for Exception\nIn finally block\nIn handler for Exception\nIn finally block\nint(1)"
  },
  {
    "path": "tests/Exception_Handling/odds_and_ends.php",
    "chars": 1182,
    "preview": "<?hh // strict\n\nnamespace NS_odds_and_ends;\n\nclass X {}\t// not derived from \\Exception\n\nclass Except extends \\Exception "
  },
  {
    "path": "tests/Exception_Handling/odds_and_ends.php.expect",
    "chars": 161,
    "preview": "L0: In try-block\nL0: In catch-block Exception\nL0: In finally-block\n$o->prop = 100\nIn try-block\nIn catch-block Except\n$e-"
  },
  {
    "path": "tests/Exception_Handling/set_exception_handler.php",
    "chars": 2063,
    "preview": "<?hh // strict\n\nnamespace NS_set_exception_handler;\n\nfunction displayExceptionObject(\\Exception $e): void {\n  echo \"\\$e "
  },
  {
    "path": "tests/Exception_Handling/set_exception_handler.php.expectf",
    "chars": 1750,
    "preview": "NULL\nNULL\nAbout to call f\nIn f's try-block\nIn f's finally-block\nIn MyDefExHandler\n$e = >exception 'Exception' with messa"
  },
  {
    "path": "tests/Expressions/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Additive_Operators/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Additive_Operators/addition_subtraction_concatenation.php",
    "chars": 858,
    "preview": "<?hh // strict\n\nnamespace NS_addition_subtraction_concatenation;\n\nfunction doit(num $p1_num): void {\n  $oper = array(100"
  },
  {
    "path": "tests/Expressions/Additive_Operators/addition_subtraction_concatenation.php.expect",
    "chars": 3626,
    "preview": ">100< + >100<, result: int(200)\n>100< + >-3.4<, result: float(96.6)\n>100< + >11<, result: int(111)\n---------------------"
  },
  {
    "path": "tests/Expressions/Additive_Operators/array_concatenation.php",
    "chars": 2478,
    "preview": "<?hh // strict\n\nnamespace NS_array_concatenation;\n\nclass Button {}\nclass CustomButton extends Button {}\n\nfunction array_"
  },
  {
    "path": "tests/Expressions/Additive_Operators/array_concatenation.php.expect",
    "chars": 841,
    "preview": "============= vector-like arrays ================\nresult of p1 + p2 = array(2) {\n  [0]=>\n  int(66)\n  [1]=>\n  int(200)\n}\n"
  },
  {
    "path": "tests/Expressions/Binary_Logical_Operators/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Binary_Logical_Operators/binary_logical_operators.php",
    "chars": 965,
    "preview": "<?hh // strict\n\nnamespace NS_binary_logical_operators;\n\nfunction f(int $a): int { echo \"inside f(int $a)\\n\"; return 10;}"
  },
  {
    "path": "tests/Expressions/Binary_Logical_Operators/binary_logical_operators.php.expect",
    "chars": 184,
    "preview": "$month 6 is in-bounds\n$month 14 is out-of-bounds\n$month 6 is in-bounds\n$month 14 is out-of-bounds\ninside f(int 5)\ninside"
  },
  {
    "path": "tests/Expressions/Bitwise_Shift_Operators/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Bitwise_Shift_Operators/bitwise_shift.php",
    "chars": 1498,
    "preview": "<?hh // strict\n\nnamespace NS_bitwise_shift;\n\nfunction main(): void {\n  $i32 = 1 << 31;\t// if this is negative, we have a"
  },
  {
    "path": "tests/Expressions/Bitwise_Shift_Operators/bitwise_shift.php.expect",
    "chars": 18863,
    "preview": "1000(000003E8): >> -65 = 00000000\t<< -65 = 00000000\n1000(000003E8): >> -64 = 000003E8\t<< -64 = 000003E8\n1000(000003E8): "
  },
  {
    "path": "tests/Expressions/Bitwise_and_or_xor_Operators/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Bitwise_and_or_xor_Operators/bitwise_and_or_xor.php",
    "chars": 1612,
    "preview": "<?hh // strict\n\nnamespace NS_bitwise_and_or_xor;\n\nfunction main(): void {\n///*\n  echo \"======= check for even/odd intege"
  },
  {
    "path": "tests/Expressions/Bitwise_and_or_xor_Operators/bitwise_and_or_xor.php.expect",
    "chars": 735,
    "preview": "======= check for even/odd integer values by inspecting the low-order bit ========\n-5 is odd\n-4 is even\n-3 is odd\n-2 is "
  },
  {
    "path": "tests/Expressions/Coalesce Operator/coalesce.php",
    "chars": 1035,
    "preview": "<?hh // strict\n\nnamespace NS_coalesce;\n\n/*\n   +-------------------------------------------------------------+\n   | Copyr"
  },
  {
    "path": "tests/Expressions/Coalesce Operator/coalesce.php.expect",
    "chars": 11,
    "preview": "bool(true)\n"
  },
  {
    "path": "tests/Expressions/Conditional_Operator/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Conditional_Operator/conditional.php",
    "chars": 1462,
    "preview": "<?hh // strict\n\nnamespace NS_conditional;\n\nfunction f(int $a): int { echo \"inside f(int $a)\\n\"; return 0;}\n\nfunction mai"
  },
  {
    "path": "tests/Expressions/Conditional_Operator/conditional.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Equality_Operators/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Equality_Operators/Testfile1.txt",
    "chars": 90,
    "preview": "Once upon a time,\nin a land\nfar,   \nfar away,  \nthere lived an ogre called Big Bad Bruce.\n"
  },
  {
    "path": "tests/Expressions/Equality_Operators/Testfile2.txt",
    "chars": 90,
    "preview": "Once upon a time,\nin a land\nfar,   \nfar away,  \nthere lived an ogre called Big Bad Bruce.\n"
  },
  {
    "path": "tests/Expressions/Equality_Operators/comparisons.php",
    "chars": 6235,
    "preview": "<?hh // strict\n\nnamespace NS_equality_comparisons;\n\nfunction doit1(num $p1_num, ?int $p2_nint): void {\n/*\n  echo \"======"
  },
  {
    "path": "tests/Expressions/Equality_Operators/comparisons.php.expect",
    "chars": 446,
    "preview": "qq============= map-like arrays ================\nresult of p1 == p7 = bool(false)\nresult of p8 == p9 = bool(false)\nresul"
  },
  {
    "path": "tests/Expressions/Equality_Operators/equality_comparison_of_objects.php",
    "chars": 2014,
    "preview": "<?hh // strict\n\nnamespace NS_equality_comparison_of_objects;\n\nclass C1 {}\nclass C2 {}\nclass C3 { public int $x = -1; }\nc"
  },
  {
    "path": "tests/Expressions/Equality_Operators/equality_comparison_of_objects.php.expect",
    "chars": 624,
    "preview": "\n===== compare instances of different object types =====\n\nbool(false)\nbool(false)\nbool(true)\nbool(true)\n\n===== compare i"
  },
  {
    "path": "tests/Expressions/Instanceof_Operator/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Instanceof_Operator/instanceof.php",
    "chars": 2720,
    "preview": "<?hh // strict\n\nnamespace NS_instanceof;\n\nclass C1 {}\nclass C2 {}\nclass D extends C1 {}\n\nfunction f1(): D { return new D"
  },
  {
    "path": "tests/Expressions/Instanceof_Operator/instanceof.php.expect",
    "chars": 492,
    "preview": "bool(true)\nbool(false)\nbool(false)\nbool(true)\nbool(true)\nbool(false)\n--------------------\nbool(true)\nbool(false)\nbool(tr"
  },
  {
    "path": "tests/Expressions/Lambda_Expressions/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Lambda_Expressions/lambdas.php",
    "chars": 4386,
    "preview": "<?hh // strict\n\nnamespace NS_lambdas;\n\nfunction concatStr(): (function (string): string) {\n  $x = 'XX:';\n  return functi"
  },
  {
    "path": "tests/Expressions/Lambda_Expressions/lambdas.php.expectf",
    "chars": 1699,
    "preview": "-------------- anonymous function concatStr ----------------\n\nXX:blue\nXX:green\n\n-------------- lam1 ----------------\n\nin"
  },
  {
    "path": "tests/Expressions/Multiplicative_Operators/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Multiplicative_Operators/multiplication_division_modulus.php",
    "chars": 1270,
    "preview": "<?hh // strict\n\nnamespace NS_multiplication_division_modulus;\n\nfunction doit(num $p1_num): void {\n  $oper = array(100, -"
  },
  {
    "path": "tests/Expressions/Multiplicative_Operators/multiplication_division_modulus.php.expect",
    "chars": 219,
    "preview": ">100< % >100<, result: int(0)\n>100< % >-3<, result: int(1)\n-------------------------------------\n>-3< % >100<, result: i"
  },
  {
    "path": "tests/Expressions/Null_safe_method_call/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Null_safe_method_call/null_safe_calls.php",
    "chars": 1440,
    "preview": "<?hh // strict\n\nnamespace NS_null_safe_calls;\n\nclass D {}\n\nclass C {\n  public function f1(int $m, int $n): D {\n    echo "
  },
  {
    "path": "tests/Expressions/Null_safe_method_call/null_safe_calls.php.expect",
    "chars": 678,
    "preview": "------------ test(new C())\n------------ $x?->f1(++$i, hello($i))\nInside NS_null_safe_calls\\hello; $j = 6\nInside NS_null_"
  },
  {
    "path": "tests/Expressions/Pipe_Operator/pipe.php",
    "chars": 4037,
    "preview": "<?hh // strict\n\nnamespace NS_pipe;\n\nfunction fint(int $p): int {\n  echo \"Inside \" . __FUNCTION__ . \"; returning \" . ($p "
  },
  {
    "path": "tests/Expressions/Pipe_Operator/pipe.php.expect",
    "chars": 1916,
    "preview": "\n\n========================= Simple Use =========================\n\nint(20)\nint(20)\nfloat(1.23)\nstring(3) \"abc\"\nInside NS_"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/.hhconfig",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Postfix_Operators/array_creation.php",
    "chars": 208,
    "preview": "<?hh // strict\n\nnamespace NS_array_creation;\n\nfunction main(): void {\n  $a = [1 => 10, 'xx' => 20, 4.5 => 30, false => 4"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/array_creation.php.expect",
    "chars": 107,
    "preview": "array(5) {\n  [1]=>\n  int(10)\n  [\"xx\"]=>\n  int(20)\n  [4]=>\n  int(30)\n  [0]=>\n  int(40)\n  [-10]=>\n  int(50)\n}"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/exponentiation.php",
    "chars": 1284,
    "preview": "<?hh // strict\n\nnamespace NS_exponentiation;\n\nclass C {\n  public float $prop = 12.0;\n}\n\nfunction f(): int { return 3; }\n"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/exponentiation.php.expect",
    "chars": 40,
    "preview": "=========== some basic tests ==========="
  },
  {
    "path": "tests/Expressions/Postfix_Operators/function_call.php",
    "chars": 1380,
    "preview": "<?hh // strict\n\nnamespace NS_function_call;\n\nfunction f(): void {\n  echo \"Inside function \" . __FUNCTION__ . \"\\n\";\n}\n\nfu"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/function_call.php.expect",
    "chars": 50,
    "preview": "Inside function NS_function_call\\f\n2, 3, 3, 12, 11"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/function_call_with_strict_checking.php",
    "chars": 525,
    "preview": "<?php\n\n/*\n   +-------------------------------------------------------------+\n   | Copyright (c) 2015-2016 Facebook, Inc."
  },
  {
    "path": "tests/Expressions/Postfix_Operators/function_call_with_strict_checking.php.expectf",
    "chars": 169,
    "preview": "\nFatal error: strict_types can only be used when hhvm.php7.scalar_types = true in %s/tests/Expressions/Postfix_Operators"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/member_selection_operator.php",
    "chars": 1879,
    "preview": "<?hh // strict\n\nnamespace NS_member_selection_operator;\n\nclass Point {\n  private float $x;\n  private float $y;\n\n  public"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/member_selection_operator.php.expect",
    "chars": 84,
    "preview": "$p1 is >(0,0)<\n$p1 is >(3,9)<\nint(555)\nint(123)\nint(999)\nfloat(3.14159)\nHello from f"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/new.php",
    "chars": 200,
    "preview": "<?hh // strict\n\nnamespace NS_new;\n\nclass C {}\n\nfunction main(): void {\n\t$c1 = new C();\n//\t$c1 = new 'C'();\n//\t$name = 'C"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/new.php.expect",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/Expressions/Postfix_Operators/new_anonymous_classes.php",
    "chars": 2042,
    "preview": "// NOT YET IMPLEMENTED IN THE CHECKER <?hh // strict\n\nnamespace NS_new_anonymous_classes;\n\n/*\n   +----------------------"
  },
  {
    "path": "tests/Expressions/Postfix_Operators/new_anonymous_classes.php.expectf",
    "chars": 192,
    "preview": "\nFatal error: HH mode: content before <?hh (Line: 1, Char: 38)\nsyntax error, unexpected T_HH_ERROR, expecting $end in %s"
  }
]

// ... and 328 more files (download for full content)

About this extraction

This page contains the full source code of the hhvm/hack-langspec GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 528 files (1.5 MB), approximately 472.4k tokens, and a symbol index with 1335 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!