add Callable typehint

php-5.4 has it http://www.php.net/manual/en/language.types.callable.php
Esse commit está contido em:
ptarjan
2013-03-20 02:21:16 -07:00
commit de Sara Golemon
commit cc37fe637a
6 arquivos alterados com 59 adições e 17 exclusões
+18 -4
Ver Arquivo
@@ -66,6 +66,7 @@ typedef __sighandler_t *sighandler_t;
#include "runtime/base/runtime_option.h"
#include "runtime/base/server/source_root_info.h"
#include "runtime/ext/ext_continuation.h"
#include "runtime/ext/ext_function.h"
#include "runtime/vm/debug/debug.h"
#include "runtime/vm/translator/targetcache.h"
#include "runtime/vm/translator/translator-deps.h"
@@ -10258,6 +10259,16 @@ VerifyParamTypeSlow(const Class* cls, const Class* constraint, int param) {
}
}
static void
VerifyParamCallable(ObjectData* obj, int param) {
TypedValue tv;
tvWriteObject(obj, &tv);
if (!UNLIKELY(f_is_callable(tvAsCVarRef(&tv)))) {
VerifyParamTypeFail(param);
}
tvDecRef(&tv);
}
void
TranslatorX64::translateVerifyParamType(const Tracelet& t,
const NormalizedInstruction& i) {
@@ -10283,18 +10294,21 @@ TranslatorX64::translateVerifyParamType(const Tracelet& t,
ScratchReg cls(m_regMap);
// Constraint may not be in the class-hierarchy of the method being traced,
// look up the class handle and emit code to put the Class* into a reg.
bool isSelfOrParent = tc.isSelf() || tc.isParent();
bool isSpecial = tc.isSelf() || tc.isParent() || tc.isCallable();
const Class* constraint = nullptr;
const StringData* clsName;
if (!isSelfOrParent) {
if (!isSpecial) {
clsName = tc.typeName();
constraint = Unit::lookupUniqueClass(clsName);
} else {
if (tc.isSelf()) {
tc.selfToClass(curFunc(), &constraint);
} else {
assert(tc.isParent());
} else if (tc.isParent()) {
tc.parentToClass(curFunc(), &constraint);
} else {
assert(tc.isCallable());
EMIT_RCALL(a, i, VerifyParamCallable, R(src), IMM(param));
return;
}
clsName = constraint ? constraint->preClass()->name() : nullptr;
}
+16 -12
Ver Arquivo
@@ -16,6 +16,7 @@
#include <util/base.h>
#include <util/trace.h>
#include <runtime/ext/ext_function.h>
#include <runtime/vm/hhbc.h>
#include <runtime/vm/class.h>
#include <runtime/vm/unit.h>
@@ -39,22 +40,23 @@ TypeConstraint::TypeConstraint(const StringData* typeName /* = NULL */,
const StringData* name;
Type type;
} pairs[] = {
{ StringData::GetStaticString("bool"), { KindOfBoolean, Precise }},
{ StringData::GetStaticString("boolean"), { KindOfBoolean, Precise }},
{ StringData::GetStaticString("bool"), { KindOfBoolean, Precise }},
{ StringData::GetStaticString("boolean"), { KindOfBoolean, Precise }},
{ StringData::GetStaticString("int"), { KindOfInt64, Precise }},
{ StringData::GetStaticString("integer"), { KindOfInt64, Precise }},
{ StringData::GetStaticString("int"), { KindOfInt64, Precise }},
{ StringData::GetStaticString("integer"), { KindOfInt64, Precise }},
{ StringData::GetStaticString("real"), { KindOfDouble, Precise }},
{ StringData::GetStaticString("double"), { KindOfDouble, Precise }},
{ StringData::GetStaticString("float"), { KindOfDouble, Precise }},
{ StringData::GetStaticString("real"), { KindOfDouble, Precise }},
{ StringData::GetStaticString("double"), { KindOfDouble, Precise }},
{ StringData::GetStaticString("float"), { KindOfDouble, Precise }},
{ StringData::GetStaticString("string"), { KindOfString, Precise }},
{ StringData::GetStaticString("string"), { KindOfString, Precise }},
{ StringData::GetStaticString("array"), { KindOfArray, Precise }},
{ StringData::GetStaticString("array"), { KindOfArray, Precise }},
{ StringData::GetStaticString("self"), { KindOfObject, Self }},
{ StringData::GetStaticString("parent"), { KindOfObject, Parent }},
{ StringData::GetStaticString("self"), { KindOfObject, Self }},
{ StringData::GetStaticString("parent"), { KindOfObject, Parent }},
{ StringData::GetStaticString("callable"), { KindOfObject, Callable }},
};
for (unsigned i = 0; i < sizeof(pairs) / sizeof(Pair); ++i) {
s_typeNamesToTypes[pairs[i].name] = pairs[i].type;
@@ -107,11 +109,13 @@ TypeConstraint::check(const TypedValue* tv, const Func* func) const {
return true;
}
const Class *c = nullptr;
if (isSelf() || isParent()) {
if (isSelf() || isParent() || isCallable()) {
if (isSelf()) {
selfToClass(func, &c);
} else if (isParent()) {
parentToClass(func, &c);
} else if (isCallable()) {
return f_is_callable(tvAsCVarRef(tv));
}
} else {
// We can't save the Class* since it moves around from request
+10 -1
Ver Arquivo
@@ -34,7 +34,8 @@ protected:
enum MetaType {
Precise,
Self,
Parent
Parent,
Callable
};
struct Type {
@@ -46,6 +47,9 @@ protected:
constexpr bool isSelf() const {
return m_metatype == Self;
}
constexpr bool isCallable() const {
return m_metatype == Callable;
}
};
Type m_type;
@@ -74,10 +78,15 @@ public:
bool isParent() const {
return m_type.isParent();
}
bool isCallable() const {
return m_type.isCallable();
}
bool isObject() const {
assert(IMPLIES(isParent(), m_type.m_dt == KindOfObject));
assert(IMPLIES(isSelf(), m_type.m_dt == KindOfObject));
assert(IMPLIES(isCallable(), m_type.m_dt == KindOfObject));
return m_type.m_dt == KindOfObject;
}
+12
Ver Arquivo
@@ -0,0 +1,12 @@
<?php
function a(callable $b) { $b(); }
$c = function() { var_dump(true); };
a($c);
try {
a('hi');
} catch (Exception $e) {
var_dump($e);
}
+2
Ver Arquivo
@@ -0,0 +1,2 @@
bool(true)
HipHop Fatal error: Argument 1 passed to a() must be an instance of callable, string given in hphp/test/vm/typehint_callable.php on line 3
+1
Ver Arquivo
@@ -0,0 +1 @@
filepath.filter