Skip to content

as(): make as() cast to use type_safety.enforce #1267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 38 additions & 37 deletions include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@ class contract_group {

constexpr contract_group (handler h = {}) : reporter{h} { }
constexpr auto set_handler(handler h = {}) { reporter = h; }
constexpr auto get_handler() const -> handler { return reporter; }
constexpr auto is_active () const -> bool { return reporter != handler{}; }

constexpr auto enforce(bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
Expand Down Expand Up @@ -2073,7 +2074,7 @@ auto as(X&& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT_AS) -> decltype(auto)
if constexpr (std::is_same_v< typename It::type, C >) { if (CPP2_FORWARD(x).index() == It::index) { ptr = &std::get<It::index>(x); return true; } };
return false;
});
if (!ptr) { Throw( std::bad_variant_access(), "'as' cast failed for 'variant'"); }
type_safety.enforce(ptr, "'as' cast failed for 'variant'");
return cpp2::forward_like<decltype(x)>(*ptr);
}

Expand All @@ -2083,28 +2084,22 @@ auto as(X&& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT_AS) -> decltype(auto)

// is Type
//
template<typename T, typename X>
requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any> && !std::is_same_v<T,empty>)
constexpr auto is( X const& x ) -> bool
{ return x.type() == Typeid<T>(); }

template<typename T, typename X>
requires (std::is_same_v<X,std::any> && std::is_same_v<T,empty>)
constexpr auto is( X const& x ) -> bool
{ return !x.has_value(); }

template<typename T, std::same_as<std::any> X>
constexpr auto is( X const& x ) -> bool{
if (!x.has_value()) {
return std::is_same_v<T,empty>;
}
return x.type() == Typeid<T>();
}

