mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
tmp
This commit is contained in:
parent
bd0e0fcdbe
commit
3249979969
@ -46,7 +46,6 @@ m_errorReporter(_analysis.errorReporter())
|
||||
m_typeSystem.declareBuiltinType(type, name, arity);
|
||||
m_voidType = m_typeSystem.builtinType(BuiltinType::Void, {});
|
||||
m_wordType = m_typeSystem.builtinType(BuiltinType::Word, {});
|
||||
m_env = make_unique<TypeEnvironment>(m_typeSystem);
|
||||
|
||||
m_typeAnnotations.resize(_analysis.maxAstId());
|
||||
}
|
||||
@ -63,32 +62,31 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
|
||||
if (functionAnnotation.type)
|
||||
return false;
|
||||
|
||||
Type functionType;
|
||||
{
|
||||
_functionDefinition.parameterList().accept(*this);
|
||||
if (_functionDefinition.returnParameterList())
|
||||
_functionDefinition.returnParameterList()->accept(*this);
|
||||
_functionDefinition.parameterList().accept(*this);
|
||||
if (_functionDefinition.returnParameterList())
|
||||
_functionDefinition.returnParameterList()->accept(*this);
|
||||
|
||||
_functionDefinition.body().accept(*this);
|
||||
_functionDefinition.body().accept(*this);
|
||||
|
||||
auto typeFromParameterList = [&](ParameterList const* _list) {
|
||||
if (!_list)
|
||||
return m_typeSystem.builtinType(BuiltinType::Unit, {});
|
||||
return TypeSystemHelpers{m_typeSystem}.tupleType(_list->parameters() | ranges::view::transform([&](auto _param) {
|
||||
auto& argAnnotation = annotation(*_param);
|
||||
solAssert(argAnnotation.type);
|
||||
return *argAnnotation.type;
|
||||
}) | ranges::to<std::vector<Type>>);
|
||||
};
|
||||
auto typeFromParameterList = [&](ParameterList const* _list) {
|
||||
if (!_list)
|
||||
return m_typeSystem.builtinType(BuiltinType::Unit, {});
|
||||
return TypeSystemHelpers{m_typeSystem}.tupleType(_list->parameters() | ranges::view::transform([&](auto _param) {
|
||||
auto& argAnnotation = annotation(*_param);
|
||||
solAssert(argAnnotation.type);
|
||||
return *argAnnotation.type;
|
||||
}) | ranges::to<std::vector<Type>>);
|
||||
};
|
||||
|
||||
Type argType = typeFromParameterList(&_functionDefinition.parameterList());
|
||||
Type resultType = typeFromParameterList(_functionDefinition.returnParameterList().get());
|
||||
Type argType = typeFromParameterList(&_functionDefinition.parameterList());
|
||||
Type resultType = typeFromParameterList(_functionDefinition.returnParameterList().get());
|
||||
|
||||
functionType = m_typeSystem.builtinType(BuiltinType::Function, {argType, resultType});
|
||||
}
|
||||
functionAnnotation.type = functionType;
|
||||
functionAnnotation.type = m_typeSystem.fresh(
|
||||
TypeSystemHelpers{m_typeSystem}.functionType(argType, resultType),
|
||||
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;
|
||||
}
|
||||
@ -135,11 +133,15 @@ experimental::Type TypeInference::fromTypeName(TypeName const& _typeName)
|
||||
}
|
||||
else
|
||||
m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported.");
|
||||
// TODO: free type?
|
||||
return m_typeSystem.freshTypeVariable();
|
||||
return m_typeSystem.freshTypeVariable(false);
|
||||
|
||||
}
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
solAssert(declarationAnnotation.type);
|
||||
m_typeSystem.unify(*declarationAnnotation.type, m_wordType);
|
||||
unify(*declarationAnnotation.type, m_wordType);
|
||||
identifierInfo.valueSize = 1;
|
||||
return true;
|
||||
};
|
||||
@ -192,7 +194,7 @@ bool TypeInference::visit(VariableDeclaration const& _variableDeclaration)
|
||||
if (_variableDeclaration.hasTypeName())
|
||||
return fromTypeName(_variableDeclaration.typeName());
|
||||
else
|
||||
return m_typeSystem.freshTypeVariable();
|
||||
return m_typeSystem.freshTypeVariable(false);
|
||||
}();
|
||||
return false;
|
||||
}
|
||||
@ -211,7 +213,7 @@ void TypeInference::endVisit(Assignment const& _assignment)
|
||||
solAssert(lhsAnnotation.type);
|
||||
auto& rhsAnnotation = annotation(_assignment.rightHandSide());
|
||||
solAssert(rhsAnnotation.type);
|
||||
m_typeSystem.unify(*lhsAnnotation.type, *rhsAnnotation.type);
|
||||
unify(*lhsAnnotation.type, *rhsAnnotation.type);
|
||||
assignmentAnnotation.type = m_typeSystem.resolve(*lhsAnnotation.type);
|
||||
}
|
||||
|
||||
@ -250,7 +252,7 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
|
||||
auto& expressionAnnotation = annotation(_functionCall.expression());
|
||||
solAssert(expressionAnnotation.type);
|
||||
|
||||
Type functionType = m_typeSystem.fresh(*expressionAnnotation.type);
|
||||
Type functionType = m_typeSystem.fresh(*expressionAnnotation.type, false);
|
||||
|
||||
std::vector<Type> argTypes;
|
||||
for(auto arg: _functionCall.arguments())
|
||||
@ -260,8 +262,8 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
|
||||
argTypes.emplace_back(*argAnnotation.type);
|
||||
}
|
||||
Type argTuple = TypeSystemHelpers{m_typeSystem}.tupleType(argTypes);
|
||||
Type genericFunctionType = TypeSystemHelpers{m_typeSystem}.functionType(argTuple, m_typeSystem.freshTypeVariable());
|
||||
m_typeSystem.unify(genericFunctionType, functionType);
|
||||
Type genericFunctionType = TypeSystemHelpers{m_typeSystem}.functionType(argTuple, m_typeSystem.freshTypeVariable(false));
|
||||
unify(genericFunctionType, functionType);
|
||||
|
||||
functionCallAnnotation.type = m_typeSystem.resolve(std::get<1>(TypeSystemHelpers{m_typeSystem}.destFunctionType(m_typeSystem.resolve(genericFunctionType))));
|
||||
}
|
||||
|
@ -61,7 +61,6 @@ private:
|
||||
Analysis& m_analysis;
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
TypeSystem m_typeSystem;
|
||||
std::unique_ptr<TypeEnvironment> m_env;
|
||||
Type m_voidType;
|
||||
Type m_wordType;
|
||||
|
||||
@ -72,6 +71,8 @@ private:
|
||||
|
||||
TypeAnnotation& annotation(ASTNode const& _node);
|
||||
|
||||
void unify(Type _a, Type _b);
|
||||
|
||||
std::vector<std::unique_ptr<TypeAnnotation>> m_typeAnnotations;
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,7 @@ using namespace solidity::frontend::experimental;
|
||||
std::string TypeSystem::typeToString(Type const& _type) const
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
[&](AtomicType const& _type) {
|
||||
[&](TypeExpression const& _type) {
|
||||
std::stringstream stream;
|
||||
if (!_type.arguments.empty())
|
||||
{
|
||||
@ -58,89 +58,56 @@ std::string TypeSystem::typeToString(Type const& _type) const
|
||||
}, _type.constructor);
|
||||
return stream.str();
|
||||
},
|
||||
[](FreeTypeVariable const& _type) {
|
||||
return fmt::format("free[{}]", _type.index());
|
||||
},
|
||||
[](GenericTypeVariable const& _type) {
|
||||
[](TypeVariable const& _type) {
|
||||
return fmt::format("var[{}]", _type.index());
|
||||
},
|
||||
}, resolve(_type));
|
||||
}
|
||||
|
||||
void TypeEnvironment::assignType(Declaration const* _declaration, Type _typeAssignment)
|
||||
{
|
||||
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<TypeSystem::UnificationFailure> TypeSystem::unify(Type _a, Type _b)
|
||||
{
|
||||
vector<UnificationFailure> failures;
|
||||
auto unificationFailure = [&]() {
|
||||
solAssert(false, fmt::format("cannot unify {} and {}", typeToString(_a), typeToString(_b)));
|
||||
failures.emplace_back(UnificationFailure{_a, _b});
|
||||
};
|
||||
_a = resolve(_a);
|
||||
_b = resolve(_b);
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](GenericTypeVariable _left, GenericTypeVariable _right) {
|
||||
[&](TypeVariable _left, TypeVariable _right) {
|
||||
validate(_left);
|
||||
validate(_right);
|
||||
if (_left.index() != _right.index())
|
||||
instantiate(_left, _right);
|
||||
},
|
||||
[&](GenericTypeVariable _var, auto) {
|
||||
[&](TypeVariable _var, auto) {
|
||||
instantiate(_var, _b);
|
||||
},
|
||||
[&](auto, GenericTypeVariable _var) {
|
||||
[&](auto, TypeVariable _var) {
|
||||
instantiate(_var, _a);
|
||||
},
|
||||
[&](AtomicType _atomicLeft, AtomicType _atomicRight) {
|
||||
if(_atomicLeft.constructor != _atomicRight.constructor)
|
||||
unificationFailure();
|
||||
if (_atomicLeft.arguments.size() != _atomicRight.arguments.size())
|
||||
unificationFailure();
|
||||
for (auto&& [left, right]: ranges::zip_view(_atomicLeft.arguments, _atomicRight.arguments))
|
||||
unify(left, right);
|
||||
[&](TypeExpression _left, TypeExpression _right) {
|
||||
if(_left.constructor != _right.constructor)
|
||||
return unificationFailure();
|
||||
if (_left.arguments.size() != _right.arguments.size())
|
||||
return unificationFailure();
|
||||
for (auto&& [left, right]: ranges::zip_view(_left.arguments, _right.arguments))
|
||||
failures += unify(left, right);
|
||||
},
|
||||
[&](auto, auto) {
|
||||
unificationFailure();
|
||||
}
|
||||
}, _a, _b);
|
||||
return failures;
|
||||
}
|
||||
|
||||
unique_ptr<TypeEnvironment> TypeEnvironment::fresh() const
|
||||
{
|
||||
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()
|
||||
experimental::Type TypeSystem::freshTypeVariable(bool _generic)
|
||||
{
|
||||
uint64_t index = m_typeVariables.size();
|
||||
m_typeVariables.emplace_back(std::nullopt);
|
||||
return GenericTypeVariable(*this, index);
|
||||
return TypeVariable(*this, index, _generic);
|
||||
}
|
||||
|
||||
experimental::Type TypeSystem::freshFreeType()
|
||||
{
|
||||
uint64_t index = m_freeTypes.size();
|
||||
m_freeTypes.emplace_back(std::nullopt);
|
||||
return FreeTypeVariable(*this, index);
|
||||
}
|
||||
|
||||
void TypeSystem::instantiate(GenericTypeVariable _variable, Type _type)
|
||||
void TypeSystem::instantiate(TypeVariable _variable, Type _type)
|
||||
{
|
||||
validate(_variable);
|
||||
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
|
||||
{
|
||||
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()))
|
||||
result = *value;
|
||||
else
|
||||
@ -172,15 +139,35 @@ experimental::Type TypeSystem::builtinType(BuiltinType _builtinType, std::vector
|
||||
{
|
||||
auto const& info = m_builtinTypes.at(_builtinType);
|
||||
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.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
|
||||
{
|
||||
if (_elements.empty())
|
||||
@ -198,31 +185,11 @@ experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType,
|
||||
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{
|
||||
[&](AtomicType const& _type) -> Type {
|
||||
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 {
|
||||
[&](TypeExpression const& _type) -> ResultType {
|
||||
return std::make_tuple(_type.constructor, _type.arguments);
|
||||
},
|
||||
[](auto) -> ResultType {
|
||||
@ -234,7 +201,7 @@ tuple<AtomicType::Constructor, vector<experimental::Type>> TypeSystemHelpers::de
|
||||
|
||||
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);
|
||||
solAssert(builtinType && *builtinType == BuiltinType::Function);
|
||||
solAssert(arguments.size() == 2);
|
||||
|
@ -35,11 +35,10 @@ namespace solidity::frontend::experimental
|
||||
class TypeSystem;
|
||||
class TypeEnvironment;
|
||||
|
||||
struct AtomicType;
|
||||
struct GenericTypeVariable;
|
||||
struct FreeTypeVariable;
|
||||
struct TypeExpression;
|
||||
struct TypeVariable;
|
||||
|
||||
using Type = std::variant<AtomicType, GenericTypeVariable, FreeTypeVariable>;
|
||||
using Type = std::variant<TypeExpression, TypeVariable>;
|
||||
|
||||
enum class BuiltinType
|
||||
{
|
||||
@ -50,7 +49,7 @@ enum class BuiltinType
|
||||
Word
|
||||
};
|
||||
|
||||
struct AtomicType
|
||||
struct TypeExpression
|
||||
{
|
||||
using Constructor = std::variant<BuiltinType, Declaration const*>;
|
||||
Constructor constructor;
|
||||
@ -58,43 +57,19 @@ struct AtomicType
|
||||
|
||||
};
|
||||
|
||||
struct FreeTypeVariable
|
||||
struct TypeVariable
|
||||
{
|
||||
TypeSystem const& parent() const { return *m_parent; }
|
||||
uint64_t index() const { return m_index; }
|
||||
bool generic() const { return m_generic; }
|
||||
private:
|
||||
friend class TypeSystem;
|
||||
TypeSystem const* m_parent = nullptr;
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -108,14 +83,15 @@ public:
|
||||
return m_builtinTypes.at(_builtinType).name;
|
||||
}
|
||||
Type freshFreeType();
|
||||
void instantiate(GenericTypeVariable _variable, Type _type);
|
||||
void validate(GenericTypeVariable _variable) const;
|
||||
Type resolve(Type _type) const;
|
||||
std::string typeToString(Type const& _type) const;
|
||||
Type freshTypeVariable();
|
||||
Type fresh(Type _type);
|
||||
void unify(Type _a, Type _b);
|
||||
Type freshTypeVariable(bool _generic);
|
||||
Type fresh(Type _type, bool _generalize);
|
||||
struct UnificationFailure { Type a; Type b; };
|
||||
[[nodiscard]] std::vector<UnificationFailure> unify(Type _a, Type _b);
|
||||
private:
|
||||
void instantiate(TypeVariable _variable, Type _type);
|
||||
void validate(TypeVariable _variable) const;
|
||||
std::vector<std::optional<Type>> m_freeTypes;
|
||||
struct TypeConstructorInfo
|
||||
{
|
||||
@ -131,7 +107,7 @@ struct TypeSystemHelpers
|
||||
TypeSystem& typeSystem;
|
||||
Type tupleType(std::vector<Type> _elements) 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;
|
||||
};
|
||||
|
||||
|
@ -85,8 +85,11 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
||||
{
|
||||
FunctionDefinition const* function = m_context.functionQueue.front();
|
||||
m_context.functionQueue.pop_front();
|
||||
m_context.generatedFunctions.insert(function);
|
||||
code << generate(*function);
|
||||
if (!m_context.generatedFunctions.count(function))
|
||||
{
|
||||
m_context.generatedFunctions.insert(function);
|
||||
code << generate(*function);
|
||||
}
|
||||
}
|
||||
|
||||
return code.str();
|
||||
|
Loading…
Reference in New Issue
Block a user