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 +----------------------------------------------------------------------+
16 #ifndef incl_HHBBC_INDEX_H_
17 #define incl_HHBBC_INDEX_H_
25 #include <boost/variant.hpp>
26 #include <tbb/concurrent_hash_map.h>
28 #include <folly/synchronization/Baton.h>
29 #include <folly/Optional.h>
30 #include <folly/Hash.h>
32 #include "hphp/util/compact-vector.h"
33 #include "hphp/util/either.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
;
52 extern const Type TTop
;
61 //////////////////////////////////////////////////////////////////////
64 * This module contains functions for building and querying an Index
65 * of data relating to "resolved" versions of the names in of a
66 * php::Program. It also records dependencies so it is possible to
67 * tell which parts of the program may be interested in new inferred
68 * information about other parts of the program.
70 * The main entry point here is the Index class. The Index is built
71 * after parse time, and then analysis can query it for information.
74 //////////////////////////////////////////////////////////////////////
77 * A DependencyContext encodes enough of the context to record a dependency - a
78 * php::Func, if we're doing private property analysis and its a suitable class,
79 * a php::Class, or a public static property with a particular name.
82 enum class DependencyContextType
: uint16_t {
88 using DependencyContext
= CompactTaggedPtr
<const void, DependencyContextType
>;
90 struct DependencyContextLess
{
91 bool operator()(const DependencyContext
& a
,
92 const DependencyContext
& b
) const {
93 return a
.getOpaque() < b
.getOpaque();
97 struct DependencyContextEquals
{
98 bool operator()(const DependencyContext
& a
,
99 const DependencyContext
& b
) const {
100 return a
.getOpaque() == b
.getOpaque();
104 struct DependencyContextHash
{
105 size_t operator()(const DependencyContext
& d
) const {
106 return pointer_hash
<void>{}(reinterpret_cast<void*>(d
.getOpaque()));
110 struct DependencyContextHashCompare
: DependencyContextHash
{
111 bool equal(const DependencyContext
& a
, const DependencyContext
& b
) const {
112 return a
.getOpaque() == b
.getOpaque();
114 size_t hash(const DependencyContext
& d
) const { return (*this)(d
); }
117 using DependencyContextSet
= hphp_hash_set
<DependencyContext
,
118 DependencyContextHash
,
119 DependencyContextEquals
>;
120 using ContextSet
= hphp_hash_set
<Context
, ContextHash
>;
122 std::string
show(Context
);
124 using ConstantMap
= hphp_hash_map
<SString
, Cell
>;
127 * State of properties on a class. Map from property name to its
130 template <typename T
= Type
>
131 struct PropStateElem
{
133 const TypeConstraint
* tc
= nullptr;
135 bool operator==(const PropStateElem
<T
>& o
) const {
136 return ty
== o
.ty
&& tc
== o
.tc
;
139 using PropState
= std::map
<LSString
,PropStateElem
<>>;
141 //////////////////////////////////////////////////////////////////////
146 //////////////////////////////////////////////////////////////////////
149 * References to "resolved" entities with information in the index are
150 * in the res:: namespace.
152 * These represent handles to program entities that may have variable
153 * amounts of information. For example, we may know the name of a
154 * class in a res::Class, but do not know for sure which php::Class
155 * struct is actually associated with it.
160 * A resolved runtime Class, for a particular php::Class.
162 * Provides various lookup tables that allow querying the Class'
167 * Returns whether two classes are definitely same at runtime. If
168 * this function returns false, they still *may* be the same at
171 bool same(const Class
&) const;
174 * Returns true if this class is definitely going to be a subtype
175 * of `o' at runtime. If this function returns false, this may
176 * still be a subtype of `o' at runtime, it just may not be known.
177 * A typical example is with "non unique" classes.
179 bool subtypeOf(const Class
& o
) const;
182 * If this function return false, it is known that this class
183 * is in no subtype relationship with the argument Class 'o'.
184 * Returns true if this class could be a subtype of `o' at runtime.
185 * When true is returned the two classes may still be unrelated but it is
186 * not possible to tell. A typical example is with "non unique" classes.
188 bool couldBe(const Class
& o
) const;
191 * Returns the name of this class. Non-null guarantee.
193 SString
name() const;
196 * Whether this class could possibly be an interface/interface or trait.
198 * True means it might be, false means it is not.
200 bool couldBeInterface() const;
201 bool couldBeInterfaceOrTrait() const;
204 * Returns whether this type has the no override attribute, that is, if it
205 * is a final class (explicitly marked by the user or known by the static
208 * When returning false the class is guaranteed to be final. When returning
209 * true the system cannot tell though the class may still be final.
211 bool couldBeOverriden() const;
214 * Whether this class (or its subtypes) could possibly have have
215 * certain magic methods.
217 bool couldHaveMagicGet() const;
220 * Whether this class (or its subtypes) could possibly have have
221 * a magic toBoolean() method.
223 bool couldHaveMagicBool() const;
226 * Whether this class could possibly have a derived class that is mocked.
229 bool couldHaveMockedDerivedClass() const;
232 * Whether this class could possibly be mocked.
234 bool couldBeMocked() const;
237 * Whether this class could have reified generics
239 bool couldHaveReifiedGenerics() const;
242 * Returns whether this resolved class might distinguish being constructed
243 * dynamically versus being constructed normally (IE, might raise a notice).
245 bool mightCareAboutDynConstructs() const;
248 * Returns the Class that is the first common ancestor between 'this' and 'o'.
249 * If there is no common ancestor folly::none is returned
251 folly::Optional
<Class
> commonAncestor(const Class
& o
) const;
254 * Returns the res::Class for this Class's parent if there is one,
257 folly::Optional
<Class
> parent() const;
260 * Returns true if we have a ClassInfo for this Class.
262 bool resolved() const {
263 return val
.right() != nullptr;
267 * Returns the php::Class for this Class if there is one, or
270 const php::Class
* cls() const;
273 Class(const Index
*, Either
<SString
,ClassInfo
*>);
276 friend std::string
show(const Class
&);
277 friend struct ::HPHP::HHBBC::Index
;
278 friend struct ::HPHP::HHBBC::PublicSPropMutations
;
280 Either
<SString
,ClassInfo
*> val
;
284 * This is an abstraction layer to represent possible runtime function
287 * Internally, this may only know the name of the function (or method), or we
288 * may know exactly which source-code-level function it refers to, or we may
289 * only have ruled it down to one of a few functions in a class hierarchy. The
290 * interpreter can treat all these cases the same way using this.
294 * Returns whether two res::Funcs definitely mean the func at
297 * Note: this is potentially pessimistic for its use in ActRec state
298 * merging right now, but not incorrect.
300 bool same(const Func
&) const;
303 * Returns the name of this function. Non-null guarantee.
305 SString
name() const;
308 * If this resolved function represents exactly one php::Func, return it.
310 const php::Func
* exactFunc() const;
313 * Returns whether this resolved function could possibly be going through a
314 * magic call, in the magic way.
316 * That is, if was resolved as part of a direct call to an __call method,
317 * this will say true. If it was resolved as part as some normal method
318 * call, and we haven't proven that there's no way an __call dispatch could
319 * be involved, this will say false.
321 bool cantBeMagicCall() const;
324 * Returns whether this resolved function is definitely safe to constant fold.
326 bool isFoldable() const;
329 * Returns whether this resolved function could possibly be skipped when
330 * looking for a caller's frame.
332 bool mightBeSkipFrame() const;
335 * Whether this function could have reified generics
337 bool couldHaveReifiedGenerics() const;
340 * Returns whether this resolved function might distinguish being called
341 * dynamically versus being called normally (IE, might raise a notice).
343 bool mightCareAboutDynCalls() const;
346 * Returns whether this resolved function might be a builtin.
348 bool mightBeBuiltin() const;
351 struct MethTabEntryPair
;
355 friend struct ::HPHP::HHBBC::Index
;
357 FuncName(SString n
, bool r
) : name
{n
}, renamable
{r
} {}
358 bool operator==(FuncName o
) const { return name
== o
.name
; }
363 bool operator==(MethodName o
) const { return name
== o
.name
; }
366 using Rep
= boost::variant
< FuncName
369 , const MethTabEntryPair
*
374 Func(const Index
*, Rep
);
375 friend std::string
show(const Func
&);
383 * Produce a trace-able string for a res::Func or res::Class.
385 std::string
show(const Func
&);
386 std::string
show(const Class
&);
390 //////////////////////////////////////////////////////////////////////
393 * This class encapsulates the known facts about the program, with a
394 * whole-program view.
396 * This structure contains unowned pointers into the php::Program it
397 * was created for. It should not out-live the Program.
399 * The const member functions of this class are thread safe for
400 * concurrent reads and writes. The non-const functions should be
401 * called in a single threaded context only (they are used during the
402 * "update" step in between whole program analysis rounds).
406 * Throwing a rebuild exception indicates that the index needs to
409 * The exception should be passed to the Index constructor.
411 struct rebuild
: std::exception
{
412 explicit rebuild(std::vector
<std::pair
<SString
, SString
>> ca
) :
413 class_aliases(std::move(ca
)) {}
416 std::vector
<std::pair
<SString
, SString
>> class_aliases
;
420 * Create an Index for a php::Program. Performs some initial
421 * analysis of the program.
423 explicit Index(php::Program
*, rebuild
* = nullptr);
426 * This class must not be destructed after its associated
432 * The index operates in two modes: frozen, and unfrozen.
434 * Conceptually, the index is mutable and may acquire new
435 * information until it has been frozen, and once frozen, it retains
436 * the information it had at the point it was frozen.
438 * The reason this exists is because certain functions on the index
439 * may cause it to need to consult information in the bodies of
440 * functions other than the Context passed in. Specifically, if the
441 * interpreter tries to look up the return type for a callee in a
442 * given CallContext, the index may choose to recursively invoke
443 * type inference on that callee's function body to see if more
444 * precise information can be determined, unless it is frozen.
446 * This is fine until the final pass, because all bytecode is
447 * read-only at that stage. However, in the final pass, other
448 * threads might be optimizing a callee's bytecode and changing it,
449 * so we should not be reading from it to perform type inference
450 * concurrently. Freezing the index tells it it can't do that
453 * These are the functions to query and transition to frozen state.
460 * Throw away data structures that won't be needed during the emit
463 void cleanup_for_emit(folly::Baton
<>* done
);
466 * The Index contains a Builder for an ArrayTypeTable.
468 * If we're creating assert types with options.InsertAssertions, we
469 * need to keep track of which array types exist in the whole
470 * program in order to include it in the repo.
472 std::unique_ptr
<ArrayTypeTable::Builder
>& array_table_builder() const;
475 * Find all the closures created inside the context of a given
478 const CompactVector
<const php::Class
*>*
479 lookup_closures(const php::Class
*) const;
482 * Find all the extra methods associated with a class from its
485 const hphp_fast_set
<php::Func
*>*
486 lookup_extra_methods(const php::Class
*) const;
489 * Attempt to record a new alias in the index. May be called from
490 * multi-threaded contexts, so doesn't actually update the index
491 * (call update_class_aliases to do that). Returns false if it would
492 * violate any current uniqueness assumptions.
494 bool register_class_alias(SString orig
, SString alias
) const;
497 * Add any aliases that have been registered since the last call to
498 * update_class_aliases to the index. Must be called from a single
501 void update_class_aliases();
504 * Try to find a res::Class for a given php::Class.
506 * Note, the returned class may or may not be *defined* at the
507 * program point you care about (it could be non-hoistable, even
508 * though it's unique, for example).
510 * Returns a name-only resolution if there are no legal
511 * instantiations of the class, or if there is more than one.
513 res::Class
resolve_class(const php::Class
*) const;
516 * Try to resolve which class will be the class named `name' from a
517 * given context, if we can resolve it to a single class.
519 * Note, the returned class may or may not be *defined* at the
520 * program point you care about (it could be non-hoistable, even
521 * though it's unique, for example).
523 * Returns folly::none if we can't prove the supplied name must be a
524 * object type. (E.g. if there are type aliases.)
526 folly::Optional
<res::Class
> resolve_class(Context
, SString name
) const;
529 * Try to resolve self/parent types for the given context
531 folly::Optional
<res::Class
> selfCls(const Context
& ctx
) const;
532 folly::Optional
<res::Class
> parentCls(const Context
& ctx
) const;
534 template <typename T
>
535 struct ResolvedInfo
{
542 * Try to resolve name, looking through TypeAliases and enums.
544 ResolvedInfo
<folly::Optional
<res::Class
>>
545 resolve_type_name(SString name
) const;
548 * Resolve a closure class.
550 * Returns both a resolved Class, and the actual php::Class for the
553 std::pair
<res::Class
,php::Class
*>
554 resolve_closure_class(Context ctx
, int32_t idx
) const;
557 * Return a resolved class for a builtin class.
559 * Pre: `name' must be the name of a class defined in a systemlib.
561 res::Class
builtin_class(SString name
) const;
564 * Try to resolve a function named `name' from a given context.
566 * Note, the returned function may or may not be defined at the
567 * program point (it could require a function autoload that might
570 res::Func
resolve_func(Context
, SString name
) const;
573 * Try to resolve a function using namespace-style fallback lookup.
575 * The name `name' is tried first, and `fallback' is used if this
576 * isn't found. Both names must already be namespace-normalized.
577 * If we don't know which will be called at runtime, both will be
580 * Note: the returned function may or may not be defined at the
581 * program point (it could require a function autoload that might
584 std::pair
<folly::Optional
<res::Func
>, folly::Optional
<res::Func
>>
585 resolve_func_fallback(Context
,
587 SString fallback
) const;
590 * Try to resolve a class method named `name' with a given Context
593 * Pre: clsType.subtypeOf(BCls)
595 res::Func
resolve_method(Context
, Type clsType
, SString name
) const;
598 * Try to resolve a class constructor for the supplied class type.
600 * Returns: folly::none if it can't at least figure out a func
601 * family for the call.
603 folly::Optional
<res::Func
>
604 resolve_ctor(Context
, res::Class rcls
, bool exact
) const;
607 * Give the Type in our type system that matches an hhvm
608 * TypeConstraint, subject to the information in this Index.
610 * This function returns a subtype of Cell, although TypeConstraints
611 * at runtime can match reference parameters. The caller should
612 * make sure to handle that case.
614 * For soft constraints (@), this function returns Cell.
616 * For some non-soft constraints (such as "Stringish"), this
617 * function may return a Type that is a strict supertype of the
620 * If something is known about the type of the object against which
621 * the constraint will be checked, it can be passed in to help
622 * disambiguate certain constraints (useful because we don't support
623 * arbitrary unions, or intersection).
625 Type
lookup_constraint(Context
, const TypeConstraint
&,
626 const Type
& t
= TTop
) const;
629 * If this function returns true, it is safe to assume that Type t
630 * will always satisfy TypeConstraint tc at run time.
632 bool satisfies_constraint(Context
, const Type
& t
,
633 const TypeConstraint
& tc
) const;
636 * Returns true if the given type-hint (declared on the given class) might not
637 * be enforced at runtime (IE, it might map to mixed or be soft).
639 bool prop_tc_maybe_unenforced(const php::Class
& propCls
,
640 const TypeConstraint
& tc
) const;
643 * Returns true if the type constraint can contain a reified type
644 * Currently, only classes and interfaces are supported
646 bool could_have_reified_type(const TypeConstraint
& tc
) const;
649 * Lookup what the best known Type for a class constant would be,
650 * using a given Index and Context, if a class of that name were
653 Type
lookup_class_constant(Context
, res::Class
, SString cns
) const;
656 * Lookup what the best known Type for a constant would be, using a
657 * given Index and Context, if a constant of that name were defined.
659 * Returns folly::none if the constant isn't in the index.
661 folly::Optional
<Type
> lookup_constant(Context ctx
,
662 SString cnsName
) const;
665 * See if the named constant has a unique scalar definition, and
666 * return its value if so.
668 folly::Optional
<Cell
> lookup_persistent_constant(SString cnsName
) const;
671 * Return true if the return value of the function might depend on arg.
673 bool func_depends_on_arg(const php::Func
* func
, int arg
) const;
676 * If func is effect-free when called with args, and it returns a constant,
677 * return that constant; otherwise return TTop.
679 Type
lookup_foldable_return_type(Context ctx
,
680 const php::Func
* func
,
682 CompactVector
<Type
> args
) const;
684 * Return the best known return type for a resolved function, in a
685 * context insensitive way. Returns TInitGen at worst.
687 Type
lookup_return_type(Context
, res::Func
) const;
690 * Return the best known return type for a resolved function, given
691 * the supplied calling context. Returns TInitGen at worst.
693 * During analyze phases, this function may re-enter analyze in
694 * order to interpret the callee with these argument types.
696 Type
lookup_return_type(Context caller
,
697 const CompactVector
<Type
>& args
,
702 * Look up the return type for an unresolved function. The
703 * interpreter should not use this routine---it's for stats or debug
706 * Nothing may be writing to the index when this function is used,
707 * but concurrent readers are allowed.
709 Type
lookup_return_type_raw(const php::Func
*) const;
712 * As lookup_return_type_raw, but also clean out the FuncInfo struct.
713 * For use during emit, to keep memory usage down.
715 Type
lookup_return_type_and_clear(const php::Func
*) const;
718 * Return the best known types of a closure's used variables (on
719 * entry to the closure). The function is the closure body.
721 * If move is true, the value will be moved out of the index. This
722 * should only be done at emit time.
725 lookup_closure_use_vars(const php::Func
*,
726 bool move
= false) const;
729 * Return the availability of $this on entry to the provided method.
730 * If the Func provided is not a method of a class false is
733 bool lookup_this_available(const php::Func
*) const;
736 * Returns the parameter preparation kind (if known) for parameter
737 * `paramId' on the given resolved Func.
739 PrepKind
lookup_param_prep(Context
, res::Func
, uint32_t paramId
) const;
742 * Returns the control-flow insensitive inferred private instance
743 * property types for a Class. The Class doesn't need to be
744 * resolved, because private properties don't depend on the
745 * inheritance hierarchy.
747 * The Index tracks the largest types for private properties that
748 * are guaranteed to hold at any program point.
750 * If move is true, the value will be moved out of the index. This
751 * should only be done at emit time.
753 PropState
lookup_private_props(const php::Class
*,
754 bool move
= false) const;
757 * Returns the control-flow insensitive inferred private static
758 * property types for a Class. The class doesn't need to be
759 * resolved for the same reasons as for instance properties.
761 * The Index tracks the largest types for private static properties
762 * that are guaranteed to hold at any program point.
764 * If move is true, the value will be moved out of the index. This
765 * should only be done at emit time.
767 PropState
lookup_private_statics(const php::Class
*,
768 bool move
= false) const;
771 * Lookup the best known type for a public static property, with a given
774 * This function will always return TInitGen before refine_public_statics has
775 * been called, or if the AnalyzePublicStatics option is off.
777 Type
lookup_public_static(Context ctx
, const Type
& cls
,
778 const Type
& name
) const;
779 Type
lookup_public_static(Context ctx
, const php::Class
*,
783 * Lookup if initializing (which is a side-effect of several bytecodes) the
784 * given class might raise.
786 bool lookup_class_init_might_raise(Context
, res::Class
) const;
789 * Lookup if a public static property with the given class and name might be
792 bool lookup_public_static_maybe_late_init(const Type
& cls
,
793 const Type
& name
) const;
796 * Returns whether a public static property is known to be immutable. This
797 * is used to add AttrPersistent flags to static properties, and relies on
798 * AnalyzePublicStatics (without this flag it will always return false).
800 bool lookup_public_static_immutable(const php::Class
*,
804 * Lookup the best known type for a public (non-static) property. Since we
805 * don't do analysis on public properties, this just inferred from the
806 * property's type-hint (if enforced).
808 Type
lookup_public_prop(const Type
& cls
, const Type
& name
) const;
809 Type
lookup_public_prop(const php::Class
* cls
, SString name
) const;
812 * Returns the computed vtable slot for the given class, if it's an interface
813 * that was given a vtable slot. No two interfaces implemented by the same
814 * class will share the same vtable slot. May return kInvalidSlot, if the
815 * given class isn't an interface or if it wasn't assigned a slot.
817 Slot
lookup_iface_vtable_slot(const php::Class
*) const;
820 * Return the DependencyContext for ctx.
822 DependencyContext
dependency_context(const Context
& ctx
) const;
825 * Determine whether to use class-at-a-time, or function-at-a-time
828 * Must be called in single-threaded context.
830 void use_class_dependencies(bool f
);
833 * Initialize the initial types for public static properties. This should be
834 * done after rewriting initial property values, as that affects the types.
836 void init_public_static_prop_types();
839 * Refine the types of the class constants defined by an 86cinit,
840 * based on a round of analysis.
842 * No other threads should be using ctx.cls->constants or deps when
843 * this function is called.
845 * Merges the set of Contexts that depended on the constants defined
848 void refine_class_constants(
850 const CompactVector
<std::pair
<size_t, TypedValue
>>& resolved
,
851 DependencyContextSet
& deps
);
854 * Refine the types of the constants defined by a function, based on
855 * a round of analysis.
857 * Constants not defined by a pseudomain are considered unknowable
859 * No other threads should be calling functions on this Index when
860 * this function is called.
862 * Merges the set of Contexts that depended on the constants defined
863 * by this php::Func into deps.
865 void refine_constants(const FuncAnalysisResult
& fa
,
866 DependencyContextSet
& deps
);
869 * Refine the return type for a function, based on a round of
872 * No other threads should be calling functions on this Index when
873 * this function is called.
875 * Merges the set of Contexts that depended on the return type of
876 * this php::Func into deps.
878 void refine_return_info(const FuncAnalysisResult
& fa
,
879 DependencyContextSet
& deps
);
882 * Refine the used var types for a closure, based on a round of
885 * No other threads should be calling functions on this Index when
886 * this function is called.
888 * Returns: true if the types have changed.
890 bool refine_closure_use_vars(const php::Class
*,
891 const CompactVector
<Type
>&);
894 * Refine the private property types for a class, based on a round
897 * No other threads should be calling functions on this Index when
898 * this function is called.
900 void refine_private_props(const php::Class
* cls
,
904 * Refine the static private property types for a class, based on a
907 * No other threads should be calling functions on this Index when
908 * this function is called.
910 void refine_private_statics(const php::Class
* cls
,
914 * Record in the index that the given set of public static property mutations
915 * has been found while analyzing the given function. During a round of
916 * analysis, the mutations are gathered from the analysis results for each
917 * function, recorded in the index, and then refine_public_statics is called
918 * to process the mutations and update the index.
920 * No other threads should be calling functions on this Index when this
921 * function is called.
923 void record_public_static_mutations(const php::Func
& func
,
924 PublicSPropMutations mutations
);
927 * After a round of analysis with all the public static property mutations
928 * being recorded with record_public_static_mutations, the types can be
929 * reflected into the index for use during another type inference pass.
931 * No other threads should be calling functions on this Index when this
932 * function is called.
934 * Merges the set of Contexts that depended on a public static property whose
937 void refine_public_statics(DependencyContextSet
& deps
);
940 * Refine whether the given class has properties with initial values which
941 * might violate their type-hints.
943 * No other threads should be calling functions on this Index when this
944 * function is called.
946 void refine_bad_initial_prop_values(const php::Class
* cls
,
948 DependencyContextSet
& deps
);
951 * Identify the persistent classes, functions and typeAliases.
953 void mark_persistent_classes_and_functions(php::Program
& program
);
956 * Mark any properties in cls that definitely do not redeclare a property in
957 * the parent, which has an inequivalent type-hint.
959 void mark_no_bad_redeclare_props(php::Class
& cls
) const;
962 * Rewrite the initial values of any AttrSystemInitialValue properties to
963 * something more suitable for its type-hint, and add AttrNoImplicitNullable
966 * This must be done before any analysis is done, as the initial values
967 * affects the analysis.
969 void rewrite_default_initial_values(php::Program
&) const;
972 * Return true if the resolved function supports async eager return.
974 folly::Optional
<bool> supports_async_eager_return(res::Func rfunc
) const;
977 * Return true if the resolved function is effect free.
979 bool is_effect_free(res::Func rfunc
) const;
982 * Return true if there are any interceptable functions
984 bool any_interceptable_functions() const;
987 * Do any necessary fixups to a return type.
989 * Note that eg for an async function it will map Type to
992 void fixup_return_type(const php::Func
*, Type
&) const;
995 * Return true if we know for sure that one php::Class must derive
996 * from another at runtime, in all possible instantiations.
998 bool must_be_derived_from(const php::Class
*,
999 const php::Class
*) const;
1003 Index(const Index
&) = delete;
1004 Index
& operator=(Index
&&) = delete;
1007 friend struct PublicSPropMutations
;
1009 template<class FuncRange
>
1010 res::Func
resolve_func_helper(const FuncRange
&, SString
) const;
1011 res::Func
do_resolve(const php::Func
*) const;
1012 bool could_be_related(const php::Class
*,
1013 const php::Class
*) const;
1015 template<bool getSuperType
>
1016 Type
get_type_for_constraint(Context
,
1017 const TypeConstraint
&,
1020 struct ConstraintResolution
;
1023 * Try to resolve name in the given context. Follows TypeAliases.
1025 ConstraintResolution
resolve_class_or_type_alias(
1026 const Context
& ctx
, SString name
, const Type
& candidate
) const;
1028 ConstraintResolution
get_type_for_annotated_type(
1029 Context ctx
, AnnotType annot
, bool nullable
,
1030 SString name
, const Type
& candidate
) const;
1032 void init_return_type(const php::Func
* func
);
1034 ResolvedInfo
<Either
<SString
,ClassInfo
*>>
1035 resolve_type_name_internal(SString name
) const;
1038 std::unique_ptr
<IndexData
> const m_data
;
1041 //////////////////////////////////////////////////////////////////////
1044 * Used for collecting all mutations of public static property types.
1046 struct PublicSPropMutations
{
1048 * This function must be called anywhere the interpreter does something that
1049 * could change the type of public static properties named `name' on classes
1050 * of type `cls' to `val'.
1052 * Note that if cls and name are both too generic this object will have to
1053 * give up all information it knows about any public static properties.
1055 void merge(const Index
& index
, Context ctx
, const Type
& cls
,
1056 const Type
& name
, const Type
& val
);
1057 void merge(const Index
& index
, Context ctx
, ClassInfo
* cinfo
,
1058 const Type
& name
, const Type
& val
);
1059 void merge(const Index
& index
, Context ctx
, const php::Class
& cls
,
1060 const Type
& name
, const Type
& val
);
1063 friend struct Index
;
1066 bool operator<(KnownKey o
) const {
1067 if (cinfo
!= o
.cinfo
) return cinfo
< o
.cinfo
;
1068 return prop
< o
.prop
;
1075 using UnknownMap
= std::map
<SString
,Type
>;
1076 using KnownMap
= std::map
<KnownKey
,Type
>;
1078 // Public static property mutations are actually rare, so defer allocating the
1079 // maps until we actually see one.
1081 bool m_nothing_known
{false};
1082 UnknownMap m_unknown
;
1085 std::unique_ptr
<Data
> m_data
;
1088 //////////////////////////////////////////////////////////////////////