mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #14168 from ethereum/pragma-solidity-next
Introduce `pragma experimental solidity`
This commit is contained in:
commit
1250ee778d
@ -5,12 +5,17 @@ Language Features:
|
||||
|
||||
Compiler Features:
|
||||
* EWasm: Remove EWasm backend.
|
||||
* Parser: Introduce ``pragma experimental solidity``, which will enable an experimental language mode that in particular has no stability guarantees between non-breaking releases and is not suited for production use.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* SMTChecker: Fix encoding of side-effects inside ``if`` and ``ternary conditional``statements in the BMC engine.
|
||||
|
||||
|
||||
AST Changes:
|
||||
* AST: Add the ``experimentalSolidity`` field to the ``SourceUnit`` nodes, which indicate whether the experimental parsing mode has been enabled via ``pragma experimental solidity``.
|
||||
|
||||
|
||||
### 0.8.20 (2023-05-10)
|
||||
|
||||
Compiler Features:
|
||||
|
@ -167,9 +167,14 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::optional<std::string> _licenseString,
|
||||
std::vector<ASTPointer<ASTNode>> _nodes
|
||||
std::vector<ASTPointer<ASTNode>> _nodes,
|
||||
bool _experimentalSolidity
|
||||
):
|
||||
ASTNode(_id, _location), m_licenseString(std::move(_licenseString)), m_nodes(std::move(_nodes)) {}
|
||||
ASTNode(_id, _location),
|
||||
m_licenseString(std::move(_licenseString)),
|
||||
m_nodes(std::move(_nodes)),
|
||||
m_experimentalSolidity(_experimentalSolidity)
|
||||
{}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -180,10 +185,12 @@ public:
|
||||
|
||||
/// @returns a set of referenced SourceUnits. Recursively if @a _recurse is true.
|
||||
std::set<SourceUnit const*> referencedSourceUnits(bool _recurse = false, std::set<SourceUnit const*> _skipList = std::set<SourceUnit const*>()) const;
|
||||
bool experimentalSolidity() const { return m_experimentalSolidity; }
|
||||
|
||||
private:
|
||||
std::optional<std::string> m_licenseString;
|
||||
std::vector<ASTPointer<ASTNode>> m_nodes;
|
||||
bool m_experimentalSolidity = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -214,9 +214,12 @@ bool ASTJsonExporter::visit(SourceUnit const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue),
|
||||
make_pair("nodes", toJson(_node.nodes()))
|
||||
make_pair("nodes", toJson(_node.nodes())),
|
||||
};
|
||||
|
||||
if (_node.experimentalSolidity())
|
||||
attributes.emplace_back("experimentalSolidity", Json::Value(_node.experimentalSolidity()));
|
||||
|
||||
if (_node.annotation().exportedSymbols.set())
|
||||
{
|
||||
Json::Value exportedSymbols = Json::objectValue;
|
||||
|
@ -271,11 +271,15 @@ ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _nod
|
||||
if (_node.isMember("license") && !_node["license"].isNull())
|
||||
license = _node["license"].asString();
|
||||
|
||||
bool experimentalSolidity = false;
|
||||
if (_node.isMember("experimentalSolidity") && !_node["experimentalSolidity"].isNull())
|
||||
experimentalSolidity = _node["experimentalSolidity"].asBool();
|
||||
|
||||
vector<ASTPointer<ASTNode>> nodes;
|
||||
for (auto& child: member(_node, "nodes"))
|
||||
nodes.emplace_back(convertJsonToASTNode(child));
|
||||
|
||||
ASTPointer<SourceUnit> tmp = createASTNode<SourceUnit>(_node, license, nodes);
|
||||
ASTPointer<SourceUnit> tmp = createASTNode<SourceUnit>(_node, license, nodes, experimentalSolidity);
|
||||
tmp->annotation().path = _srcName;
|
||||
return tmp;
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ enum class ExperimentalFeature
|
||||
ABIEncoderV2, // new ABI encoder that makes use of Yul
|
||||
SMTChecker,
|
||||
Test,
|
||||
TestOnlyAnalysis
|
||||
TestOnlyAnalysis,
|
||||
Solidity
|
||||
};
|
||||
|
||||
static std::set<ExperimentalFeature> const ExperimentalFeatureWithoutWarning =
|
||||
@ -48,6 +49,7 @@ static std::map<std::string, ExperimentalFeature> const ExperimentalFeatureNames
|
||||
{ "SMTChecker", ExperimentalFeature::SMTChecker },
|
||||
{ "__test", ExperimentalFeature::Test },
|
||||
{ "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis },
|
||||
{ "solidity", ExperimentalFeature::Solidity }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -429,7 +429,9 @@ bool CompilerStack::analyze()
|
||||
{
|
||||
if (m_stackState != ParsedAndImported || m_stackState >= AnalysisPerformed)
|
||||
solThrow(CompilerError, "Must call analyze only after parsing was performed.");
|
||||
resolveImports();
|
||||
|
||||
if (!resolveImports())
|
||||
return false;
|
||||
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast)
|
||||
@ -1175,7 +1177,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
|
||||
return m_importRemapper.apply(_path, _context);
|
||||
}
|
||||
|
||||
void CompilerStack::resolveImports()
|
||||
bool CompilerStack::resolveImports()
|
||||
{
|
||||
solAssert(m_stackState == ParsedAndImported, "");
|
||||
|
||||
@ -1200,11 +1202,34 @@ void CompilerStack::resolveImports()
|
||||
sourceOrder.push_back(_source);
|
||||
};
|
||||
|
||||
vector<PragmaDirective const*> experimentalPragmaDirectives;
|
||||
for (auto const& sourcePair: m_sources)
|
||||
{
|
||||
if (isRequestedSource(sourcePair.first))
|
||||
toposort(&sourcePair.second);
|
||||
if (sourcePair.second.ast && sourcePair.second.ast->experimentalSolidity())
|
||||
for (ASTPointer<ASTNode> const& node: sourcePair.second.ast->nodes())
|
||||
if (PragmaDirective const* pragma = dynamic_cast<PragmaDirective*>(node.get()))
|
||||
if (pragma->literals().size() >=2 && pragma->literals()[0] == "experimental" && pragma->literals()[1] == "solidity")
|
||||
{
|
||||
experimentalPragmaDirectives.push_back(pragma);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!experimentalPragmaDirectives.empty() && experimentalPragmaDirectives.size() != m_sources.size())
|
||||
{
|
||||
for (auto &&pragma: experimentalPragmaDirectives)
|
||||
m_errorReporter.parserError(
|
||||
2141_error,
|
||||
pragma->location(),
|
||||
"File declares \"pragma experimental solidity\". If you want to enable the experimental mode, all source units must include the pragma."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
swap(m_sourceOrder, sourceOrder);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompilerStack::storeContractDefinitions()
|
||||
|
@ -399,7 +399,7 @@ private:
|
||||
/// @returns the newly loaded sources.
|
||||
StringMap loadMissingSources(SourceUnit const& _ast);
|
||||
std::string applyRemapping(std::string const& _path, std::string const& _context);
|
||||
void resolveImports();
|
||||
bool resolveImports();
|
||||
|
||||
/// Store the contract definitions in m_contracts.
|
||||
void storeContractDefinitions();
|
||||
|
@ -94,14 +94,18 @@ ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream)
|
||||
m_recursionDepth = 0;
|
||||
m_scanner = make_shared<Scanner>(_charStream);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
m_experimentalSolidityEnabledInCurrentSourceUnit = false;
|
||||
|
||||
vector<ASTPointer<ASTNode>> nodes;
|
||||
while (m_scanner->currentToken() == Token::Pragma)
|
||||
nodes.push_back(parsePragmaDirective(false));
|
||||
|
||||
while (m_scanner->currentToken() != Token::EOS)
|
||||
{
|
||||
switch (m_scanner->currentToken())
|
||||
{
|
||||
case Token::Pragma:
|
||||
nodes.push_back(parsePragmaDirective());
|
||||
nodes.push_back(parsePragmaDirective(true));
|
||||
break;
|
||||
case Token::Import:
|
||||
nodes.push_back(parseImportDirective());
|
||||
@ -150,7 +154,7 @@ ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream)
|
||||
}
|
||||
}
|
||||
solAssert(m_recursionDepth == 0, "");
|
||||
return nodeFactory.createNode<SourceUnit>(findLicenseString(nodes), nodes);
|
||||
return nodeFactory.createNode<SourceUnit>(findLicenseString(nodes), nodes, m_experimentalSolidityEnabledInCurrentSourceUnit);
|
||||
}
|
||||
catch (FatalError const&)
|
||||
{
|
||||
@ -203,7 +207,7 @@ ASTPointer<StructuredDocumentation> Parser::parseStructuredDocumentation()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASTPointer<PragmaDirective> Parser::parsePragmaDirective()
|
||||
ASTPointer<PragmaDirective> Parser::parsePragmaDirective(bool const _finishedParsingTopLevelPragmas)
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
// pragma anything* ;
|
||||
@ -213,6 +217,7 @@ ASTPointer<PragmaDirective> Parser::parsePragmaDirective()
|
||||
expectToken(Token::Pragma);
|
||||
vector<string> literals;
|
||||
vector<Token> tokens;
|
||||
|
||||
do
|
||||
{
|
||||
Token token = m_scanner->currentToken();
|
||||
@ -241,6 +246,13 @@ ASTPointer<PragmaDirective> Parser::parsePragmaDirective()
|
||||
);
|
||||
}
|
||||
|
||||
if (literals.size() >= 2 && literals[0] == "experimental" && literals[1] == "solidity")
|
||||
{
|
||||
if (_finishedParsingTopLevelPragmas)
|
||||
fatalParserError(8185_error, "Experimental pragma \"solidity\" can only be set at the beginning of the source unit.");
|
||||
m_experimentalSolidityEnabledInCurrentSourceUnit = true;
|
||||
}
|
||||
|
||||
return nodeFactory.createNode<PragmaDirective>(tokens, literals);
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ private:
|
||||
///@name Parsing functions for the AST nodes
|
||||
void parsePragmaVersion(langutil::SourceLocation const& _location, std::vector<Token> const& _tokens, std::vector<std::string> const& _literals);
|
||||
ASTPointer<StructuredDocumentation> parseStructuredDocumentation();
|
||||
ASTPointer<PragmaDirective> parsePragmaDirective();
|
||||
ASTPointer<PragmaDirective> parsePragmaDirective(bool _finishedParsingTopLevelPragmas);
|
||||
ASTPointer<ImportDirective> parseImportDirective();
|
||||
/// @returns an std::pair<ContractKind, bool>, where
|
||||
/// result.second is set to true, if an abstract contract was parsed, false otherwise.
|
||||
@ -227,6 +227,8 @@ private:
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
/// Counter for the next AST node ID
|
||||
int64_t m_currentNodeID = 0;
|
||||
/// Flag that indicates whether experimental mode is enabled in the current source unit
|
||||
bool m_experimentalSolidityEnabledInCurrentSourceUnit = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ do
|
||||
SOL_FILES+=("$line")
|
||||
done < <(
|
||||
grep --include "*.sol" -riL -E \
|
||||
"^\/\/ (Syntax|Type|Declaration)Error|^\/\/ ParserError (1684|2837|3716|3997|5333|6275|6281|6933|7319)|^==== Source:" \
|
||||
"^\/\/ (Syntax|Type|Declaration)Error|^\/\/ ParserError (1684|2837|3716|3997|5333|6275|6281|6933|7319|8185)|^==== Source:" \
|
||||
"${ROOT_DIR}/test/libsolidity/syntaxTests" \
|
||||
"${ROOT_DIR}/test/libsolidity/semanticTests" |
|
||||
# Skipping the unicode tests as I couldn't adapt the lexical grammar to recursively counting RLO/LRO/PDF's.
|
||||
|
21
test/libsolidity/ASTJSON/pragma_experimental_solidity.json
Normal file
21
test/libsolidity/ASTJSON/pragma_experimental_solidity.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"absolutePath": "a",
|
||||
"experimentalSolidity": true,
|
||||
"exportedSymbols": {},
|
||||
"id": 2,
|
||||
"nodeType": "SourceUnit",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"literals":
|
||||
[
|
||||
"experimental",
|
||||
"solidity"
|
||||
],
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "0:29:1"
|
||||
}
|
||||
],
|
||||
"src": "0:30:1"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
pragma experimental solidity;
|
||||
|
||||
// ----
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"absolutePath": "a",
|
||||
"experimentalSolidity": true,
|
||||
"id": 2,
|
||||
"nodeType": "SourceUnit",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"literals":
|
||||
[
|
||||
"experimental",
|
||||
"solidity"
|
||||
],
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "0:29:1"
|
||||
}
|
||||
],
|
||||
"src": "0:30:1"
|
||||
}
|
@ -213,7 +213,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
ModifierDefinition mod(++id, SourceLocation{}, make_shared<string>("modif"), SourceLocation{}, {}, emptyParams, {}, {}, {});
|
||||
BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$");
|
||||
|
||||
SourceUnit su(++id, {}, {}, {});
|
||||
SourceUnit su(++id, {}, {}, {}, {});
|
||||
BOOST_CHECK_EQUAL(ModuleType(su).identifier(), "t_module_7");
|
||||
BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Block).identifier(), "t_magic_block");
|
||||
BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Message).identifier(), "t_magic_message");
|
||||
|
@ -0,0 +1,3 @@
|
||||
pragma experimental solidity;
|
||||
// ----
|
||||
// Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments.
|
@ -0,0 +1,24 @@
|
||||
==== Source: A.sol ====
|
||||
contract A {}
|
||||
==== Source: B.sol ====
|
||||
pragma experimental solidity;
|
||||
import "A.sol";
|
||||
contract B {
|
||||
A a;
|
||||
}
|
||||
==== Source: C.sol ====
|
||||
pragma experimental solidity;
|
||||
import "A.sol";
|
||||
contract C {
|
||||
A a;
|
||||
}
|
||||
==== Source: D.sol ====
|
||||
pragma experimental solidity;
|
||||
import "A.sol";
|
||||
contract D {
|
||||
A a;
|
||||
}
|
||||
// ----
|
||||
// ParserError 2141: (B.sol:0-29): File declares "pragma experimental solidity". If you want to enable the experimental mode, all source units must include the pragma.
|
||||
// ParserError 2141: (C.sol:0-29): File declares "pragma experimental solidity". If you want to enable the experimental mode, all source units must include the pragma.
|
||||
// ParserError 2141: (D.sol:0-29): File declares "pragma experimental solidity". If you want to enable the experimental mode, all source units must include the pragma.
|
@ -0,0 +1,5 @@
|
||||
contract A {}
|
||||
|
||||
pragma experimental solidity;
|
||||
// ----
|
||||
// ParserError 8185: (45-45): Experimental pragma "solidity" can only be set at the beginning of the source unit.
|
@ -0,0 +1,13 @@
|
||||
function f() pure returns (uint)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
pragma experimental solidity;
|
||||
|
||||
struct A
|
||||
{
|
||||
uint256 x;
|
||||
}
|
||||
// ----
|
||||
// ParserError 8185: (83-89): Experimental pragma "solidity" can only be set at the beginning of the source unit.
|
Loading…
Reference in New Issue
Block a user