// is Value
//
inline constexpr auto is( std::any const& x, auto&& value ) -> bool
{
// Predicate case
if constexpr (requires{ bool{ value(x) }; }) {
if constexpr (valid_predicate<decltype(value), decltype(x)>) {
return value(x);
}
else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
return false;
}

// Value case
else if constexpr (requires{ bool{ *std::any_cast<CPP2_TYPEOF(value)>(&x) == value }; }) {
Expand All @@ -2118,10 +2113,12 @@ inline constexpr auto is( std::any const& x, auto&& value ) -> bool

// as
//
template<typename T, typename X>
requires (!std::is_reference_v<T> && std::is_same_v<X,std::any> && !std::is_same_v<T,std::any>)
constexpr auto as( X const& x ) -> T
{ return std::any_cast<T>( x ); }
template<typename T, same_type_as<std::any> X>
constexpr auto as( X && x ) -> decltype(auto) {
constness_like_t<T, X>* ptr = std::any_cast<T>( &x );
type_safety.enforce(ptr, "'as' cast failed for 'std::any'");
return cpp2::forward_like<X>(*ptr);
}


//-------------------------------------------------------------------------------------------------------------
Expand All @@ -2130,29 +2127,26 @@ constexpr auto as( X const& x ) -> T

// is Type
//
template<typename T, typename X>
requires std::is_same_v<X,std::optional<T>>
constexpr auto is( X const& x ) -> bool
{ return x.has_value(); }

template<typename T, typename U>
requires std::is_same_v<T,empty>
constexpr auto is( std::optional<U> const& x ) -> bool
{ return !x.has_value(); }

template<typename T, specialization_of_template<std::optional> X>
constexpr auto is( X const& x ) -> bool {
if (!x.has_value()) {
return std::same_as<T, empty>;
}
if constexpr (requires { static_cast<const T&>(*x);}) {
return true;
}
return false;
}

// is Value
//
template<typename T>
constexpr auto is( std::optional<T> const& x, auto&& value ) -> bool
{
// Predicate case
if constexpr (requires{ bool{ value(x) }; }) {
if constexpr (valid_predicate<decltype(value), decltype(x)>) {
return value(x);
}
else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
return false;
}

// Value case
else if constexpr (requires{ bool{ x.value() == value }; }) {
Expand All @@ -2164,10 +2158,17 @@ constexpr auto is( std::optional<T> const& x, auto&& value ) -> bool

// as
//
template<typename T, typename X>
requires std::is_same_v<X,std::optional<T>>
constexpr auto as( X const& x ) -> decltype(auto)
{ return x.value(); }
template<typename T, specialization_of_template<std::optional> X>
constexpr auto as( X&& x ) -> decltype(auto) {
constness_like_t<T, X>* ptr = nullptr;
if constexpr (requires { static_cast<constness_like_t<T, X>&>(*x); }) {
if (x.has_value()) {
ptr = &static_cast<constness_like_t<T, X>&>(*x);
}
}
type_safety.enforce(ptr, "'as' cast failed for 'std::optional'");
return cpp2::forward_like<X>(*ptr);
}


} // impl
Expand Down
32 changes: 32 additions & 0 deletions regression-tests/mixed-as-with-typesafety.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
void throw_error(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM) {
throw std::runtime_error(std::string("Type safety exception: ") + msg);
}

make_throwable: (inout cg : cpp2::contract_group) -> _ = {
h := cg.get_handler();
sh := :(pcg : *cpp2::contract_group) = {
pcg*.set_handler(h$);
};
cg.set_handler(throw_error);
return std::unique_ptr<cpp2::contract_group, decltype(sh)>(cg&, sh);
}

void expect_no_throw(auto&& fun) try {
fun();
} catch(std::exception const& e) {
std::cout << e.what() << std::endl;
} catch(...) {
std::cout << "Unknown exception!" << std::endl;
}

main: () = {
o : std::optional<int> = ();

(_ := make_throwable(cpp2::type_safety)) {
expect_no_throw( :() = {
std::cout << (o$ as int) << std::endl; // that will throw
});
}

std::cout << (o as int) << std::endl; // that will terminate
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Type safety exception: 'as' cast failed for 'std::optional'
Type safety violation: 'as' cast failed for 'std::optional'
libc++abi: terminating
Original file line number Diff line number Diff line change
@@ -1,66 +1,66 @@
In file included from pure2-default-arguments.cpp:7:
../../../include/cpp2util.h:2086:28: error: local variable ‘obj’ may not appear in this context
2086 | template<typename T, typename X>
2086 | template<typename T, std::same_as<std::any> X>
| ^~~
../../../include/cpp2util.h:2047:34: note: in definition of macro ‘CPP2_UFCS_IDENTITY’
2047 | return false;
| ^
../../../include/cpp2util.h:2086:15: note: in expansion of macro ‘CPP2_FORWARD’
2086 | template<typename T, typename X>
2086 | template<typename T, std::same_as<std::any> X>
| ^~~~~~~~~~~~
../../../include/cpp2util.h:2107:22: note: in expansion of macro ‘CPP2_UFCS_CONSTRAINT_ARG’
2107 | }
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
pure2-default-arguments.cpp2:6:22: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
../../../include/cpp2util.h:2086:92: error: local variable ‘params’ may not appear in this context
2086 | template<typename T, typename X>
2086 | template<typename T, std::same_as<std::any> X>
| ^
../../../include/cpp2util.h:2047:34: note: in definition of macro ‘CPP2_UFCS_IDENTITY’
2047 | return false;
| ^
../../../include/cpp2util.h:2086:79: note: in expansion of macro ‘CPP2_FORWARD’
2086 | template<typename T, typename X>
2086 | template<typename T, std::same_as<std::any> X>
| ^
../../../include/cpp2util.h:2107:22: note: in expansion of macro ‘CPP2_UFCS_CONSTRAINT_ARG’
2107 | }
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
pure2-default-arguments.cpp2:6:22: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
../../../include/cpp2util.h:2087:74: error: local variable ‘obj’ may not appear in this context
2087 | requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any> && !std::is_same_v<T,empty>)
| ^~~
2087 | constexpr auto is( X const& x ) -> bool{
| ^
../../../include/cpp2util.h:2047:34: note: in definition of macro ‘CPP2_UFCS_IDENTITY’
2047 | return false;
| ^
../../../include/cpp2util.h:2087:61: note: in expansion of macro ‘CPP2_FORWARD’
2087 | requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any> && !std::is_same_v<T,empty>)
| ^~~~~~~~~~~~
2087 | constexpr auto is( X const& x ) -> bool{
| ^
../../../include/cpp2util.h:2107:22: note: in expansion of macro ‘CPP2_UFCS_CONSTRAINT_ARG’
2107 | }
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
pure2-default-arguments.cpp2:6:22: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
../../../include/cpp2util.h:2087:93: error: local variable ‘params’ may not appear in this context
2087 | requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any> && !std::is_same_v<T,empty>)
| ^~~~~~
2087 | constexpr auto is( X const& x ) -> bool{
| ^
../../../include/cpp2util.h:2047:34: note: in definition of macro ‘CPP2_UFCS_IDENTITY’
2047 | return false;
| ^
../../../include/cpp2util.h:2087:80: note: in expansion of macro ‘CPP2_FORWARD’
2087 | requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any> && !std::is_same_v<T,empty>)
| ^~~~~~~~~~~~
2087 | constexpr auto is( X const& x ) -> bool{
| ^
../../../include/cpp2util.h:2107:22: note: in expansion of macro ‘CPP2_UFCS_CONSTRAINT_ARG’
2107 | }
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
pure2-default-arguments.cpp2:6:22: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
pure2-default-arguments.cpp2:6:61: error: ‘std::source_location’ has not been declared
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
In file included from mixed-bugfix-for-ufcs-non-local.cpp:6:
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:13:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:13:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:31:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:31:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:33:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:33:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
In file included from mixed-bugfix-for-ufcs-non-local.cpp:6:
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:13:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:13:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:31:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:31:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:33:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:33:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | {
2100 | return value(x);
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 |
2137 | return false;
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
Loading
Loading