Skip to content

Commit eb552be

Browse files
committed
fix(to_cpp1): improve recognition of dependent types and deducible parameters
1 parent ccf7011 commit eb552be

11 files changed

+855
-128
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Dependent, non-deducible parameters are wrapped like non-dependent parameters.
2+
init: <T> (out x: std::integral_constant<i32, T::value>) = { x = (); }
3+
init: <T> (out x: std::integral_constant<i32, T::value>, _: T) = { x = (); }
4+
id: <T> (x: std::integral_constant<i32, T::value>) -> _ = x&;
5+
id: <T> (x: std::integral_constant<i32, T::value>, y: T) = { assert(x& == y&); }
6+
7+
main: () = {
8+
zero: type == std::integral_constant<i32, 0>;
9+
10+
z: zero;
11+
init<zero>(out z);
12+
assert(id<zero>(z) == z&);
13+
14+
// Deducible parameters.
15+
_ = :v = 0;
16+
:<T> (_: std::vector<T>) = {}(:std::vector<i32> = ());
17+
:<T> (_: std::vector<std::vector<T>>) = {}(:std::vector<std::vector<i32>> = ());
18+
// _ = :<T, U> (x: std::pair<T, typename U::value_type>, y: U) = {}(:std::pair = (0, 0), z); // Blocked on #727.
19+
:<T, U> (_: std::array<T, U::value>, _: U) = {}(:std::array<i32, 0> = (), z);
20+
init(out z, z);
21+
id(z, z);
22+
23+
// Test that these are emitted unwrapped in case they are deducible.
24+
(copy f := :<T> (_: std::vector<std::type_identity_t<T>>) = {})
25+
static_assert(!std::is_invocable_v<decltype(f), std::vector<i32>>, "`T` is non-deducible.");
26+
(copy f := :<T> (_: std::vector<std::vector<T>>) = {})
27+
static_assert(std::is_invocable_v<decltype(f), std::vector<std::vector<i32>>>, "`T` is deducible.");
28+
}
29+
30+
v: <T> type = {
31+
operator=: (out this, _: T) = { }
32+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
main: () = {
2+
a: type == b;
3+
b: type == a;
4+
_ = a::t;
5+
_ = b::t;
6+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
identity: <T> type == T;
2+
3+
f: <T> (inout _: T::value_type) = { }
4+
f: <T> (move _: T::value_type) = { }
5+
f: <T, V: T::value_type> (x: T::value_type) -> T::value_type = {
6+
assert(x is T::value_type);
7+
y: T::value_type;
8+
y = x;
9+
z: type == T::value_type;
10+
return (:T::value_type = x);
11+
12+
// Dependent *template-id*s.
13+
_ = :identity<T>::value_type = (); // First identifier.
14+
_ = :std::optional<T>::value_type = (); // Non-first identifier.
15+
_ = :std::array<i32, T::value>::value_type = ();
16+
_ = :std::array<i32, T::value + T::value>::value_type = ();
17+
18+
// Emitted `template`.
19+
ptr: type == * T; // Also test lookup through type aliases.
20+
nptr: type == * i32;
21+
_ = :std::pointer_traits<ptr>::rebind<ptr> = (); // Type-only context.
22+
_ = :std::pointer_traits<nptr>::rebind<nptr> = (); // Non-dependent.
23+
_ = :std::pointer_traits<nptr>::rebind<ptr> = (); // Dependent on the nested template.
24+
_ = :std::pointer_traits<ptr>::rebind<nptr> = (); // Dependent on the outer template.
25+
// _ = :identity<typename std::pointer_traits<ptr>::rebind<ptr>> = (); // Non type-only context. Blocked on #727.
26+
27+
// Aliases.
28+
w: type == T;
29+
_ = :w::value_type = x;
30+
v: type == w;
31+
_ = :v::value_type = x;
32+
a: type == T::type;
33+
_ = :a::value_type = x;
34+
35+
{
36+
// Test that there's no prefixed `typename` to....
37+
_ = std::integral_constant<i32, T::value>(); // `T::value`.
38+
_ = :std::type_identity_t<T> = (); // `std::type_identity_t<T>`.
39+
40+
// Test that non-dependent names aren't emitted with `typename`.
41+
a: type == std::integral_constant<i32, 0>;
42+
b: type == a;
43+
c: type == b;
44+
_ = :b::value_type = x;
45+
_ = :c::value_type = x;
46+
}
47+
}
48+
49+
t: @cpp1_rule_of_zero <T: type> type = {
50+
u: type = {
51+
x: T::value_type = ();
52+
this: T::type = ();
53+
// Test that there's no `typename` in the member initializer list.
54+
operator=: (out this, that) = { }
55+
}
56+
x: T::value_type = 0;
57+
}
58+
59+
main: () = {
60+
zero: type == std::integral_constant<i32, 0>;
61+
_ = f<zero, 0>(0);
62+
63+
_ = : ::t<zero> = ();
64+
65+
// Emitted `template` (noop, taken care of by the UFCS macro).
66+
_ = :(move f) = _ = f.operator()<i32>();(:<T> () = {});
67+
68+
// Nesting is not relevant to lookup.
69+
_ = :<T> () = { _ = :T::value_type = (); };
70+
_ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; };
71+
_ = :() = { _ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; }; };
72+
_ = :() = { _ = :() = { _ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; }; }; };
73+
_ = :() = { _ = :() = { _ = :<T> () = { _ = :() = { _ = :T::value_type = (); }; }; }; };
74+
_ = :() = { _ = :<T> () = { _ = :() = { _ = :() = { _ = :T::value_type = (); }; }; }; };
75+
_ = :<T> () = { _ = :() = { _ = :() = { _ = :() = { _ = :T::value_type = (); }; }; }; };
76+
_ = :<T> () = { _ = :() = { _ = :() = { _ = :(_: T::value_type) = {}; }; }; };
77+
_ = :<T> () = { _ = :() = { _ = :(_: T::value_type) = { _ = :() = {}; }; }; };
78+
_ = :<T> () = { _ = :(_: T::value_type) = { _ = :() = { _ = :() = {}; }; }; };
79+
_ = :<T> (_: T::value_type) = { _ = :() = { _ = :() = { _ = :() = {}; }; }; };
80+
81+
// Lookup.
82+
{
83+
alias: type == std::integral_constant<i32, 0>;
84+
_ = :alias::value_type = 0; // Non-dependent.
85+
}
86+
_ = :<T> (_: T) = {
87+
alias: type == std::integral_constant<T, 0>;
88+
_ = :alias::value_type = 0; // Dependent.
89+
{
90+
alias: type == std::integral_constant<i32, 0>;
91+
_ = :alias::value_type = 0; // Non-dependent.
92+
}
93+
}(0);
94+
95+
_ = :(r) -> std::type_identity_t<decltype(begin(r)*)> = r[0];(std::vector<int>(1));
96+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2"
10+
11+
#line 30 "pure2-bugfix-for-deducible-parameters.cpp2"
12+
template<typename T> class v;
13+
14+
15+
//=== Cpp2 type definitions and function declarations ===========================
16+
17+
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2"
18+
// Dependent, non-deducible parameters are wrapped like non-dependent parameters.
19+
#line 2 "pure2-bugfix-for-deducible-parameters.cpp2"
20+
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x) -> void;
21+
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& unnamed_param_2) -> void;
22+
template<typename T> [[nodiscard]] auto id(cpp2::impl::in<std::integral_constant<cpp2::i32,T::value>> x) -> auto;
23+
template<typename T> auto id(cpp2::impl::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void;
24+
25+
auto main() -> int;
26+
27+
#line 30 "pure2-bugfix-for-deducible-parameters.cpp2"
28+
template<typename T> class v {
29+
public: explicit v([[maybe_unused]] T const& unnamed_param_2);
30+
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2"
31+
public: auto operator=([[maybe_unused]] T const& unnamed_param_2) -> v& ;
32+
public: v(v const&) = delete; /* No 'that' constructor, suppress copy */
33+
public: auto operator=(v const&) -> void = delete;
34+
35+
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2"
36+
};
37+
38+
39+
//=== Cpp2 function definitions =================================================
40+
41+
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2"
42+
43+
#line 2 "pure2-bugfix-for-deducible-parameters.cpp2"
44+
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x) -> void{x.construct(); }
45+
#line 3 "pure2-bugfix-for-deducible-parameters.cpp2"
46+
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& unnamed_param_2) -> void{x.construct(); }
47+
#line 4 "pure2-bugfix-for-deducible-parameters.cpp2"
48+
template<typename T> [[nodiscard]] auto id(cpp2::impl::in<std::integral_constant<cpp2::i32,T::value>> x) -> auto { return &x; }
49+
#line 5 "pure2-bugfix-for-deducible-parameters.cpp2"
50+
template<typename T> auto id(cpp2::impl::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void{if (cpp2::cpp2_default.is_active() && !(&x == &y) ) { cpp2::cpp2_default.report_violation(""); }}
51+
52+
#line 7 "pure2-bugfix-for-deducible-parameters.cpp2"
53+
auto main() -> int{
54+
using zero = std::integral_constant<cpp2::i32,0>;
55+
56+
cpp2::impl::deferred_init<zero> z;
57+
init<zero>(cpp2::impl::out(&z));
58+
if (cpp2::cpp2_default.is_active() && !(id<zero>(z.value()) == &z.value()) ) { cpp2::cpp2_default.report_violation(""); }
59+
60+
// Deducible parameters.
61+
static_cast<void>(v{ 0});
62+
[]<typename T>([[maybe_unused]] std::vector<T> const& unnamed_param_1) -> void{}(std::vector<cpp2::i32>{});
63+
[]<typename T>([[maybe_unused]] std::vector<std::vector<T>> const& unnamed_param_1) -> void{}(std::vector<std::vector<cpp2::i32>>{});
64+
// _ = :<T, U> (x: std::pair<T, typename U::value_type>, y: U) = {}(:std::pair = (0, 0), z); // Blocked on #727.
65+
[]<typename T, typename U>([[maybe_unused]] std::array<T,U::value> const& unnamed_param_1, [[maybe_unused]] U const& unnamed_param_2) -> void{}(std::array<cpp2::i32,0>{}, z.value());
66+
init(cpp2::impl::out(&z.value()), z.value());
67+
id(z.value(), cpp2::move(z.value()));
68+
{
69+
auto f{[]<typename T>([[maybe_unused]] std::vector<std::type_identity_t<T>> const& unnamed_param_1) -> void{}};
70+
71+
// Test that these are emitted unwrapped in case they are deducible.
72+
73+
#line 25 "pure2-bugfix-for-deducible-parameters.cpp2"
74+
static_assert(!(std::is_invocable_v<decltype(cpp2::move(f)),std::vector<cpp2::i32>>), "`T` is non-deducible.");
75+
}
76+
{
77+
auto f{[]<typename T>([[maybe_unused]] std::vector<std::vector<T>> const& unnamed_param_1) -> void{}};
78+
79+
#line 27 "pure2-bugfix-for-deducible-parameters.cpp2"
80+
static_assert(std::is_invocable_v<decltype(cpp2::move(f)),std::vector<std::vector<cpp2::i32>>>, "`T` is deducible.");
81+
}
82+
#line 28 "pure2-bugfix-for-deducible-parameters.cpp2"
83+
}
84+
85+
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2"
86+
template <typename T> v<T>::v([[maybe_unused]] T const& unnamed_param_2){}
87+
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2"
88+
template <typename T> auto v<T>::operator=([[maybe_unused]] T const& unnamed_param_2) -> v& {
89+
return *this; }
90+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-bugfix-for-deducible-parameters.cpp2... ok (all Cpp2, passes safety checks)
2+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2"
10+
11+
12+
//=== Cpp2 type definitions and function declarations ===========================
13+
14+
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2"
15+
auto main() -> int;
16+
17+
//=== Cpp2 function definitions =================================================
18+
19+
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2"
20+
auto main() -> int{
21+
#line 2 "pure2-bugfix-for-dependent-types-recursion.cpp2"
22+
using a = b;
23+
using b = a;
24+
static_cast<void>(a::t);
25+
static_cast<void>(b::t);
26+
}
27+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-bugfix-for-dependent-types-recursion.cpp2... ok (all Cpp2, passes safety checks)
2+

0 commit comments

Comments
 (0)