Skip to content
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

[BUG] No direct UFCS syntax for (captured function object, dependent base member, function object prvalue) #748

Open
JohelEGP opened this issue Oct 12, 2023 · 4 comments
Labels
bug Something isn't working

Comments

@JohelEGP
Copy link
Contributor

JohelEGP commented Oct 12, 2023

Title: Can't capture function object for UFCS.

Description:

As an exercise, I tried implementing the CL combinators from Function Composition in Programming Languages - Conor Hoekstra - CppNorth 2023.

Implementations

https://cpp2.godbolt.org/z/WjTTnf383:
1699742209
1697146848
1697146876

At first, I tried using UFCS.
That doesn't work because the capture is the postfix-expression before the $.
That includes the object argument.
But I just wanted the function object.

Minimal reproducer (https://cpp2.godbolt.org/z/cYcb4c5YW):

w: (f) :(x) x.f$();
// w: (f) :(x) f$(x);
main: () = {
  assert(w(:(x) -x;)(1) == -1);
}
Commands:
cppfront main.cpp2
clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -I . main.cpp

Expected result: Same as not using UFCS.

Actual result and error:

Cpp2 lowered to Cpp1:
//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"



//=== Cpp2 type definitions and function declarations ===========================

[[nodiscard]] auto w(auto const& f) -> auto;
// w: (f) :(x) f$(x);
auto main() -> int;
  

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

[[nodiscard]] auto w(auto const& f) -> auto { return [_0 = x.f](auto const& x) -> auto { return _0();  };  }

auto main() -> int{
  cpp2::Default.expects(w([](auto const& x) -> auto { return -x;  })(1) == -1, "");
}
Output:
build/main.cpp:19:60: error: use of undeclared identifier 'x'
   19 | [[nodiscard]] auto w(auto const& f) -> auto { return [_0 = x.f](auto const& x) -> auto { return _0();  };  }
      |                                                            ^
build/main.cpp:19:97: error: use of undeclared identifier '_0'
   19 | [[nodiscard]] auto w(auto const& f) -> auto { return [_0 = x.f](auto const& x) -> auto { return _0();  };  }
      |                                                                                                 ^
build/main.cpp:19:77: warning: unused parameter 'x' [-Wunused-parameter]
   19 | [[nodiscard]] auto w(auto const& f) -> auto { return [_0 = x.f](auto const& x) -> auto { return _0();  };  }
      |                                                                             ^
build/main.cpp:19:34: warning: unused parameter 'f' [-Wunused-parameter]
   19 | [[nodiscard]] auto w(auto const& f) -> auto { return [_0 = x.f](auto const& x) -> auto { return _0();  };  }
      |                                  ^
2 warnings and 2 errors generated.
@JohelEGP
Copy link
Contributor Author

From #741 (comment):

. :(x) zip_transform(std::logical_or(), x, scan_left(x, true, std::not_equal_to())) ()

That's not valid grammar (https://cpp2.godbolt.org/z/9avjYh6sb):

Right, I like the call helper well enough that I'm waiting to see if there's really a need to write a new function expression in the middle of a postfix-expression... it's doable but is it needed?

You could say it's needed for #748,
so we could write w: (f) :(x) x.(f$)();
and have x.(f$)() call (f$)(x).

@JohelEGP
Copy link
Contributor Author

Also, can't do UFCS on a dependent base member (#741 (comment)):

. :(x) zip_transform(std::logical_or(), x, scan_left(x, true, std::not_equal_to())) ()

That's not valid grammar (https://cpp2.godbolt.org/z/9avjYh6sb):

Right, I like the call helper well enough that I'm waiting to see if there's really a need to write a new function expression in the middle of a postfix-expression... it's doable but is it needed?

You could say it's needed for #748,
so we could write w: (f) :(x) x.(f$)();
and have x.(f$)() call (f$)(x).

There is another use case.
In a member function of a type template,
UFCS on a dependent base member requires explicit qualification (https://cpp2.godbolt.org/z/Mff1G9331):

u: @struct <T> type = {
  f: (_) true;
}

t: @struct <T> type = {
  this: u<T>;

  operator(): (this, r: std::span<const int>) -> _ = {
    for r do (e) {
      // OK.
      return this.f(e);

      // error: explicit qualification required to use member 'f' from dependent base class
      //   16 |       return CPP2_UFCS_0(f, e);
      //      |                          ^
      return e.f();

      // error: expected unqualified-id
      //   21 |       return CPP2_UFCS_0(f, e.(*this));
      //      |                               ^
      return e.this.f();

      // OK.
      return e.u<T>::f();

      // What I would like to write:
      // return e.(this.f)();
      //  That translates to this:
      return (this.f)(e);
    }
  }
}

main: () = {
  r: std::vector = (0, 1, 2);
  assert(t<int>()(r));
}

@JohelEGP JohelEGP changed the title [BUG] Can't capture function object for UFCS [BUG] Can't use UFCS on captured function object or dependent base member Nov 25, 2023
@JohelEGP
Copy link
Contributor Author

Also, can't do UFCS on a dependent base member (#741 (comment)):

For now, I can workaround this with using u<T>::f;, which makes return e.f(); well-formed: https://cpp2.godbolt.org/z/T5b5sxbYr.

@JohelEGP
Copy link
Contributor Author

Function object prvalue

I forgot to mention this other case where you first need to construct a callable.

Consider the call in the assert in the main above: t<int>()(r).
t<int>() is the function object we want to call.

Let's rewrite it in UFCS order: r.t<int>()().
The function to call becomes t<int> instead.
The second () applies to the result of the UFCS.

The call helper does help:
r.call(t<int>()) (https://cpp2.godbolt.org/z/Mfc5TP8xz).

@JohelEGP JohelEGP changed the title [BUG] Can't use UFCS on captured function object or dependent base member [BUG] No direct UFCS syntax for (captured function object, dependent base member, function object prvalue) Nov 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant