This commit is contained in:
Daniel Kirchner 2023-06-20 04:45:30 +02:00
parent bd0e0fcdbe
commit 3249979969
5 changed files with 100 additions and 151 deletions

View File

@ -46,7 +46,6 @@ m_errorReporter(_analysis.errorReporter())
m_typeSystem.declareBuiltinType(type, name, arity); m_typeSystem.declareBuiltinType(type, name, arity);
m_voidType = m_typeSystem.builtinType(BuiltinType::Void, {}); m_voidType = m_typeSystem.builtinType(BuiltinType::Void, {});
m_wordType = m_typeSystem.builtinType(BuiltinType::Word, {}); m_wordType = m_typeSystem.builtinType(BuiltinType::Word, {});
m_env = make_unique<TypeEnvironment>(m_typeSystem);
m_typeAnnotations.resize(_analysis.maxAstId()); m_typeAnnotations.resize(_analysis.maxAstId());
} }
@ -63,8 +62,6 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
if (functionAnnotation.type) if (functionAnnotation.type)
return false; return false;
Type functionType;
{
_functionDefinition.parameterList().accept(*this); _functionDefinition.parameterList().accept(*this);
if (_functionDefinition.returnParameterList()) if (_functionDefinition.returnParameterList())
_functionDefinition.returnParameterList()->accept(*this); _functionDefinition.returnParameterList()->accept(*this);
@ -84,11 +81,12 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
Type argType = typeFromParameterList(&_functionDefinition.parameterList()); Type argType = typeFromParameterList(&_functionDefinition.parameterList());
Type resultType = typeFromParameterList(_functionDefinition.returnParameterList().get()); Type resultType = typeFromParameterList(_functionDefinition.returnParameterList().get());
functionType = m_typeSystem.builtinType(BuiltinType::Function, {argType, resultType}); functionAnnotation.type = m_typeSystem.fresh(
} TypeSystemHelpers{m_typeSystem}.functionType(argType, resultType),
functionAnnotation.type = functionType; true
);
m_errorReporter.warning(0000_error, _functionDefinition.location(), m_typeSystem.typeToString(m_typeSystem.resolve(functionType))); m_errorReporter.warning(0000_error, _functionDefinition.location(), m_typeSystem.typeToString(*functionAnnotation.type));
return false; return false;
} }
@ -135,11 +133,15 @@ experimental::Type TypeInference::fromTypeName(TypeName const& _typeName)
} }
else else
m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported."); m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported.");
// TODO: free type? return m_typeSystem.freshTypeVariable(false);
return m_typeSystem.freshTypeVariable();
} }
void TypeInference::unify(Type _a, Type _b)
{
for (auto failure: m_typeSystem.unify(_a, _b))
m_errorReporter.typeError(0000_error, {}, fmt::format("Cannot unify {} and {}.", m_typeSystem.typeToString(_a), m_typeSystem.typeToString(_b)));
}
bool TypeInference::visit(InlineAssembly const& _inlineAssembly) bool TypeInference::visit(InlineAssembly const& _inlineAssembly)
{ {
// External references have already been resolved in a prior stage and stored in the annotation. // External references have already been resolved in a prior stage and stored in the annotation.
@ -166,7 +168,7 @@ bool TypeInference::visit(InlineAssembly const& _inlineAssembly)
auto& declarationAnnotation = annotation(*declaration); auto& declarationAnnotation = annotation(*declaration);
solAssert(declarationAnnotation.type); solAssert(declarationAnnotation.type);
m_typeSystem.unify(*declarationAnnotation.type, m_wordType); unify(*declarationAnnotation.type, m_wordType);
identifierInfo.valueSize = 1; identifierInfo.valueSize = 1;
return true; return true;
}; };
@ -192,7 +194,7 @@ bool TypeInference::visit(VariableDeclaration const& _variableDeclaration)
if (_variableDeclaration.hasTypeName()) if (_variableDeclaration.hasTypeName())
return fromTypeName(_variableDeclaration.typeName()); return fromTypeName(_variableDeclaration.typeName());
else else
return m_typeSystem.freshTypeVariable(); return m_typeSystem.freshTypeVariable(false);
}(); }();
return false; return false;
} }
@ -211,7 +213,7 @@ void TypeInference::endVisit(Assignment const& _assignment)
solAssert(lhsAnnotation.type); solAssert(lhsAnnotation.type);
auto& rhsAnnotation = annotation(_assignment.rightHandSide()); auto& rhsAnnotation = annotation(_assignment.rightHandSide());
solAssert(rhsAnnotation.type); solAssert(rhsAnnotation.type);
m_typeSystem.unify(*lhsAnnotation.type, *rhsAnnotation.type); unify(*lhsAnnotation.type, *rhsAnnotation.type);
assignmentAnnotation.type = m_typeSystem.resolve(*lhsAnnotation.type); assignmentAnnotation.type = m_typeSystem.resolve(*lhsAnnotation.type);
} }
@ -250,7 +252,7 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
auto& expressionAnnotation = annotation(_functionCall.expression()); auto& expressionAnnotation = annotation(_functionCall.expression());
solAssert(expressionAnnotation.type); solAssert(expressionAnnotation.type);
Type functionType = m_typeSystem.fresh(*expressionAnnotation.type); Type functionType = m_typeSystem.fresh(*expressionAnnotation.type, false);
std::vector<Type> argTypes; std::vector<Type> argTypes;
for(auto arg: _functionCall.arguments()) for(auto arg: _functionCall.arguments())
@ -260,8 +262,8 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
argTypes.emplace_back(*argAnnotation.type); argTypes.emplace_back(*argAnnotation.type);
} }
Type argTuple = TypeSystemHelpers{m_typeSystem}.tupleType(argTypes); Type argTuple = TypeSystemHelpers{m_typeSystem}.tupleType(argTypes);
Type genericFunctionType = TypeSystemHelpers{m_typeSystem}.functionType(argTuple, m_typeSystem.freshTypeVariable()); Type genericFunctionType = TypeSystemHelpers{m_typeSystem}.functionType(argTuple, m_typeSystem.freshTypeVariable(false));
m_typeSystem.unify(genericFunctionType, functionType); unify(genericFunctionType, functionType);
functionCallAnnotation.type = m_typeSystem.resolve(std::get<1>(TypeSystemHelpers{m_typeSystem}.destFunctionType(m_typeSystem.resolve(genericFunctionType)))); functionCallAnnotation.type = m_typeSystem.resolve(std::get<1>(TypeSystemHelpers{m_typeSystem}.destFunctionType(m_typeSystem.resolve(genericFunctionType))));
} }

