From c7107881774c9ed37b2db0aec6be9301595a243d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 19 Sep 2023 15:17:35 +0200 Subject: [PATCH 1/6] Distinct identifiers and tokens for integer type and integer class - Using the same name causes syntax ambiguities. It's also not allowed for user-defined classes and types. --- liblangutil/Token.h | 5 +++-- libsolidity/experimental/analysis/TypeRegistration.cpp | 2 +- libsolidity/experimental/ast/TypeSystemHelper.cpp | 2 +- test/libsolidity/semanticTests/experimental/stub.sol | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/liblangutil/Token.h b/liblangutil/Token.h index c4788f58cbc0..b3b3b1718c68 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -273,7 +273,8 @@ namespace solidity::langutil K(Class, "class", 0) \ K(Instantiation, "instantiation", 0) \ K(Word, "word", 0) \ - K(Integer, "integer", 0) \ + K(IntegerType, "integer", 0) \ + K(Integer, "Integer", 0) \ K(Itself, "itself", 0) \ K(Void, "void", 0) \ K(Pair, "pair", 0) \ @@ -310,7 +311,7 @@ namespace TokenTraits (Token::Int <= _token && _token < Token::TypesEnd) || _token == Token::Word || _token == Token::Void || - _token == Token::Integer || + _token == Token::IntegerType || _token == Token::Pair || _token == Token::Unit || _token == Token::Fun; diff --git a/libsolidity/experimental/analysis/TypeRegistration.cpp b/libsolidity/experimental/analysis/TypeRegistration.cpp index 1f6ff1ba0ef0..6813e9151572 100644 --- a/libsolidity/experimental/analysis/TypeRegistration.cpp +++ b/libsolidity/experimental/analysis/TypeRegistration.cpp @@ -73,7 +73,7 @@ bool TypeRegistration::visit(ElementaryTypeName const& _typeName) return m_typeSystem.constructor(PrimitiveType::Pair); case Token::Word: return m_typeSystem.constructor(PrimitiveType::Word); - case Token::Integer: + case Token::IntegerType: return m_typeSystem.constructor(PrimitiveType::Integer); case Token::Bool: return m_typeSystem.constructor(PrimitiveType::Bool); diff --git a/libsolidity/experimental/ast/TypeSystemHelper.cpp b/libsolidity/experimental/ast/TypeSystemHelper.cpp index d2280b181179..2b4d379ad845 100644 --- a/libsolidity/experimental/ast/TypeSystemHelper.cpp +++ b/libsolidity/experimental/ast/TypeSystemHelper.cpp @@ -66,7 +66,7 @@ std::optional experimental::typeConstructorFromToken(Analysis c return typeSystem.builtinConstructor(BuiltinType::Pair); case Token::Word: return typeSystem.builtinConstructor(BuiltinType::Word); - case Token::Integer: + case Token::IntegerType: return typeSystem.builtinConstructor(BuiltinType::Integer); case Token::Bool: return typeSystem.builtinConstructor(BuiltinType::Bool); diff --git a/test/libsolidity/semanticTests/experimental/stub.sol b/test/libsolidity/semanticTests/experimental/stub.sol index 5ec9c5d1e9cc..d59a24994a51 100644 --- a/test/libsolidity/semanticTests/experimental/stub.sol +++ b/test/libsolidity/semanticTests/experimental/stub.sol @@ -34,7 +34,7 @@ instantiation word: * { } } -instantiation word: integer { +instantiation word: Integer { function fromInteger(x:integer) -> word { //x + x; } From 39f85477eb6780072f00da2c1e255868a8e5ea1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 18 Sep 2023 18:16:31 +0200 Subject: [PATCH 2/6] Syntax test for built-in types in experimental Solidity. --- .../builtin/builtin_type_definition.sol | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol diff --git a/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol new file mode 100644 index 000000000000..e8e9ab4ae572 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol @@ -0,0 +1,68 @@ +pragma experimental solidity; + +contract C { + fallback() external { + let v: void; + + let b: bool; + bool.abs(bool.rep(b)); + + let w: word; + let i: integer; + let u: unit; + + let f: fun(word, bool); + b = f(w); + + let p: pair(bool, word); + pair.first(p); + pair.second(p); + } +} +// ==== +// EVMVersion: >=constantinople +// compileViaYul: true +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// Info 4164: (48-348): Inferred type: () -> () +// Info 4164: (56-58): Inferred type: () +// Info 4164: (82-89): Inferred type: void +// Info 4164: (85-89): Inferred type: void +// Info 4164: (104-111): Inferred type: bool +// Info 4164: (107-111): Inferred type: bool +// Info 4164: (121-142): Inferred type: bool +// Info 4164: (121-129): Inferred type: word -> bool +// Info 4164: (121-125): Inferred type: bool +// Info 4164: (130-141): Inferred type: word +// Info 4164: (130-138): Inferred type: bool -> word +// Info 4164: (130-134): Inferred type: bool +// Info 4164: (139-140): Inferred type: bool +// Info 4164: (157-164): Inferred type: word +// Info 4164: (160-164): Inferred type: word +// Info 4164: (178-188): Inferred type: integer +// Info 4164: (181-188): Inferred type: integer +// Info 4164: (202-209): Inferred type: () +// Info 4164: (205-209): Inferred type: () +// Info 4164: (224-242): Inferred type: word -> bool +// Info 4164: (227-242): Inferred type: word -> bool +// Info 4164: (227-230): Inferred type: tfun((word, bool), word -> bool) +// Info 4164: (231-235): Inferred type: word +// Info 4164: (237-241): Inferred type: bool +// Info 4164: (252-260): Inferred type: bool +// Info 4164: (252-253): Inferred type: bool +// Info 4164: (256-260): Inferred type: bool +// Info 4164: (256-257): Inferred type: word -> bool +// Info 4164: (258-259): Inferred type: word +// Info 4164: (275-294): Inferred type: (bool, word) +// Info 4164: (278-294): Inferred type: (bool, word) +// Info 4164: (278-282): Inferred type: tfun((bool, word), (bool, word)) +// Info 4164: (283-287): Inferred type: bool +// Info 4164: (289-293): Inferred type: word +// Info 4164: (304-317): Inferred type: bool +// Info 4164: (304-314): Inferred type: (bool, word) -> bool +// Info 4164: (304-308): Inferred type: ('bh:type, 'bi:type) +// Info 4164: (315-316): Inferred type: (bool, word) +// Info 4164: (327-341): Inferred type: word +// Info 4164: (327-338): Inferred type: (bool, word) -> word +// Info 4164: (327-331): Inferred type: ('bn:type, 'bo:type) +// Info 4164: (339-340): Inferred type: (bool, word) From 9147dac46a0de8a3ab9cacf81991dc7812ad3656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 18 Sep 2023 15:58:29 +0200 Subject: [PATCH 3/6] TypeSystemHelper: Add isPrimitiveType() --- .../experimental/ast/TypeSystemHelper.cpp | 18 ++++++++++-------- .../experimental/ast/TypeSystemHelper.h | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/libsolidity/experimental/ast/TypeSystemHelper.cpp b/libsolidity/experimental/ast/TypeSystemHelper.cpp index 2b4d379ad845..bc7dd4fcc35a 100644 --- a/libsolidity/experimental/ast/TypeSystemHelper.cpp +++ b/libsolidity/experimental/ast/TypeSystemHelper.cpp @@ -224,6 +224,14 @@ bool TypeSystemHelpers::isTypeConstant(Type _type) const }, _type); } +bool TypeSystemHelpers::isPrimitiveType(Type _type, PrimitiveType _primitiveType) const +{ + if (!isTypeConstant(_type)) + return false; + auto constructor = std::get<0>(destTypeConstant(_type)); + return constructor == typeSystem.constructor(_primitiveType); +} + experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType, experimental::Type _resultType) const { return typeSystem.type(PrimitiveType::Function, {_argType, _resultType}); @@ -239,10 +247,7 @@ std::tuple TypeSystemHelpers::destFuncti bool TypeSystemHelpers::isFunctionType(Type _type) const { - if (!isTypeConstant(_type)) - return false; - auto constructor = std::get<0>(destTypeConstant(_type)); - return constructor == typeSystem.constructor(PrimitiveType::Function); + return isPrimitiveType(_type, PrimitiveType::Function); } experimental::Type TypeSystemHelpers::typeFunctionType(experimental::Type _argType, experimental::Type _resultType) const @@ -260,10 +265,7 @@ std::tuple TypeSystemHelpers::destTypeFu bool TypeSystemHelpers::isTypeFunctionType(Type _type) const { - if (!isTypeConstant(_type)) - return false; - auto constructor = std::get<0>(destTypeConstant(_type)); - return constructor == typeSystem.constructor(PrimitiveType::TypeFunction); + return isPrimitiveType(_type, PrimitiveType::TypeFunction); } std::vector TypeEnvironmentHelpers::typeVars(Type _type) const diff --git a/libsolidity/experimental/ast/TypeSystemHelper.h b/libsolidity/experimental/ast/TypeSystemHelper.h index 5149d34bdb83..fd55c1bf842e 100644 --- a/libsolidity/experimental/ast/TypeSystemHelper.h +++ b/libsolidity/experimental/ast/TypeSystemHelper.h @@ -35,6 +35,7 @@ struct TypeSystemHelpers TypeSystem const& typeSystem; std::tuple> destTypeConstant(Type _type) const; bool isTypeConstant(Type _type) const; + bool isPrimitiveType(Type _type, PrimitiveType _primitiveType) const; Type tupleType(std::vector _elements) const; std::vector destTupleType(Type _tupleType) const; Type sumType(std::vector _elements) const; From 7a505412c0c27b44d147afefd5904b957e8cd0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 12 Sep 2023 16:26:42 +0200 Subject: [PATCH 4/6] Add Builtin AST node --- libsolidity/ast/AST.h | 29 +++++++++++++++++++++++++++++ libsolidity/ast/ASTForward.h | 1 + libsolidity/ast/ASTVisitor.h | 4 ++++ libsolidity/ast/AST_accept.h | 12 ++++++++++++ 4 files changed, 46 insertions(+) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 4767f7c30861..b9cc2118ef54 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -2596,6 +2596,35 @@ class TypeClassName: public ASTNode std::variant> m_name; }; +class Builtin: public Expression +{ +public: + Builtin( + int64_t _id, + SourceLocation _location, + ASTPointer _nameParameter, + SourceLocation _nameParameterLocation + ): + Expression(_id, std::move(_location)), + m_nameParameter(std::move(_nameParameter)), + m_nameParameterLocation(std::move(_nameParameterLocation)) + { + solAssert(m_nameParameter); + } + + void accept(ASTVisitor& _visitor) override; + void accept(ASTConstVisitor& _visitor) const override; + + bool experimentalSolidityOnly() const override { return true; } + + ASTString const& nameParameter() const { return *m_nameParameter; } + SourceLocation const& nameParameterLocation() const { return m_nameParameterLocation; } + +private: + ASTPointer m_nameParameter; + SourceLocation m_nameParameterLocation; +}; + /// @} } diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index f13b6e55dba3..f7c3d60237d7 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -105,6 +105,7 @@ class TypeClassDefinition; class TypeClassInstantiation; class TypeClassName; class TypeDefinition; +class Builtin; /// @} class VariableScope; diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 959cd5dce168..f9196d6b95c8 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -115,6 +115,7 @@ class ASTVisitor virtual bool visit(TypeClassInstantiation& _node) { return visitNode(_node); } virtual bool visit(TypeDefinition& _node) { return visitNode(_node); } virtual bool visit(TypeClassName& _node) { return visitNode(_node); } + virtual bool visit(Builtin& _node) { return visitNode(_node); } /// @} virtual void endVisit(SourceUnit& _node) { endVisitNode(_node); } @@ -178,6 +179,7 @@ class ASTVisitor virtual void endVisit(TypeClassInstantiation& _node) { endVisitNode(_node); } virtual void endVisit(TypeDefinition& _node) { endVisitNode(_node); } virtual void endVisit(TypeClassName& _node) { endVisitNode(_node); } + virtual void endVisit(Builtin& _node) { endVisitNode(_node); } /// @} protected: @@ -263,6 +265,7 @@ class ASTConstVisitor virtual bool visit(TypeClassInstantiation const& _node) { return visitNode(_node); } virtual bool visit(TypeDefinition const& _node) { return visitNode(_node); } virtual bool visit(TypeClassName const& _node) { return visitNode(_node); } + virtual bool visit(Builtin const& _node) { return visitNode(_node); } /// @} virtual void endVisit(SourceUnit const& _node) { endVisitNode(_node); } @@ -326,6 +329,7 @@ class ASTConstVisitor virtual void endVisit(TypeClassInstantiation const& _node) { endVisitNode(_node); } virtual void endVisit(TypeDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(TypeClassName const& _node) { endVisitNode(_node); } + virtual void endVisit(Builtin const& _node) { endVisitNode(_node); } /// @} protected: diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index d0b5ad28188d..be9de64db7a2 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -1128,6 +1128,18 @@ void TypeClassName::accept(ASTConstVisitor& _visitor) const } _visitor.endVisit(*this); } + +void Builtin::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Builtin::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} /// @} } From a28ece9509b71d4a415e4c49a4c1df320b041f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 12 Sep 2023 17:54:52 +0200 Subject: [PATCH 5/6] Replace hard-coded types with __builtin() --- liblangutil/Token.h | 22 +--- .../experimental/analysis/TypeInference.cpp | 90 ++++----------- .../experimental/analysis/TypeInference.h | 1 - .../analysis/TypeRegistration.cpp | 72 ++++++------ .../experimental/analysis/TypeRegistration.h | 5 +- libsolidity/parsing/Parser.cpp | 17 ++- .../semanticTests/experimental/stub.sol | 4 + .../semanticTests/experimental/type_class.sol | 4 +- .../builtin/builtin_type_definition.sol | 107 +++++++++++------- .../builtin_type_definition_unknown.sol | 8 ++ 10 files changed, 165 insertions(+), 165 deletions(-) create mode 100644 test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_unknown.sol diff --git a/liblangutil/Token.h b/liblangutil/Token.h index b3b3b1718c68..98de0b228d04 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -269,18 +269,13 @@ namespace solidity::langutil T(Leave, "leave", 0) \ \ T(NonExperimentalEnd, nullptr, 0) /* used as non-experimental enum end marker */ \ - /* Experimental Solidity specific keywords. */ \ + /* Experimental Solidity specific keywords. */ \ K(Class, "class", 0) \ K(Instantiation, "instantiation", 0) \ - K(Word, "word", 0) \ - K(IntegerType, "integer", 0) \ K(Integer, "Integer", 0) \ K(Itself, "itself", 0) \ - K(Void, "void", 0) \ - K(Pair, "pair", 0) \ - K(Fun, "fun", 0) \ - K(Unit, "unit", 0) \ K(StaticAssert, "static_assert", 0) \ + K(Builtin, "__builtin", 0) \ T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \ \ /* Illegal token - not able to scan. */ \ @@ -305,17 +300,7 @@ namespace TokenTraits constexpr size_t count() { return static_cast(Token::NUM_TOKENS); } // Predicates - constexpr bool isElementaryTypeName(Token _token) - { - return - (Token::Int <= _token && _token < Token::TypesEnd) || - _token == Token::Word || - _token == Token::Void || - _token == Token::IntegerType || - _token == Token::Pair || - _token == Token::Unit || - _token == Token::Fun; - } + constexpr bool isElementaryTypeName(Token _token) { return Token::Int <= _token && _token < Token::TypesEnd; } constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; } constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; } constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd || @@ -372,7 +357,6 @@ namespace TokenTraits token == Token::Let || token == Token::Return || token == Token::Type || - token == Token::Bool || token == Token::If || token == Token::Else || token == Token::Do || diff --git a/libsolidity/experimental/analysis/TypeInference.cpp b/libsolidity/experimental/analysis/TypeInference.cpp index 5824767ef849..590e82b4227d 100644 --- a/libsolidity/experimental/analysis/TypeInference.cpp +++ b/libsolidity/experimental/analysis/TypeInference.cpp @@ -125,22 +125,6 @@ TypeInference::TypeInference(Analysis& _analysis): defineBinaryCompareOperator(BuiltinClass::LessOrEqual, Token::LessThanOrEqual, "leq"); defineBinaryCompareOperator(BuiltinClass::Greater, Token::GreaterThan, "gt"); defineBinaryCompareOperator(BuiltinClass::GreaterOrEqual, Token::GreaterThanOrEqual, "geq"); - - { - auto [members, newlyInserted] = annotation().members.emplace(m_typeSystem.constructor(PrimitiveType::Bool), std::map{}); - solAssert(newlyInserted); - members->second.emplace("abs", TypeMember{helper.functionType(m_wordType, m_boolType)}); - members->second.emplace("rep", TypeMember{helper.functionType(m_boolType, m_wordType)}); - } - { - Type first = m_typeSystem.freshTypeVariable({}); - Type second = m_typeSystem.freshTypeVariable({}); - Type pairType = m_typeSystem.type(PrimitiveType::Pair, {first, second}); - auto [members, newlyInserted] = annotation().members.emplace(m_typeSystem.constructor(PrimitiveType::Pair), std::map{}); - solAssert(newlyInserted); - members->second.emplace("first", TypeMember{helper.functionType(pairType, first)}); - members->second.emplace("second", TypeMember{helper.functionType(pairType, second)}); - } } bool TypeInference::analyze(SourceUnit const& _sourceUnit) @@ -307,48 +291,6 @@ bool TypeInference::visit(InlineAssembly const& _inlineAssembly) return false; } -bool TypeInference::visit(ElementaryTypeNameExpression const& _expression) -{ - auto& expressionAnnotation = annotation(_expression); - solAssert(!expressionAnnotation.type); - - switch (m_expressionContext) - { - case ExpressionContext::Term: - case ExpressionContext::Type: - if (auto constructor = m_analysis.annotation(_expression).typeConstructor) - { - std::vector arguments; - std::generate_n(std::back_inserter(arguments), m_typeSystem.constructorInfo(*constructor).arguments(), [&]() { - return m_typeSystem.freshTypeVariable({}); - }); - // TODO: get rid of the distinction (assign a function on unit for the empty case)? Ambiguity? - if (arguments.empty() || m_expressionContext == ExpressionContext::Term) - expressionAnnotation.type = m_typeSystem.type(*constructor, arguments); - else - { - TypeSystemHelpers helper{m_typeSystem}; - expressionAnnotation.type = - helper.typeFunctionType( - helper.tupleType(arguments), - m_typeSystem.type(*constructor, arguments) - ); - } - } - else - { - m_errorReporter.typeError(4107_error, _expression.location(), "No type constructor registered for elementary type name."); - expressionAnnotation.type = m_typeSystem.freshTypeVariable({}); - } - break; - case ExpressionContext::Sort: - m_errorReporter.typeError(2024_error, _expression.location(), "Elementary type name expression not supported in sort context."); - expressionAnnotation.type = m_typeSystem.freshTypeVariable({}); - break; - } - return false; -} - bool TypeInference::visit(BinaryOperation const& _binaryOperation) { auto& operationAnnotation = annotation(_binaryOperation); @@ -825,6 +767,8 @@ void TypeInference::endVisit(MemberAccess const& _memberAccess) bool TypeInference::visit(TypeDefinition const& _typeDefinition) { + bool isBuiltIn = dynamic_cast(_typeDefinition.typeExpression()); + TypeSystemHelpers helper{m_typeSystem}; auto& typeDefinitionAnnotation = annotation(_typeDefinition); if (typeDefinitionAnnotation.type) @@ -833,14 +777,6 @@ bool TypeInference::visit(TypeDefinition const& _typeDefinition) if (_typeDefinition.arguments()) _typeDefinition.arguments()->accept(*this); - std::optional underlyingType; - if (_typeDefinition.typeExpression()) - { - ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type}; - _typeDefinition.typeExpression()->accept(*this); - underlyingType = annotation(*_typeDefinition.typeExpression()).type; - } - std::vector arguments; if (_typeDefinition.arguments()) for (size_t i = 0; i < _typeDefinition.arguments()->parameters().size(); ++i) @@ -852,6 +788,19 @@ bool TypeInference::visit(TypeDefinition const& _typeDefinition) else typeDefinitionAnnotation.type = helper.typeFunctionType(helper.tupleType(arguments), definedType); + std::optional underlyingType; + + if (isBuiltIn) + // TODO: This special case should eventually become user-definable. + underlyingType = m_wordType; + else if (_typeDefinition.typeExpression()) + { + ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type}; + _typeDefinition.typeExpression()->accept(*this); + + underlyingType = annotation(*_typeDefinition.typeExpression()).type; + } + TypeConstructor constructor = typeConstructor(&_typeDefinition); auto [members, newlyInserted] = annotation().members.emplace(constructor, std::map{}); solAssert(newlyInserted, fmt::format("Members of type '{}' are already defined.", m_typeSystem.constructorInfo(constructor).name)); @@ -860,6 +809,15 @@ bool TypeInference::visit(TypeDefinition const& _typeDefinition) members->second.emplace("abs", TypeMember{helper.functionType(*underlyingType, definedType)}); members->second.emplace("rep", TypeMember{helper.functionType(definedType, *underlyingType)}); } + + if (helper.isPrimitiveType(definedType, PrimitiveType::Pair)) + { + solAssert(isBuiltIn); + solAssert(arguments.size() == 2); + members->second.emplace("first", TypeMember{helper.functionType(definedType, arguments[0])}); + members->second.emplace("second", TypeMember{helper.functionType(definedType, arguments[1])}); + } + return false; } diff --git a/libsolidity/experimental/analysis/TypeInference.h b/libsolidity/experimental/analysis/TypeInference.h index 27b15ab45550..eb1b03f6974d 100644 --- a/libsolidity/experimental/analysis/TypeInference.h +++ b/libsolidity/experimental/analysis/TypeInference.h @@ -79,7 +79,6 @@ class TypeInference: public ASTConstVisitor bool visit(MemberAccess const& _memberAccess) override; void endVisit(MemberAccess const& _memberAccess) override; - bool visit(ElementaryTypeNameExpression const& _expression) override; bool visit(TypeClassDefinition const& _typeClassDefinition) override; bool visit(TypeClassInstantiation const& _typeClassInstantiation) override; diff --git a/libsolidity/experimental/analysis/TypeRegistration.cpp b/libsolidity/experimental/analysis/TypeRegistration.cpp index 6813e9151572..78f3a81316a9 100644 --- a/libsolidity/experimental/analysis/TypeRegistration.cpp +++ b/libsolidity/experimental/analysis/TypeRegistration.cpp @@ -56,32 +56,30 @@ bool TypeRegistration::visit(TypeClassDefinition const& _typeClassDefinition) return true; } -bool TypeRegistration::visit(ElementaryTypeName const& _typeName) +bool TypeRegistration::visit(Builtin const& _builtin) { - if (annotation(_typeName).typeConstructor) + if (annotation(_builtin).typeConstructor) return false; - annotation(_typeName).typeConstructor = [&]() -> std::optional { - switch (_typeName.typeName().token()) - { - case Token::Void: - return m_typeSystem.constructor(PrimitiveType::Void); - case Token::Fun: - return m_typeSystem.constructor(PrimitiveType::Function); - case Token::Unit: - return m_typeSystem.constructor(PrimitiveType::Unit); - case Token::Pair: - return m_typeSystem.constructor(PrimitiveType::Pair); - case Token::Word: - return m_typeSystem.constructor(PrimitiveType::Word); - case Token::IntegerType: - return m_typeSystem.constructor(PrimitiveType::Integer); - case Token::Bool: - return m_typeSystem.constructor(PrimitiveType::Bool); - default: - m_errorReporter.fatalTypeError(7758_error, _typeName.location(), "Expected primitive type."); - return std::nullopt; - } - }(); + + auto primitiveType = [&](std::string _name) -> std::optional { + if (_name == "void") return PrimitiveType::Void; + if (_name == "fun") return PrimitiveType::Function; + if (_name == "unit") return PrimitiveType::Unit; + if (_name == "pair") return PrimitiveType::Pair; + if (_name == "word") return PrimitiveType::Word; + if (_name == "integer") return PrimitiveType::Integer; + if (_name == "bool") return PrimitiveType::Bool; + return std::nullopt; + }(_builtin.nameParameter()); + + if (!primitiveType.has_value()) + m_errorReporter.fatalTypeError( + 7758_error, + _builtin.location(), + "Expected the name of a built-in primitive type." + ); + + annotation(_builtin).typeConstructor = m_typeSystem.constructor(primitiveType.value()); return true; } @@ -165,15 +163,23 @@ bool TypeRegistration::visit(TypeClassInstantiation const& _typeClassInstantiati bool TypeRegistration::visit(TypeDefinition const& _typeDefinition) { - if (annotation(_typeDefinition).typeConstructor) - return false; - annotation(_typeDefinition).typeConstructor = m_typeSystem.declareTypeConstructor( - _typeDefinition.name(), - "t_" + *_typeDefinition.annotation().canonicalName + "_" + util::toString(_typeDefinition.id()), - _typeDefinition.arguments() ? _typeDefinition.arguments()->parameters().size() : 0, - &_typeDefinition - ); - return true; + return !annotation(_typeDefinition).typeConstructor.has_value(); +} + +void TypeRegistration::endVisit(TypeDefinition const& _typeDefinition) +{ + if (annotation(_typeDefinition).typeConstructor.has_value()) + return; + + if (auto const* builtin = dynamic_cast(_typeDefinition.typeExpression())) + annotation(_typeDefinition).typeConstructor = annotation(*builtin).typeConstructor; + else + annotation(_typeDefinition).typeConstructor = m_typeSystem.declareTypeConstructor( + _typeDefinition.name(), + "t_" + *_typeDefinition.annotation().canonicalName + "_" + util::toString(_typeDefinition.id()), + _typeDefinition.arguments() ? _typeDefinition.arguments()->parameters().size() : 0, + &_typeDefinition + ); } TypeRegistration::Annotation& TypeRegistration::annotation(ASTNode const& _node) diff --git a/libsolidity/experimental/analysis/TypeRegistration.h b/libsolidity/experimental/analysis/TypeRegistration.h index d6d534fa7cd3..e8b087daa930 100644 --- a/libsolidity/experimental/analysis/TypeRegistration.h +++ b/libsolidity/experimental/analysis/TypeRegistration.h @@ -35,7 +35,7 @@ class TypeRegistration: public ASTConstVisitor { // For type class definitions. TypeClassInstantiations instantiations; - // For type definitions, type class definitions, type names and type name expressions. + // For builtins, type definitions, type class definitions, type names and type name expressions. std::optional typeConstructor; }; struct GlobalAnnotation @@ -50,9 +50,10 @@ class TypeRegistration: public ASTConstVisitor bool visit(TypeClassDefinition const& _typeClassDefinition) override; bool visit(TypeClassInstantiation const& _typeClassInstantiation) override; bool visit(TypeDefinition const& _typeDefinition) override; + void endVisit(TypeDefinition const& _typeDefinition) override; bool visit(UserDefinedTypeName const& _typeName) override; void endVisit(ElementaryTypeNameExpression const& _typeName) override; - bool visit(ElementaryTypeName const& _typeName) override; + bool visit(Builtin const& _builtin) override; Annotation& annotation(ASTNode const& _node); GlobalAnnotation& annotation(); diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 71f5108e5c52..42be1ab9eecf 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1834,7 +1834,22 @@ ASTPointer Parser::parseTypeDefinition() if (m_scanner->currentToken() == Token::Assign) { expectToken(Token::Assign); - expression = parseExpression(); + + if (m_scanner->currentToken() != Token::Builtin) + expression = parseExpression(); + else + { + expectToken(Token::Builtin); + expectToken(Token::LParen); + + expression = nodeFactory.createNode( + std::make_shared(m_scanner->currentLiteral()), + m_scanner->currentLocation() + ); + + expectToken(Token::StringLiteral); + expectToken(Token::RParen); + } } nodeFactory.markEndPosition(); expectToken(Token::Semicolon); diff --git a/test/libsolidity/semanticTests/experimental/stub.sol b/test/libsolidity/semanticTests/experimental/stub.sol index d59a24994a51..6e7a750fe980 100644 --- a/test/libsolidity/semanticTests/experimental/stub.sol +++ b/test/libsolidity/semanticTests/experimental/stub.sol @@ -1,5 +1,9 @@ pragma experimental solidity; +type word = __builtin("word"); +type bool = __builtin("bool"); +type integer = __builtin("integer"); + type uint256 = word; instantiation uint256: + { diff --git a/test/libsolidity/semanticTests/experimental/type_class.sol b/test/libsolidity/semanticTests/experimental/type_class.sol index b987b3f0665f..69fa568dfd96 100644 --- a/test/libsolidity/semanticTests/experimental/type_class.sol +++ b/test/libsolidity/semanticTests/experimental/type_class.sol @@ -1,5 +1,8 @@ pragma experimental solidity; +type word = __builtin("word"); +type bool = __builtin("bool"); + type Cat = word; type Dog = word; @@ -59,7 +62,6 @@ contract C { // ==== // EVMVersion: >=constantinople -// ==== // compileViaYul: true // ---- // () -> 1, 0 diff --git a/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol index e8e9ab4ae572..753cf42faf8f 100644 --- a/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol +++ b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition.sol @@ -1,5 +1,15 @@ pragma experimental solidity; +type void = __builtin("void"); + +type bool = __builtin("bool"); +type word = __builtin("word"); +type integer = __builtin("integer"); +type unit = __builtin("unit"); + +type fun(T, U) = __builtin("fun"); +type pair(T, U) = __builtin("pair"); + contract C { fallback() external { let v: void; @@ -24,45 +34,58 @@ contract C { // compileViaYul: true // ---- // Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. -// Info 4164: (48-348): Inferred type: () -> () -// Info 4164: (56-58): Inferred type: () -// Info 4164: (82-89): Inferred type: void -// Info 4164: (85-89): Inferred type: void -// Info 4164: (104-111): Inferred type: bool -// Info 4164: (107-111): Inferred type: bool -// Info 4164: (121-142): Inferred type: bool -// Info 4164: (121-129): Inferred type: word -> bool -// Info 4164: (121-125): Inferred type: bool -// Info 4164: (130-141): Inferred type: word -// Info 4164: (130-138): Inferred type: bool -> word -// Info 4164: (130-134): Inferred type: bool -// Info 4164: (139-140): Inferred type: bool -// Info 4164: (157-164): Inferred type: word -// Info 4164: (160-164): Inferred type: word -// Info 4164: (178-188): Inferred type: integer -// Info 4164: (181-188): Inferred type: integer -// Info 4164: (202-209): Inferred type: () -// Info 4164: (205-209): Inferred type: () -// Info 4164: (224-242): Inferred type: word -> bool -// Info 4164: (227-242): Inferred type: word -> bool -// Info 4164: (227-230): Inferred type: tfun((word, bool), word -> bool) -// Info 4164: (231-235): Inferred type: word -// Info 4164: (237-241): Inferred type: bool -// Info 4164: (252-260): Inferred type: bool -// Info 4164: (252-253): Inferred type: bool -// Info 4164: (256-260): Inferred type: bool -// Info 4164: (256-257): Inferred type: word -> bool -// Info 4164: (258-259): Inferred type: word -// Info 4164: (275-294): Inferred type: (bool, word) -// Info 4164: (278-294): Inferred type: (bool, word) -// Info 4164: (278-282): Inferred type: tfun((bool, word), (bool, word)) -// Info 4164: (283-287): Inferred type: bool -// Info 4164: (289-293): Inferred type: word -// Info 4164: (304-317): Inferred type: bool -// Info 4164: (304-314): Inferred type: (bool, word) -> bool -// Info 4164: (304-308): Inferred type: ('bh:type, 'bi:type) -// Info 4164: (315-316): Inferred type: (bool, word) -// Info 4164: (327-341): Inferred type: word -// Info 4164: (327-338): Inferred type: (bool, word) -> word -// Info 4164: (327-331): Inferred type: ('bn:type, 'bo:type) -// Info 4164: (339-340): Inferred type: (bool, word) +// Info 4164: (31-61): Inferred type: void +// Info 4164: (63-93): Inferred type: bool +// Info 4164: (94-124): Inferred type: word +// Info 4164: (125-161): Inferred type: integer +// Info 4164: (162-192): Inferred type: () +// Info 4164: (194-228): Inferred type: tfun(('u:type, 'v:type), 'u:type -> 'v:type) +// Info 4164: (202-208): Inferred type: ('s:type, 't:type) +// Info 4164: (203-204): Inferred type: 's:type +// Info 4164: (206-207): Inferred type: 't:type +// Info 4164: (229-265): Inferred type: tfun(('y:type, 'z:type), ('y:type, 'z:type)) +// Info 4164: (238-244): Inferred type: ('w:type, 'x:type) +// Info 4164: (239-240): Inferred type: 'w:type +// Info 4164: (242-243): Inferred type: 'x:type +// Info 4164: (284-584): Inferred type: () -> () +// Info 4164: (292-294): Inferred type: () +// Info 4164: (318-325): Inferred type: void +// Info 4164: (321-325): Inferred type: void +// Info 4164: (340-347): Inferred type: bool +// Info 4164: (343-347): Inferred type: bool +// Info 4164: (357-378): Inferred type: bool +// Info 4164: (357-365): Inferred type: word -> bool +// Info 4164: (357-361): Inferred type: bool +// Info 4164: (366-377): Inferred type: word +// Info 4164: (366-374): Inferred type: bool -> word +// Info 4164: (366-370): Inferred type: bool +// Info 4164: (375-376): Inferred type: bool +// Info 4164: (393-400): Inferred type: word +// Info 4164: (396-400): Inferred type: word +// Info 4164: (414-424): Inferred type: integer +// Info 4164: (417-424): Inferred type: integer +// Info 4164: (438-445): Inferred type: () +// Info 4164: (441-445): Inferred type: () +// Info 4164: (460-478): Inferred type: word -> bool +// Info 4164: (463-478): Inferred type: word -> bool +// Info 4164: (463-466): Inferred type: tfun((word, bool), word -> bool) +// Info 4164: (467-471): Inferred type: word +// Info 4164: (473-477): Inferred type: bool +// Info 4164: (488-496): Inferred type: bool +// Info 4164: (488-489): Inferred type: bool +// Info 4164: (492-496): Inferred type: bool +// Info 4164: (492-493): Inferred type: word -> bool +// Info 4164: (494-495): Inferred type: word +// Info 4164: (511-530): Inferred type: (bool, word) +// Info 4164: (514-530): Inferred type: (bool, word) +// Info 4164: (514-518): Inferred type: tfun((bool, word), (bool, word)) +// Info 4164: (519-523): Inferred type: bool +// Info 4164: (525-529): Inferred type: word +// Info 4164: (540-553): Inferred type: bool +// Info 4164: (540-550): Inferred type: (bool, word) -> bool +// Info 4164: (540-544): Inferred type: ('cb:type, 'cc:type) +// Info 4164: (551-552): Inferred type: (bool, word) +// Info 4164: (563-577): Inferred type: word +// Info 4164: (563-574): Inferred type: (bool, word) -> word +// Info 4164: (563-567): Inferred type: ('ci:type, 'cj:type) +// Info 4164: (575-576): Inferred type: (bool, word) diff --git a/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_unknown.sol b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_unknown.sol new file mode 100644 index 000000000000..90072f19838f --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_unknown.sol @@ -0,0 +1,8 @@ +pragma experimental solidity; + +type someUnknownType = __builtin("someUnknownType"); +// ==== +// EVMVersion: >=constantinople +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError 7758: (31-81): Expected the name of a built-in primitive type. From 6cbe55b518ec836e6c05677c62260b27e7983ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 18 Sep 2023 14:01:32 +0200 Subject: [PATCH 6/6] Reject duplicate built-in type definitions --- .../analysis/TypeRegistration.cpp | 20 ++++++++++++++++++- .../experimental/analysis/TypeRegistration.h | 1 + .../builtin_type_definition_duplicate.sol | 17 ++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_duplicate.sol diff --git a/libsolidity/experimental/analysis/TypeRegistration.cpp b/libsolidity/experimental/analysis/TypeRegistration.cpp index 78f3a81316a9..43fd8d1175b9 100644 --- a/libsolidity/experimental/analysis/TypeRegistration.cpp +++ b/libsolidity/experimental/analysis/TypeRegistration.cpp @@ -172,7 +172,25 @@ void TypeRegistration::endVisit(TypeDefinition const& _typeDefinition) return; if (auto const* builtin = dynamic_cast(_typeDefinition.typeExpression())) - annotation(_typeDefinition).typeConstructor = annotation(*builtin).typeConstructor; + { + auto [previousDefinitionIt, inserted] = annotation().builtinTypeDefinitions.try_emplace( + builtin->nameParameter(), + &_typeDefinition + ); + + if (inserted) + annotation(_typeDefinition).typeConstructor = annotation(*builtin).typeConstructor; + else + { + auto const& [builtinName, previousDefinition] = *previousDefinitionIt; + m_errorReporter.typeError( + 9609_error, + _typeDefinition.location(), + SecondarySourceLocation{}.append("Previous definition:", previousDefinition->location()), + "Duplicate builtin type definition." + ); + } + } else annotation(_typeDefinition).typeConstructor = m_typeSystem.declareTypeConstructor( _typeDefinition.name(), diff --git a/libsolidity/experimental/analysis/TypeRegistration.h b/libsolidity/experimental/analysis/TypeRegistration.h index e8b087daa930..9bc49a29cfe4 100644 --- a/libsolidity/experimental/analysis/TypeRegistration.h +++ b/libsolidity/experimental/analysis/TypeRegistration.h @@ -42,6 +42,7 @@ class TypeRegistration: public ASTConstVisitor { std::map primitiveClassInstantiations; std::map builtinClassInstantiations; + std::map builtinTypeDefinitions; }; TypeRegistration(Analysis& _analysis); diff --git a/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_duplicate.sol b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_duplicate.sol new file mode 100644 index 000000000000..28f6c39fd754 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental/builtin/builtin_type_definition_duplicate.sol @@ -0,0 +1,17 @@ +pragma experimental solidity; + +type void1 = __builtin("void"); +type void2 = __builtin("void"); + +type word1 = __builtin("word"); +type word2 = __builtin("word"); + +type fun1(T, U) = __builtin("fun"); +type fun2(T, U) = __builtin("fun"); +// ==== +// EVMVersion: >=constantinople +// ---- +// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError 9609: (63-94): Duplicate builtin type definition. +// TypeError 9609: (128-159): Duplicate builtin type definition. +// TypeError 9609: (197-232): Duplicate builtin type definition.