From 14aed392614673505fe302fe1ac88bb351464217 Mon Sep 17 00:00:00 2001 From: Matheus Aguiar Date: Tue, 5 Sep 2023 21:29:11 -0300 Subject: [PATCH] Introduce experimental analysis basic infrastructure --- liblangutil/Scanner.cpp | 15 +- liblangutil/Scanner.h | 3 +- liblangutil/Token.h | 35 ++ libsolidity/CMakeLists.txt | 3 +- .../experimental/analysis/Analysis.cpp | 34 ++ libsolidity/experimental/analysis/Analysis.h | 49 +++ libsolidity/interface/CompilerStack.cpp | 304 ++++++++++-------- libsolidity/interface/CompilerStack.h | 13 + libyul/AsmParser.cpp | 3 +- .../ASTJSON/pragma_experimental_solidity.json | 21 -- .../ASTJSON/pragma_experimental_solidity.sol | 1 + .../experimental/parsing_stdlib_import_1.sol | 1 + .../experimental/parsing_stdlib_import_2.sol | 1 + .../experimental/parsing_stdlib_import_3.sol | 1 + .../experimental/parsing_stdlib_import_4.sol | 1 + .../pragma/experimental_solidity.sol | 1 + 16 files changed, 329 insertions(+), 157 deletions(-) create mode 100644 libsolidity/experimental/analysis/Analysis.cpp create mode 100644 libsolidity/experimental/analysis/Analysis.h delete mode 100644 test/libsolidity/ASTJSON/pragma_experimental_solidity.json diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index 2d5607607..3db3f29d5 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -1019,15 +1019,28 @@ std::tuple Scanner::scanIdentifierOrKeyword() while (isIdentifierPart(m_char) || (m_char == '.' && m_kind == ScannerKind::Yul)) addLiteralCharAndAdvance(); literal.complete(); + auto const token = TokenTraits::fromIdentifierOrKeyword(m_tokens[NextNext].literal); - if (m_kind == ScannerKind::Yul) + switch (m_kind) { + case ScannerKind::Solidity: + // Turn experimental Solidity keywords that are not keywords in legacy Solidity into identifiers. + if (TokenTraits::isExperimentalSolidityOnlyKeyword(std::get<0>(token))) + return std::make_tuple(Token::Identifier, 0, 0); + break; + case ScannerKind::Yul: // Turn Solidity identifier into a Yul keyword if (m_tokens[NextNext].literal == "leave") return std::make_tuple(Token::Leave, 0, 0); // Turn non-Yul keywords into identifiers. if (!TokenTraits::isYulKeyword(std::get<0>(token))) return std::make_tuple(Token::Identifier, 0, 0); + break; + case ScannerKind::ExperimentalSolidity: + // Turn legacy Solidity keywords that are not keywords in experimental Solidity into identifiers. + if (!TokenTraits::isExperimentalSolidityKeyword(std::get<0>(token))) + return std::make_tuple(Token::Identifier, 0, 0); + break; } return token; } diff --git a/liblangutil/Scanner.h b/liblangutil/Scanner.h index c45a2ec24..eaa2b3b54 100644 --- a/liblangutil/Scanner.h +++ b/liblangutil/Scanner.h @@ -69,7 +69,8 @@ class ParserRecorder; enum class ScannerKind { Solidity, - Yul + Yul, + ExperimentalSolidity }; enum class ScannerError diff --git a/liblangutil/Token.h b/liblangutil/Token.h index ef0c7f6af..d79c7f193 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -268,6 +268,8 @@ namespace solidity::langutil /* Yul-specific tokens, but not keywords. */ \ T(Leave, "leave", 0) \ \ + T(NonExperimentalEnd, nullptr, 0) /* used as non-experimental enum end marker */ \ + T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \ /* Illegal token - not able to scan. */ \ T(Illegal, "ILLEGAL", 0) \ \ @@ -323,6 +325,39 @@ namespace TokenTraits tok == Token::TrueLiteral || tok == Token::FalseLiteral || tok == Token::HexStringLiteral || tok == Token::Hex; } + constexpr bool isExperimentalSolidityKeyword(Token token) + { + return + token == Token::Assembly || + token == Token::Contract || + token == Token::External || + token == Token::Fallback || + token == Token::Pragma || + token == Token::Import || + token == Token::As || + token == Token::Function || + token == Token::Let || + token == Token::Return || + token == Token::Type || + token == Token::If || + token == Token::Else || + token == Token::Do || + token == Token::While || + token == Token::For || + token == Token::Continue || + token == Token::Break; + // TODO: see isExperimentalSolidityKeyword below + // || (token > Token::NonExperimentalEnd && token < Token::ExperimentalEnd); + } + + constexpr bool isExperimentalSolidityOnlyKeyword(Token) + { + // TODO: use token > Token::NonExperimentalEnd && token < Token::ExperimentalEnd + // as soon as other experimental tokens are added. For now the comparison generates + // a warning from clang because it is always false. + return false; + } + bool isYulKeyword(std::string const& _literal); Token AssignmentToBinaryOp(Token op); diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 32869ba13..0a8c90f36 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -101,6 +101,8 @@ set(sources codegen/ir/IRLValue.h codegen/ir/IRVariable.cpp codegen/ir/IRVariable.h + experimental/analysis/Analysis.cpp + experimental/analysis/Analysis.h formal/ArraySlicePredicate.cpp formal/ArraySlicePredicate.h formal/BMC.cpp @@ -186,4 +188,3 @@ set(sources add_library(solidity ${sources}) target_link_libraries(solidity PUBLIC yul evmasm langutil smtutil solutil Boost::boost fmt::fmt-header-only Threads::Threads) - diff --git a/libsolidity/experimental/analysis/Analysis.cpp b/libsolidity/experimental/analysis/Analysis.cpp new file mode 100644 index 000000000..672aa4f87 --- /dev/null +++ b/libsolidity/experimental/analysis/Analysis.cpp @@ -0,0 +1,34 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#include + +#include + +using namespace solidity::langutil; +using namespace solidity::frontend::experimental; + +bool Analysis::check(std::vector> const&) +{ + m_errorReporter.error( + 6547_error, + Error::Type::UnimplementedFeatureError, + SourceLocation{}, + "Experimental Analysis is not implemented yet." + ); + return false; +} diff --git a/libsolidity/experimental/analysis/Analysis.h b/libsolidity/experimental/analysis/Analysis.h new file mode 100644 index 000000000..729ff2b93 --- /dev/null +++ b/libsolidity/experimental/analysis/Analysis.h @@ -0,0 +1,49 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#pragma once + +#include +#include + +namespace solidity::frontend +{ +class SourceUnit; +} + +namespace solidity::langutil +{ +class ErrorReporter; +} + +namespace solidity::frontend::experimental +{ + +class Analysis +{ +public: + Analysis(langutil::ErrorReporter& _errorReporter): + m_errorReporter(_errorReporter) + {} + + bool check(std::vector> const& _sourceUnits); + +private: + langutil::ErrorReporter& m_errorReporter; +}; + +} diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index f646ff014..44413afdf 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -56,6 +56,8 @@ #include #include +#include + #include #include @@ -325,6 +327,7 @@ void CompilerStack::reset(bool _keepSettings) m_metadataHash = MetadataHash::IPFS; m_stopAfter = State::CompilationSuccessful; } + m_experimentalAnalysis.reset(); m_globalContext.reset(); m_sourceOrder.clear(); m_contracts.clear(); @@ -449,6 +452,8 @@ bool CompilerStack::analyze() try { + bool experimentalSolidity = !m_sourceOrder.empty() && m_sourceOrder.front()->ast->experimentalSolidity(); + SyntaxChecker syntaxChecker(m_errorReporter, m_optimiserSettings.runYulOptimiser); for (Source const* source: m_sourceOrder) if (source->ast && !syntaxChecker.checkSyntax(*source->ast)) @@ -480,141 +485,13 @@ bool CompilerStack::analyze() if (source->ast && !resolver.resolveNamesAndTypes(*source->ast)) return false; - DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion); - for (Source const* source: m_sourceOrder) - if (source->ast && !declarationTypeChecker.check(*source->ast)) - return false; - - // Requires DeclarationTypeChecker to have run - for (Source const* source: m_sourceOrder) - if (source->ast && !docStringTagParser.validateDocStringsUsingTypes(*source->ast)) - noErrors = false; - - // Next, we check inheritance, overrides, function collisions and other things at - // contract or function level. - // This also calculates whether a contract is abstract, which is needed by the - // type checker. - ContractLevelChecker contractLevelChecker(m_errorReporter); - - for (Source const* source: m_sourceOrder) - if (auto sourceAst = source->ast) - noErrors = contractLevelChecker.check(*sourceAst); - - // Now we run full type checks that go down to the expression level. This - // cannot be done earlier, because we need cross-contract types and information - // about whether a contract is abstract for the `new` expression. - // This populates the `type` annotation for all expressions. - // - // Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed, - // which is only done one step later. - TypeChecker typeChecker(m_evmVersion, m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !typeChecker.checkTypeRequirements(*source->ast)) - noErrors = false; - - if (noErrors) + if (experimentalSolidity) { - // Requires ContractLevelChecker and TypeChecker - DocStringAnalyser docStringAnalyser(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast)) - noErrors = false; - } - - if (noErrors) - { - // Checks that can only be done when all types of all AST nodes are known. - PostTypeChecker postTypeChecker(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !postTypeChecker.check(*source->ast)) - noErrors = false; - if (!postTypeChecker.finalize()) + if (!analyzeExperimental()) noErrors = false; } - - // Create & assign callgraphs and check for contract dependency cycles - if (noErrors) - { - createAndAssignCallGraphs(); - annotateInternalFunctionIDs(); - findAndReportCyclicContractDependencies(); - } - - if (noErrors) - for (Source const* source: m_sourceOrder) - if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast)) - noErrors = false; - - // Check that immutable variables are never read in c'tors and assigned - // exactly once - if (noErrors) - for (Source const* source: m_sourceOrder) - if (source->ast) - for (ASTPointer const& node: source->ast->nodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - ImmutableValidator(m_errorReporter, *contract).analyze(); - - if (noErrors) - { - // Control flow graph generator and analyzer. It can check for issues such as - // variable is used before it is assigned to. - CFG cfg(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !cfg.constructFlow(*source->ast)) - noErrors = false; - - if (noErrors) - { - ControlFlowRevertPruner pruner(cfg); - pruner.run(); - - ControlFlowAnalyzer controlFlowAnalyzer(cfg, m_errorReporter); - if (!controlFlowAnalyzer.run()) - noErrors = false; - } - } - - if (noErrors) - { - // Checks for common mistakes. Only generates warnings. - StaticAnalyzer staticAnalyzer(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !staticAnalyzer.analyze(*source->ast)) - noErrors = false; - } - - if (noErrors) - { - // Check for state mutability in every function. - std::vector> ast; - for (Source const* source: m_sourceOrder) - if (source->ast) - ast.push_back(source->ast); - - if (!ViewPureChecker(ast, m_errorReporter).check()) - noErrors = false; - } - - if (noErrors) - { - // Run SMTChecker - - auto allSources = util::applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }); - if (ModelChecker::isPragmaPresent(allSources)) - m_modelCheckerSettings.engine = ModelCheckerEngine::All(); - - // m_modelCheckerSettings is spread to engines and solver interfaces, - // so we need to check whether the enabled ones are available before building the classes. - if (m_modelCheckerSettings.engine.any()) - m_modelCheckerSettings.solvers = ModelChecker::checkRequestedSolvers(m_modelCheckerSettings.solvers, m_errorReporter); - - ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile); - modelChecker.checkRequestedSourcesAndContracts(allSources); - for (Source const* source: m_sourceOrder) - if (source->ast) - modelChecker.analyze(*source->ast); - m_unhandledSMTLib2Queries += modelChecker.unhandledQueries(); - } + else if (!analyzeLegacy(noErrors)) + noErrors = false; } catch (FatalError const&) { @@ -630,6 +507,162 @@ bool CompilerStack::analyze() return true; } + +bool CompilerStack::analyzeLegacy(bool _noErrorsSoFar) +{ + bool noErrors = _noErrorsSoFar; + + DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion); + for (Source const* source: m_sourceOrder) + if (source->ast && !declarationTypeChecker.check(*source->ast)) + return false; + + // Requires DeclarationTypeChecker to have run + DocStringTagParser docStringTagParser(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !docStringTagParser.validateDocStringsUsingTypes(*source->ast)) + noErrors = false; + + // Next, we check inheritance, overrides, function collisions and other things at + // contract or function level. + // This also calculates whether a contract is abstract, which is needed by the + // type checker. + ContractLevelChecker contractLevelChecker(m_errorReporter); + + for (Source const* source: m_sourceOrder) + if (auto sourceAst = source->ast) + noErrors = contractLevelChecker.check(*sourceAst); + + // Now we run full type checks that go down to the expression level. This + // cannot be done earlier, because we need cross-contract types and information + // about whether a contract is abstract for the `new` expression. + // This populates the `type` annotation for all expressions. + // + // Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed, + // which is only done one step later. + TypeChecker typeChecker(m_evmVersion, m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !typeChecker.checkTypeRequirements(*source->ast)) + noErrors = false; + + if (noErrors) + { + // Requires ContractLevelChecker and TypeChecker + DocStringAnalyser docStringAnalyser(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast)) + noErrors = false; + } + + if (noErrors) + { + // Checks that can only be done when all types of all AST nodes are known. + PostTypeChecker postTypeChecker(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !postTypeChecker.check(*source->ast)) + noErrors = false; + if (!postTypeChecker.finalize()) + noErrors = false; + } + + // Create & assign callgraphs and check for contract dependency cycles + if (noErrors) + { + createAndAssignCallGraphs(); + annotateInternalFunctionIDs(); + findAndReportCyclicContractDependencies(); + } + + if (noErrors) + for (Source const* source: m_sourceOrder) + if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast)) + noErrors = false; + + // Check that immutable variables are never read in c'tors and assigned + // exactly once + if (noErrors) + for (Source const* source: m_sourceOrder) + if (source->ast) + for (ASTPointer const& node: source->ast->nodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + ImmutableValidator(m_errorReporter, *contract).analyze(); + + if (noErrors) + { + // Control flow graph generator and analyzer. It can check for issues such as + // variable is used before it is assigned to. + CFG cfg(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !cfg.constructFlow(*source->ast)) + noErrors = false; + + if (noErrors) + { + ControlFlowRevertPruner pruner(cfg); + pruner.run(); + + ControlFlowAnalyzer controlFlowAnalyzer(cfg, m_errorReporter); + if (!controlFlowAnalyzer.run()) + noErrors = false; + } + } + + if (noErrors) + { + // Checks for common mistakes. Only generates warnings. + StaticAnalyzer staticAnalyzer(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !staticAnalyzer.analyze(*source->ast)) + noErrors = false; + } + + if (noErrors) + { + // Check for state mutability in every function. + std::vector> ast; + for (Source const* source: m_sourceOrder) + if (source->ast) + ast.push_back(source->ast); + + if (!ViewPureChecker(ast, m_errorReporter).check()) + noErrors = false; + } + + if (noErrors) + { + // Run SMTChecker + + auto allSources = util::applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }); + if (ModelChecker::isPragmaPresent(allSources)) + m_modelCheckerSettings.engine = ModelCheckerEngine::All(); + + // m_modelCheckerSettings is spread to engines and solver interfaces, + // so we need to check whether the enabled ones are available before building the classes. + if (m_modelCheckerSettings.engine.any()) + m_modelCheckerSettings.solvers = ModelChecker::checkRequestedSolvers(m_modelCheckerSettings.solvers, m_errorReporter); + + ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile); + modelChecker.checkRequestedSourcesAndContracts(allSources); + for (Source const* source: m_sourceOrder) + if (source->ast) + modelChecker.analyze(*source->ast); + m_unhandledSMTLib2Queries += modelChecker.unhandledQueries(); + } + + return noErrors; +} + +bool CompilerStack::analyzeExperimental() +{ + solAssert(!m_experimentalAnalysis); + m_experimentalAnalysis = std::make_unique(m_errorReporter); + std::vector> sourceAsts; + for (Source const* source: m_sourceOrder) + if (source->ast) + sourceAsts.emplace_back(source->ast); + return m_experimentalAnalysis->check(sourceAsts); +} + bool CompilerStack::parseAndAnalyze(State _stopAfter) { m_stopAfter = _stopAfter; @@ -694,7 +727,11 @@ bool CompilerStack::compile(State _stopAfter) if (m_viaIR) generateEVMFromIR(*contract); else + { + if (m_experimentalAnalysis) + solThrow(CompilerError, "Legacy codegen after experimental analysis is unsupported."); compileContract(*contract, otherCompilers); + } } } catch (Error const& _error) @@ -1429,6 +1466,9 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) { solAssert(m_stackState >= AnalysisSuccessful, ""); + if (m_experimentalAnalysis) + solThrow(CompilerError, "IR codegen after experimental analysis is unsupported."); + Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); if (!compiledContract.yulIR.empty()) return; diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 0227896ae..06c78b686 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -81,6 +81,10 @@ class Compiler; class GlobalContext; class Natspec; class DeclarationContainer; +namespace experimental +{ +class Analysis; +} /** * Easy to use and self-contained Solidity compiler with as few header dependencies as possible. @@ -407,6 +411,14 @@ private: /// @returns true if the contract is requested to be compiled. bool isRequestedContract(ContractDefinition const& _contract) const; + /// Perform the analysis steps of legacy language mode. + /// @returns false on error. + bool analyzeLegacy(bool _noErrorsSoFar); + + /// Perform the analysis steps of experimental language mode. + /// @returns false on error. + bool analyzeExperimental(); + /// Assembles the contract. /// This function should only be internally called by compileContract and generateEVMFromIR. void assembleYul( @@ -500,6 +512,7 @@ private: langutil::ErrorList m_errorList; langutil::ErrorReporter m_errorReporter; + std::unique_ptr m_experimentalAnalysis; bool m_metadataLiteralSources = false; MetadataHash m_metadataHash = MetadataHash::IPFS; langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default(); diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index b31e10572..5d3ec84a4 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -115,8 +115,9 @@ std::unique_ptr Parser::parseInline(std::shared_ptr const& _scan { m_recursionDepth = 0; + auto previousScannerKind = _scanner->scannerKind(); _scanner->setScannerMode(ScannerKind::Yul); - ScopeGuard resetScanner([&]{ _scanner->setScannerMode(ScannerKind::Solidity); }); + ScopeGuard resetScanner([&]{ _scanner->setScannerMode(previousScannerKind); }); try { diff --git a/test/libsolidity/ASTJSON/pragma_experimental_solidity.json b/test/libsolidity/ASTJSON/pragma_experimental_solidity.json deleted file mode 100644 index 66ece94e0..000000000 --- a/test/libsolidity/ASTJSON/pragma_experimental_solidity.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "absolutePath": "a", - "experimentalSolidity": true, - "exportedSymbols": {}, - "id": 2, - "nodeType": "SourceUnit", - "nodes": - [ - { - "id": 1, - "literals": - [ - "experimental", - "solidity" - ], - "nodeType": "PragmaDirective", - "src": "0:29:1" - } - ], - "src": "0:70:1" -} diff --git a/test/libsolidity/ASTJSON/pragma_experimental_solidity.sol b/test/libsolidity/ASTJSON/pragma_experimental_solidity.sol index b902bb061..bb5b771a6 100644 --- a/test/libsolidity/ASTJSON/pragma_experimental_solidity.sol +++ b/test/libsolidity/ASTJSON/pragma_experimental_solidity.sol @@ -2,3 +2,4 @@ pragma experimental solidity; // ==== // EVMVersion: >=constantinople // ---- +// failAfter: Parsed diff --git a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_1.sol b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_1.sol index beec24c1e..7a6f79151 100644 --- a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_1.sol +++ b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_1.sol @@ -6,3 +6,4 @@ import std.stub; // ---- // Warning 2264: (std.stub:63-92): Experimental features are turned on. Do not use experimental features on live deployments. // Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// UnimplementedFeatureError 6547: Experimental Analysis is not implemented yet. diff --git a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_2.sol b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_2.sol index 85d3a4ac7..d6662a14a 100644 --- a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_2.sol +++ b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_2.sol @@ -6,3 +6,4 @@ import std.stub as stub; // ---- // Warning 2264: (std.stub:63-92): Experimental features are turned on. Do not use experimental features on live deployments. // Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// UnimplementedFeatureError 6547: Experimental Analysis is not implemented yet. diff --git a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_3.sol b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_3.sol index 7e51a73b1..c5f6550aa 100644 --- a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_3.sol +++ b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_3.sol @@ -6,3 +6,4 @@ import { identity } from std.stub; // ---- // Warning 2264: (std.stub:63-92): Experimental features are turned on. Do not use experimental features on live deployments. // Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// UnimplementedFeatureError 6547: Experimental Analysis is not implemented yet. diff --git a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_4.sol b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_4.sol index 3c4ff41d6..5aa043746 100644 --- a/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_4.sol +++ b/test/libsolidity/syntaxTests/experimental/parsing_stdlib_import_4.sol @@ -6,3 +6,4 @@ import * as stub from std.stub; // ---- // Warning 2264: (std.stub:63-92): Experimental features are turned on. Do not use experimental features on live deployments. // Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// UnimplementedFeatureError 6547: Experimental Analysis is not implemented yet. diff --git a/test/libsolidity/syntaxTests/pragma/experimental_solidity.sol b/test/libsolidity/syntaxTests/pragma/experimental_solidity.sol index b6f871d87..285c76ed3 100644 --- a/test/libsolidity/syntaxTests/pragma/experimental_solidity.sol +++ b/test/libsolidity/syntaxTests/pragma/experimental_solidity.sol @@ -3,3 +3,4 @@ pragma experimental solidity; // EVMVersion: >=constantinople // ---- // Warning 2264: (0-29): Experimental features are turned on. Do not use experimental features on live deployments. +// UnimplementedFeatureError 6547: Experimental Analysis is not implemented yet.