Skip to content

Commit

Permalink
feat: allow object alias specialization
Browse files Browse the repository at this point in the history
  • Loading branch information
JohelEGP committed Oct 31, 2023
1 parent 7e96f5d commit 7dd5d76
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 8 deletions.
6 changes: 6 additions & 0 deletions regression-tests/pure2-template-specialization.cpp2
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ t: @struct specialize<i64> type = {
v: <T> const i32 = 1;
v: <> specialize<void> const i32 = 2;
v: specialize<i64> const i32 = 3;
v: specialize<i16> std::optional<i32> == 4;
v: <> specialize<i8> std::optional<i8> == 5;
v: <T> specialize<* T> std::optional<int> == 6;
main: () = {
[[assert Testing: t<i32>().a == 1]]
[[assert Testing: t<void>().b == 2]]
[[assert Testing: t<i64>().c == 3]]
[[assert Testing: v<i32> == 1]]
[[assert Testing: v<void> == 2]]
[[assert Testing: v<i64> == 3]]
static_assert(v<i16> == 4);
static_assert(v<i8> == 5);
static_assert(v<* int> == 6);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ template<> class t<cpp2::i64> {
template<typename T> extern cpp2::i32 const v;

#line 13 "pure2-template-specialization.cpp2"
template<> std::optional<cpp2::i32> inline constexpr v<cpp2::i16> = 4;
template<> std::optional<cpp2::i8> inline constexpr v<cpp2::i8> = 5;
template<typename T> std::optional<int> inline constexpr v<T*> = 6;
auto main() -> int;


Expand All @@ -33,12 +36,17 @@ auto main() -> int;
template<typename T> cpp2::i32 const v {1};
template<> cpp2::i32 const v<void> {2};
template<> cpp2::i32 const v<cpp2::i64> {3};

#line 16 "pure2-template-specialization.cpp2"
auto main() -> int{
cpp2::Testing.expects(t<cpp2::i32>().a == 1, "");
cpp2::Testing.expects(t<void>().b == 2, "");
cpp2::Testing.expects(t<cpp2::i64>().c == 3, "");
cpp2::Testing.expects(v<cpp2::i32> == 1, "");
cpp2::Testing.expects(v<void> == 2, "");
cpp2::Testing.expects(v<cpp2::i64> == 3, "");
static_assert(v<cpp2::i16> == 4);
static_assert(v<cpp2::i8> == 5);
static_assert(v<int*> == 6);
}

15 changes: 15 additions & 0 deletions source/cppfront.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5133,6 +5133,8 @@ class cppfront
printer.print_cpp2("template", n.position());
emit(*n.template_parameters, false, true);
printer.print_cpp2(" ", n.position());
} else if (n.is_specialization()) {
printer.print_cpp2("template<> ", n.position());
}

// Emit requires clause if any
Expand Down Expand Up @@ -5178,6 +5180,13 @@ class cppfront
if (n.parent_is_type())
{
assert (n.parent_declaration->name());
if (n.specialization_template_arguments) {
errors.emplace_back(
n.position(),
"(temporary alpha limitation) an object alias in type scope cannot be specialized"
);
return;
}

if (printer.get_phase() == printer.phase1_type_defs_func_decls) {
printer.print_cpp2(
Expand Down Expand Up @@ -5223,10 +5232,16 @@ class cppfront
intro = "inline constexpr";
}

auto specialization_template_arguments = std::string{};
if (n.specialization_template_arguments) {
specialization_template_arguments = print_to_string(*n.specialization_template_arguments, false, true, false, false);
}

printer.print_cpp2(
type + " "
+ intro + " "
+ print_to_string(*n.identifier)
+ specialization_template_arguments
+ " = "
+ print_to_string( *std::get<alias_node::an_object>(a->initializer) )
+ ";\n",
Expand Down
46 changes: 38 additions & 8 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -4869,7 +4869,8 @@ auto pretty_print_visualize(declaration_node const& n, int indent, bool include_
object_type_id += " " + pretty_print_visualize(*a->type_id, indent);
}

ret += template_params;
ret += template_params
+ specialization_args;
if (a->is_type_alias()) {
auto& t = std::get<alias_node::a_type>(a->initializer);
ret += " type"
Expand Down Expand Up @@ -7898,12 +7899,12 @@ class parser
&& peek(1)->type() == lexeme::Less
)
{
auto specialization_template_arguments = unqualified_id();
if (!specialization_template_arguments) {
error("invalid template specialization argument list");
return {};
}
n->specialization_template_arguments = std::move(specialization_template_arguments);
auto specialization_template_arguments = unqualified_id();
if (!specialization_template_arguments) {
error("invalid template specialization argument list");
return {};
}
n->specialization_template_arguments = std::move(specialization_template_arguments);
}

auto guard =
Expand Down Expand Up @@ -8271,7 +8272,7 @@ class parser
//G alias:
//G ':' template-parameter-declaration-list? 'type' requires-clause? '==' type-id ';'
//G ':' 'namespace' '==' id-expression ';'
//G ':' template-parameter-declaration-list? type-id? requires-clause? '==' expression ';'
//G ':' template-parameter-declaration-list? template-specialization-argument-list? type-id? requires-clause? '==' expression ';'
//G
//GT ':' function-type '==' expression ';'
//GT # See commit 63efa6ed21c4d4f4f136a7a73e9f6b2c110c81d7 comment
Expand Down Expand Up @@ -8300,12 +8301,34 @@ class parser
n->template_parameters = std::move(template_parameters);
}

// Next is an optional template specialization argument list
if (
curr() == "specialize"
&& peek(1)
&& peek(1)->type() == lexeme::Less
)
{
auto specialization_template_arguments = unqualified_id();
if (!specialization_template_arguments) {
pos = start_pos; // backtrack
return {};
}
n->specialization_template_arguments = std::move(specialization_template_arguments);
}

auto a = std::make_unique<alias_node>( &curr() );

// Next must be 'type', 'namespace', a type-id, or we're at the 'requires' or '=='
if (curr() == "type")
{
next();
if (n->specialization_template_arguments) {
errors.emplace_back(
curr().position(),
"a type alias cannot be specialized"
);
return {};
}
}
else if (curr() == "namespace")
{
Expand All @@ -8317,6 +8340,13 @@ class parser
);
return {};
}
if (n->specialization_template_arguments) {
errors.emplace_back(
curr().position(),
"a namespace alias cannot be specialized"
);
return {};
}
}
else if (curr().type() != lexeme::EqualComparison && curr() != "requires")
{
Expand Down

0 comments on commit 7dd5d76

Please sign in to comment.