Fix classof for traits

Class::classof(Class* t) would always return false, if t
was a trait, but should return true if t == this.

This was causing the call_user_func in the new test to fail,
reporting that T was not a subclass of T.
Esse commit está contido em:
Mark Williams
2013-05-16 15:24:45 -07:00
commit de Sara Golemon
commit 53433c3359
3 arquivos alterados com 27 adições e 12 exclusões
+13 -12
Ver Arquivo
@@ -156,7 +156,7 @@ class PreClass : public AtomicCountable {
struct Const {
Const() {}
Const(PreClass* preClass, const StringData* n,
const StringData* typeConstraint, const TypedValue& val,
const StringData* typeConstraint, const TypedValue& val,
const StringData* phpCode);
void prettyPrint(std::ostream& out) const;
@@ -421,7 +421,7 @@ class PreClassEmitter {
, m_phpCode(0)
{}
Const(const StringData* n, const StringData* typeConstraint,
TypedValue* val, const StringData* phpCode)
TypedValue* val, const StringData* phpCode)
: m_name(n), m_typeConstraint(typeConstraint), m_phpCode(phpCode) {
memcpy(&m_val, val, sizeof(TypedValue));
}
@@ -467,7 +467,7 @@ class PreClassEmitter {
DataType hphpcType);
const Prop& lookupProp(const StringData* propName) const;
bool addConstant(const StringData* n, const StringData* typeConstraint,
TypedValue* val, const StringData* phpCode);
TypedValue* val, const StringData* phpCode);
void addUsedTrait(const StringData* traitName);
void addTraitPrecRule(const PreClass::TraitPrecRule &rule);
void addTraitAliasRule(const PreClass::TraitAliasRule &rule);
@@ -516,7 +516,7 @@ class PreClassRepoProxy : public RepoProxy {
friend class PreClass;
friend class PreClassEmitter;
public:
PreClassRepoProxy(Repo& repo);
explicit PreClassRepoProxy(Repo& repo);
~PreClassRepoProxy();
void createSchema(int repoId, RepoTxn& txn);
@@ -653,19 +653,20 @@ public:
Avail avail(Class *&parent, bool tryAutoload = false) const;
bool classof(const Class* cls) const {
/*
If cls is an interface or trait, we're going to have
to do the slow search via classof(PreClass*).
Otherwise, if this is not an interface or trait,
If cls is an interface, we can simply check to
see if cls is in this->m_interfaces.
Otherwise, if this is not an interface,
the classVec check will determine whether its
an instance of cls.
Otherwise, this is an interface or trait, and cls
an instance of cls (including the case where
this and cls are the same trait).
Otherwise, this is an interface, and cls
is not, so we need to return false. But the classVec
check can never return true in that case (cls's
classVec contains only non-interfaces and non-traits,
classVec contains only non-interfaces,
while this->classVec is either empty, or contains
interfaces/traits).
interfaces).
*/
if (UNLIKELY(cls->attrs() & (AttrInterface | AttrTrait))) {
if (UNLIKELY(cls->attrs() & AttrInterface)) {
return m_interfaces.lookupDefault(cls->m_preClass->name(), nullptr)
== cls;
}
+13
Ver Arquivo
@@ -0,0 +1,13 @@
<?php
trait T {
function foo() {
var_dump(__METHOD__);
}
}
function test($f) {
call_user_func($f);
}
test(array('T', 'T::foo'));
+1
Ver Arquivo
@@ -0,0 +1 @@
string(6) "T::foo"