Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2022-04-13 17:08:27 +02:00
186 changed files with 3081 additions and 976 deletions
@@ -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,
+33 -33
View File
@@ -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())
);
+2 -2
View File
@@ -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)
+2 -1
View File
@@ -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)
+3 -3
View File
@@ -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()
);
+11
View File
@@ -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))
+7 -7
View File
@@ -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);
}
+3 -3
View File
@@ -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() :
+23
View File
@@ -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();
+1
View File
@@ -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);
+12
View File
@@ -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());
+16
View File
@@ -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;
};
/**