Skip to content

Regression test for overlapping inspect #5

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
wants to merge 1 commit into from

Conversation

drew-gross
Copy link

Hi I saw your talk today and am curious about how inspect is intended to behave when there are overlapping matches. Should it execute the first match? All the matches? Fail to compile? I've attached a regression test to demonstrate.

Current behaviour is:

// ----- Cpp2 support -----
#include "cpp2util.h"


#line 1 "../regression-tests/pure2-inspect-expression-in-generic-function-overlapping-types.cpp2"
[[nodiscard]] auto main() -> int;
#line 12 "../regression-tests/pure2-inspect-expression-in-generic-function-overlapping-types.cpp2"
auto test_generic(auto const& x) -> void;

//=== Cpp2 definitions ==========================================================

#line 1 "../regression-tests/pure2-inspect-expression-in-generic-function-overlapping-types.cpp2"
[[nodiscard]] auto main() -> int{
    std::variant<int,std::string> v { cpp2::as<std::string>("xyzzy") };
    std::any a { cpp2::as<std::string>("xyzzy") };
    std::optional<std::string> o { cpp2::as<std::string>("xyzzy") };

    test_generic(v);
    test_generic(a);
    test_generic(o);

}

auto test_generic(auto const& x) -> void{
    std::cout
        << std::setw(30) << typeid(x).name()
        << [&] () -> std::string { auto&& __expr = x;
            if (cpp2::is<std::string>(__expr)) { if constexpr( requires{"matches std::string";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF("matches std::string"),std::string> ) return "matches std::string"; else return std::string{}; else return std::string{}; }
            else if (cpp2::is<std::variant<int,std::string>>(__expr)) { if constexpr( requires{"matches std::variant<int, std::string>";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF("matches std::variant<int, std::string>"),std::string> ) return "matches std::variant<int, std::string>"; else return std::string{}; else return std::string{}; }
            else if (cpp2::is<std::any>(__expr)) { if constexpr( requires{"matches std::any";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF("matches std::any"),std::string> ) return "matches std::any"; else return std::string{}; else return std::string{}; }
            else if (cpp2::is<std::optional<std::string>>(__expr)) { if constexpr( requires{"matches std::optional<std::string>";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF("matches std::optional<std::string>"),std::string> ) return "matches std::optional<std::string>"; else return std::string{}; else return std::string{}; }
            else return "no match"; }
        ()
        << "\n";
}

I tried it in godbolt and it seems like the std::any matcher fails to compile, and for the rest it executes the first successful match. (but I may have screwed up while trying to compile the generated C++ code, maybe the std::any would compile if I did something different)

@drew-gross
Copy link
Author

BTW not sure if you appreciate pull requests and bug reports at this stage, but I think I found a bug: is std::nullopt_t doesn't appear to match an empty optional: godbolt. I can try to submit a fix if you would appreciate that.

@JohelEGP
Copy link
Contributor

It should be the first, as presented (https://github.com/hsutter/cppfront#2021-is-as-and-pattern-matching). All those pass the is std::string test, so of course only the first match executes.

@Vinodkumar-Karapurath
Copy link

Hi.. i have one query

@hsutter
Copy link
Owner

hsutter commented Sep 24, 2022

Thanks! I've got a fix for the any matcher failure and I'll add a variation of your example as a test cases in that same commit.

Re matching nullopt_t: That's a good question, nullopt_t is already an example of where we have divergent spellings of "empty state":

  • nullopt_t is one for std::optional
  • nullptr_t is arguably another for raw/smart pointers (generalizing that, the default-constructed state is one for Pointer-like things including iterators; this is already the way the Lifetime profile handles it)
  • monostate (and arguably valueless_by_exception) is another for std::variant
  • !a.has_value is another for std::any
  • !f.is_ready is another for std:::*future

So we have not only divergently spelled types for this concept but also even more divergently spelled state queries...)

I'll think more about this. My current thought is that the right solution is for Cpp2 is to have some single spelling for this, perhaps void or possibly an actual common "cpp2::empty" type (or using empty = void; :) ) that works the same for all of these, and supports is void but not as void... hmm, I think I might like that spelling.

@hsutter hsutter closed this in e119ada Sep 24, 2022
@hsutter
Copy link
Owner

hsutter commented Sep 24, 2022

OK, I've now added general support for is void (and a synonym is empty with a TODO note about whether we really need a synonym), and this test case works uniformly for all these types -- pointers, iterators, variant, any, optional:


main: () -> int = {
    p: std::unique_ptr<int> = ();
    i: std::vector<int>::iterator = ();
    v: std::variant<std::monostate, int, std::string> = ();
    a: std::any = ();
    o: std::optional<std::string> = ();

    std::cout << "\nAll these cases satisfy \"VOYDE AND EMPTIE\"\n";

    test_generic(p);
    test_generic(i);
    test_generic(v);
    test_generic(a);
    test_generic(o);
}

test_generic: ( x: _ ) = {
    std::cout
        << "\n" << typeid(x).name() << "\n    ..."
        << inspect x -> std::string {
            is void = " VOYDE AND EMPTIE";
            is _   = " no match";
        }
        << "\n";
}

This is in response to the question above about:

std::nullopt_t doesn't appear to match an empty optional

That should now work, and work uniformly and generally for all "empty" states in these types. Thanks!

@malcolmdavey
Copy link

Wondering what what happen for the new C++23 std::expected.
Would an expected with no value (i.e. has_value() is false) also match void, assuming it doesn't match on an error type), otherwise would we treat it as a variant?

Azmah-Bad pushed a commit to Azmah-Bad/cppfront that referenced this pull request Feb 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants