Fixed usertype checking for overloading resolution (and for userdata in general)

This commit is contained in:
ThePhD 2016-02-11 02:28:38 -05:00
parent 427194bc92
commit a71c9737d4
2 changed files with 42 additions and 14 deletions

View File

@ -64,7 +64,7 @@ struct overloaded_function : base_function {
if (!detail::check_types(args_type(), args_type(), L)) { if (!detail::check_types(args_type(), args_type(), L)) {
return match_arity(L, x, indices<In...>()); return match_arity(L, x, indices<In...>());
} }
return stack::typed_call(return_type(), args_type(), func, L); return stack::typed_call<false>(return_type(), args_type(), func, L);
} }
int match_arity(lua_State* L) { int match_arity(lua_State* L) {
@ -120,7 +120,7 @@ struct usertype_overloaded_function : base_function {
return match_arity(L, x, indices<In...>()); return match_arity(L, x, indices<In...>());
} }
func.item = ptr(stack::get<T>(L, 1)); func.item = ptr(stack::get<T>(L, 1));
return stack::typed_call(return_type(), args_type(), func, L); return stack::typed_call<false>(return_type(), args_type(), func, L);
} }
int match_arity(lua_State* L) { int match_arity(lua_State* L) {
@ -175,7 +175,7 @@ struct usertype_indexing_function<overload_set<Functions...>, T> : base_function
return match_arity(L, x, indices<In...>()); return match_arity(L, x, indices<In...>());
} }
func.item = ptr(stack::get<T>(L, 1)); func.item = ptr(stack::get<T>(L, 1));
return stack::typed_call(return_type(), args_type(), func, L); return stack::typed_call<false>(return_type(), args_type(), func, L);
} }
int match_arity(lua_State* L) { int match_arity(lua_State* L) {

View File

@ -203,19 +203,47 @@ struct checker {
} }
}; };
template <typename T, type expected, typename C> template <typename T, typename C>
struct checker<T*, expected, C> { struct checker<T*, type::userdata, C> {
template <typename Handler> template <typename Handler>
static bool check (lua_State* L, int index, const Handler& handler) { static bool check (lua_State* L, int index, const Handler& handler) {
const type indextype = type_of(L, index); const type indextype = type_of(L, index);
// Allow nil to be transformed to nullptr // Allow nil to be transformed to nullptr
bool success = expected == indextype || indextype == type::nil; if (indextype == type::nil) {
if (!success) { return true;
// expected type, actual type
handler(L, index, expected, indextype);
} }
return checker<T, type::userdata, C>{}.check(L, indextype, index, handler);
}
};
template <typename T,typename C>
struct checker<T, type::userdata, C> {
template <typename Handler>
static bool check (lua_State* L, type indextype, int index, const Handler& handler) {
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype);
return false;
}
if (lua_getmetatable(L, index) == 0) {
handler(L, index, type::userdata, indextype);
return false;
}
const type expectedmetatabletype = static_cast<type>(luaL_getmetatable(L, &usertype_traits<T>::metatable[0]));
if (expectedmetatabletype == type::nil) {
lua_pop(L, 2);
handler(L, index, type::userdata, indextype);
return false;
}
bool success = lua_rawequal(L, -1, -2) == 1;
lua_pop(L, 2);
return success; return success;
} }
template <typename Handler>
static bool check (lua_State* L, int index, const Handler& handler) {
const type indextype = type_of(L, index);
return check(L, indextype, index, handler);
}
}; };
template<typename T, typename> template<typename T, typename>
@ -628,17 +656,17 @@ inline void call(lua_State* L, types<void> tr, types<Args...> ta, Fx&& fx, FxArg
call<checkargs>(L, 0, ta, tr, ta, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); call<checkargs>(L, 0, ta, tr, ta, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
template<typename... Args, typename Fx> template<bool check_args = detail::default_check_arguments, typename... Args, typename Fx>
inline int typed_call(types<void> tr, types<Args...> ta, Fx&& fx, lua_State* L) { inline int typed_call(types<void> tr, types<Args...> ta, Fx&& fx, lua_State* L) {
stack::call(L, 0, tr, ta, fx); stack::call<check_args>(L, 0, tr, ta, fx);
int nargs = static_cast<int>(sizeof...(Args)); int nargs = static_cast<int>(sizeof...(Args));
lua_pop(L, nargs); lua_pop(L, nargs);
return 0; return 0;
} }
template<typename... Ret, typename... Args, typename Fx> template<bool check_args = detail::default_check_arguments, typename... Ret, typename... Args, typename Fx>
inline int typed_call(types<Ret...> tr, types<Args...> ta, Fx&& fx, lua_State* L) { inline int typed_call(types<Ret...> tr, types<Args...> ta, Fx&& fx, lua_State* L) {
decltype(auto) r = stack::call(L, 0, tr, ta, fx); decltype(auto) r = stack::call<check_args>(L, 0, tr, ta, fx);
int nargs = static_cast<int>(sizeof...(Args)); int nargs = static_cast<int>(sizeof...(Args));
lua_pop(L, nargs); lua_pop(L, nargs);
return stack::push(L, std::forward<decltype(r)>(r)); return stack::push(L, std::forward<decltype(r)>(r));