Skip to content

Commit b4d2757

Browse files
authored
evaulator: Fix crash on identity using declarations (#209)
This commit resolves a crash that occurred when processing using declarations that aliased a type to its template parameter, such as using T<K> = K. This was caused by a type not being resolved in getTypeDefinition. The fix ensures that type template arguments are passed down in getTypeDefinition, and extracts the actual type definition.
1 parent 3305788 commit b4d2757

5 files changed

Lines changed: 88 additions & 2 deletions

File tree

lib/source/pl/core/ast/ast_node_type_application.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,20 @@ namespace pl::core::ast {
127127

128128
ast::ASTNode* type = this->getType().get();
129129
if (auto typDecl = dynamic_cast<ast::ASTNodeTypeDecl*>(type); typDecl != nullptr) {
130+
std::vector<std::unique_ptr<ASTNode>> templateArgs(this->m_templateArguments.size());
131+
for (size_t i = 0; i < this->m_templateArguments.size(); i++) {
132+
auto &templateArgument = this->m_templateArguments[i];
133+
if (auto typeApp = dynamic_cast<ast::ASTNodeTypeApplication*>(templateArgument.get()); typeApp != nullptr) {
134+
templateArgs[i] = templateArgument->evaluate(evaluator);
135+
}
136+
}
137+
138+
evaluator->setCurrentTemplateArguments(std::move(templateArgs));
130139
return typDecl->getTypeDefinition(evaluator);
131140
} else if(auto builtinType = dynamic_cast<ast::ASTNodeBuiltinType*>(type); builtinType != nullptr) {
132141
return builtinType;
142+
} else if(auto typeApp = dynamic_cast<ast::ASTNodeTypeApplication*>(type); typeApp != nullptr) {
143+
return typeApp->getTypeDefinition(evaluator);
133144
}
134145

135146
return nullptr;

lib/source/pl/core/ast/ast_node_type_decl.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,31 @@ namespace pl::core::ast {
146146
const ASTNode* ASTNodeTypeDecl::getTypeDefinition(Evaluator *evaluator) const {
147147
if (m_type == nullptr)
148148
err::E0004.throwError(fmt::format("Cannot use incomplete type '{}' before it has been defined.", this->m_name), "Try defining this type further up in your code before trying to instantiate it.", this->getLocation());
149-
else if (auto typeApp = dynamic_cast<ASTNodeTypeApplication*>(m_type.get()); typeApp != nullptr)
149+
else if (auto typeApp = dynamic_cast<ASTNodeTypeApplication*>(m_type.get()); typeApp != nullptr) {
150+
evaluator->pushTypeTemplateParameters();
151+
ON_SCOPE_EXIT {
152+
evaluator->popTypeTemplateParameters();
153+
};
154+
155+
auto& templateArguments = evaluator->getCurrentTemplateArguments();
156+
std::vector<std::shared_ptr<ptrn::Pattern>> templatePatterns;
157+
for (size_t i = 0; i < this->m_templateParameters.size(); i++) {
158+
auto &templateParameter = this->m_templateParameters[i];
159+
160+
if (i >= templateArguments.size()) {
161+
break;
162+
}
163+
164+
if (templateParameter->isType()) {
165+
auto& argument = templateArguments[i];
166+
evaluator->getTypeTemplateParameters().emplace_back(std::move(argument));
167+
}
168+
}
169+
150170
return typeApp->getTypeDefinition(evaluator);
151-
else
171+
} else {
152172
return m_type.get();
173+
}
153174
}
154175

155176
[[nodiscard]] const std::string ASTNodeTypeDecl::getTypeName() const {

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(AVAILABLE_TESTS
3535
TemplateParametersScope
3636
TypeNameOf
3737
CustomBuiltInType
38+
Using
3839
)
3940

4041

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
3+
#include "test_pattern.hpp"
4+
5+
namespace pl::test {
6+
7+
class TestPatternUsing : public TestPattern {
8+
public:
9+
TestPatternUsing(core::Evaluator *evaluator) : TestPattern(evaluator, "Using") {
10+
}
11+
~TestPatternUsing() override = default;
12+
13+
[[nodiscard]] std::string getSourceCode() const override {
14+
return R"(
15+
using US<T> = T;
16+
US<u32> u;
17+
US<u32> v = 64;
18+
u = 64;
19+
std::assert(u == 64 && v == 64, "u,v should be 64");
20+
21+
using UST<T> = US<T>;
22+
UST<u32> ust;
23+
UST<u32> vst = 16;
24+
ust = 16;
25+
std::assert(ust == 16 && vst == 16, "ust,vst should be 16");
26+
27+
struct USS<T> {
28+
US<T> us = 16;
29+
};
30+
USS<u32> uss;
31+
std::assert(uss.us == 16, "us should be 16");
32+
33+
USS<US<u32>> ussus;
34+
std::assert(ussus.us == 16, "ussus should be 16");
35+
36+
US<u8> us2[2];
37+
US<u8> us3[2] @ 0;
38+
std::assert(us3[0] == 137, "us3[0] should be 137");
39+
40+
namespace A {
41+
using US<T> = T;
42+
}
43+
A::US<u8> us4;
44+
A::US<u8> us5 @ 0;
45+
us4 = us5;
46+
std::assert(us5 == 137 && us4 == 137, "us4, us5 should be 137");
47+
)";
48+
}
49+
};
50+
51+
}

tests/source/tests.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "test_patterns/test_pattern_template_parameters_scope.hpp"
3131
#include "test_patterns/test_pattern_typenameof.hpp"
3232
#include "test_patterns/test_pattern_custom_builtin_type.hpp"
33+
#include "test_patterns/test_pattern_using.hpp"
3334

3435
static pl::core::Evaluator s_evaluator;
3536

@@ -65,4 +66,5 @@ std::array Tests = {
6566
TEST(TemplateParametersScope),
6667
TEST(TypeNameOf),
6768
TEST(CustomBuiltinType),
69+
TEST(Using),
6870
};

0 commit comments

Comments
 (0)