View File

@ -61,7 +61,6 @@ private:
Analysis& m_analysis; Analysis& m_analysis;
langutil::ErrorReporter& m_errorReporter; langutil::ErrorReporter& m_errorReporter;
TypeSystem m_typeSystem; TypeSystem m_typeSystem;
std::unique_ptr<TypeEnvironment> m_env;
Type m_voidType; Type m_voidType;
Type m_wordType; Type m_wordType;
@ -72,6 +71,8 @@ private:
TypeAnnotation& annotation(ASTNode const& _node); TypeAnnotation& annotation(ASTNode const& _node);
void unify(Type _a, Type _b);
std::vector<std::unique_ptr<TypeAnnotation>> m_typeAnnotations; std::vector<std::unique_ptr<TypeAnnotation>> m_typeAnnotations;
}; };

View File

@ -38,7 +38,7 @@ using namespace solidity::frontend::experimental;
std::string TypeSystem::typeToString(Type const& _type) const std::string TypeSystem::typeToString(Type const& _type) const
{ {
return std::visit(util::GenericVisitor{ return std::visit(util::GenericVisitor{
[&](AtomicType const& _type) { [&](TypeExpression const& _type) {
std::stringstream stream; std::stringstream stream;
if (!_type.arguments.empty()) if (!_type.arguments.empty())
{ {
@ -58,89 +58,56 @@ std::string TypeSystem::typeToString(Type const& _type) const
}, _type.constructor); }, _type.constructor);
return stream.str(); return stream.str();
}, },
[](FreeTypeVariable const& _type) { [](TypeVariable const& _type) {
return fmt::format("free[{}]", _type.index());
},
[](GenericTypeVariable const& _type) {
return fmt::format("var[{}]", _type.index()); return fmt::format("var[{}]", _type.index());
}, },
}, resolve(_type)); }, resolve(_type));
} }
void TypeEnvironment::assignType(Declaration const* _declaration, Type _typeAssignment) vector<TypeSystem::UnificationFailure> TypeSystem::unify(Type _a, Type _b)
{
auto&& [type, newlyInserted] = m_types.emplace(std::piecewise_construct, std::forward_as_tuple(_declaration), std::forward_as_tuple(std::move(_typeAssignment)));
if (!newlyInserted)
{
m_parent.unify(type->second, _typeAssignment);
}
}
std::optional<experimental::Type> TypeEnvironment::lookup(Declaration const* _declaration)
{
if (m_types.count(_declaration))
return m_types[_declaration];
return std::nullopt;
}
void TypeSystem::unify(Type _a, Type _b)
{ {
vector<UnificationFailure> failures;
auto unificationFailure = [&]() { auto unificationFailure = [&]() {
solAssert(false, fmt::format("cannot unify {} and {}", typeToString(_a), typeToString(_b))); failures.emplace_back(UnificationFailure{_a, _b});
}; };
_a = resolve(_a); _a = resolve(_a);
_b = resolve(_b); _b = resolve(_b);
std::visit(util::GenericVisitor{ std::visit(util::GenericVisitor{
[&](GenericTypeVariable _left, GenericTypeVariable _right) { [&](TypeVariable _left, TypeVariable _right) {
validate(_left); validate(_left);
validate(_right); validate(_right);
if (_left.index() != _right.index()) if (_left.index() != _right.index())
instantiate(_left, _right); instantiate(_left, _right);
}, },
[&](GenericTypeVariable _var, auto) { [&](TypeVariable _var, auto) {
instantiate(_var, _b); instantiate(_var, _b);
}, },
[&](auto, GenericTypeVariable _var) { [&](auto, TypeVariable _var) {
instantiate(_var, _a); instantiate(_var, _a);
}, },
[&](AtomicType _atomicLeft, AtomicType _atomicRight) { [&](TypeExpression _left, TypeExpression _right) {
if(_atomicLeft.constructor != _atomicRight.constructor) if(_left.constructor != _right.constructor)
unificationFailure(); return unificationFailure();
if (_atomicLeft.arguments.size() != _atomicRight.arguments.size()) if (_left.arguments.size() != _right.arguments.size())
unificationFailure(); return unificationFailure();
for (auto&& [left, right]: ranges::zip_view(_atomicLeft.arguments, _atomicRight.arguments)) for (auto&& [left, right]: ranges::zip_view(_left.arguments, _right.arguments))
unify(left, right); failures += unify(left, right);
}, },
[&](auto, auto) { [&](auto, auto) {
unificationFailure(); unificationFailure();
} }
}, _a, _b); }, _a, _b);
return failures;
} }
unique_ptr<TypeEnvironment> TypeEnvironment::fresh() const experimental::Type TypeSystem::freshTypeVariable(bool _generic)
{
auto newEnv = make_unique<TypeEnvironment>(m_parent);
for(auto [decl,type]: m_types)
newEnv->m_types.emplace(decl, type);
return newEnv;
}
experimental::Type TypeSystem::freshTypeVariable()
{ {
uint64_t index = m_typeVariables.size(); uint64_t index = m_typeVariables.size();
m_typeVariables.emplace_back(std::nullopt); m_typeVariables.emplace_back(std::nullopt);
return GenericTypeVariable(*this, index); return TypeVariable(*this, index, _generic);
} }
experimental::Type TypeSystem::freshFreeType() void TypeSystem::instantiate(TypeVariable _variable, Type _type)
{
uint64_t index = m_freeTypes.size();
m_freeTypes.emplace_back(std::nullopt);
return FreeTypeVariable(*this, index);
}
void TypeSystem::instantiate(GenericTypeVariable _variable, Type _type)
{ {
validate(_variable); validate(_variable);
solAssert(!m_typeVariables.at(_variable.index()).has_value()); solAssert(!m_typeVariables.at(_variable.index()).has_value());
@ -151,7 +118,7 @@ void TypeSystem::instantiate(GenericTypeVariable _variable, Type _type)
experimental::Type TypeSystem::resolve(Type _type) const experimental::Type TypeSystem::resolve(Type _type) const
{ {
Type result = _type; Type result = _type;
while(auto const* var = std::get_if<GenericTypeVariable>(&result)) while(auto const* var = std::get_if<TypeVariable>(&result))
if (auto value = m_typeVariables.at(var->index())) if (auto value = m_typeVariables.at(var->index()))
result = *value; result = *value;
else else
@ -172,15 +139,35 @@ experimental::Type TypeSystem::builtinType(BuiltinType _builtinType, std::vector
{ {
auto const& info = m_builtinTypes.at(_builtinType); auto const& info = m_builtinTypes.at(_builtinType);
solAssert(info.arity == _arguments.size(), "Invalid arity."); solAssert(info.arity == _arguments.size(), "Invalid arity.");
return AtomicType{_builtinType, _arguments}; return TypeExpression{_builtinType, _arguments};
} }
void TypeSystem::validate(GenericTypeVariable _variable) const void TypeSystem::validate(TypeVariable _variable) const
{ {
solAssert(_variable.m_parent == this); solAssert(_variable.m_parent == this);
solAssert(_variable.index() < m_typeVariables.size()); solAssert(_variable.index() < m_typeVariables.size());
} }
experimental::Type TypeSystem::fresh(Type _type, bool _generalize)
{
return std::visit(util::GenericVisitor{
[&](TypeExpression const& _type) -> Type {
return TypeExpression{
_type.constructor,
_type.arguments | ranges::view::transform([&](Type _argType) {
return fresh(_argType, _generalize);
}) | ranges::to<vector<Type>>
};
},
[&](TypeVariable const& _var) {
if (_generalize || _var.generic())
return freshTypeVariable(true);
else
return _type;
},
}, resolve(_type));
}
experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
{ {
if (_elements.empty()) if (_elements.empty())
@ -198,31 +185,11 @@ experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType,
return typeSystem.builtinType(BuiltinType::Function, {_argType, _resultType}); return typeSystem.builtinType(BuiltinType::Function, {_argType, _resultType});
} }
experimental::Type TypeSystem::fresh(Type _type) tuple<TypeExpression::Constructor, vector<experimental::Type>> TypeSystemHelpers::destTypeExpression(Type _functionType) const
{ {
using ResultType = tuple<TypeExpression::Constructor, vector<Type>>;
return std::visit(util::GenericVisitor{ return std::visit(util::GenericVisitor{
[&](AtomicType const& _type) -> Type { [&](TypeExpression const& _type) -> ResultType {
return AtomicType{
_type.constructor,
_type.arguments | ranges::view::transform([&](Type _argType) {
return fresh(_argType);
}) | ranges::to<vector<Type>>
};
},
[&](FreeTypeVariable const&) {
return _type;
},
[&](GenericTypeVariable const&) {
return freshTypeVariable();
},
}, resolve(_type));
}
tuple<AtomicType::Constructor, vector<experimental::Type>> TypeSystemHelpers::destAtomicType(Type _functionType) const
{
using ResultType = tuple<AtomicType::Constructor, vector<Type>>;
return std::visit(util::GenericVisitor{
[&](AtomicType const& _type) -> ResultType {
return std::make_tuple(_type.constructor, _type.arguments); return std::make_tuple(_type.constructor, _type.arguments);
}, },
[](auto) -> ResultType { [](auto) -> ResultType {
@ -234,7 +201,7 @@ tuple<AtomicType::Constructor, vector<experimental::Type>> TypeSystemHelpers::de
tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destFunctionType(Type _functionType) const tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destFunctionType(Type _functionType) const
{ {
auto [constructor, arguments] = destAtomicType(_functionType); auto [constructor, arguments] = destTypeExpression(_functionType);
auto const* builtinType = get_if<BuiltinType>(&constructor); auto const* builtinType = get_if<BuiltinType>(&constructor);
solAssert(builtinType && *builtinType == BuiltinType::Function); solAssert(builtinType && *builtinType == BuiltinType::Function);
solAssert(arguments.size() == 2); solAssert(arguments.size() == 2);

View File

@ -35,11 +35,10 @@ namespace solidity::frontend::experimental
class TypeSystem; class TypeSystem;
class TypeEnvironment; class TypeEnvironment;
struct AtomicType; struct TypeExpression;
struct GenericTypeVariable; struct TypeVariable;
struct FreeTypeVariable;
using Type = std::variant<AtomicType, GenericTypeVariable, FreeTypeVariable>; using Type = std::variant<TypeExpression, TypeVariable>;
enum class BuiltinType enum class BuiltinType
{ {
@ -50,7 +49,7 @@ enum class BuiltinType
Word Word
}; };
struct AtomicType struct TypeExpression
{ {
using Constructor = std::variant<BuiltinType, Declaration const*>; using Constructor = std::variant<BuiltinType, Declaration const*>;
Constructor constructor; Constructor constructor;
@ -58,43 +57,19 @@ struct AtomicType
}; };
struct FreeTypeVariable struct TypeVariable
{ {
TypeSystem const& parent() const { return *m_parent; } TypeSystem const& parent() const { return *m_parent; }
uint64_t index() const { return m_index; } uint64_t index() const { return m_index; }
bool generic() const { return m_generic; }
private: private:
friend class TypeSystem; friend class TypeSystem;
TypeSystem const* m_parent = nullptr; TypeSystem const* m_parent = nullptr;
uint64_t m_index = 0; uint64_t m_index = 0;
FreeTypeVariable(TypeSystem const& _parent, uint64_t _index): m_parent(&_parent), m_index(_index) {} bool m_generic = false;
TypeVariable(TypeSystem const& _parent, uint64_t _index, bool _generic): m_parent(&_parent), m_index(_index), m_generic(_generic) {}
}; };
struct GenericTypeVariable
{
TypeSystem const& parent() const { return *m_parent; }
uint64_t index() const { return m_index; }
private:
friend class TypeSystem;
TypeSystem const* m_parent = nullptr;
uint64_t m_index = 0;
GenericTypeVariable(TypeSystem const& _parent, uint64_t _index): m_parent(&_parent), m_index(_index) {}
};
class TypeEnvironment
{
public:
TypeEnvironment(TypeSystem& _parent): m_parent(_parent) {}
TypeEnvironment(TypeEnvironment const& _env) = delete;
TypeEnvironment& operator=(TypeEnvironment const& _env) = delete;
std::unique_ptr<TypeEnvironment> fresh() const;
void assignType(Declaration const* _declaration, Type _typeAssignment);
std::optional<Type> lookup(Declaration const* _declaration);
private:
TypeSystem& m_parent;
std::map<Declaration const*, Type> m_types;
};
class TypeSystem class TypeSystem
{ {
public: public:
@ -108,14 +83,15 @@ public:
return m_builtinTypes.at(_builtinType).name; return m_builtinTypes.at(_builtinType).name;
} }
Type freshFreeType(); Type freshFreeType();
void instantiate(GenericTypeVariable _variable, Type _type);
void validate(GenericTypeVariable _variable) const;
Type resolve(Type _type) const; Type resolve(Type _type) const;
std::string typeToString(Type const& _type) const; std::string typeToString(Type const& _type) const;
Type freshTypeVariable(); Type freshTypeVariable(bool _generic);
Type fresh(Type _type); Type fresh(Type _type, bool _generalize);
void unify(Type _a, Type _b); struct UnificationFailure { Type a; Type b; };
[[nodiscard]] std::vector<UnificationFailure> unify(Type _a, Type _b);
private: private:
void instantiate(TypeVariable _variable, Type _type);
void validate(TypeVariable _variable) const;
std::vector<std::optional<Type>> m_freeTypes; std::vector<std::optional<Type>> m_freeTypes;
struct TypeConstructorInfo struct TypeConstructorInfo
{ {
@ -131,7 +107,7 @@ struct TypeSystemHelpers
TypeSystem& typeSystem; TypeSystem& typeSystem;
Type tupleType(std::vector<Type> _elements) const; Type tupleType(std::vector<Type> _elements) const;
Type functionType(Type _argType, Type _resultType) const; Type functionType(Type _argType, Type _resultType) const;
std::tuple<AtomicType::Constructor, std::vector<Type>> destAtomicType(Type _functionType) const; std::tuple<TypeExpression::Constructor, std::vector<Type>> destTypeExpression(Type _functionType) const;
std::tuple<Type, Type> destFunctionType(Type _functionType) const; std::tuple<Type, Type> destFunctionType(Type _functionType) const;
}; };

View File

@ -85,9 +85,12 @@ string IRGenerator::generate(ContractDefinition const& _contract)
{ {
FunctionDefinition const* function = m_context.functionQueue.front(); FunctionDefinition const* function = m_context.functionQueue.front();
m_context.functionQueue.pop_front(); m_context.functionQueue.pop_front();
if (!m_context.generatedFunctions.count(function))
{
m_context.generatedFunctions.insert(function); m_context.generatedFunctions.insert(function);
code << generate(*function); code << generate(*function);
} }
}
return code.str(); return code.str();
} }