/* * In the case of HNI builtin classes, private properties are * allowed to be mutated by native code, so we may not see all the * modifications. * * We are allowed to assume the type annotation on the property is * accurate, although nothing is currently checking that this is the * case. We handle this right now by doing inference as if it * couldn't be affected by native code, then assert the inferred * type is at least a subtype of the annotated type, and expanding * it to be the annotated type if it is bigger. */ void expand_hni_prop_types(ClassAnalysis& clsAnalysis) { auto relax_prop = [&] (const php::Prop& prop, PropState& propState) { auto it = propState.find(prop.name); if (it == end(propState)) return; /* * When HardTypeHints isn't on, we don't require the constraints * to actually match, and relax all the HNI types to Gen. (This * is because extensions may wish to assign to properties after a * typehint guard, which is going to fail without this flag on.) */ auto const hniTy = !options.HardTypeHints ? TGen : from_hni_constraint(prop.typeConstraint); if (it->second.subtypeOf(hniTy)) { it->second = hniTy; return; } std::fprintf( stderr, "HNI class %s::%s inferred property type (%s) doesn't " "match annotation (%s)\n", clsAnalysis.ctx.cls->name->data(), prop.name->data(), show(it->second).c_str(), show(hniTy).c_str() ); always_assert(!"HNI property type annotation was wrong"); }; for (auto& prop : clsAnalysis.ctx.cls->properties) { relax_prop(prop, clsAnalysis.privateProperties); relax_prop(prop, clsAnalysis.privateStatics); } }
/* * In the case of HNI builtin classes, private properties are * allowed to be mutated by native code, so we may not see all the * modifications. * * We are allowed to assume the type annotation on the property is * accurate, although nothing is currently checking that this is the * case. We handle this right now by doing inference as if it * couldn't be affected by native code, then assert the inferred * type is at least a subtype of the annotated type, and expanding * it to be the annotated type if it is bigger. */ void expand_hni_prop_types(ClassAnalysis& clsAnalysis) { auto relax_prop = [&] (const php::Prop& prop, PropState& propState) { auto it = propState.find(prop.name); if (it == end(propState)) return; /* * When HardTypeHints isn't on, AllFuncsInterceptable is on, or any * InterceptableFunctions are listed, we don't require the constraints to * actually match, and relax all the HNI types to Gen. * * This is because extensions may wish to assign to properties after a * typehint guard, which is going to fail without HardTypeHints. Or, with * AllFuncsInterceptable or InterceptableFunctions, it's quite possible * that some function calls in systemlib might not be known to return * things matching the property type hints for some properties, or not to * take their arguments by reference. */ auto const hniTy = !options.HardTypeHints || options.AllFuncsInterceptable || !options.InterceptableFunctions.empty() ? TGen : from_hni_constraint(prop.typeConstraint); if (it->second.subtypeOf(hniTy)) { it->second = hniTy; return; } std::fprintf( stderr, "HNI class %s::%s inferred property type (%s) doesn't " "match annotation (%s)\n", clsAnalysis.ctx.cls->name->data(), prop.name->data(), show(it->second).c_str(), show(hniTy).c_str() ); always_assert(!"HNI property type annotation was wrong"); }; for (auto& prop : clsAnalysis.ctx.cls->properties) { relax_prop(prop, clsAnalysis.privateProperties); relax_prop(prop, clsAnalysis.privateStatics); } }
/* * In the case of HNI builtin classes, private properties are * allowed to be mutated by native code, so we may not see all the * modifications. * * We are allowed to assume the type annotation on the property is * accurate, although nothing is currently checking that this is the * case. We handle this right now by doing inference as if it * couldn't be affected by native code, then assert the inferred * type is at least a subtype of the annotated type, and expanding * it to be the annotated type if it is bigger. */ void expand_hni_prop_types(ClassAnalysis& clsAnalysis) { auto relax_prop = [&] (const php::Prop& prop, PropState& propState) { auto it = propState.find(prop.name); if (it == end(propState)) return; /* * When HardTypeHints isn't on, DisallowDynamicVarEnvFuncs isn't on, or any * functions are interceptable, we don't require the constraints to actually * match, and relax all the HNI types to Gen. * * This is because extensions may wish to assign to properties * after a typehint guard, which is going to fail without * HardTypeHints. Or, with any interceptable functions, it's * quite possible that some function calls in systemlib might not * be known to return things matching the property type hints for * some properties, or not to take their arguments by reference. */ auto const hniTy = !RuntimeOption::EvalHardTypeHints || RuntimeOption::DisallowDynamicVarEnvFuncs != HackStrictOption::ON || clsAnalysis.anyInterceptable ? TGen : from_hni_constraint(prop.typeConstraint); if (it->second.subtypeOf(hniTy)) { it->second = hniTy; return; } std::fprintf( stderr, "HNI class %s::%s inferred property type (%s) doesn't " "match annotation (%s)\n", clsAnalysis.ctx.cls->name->data(), prop.name->data(), show(it->second).c_str(), show(hniTy).c_str() ); always_assert(!"HNI property type annotation was wrong"); }; for (auto& prop : clsAnalysis.ctx.cls->properties) { relax_prop(prop, clsAnalysis.privateProperties); relax_prop(prop, clsAnalysis.privateStatics); } }