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 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_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 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 ); } }