bool UnitRepoProxy::GetUnitStmt ::get(UnitEmitter& ue, const MD5& md5) { try { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT unitSn,preload,bc,data FROM " << m_repo.table(m_repoId, "Unit") << " WHERE md5 == @md5;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindMd5("@md5", md5); query.step(); if (!query.row()) { return true; } int64_t unitSn; /**/ query.getInt64(0, unitSn); int preloadPriority; /**/ query.getInt(1, preloadPriority); const void* bc; size_t bclen; /**/ query.getBlob(2, bc, bclen); BlobDecoder dataBlob = /**/ query.getBlob(3); ue.m_repoId = m_repoId; ue.m_sn = unitSn; ue.m_preloadPriority = preloadPriority; ue.setBc(static_cast<const unsigned char*>(bc), bclen); ue.serdeMetaData(dataBlob); txn.commit(); } catch (RepoExc& re) { return true; } return false; }
RepoAuthType decodeRAT(const UnitEmitter& ue, const unsigned char*& pc) { return decodeRATImpl( pc, [&](uint32_t id) { return ue.lookupLitstr(id); }, [&](uint32_t id) { return ue.lookupArrayType(id); } ); }
void UnitRepoProxy::GetUnitArraysStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT arrayId,array FROM " << m_repo.table(m_repoId, "UnitArray") << " WHERE unitSn == @unitSn ORDER BY arrayId ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.sn()); do { query.step(); if (query.row()) { Id arrayId; /**/ query.getId(0, arrayId); StringData* array; /**/ query.getStaticString(1, array); String s(array); Variant v = f_unserialize(s); Id id UNUSED = ue.mergeArray(v.asArrRef().get(), array); ASSERT(id == arrayId); } } while (!query.done()); txn.commit(); }
void PreClassRepoProxy::GetPreClassesStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT preClassId,name,hoistable,extraData FROM " << m_repo.table(m_repoId, "PreClass") << " WHERE unitSn == @unitSn ORDER BY preClassId ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.sn()); do { query.step(); if (query.row()) { Id preClassId; /**/ query.getId(0, preClassId); StringData* name; /**/ query.getStaticString(1, name); int hoistable; /**/ query.getInt(2, hoistable); BlobDecoder extraBlob = /**/ query.getBlob(3); PreClassEmitter* pce = ue.newPreClassEmitter( name, (PreClass::Hoistable)hoistable); pce->serdeMetaData(extraBlob); if (!SystemLib::s_inited) { assert(pce->attrs() & AttrPersistent); assert(pce->attrs() & AttrUnique); } assert(pce->id() == preClassId); } } while (!query.done()); txn.commit(); }
void UnitRepoProxy::GetUnitMergeablesStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT mergeableIx,mergeableKind,mergeableId,mergeableValue" " FROM " << m_repo.table(m_repoId, "UnitMergeables") << " WHERE unitSn == @unitSn ORDER BY mergeableIx ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.m_sn); do { query.step(); if (query.row()) { int mergeableIx; /**/ query.getInt(0, mergeableIx); int mergeableKind; /**/ query.getInt(1, mergeableKind); Id mergeableId; /**/ query.getInt(2, mergeableId); auto k = MergeKind(mergeableKind); if (UNLIKELY(!RuntimeOption::RepoAuthoritative)) { /* * We're using a repo generated in WholeProgram mode, * but we're not using it in RepoAuthoritative mode * (this is dodgy to start with). We're not going to * deal with requires at merge time, so drop them * here, and clear the mergeOnly flag for the unit. * The two exceptions are persistent constants and * TypeAliases which are allowed in systemlib. */ if ((k != MergeKind::PersistentDefine && k != MergeKind::TypeAlias) || SystemLib::s_inited) { ue.m_mergeOnly = false; } } switch (k) { case MergeKind::TypeAlias: ue.insertMergeableTypeAlias(mergeableIx, k, mergeableId); break; case MergeKind::ReqDoc: ue.insertMergeableInclude(mergeableIx, k, mergeableId); break; case MergeKind::PersistentDefine: case MergeKind::Define: case MergeKind::Global: { TypedValue mergeableValue; /**/ query.getTypedValue(3, mergeableValue); ue.insertMergeableDef(mergeableIx, k, mergeableId, mergeableValue); break; } default: break; } } } while (!query.done()); txn.commit(); }
void emit_pseudomain(EmitUnitState& state, UnitEmitter& ue, const php::Unit& unit) { FTRACE(2, " pseudomain\n"); auto& pm = *unit.pseudomain; ue.initMain(std::get<0>(pm.srcInfo.loc), std::get<1>(pm.srcInfo.loc)); auto const fe = ue.getMain(); auto const info = emit_bytecode(state, ue, pm); emit_finish_func(pm, *fe, info); }
void emit_class(EmitUnitState& state, UnitEmitter& ue, const php::Class& cls) { FTRACE(2, " class: {}\n", cls.name->data()); auto const pce = ue.newPreClassEmitter( cls.name, cls.hoistability ); pce->init( std::get<0>(cls.srcInfo.loc), std::get<1>(cls.srcInfo.loc), ue.bcPos(), cls.attrs, cls.parentName ? cls.parentName : s_empty.get(), cls.srcInfo.docComment ); pce->setUserAttributes(cls.userAttributes); for (auto& i : cls.interfaceNames) pce->addInterface(i); for (auto& ut : cls.usedTraitNames) pce->addUsedTrait(ut); for (auto& req : cls.traitRequirements) pce->addTraitRequirement(req); for (auto& tp : cls.traitPrecRules) pce->addTraitPrecRule(tp); for (auto& ta : cls.traitAliasRules) pce->addTraitAliasRule(ta); for (auto& m : cls.methods) { FTRACE(2, " method: {}\n", m->name->data()); auto const fe = ue.newMethodEmitter(m->name, pce); emit_init_func(*fe, *m); pce->addMethod(fe); auto const info = emit_bytecode(state, ue, *m); emit_finish_func(*m, *fe, info); } for (auto& prop : cls.properties) { pce->addProperty( prop.name, prop.attrs, prop.typeConstraint, prop.docComment, &prop.val, KindOfInvalid // hphpcType ); } for (auto& cconst : cls.constants) { pce->addConstant( cconst.name, cconst.typeConstraint, &cconst.val, cconst.phpCode ); } }
void FuncRepoProxy::GetFuncsStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT funcSn,preClassId,name,top,extraData " "FROM " << m_repo.table(m_repoId, "Func") << " WHERE unitSn == @unitSn ORDER BY funcSn ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.m_sn); do { query.step(); if (query.row()) { int funcSn; /**/ query.getInt(0, funcSn); Id preClassId; /**/ query.getId(1, preClassId); StringData* name; /**/ query.getStaticString(2, name); bool top; /**/ query.getBool(3, top); BlobDecoder extraBlob = /**/ query.getBlob(4); FuncEmitter* fe; if (preClassId < 0) { fe = ue.newFuncEmitter(name); } else { PreClassEmitter* pce = ue.pce(preClassId); fe = ue.newMethodEmitter(name, pce); bool added UNUSED = pce->addMethod(fe); assert(added); } assert(fe->sn() == funcSn); fe->top = top; fe->serdeMetaData(extraBlob); if (!SystemLib::s_inited && !fe->isPseudoMain()) { assert(fe->attrs & AttrBuiltin); if (preClassId < 0) { assert(fe->attrs & AttrPersistent); assert(fe->attrs & AttrUnique); assert(fe->attrs & AttrSkipFrame); } } fe->setEHTabIsSorted(); fe->finish(fe->past, true); ue.recordFunction(fe); } } while (!query.done()); txn.commit(); }
void emit_func(EmitUnitState& state, UnitEmitter& ue, const php::Func& func) { FTRACE(2, " func {}\n", func.name->data()); auto const fe = ue.newFuncEmitter(func.name); emit_init_func(*fe, func); auto const info = emit_bytecode(state, ue, func); emit_finish_func(func, *fe, info); }
void UnitRepoProxy::GetUnitArraysStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT arrayId,array FROM " << m_repo.table(m_repoId, "UnitArray") << " WHERE unitSn == @unitSn ORDER BY arrayId ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.m_sn); do { query.step(); if (query.row()) { Id arrayId; /**/ query.getId(0, arrayId); std::string key; /**/ query.getStdString(1, key); Variant v = unserialize_from_buffer(key.data(), key.size()); Id id UNUSED = ue.mergeArray( v.asArrRef().get(), ArrayData::GetScalarArrayKey(key.c_str(), key.size())); assert(id == arrayId); } } while (!query.done()); txn.commit(); }
void encode_member_key(MemberKey mk, UnitEmitter& ue) { ue.emitByte(mk.mcode); switch (mk.mcode) { case MEC: case MEL: case MPC: case MPL: ue.emitIVA(mk.iva); break; case MEI: ue.emitInt64(mk.int64); break; case MET: case MPT: case MQT: ue.emitInt32(ue.mergeLitstr(mk.litstr)); break; case MW: // No immediate break; } }
void UnitRepoProxy::GetUnitLitstrsStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT litstrId,litstr FROM " << m_repo.table(m_repoId, "UnitLitstr") << " WHERE unitSn == @unitSn ORDER BY litstrId ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.sn()); do { query.step(); if (query.row()) { Id litstrId; /**/ query.getId(0, litstrId); StringData* litstr; /**/ query.getStaticString(1, litstr); Id id UNUSED = ue.mergeLitstr(litstr); ASSERT(id == litstrId); } } while (!query.done()); txn.commit(); }
void UnitRepoProxy::GetUnitPreConstsStmt ::get(UnitEmitter& ue) { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT name,value,preconstId FROM " << m_repo.table(m_repoId, "UnitPreConst") << " WHERE unitSn == @unitSn ORDER BY preConstId ASC;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindInt64("@unitSn", ue.sn()); do { query.step(); if (query.row()) { StringData* name; /**/ query.getStaticString(0, name); TypedValue value; /**/ query.getTypedValue(1, value); Id id; /**/ query.getId(2, id); UNUSED Id addedId = ue.addPreConst(name, value); ASSERT(id == addedId); } } while (!query.done()); txn.commit(); }
void merge_repo_auth_type(UnitEmitter& ue, RepoAuthType rat) { using T = RepoAuthType::Tag; switch (rat.tag()) { case T::OptBool: case T::OptInt: case T::OptSStr: case T::OptStr: case T::OptDbl: case T::OptRes: case T::OptObj: case T::Null: case T::Cell: case T::Ref: case T::InitUnc: case T::Unc: case T::InitCell: case T::InitGen: case T::Gen: case T::Uninit: case T::InitNull: case T::Bool: case T::Int: case T::Dbl: case T::Res: case T::SStr: case T::Str: case T::Obj: return; case T::OptSArr: case T::OptArr: case T::SArr: case T::Arr: // We don't need to merge the litstrs in the array, because rats // in arrays in the array type table must be using global litstr // ids. (As the array type table itself is not associated with // any unit.) return; case T::OptSubObj: case T::OptExactObj: case T::SubObj: case T::ExactObj: ue.mergeLitstr(rat.clsName()); return; } }
RepoAuthType make_repo_type(UnitEmitter& ue, const Type& t) { using T = RepoAuthType::Tag; if (t.strictSubtypeOf(TObj) || (is_opt(t) && t.strictSubtypeOf(TOptObj))) { auto const dobj = dobj_of(t); auto const tag = is_opt(t) ? (dobj.type == DObj::Exact ? T::OptExactObj : T::OptSubObj) : (dobj.type == DObj::Exact ? T::ExactObj : T::SubObj); ue.mergeLitstr(dobj.cls.name()); return RepoAuthType { tag, dobj.cls.name() }; } #define ASSERTT_OP(x) if (t.subtypeOf(T##x)) return RepoAuthType{T::x}; ASSERTT_OPS #undef ASSERTT_OP return RepoAuthType{}; }
bool UnitRepoProxy::GetUnitStmt ::get(UnitEmitter& ue, const MD5& md5) { try { RepoTxn txn(m_repo); if (!prepared()) { std::stringstream ssSelect; ssSelect << "SELECT unitSn,bc,bc_meta,mainReturn,mergeable,lines FROM " << m_repo.table(m_repoId, "Unit") << " WHERE md5 == @md5;"; txn.prepare(*this, ssSelect.str()); } RepoTxnQuery query(txn, *this); query.bindMd5("@md5", md5); query.step(); if (!query.row()) { return true; } int64 unitSn; /**/ query.getInt64(0, unitSn); const void* bc; size_t bclen; /**/ query.getBlob(1, bc, bclen); const void* bc_meta; size_t bc_meta_len; /**/ query.getBlob(2, bc_meta, bc_meta_len); TypedValue value; /**/ query.getTypedValue(3, value); bool mergeable; /**/ query.getBool(4, mergeable); BlobDecoder linesBlob = /**/ query.getBlob(5); ue.setRepoId(m_repoId); ue.setSn(unitSn); ue.setBc((const uchar*)bc, bclen); ue.setBcMeta((const uchar*)bc_meta, bc_meta_len); value._count = mergeable; ue.setMainReturn(&value); LineTable lines; linesBlob(lines); ue.setLines(lines); txn.commit(); } catch (RepoExc& re) { return true; } return false; }
void RepoAuthType::resolveArray(const UnitEmitter& ue) { auto fn = [&](const uint32_t id) { return ue.lookupArrayType(id); }; doResolve(fn); }
void emit_class(EmitUnitState& state, UnitEmitter& ue, const php::Class& cls) { FTRACE(2, " class: {}\n", cls.name->data()); auto const pce = ue.newPreClassEmitter( cls.name, cls.hoistability ); pce->init( std::get<0>(cls.srcInfo.loc), std::get<1>(cls.srcInfo.loc), ue.bcPos(), cls.attrs, cls.parentName ? cls.parentName : s_empty.get(), cls.srcInfo.docComment ); pce->setUserAttributes(cls.userAttributes); for (auto& x : cls.interfaceNames) pce->addInterface(x); for (auto& x : cls.usedTraitNames) pce->addUsedTrait(x); for (auto& x : cls.requirements) pce->addClassRequirement(x); for (auto& x : cls.traitPrecRules) pce->addTraitPrecRule(x); for (auto& x : cls.traitAliasRules) pce->addTraitAliasRule(x); for (auto& m : cls.methods) { FTRACE(2, " method: {}\n", m->name->data()); auto const fe = ue.newMethodEmitter(m->name, pce); emit_init_func(*fe, *m); pce->addMethod(fe); auto const info = emit_bytecode(state, ue, *m); emit_finish_func(*m, *fe, info); } auto const privateProps = state.index.lookup_private_props(&cls); auto const privateStatics = state.index.lookup_private_statics(&cls); for (auto& prop : cls.properties) { auto const repoTy = [&] (const PropState& ps) -> RepoAuthType { // TODO(#3599292): we don't currently infer closure use var types. if (is_closure(cls)) return RepoAuthType{}; auto it = ps.find(prop.name); if (it == end(ps)) return RepoAuthType{}; auto const rat = make_repo_type(*state.index.array_table_builder(), it->second); merge_repo_auth_type(ue, rat); return rat; }; pce->addProperty( prop.name, prop.attrs, prop.typeConstraint, prop.docComment, &prop.val, (prop.attrs & AttrStatic) ? repoTy(privateStatics) : repoTy(privateProps) ); } for (auto& cconst : cls.constants) { pce->addConstant( cconst.name, cconst.typeConstraint, &cconst.val, cconst.phpCode ); } }
void emit_class(EmitUnitState& state, UnitEmitter& ue, const php::Class& cls) { FTRACE(2, " class: {}\n", cls.name->data()); auto const pce = ue.newPreClassEmitter( cls.name, cls.hoistability ); pce->init( std::get<0>(cls.srcInfo.loc), std::get<1>(cls.srcInfo.loc), ue.bcPos(), cls.attrs, cls.parentName ? cls.parentName : s_empty.get(), cls.srcInfo.docComment ); pce->setUserAttributes(cls.userAttributes); for (auto& x : cls.interfaceNames) pce->addInterface(x); for (auto& x : cls.usedTraitNames) pce->addUsedTrait(x); for (auto& x : cls.requirements) pce->addClassRequirement(x); for (auto& x : cls.traitPrecRules) pce->addTraitPrecRule(x); for (auto& x : cls.traitAliasRules) pce->addTraitAliasRule(x); pce->setNumDeclMethods(cls.numDeclMethods); pce->setIfaceVtableSlot(state.index.lookup_iface_vtable_slot(&cls)); for (auto& m : cls.methods) { FTRACE(2, " method: {}\n", m->name->data()); auto const fe = ue.newMethodEmitter(m->name, pce); emit_init_func(*fe, *m); pce->addMethod(fe); auto const info = emit_bytecode(state, ue, *m); emit_finish_func(*m, *fe, info); } std::vector<Type> useVars; if (is_closure(cls)) { auto f = find_method(&cls, s_invoke.get()); useVars = state.index.lookup_closure_use_vars(f); } auto uvIt = useVars.begin(); auto const privateProps = state.index.lookup_private_props(&cls); auto const privateStatics = state.index.lookup_private_statics(&cls); for (auto& prop : cls.properties) { auto const makeRat = [&] (const Type& ty) -> RepoAuthType { if (ty.couldBe(TCls)) { return RepoAuthType{}; } auto const rat = make_repo_type(*state.index.array_table_builder(), ty); merge_repo_auth_type(ue, rat); return rat; }; auto const privPropTy = [&] (const PropState& ps) -> Type { if (is_closure(cls)) { // For closures use variables will be the first properties of the // closure object, in declaration order if (uvIt != useVars.end()) return *uvIt++; return Type{}; } auto it = ps.find(prop.name); if (it == end(ps)) return Type{}; return it->second; }; Type propTy; auto const attrs = prop.attrs; if (attrs & AttrPrivate) { propTy = privPropTy((attrs & AttrStatic) ? privateStatics : privateProps); } else if ((attrs & AttrPublic) && (attrs & AttrStatic)) { propTy = state.index.lookup_public_static(&cls, prop.name); } pce->addProperty( prop.name, prop.attrs, prop.typeConstraint, prop.docComment, &prop.val, makeRat(propTy) ); } assert(uvIt == useVars.end()); for (auto& cconst : cls.constants) { if (!cconst.val.hasValue()) { pce->addAbstractConstant( cconst.name, cconst.typeConstraint, cconst.isTypeconst ); } else { pce->addConstant( cconst.name, cconst.typeConstraint, &cconst.val.value(), cconst.phpCode, cconst.isTypeconst ); } } pce->setEnumBaseTy(cls.enumBaseTy); }
void encodeRAT(UnitEmitter& ue, RepoAuthType rat) { using T = RepoAuthType::Tag; switch (rat.tag()) { case T::Uninit: case T::InitNull: case T::Null: case T::Int: case T::OptInt: case T::Dbl: case T::OptDbl: case T::Res: case T::OptRes: case T::Bool: case T::OptBool: case T::SStr: case T::OptSStr: case T::Str: case T::OptStr: case T::SVec: case T::OptSVec: case T::Vec: case T::OptVec: case T::SDict: case T::OptSDict: case T::Dict: case T::OptDict: case T::SKeyset: case T::OptSKeyset: case T::Keyset: case T::OptKeyset: case T::Obj: case T::OptObj: case T::UncArrKey: case T::ArrKey: case T::OptUncArrKey: case T::OptArrKey: case T::InitUnc: case T::Unc: case T::InitCell: case T::Cell: case T::Ref: case T::InitGen: case T::Gen: ue.emitByte(static_cast<uint8_t>(rat.tag())); break; case T::SArr: case T::OptSArr: case T::Arr: case T::OptArr: case T::SVArr: case T::OptSVArr: case T::VArr: case T::OptVArr: case T::SDArr: case T::OptSDArr: case T::DArr: case T::OptDArr: { auto tagByte = static_cast<uint8_t>(rat.tag()); if (rat.hasArrData()) tagByte |= kRATArrayDataBit; ue.emitByte(tagByte); if (rat.hasArrData()) { ue.emitInt32(rat.arrayId()); } break; } case T::ExactObj: case T::SubObj: case T::OptExactObj: case T::OptSubObj: ue.emitByte(static_cast<uint8_t>(rat.tag())); ue.emitInt32(ue.mergeLitstr(rat.clsName())); break; } }
void emit_class(EmitUnitState& state, UnitEmitter& ue, const php::Class& cls) { FTRACE(2, " class: {}\n", cls.name->data()); auto const pce = ue.newPreClassEmitter( cls.name, cls.hoistability ); pce->init( std::get<0>(cls.srcInfo.loc), std::get<1>(cls.srcInfo.loc), ue.bcPos(), cls.attrs, cls.parentName ? cls.parentName : s_empty.get(), cls.srcInfo.docComment ); pce->setUserAttributes(cls.userAttributes); for (auto& x : cls.interfaceNames) pce->addInterface(x); for (auto& x : cls.usedTraitNames) pce->addUsedTrait(x); for (auto& x : cls.requirements) pce->addClassRequirement(x); for (auto& x : cls.traitPrecRules) pce->addTraitPrecRule(x); for (auto& x : cls.traitAliasRules) pce->addTraitAliasRule(x); pce->setNumDeclMethods(cls.numDeclMethods); pce->setIfaceVtableSlot(state.index.lookup_iface_vtable_slot(&cls)); for (auto& m : cls.methods) { FTRACE(2, " method: {}\n", m->name->data()); auto const fe = ue.newMethodEmitter(m->name, pce); emit_init_func(*fe, *m); pce->addMethod(fe); auto const info = emit_bytecode(state, ue, *m); emit_finish_func(*m, *fe, info); } auto const privateProps = state.index.lookup_private_props(&cls); auto const privateStatics = state.index.lookup_private_statics(&cls); for (auto& prop : cls.properties) { auto const makeRat = [&] (const Type& ty) -> RepoAuthType { if (ty.couldBe(TCls)) { return RepoAuthType{}; } auto const rat = make_repo_type(*state.index.array_table_builder(), ty); merge_repo_auth_type(ue, rat); return rat; }; auto const privPropTy = [&] (const PropState& ps) -> Type { /* * Skip closures, because the types of their used vars can be * communicated via assert opcodes right now. At the time of this * writing there was nothing to gain by including RAT's for the * properties, since closure properties are only used internally by the * runtime, not directly via opcodes like CGetM. */ if (is_closure(cls)) return Type{}; auto it = ps.find(prop.name); if (it == end(ps)) return Type{}; return it->second; }; Type propTy; auto const attrs = prop.attrs; if (attrs & AttrPrivate) { propTy = privPropTy((attrs & AttrStatic) ? privateStatics : privateProps); } else if ((attrs & AttrPublic) && (attrs & AttrStatic)) { propTy = state.index.lookup_public_static(&cls, prop.name); } pce->addProperty( prop.name, prop.attrs, prop.typeConstraint, prop.docComment, &prop.val, makeRat(propTy) ); } for (auto& cconst : cls.constants) { if (!cconst.val.hasValue()) { pce->addAbstractConstant( cconst.name, cconst.typeConstraint, cconst.isTypeconst ); } else { pce->addConstant( cconst.name, cconst.typeConstraint, &cconst.val.value(), cconst.phpCode, cconst.isTypeconst ); } } pce->setEnumBaseTy(cls.enumBaseTy); }
void emit_typealias(UnitEmitter& ue, const php::TypeAlias& alias) { auto const id = ue.addTypeAlias(alias); ue.pushMergeableTypeAlias(HPHP::Unit::MergeKind::TypeAlias, id); }