start type narrowing for binary exprs
This commit is contained in:
@@ -122,7 +122,7 @@ namespace Solstice {
|
|||||||
throw std::runtime_error("unknown variable " + *identifier);
|
throw std::runtime_error("unknown variable " + *identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
node.ptype = {{variables[*identifier]}};
|
node.ptype = variables[*identifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeChecker::checkTupleNodeType(Node& node) {
|
void TypeChecker::checkTupleNodeType(Node& node) {
|
||||||
@@ -200,6 +200,135 @@ namespace Solstice {
|
|||||||
variables[*id].isConstant = true;
|
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) {
|
void TypeChecker::checkSetNodeType(Node& node) {
|
||||||
auto id = node.children[0].getIdentifier();
|
auto id = node.children[0].getIdentifier();
|
||||||
if (!id.has_value()) {
|
if (!id.has_value()) {
|
||||||
@@ -232,6 +361,8 @@ namespace Solstice {
|
|||||||
checkNodeType(node.children[0]);
|
checkNodeType(node.children[0]);
|
||||||
checkNodeType(node.children[1]);
|
checkNodeType(node.children[1]);
|
||||||
|
|
||||||
|
// narrow if required
|
||||||
|
narrowBinaryNode(node, addOverloads);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,6 +411,7 @@ namespace Solstice {
|
|||||||
case NodeType::Add:
|
case NodeType::Add:
|
||||||
checkAddType(node);
|
checkAddType(node);
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
case NodeType::Subtract:
|
case NodeType::Subtract:
|
||||||
checkSubtractType(node);
|
checkSubtractType(node);
|
||||||
break;
|
break;
|
||||||
@@ -301,6 +433,7 @@ namespace Solstice {
|
|||||||
case NodeType::LesserThan:
|
case NodeType::LesserThan:
|
||||||
checkLesserThanType(node);
|
checkLesserThanType(node);
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
|
|
||||||
namespace Solstice {
|
namespace Solstice {
|
||||||
|
|
||||||
|
enum class Narrowing {
|
||||||
|
None,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Both
|
||||||
|
};
|
||||||
|
|
||||||
class TypeChecker {
|
class TypeChecker {
|
||||||
std::unordered_map<std::string, PossibleType> variables;
|
std::unordered_map<std::string, PossibleType> variables;
|
||||||
std::unordered_map<std::string, Type> types;
|
std::unordered_map<std::string, Type> types;
|
||||||
@@ -37,6 +44,9 @@ namespace Solstice {
|
|||||||
|
|
||||||
void checkCodeBlockType(Node& node);
|
void checkCodeBlockType(Node& node);
|
||||||
|
|
||||||
|
Narrowing doesNodeChildrenNeedNarrowing(Node& node);
|
||||||
|
void narrowBinaryNode(Node& node, std::unordered_map<TypePair, Type>& overloads);
|
||||||
|
|
||||||
void checkAddType(Node& node);
|
void checkAddType(Node& node);
|
||||||
void checkSubtractType(Node& node);
|
void checkSubtractType(Node& node);
|
||||||
void checkMultiplyType(Node& node);
|
void checkMultiplyType(Node& node);
|
||||||
|
|||||||
Reference in New Issue
Block a user