mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
@@ -297,7 +297,7 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
||||
else if (optional<ConstantEvaluator::TypedRational> value = ConstantEvaluator::evaluate(m_errorReporter, *length))
|
||||
lengthValue = value->value;
|
||||
|
||||
if (!lengthValue || lengthValue > TypeProvider::uint256()->max())
|
||||
if (!lengthValue)
|
||||
m_errorReporter.typeError(
|
||||
5462_error,
|
||||
length->location(),
|
||||
@@ -309,6 +309,12 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
||||
m_errorReporter.typeError(3208_error, length->location(), "Array with fractional length specified.");
|
||||
else if (*lengthValue < 0)
|
||||
m_errorReporter.typeError(3658_error, length->location(), "Array with negative length specified.");
|
||||
else if (lengthValue > TypeProvider::uint256()->max())
|
||||
m_errorReporter.typeError(
|
||||
1847_error,
|
||||
length->location(),
|
||||
"Array length too large, maximum is 2**256 - 1."
|
||||
);
|
||||
|
||||
_typeName.annotation().type = TypeProvider::array(
|
||||
DataLocation::Storage,
|
||||
|
||||
@@ -1658,24 +1658,21 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
|
||||
|
||||
Type const* subExprType = type(_operation.subExpression());
|
||||
TypeResult result = subExprType->unaryOperatorResult(op);
|
||||
Type const* t = result;
|
||||
if (!result)
|
||||
{
|
||||
string description = "Unary operator " +
|
||||
string(TokenTraits::toString(op)) +
|
||||
" cannot be applied to type " +
|
||||
subExprType->toString() +
|
||||
(result.message().empty() ? "" : (": " + result.message()));
|
||||
|
||||
string description = "Unary operator " + string(TokenTraits::toString(op)) + " cannot be applied to type " + subExprType->toString();
|
||||
if (!result.message().empty())
|
||||
description += ". " + result.message();
|
||||
if (modifying)
|
||||
// Cannot just report the error, ignore the unary operator, and continue,
|
||||
// because the sub-expression was already processed with requireLValue()
|
||||
m_errorReporter.fatalTypeError(9767_error, _operation.location(), description);
|
||||
else
|
||||
m_errorReporter.typeError(4907_error, _operation.location(), description);
|
||||
t = subExprType;
|
||||
_operation.annotation().type = subExprType;
|
||||
}
|
||||
_operation.annotation().type = t;
|
||||
else
|
||||
_operation.annotation().type = result.get();
|
||||
_operation.annotation().isConstant = false;
|
||||
_operation.annotation().isPure = !modifying && *_operation.subExpression().annotation().isPure;
|
||||
_operation.annotation().isLValue = false;
|
||||
@@ -2111,57 +2108,60 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
return;
|
||||
}
|
||||
|
||||
auto const functionPointerType = dynamic_cast<FunctionTypePointer>(type(*arguments.front()));
|
||||
|
||||
if (!functionPointerType)
|
||||
FunctionType const* externalFunctionType = nullptr;
|
||||
if (auto const functionPointerType = dynamic_cast<FunctionTypePointer>(type(*arguments.front())))
|
||||
{
|
||||
// this cannot be a library function, that is checked below
|
||||
externalFunctionType = functionPointerType->asExternallyCallableFunction(false);
|
||||
solAssert(externalFunctionType->kind() == functionPointerType->kind());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
5511_error,
|
||||
arguments.front()->location(),
|
||||
"Expected first argument to be a function pointer, not \"" +
|
||||
type(*arguments.front())->canonicalName() +
|
||||
type(*arguments.front())->toString() +
|
||||
"\"."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
functionPointerType->kind() != FunctionType::Kind::External &&
|
||||
functionPointerType->kind() != FunctionType::Kind::Declaration
|
||||
externalFunctionType->kind() != FunctionType::Kind::External &&
|
||||
externalFunctionType->kind() != FunctionType::Kind::Declaration
|
||||
)
|
||||
{
|
||||
string msg = "Expected regular external function type, or external view on public function.";
|
||||
if (functionPointerType->kind() == FunctionType::Kind::Internal)
|
||||
if (externalFunctionType->kind() == FunctionType::Kind::Internal)
|
||||
msg += " Provided internal function.";
|
||||
else if (functionPointerType->kind() == FunctionType::Kind::DelegateCall)
|
||||
else if (externalFunctionType->kind() == FunctionType::Kind::DelegateCall)
|
||||
msg += " Cannot use library functions for abi.encodeCall.";
|
||||
else if (functionPointerType->kind() == FunctionType::Kind::Creation)
|
||||
else if (externalFunctionType->kind() == FunctionType::Kind::Creation)
|
||||
msg += " Provided creation function.";
|
||||
else
|
||||
msg += " Cannot use special function.";
|
||||
SecondarySourceLocation ssl{};
|
||||
|
||||
if (functionPointerType->hasDeclaration())
|
||||
if (externalFunctionType->hasDeclaration())
|
||||
{
|
||||
ssl.append("Function is declared here:", functionPointerType->declaration().location());
|
||||
ssl.append("Function is declared here:", externalFunctionType->declaration().location());
|
||||
if (
|
||||
functionPointerType->declaration().visibility() == Visibility::Public &&
|
||||
functionPointerType->declaration().scope() == m_currentContract
|
||||
externalFunctionType->declaration().visibility() == Visibility::Public &&
|
||||
externalFunctionType->declaration().scope() == m_currentContract
|
||||
)
|
||||
msg += " Did you forget to prefix \"this.\"?";
|
||||
else if (util::contains(
|
||||
m_currentContract->annotation().linearizedBaseContracts,
|
||||
functionPointerType->declaration().scope()
|
||||
) && functionPointerType->declaration().scope() != m_currentContract)
|
||||
externalFunctionType->declaration().scope()
|
||||
) && externalFunctionType->declaration().scope() != m_currentContract)
|
||||
msg += " Functions from base contracts have to be external.";
|
||||
}
|
||||
|
||||
m_errorReporter.typeError(3509_error, arguments[0]->location(), ssl, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(!functionPointerType->takesArbitraryParameters(), "Function must have fixed parameters.");
|
||||
|
||||
solAssert(!externalFunctionType->takesArbitraryParameters(), "Function must have fixed parameters.");
|
||||
// Tuples with only one component become that component
|
||||
vector<ASTPointer<Expression const>> callArguments;
|
||||
|
||||
@@ -2174,14 +2174,14 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
else
|
||||
callArguments.push_back(arguments[1]);
|
||||
|
||||
if (functionPointerType->parameterTypes().size() != callArguments.size())
|
||||
if (externalFunctionType->parameterTypes().size() != callArguments.size())
|
||||
{
|
||||
if (tupleType)
|
||||
m_errorReporter.typeError(
|
||||
7788_error,
|
||||
_functionCall.location(),
|
||||
"Expected " +
|
||||
to_string(functionPointerType->parameterTypes().size()) +
|
||||
to_string(externalFunctionType->parameterTypes().size()) +
|
||||
" instead of " +
|
||||
to_string(callArguments.size()) +
|
||||
" components for the tuple parameter."
|
||||
@@ -2191,18 +2191,18 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
7515_error,
|
||||
_functionCall.location(),
|
||||
"Expected a tuple with " +
|
||||
to_string(functionPointerType->parameterTypes().size()) +
|
||||
to_string(externalFunctionType->parameterTypes().size()) +
|
||||
" components instead of a single non-tuple parameter."
|
||||
);
|
||||
}
|
||||
|
||||
// Use min() to check as much as we can before failing fatally
|
||||
size_t const numParameters = min(callArguments.size(), functionPointerType->parameterTypes().size());
|
||||
size_t const numParameters = min(callArguments.size(), externalFunctionType->parameterTypes().size());
|
||||
|
||||
for (size_t i = 0; i < numParameters; i++)
|
||||
{
|
||||
Type const& argType = *type(*callArguments[i]);
|
||||
BoolResult result = argType.isImplicitlyConvertibleTo(*functionPointerType->parameterTypes()[i]);
|
||||
BoolResult result = argType.isImplicitlyConvertibleTo(*externalFunctionType->parameterTypes()[i]);
|
||||
if (!result)
|
||||
m_errorReporter.typeError(
|
||||
5407_error,
|
||||
@@ -2212,7 +2212,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
" from \"" +
|
||||
argType.toString() +
|
||||
"\" to \"" +
|
||||
functionPointerType->parameterTypes()[i]->toString() +
|
||||
externalFunctionType->parameterTypes()[i]->toString() +
|
||||
"\"" +
|
||||
(result.message().empty() ? "." : ": " + result.message())
|
||||
);
|
||||
|
||||
@@ -190,9 +190,9 @@ Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<yul::Identifie
|
||||
return tuple;
|
||||
}
|
||||
|
||||
void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node)
|
||||
void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node, util::JsonFormat const& _format)
|
||||
{
|
||||
_stream << util::jsonPrettyPrint(toJson(_node));
|
||||
_stream << util::jsonPrint(toJson(_node), _format);
|
||||
}
|
||||
|
||||
Json::Value ASTJsonConverter::toJson(ASTNode const& _node)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <json/json.h>
|
||||
#include <libsolutil/JSON.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
@@ -58,7 +59,7 @@ public:
|
||||
std::map<std::string, unsigned> _sourceIndices = std::map<std::string, unsigned>()
|
||||
);
|
||||
/// Output the json representation of the AST to _stream.
|
||||
void print(std::ostream& _stream, ASTNode const& _node);
|
||||
void print(std::ostream& _stream, ASTNode const& _node, util::JsonFormat const& _format);
|
||||
Json::Value toJson(ASTNode const& _node);
|
||||
template <class T>
|
||||
Json::Value toJson(std::vector<ASTPointer<T>> const& _nodes)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <libsolidity/codegen/ABIFunctions.h>
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <libyul/YulStack.h>
|
||||
#include <libyul/Utilities.h>
|
||||
|
||||
#include <libsolutil/Algorithms.h>
|
||||
@@ -95,9 +95,9 @@ pair<string, string> IRGenerator::run(
|
||||
{
|
||||
string ir = yul::reindent(generate(_contract, _cborMetadata, _otherYulSources));
|
||||
|
||||
yul::AssemblyStack asmStack(
|
||||
yul::YulStack asmStack(
|
||||
m_evmVersion,
|
||||
yul::AssemblyStack::Language::StrictAssembly,
|
||||
yul::YulStack::Language::StrictAssembly,
|
||||
m_optimiserSettings,
|
||||
m_context.debugInfoSelection()
|
||||
);
|
||||
|
||||
@@ -586,6 +586,16 @@ bool SMTEncoder::visit(FunctionCall const& _funCall)
|
||||
arg->accept(*this);
|
||||
return false;
|
||||
}
|
||||
else if (funType.kind() == FunctionType::Kind::ABIEncodeCall)
|
||||
{
|
||||
auto fun = _funCall.arguments().front();
|
||||
createExpr(*fun);
|
||||
auto const* functionType = dynamic_cast<FunctionType const*>(fun->annotation().type);
|
||||
if (functionType->hasDeclaration())
|
||||
defineExpr(*fun, functionType->externalIdentifier());
|
||||
return true;
|
||||
}
|
||||
|
||||
// We do not really need to visit the expression in a wrap/unwrap no-op call,
|
||||
// so we just ignore the function call expression to avoid "unsupported" warnings.
|
||||
else if (
|
||||
@@ -1323,6 +1333,7 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess)
|
||||
|
||||
auto const& exprType = memberExpr->annotation().type;
|
||||
solAssert(exprType, "");
|
||||
|
||||
if (exprType->category() == Type::Category::Magic)
|
||||
{
|
||||
if (auto const* identifier = dynamic_cast<Identifier const*>(memberExpr))
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
#include <libyul/YulString.h>
|
||||
#include <libyul/AsmPrinter.h>
|
||||
#include <libyul/AsmJsonConverter.h>
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <libyul/YulStack.h>
|
||||
#include <libyul/AST.h>
|
||||
#include <libyul/AsmParser.h>
|
||||
|
||||
@@ -1382,9 +1382,9 @@ void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract)
|
||||
return;
|
||||
|
||||
// Re-parse the Yul IR in EVM dialect
|
||||
yul::AssemblyStack stack(
|
||||
yul::YulStack stack(
|
||||
m_evmVersion,
|
||||
yul::AssemblyStack::Language::StrictAssembly,
|
||||
yul::YulStack::Language::StrictAssembly,
|
||||
m_optimiserSettings,
|
||||
m_debugInfoSelection
|
||||
);
|
||||
@@ -1414,22 +1414,22 @@ void CompilerStack::generateEwasm(ContractDefinition const& _contract)
|
||||
return;
|
||||
|
||||
// Re-parse the Yul IR in EVM dialect
|
||||
yul::AssemblyStack stack(
|
||||
yul::YulStack stack(
|
||||
m_evmVersion,
|
||||
yul::AssemblyStack::Language::StrictAssembly,
|
||||
yul::YulStack::Language::StrictAssembly,
|
||||
m_optimiserSettings,
|
||||
m_debugInfoSelection
|
||||
);
|
||||
stack.parseAndAnalyze("", compiledContract.yulIROptimized);
|
||||
|
||||
stack.optimize();
|
||||
stack.translate(yul::AssemblyStack::Language::Ewasm);
|
||||
stack.translate(yul::YulStack::Language::Ewasm);
|
||||
stack.optimize();
|
||||
|
||||
//cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
|
||||
|
||||
// Turn into Ewasm text representation.
|
||||
auto result = stack.assemble(yul::AssemblyStack::Machine::Ewasm);
|
||||
auto result = stack.assemble(yul::YulStack::Machine::Ewasm);
|
||||
compiledContract.ewasm = std::move(result.assembly);
|
||||
compiledContract.ewasmObject = std::move(*result.bytecode);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
|
||||
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <libyul/YulStack.h>
|
||||
#include <libyul/Exceptions.h>
|
||||
#include <libyul/optimiser/Suite.h>
|
||||
|
||||
@@ -1407,9 +1407,9 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
|
||||
return output;
|
||||
}
|
||||
|
||||
AssemblyStack stack(
|
||||
YulStack stack(
|
||||
_inputsAndSettings.evmVersion,
|
||||
AssemblyStack::Language::StrictAssembly,
|
||||
YulStack::Language::StrictAssembly,
|
||||
_inputsAndSettings.optimiserSettings,
|
||||
_inputsAndSettings.debugInfoSelection.has_value() ?
|
||||
_inputsAndSettings.debugInfoSelection.value() :
|
||||
|
||||
@@ -76,6 +76,7 @@ LanguageServer::LanguageServer(Transport& _transport):
|
||||
{"exit", [this](auto, auto) { m_state = (m_state == State::ShutdownRequested ? State::ExitRequested : State::ExitWithoutShutdown); }},
|
||||
{"initialize", bind(&LanguageServer::handleInitialize, this, _1, _2)},
|
||||
{"initialized", [](auto, auto) {}},
|
||||
{"$/setTrace", bind(&LanguageServer::setTrace, this, _2)},
|
||||
{"shutdown", [this](auto, auto) { m_state = State::ShutdownRequested; }},
|
||||
{"textDocument/definition", GotoDefinition(*this) },
|
||||
{"textDocument/didOpen", bind(&LanguageServer::handleTextDocumentDidOpen, this, _2)},
|
||||
@@ -166,6 +167,13 @@ void LanguageServer::compileAndUpdateDiagnostics()
|
||||
diagnosticsBySourceUnit[*location->sourceName].append(jsonDiag);
|
||||
}
|
||||
|
||||
if (m_client.traceValue() != TraceValue::Off)
|
||||
{
|
||||
Json::Value extra;
|
||||
extra["openFileCount"] = Json::UInt64(diagnosticsBySourceUnit.size());
|
||||
m_client.trace("Number of currently open files: " + to_string(diagnosticsBySourceUnit.size()), extra);
|
||||
}
|
||||
|
||||
m_nonemptyDiagnostics.clear();
|
||||
for (auto&& [sourceUnitName, diagnostics]: diagnosticsBySourceUnit)
|
||||
{
|
||||
@@ -273,6 +281,21 @@ void LanguageServer::handleWorkspaceDidChangeConfiguration(Json::Value const& _a
|
||||
changeConfiguration(_args["settings"]);
|
||||
}
|
||||
|
||||
void LanguageServer::setTrace(Json::Value const& _args)
|
||||
{
|
||||
if (!_args["value"].isString())
|
||||
// Simply ignore invalid parameter.
|
||||
return;
|
||||
|
||||
string const stringValue = _args["value"].asString();
|
||||
if (stringValue == "off")
|
||||
m_client.setTrace(TraceValue::Off);
|
||||
else if (stringValue == "messages")
|
||||
m_client.setTrace(TraceValue::Messages);
|
||||
else if (stringValue == "verbose")
|
||||
m_client.setTrace(TraceValue::Verbose);
|
||||
}
|
||||
|
||||
void LanguageServer::handleTextDocumentDidOpen(Json::Value const& _args)
|
||||
{
|
||||
requireServerInitialized();
|
||||
|
||||
@@ -68,6 +68,7 @@ private:
|
||||
void requireServerInitialized();
|
||||
void handleInitialize(MessageID _id, Json::Value const& _args);
|
||||
void handleWorkspaceDidChangeConfiguration(Json::Value const& _args);
|
||||
void setTrace(Json::Value const& _args);
|
||||
void handleTextDocumentDidOpen(Json::Value const& _args);
|
||||
void handleTextDocumentDidChange(Json::Value const& _args);
|
||||
void handleTextDocumentDidClose(Json::Value const& _args);
|
||||
|
||||
@@ -98,6 +98,18 @@ void IOStreamTransport::error(MessageID _id, ErrorCode _code, string _message)
|
||||
send(move(json), _id);
|
||||
}
|
||||
|
||||
void Transport::trace(std::string _message, Json::Value _extra)
|
||||
{
|
||||
if (m_logTrace != TraceValue::Off)
|
||||
{
|
||||
Json::Value params;
|
||||
if (_extra.isObject())
|
||||
params = move(_extra);
|
||||
params["message"] = move(_message);
|
||||
notify("$/logTrace", move(params));
|
||||
}
|
||||
}
|
||||
|
||||
void IOStreamTransport::send(Json::Value _json, MessageID _id)
|
||||
{
|
||||
solAssert(_json.isObject());
|
||||
|
||||
@@ -34,6 +34,13 @@ namespace solidity::lsp
|
||||
|
||||
using MessageID = Json::Value;
|
||||
|
||||
enum class TraceValue
|
||||
{
|
||||
Off,
|
||||
Messages,
|
||||
Verbose
|
||||
};
|
||||
|
||||
enum class ErrorCode
|
||||
{
|
||||
// Defined by JSON RPC
|
||||
@@ -89,6 +96,15 @@ public:
|
||||
virtual void notify(std::string _method, Json::Value _params) = 0;
|
||||
virtual void reply(MessageID _id, Json::Value _result) = 0;
|
||||
virtual void error(MessageID _id, ErrorCode _code, std::string _message) = 0;
|
||||
|
||||
void trace(std::string _message, Json::Value _extra = Json::nullValue);
|
||||
|
||||
TraceValue traceValue() const noexcept { return m_logTrace; }
|
||||
void setTrace(TraceValue _value) noexcept { m_logTrace = _value; }
|
||||
|
||||
|
||||
private:
|
||||
TraceValue m_logTrace = TraceValue::Off;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user