2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
24 #include <boost/variant.hpp>
25 #include <tbb/concurrent_hash_map.h>
27 #include <folly/synchronization/Baton.h>
28 #include <folly/Hash.h>
30 #include "hphp/util/compact-vector.h"
31 #include "hphp/util/either.h"
32 #include "hphp/util/tribool.h"
34 #include "hphp/runtime/base/repo-auth-type-array.h"
35 #include "hphp/runtime/vm/type-constraint.h"
37 #include "hphp/hhbbc/hhbbc.h"
38 #include "hphp/hhbbc/misc.h"
40 namespace HPHP
{ namespace HHBBC
{
42 //////////////////////////////////////////////////////////////////////
46 struct PublicSPropMutations
;
47 struct FuncAnalysisResult
;
51 struct PropertiesInfo
;
54 struct TypeStructureResolution
;
56 extern const Type TCell
;
68 //////////////////////////////////////////////////////////////////////
71 * This module contains functions for building and querying an Index
72 * of data relating to "resolved" versions of the names in of a
73 * php::Program. It also records dependencies so it is possible to
74 * tell which parts of the program may be interested in new inferred
75 * information about other parts of the program.
77 * The main entry point here is the Index class. The Index is built
78 * after parse time, and then analysis can query it for information.
81 //////////////////////////////////////////////////////////////////////
83 enum class Dep
: uintptr_t {
84 /* This dependency should trigger when the return type changes */
86 /* This dependency should trigger when a DefCns is resolved */
88 /* This dependency should trigger when a class constant is resolved */
90 /* This dependency should trigger when the bad initial prop value bit for a
92 PropBadInitialValues
= (1u << 3),
93 /* This dependency should trigger when a public static property changes */
94 PublicSProp
= (1u << 4),
95 /* This dependency means that we refused to do inline analysis on
96 * this function due to inline analysis depth. The dependency will
97 * trigger if the target function becomes effect-free, or gets a
98 * literal return value.
100 InlineDepthLimit
= (1u << 5),
104 * A DependencyContext encodes enough of the context to record a dependency - a
105 * php::Func, if we're doing private property analysis and its a suitable class,
106 * a php::Class, or a public static property.
109 enum class DependencyContextType
: uint16_t {
116 using DependencyContext
= CompactTaggedPtr
<const void, DependencyContextType
>;
118 struct DependencyContextLess
{
119 bool operator()(const DependencyContext
& a
,
120 const DependencyContext
& b
) const {
121 return a
.getOpaque() < b
.getOpaque();
125 struct DependencyContextEquals
{
126 bool operator()(const DependencyContext
& a
,
127 const DependencyContext
& b
) const {
128 return a
.getOpaque() == b
.getOpaque();
132 struct DependencyContextHash
{
133 size_t operator()(const DependencyContext
& d
) const {
134 return pointer_hash
<void>{}(reinterpret_cast<void*>(d
.getOpaque()));
138 struct DependencyContextHashCompare
: DependencyContextHash
{
139 bool equal(const DependencyContext
& a
, const DependencyContext
& b
) const {
140 return a
.getOpaque() == b
.getOpaque();
142 size_t hash(const DependencyContext
& d
) const { return (*this)(d
); }
145 using DependencyContextSet
= hphp_hash_set
<DependencyContext
,
146 DependencyContextHash
,
147 DependencyContextEquals
>;
148 using ContextSet
= hphp_hash_set
<Context
, ContextHash
>;
150 std::string
show(Context
);
152 using ConstantMap
= hphp_hash_map
<SString
, TypedValue
>;
155 * State of properties on a class. Map from property name to its
158 template <typename T
= Type
> // NB: The template param here is to
159 // break a cyclic dependency on Type.
160 struct PropStateElem
{
162 const TypeConstraint
* tc
= nullptr;
166 bool operator==(const PropStateElem
<T
>& o
) const {
171 everModified
== o
.everModified
;
174 using PropState
= std::map
<LSString
,PropStateElem
<>>;
177 * The result of Index::lookup_static
179 template <typename T
= Type
> // NB: The template parameter is here to
180 // break a cyclic dependency on Type.
181 struct PropLookupResult
{
182 T ty
; // The best known type of the property (TBottom if not found)
183 SString name
; // The statically known name of the string, if any
184 TriBool found
; // If the property was found
185 TriBool isConst
; // If the property is AttrConst
186 TriBool readOnly
; // If the property is AttrIsReadonly
187 TriBool lateInit
; // If the property is AttrLateInit
188 bool classInitMightRaise
; // If class initialization during the
189 // property access can raise (unlike the
190 // others, this is only no or maybe).
193 template <typename T
>
194 inline PropLookupResult
<T
>& operator|=(PropLookupResult
<T
>& a
,
195 const PropLookupResult
<T
>& b
) {
196 assertx(a
.name
== b
.name
);
199 a
.isConst
|= b
.isConst
;
200 a
.readOnly
|= b
.readOnly
;
201 a
.lateInit
|= b
.lateInit
;
202 a
.classInitMightRaise
|= b
.classInitMightRaise
;
206 std::string
show(const PropLookupResult
<Type
>&);
209 * The result of Index::merge_static_type
211 template <typename T
= Type
> // NB: The template parameter is here to
212 // break a cyclic dependency on Type
213 struct PropMergeResult
{
214 T adjusted
; // The merged type, potentially adjusted according to
215 // the prop's type-constraint (it's the subtype of the
216 // merged type that would succeed).
217 TriBool throws
; // Whether the mutation this merge represents
221 template <typename T
>
222 inline PropMergeResult
<T
>& operator|=(PropMergeResult
<T
>& a
,
223 const PropMergeResult
<T
>& b
) {
224 a
.adjusted
|= b
.adjusted
;
225 a
.throws
|= b
.throws
;
229 std::string
show(const PropMergeResult
<Type
>&);
232 * The result of Index::lookup_class_constant
234 template <typename T
= Type
> // NB: The template parameter is here to
235 // break a cyclic dependency on Type
236 struct ClsConstLookupResult
{
237 T ty
; // The best known type of the constant (might not be a
239 TriBool found
; // If the constant was found
240 bool mightThrow
; // If accessing the constant can throw
243 template <typename T
>
244 inline ClsConstLookupResult
<T
>& operator|=(ClsConstLookupResult
<T
>& a
,
245 const ClsConstLookupResult
<T
>& b
) {
248 a
.mightThrow
|= b
.mightThrow
;
252 std::string
show(const ClsConstLookupResult
<Type
>&);
255 * The result of Index::lookup_class_type_constant
257 template <typename T
= TypeStructureResolution
>
258 struct ClsTypeConstLookupResult
{
259 T resolution
; // The result from resolving the type-structure
260 TriBool found
; // If the constant was found
261 TriBool abstract
; // If the constant was abstract (this only applies
262 // to the subset which wasn't found).
265 template <typename T
>
266 inline ClsTypeConstLookupResult
<T
>& operator|=(
267 ClsTypeConstLookupResult
<T
>& a
,
268 const ClsTypeConstLookupResult
<T
>& b
) {
269 a
.resolution
|= b
.resolution
;
270 if (a
.found
== TriBool::Yes
) {
271 a
.abstract
= b
.abstract
;
272 } else if (b
.found
!= TriBool::Yes
) {
273 a
.abstract
|= b
.abstract
;
279 std::string
show(const ClsTypeConstLookupResult
<TypeStructureResolution
>&);
281 //////////////////////////////////////////////////////////////////////
286 //////////////////////////////////////////////////////////////////////
289 * References to "resolved" entities with information in the index are
290 * in the res:: namespace.
292 * These represent handles to program entities that may have variable
293 * amounts of information. For example, we may know the name of a
294 * class in a res::Class, but do not know for sure which php::Class
295 * struct is actually associated with it.
300 * A resolved runtime Class, for a particular php::Class.
302 * Provides various lookup tables that allow querying the Class'
307 * Returns whether two classes are definitely same at runtime. If
308 * this function returns false, they still *may* be the same at
311 bool same(const Class
&) const;
314 * Returns true if this class is definitely going to be a subtype
315 * of `o' at runtime. If this function returns false, this may
316 * still be a subtype of `o' at runtime, it just may not be known.
317 * A typical example is with "non unique" classes.
319 bool mustBeSubtypeOf(const Class
& o
) const;
322 * Returns false if this class is definitely not going to be a subtype
323 * of `o' at runtime. If this function returns true, this may
324 * still not be a subtype of `o' at runtime, it just may not be known.
325 * A typical example is with "non unique" classes.
327 bool maybeSubtypeOf(const Class
& o
) const;
330 * If this function return false, it is known that this class
331 * is in no subtype relationship with the argument Class 'o'.
332 * Returns true if this class could be a subtype of `o' at runtime.
333 * When true is returned the two classes may still be unrelated but it is
334 * not possible to tell. A typical example is with "non unique" classes.
336 bool couldBe(const Class
& o
) const;
339 * Returns the name of this class. Non-null guarantee.
341 SString
name() const;
344 * Whether this class could possibly be an interface/interface or trait.
346 * True means it might be, false means it is not.
348 bool couldBeInterface() const;
351 * Whether this class must be an interface.
353 * True means it is, false means it might not be.
355 bool mustBeInterface() const;
357 * Returns whether this type has the no override attribute, that is, if it
358 * is a final class (explicitly marked by the user or known by the static
361 * When returning false the class is guaranteed to be final. When returning
362 * true the system cannot tell though the class may still be final.
364 bool couldBeOverriden() const;
367 * Whether this class (or its subtypes) could possibly have have
368 * a magic toBoolean() method.
370 bool couldHaveMagicBool() const;
373 * Whether this class could possibly have a derived class that is mocked.
376 bool couldHaveMockedDerivedClass() const;
379 * Whether this class could possibly be mocked.
381 bool couldBeMocked() const;
384 * Whether this class could have reified generics
386 bool couldHaveReifiedGenerics() const;
389 * Returns whether this resolved class might distinguish being constructed
390 * dynamically versus being constructed normally (IE, might raise a notice).
392 bool mightCareAboutDynConstructs() const;
395 * Whether this class (or clases derived from it) could have const props.
397 bool couldHaveConstProp() const;
398 bool derivedCouldHaveConstProp() const;
401 * Returns the Class that is the first common ancestor between 'this' and 'o'.
402 * If there is no common ancestor std::nullopt is returned
404 Optional
<Class
> commonAncestor(const Class
& o
) const;
407 * Returns the res::Class for this Class's parent if there is one,
410 Optional
<Class
> parent() const;
413 * Returns true if we have a ClassInfo for this Class.
415 bool resolved() const {
416 return val
.right() != nullptr;
420 * Returns the php::Class for this Class if there is one, or
423 const php::Class
* cls() const;
426 * Invoke the given function on every possible subclass of this
427 * class. This must be a resolved class.
429 void forEachSubclass(const std::function
<void(const php::Class
*)>&) const;
432 explicit Class(Either
<SString
,ClassInfo
*>);
433 template <bool> bool subtypeOfImpl(const Class
&) const;
436 friend std::string
show(const Class
&);
437 friend struct ::HPHP::HHBBC::Index
;
438 friend struct ::HPHP::HHBBC::PublicSPropMutations
;
439 Either
<SString
,ClassInfo
*> val
;
443 * This is an abstraction layer to represent possible runtime function
446 * Internally, this may only know the name of the function (or method), or we
447 * may know exactly which source-code-level function it refers to, or we may
448 * only have ruled it down to one of a few functions in a class hierarchy. The
449 * interpreter can treat all these cases the same way using this.
453 * Returns the name of this function. Non-null guarantee.
455 SString
name() const;
458 * If this resolved function represents exactly one php::Func, return it.
460 const php::Func
* exactFunc() const;
463 * Returns whether this resolved function is definitely safe to constant fold.
465 bool isFoldable() const;
468 * Whether this function could have reified generics
470 bool couldHaveReifiedGenerics() const;
473 * Returns whether this resolved function might distinguish being called
474 * dynamically versus being called normally (IE, might raise a notice).
476 bool mightCareAboutDynCalls() const;
479 * Returns whether this resolved function might be a builtin.
481 bool mightBeBuiltin() const;
484 * Minimum/maximum bound on the number of non-variadic parameters of the
487 uint32_t minNonVariadicParams() const;
488 uint32_t maxNonVariadicParams() const;
493 const RuntimeCoeffects
* requiredCoeffects() const;
494 // Returns nullptr if we cant tell whether there are coeffect rules
495 const CompactVector
<CoeffectRule
>* coeffectRules() const;
498 struct MethTabEntryPair
;
502 friend struct ::HPHP::HHBBC::Index
;
504 FuncName(SString n
, bool r
) : name
{n
}, renamable
{r
} {}
505 bool operator==(FuncName o
) const { return name
== o
.name
; }
510 bool operator==(MethodName o
) const { return name
== o
.name
; }
513 using Rep
= boost::variant
< FuncName
516 , const MethTabEntryPair
*
521 Func(const Index
*, Rep
);
522 friend std::string
show(const Func
&);
530 * Produce a trace-able string for a res::Func or res::Class.
532 std::string
show(const Func
&);
533 std::string
show(const Class
&);
537 //////////////////////////////////////////////////////////////////////
540 * This class encapsulates the known facts about the program, with a
541 * whole-program view.
543 * This structure contains unowned pointers into the php::Program it
544 * was created for. It should not out-live the Program.
546 * The const member functions of this class are thread safe for
547 * concurrent reads and writes. The non-const functions should be
548 * called in a single threaded context only (they are used during the
549 * "update" step in between whole program analysis rounds).
553 * Create an Index for a php::Program. Performs some initial
554 * analysis of the program.
556 explicit Index(php::Program
*);
559 * This class must not be destructed after its associated
565 * The index operates in two modes: frozen, and unfrozen.
567 * Conceptually, the index is mutable and may acquire new
568 * information until it has been frozen, and once frozen, it retains
569 * the information it had at the point it was frozen.
571 * The reason this exists is because certain functions on the index
572 * may cause it to need to consult information in the bodies of
573 * functions other than the Context passed in. Specifically, if the
574 * interpreter tries to look up the return type for a callee in a
575 * given CallContext, the index may choose to recursively invoke
576 * type inference on that callee's function body to see if more
577 * precise information can be determined, unless it is frozen.
579 * This is fine until the final pass, because all bytecode is
580 * read-only at that stage. However, in the final pass, other
581 * threads might be optimizing a callee's bytecode and changing it,
582 * so we should not be reading from it to perform type inference
583 * concurrently. Freezing the index tells it it can't do that
586 * These are the functions to query and transition to frozen state.
593 * Throw away data structures that won't be needed during or after
594 * the final pass. Currently the dependency map, which can take a
595 * long time to destroy.
597 void cleanup_for_final();
600 * Throw away data structures that won't be needed after the emit
603 void cleanup_post_emit(php::ProgramPtr program
);
606 * The Index contains a Builder for an ArrayTypeTable.
608 * If we're creating assert types with options.InsertAssertions, we
609 * need to keep track of which array types exist in the whole
610 * program in order to include it in the repo.
612 std::unique_ptr
<ArrayTypeTable::Builder
>& array_table_builder() const;
615 * Find all the closures created inside the context of a given
618 const CompactVector
<const php::Class
*>*
619 lookup_closures(const php::Class
*) const;
622 * Find all the extra methods associated with a class from its
625 const hphp_fast_set
<const php::Func
*>*
626 lookup_extra_methods(const php::Class
*) const;
629 * Try to find a res::Class for a given php::Class.
631 * Note, the returned class may or may not be *defined* at the
632 * program point you care about (it could be non-hoistable, even
633 * though it's unique, for example).
635 * Returns a name-only resolution if there are no legal
636 * instantiations of the class, or if there is more than one.
638 res::Class
resolve_class(const php::Class
*) const;
641 * Try to resolve which class will be the class named `name' from a
642 * given context, if we can resolve it to a single class.
644 * Note, the returned class may or may not be *defined* at the
645 * program point you care about (it could be non-hoistable, even
646 * though it's unique, for example).
648 * Returns std::nullopt if we can't prove the supplied name must be a
649 * object type. (E.g. if there are type aliases.)
651 Optional
<res::Class
> resolve_class(Context
, SString name
) const;
654 * Find a type-alias with the given name. If a nullptr is returned,
655 * then no type-alias exists with that name.
657 const php::TypeAlias
* lookup_type_alias(SString name
) const;
660 * Try to resolve self/parent types for the given context
662 Optional
<res::Class
> selfCls(const Context
& ctx
) const;
663 Optional
<res::Class
> parentCls(const Context
& ctx
) const;
665 template <typename T
>
666 struct ResolvedInfo
{
673 * Try to resolve name, looking through TypeAliases and enums.
675 ResolvedInfo
<Optional
<res::Class
>> resolve_type_name(SString name
) const;
678 * Resolve a closure class.
680 * Returns both a resolved Class, and the actual php::Class for the
683 std::pair
<res::Class
,php::Class
*>
684 resolve_closure_class(Context ctx
, int32_t idx
) const;
687 * Return a resolved class for a builtin class.
689 * Pre: `name' must be the name of a class defined in a systemlib.
691 res::Class
builtin_class(SString name
) const;
694 * Try to resolve a function named `name' from a given context.
696 * Note, the returned function may or may not be defined at the
697 * program point (it could require a function autoload that might
700 res::Func
resolve_func(Context
, SString name
) const;
703 * Try to resolve a class method named `name' with a given Context
706 * Pre: clsType.subtypeOf(BCls)
708 res::Func
resolve_method(Context
, Type clsType
, SString name
) const;
711 * Try to resolve a class constructor for the supplied class type.
713 * Returns: std::nullopt if it can't at least figure out a func
714 * family for the call.
717 resolve_ctor(Context
, res::Class rcls
, bool exact
) const;
720 * Give the Type in our type system that matches an hhvm
721 * TypeConstraint, subject to the information in this Index.
723 * This function returns a subtype of Cell, although TypeConstraints
724 * at runtime can match reference parameters. The caller should
725 * make sure to handle that case.
727 * For soft constraints (@), this function returns Cell.
729 * For some non-soft constraints (such as "Stringish"), this
730 * function may return a Type that is a strict supertype of the
733 * If something is known about the type of the object against which
734 * the constraint will be checked, it can be passed in to help
735 * disambiguate certain constraints (useful because we don't support
736 * arbitrary unions, or intersection).
738 Type
lookup_constraint(Context
, const TypeConstraint
&,
739 const Type
& t
= TCell
) const;
742 * If this function returns true, it is safe to assume that Type t
743 * will always satisfy TypeConstraint tc at run time.
745 bool satisfies_constraint(Context
, const Type
& t
,
746 const TypeConstraint
& tc
) const;
749 * Returns true if the given type-hint (declared on the given class) might not
750 * be enforced at runtime (IE, it might map to mixed or be soft).
752 bool prop_tc_maybe_unenforced(const php::Class
& propCls
,
753 const TypeConstraint
& tc
) const;
756 * Returns true if the type constraint can contain a reified type
757 * Currently, only classes and interfaces are supported
759 bool could_have_reified_type(Context ctx
, const TypeConstraint
& tc
) const;
762 * Lookup metadata about the constant access `cls'::`name', in the
763 * current context `ctx'. The returned metadata not only includes
764 * the best known type of the constant, but whether it is definitely
765 * found, and whether accessing the constant might throw. This
766 * function is responsible for walking the class hierarchy to find
767 * all possible constants and combining the results. This is
768 * intended to be the source of truth about constants during
771 * This function only looks up non-type, non-context constants.
773 ClsConstLookupResult
<>
774 lookup_class_constant(Context ctx
, const Type
& cls
, const Type
& name
) const;
777 * Lookup metadata about the constant access `cls'::`name', where
778 * that constant is meant to be a type-constant. The returned
779 * metadata includes the best known type of the resolved
780 * type-structure, whether it was found, and whether it was
781 * abstract. This is intended to be the source of truth about
782 * type-constants during analysis. The returned type-structure type
783 * will always be static.
785 * By default, lookup_class_type_constant calls
786 * resolve_type_structure to resolve any found type-structure. This
787 * behavior can be overridden by providing a customer resolver.
789 using ClsTypeConstLookupResolver
=
790 std::function
<TypeStructureResolution(const php::Const
&,const php::Class
&)>;
792 ClsTypeConstLookupResult
<>
793 lookup_class_type_constant(
796 const ClsTypeConstLookupResolver
& resolver
= {}) const;
799 * Lookup what the best known Type for a constant would be, using a
800 * given Index and Context, if a constant of that name were defined.
802 Type
lookup_constant(Context ctx
, SString cnsName
) const;
805 * Return true if the return value of the function might depend on arg.
807 bool func_depends_on_arg(const php::Func
* func
, int arg
) const;
810 * If func is effect-free when called with args, and it returns a constant,
811 * return that constant; otherwise return TInitCell.
813 Type
lookup_foldable_return_type(Context ctx
,
814 const php::Func
* func
,
816 CompactVector
<Type
> args
) const;
818 * Return the best known return type for a resolved function, in a
819 * context insensitive way. Returns TInitCell at worst.
821 Type
lookup_return_type(Context
, MethodsInfo
*, res::Func
,
822 Dep dep
= Dep::ReturnTy
) const;
825 * Return the best known return type for a resolved function, given
826 * the supplied calling context. Returns TInitCell at worst.
828 * During analyze phases, this function may re-enter analyze in
829 * order to interpret the callee with these argument types.
831 Type
lookup_return_type(Context caller
,
833 const CompactVector
<Type
>& args
,
836 Dep dep
= Dep::ReturnTy
) const;
839 * Look up raw return type information for an unresolved
840 * function. This is the best known return type, and the number of
841 * refinements done to that type.
843 * This function does not register a dependency on the return type
846 * Nothing may be writing to the index when this function is used,
847 * but concurrent readers are allowed.
849 std::pair
<Type
, size_t> lookup_return_type_raw(const php::Func
*) const;
852 * Return the best known types of a closure's used variables (on
853 * entry to the closure). The function is the closure body.
855 * If move is true, the value will be moved out of the index. This
856 * should only be done at emit time. (note that the only other user
857 * of this info is analysis, which only uses it when processing the
858 * owning class, so its safe to kill after emitting the owning
862 lookup_closure_use_vars(const php::Func
*,
863 bool move
= false) const;
866 * Return the availability of $this on entry to the provided method.
867 * If the Func provided is not a method of a class false is
870 bool lookup_this_available(const php::Func
*) const;
873 * Returns the parameter preparation kind (if known) for parameter
874 * `paramId' on the given resolved Func.
876 PrepKind
lookup_param_prep(Context
, res::Func
, uint32_t paramId
) const;
879 * Returns the number of inout parameters expected by func (if known).
881 Optional
<uint32_t> lookup_num_inout_params(Context
, res::Func
) const;
884 * Returns whether the function's return value is readonly
886 TriBool
lookup_return_readonly(Context
, res::Func
) const;
889 * Returns whether the function is marked as readonly
891 TriBool
lookup_readonly_this(Context
, res::Func
) const;
894 * Returns the control-flow insensitive inferred private instance
895 * property types for a Class. The Class doesn't need to be
896 * resolved, because private properties don't depend on the
897 * inheritance hierarchy.
899 * The Index tracks the largest types for private properties that
900 * are guaranteed to hold at any program point.
902 * If move is true, the value will be moved out of the index. This
903 * should only be done at emit time. (note that the only other user
904 * of this info is analysis, which only uses it when processing the
905 * owning class, so its safe to kill after emitting the owning
908 PropState
lookup_private_props(const php::Class
*,
909 bool move
= false) const;
912 * Returns the control-flow insensitive inferred private static
913 * property types for a Class. The class doesn't need to be
914 * resolved for the same reasons as for instance properties.
916 * The Index tracks the largest types for private static properties
917 * that are guaranteed to hold at any program point.
919 * If move is true, the value will be moved out of the index. This
920 * should only be done at emit time. (note that the only other user
921 * of this info is analysis, which only uses it when processing the
922 * owning class, so its safe to kill after emitting the owning
925 PropState
lookup_private_statics(const php::Class
*,
926 bool move
= false) const;
927 PropState
lookup_public_statics(const php::Class
*) const;
930 * Lookup metadata about the static property access `cls'::`name',
931 * in the current context `ctx'. The returned metadata not only
932 * includes the best known type of the property, but whether it is
933 * definitely found, and whether the access might raise for various
934 * reasons. This function is responsible for walking the class
935 * hierarchy to find the appropriate property while applying
936 * accessibility rules. This is intended to be the source of truth
937 * about static properties during analysis.
939 PropLookupResult
<> lookup_static(Context ctx
,
940 const PropertiesInfo
& privateProps
,
942 const Type
& name
) const;
945 * Lookup if initializing (which is a side-effect of several bytecodes) the
946 * given class might raise.
948 bool lookup_class_init_might_raise(Context
, res::Class
) const;
951 * Lookup the best known type for a public (non-static) property. Since we
952 * don't do analysis on public properties, this just inferred from the
953 * property's type-hint (if enforced).
955 Type
lookup_public_prop(const Type
& cls
, const Type
& name
) const;
956 Type
lookup_public_prop(const php::Class
* cls
, SString name
) const;
959 * We compute the interface vtables in a separate thread. It needs
960 * to be joined (in single threaded context) before calling
961 * lookup_iface_vtable_slot.
963 void join_iface_vtable_thread() const;
966 * Returns the computed vtable slot for the given class, if it's an interface
967 * that was given a vtable slot. No two interfaces implemented by the same
968 * class will share the same vtable slot. May return kInvalidSlot, if the
969 * given class isn't an interface or if it wasn't assigned a slot.
971 Slot
lookup_iface_vtable_slot(const php::Class
*) const;
974 * Return the DependencyContext for ctx.
976 DependencyContext
dependency_context(const Context
& ctx
) const;
979 * Determine whether to use class-at-a-time, or function-at-a-time
982 * Must be called in single-threaded context.
984 void use_class_dependencies(bool f
);
987 * Merge the type `val' into the known type for static property
988 * `cls'::`name'. Depending on what we know about `cls' and `name',
989 * this might affect multiple properties. This function is
990 * responsible for walking the class hierarchy to find the
991 * appropriate property while applying accessibility
992 * rules. Mutations of AttrConst properties are ignored unless
993 * `ignoreConst' is set to true. If `checkUB' is true, upper-bound
994 * type constraints are consulted in addition to the normal type
997 * The result tells you the subtype of val that would be
998 * successfully set (according to the type constraints), and if the
999 * mutation would throw or not.
1001 PropMergeResult
<> merge_static_type(Context ctx
,
1002 PublicSPropMutations
& publicMutations
,
1003 PropertiesInfo
& privateProps
,
1007 bool checkUB
= false,
1008 bool ignoreConst
= false,
1009 bool mustBeReadOnly
= false) const;
1012 * Initialize the initial types for public static properties. This should be
1013 * done after rewriting initial property values, as that affects the types.
1015 void init_public_static_prop_types();
1018 * Initialize the initial "may have bad initial value" bit for
1019 * properties. By initially setting this before analysis, we save
1020 * redundant re-analyzes.
1022 void preinit_bad_initial_prop_values();
1025 * Attempt to pre-resolve as many type-structures as possible in
1026 * type-constants and type-aliases.
1028 void preresolve_type_structures(php::Program
&);
1031 * Refine the types of the class constants defined by an 86cinit,
1032 * based on a round of analysis.
1034 * No other threads should be using ctx.cls->constants or deps when
1035 * this function is called.
1037 * Merges the set of Contexts that depended on the constants defined
1040 void refine_class_constants(
1042 const CompactVector
<std::pair
<size_t, Type
>>& resolved
,
1043 DependencyContextSet
& deps
);
1046 * Refine the types of the constants defined by a function, based on
1047 * a round of analysis.
1049 * Constants not defined by a pseudomain are considered unknowable
1051 * No other threads should be calling functions on this Index when
1052 * this function is called.
1054 * Merges the set of Contexts that depended on the constants defined
1055 * by this php::Func into deps.
1057 void refine_constants(const FuncAnalysisResult
& fa
,
1058 DependencyContextSet
& deps
);
1061 * Refine the return type for a function, based on a round of
1064 * No other threads should be calling functions on this Index when
1065 * this function is called.
1067 * Merges the set of Contexts that depended on the return type of
1068 * this php::Func into deps.
1070 void refine_return_info(const FuncAnalysisResult
& fa
,
1071 DependencyContextSet
& deps
);
1074 * Refine the used var types for a closure, based on a round of
1077 * No other threads should be calling functions on this Index when
1078 * this function is called.
1080 * Returns: true if the types have changed.
1082 bool refine_closure_use_vars(const php::Class
*,
1083 const CompactVector
<Type
>&);
1086 * Refine the private property types for a class, based on a round
1089 * No other threads should be calling functions on this Index when
1090 * this function is called.
1092 void refine_private_props(const php::Class
* cls
,
1096 * Refine the static private property types for a class, based on a
1097 * round of analysis.
1099 * No other threads should be calling functions on this Index when
1100 * this function is called.
1102 void refine_private_statics(const php::Class
* cls
,
1106 * Record in the index that the given set of public static property mutations
1107 * has been found while analyzing the given function. During a round of
1108 * analysis, the mutations are gathered from the analysis results for each
1109 * function, recorded in the index, and then refine_public_statics is called
1110 * to process the mutations and update the index.
1112 * No other threads should be calling functions on this Index when this
1113 * function is called.
1115 void record_public_static_mutations(const php::Func
& func
,
1116 PublicSPropMutations mutations
);
1120 * If we resolve the intial value of a public property, we need to
1121 * tell the refine_public_statics phase about it, because the init
1122 * value won't be included in the mutations any more.
1124 * Note that we can't modify the initial value here, because other
1125 * threads might be reading it (via loookup_public_static), so we
1126 * set a flag to tell us to update it during the next
1127 * refine_public_statics pass.
1129 void update_static_prop_init_val(const php::Class
* cls
,
1130 SString name
) const;
1132 * After a round of analysis with all the public static property mutations
1133 * being recorded with record_public_static_mutations, the types can be
1134 * reflected into the index for use during another type inference pass.
1136 * No other threads should be calling functions on this Index when this
1137 * function is called.
1139 * Merges the set of Contexts that depended on a public static property whose
1142 void refine_public_statics(DependencyContextSet
& deps
);
1145 * Refine whether the given class has properties with initial values which
1146 * might violate their type-hints.
1148 * No other threads should be calling functions on this Index when this
1149 * function is called.
1151 void refine_bad_initial_prop_values(const php::Class
* cls
,
1153 DependencyContextSet
& deps
);
1156 * Mark any properties in cls that definitely do not redeclare a property in
1157 * the parent, which has an inequivalent type-hint.
1159 void mark_no_bad_redeclare_props(php::Class
& cls
) const;
1162 * Rewrite the initial values of any AttrSystemInitialValue properties to
1163 * something more suitable for its type-hint, and add AttrNoImplicitNullable
1164 * where appropriate.
1166 * This must be done before any analysis is done, as the initial values
1167 * affects the analysis.
1169 void rewrite_default_initial_values(php::Program
&) const;
1172 * Return true if the resolved function supports async eager return.
1174 Optional
<bool> supports_async_eager_return(res::Func rfunc
) const;
1177 * Return true if the function is effect free.
1179 bool is_effect_free(res::Func rfunc
) const;
1180 bool is_effect_free(const php::Func
* func
) const;
1183 * Do any necessary fixups to a return type.
1185 * Note that eg for an async function it will map Type to
1188 void fixup_return_type(const php::Func
*, Type
&) const;
1191 * Return true if we know for sure that one php::Class must derive
1192 * from another at runtime, in all possible instantiations.
1194 bool must_be_derived_from(const php::Class
*,
1195 const php::Class
*) const;
1199 Index(const Index
&) = delete;
1200 Index
& operator=(Index
&&) = delete;
1203 friend struct PublicSPropMutations
;
1205 res::Func
resolve_func_helper(const php::Func
*, SString
) const;
1206 res::Func
do_resolve(const php::Func
*) const;
1207 bool could_be_related(const php::Class
*,
1208 const php::Class
*) const;
1210 template<bool getSuperType
>
1211 Type
get_type_for_constraint(Context
,
1212 const TypeConstraint
&,
1215 struct ConstraintResolution
;
1218 * Try to resolve name in the given context. Follows TypeAliases.
1220 ConstraintResolution
resolve_named_type(
1221 const Context
& ctx
, SString name
, const Type
& candidate
) const;
1223 ConstraintResolution
get_type_for_annotated_type(
1224 Context ctx
, AnnotType annot
, bool nullable
,
1225 SString name
, const Type
& candidate
) const;
1227 void init_return_type(const php::Func
* func
);
1229 ResolvedInfo
<boost::variant
<boost::blank
,SString
,ClassInfo
*>>
1230 resolve_type_name_internal(SString name
) const;
1233 std::unique_ptr
<IndexData
> const m_data
;
1236 //////////////////////////////////////////////////////////////////////
1239 * Used for collecting all mutations of public static property types.
1241 struct PublicSPropMutations
{
1243 friend struct Index
;
1246 bool operator<(KnownKey o
) const {
1247 if (cinfo
!= o
.cinfo
) return cinfo
< o
.cinfo
;
1248 return prop
< o
.prop
;
1255 using UnknownMap
= std::map
<SString
,Type
>;
1256 using KnownMap
= std::map
<KnownKey
,Type
>;
1258 // Public static property mutations are actually rare, so defer allocating the
1259 // maps until we actually see one.
1261 bool m_nothing_known
{false};
1262 UnknownMap m_unknown
;
1265 std::unique_ptr
<Data
> m_data
;
1269 void mergeKnown(const ClassInfo
* ci
, const php::Prop
& prop
, const Type
& val
);
1270 void mergeUnknownClass(SString prop
, const Type
& val
);
1271 void mergeUnknown(Context
);
1274 //////////////////////////////////////////////////////////////////////