start type narrowing for binary exprs
This commit is contained in:
@@ -122,7 +122,7 @@ namespace Solstice {
|
||||
throw std::runtime_error("unknown variable " + *identifier);
|
||||
}
|
||||
|
||||
node.ptype = {{variables[*identifier]}};
|
||||
node.ptype = variables[*identifier];
|
||||
}
|
||||
|
||||
void TypeChecker::checkTupleNodeType(Node& node) {
|
||||
@@ -200,6 +200,135 @@ namespace Solstice {
|
||||
variables[*id].isConstant = true;
|
||||
}
|
||||
|
||||
Narrowing TypeChecker::doesNodeChildrenNeedNarrowing(Node& node) {
|
||||
Narrowing ret;
|
||||
if (
|
||||
node.children[0].type == NodeType::Expression &&
|
||||
variables.find(*node.children[0].getIdentifier()) != variables.end() &&
|
||||
variables[*node.children[0].getIdentifier()].unknownType
|
||||
) {
|
||||
ret = Narrowing::Left;
|
||||
}
|
||||
|
||||
if (
|
||||
node.children[1].type == NodeType::Expression &&
|
||||
variables.find(*node.children[1].getIdentifier()) != variables.end() &&
|
||||
variables[*node.children[1].getIdentifier()].unknownType
|
||||
) {
|
||||
if (ret == Narrowing::Left) {
|
||||
ret = Narrowing::Both;
|
||||
} else {
|
||||
ret = Narrowing::Right;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TypeChecker::narrowBinaryNode(Node& node, std::unordered_map<TypePair, Type>& overloads) {
|
||||
auto& left = node.children[0];
|
||||
auto& right = node.children[1];
|
||||
|
||||
// narrow types if we need to
|
||||
switch (doesNodeChildrenNeedNarrowing(node)) {
|
||||
case Narrowing::Both: {
|
||||
auto& leftVar = variables[*left.getIdentifier()];
|
||||
auto& rightVar = variables[*right.getIdentifier()];
|
||||
|
||||
if (leftVar.possiblities.empty() && rightVar.possiblities.empty()) {
|
||||
for (const auto& [key, value] : overloads) {
|
||||
leftVar.possiblities.insert(key.left);
|
||||
rightVar.possiblities.insert(key.right);
|
||||
node.ptype.possiblities.insert(value);
|
||||
}
|
||||
} else if (leftVar.possiblities.empty()) {
|
||||
std::unordered_set<Type> rightMatches;
|
||||
for (const auto& [key, value] : overloads) {
|
||||
if (rightVar.possiblities.find(key.right) != rightVar.possiblities.end()) {
|
||||
rightMatches.insert(key.left);
|
||||
node.ptype.possiblities.insert(value);
|
||||
}
|
||||
}
|
||||
if (rightMatches.empty()) {
|
||||
throw std::runtime_error("no valid overload compatible with previous statements");
|
||||
}
|
||||
leftVar.possiblities = rightMatches;
|
||||
} else if (rightVar.possiblities.empty()) {
|
||||
std::unordered_set<Type> leftMatches;
|
||||
for (const auto& [key, value] : overloads) {
|
||||
if (leftVar.possiblities.find(key.right) != leftVar.possiblities.end()) {
|
||||
leftMatches.insert(key.left);
|
||||
node.ptype.possiblities.insert(value);
|
||||
}
|
||||
}
|
||||
if (leftMatches.empty()) {
|
||||
throw std::runtime_error("no valid overload compatible with previous statements");
|
||||
}
|
||||
rightVar.possiblities = leftMatches;
|
||||
} else {
|
||||
std::unordered_set<Type> left;
|
||||
std::unordered_set<Type> right;
|
||||
for (const auto& [key, value] : overloads) {
|
||||
if (
|
||||
leftVar.possiblities.find(key.right) != leftVar.possiblities.end() &&
|
||||
rightVar.possiblities.find(key.right) != rightVar.possiblities.end()
|
||||
) {
|
||||
left.insert(key.left);
|
||||
right.insert(key.right);
|
||||
node.ptype.possiblities.insert(value);
|
||||
}
|
||||
}
|
||||
if (left.empty() || right.empty()) {
|
||||
throw std::runtime_error("no valid overload compatible with previous statements");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Narrowing::Left: {
|
||||
auto& leftVar = variables[*left.getIdentifier()];
|
||||
std::unordered_set<Type> rightMatches;
|
||||
for (const auto& [key, value] : overloads) {
|
||||
if (right.ptype.possiblities.find(key.right) != right.ptype.possiblities.end()) {
|
||||
rightMatches.insert(key.left);
|
||||
node.ptype.possiblities.insert(value);
|
||||
}
|
||||
}
|
||||
if (rightMatches.empty()) {
|
||||
throw std::runtime_error("no valid overload compatible with previous statements");
|
||||
}
|
||||
leftVar.possiblities = rightMatches;
|
||||
break;
|
||||
}
|
||||
case Narrowing::Right: {
|
||||
auto& rightVar = variables[*right.getIdentifier()];
|
||||
std::unordered_set<Type> rightMatches;
|
||||
for (const auto& [key, value] : overloads) {
|
||||
if (left.ptype.possiblities.find(key.left) != left.ptype.possiblities.end()) {
|
||||
rightMatches.insert(key.left);
|
||||
node.ptype.possiblities.insert(value);
|
||||
}
|
||||
}
|
||||
if (rightMatches.empty()) {
|
||||
throw std::runtime_error("no valid overload compatible with previous statements");
|
||||
}
|
||||
rightVar.possiblities = rightMatches;
|
||||
break;
|
||||
}
|
||||
case Narrowing::None: {
|
||||
for (const auto& [key, value] : overloads) {
|
||||
if (
|
||||
left.ptype.possiblities.find(key.right) != left.ptype.possiblities.end() &&
|
||||
right.ptype.possiblities.find(key.right) != right.ptype.possiblities.end()
|
||||
) {
|
||||
node.ptype.possiblities.insert(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TypeChecker::checkSetNodeType(Node& node) {
|
||||
auto id = node.children[0].getIdentifier();
|
||||
if (!id.has_value()) {
|
||||
@@ -232,7 +361,9 @@ namespace Solstice {
|
||||
checkNodeType(node.children[0]);
|
||||
checkNodeType(node.children[1]);
|
||||
|
||||
|
||||
// narrow if required
|
||||
narrowBinaryNode(node, addOverloads);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -280,6 +411,7 @@ namespace Solstice {
|
||||
case NodeType::Add:
|
||||
checkAddType(node);
|
||||
break;
|
||||
/*
|
||||
case NodeType::Subtract:
|
||||
checkSubtractType(node);
|
||||
break;
|
||||
@@ -301,6 +433,7 @@ namespace Solstice {
|
||||
case NodeType::LesserThan:
|
||||
checkLesserThanType(node);
|
||||
break;
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
|
||||
namespace Solstice {
|
||||
|
||||
enum class Narrowing {
|
||||
None,
|
||||
Left,
|
||||
Right,
|
||||
Both
|
||||
};
|
||||
|
||||
class TypeChecker {
|
||||
std::unordered_map<std::string, PossibleType> variables;
|
||||
std::unordered_map<std::string, Type> types;
|
||||
@@ -37,6 +44,9 @@ namespace Solstice {
|
||||
|
||||
void checkCodeBlockType(Node& node);
|
||||
|
||||
Narrowing doesNodeChildrenNeedNarrowing(Node& node);
|
||||
void narrowBinaryNode(Node& node, std::unordered_map<TypePair, Type>& overloads);
|
||||
|
||||
void checkAddType(Node& node);
|
||||
void checkSubtractType(Node& node);
|
||||
void checkMultiplyType(Node& node);
|
||||
|
||||
Reference in New Issue
Block a user