1 /*
2 	This file is part of solidity.
3 
4 	solidity is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU General Public License as published by
6 	the Free Software Foundation, either version 3 of the License, or
7 	(at your option) any later version.
8 
9 	solidity is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18 /**
19  * Component that translates Solidity code into Yul at statement level and below.
20  */
21 
22 #include <libsolidity/codegen/ir/IRGeneratorForStatements.h>
23 
24 #include <libsolidity/codegen/ABIFunctions.h>
25 #include <libsolidity/codegen/ir/IRGenerationContext.h>
26 #include <libsolidity/codegen/ir/IRLValue.h>
27 #include <libsolidity/codegen/ir/IRVariable.h>
28 #include <libsolidity/codegen/YulUtilFunctions.h>
29 #include <libsolidity/codegen/ABIFunctions.h>
30 #include <libsolidity/codegen/CompilerUtils.h>
31 #include <libsolidity/codegen/ReturnInfo.h>
32 #include <libsolidity/ast/TypeProvider.h>
33 #include <libsolidity/ast/ASTUtils.h>
34 
35 #include <libevmasm/GasMeter.h>
36 
37 #include <libyul/AsmPrinter.h>
38 #include <libyul/AST.h>
39 #include <libyul/Dialect.h>
40 #include <libyul/optimiser/ASTCopier.h>
41 
42 #include <liblangutil/Exceptions.h>
43 
44 #include <libsolutil/Whiskers.h>
45 #include <libsolutil/StringUtils.h>
46 #include <libsolutil/Keccak256.h>
47 #include <libsolutil/FunctionSelector.h>
48 #include <libsolutil/Visitor.h>
49 
50 #include <range/v3/view/transform.hpp>
51 
52 using namespace std;
53 using namespace solidity;
54 using namespace solidity::util;
55 using namespace solidity::frontend;
56 using namespace std::string_literals;
57 
58 namespace
59 {
60 
61 struct CopyTranslate: public yul::ASTCopier
62 {
63 	using ExternalRefsMap = std::map<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo>;
64 
CopyTranslate__anon44c09ec70111::CopyTranslate65 	CopyTranslate(yul::Dialect const& _dialect, IRGenerationContext& _context, ExternalRefsMap const& _references):
66 		m_dialect(_dialect), m_context(_context), m_references(_references) {}
67 
68 	using ASTCopier::operator();
69 
operator ()__anon44c09ec70111::CopyTranslate70 	yul::Expression operator()(yul::Identifier const& _identifier) override
71 	{
72 		// The operator() function is only called in lvalue context. In rvalue context,
73 		// only translate(yul::Identifier) is called.
74 		if (m_references.count(&_identifier))
75 			return translateReference(_identifier);
76 		else
77 			return ASTCopier::operator()(_identifier);
78 	}
79 
translateIdentifier__anon44c09ec70111::CopyTranslate80 	yul::YulString translateIdentifier(yul::YulString _name) override
81 	{
82 		// Strictly, the dialect used by inline assembly (m_dialect) could be different
83 		// from the Yul dialect we are compiling to. So we are assuming here that the builtin
84 		// functions are identical. This should not be a problem for now since everything
85 		// is EVM anyway.
86 		if (m_dialect.builtin(_name))
87 			return _name;
88 		else
89 			return yul::YulString{"usr$" + _name.str()};
90 	}
91 
translate__anon44c09ec70111::CopyTranslate92 	yul::Identifier translate(yul::Identifier const& _identifier) override
93 	{
94 		if (!m_references.count(&_identifier))
95 			return ASTCopier::translate(_identifier);
96 
97 		yul::Expression translated = translateReference(_identifier);
98 		solAssert(holds_alternative<yul::Identifier>(translated), "");
99 		return get<yul::Identifier>(std::move(translated));
100 	}
101 
102 private:
103 
104 	/// Translates a reference to a local variable, potentially including
105 	/// a suffix. Might return a literal, which causes this to be invalid in
106 	/// lvalue-context.
translateReference__anon44c09ec70111::CopyTranslate107 	yul::Expression translateReference(yul::Identifier const& _identifier)
108 	{
109 		auto const& reference = m_references.at(&_identifier);
110 		auto const varDecl = dynamic_cast<VariableDeclaration const*>(reference.declaration);
111 		solUnimplementedAssert(varDecl);
112 		string const& suffix = reference.suffix;
113 
114 		string value;
115 		if (suffix.empty() && varDecl->isLocalVariable())
116 		{
117 			auto const& var = m_context.localVariable(*varDecl);
118 			solAssert(var.type().sizeOnStack() == 1, "");
119 
120 			value = var.commaSeparatedList();
121 		}
122 		else if (varDecl->isConstant())
123 		{
124 			VariableDeclaration const* variable = rootConstVariableDeclaration(*varDecl);
125 			solAssert(variable, "");
126 
127 			if (variable->value()->annotation().type->category() == Type::Category::RationalNumber)
128 			{
129 				u256 intValue = dynamic_cast<RationalNumberType const&>(*variable->value()->annotation().type).literalValue(nullptr);
130 				if (auto const* bytesType = dynamic_cast<FixedBytesType const*>(variable->type()))
131 					intValue <<= 256 - 8 * bytesType->numBytes();
132 				else
133 					solAssert(variable->type()->category() == Type::Category::Integer, "");
134 				value = intValue.str();
135 			}
136 			else if (auto const* literal = dynamic_cast<Literal const*>(variable->value().get()))
137 			{
138 				Type const* type = literal->annotation().type;
139 
140 				switch (type->category())
141 				{
142 				case Type::Category::Bool:
143 				case Type::Category::Address:
144 					solAssert(type->category() == variable->annotation().type->category(), "");
145 					value = toCompactHexWithPrefix(type->literalValue(literal));
146 					break;
147 				case Type::Category::StringLiteral:
148 				{
149 					auto const& stringLiteral = dynamic_cast<StringLiteralType const&>(*type);
150 					solAssert(variable->type()->category() == Type::Category::FixedBytes, "");
151 					unsigned const numBytes = dynamic_cast<FixedBytesType const&>(*variable->type()).numBytes();
152 					solAssert(stringLiteral.value().size() <= numBytes, "");
153 					value = formatNumber(u256(h256(stringLiteral.value(), h256::AlignLeft)));
154 					break;
155 				}
156 				default:
157 					solAssert(false, "");
158 				}
159 			}
160 			else
161 				solAssert(false, "Invalid constant in inline assembly.");
162 		}
163 		else if (varDecl->isStateVariable())
164 		{
165 			if (suffix == "slot")
166 				value = m_context.storageLocationOfStateVariable(*varDecl).first.str();
167 			else if (suffix == "offset")
168 				value = to_string(m_context.storageLocationOfStateVariable(*varDecl).second);
169 			else
170 				solAssert(false, "");
171 		}
172 		else if (varDecl->type()->dataStoredIn(DataLocation::Storage))
173 		{
174 			solAssert(suffix == "slot" || suffix == "offset", "");
175 			solAssert(varDecl->isLocalVariable(), "");
176 			if (suffix == "slot")
177 				value = IRVariable{*varDecl}.part("slot").name();
178 			else if (varDecl->type()->isValueType())
179 				value = IRVariable{*varDecl}.part("offset").name();
180 			else
181 			{
182 				solAssert(!IRVariable{*varDecl}.hasPart("offset"), "");
183 				value = "0";
184 			}
185 		}
186 		else if (varDecl->type()->dataStoredIn(DataLocation::CallData))
187 		{
188 			solAssert(suffix == "offset" || suffix == "length", "");
189 			value = IRVariable{*varDecl}.part(suffix).name();
190 		}
191 		else if (
192 			auto const* functionType = dynamic_cast<FunctionType const*>(varDecl->type());
193 			functionType && functionType->kind() == FunctionType::Kind::External
194 		)
195 		{
196 			solAssert(suffix == "selector" || suffix == "address", "");
197 			solAssert(varDecl->type()->sizeOnStack() == 2, "");
198 			if (suffix == "selector")
199 				value = IRVariable{*varDecl}.part("functionSelector").name();
200 			else
201 				value = IRVariable{*varDecl}.part("address").name();
202 		}
203 		else
204 			solAssert(false, "");
205 
206 		if (isdigit(value.front()))
207 			return yul::Literal{_identifier.debugData, yul::LiteralKind::Number, yul::YulString{value}, {}};
208 		else
209 			return yul::Identifier{_identifier.debugData, yul::YulString{value}};
210 	}
211 
212 
213 	yul::Dialect const& m_dialect;
214 	IRGenerationContext& m_context;
215 	ExternalRefsMap const& m_references;
216 };
217 
218 }
219 
code() const220 string IRGeneratorForStatementsBase::code() const
221 {
222 	return m_code.str();
223 }
224 
appendCode(bool _addLocationComment)225 std::ostringstream& IRGeneratorForStatementsBase::appendCode(bool _addLocationComment)
226 {
227 	if (
228 		_addLocationComment &&
229 		m_currentLocation.isValid() &&
230 		m_lastLocation != m_currentLocation
231 	)
232 		m_code << dispenseLocationComment(m_currentLocation, m_context) << "\n";
233 
234 	m_lastLocation = m_currentLocation;
235 
236 	return m_code;
237 }
238 
setLocation(ASTNode const & _node)239 void IRGeneratorForStatementsBase::setLocation(ASTNode const& _node)
240 {
241 	m_currentLocation = _node.location();
242 }
243 
code() const244 string IRGeneratorForStatements::code() const
245 {
246 	solAssert(!m_currentLValue, "LValue not reset!");
247 	return IRGeneratorForStatementsBase::code();
248 }
249 
generate(Block const & _block)250 void IRGeneratorForStatements::generate(Block const& _block)
251 {
252 	try
253 	{
254 		_block.accept(*this);
255 	}
256 	catch (langutil::UnimplementedFeatureError const& _error)
257 	{
258 		if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
259 			_error << langutil::errinfo_sourceLocation(m_currentLocation);
260 		BOOST_THROW_EXCEPTION(_error);
261 	}
262 }
263 
initializeStateVar(VariableDeclaration const & _varDecl)264 void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _varDecl)
265 {
266 	try
267 	{
268 		setLocation(_varDecl);
269 
270 		solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable.");
271 		solAssert(!_varDecl.isConstant(), "");
272 		if (!_varDecl.value())
273 			return;
274 
275 		_varDecl.value()->accept(*this);
276 
277 		writeToLValue(
278 			_varDecl.immutable() ?
279 			IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} :
280 			IRLValue{*_varDecl.annotation().type, IRLValue::Storage{
281 				toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_varDecl).first),
282 				m_context.storageLocationOfStateVariable(_varDecl).second
283 			}},
284 			*_varDecl.value()
285 		);
286 	}
287 	catch (langutil::UnimplementedFeatureError const& _error)
288 	{
289 		if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
290 			_error << langutil::errinfo_sourceLocation(m_currentLocation);
291 		BOOST_THROW_EXCEPTION(_error);
292 	}
293 }
294 
initializeLocalVar(VariableDeclaration const & _varDecl)295 void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl)
296 {
297 	try
298 	{
299 		setLocation(_varDecl);
300 
301 		solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable.");
302 
303 		auto const* type = _varDecl.type();
304 		if (dynamic_cast<MappingType const*>(type))
305 			return;
306 		else if (auto const* refType = dynamic_cast<ReferenceType const*>(type))
307 			if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer())
308 				return;
309 
310 		IRVariable zero = zeroValue(*type);
311 		assign(m_context.localVariable(_varDecl), zero);
312 	}
313 	catch (langutil::UnimplementedFeatureError const& _error)
314 	{
315 		if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
316 			_error << langutil::errinfo_sourceLocation(m_currentLocation);
317 		BOOST_THROW_EXCEPTION(_error);
318 	}
319 }
320 
evaluateExpression(Expression const & _expression,Type const & _targetType)321 IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expression, Type const& _targetType)
322 {
323 	try
324 	{
325 		setLocation(_expression);
326 
327 		_expression.accept(*this);
328 
329 		setLocation(_expression);
330 		IRVariable variable{m_context.newYulVariable(), _targetType};
331 		define(variable, _expression);
332 		return variable;
333 	}
334 	catch (langutil::UnimplementedFeatureError const& _error)
335 	{
336 		if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
337 			_error << langutil::errinfo_sourceLocation(m_currentLocation);
338 		BOOST_THROW_EXCEPTION(_error);
339 	}
340 }
341 
constantValueFunction(VariableDeclaration const & _constant)342 string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant)
343 {
344 	try
345 	{
346 		string functionName = IRNames::constantValueFunction(_constant);
347 		return m_context.functionCollector().createFunction(functionName, [&] {
348 			Whiskers templ(R"(
349 				<sourceLocationComment>
350 				function <functionName>() -> <ret> {
351 					<code>
352 					<ret> := <value>
353 				}
354 			)");
355 			templ("sourceLocationComment", dispenseLocationComment(_constant, m_context));
356 			templ("functionName", functionName);
357 			IRGeneratorForStatements generator(m_context, m_utils);
358 			solAssert(_constant.value(), "");
359 			Type const& constantType = *_constant.type();
360 			templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList());
361 			templ("code", generator.code());
362 			templ("ret", IRVariable("ret", constantType).commaSeparatedList());
363 
364 			return templ.render();
365 		});
366 	}
367 	catch (langutil::UnimplementedFeatureError const& _error)
368 	{
369 		if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
370 			_error << langutil::errinfo_sourceLocation(m_currentLocation);
371 		BOOST_THROW_EXCEPTION(_error);
372 	}
373 }
374 
endVisit(VariableDeclarationStatement const & _varDeclStatement)375 void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
376 {
377 	setLocation(_varDeclStatement);
378 
379 	if (Expression const* expression = _varDeclStatement.initialValue())
380 	{
381 		if (_varDeclStatement.declarations().size() > 1)
382 		{
383 			auto const* tupleType = dynamic_cast<TupleType const*>(expression->annotation().type);
384 			solAssert(tupleType, "Expected expression of tuple type.");
385 			solAssert(_varDeclStatement.declarations().size() == tupleType->components().size(), "Invalid number of tuple components.");
386 			for (size_t i = 0; i < _varDeclStatement.declarations().size(); ++i)
387 				if (auto const& decl = _varDeclStatement.declarations()[i])
388 				{
389 					solAssert(tupleType->components()[i], "");
390 					define(m_context.addLocalVariable(*decl), IRVariable(*expression).tupleComponent(i));
391 				}
392 		}
393 		else
394 		{
395 			VariableDeclaration const& varDecl = *_varDeclStatement.declarations().front();
396 			define(m_context.addLocalVariable(varDecl), *expression);
397 		}
398 	}
399 	else
400 		for (auto const& decl: _varDeclStatement.declarations())
401 			if (decl)
402 			{
403 				declare(m_context.addLocalVariable(*decl));
404 				initializeLocalVar(*decl);
405 			}
406 }
407 
visit(Conditional const & _conditional)408 bool IRGeneratorForStatements::visit(Conditional const& _conditional)
409 {
410 	_conditional.condition().accept(*this);
411 
412 	setLocation(_conditional);
413 
414 	string condition = expressionAsType(_conditional.condition(), *TypeProvider::boolean());
415 	declare(_conditional);
416 
417 	appendCode() << "switch " << condition << "\n" "case 0 {\n";
418 
419 	_conditional.falseExpression().accept(*this);
420 	setLocation(_conditional);
421 
422 	assign(_conditional, _conditional.falseExpression());
423 	appendCode() << "}\n" "default {\n";
424 
425 	_conditional.trueExpression().accept(*this);
426 	setLocation(_conditional);
427 
428 	assign(_conditional, _conditional.trueExpression());
429 	appendCode() << "}\n";
430 
431 	return false;
432 }
433 
visit(Assignment const & _assignment)434 bool IRGeneratorForStatements::visit(Assignment const& _assignment)
435 {
436 	_assignment.rightHandSide().accept(*this);
437 	setLocation(_assignment);
438 
439 	Token assignmentOperator = _assignment.assignmentOperator();
440 	Token binaryOperator =
441 		assignmentOperator == Token::Assign ?
442 		assignmentOperator :
443 		TokenTraits::AssignmentToBinaryOp(assignmentOperator);
444 
445 	if (TokenTraits::isShiftOp(binaryOperator))
446 		solAssert(type(_assignment.rightHandSide()).mobileType(), "");
447 	IRVariable value =
448 		type(_assignment.leftHandSide()).isValueType() ?
449 		convert(
450 			_assignment.rightHandSide(),
451 			TokenTraits::isShiftOp(binaryOperator) ? *type(_assignment.rightHandSide()).mobileType() : type(_assignment)
452 		) :
453 		_assignment.rightHandSide();
454 
455 	_assignment.leftHandSide().accept(*this);
456 
457 	solAssert(!!m_currentLValue, "LValue not retrieved.");
458 	setLocation(_assignment);
459 
460 	if (assignmentOperator != Token::Assign)
461 	{
462 		solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types.");
463 		solAssert(binaryOperator != Token::Exp, "");
464 		solAssert(type(_assignment) == type(_assignment.leftHandSide()), "");
465 
466 		IRVariable leftIntermediate = readFromLValue(*m_currentLValue);
467 		solAssert(type(_assignment) == leftIntermediate.type(), "");
468 
469 		define(_assignment) << (
470 			TokenTraits::isShiftOp(binaryOperator) ?
471 			shiftOperation(binaryOperator, leftIntermediate, value) :
472 			binaryOperation(binaryOperator, type(_assignment), leftIntermediate.name(), value.name())
473 		) << "\n";
474 
475 		writeToLValue(*m_currentLValue, IRVariable(_assignment));
476 	}
477 	else
478 	{
479 		writeToLValue(*m_currentLValue, value);
480 
481 		if (dynamic_cast<ReferenceType const*>(&m_currentLValue->type))
482 			define(_assignment, readFromLValue(*m_currentLValue));
483 		else if (*_assignment.annotation().type != *TypeProvider::emptyTuple())
484 			define(_assignment, value);
485 	}
486 
487 	m_currentLValue.reset();
488 	return false;
489 }
490 
visit(TupleExpression const & _tuple)491 bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
492 {
493 	setLocation(_tuple);
494 
495 	if (_tuple.isInlineArray())
496 	{
497 		auto const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);
498 		solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
499 		define(_tuple) <<
500 			m_utils.allocateMemoryArrayFunction(arrayType) <<
501 			"(" <<
502 			_tuple.components().size() <<
503 			")\n";
504 
505 		string mpos = IRVariable(_tuple).part("mpos").name();
506 		Type const& baseType = *arrayType.baseType();
507 		for (size_t i = 0; i < _tuple.components().size(); i++)
508 		{
509 			Expression const& component = *_tuple.components()[i];
510 			component.accept(*this);
511 			setLocation(_tuple);
512 			IRVariable converted = convert(component, baseType);
513 			appendCode() <<
514 				m_utils.writeToMemoryFunction(baseType) <<
515 				"(" <<
516 				("add(" + mpos + ", " + to_string(i * arrayType.memoryStride()) + ")") <<
517 				", " <<
518 				converted.commaSeparatedList() <<
519 				")\n";
520 		}
521 	}
522 	else
523 	{
524 		bool willBeWrittenTo = _tuple.annotation().willBeWrittenTo;
525 		if (willBeWrittenTo)
526 			solAssert(!m_currentLValue, "");
527 		if (_tuple.components().size() == 1)
528 		{
529 			solAssert(_tuple.components().front(), "");
530 			_tuple.components().front()->accept(*this);
531 			setLocation(_tuple);
532 			if (willBeWrittenTo)
533 				solAssert(!!m_currentLValue, "");
534 			else
535 				define(_tuple, *_tuple.components().front());
536 		}
537 		else
538 		{
539 			vector<optional<IRLValue>> lvalues;
540 			for (size_t i = 0; i < _tuple.components().size(); ++i)
541 				if (auto const& component = _tuple.components()[i])
542 				{
543 					component->accept(*this);
544 					setLocation(_tuple);
545 					if (willBeWrittenTo)
546 					{
547 						solAssert(!!m_currentLValue, "");
548 						lvalues.emplace_back(std::move(m_currentLValue));
549 						m_currentLValue.reset();
550 					}
551 					else
552 						define(IRVariable(_tuple).tupleComponent(i), *component);
553 				}
554 				else if (willBeWrittenTo)
555 					lvalues.emplace_back();
556 
557 			if (_tuple.annotation().willBeWrittenTo)
558 				m_currentLValue.emplace(IRLValue{
559 					*_tuple.annotation().type,
560 					IRLValue::Tuple{std::move(lvalues)}
561 				});
562 		}
563 	}
564 	return false;
565 }
566 
visit(Block const & _block)567 bool IRGeneratorForStatements::visit(Block const& _block)
568 {
569 	if (_block.unchecked())
570 	{
571 		solAssert(m_context.arithmetic() == Arithmetic::Checked, "");
572 		m_context.setArithmetic(Arithmetic::Wrapping);
573 	}
574 	return true;
575 }
576 
endVisit(Block const & _block)577 void IRGeneratorForStatements::endVisit(Block const& _block)
578 {
579 	if (_block.unchecked())
580 	{
581 		solAssert(m_context.arithmetic() == Arithmetic::Wrapping, "");
582 		m_context.setArithmetic(Arithmetic::Checked);
583 	}
584 }
585 
visit(IfStatement const & _ifStatement)586 bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
587 {
588 	_ifStatement.condition().accept(*this);
589 	setLocation(_ifStatement);
590 	string condition = expressionAsType(_ifStatement.condition(), *TypeProvider::boolean());
591 
592 	if (_ifStatement.falseStatement())
593 	{
594 		appendCode() << "switch " << condition << "\n" "case 0 {\n";
595 		_ifStatement.falseStatement()->accept(*this);
596 		setLocation(_ifStatement);
597 		appendCode() << "}\n" "default {\n";
598 	}
599 	else
600 		appendCode() << "if " << condition << " {\n";
601 	_ifStatement.trueStatement().accept(*this);
602 	setLocation(_ifStatement);
603 	appendCode() << "}\n";
604 
605 	return false;
606 }
607 
endVisit(PlaceholderStatement const & _placeholder)608 void IRGeneratorForStatements::endVisit(PlaceholderStatement const& _placeholder)
609 {
610 	solAssert(m_placeholderCallback, "");
611 	setLocation(_placeholder);
612 	appendCode() << m_placeholderCallback();
613 }
614 
visit(ForStatement const & _forStatement)615 bool IRGeneratorForStatements::visit(ForStatement const& _forStatement)
616 {
617 	setLocation(_forStatement);
618 	generateLoop(
619 		_forStatement.body(),
620 		_forStatement.condition(),
621 		_forStatement.initializationExpression(),
622 		_forStatement.loopExpression()
623 	);
624 
625 	return false;
626 }
627 
visit(WhileStatement const & _whileStatement)628 bool IRGeneratorForStatements::visit(WhileStatement const& _whileStatement)
629 {
630 	setLocation(_whileStatement);
631 	generateLoop(
632 		_whileStatement.body(),
633 		&_whileStatement.condition(),
634 		nullptr,
635 		nullptr,
636 		_whileStatement.isDoWhile()
637 	);
638 
639 	return false;
640 }
641 
visit(Continue const & _continue)642 bool IRGeneratorForStatements::visit(Continue const& _continue)
643 {
644 	setLocation(_continue);
645 	appendCode() << "continue\n";
646 	return false;
647 }
648 
visit(Break const & _break)649 bool IRGeneratorForStatements::visit(Break const& _break)
650 {
651 	setLocation(_break);
652 	appendCode() << "break\n";
653 	return false;
654 }
655 
endVisit(Return const & _return)656 void IRGeneratorForStatements::endVisit(Return const& _return)
657 {
658 	setLocation(_return);
659 	if (Expression const* value = _return.expression())
660 	{
661 		solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer.");
662 		vector<ASTPointer<VariableDeclaration>> const& returnParameters =
663 			_return.annotation().functionReturnParameters->parameters();
664 		if (returnParameters.size() > 1)
665 			for (size_t i = 0; i < returnParameters.size(); ++i)
666 				assign(m_context.localVariable(*returnParameters[i]), IRVariable(*value).tupleComponent(i));
667 		else if (returnParameters.size() == 1)
668 			assign(m_context.localVariable(*returnParameters.front()), *value);
669 	}
670 	appendCode() << "leave\n";
671 }
672 
visit(UnaryOperation const & _unaryOperation)673 bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation)
674 {
675 	setLocation(_unaryOperation);
676 	Type const& resultType = type(_unaryOperation);
677 	Token const op = _unaryOperation.getOperator();
678 
679 	if (resultType.category() == Type::Category::RationalNumber)
680 	{
681 		define(_unaryOperation) << formatNumber(resultType.literalValue(nullptr)) << "\n";
682 		return false;
683 	}
684 
685 	_unaryOperation.subExpression().accept(*this);
686 	setLocation(_unaryOperation);
687 
688 	if (op == Token::Delete)
689 	{
690 		solAssert(!!m_currentLValue, "LValue not retrieved.");
691 		std::visit(
692 			util::GenericVisitor{
693 				[&](IRLValue::Storage const& _storage) {
694 					appendCode() <<
695 						m_utils.storageSetToZeroFunction(m_currentLValue->type) <<
696 						"(" <<
697 						_storage.slot <<
698 						", " <<
699 						_storage.offsetString() <<
700 						")\n";
701 					m_currentLValue.reset();
702 				},
703 				[&](auto const&) {
704 					IRVariable zeroValue(m_context.newYulVariable(), m_currentLValue->type);
705 					define(zeroValue) << m_utils.zeroValueFunction(m_currentLValue->type) << "()\n";
706 					writeToLValue(*m_currentLValue, zeroValue);
707 					m_currentLValue.reset();
708 				}
709 			},
710 			m_currentLValue->kind
711 		);
712 	}
713 	else if (resultType.category() == Type::Category::Integer)
714 	{
715 		solAssert(resultType == type(_unaryOperation.subExpression()), "Result type doesn't match!");
716 
717 		if (op == Token::Inc || op == Token::Dec)
718 		{
719 			solAssert(!!m_currentLValue, "LValue not retrieved.");
720 			IRVariable modifiedValue(m_context.newYulVariable(), resultType);
721 			IRVariable originalValue = readFromLValue(*m_currentLValue);
722 
723 			bool checked = m_context.arithmetic() == Arithmetic::Checked;
724 			define(modifiedValue) <<
725 				(op == Token::Inc ?
726 					(checked ? m_utils.incrementCheckedFunction(resultType) : m_utils.incrementWrappingFunction(resultType)) :
727 					(checked ? m_utils.decrementCheckedFunction(resultType) : m_utils.decrementWrappingFunction(resultType))
728 				) <<
729 				"(" <<
730 				originalValue.name() <<
731 				")\n";
732 			writeToLValue(*m_currentLValue, modifiedValue);
733 			m_currentLValue.reset();
734 
735 			define(_unaryOperation, _unaryOperation.isPrefixOperation() ? modifiedValue : originalValue);
736 		}
737 		else if (op == Token::BitNot)
738 			appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression());
739 		else if (op == Token::Add)
740 			// According to SyntaxChecker...
741 			solAssert(false, "Use of unary + is disallowed.");
742 		else if (op == Token::Sub)
743 		{
744 			IntegerType const& intType = *dynamic_cast<IntegerType const*>(&resultType);
745 			define(_unaryOperation) << (
746 				m_context.arithmetic() == Arithmetic::Checked ?
747 				m_utils.negateNumberCheckedFunction(intType) :
748 				m_utils.negateNumberWrappingFunction(intType)
749 			) << "(" << IRVariable(_unaryOperation.subExpression()).name() << ")\n";
750 		}
751 		else
752 			solUnimplemented("Unary operator not yet implemented");
753 	}
754 	else if (resultType.category() == Type::Category::FixedBytes)
755 	{
756 		solAssert(op == Token::BitNot, "Only bitwise negation is allowed for FixedBytes");
757 		solAssert(resultType == type(_unaryOperation.subExpression()), "Result type doesn't match!");
758 		appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression());
759 	}
760 	else if (resultType.category() == Type::Category::Bool)
761 	{
762 		solAssert(
763 			op != Token::BitNot,
764 			"Bitwise Negation can't be done on bool!"
765 		);
766 
767 		appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression());
768 	}
769 	else
770 		solUnimplemented("Unary operator not yet implemented");
771 
772 	return false;
773 }
774 
visit(BinaryOperation const & _binOp)775 bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
776 {
777 	setLocation(_binOp);
778 
779 	solAssert(!!_binOp.annotation().commonType, "");
780 	Type const* commonType = _binOp.annotation().commonType;
781 	langutil::Token op = _binOp.getOperator();
782 
783 	if (op == Token::And || op == Token::Or)
784 	{
785 		// This can short-circuit!
786 		appendAndOrOperatorCode(_binOp);
787 		return false;
788 	}
789 
790 	if (commonType->category() == Type::Category::RationalNumber)
791 	{
792 		define(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n";
793 		return false; // skip sub-expressions
794 	}
795 
796 	_binOp.leftExpression().accept(*this);
797 	_binOp.rightExpression().accept(*this);
798 	setLocation(_binOp);
799 
800 	if (TokenTraits::isCompareOp(op))
801 	{
802 		if (auto type = dynamic_cast<FunctionType const*>(commonType))
803 		{
804 			solAssert(op == Token::Equal || op == Token::NotEqual, "Invalid function pointer comparison!");
805 			solAssert(type->kind() != FunctionType::Kind::External, "External function comparison not allowed!");
806 		}
807 
808 		solAssert(commonType->isValueType(), "");
809 		bool isSigned = false;
810 		if (auto type = dynamic_cast<IntegerType const*>(commonType))
811 			isSigned = type->isSigned();
812 
813 		string args = expressionAsType(_binOp.leftExpression(), *commonType, true);
814 		args += ", " + expressionAsType(_binOp.rightExpression(), *commonType, true);
815 
816 		string expr;
817 		if (op == Token::Equal)
818 			expr = "eq(" + move(args) + ")";
819 		else if (op == Token::NotEqual)
820 			expr = "iszero(eq(" + move(args) + "))";
821 		else if (op == Token::GreaterThanOrEqual)
822 			expr = "iszero(" + string(isSigned ? "slt(" : "lt(") + move(args) + "))";
823 		else if (op == Token::LessThanOrEqual)
824 			expr = "iszero(" + string(isSigned ? "sgt(" : "gt(") + move(args) + "))";
825 		else if (op == Token::GreaterThan)
826 			expr = (isSigned ? "sgt(" : "gt(") + move(args) + ")";
827 		else if (op == Token::LessThan)
828 			expr = (isSigned ? "slt(" : "lt(") + move(args) + ")";
829 		else
830 			solAssert(false, "Unknown comparison operator.");
831 		define(_binOp) << expr << "\n";
832 	}
833 	else if (op == Token::Exp)
834 	{
835 		IRVariable left = convert(_binOp.leftExpression(), *commonType);
836 		IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType());
837 
838 		if (m_context.arithmetic() == Arithmetic::Wrapping)
839 			define(_binOp) << m_utils.wrappingIntExpFunction(
840 				dynamic_cast<IntegerType const&>(left.type()),
841 				dynamic_cast<IntegerType const&>(right.type())
842 			) << "(" << left.name() << ", " << right.name() << ")\n";
843 		else if (auto rationalNumberType = dynamic_cast<RationalNumberType const*>(_binOp.leftExpression().annotation().type))
844 		{
845 			solAssert(rationalNumberType->integerType(), "Invalid literal as the base for exponentiation.");
846 			solAssert(dynamic_cast<IntegerType const*>(commonType), "");
847 
848 			define(_binOp) << m_utils.overflowCheckedIntLiteralExpFunction(
849 				*rationalNumberType,
850 				dynamic_cast<IntegerType const&>(right.type()),
851 				dynamic_cast<IntegerType const&>(*commonType)
852 			) << "(" << right.name() << ")\n";
853 		}
854 		else
855 			define(_binOp) << m_utils.overflowCheckedIntExpFunction(
856 				dynamic_cast<IntegerType const&>(left.type()),
857 				dynamic_cast<IntegerType const&>(right.type())
858 			) << "(" << left.name() << ", " << right.name() << ")\n";
859 	}
860 	else if (TokenTraits::isShiftOp(op))
861 	{
862 		IRVariable left = convert(_binOp.leftExpression(), *commonType);
863 		IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType());
864 		define(_binOp) << shiftOperation(_binOp.getOperator(), left, right) << "\n";
865 	}
866 	else
867 	{
868 		string left = expressionAsType(_binOp.leftExpression(), *commonType);
869 		string right = expressionAsType(_binOp.rightExpression(), *commonType);
870 		define(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right) << "\n";
871 	}
872 	return false;
873 }
874 
endVisit(FunctionCall const & _functionCall)875 void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
876 {
877 	setLocation(_functionCall);
878 	auto functionCallKind = *_functionCall.annotation().kind;
879 
880 	if (functionCallKind == FunctionCallKind::TypeConversion)
881 	{
882 		solAssert(
883 			_functionCall.expression().annotation().type->category() == Type::Category::TypeType,
884 			"Expected category to be TypeType"
885 		);
886 		solAssert(_functionCall.arguments().size() == 1, "Expected one argument for type conversion");
887 		define(_functionCall, *_functionCall.arguments().front());
888 		return;
889 	}
890 
891 	FunctionTypePointer functionType = nullptr;
892 	if (functionCallKind == FunctionCallKind::StructConstructorCall)
893 	{
894 		auto const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type);
895 		auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
896 		functionType = structType.constructorType();
897 	}
898 	else
899 		functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
900 
901 	TypePointers parameterTypes = functionType->parameterTypes();
902 
903 	vector<ASTPointer<Expression const>> const& arguments = _functionCall.sortedArguments();
904 
905 	if (functionCallKind == FunctionCallKind::StructConstructorCall)
906 	{
907 		TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type);
908 		auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
909 
910 		define(_functionCall) << m_utils.allocateMemoryStructFunction(structType) << "()\n";
911 
912 		MemberList::MemberMap members = structType.nativeMembers(nullptr);
913 
914 		solAssert(members.size() == arguments.size(), "Struct parameter mismatch.");
915 
916 		for (size_t i = 0; i < arguments.size(); i++)
917 		{
918 			IRVariable converted = convert(*arguments[i], *parameterTypes[i]);
919 			appendCode() <<
920 				m_utils.writeToMemoryFunction(*functionType->parameterTypes()[i]) <<
921 				"(add(" <<
922 				IRVariable(_functionCall).part("mpos").name() <<
923 				", " <<
924 				structType.memoryOffsetOfMember(members[i].name) <<
925 				"), " <<
926 				converted.commaSeparatedList() <<
927 				")\n";
928 		}
929 
930 		return;
931 	}
932 
933 	switch (functionType->kind())
934 	{
935 	case FunctionType::Kind::Declaration:
936 		solAssert(false, "Attempted to generate code for calling a function definition.");
937 		break;
938 	case FunctionType::Kind::Internal:
939 	{
940 		FunctionDefinition const* functionDef = ASTNode::resolveFunctionCall(_functionCall, &m_context.mostDerivedContract());
941 
942 		solAssert(!functionType->takesArbitraryParameters(), "");
943 
944 		vector<string> args;
945 		if (functionType->bound())
946 			args += IRVariable(_functionCall.expression()).part("self").stackSlots();
947 
948 		for (size_t i = 0; i < arguments.size(); ++i)
949 			args += convert(*arguments[i], *parameterTypes[i]).stackSlots();
950 
951 		if (functionDef)
952 		{
953 			solAssert(functionDef->isImplemented(), "");
954 
955 			define(_functionCall) <<
956 				m_context.enqueueFunctionForCodeGeneration(*functionDef) <<
957 				"(" <<
958 				joinHumanReadable(args) <<
959 				")\n";
960 		}
961 		else
962 		{
963 			YulArity arity = YulArity::fromType(*functionType);
964 			m_context.internalFunctionCalledThroughDispatch(arity);
965 
966 			define(_functionCall) <<
967 				IRNames::internalDispatch(arity) <<
968 				"(" <<
969 				IRVariable(_functionCall.expression()).part("functionIdentifier").name() <<
970 				joinHumanReadablePrefixed(args) <<
971 				")\n";
972 		}
973 		break;
974 	}
975 	case FunctionType::Kind::External:
976 	case FunctionType::Kind::DelegateCall:
977 		appendExternalFunctionCall(_functionCall, arguments);
978 		break;
979 	case FunctionType::Kind::BareCall:
980 	case FunctionType::Kind::BareDelegateCall:
981 	case FunctionType::Kind::BareStaticCall:
982 		appendBareCall(_functionCall, arguments);
983 		break;
984 	case FunctionType::Kind::BareCallCode:
985 		solAssert(false, "Callcode has been removed.");
986 	case FunctionType::Kind::Event:
987 	{
988 		auto const& event = dynamic_cast<EventDefinition const&>(functionType->declaration());
989 		TypePointers paramTypes = functionType->parameterTypes();
990 		ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
991 
992 		vector<IRVariable> indexedArgs;
993 		vector<string> nonIndexedArgs;
994 		TypePointers nonIndexedArgTypes;
995 		TypePointers nonIndexedParamTypes;
996 		if (!event.isAnonymous())
997 			define(indexedArgs.emplace_back(m_context.newYulVariable(), *TypeProvider::uint256())) <<
998 				formatNumber(u256(h256::Arith(keccak256(functionType->externalSignature())))) << "\n";
999 		for (size_t i = 0; i < event.parameters().size(); ++i)
1000 		{
1001 			Expression const& arg = *arguments[i];
1002 			if (event.parameters()[i]->isIndexed())
1003 			{
1004 				string value;
1005 				if (auto const& referenceType = dynamic_cast<ReferenceType const*>(paramTypes[i]))
1006 					define(indexedArgs.emplace_back(m_context.newYulVariable(), *TypeProvider::uint256())) <<
1007 						m_utils.packedHashFunction({arg.annotation().type}, {referenceType}) <<
1008 						"(" <<
1009 						IRVariable(arg).commaSeparatedList() <<
1010 						")\n";
1011 				else if (auto functionType = dynamic_cast<FunctionType const*>(paramTypes[i]))
1012 				{
1013 					solAssert(
1014 						IRVariable(arg).type() == *functionType &&
1015 						functionType->kind() == FunctionType::Kind::External &&
1016 						!functionType->bound(),
1017 						""
1018 					);
1019 					define(indexedArgs.emplace_back(m_context.newYulVariable(), *TypeProvider::fixedBytes(32))) <<
1020 						m_utils.combineExternalFunctionIdFunction() <<
1021 						"(" <<
1022 						IRVariable(arg).commaSeparatedList() <<
1023 						")\n";
1024 				}
1025 				else
1026 					indexedArgs.emplace_back(convert(arg, *paramTypes[i]));
1027 			}
1028 			else
1029 			{
1030 				nonIndexedArgs += IRVariable(arg).stackSlots();
1031 				nonIndexedArgTypes.push_back(arg.annotation().type);
1032 				nonIndexedParamTypes.push_back(paramTypes[i]);
1033 			}
1034 		}
1035 		solAssert(indexedArgs.size() <= 4, "Too many indexed arguments.");
1036 		Whiskers templ(R"({
1037 			let <pos> := <allocateUnbounded>()
1038 			let <end> := <encode>(<pos> <nonIndexedArgs>)
1039 			<log>(<pos>, sub(<end>, <pos>) <indexedArgs>)
1040 		})");
1041 		templ("pos", m_context.newYulVariable());
1042 		templ("end", m_context.newYulVariable());
1043 		templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
1044 		templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes));
1045 		templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs));
1046 		templ("log", "log" + to_string(indexedArgs.size()));
1047 		templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | ranges::views::transform([&](auto const& _arg) {
1048 			return _arg.commaSeparatedList();
1049 		})));
1050 		appendCode() << templ.render();
1051 		break;
1052 	}
1053 	case FunctionType::Kind::Error:
1054 	{
1055 		ErrorDefinition const* error = dynamic_cast<ErrorDefinition const*>(ASTNode::referencedDeclaration(_functionCall.expression()));
1056 		solAssert(error, "");
1057 		revertWithError(
1058 			error->functionType(true)->externalSignature(),
1059 			error->functionType(true)->parameterTypes(),
1060 			_functionCall.sortedArguments()
1061 		);
1062 		break;
1063 	}
1064 	case FunctionType::Kind::Wrap:
1065 	case FunctionType::Kind::Unwrap:
1066 	{
1067 		solAssert(arguments.size() == 1, "");
1068 		FunctionType::Kind kind = functionType->kind();
1069 		if (kind == FunctionType::Kind::Wrap)
1070 			solAssert(
1071 				type(*arguments.at(0)).isImplicitlyConvertibleTo(
1072 					dynamic_cast<UserDefinedValueType const&>(type(_functionCall)).underlyingType()
1073 				),
1074 				""
1075 			);
1076 		else
1077 			solAssert(type(*arguments.at(0)).category() == Type::Category::UserDefinedValueType, "");
1078 
1079 		define(_functionCall, *arguments.at(0));
1080 		break;
1081 	}
1082 	case FunctionType::Kind::Assert:
1083 	case FunctionType::Kind::Require:
1084 	{
1085 		solAssert(arguments.size() > 0, "Expected at least one parameter for require/assert");
1086 		solAssert(arguments.size() <= 2, "Expected no more than two parameters for require/assert");
1087 
1088 		Type const* messageArgumentType =
1089 			arguments.size() > 1 && m_context.revertStrings() != RevertStrings::Strip ?
1090 			arguments[1]->annotation().type :
1091 			nullptr;
1092 		string requireOrAssertFunction = m_utils.requireOrAssertFunction(
1093 			functionType->kind() == FunctionType::Kind::Assert,
1094 			messageArgumentType
1095 		);
1096 
1097 		appendCode() << move(requireOrAssertFunction) << "(" << IRVariable(*arguments[0]).name();
1098 		if (messageArgumentType && messageArgumentType->sizeOnStack() > 0)
1099 			appendCode() << ", " << IRVariable(*arguments[1]).commaSeparatedList();
1100 		appendCode() << ")\n";
1101 
1102 		break;
1103 	}
1104 	case FunctionType::Kind::ABIEncode:
1105 	case FunctionType::Kind::ABIEncodePacked:
1106 	case FunctionType::Kind::ABIEncodeWithSelector:
1107 	case FunctionType::Kind::ABIEncodeCall:
1108 	case FunctionType::Kind::ABIEncodeWithSignature:
1109 	{
1110 		bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked;
1111 		solAssert(functionType->padArguments() != isPacked, "");
1112 		bool const hasSelectorOrSignature =
1113 			functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector ||
1114 			functionType->kind() == FunctionType::Kind::ABIEncodeCall ||
1115 			functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature;
1116 
1117 		TypePointers argumentTypes;
1118 		TypePointers targetTypes;
1119 		vector<string> argumentVars;
1120 		string selector;
1121 		vector<ASTPointer<Expression const>> argumentsOfEncodeFunction;
1122 
1123 		if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
1124 		{
1125 			solAssert(arguments.size() == 2, "");
1126 			// Account for tuples with one component which become that component
1127 			if (type(*arguments[1]).category() == Type::Category::Tuple)
1128 			{
1129 				auto const& tupleExpression = dynamic_cast<TupleExpression const&>(*arguments[1]);
1130 				for (auto component: tupleExpression.components())
1131 					argumentsOfEncodeFunction.push_back(component);
1132 			}
1133 			else
1134 				argumentsOfEncodeFunction.push_back(arguments[1]);
1135 		}
1136 		else
1137 			for (size_t i = 0; i < arguments.size(); ++i)
1138 			{
1139 				// ignore selector
1140 				if (hasSelectorOrSignature && i == 0)
1141 					continue;
1142 				argumentsOfEncodeFunction.push_back(arguments[i]);
1143 			}
1144 
1145 		for (auto const& argument: argumentsOfEncodeFunction)
1146 		{
1147 			argumentTypes.emplace_back(&type(*argument));
1148 			targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked));
1149 			argumentVars += IRVariable(*argument).stackSlots();
1150 		}
1151 
1152 		if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
1153 			selector = convert(
1154 				IRVariable(*arguments[0]).part("functionSelector"),
1155 				*TypeProvider::fixedBytes(4)
1156 			).name();
1157 		else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature)
1158 		{
1159 			// hash the signature
1160 			Type const& selectorType = type(*arguments.front());
1161 			if (auto const* stringType = dynamic_cast<StringLiteralType const*>(&selectorType))
1162 				selector = formatNumber(util::selectorFromSignature(stringType->value()));
1163 			else
1164 			{
1165 				// Used to reset the free memory pointer later.
1166 				// TODO This is an abuse of the `allocateUnbounded` function.
1167 				// We might want to introduce a new set of memory handling functions here
1168 				// a la "setMemoryCheckPoint" and "freeUntilCheckPoint".
1169 				string freeMemoryPre = m_context.newYulVariable();
1170 				appendCode() << "let " << freeMemoryPre << " := " << m_utils.allocateUnboundedFunction() << "()\n";
1171 				IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory());
1172 				IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32));
1173 
1174 				string dataAreaFunction = m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory());
1175 				string arrayLengthFunction = m_utils.arrayLengthFunction(*TypeProvider::bytesMemory());
1176 				define(hashVariable) <<
1177 					"keccak256(" <<
1178 					(dataAreaFunction + "(" + array.commaSeparatedList() + ")") <<
1179 					", " <<
1180 					(arrayLengthFunction + "(" + array.commaSeparatedList() +")") <<
1181 					")\n";
1182 				IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4));
1183 				define(selectorVariable, hashVariable);
1184 				selector = selectorVariable.name();
1185 				appendCode() << m_utils.finalizeAllocationFunction() << "(" << freeMemoryPre << ", 0)\n";
1186 			}
1187 		}
1188 		else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector)
1189 			selector = convert(*arguments.front(), *TypeProvider::fixedBytes(4)).name();
1190 
1191 		Whiskers templ(R"(
1192 			let <data> := <allocateUnbounded>()
1193 			let <memPtr> := add(<data>, 0x20)
1194 			<?+selector>
1195 				mstore(<memPtr>, <selector>)
1196 				<memPtr> := add(<memPtr>, 4)
1197 			</+selector>
1198 			let <mend> := <encode>(<memPtr><arguments>)
1199 			mstore(<data>, sub(<mend>, add(<data>, 0x20)))
1200 			<finalizeAllocation>(<data>, sub(<mend>, <data>))
1201 		)");
1202 		templ("data", IRVariable(_functionCall).part("mpos").name());
1203 		templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
1204 		templ("memPtr", m_context.newYulVariable());
1205 		templ("mend", m_context.newYulVariable());
1206 		templ("selector", selector);
1207 		templ("encode",
1208 			isPacked ?
1209 			m_context.abiFunctions().tupleEncoderPacked(argumentTypes, targetTypes) :
1210 			m_context.abiFunctions().tupleEncoder(argumentTypes, targetTypes, false)
1211 		);
1212 		templ("arguments", joinHumanReadablePrefixed(argumentVars));
1213 		templ("finalizeAllocation", m_utils.finalizeAllocationFunction());
1214 
1215 		appendCode() << templ.render();
1216 		break;
1217 	}
1218 	case FunctionType::Kind::ABIDecode:
1219 	{
1220 		Whiskers templ(R"(
1221 			<?+retVars>let <retVars> := </+retVars> <abiDecode>(<offset>, add(<offset>, <length>))
1222 		)");
1223 
1224 		Type const* firstArgType = arguments.front()->annotation().type;
1225 		TypePointers targetTypes;
1226 
1227 		if (TupleType const* targetTupleType = dynamic_cast<TupleType const*>(_functionCall.annotation().type))
1228 			targetTypes = targetTupleType->components();
1229 		else
1230 			targetTypes = TypePointers{_functionCall.annotation().type};
1231 
1232 		if (
1233 			auto referenceType = dynamic_cast<ReferenceType const*>(firstArgType);
1234 			referenceType && referenceType->dataStoredIn(DataLocation::CallData)
1235 			)
1236 		{
1237 			solAssert(referenceType->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata()), "");
1238 			IRVariable var = convert(*arguments[0], *TypeProvider::bytesCalldata());
1239 			templ("abiDecode", m_context.abiFunctions().tupleDecoder(targetTypes, false));
1240 			templ("offset", var.part("offset").name());
1241 			templ("length", var.part("length").name());
1242 		}
1243 		else
1244 		{
1245 			IRVariable var = convert(*arguments[0], *TypeProvider::bytesMemory());
1246 			templ("abiDecode", m_context.abiFunctions().tupleDecoder(targetTypes, true));
1247 			templ("offset", "add(" + var.part("mpos").name() + ", 32)");
1248 			templ("length",
1249 				m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()) + "(" + var.part("mpos").name() + ")"
1250 			);
1251 		}
1252 		templ("retVars", IRVariable(_functionCall).commaSeparatedList());
1253 
1254 		appendCode() << templ.render();
1255 		break;
1256 	}
1257 	case FunctionType::Kind::Revert:
1258 	{
1259 		solAssert(arguments.size() == parameterTypes.size(), "");
1260 		solAssert(arguments.size() <= 1, "");
1261 		solAssert(
1262 			arguments.empty() ||
1263 			arguments.front()->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),
1264 		"");
1265 		if (m_context.revertStrings() == RevertStrings::Strip || arguments.empty())
1266 			appendCode() << "revert(0, 0)\n";
1267 		else
1268 			revertWithError(
1269 				"Error(string)",
1270 				{TypeProvider::stringMemory()},
1271 				{arguments.front()}
1272 			);
1273 		break;
1274 	}
1275 	// Array creation using new
1276 	case FunctionType::Kind::ObjectCreation:
1277 	{
1278 		ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_functionCall.annotation().type);
1279 		solAssert(arguments.size() == 1, "");
1280 
1281 		IRVariable value = convert(*arguments[0], *TypeProvider::uint256());
1282 		define(_functionCall) <<
1283 			m_utils.allocateAndInitializeMemoryArrayFunction(arrayType) <<
1284 			"(" <<
1285 			value.commaSeparatedList() <<
1286 			")\n";
1287 		break;
1288 	}
1289 	case FunctionType::Kind::KECCAK256:
1290 	{
1291 		solAssert(arguments.size() == 1, "");
1292 
1293 		ArrayType const* arrayType = TypeProvider::bytesMemory();
1294 
1295 		if (auto const* stringLiteral = dynamic_cast<StringLiteralType const*>(arguments.front()->annotation().type))
1296 		{
1297 			// Optimization: Compute keccak256 on string literals at compile-time.
1298 			define(_functionCall) <<
1299 				("0x" + keccak256(stringLiteral->value()).hex()) <<
1300 				"\n";
1301 		}
1302 		else
1303 		{
1304 			auto array = convert(*arguments[0], *arrayType);
1305 
1306 			string dataAreaFunction = m_utils.arrayDataAreaFunction(*arrayType);
1307 			string arrayLengthFunction = m_utils.arrayLengthFunction(*arrayType);
1308 			define(_functionCall) <<
1309 				"keccak256(" <<
1310 				(dataAreaFunction + "(" + array.commaSeparatedList() + ")") <<
1311 				", " <<
1312 				(arrayLengthFunction + "(" + array.commaSeparatedList() +")") <<
1313 				")\n";
1314 		}
1315 		break;
1316 	}
1317 	case FunctionType::Kind::ArrayPop:
1318 	{
1319 		solAssert(functionType->bound(), "");
1320 		solAssert(functionType->parameterTypes().empty(), "");
1321 		ArrayType const* arrayType = dynamic_cast<ArrayType const*>(functionType->selfType());
1322 		solAssert(arrayType, "");
1323 		define(_functionCall) <<
1324 			m_utils.storageArrayPopFunction(*arrayType) <<
1325 			"(" <<
1326 			IRVariable(_functionCall.expression()).commaSeparatedList() <<
1327 			")\n";
1328 		break;
1329 	}
1330 	case FunctionType::Kind::ArrayPush:
1331 	{
1332 		ArrayType const* arrayType = dynamic_cast<ArrayType const*>(functionType->selfType());
1333 		solAssert(arrayType, "");
1334 
1335 		if (arguments.empty())
1336 		{
1337 			auto slotName = m_context.newYulVariable();
1338 			auto offsetName = m_context.newYulVariable();
1339 			appendCode() << "let " << slotName << ", " << offsetName << " := " <<
1340 				m_utils.storageArrayPushZeroFunction(*arrayType) <<
1341 				"(" << IRVariable(_functionCall.expression()).commaSeparatedList() << ")\n";
1342 			setLValue(_functionCall, IRLValue{
1343 				*arrayType->baseType(),
1344 				IRLValue::Storage{
1345 					slotName,
1346 					offsetName,
1347 				}
1348 			});
1349 		}
1350 		else
1351 		{
1352 			IRVariable argument =
1353 				arrayType->baseType()->isValueType() ?
1354 				convert(*arguments.front(), *arrayType->baseType()) :
1355 				*arguments.front();
1356 
1357 			appendCode() <<
1358 				m_utils.storageArrayPushFunction(*arrayType, &argument.type()) <<
1359 				"(" <<
1360 				IRVariable(_functionCall.expression()).commaSeparatedList() <<
1361 				(argument.stackSlots().empty() ? "" : (", " + argument.commaSeparatedList()))  <<
1362 				")\n";
1363 		}
1364 		break;
1365 	}
1366 	case FunctionType::Kind::BytesConcat:
1367 	{
1368 		TypePointers argumentTypes;
1369 		vector<string> argumentVars;
1370 		for (ASTPointer<Expression const> const& argument: arguments)
1371 		{
1372 			argumentTypes.emplace_back(&type(*argument));
1373 			argumentVars += IRVariable(*argument).stackSlots();
1374 		}
1375 		define(IRVariable(_functionCall)) <<
1376 			m_utils.bytesConcatFunction(argumentTypes) <<
1377 			"(" <<
1378 			joinHumanReadable(argumentVars) <<
1379 			")\n";
1380 
1381 		break;
1382 	}
1383 	case FunctionType::Kind::MetaType:
1384 	{
1385 		break;
1386 	}
1387 	case FunctionType::Kind::AddMod:
1388 	case FunctionType::Kind::MulMod:
1389 	{
1390 		static map<FunctionType::Kind, string> functions = {
1391 			{FunctionType::Kind::AddMod, "addmod"},
1392 			{FunctionType::Kind::MulMod, "mulmod"},
1393 		};
1394 		solAssert(functions.find(functionType->kind()) != functions.end(), "");
1395 		solAssert(arguments.size() == 3 && parameterTypes.size() == 3, "");
1396 
1397 		IRVariable modulus(m_context.newYulVariable(), *(parameterTypes[2]));
1398 		define(modulus, *arguments[2]);
1399 		Whiskers templ("if iszero(<modulus>) { <panic>() }\n");
1400 		templ("modulus", modulus.name());
1401 		templ("panic", m_utils.panicFunction(PanicCode::DivisionByZero));
1402 		appendCode() << templ.render();
1403 
1404 		string args;
1405 		for (size_t i = 0; i < 2; ++i)
1406 			args += expressionAsType(*arguments[i], *(parameterTypes[i])) + ", ";
1407 		args += modulus.name();
1408 		define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n";
1409 		break;
1410 	}
1411 	case FunctionType::Kind::GasLeft:
1412 	case FunctionType::Kind::Selfdestruct:
1413 	case FunctionType::Kind::BlockHash:
1414 	{
1415 		static map<FunctionType::Kind, string> functions = {
1416 			{FunctionType::Kind::GasLeft, "gas"},
1417 			{FunctionType::Kind::Selfdestruct, "selfdestruct"},
1418 			{FunctionType::Kind::BlockHash, "blockhash"},
1419 		};
1420 		solAssert(functions.find(functionType->kind()) != functions.end(), "");
1421 
1422 		string args;
1423 		for (size_t i = 0; i < arguments.size(); ++i)
1424 			args += (args.empty() ? "" : ", ") + expressionAsType(*arguments[i], *(parameterTypes[i]));
1425 		define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n";
1426 		break;
1427 	}
1428 	case FunctionType::Kind::Creation:
1429 	{
1430 		solAssert(!functionType->gasSet(), "Gas limit set for contract creation.");
1431 		solAssert(
1432 			functionType->returnParameterTypes().size() == 1,
1433 			"Constructor should return only one type"
1434 		);
1435 
1436 		TypePointers argumentTypes;
1437 		vector<string> constructorParams;
1438 		for (ASTPointer<Expression const> const& arg: arguments)
1439 		{
1440 			argumentTypes.push_back(arg->annotation().type);
1441 			constructorParams += IRVariable{*arg}.stackSlots();
1442 		}
1443 
1444 		ContractDefinition const* contract =
1445 			&dynamic_cast<ContractType const&>(*functionType->returnParameterTypes().front()).contractDefinition();
1446 		m_context.subObjectsCreated().insert(contract);
1447 
1448 		Whiskers t(R"(let <memPos> := <allocateUnbounded>()
1449 			let <memEnd> := add(<memPos>, datasize("<object>"))
1450 			if or(gt(<memEnd>, 0xffffffffffffffff), lt(<memEnd>, <memPos>)) { <panic>() }
1451 			datacopy(<memPos>, dataoffset("<object>"), datasize("<object>"))
1452 			<memEnd> := <abiEncode>(<memEnd><constructorParams>)
1453 			<?saltSet>
1454 				let <address> := create2(<value>, <memPos>, sub(<memEnd>, <memPos>), <salt>)
1455 			<!saltSet>
1456 				let <address> := create(<value>, <memPos>, sub(<memEnd>, <memPos>))
1457 			</saltSet>
1458 			<?isTryCall>
1459 				let <success> := iszero(iszero(<address>))
1460 			<!isTryCall>
1461 				if iszero(<address>) { <forwardingRevert>() }
1462 			</isTryCall>
1463 		)");
1464 		t("memPos", m_context.newYulVariable());
1465 		t("memEnd", m_context.newYulVariable());
1466 		t("allocateUnbounded", m_utils.allocateUnboundedFunction());
1467 		t("object", IRNames::creationObject(*contract));
1468 		t("panic", m_utils.panicFunction(PanicCode::ResourceError));
1469 		t("abiEncode",
1470 			m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false)
1471 		);
1472 		t("constructorParams", joinHumanReadablePrefixed(constructorParams));
1473 		t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0");
1474 		t("saltSet", functionType->saltSet());
1475 		if (functionType->saltSet())
1476 			t("salt", IRVariable(_functionCall.expression()).part("salt").name());
1477 		solAssert(IRVariable(_functionCall).stackSlots().size() == 1, "");
1478 		t("address", IRVariable(_functionCall).commaSeparatedList());
1479 		t("isTryCall", _functionCall.annotation().tryCall);
1480 		if (_functionCall.annotation().tryCall)
1481 			t("success", IRNames::trySuccessConditionVariable(_functionCall));
1482 		else
1483 			t("forwardingRevert", m_utils.forwardingRevertFunction());
1484 		appendCode() << t.render();
1485 
1486 		break;
1487 	}
1488 	case FunctionType::Kind::Send:
1489 	case FunctionType::Kind::Transfer:
1490 	{
1491 		solAssert(arguments.size() == 1 && parameterTypes.size() == 1, "");
1492 		string address{IRVariable(_functionCall.expression()).part("address").name()};
1493 		string value{expressionAsType(*arguments[0], *(parameterTypes[0]))};
1494 		Whiskers templ(R"(
1495 			let <gas> := 0
1496 			if iszero(<value>) { <gas> := <callStipend> }
1497 			let <success> := call(<gas>, <address>, <value>, 0, 0, 0, 0)
1498 			<?isTransfer>
1499 				if iszero(<success>) { <forwardingRevert>() }
1500 			</isTransfer>
1501 		)");
1502 		templ("gas", m_context.newYulVariable());
1503 		templ("callStipend", toString(evmasm::GasCosts::callStipend));
1504 		templ("address", address);
1505 		templ("value", value);
1506 		if (functionType->kind() == FunctionType::Kind::Transfer)
1507 			templ("success", m_context.newYulVariable());
1508 		else
1509 			templ("success", IRVariable(_functionCall).commaSeparatedList());
1510 		templ("isTransfer", functionType->kind() == FunctionType::Kind::Transfer);
1511 		templ("forwardingRevert", m_utils.forwardingRevertFunction());
1512 		appendCode() << templ.render();
1513 
1514 		break;
1515 	}
1516 	case FunctionType::Kind::ECRecover:
1517 	case FunctionType::Kind::RIPEMD160:
1518 	case FunctionType::Kind::SHA256:
1519 	{
1520 		solAssert(!_functionCall.annotation().tryCall, "");
1521 		solAssert(!functionType->valueSet(), "");
1522 		solAssert(!functionType->gasSet(), "");
1523 		solAssert(!functionType->bound(), "");
1524 
1525 		static map<FunctionType::Kind, std::tuple<unsigned, size_t>> precompiles = {
1526 			{FunctionType::Kind::ECRecover, std::make_tuple(1, 0)},
1527 			{FunctionType::Kind::SHA256, std::make_tuple(2, 0)},
1528 			{FunctionType::Kind::RIPEMD160, std::make_tuple(3, 12)},
1529 		};
1530 		auto [ address, offset ] = precompiles[functionType->kind()];
1531 		TypePointers argumentTypes;
1532 		vector<string> argumentStrings;
1533 		for (auto const& arg: arguments)
1534 		{
1535 			argumentTypes.emplace_back(&type(*arg));
1536 			argumentStrings += IRVariable(*arg).stackSlots();
1537 		}
1538 		Whiskers templ(R"(
1539 			let <pos> := <allocateUnbounded>()
1540 			let <end> := <encodeArgs>(<pos> <argumentString>)
1541 			<?isECRecover>
1542 				mstore(0, 0)
1543 			</isECRecover>
1544 			let <success> := <call>(<gas>, <address> <?isCall>, 0</isCall>, <pos>, sub(<end>, <pos>), 0, 32)
1545 			if iszero(<success>) { <forwardingRevert>() }
1546 			let <retVars> := <shl>(mload(0))
1547 		)");
1548 		templ("call", m_context.evmVersion().hasStaticCall() ? "staticcall" : "call");
1549 		templ("isCall", !m_context.evmVersion().hasStaticCall());
1550 		templ("shl", m_utils.shiftLeftFunction(offset * 8));
1551 		templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
1552 		templ("pos", m_context.newYulVariable());
1553 		templ("end", m_context.newYulVariable());
1554 		templ("isECRecover", FunctionType::Kind::ECRecover == functionType->kind());
1555 		if (FunctionType::Kind::ECRecover == functionType->kind())
1556 			templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes));
1557 		else
1558 			templ("encodeArgs", m_context.abiFunctions().tupleEncoderPacked(argumentTypes, parameterTypes));
1559 		templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
1560 		templ("address", toString(address));
1561 		templ("success", m_context.newYulVariable());
1562 		templ("retVars", IRVariable(_functionCall).commaSeparatedList());
1563 		templ("forwardingRevert", m_utils.forwardingRevertFunction());
1564 		if (m_context.evmVersion().canOverchargeGasForCall())
1565 			// Send all gas (requires tangerine whistle EVM)
1566 			templ("gas", "gas()");
1567 		else
1568 		{
1569 			// @todo The value 10 is not exact and this could be fine-tuned,
1570 			// but this has worked for years in the old code generator.
1571 			u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10 + evmasm::GasCosts::callNewAccountGas;
1572 			templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")");
1573 		}
1574 
1575 		appendCode() << templ.render();
1576 
1577 		break;
1578 	}
1579 	default:
1580 		solUnimplemented("FunctionKind " + toString(static_cast<int>(functionType->kind())) + " not yet implemented");
1581 	}
1582 }
1583 
endVisit(FunctionCallOptions const & _options)1584 void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options)
1585 {
1586 	setLocation(_options);
1587 	FunctionType const& previousType = dynamic_cast<FunctionType const&>(*_options.expression().annotation().type);
1588 
1589 	solUnimplementedAssert(!previousType.bound());
1590 
1591 	// Copy over existing values.
1592 	for (auto const& item: previousType.stackItems())
1593 		define(IRVariable(_options).part(get<0>(item)), IRVariable(_options.expression()).part(get<0>(item)));
1594 
1595 	for (size_t i = 0; i < _options.names().size(); ++i)
1596 	{
1597 		string const& name = *_options.names()[i];
1598 		solAssert(name == "salt" || name == "gas" || name == "value", "");
1599 
1600 		define(IRVariable(_options).part(name), *_options.options()[i]);
1601 	}
1602 }
1603 
visit(MemberAccess const & _memberAccess)1604 bool IRGeneratorForStatements::visit(MemberAccess const& _memberAccess)
1605 {
1606 	// A shortcut for <address>.code.length. We skip visiting <address>.code and directly visit
1607 	// <address>. The actual code is generated in endVisit.
1608 	if (
1609 		auto innerExpression = dynamic_cast<MemberAccess const*>(&_memberAccess.expression());
1610 		_memberAccess.memberName() == "length" &&
1611 		innerExpression &&
1612 		innerExpression->memberName() == "code" &&
1613 		innerExpression->expression().annotation().type->category() == Type::Category::Address
1614 	)
1615 	{
1616 		solAssert(innerExpression->annotation().type->category() == Type::Category::Array, "");
1617 		// Skip visiting <address>.code
1618 		innerExpression->expression().accept(*this);
1619 
1620 		return false;
1621 	}
1622 
1623 	return true;
1624 }
1625 
endVisit(MemberAccess const & _memberAccess)1626 void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
1627 {
1628 	setLocation(_memberAccess);
1629 
1630 	ASTString const& member = _memberAccess.memberName();
1631 	auto memberFunctionType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
1632 	Type::Category objectCategory = _memberAccess.expression().annotation().type->category();
1633 
1634 	if (memberFunctionType && memberFunctionType->bound())
1635 	{
1636 		define(IRVariable(_memberAccess).part("self"), _memberAccess.expression());
1637 		solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
1638 		if (memberFunctionType->kind() == FunctionType::Kind::Internal)
1639 			assignInternalFunctionIDIfNotCalledDirectly(
1640 				_memberAccess,
1641 				dynamic_cast<FunctionDefinition const&>(memberFunctionType->declaration())
1642 			);
1643 		else if (
1644 			memberFunctionType->kind() == FunctionType::Kind::ArrayPush ||
1645 			memberFunctionType->kind() == FunctionType::Kind::ArrayPop
1646 		)
1647 		{
1648 			// Nothing to do.
1649 		}
1650 		else
1651 		{
1652 			auto const& functionDefinition = dynamic_cast<FunctionDefinition const&>(memberFunctionType->declaration());
1653 			solAssert(memberFunctionType->kind() == FunctionType::Kind::DelegateCall, "");
1654 			auto contract = dynamic_cast<ContractDefinition const*>(functionDefinition.scope());
1655 			solAssert(contract && contract->isLibrary(), "");
1656 			define(IRVariable(_memberAccess).part("address")) << linkerSymbol(*contract) << "\n";
1657 			define(IRVariable(_memberAccess).part("functionSelector")) << memberFunctionType->externalIdentifier() << "\n";
1658 		}
1659 		return;
1660 	}
1661 
1662 	switch (objectCategory)
1663 	{
1664 	case Type::Category::Contract:
1665 	{
1666 		ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
1667 		if (type.isSuper())
1668 			solAssert(false, "");
1669 
1670 		// ordinary contract type
1671 		else if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
1672 		{
1673 			u256 identifier;
1674 			if (auto const* variable = dynamic_cast<VariableDeclaration const*>(declaration))
1675 				identifier = FunctionType(*variable).externalIdentifier();
1676 			else if (auto const* function = dynamic_cast<FunctionDefinition const*>(declaration))
1677 				identifier = FunctionType(*function).externalIdentifier();
1678 			else
1679 				solAssert(false, "Contract member is neither variable nor function.");
1680 
1681 			define(IRVariable(_memberAccess).part("address"), _memberAccess.expression());
1682 			define(IRVariable(_memberAccess).part("functionSelector")) << formatNumber(identifier) << "\n";
1683 		}
1684 		else
1685 			solAssert(false, "Invalid member access in contract");
1686 		break;
1687 	}
1688 	case Type::Category::Integer:
1689 	{
1690 		solAssert(false, "Invalid member access to integer");
1691 		break;
1692 	}
1693 	case Type::Category::Address:
1694 	{
1695 		if (member == "balance")
1696 			define(_memberAccess) <<
1697 				"balance(" <<
1698 				expressionAsType(_memberAccess.expression(), *TypeProvider::address()) <<
1699 				")\n";
1700 		else if (member == "code")
1701 		{
1702 			string externalCodeFunction = m_utils.externalCodeFunction();
1703 			define(_memberAccess) <<
1704 				externalCodeFunction <<
1705 				"(" <<
1706 				expressionAsType(_memberAccess.expression(), *TypeProvider::address()) <<
1707 				")\n";
1708 		}
1709 		else if (member == "codehash")
1710 			define(_memberAccess) <<
1711 				"extcodehash(" <<
1712 				expressionAsType(_memberAccess.expression(), *TypeProvider::address()) <<
1713 				")\n";
1714 		else if (set<string>{"send", "transfer"}.count(member))
1715 		{
1716 			solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, "");
1717 			define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression());
1718 		}
1719 		else if (set<string>{"call", "callcode", "delegatecall", "staticcall"}.count(member))
1720 			define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression());
1721 		else
1722 			solAssert(false, "Invalid member access to address");
1723 		break;
1724 	}
1725 	case Type::Category::Function:
1726 		if (member == "selector")
1727 		{
1728 			FunctionType const& functionType = dynamic_cast<FunctionType const&>(
1729 				*_memberAccess.expression().annotation().type
1730 			);
1731 			if (
1732 				functionType.kind() == FunctionType::Kind::External ||
1733 				functionType.kind() == FunctionType::Kind::DelegateCall
1734 			)
1735 				define(IRVariable{_memberAccess}, IRVariable(_memberAccess.expression()).part("functionSelector"));
1736 			else if (
1737 				functionType.kind() == FunctionType::Kind::Declaration ||
1738 				functionType.kind() == FunctionType::Kind::Error ||
1739 				// In some situations, internal function types also provide the "selector" member.
1740 				// See Types.cpp for details.
1741 				functionType.kind() == FunctionType::Kind::Internal
1742 			)
1743 			{
1744 				solAssert(functionType.hasDeclaration(), "");
1745 				solAssert(
1746 					functionType.kind() == FunctionType::Kind::Error ||
1747 					functionType.declaration().isPartOfExternalInterface(),
1748 					""
1749 				);
1750 				define(IRVariable{_memberAccess}) << formatNumber(functionType.externalIdentifier() << 224) << "\n";
1751 			}
1752 			else
1753 				solAssert(false, "Invalid use of .selector: " + functionType.toString(false));
1754 		}
1755 		else if (member == "address")
1756 		{
1757 			solUnimplementedAssert(
1758 				dynamic_cast<FunctionType const&>(*_memberAccess.expression().annotation().type).kind() ==
1759 				FunctionType::Kind::External
1760 			);
1761 			define(IRVariable{_memberAccess}, IRVariable(_memberAccess.expression()).part("address"));
1762 		}
1763 		else
1764 			solAssert(
1765 				!!_memberAccess.expression().annotation().type->memberType(member),
1766 				"Invalid member access to function."
1767 			);
1768 		break;
1769 	case Type::Category::Magic:
1770 		// we can ignore the kind of magic and only look at the name of the member
1771 		if (member == "coinbase")
1772 			define(_memberAccess) << "coinbase()\n";
1773 		else if (member == "timestamp")
1774 			define(_memberAccess) << "timestamp()\n";
1775 		else if (member == "difficulty")
1776 			define(_memberAccess) << "difficulty()\n";
1777 		else if (member == "number")
1778 			define(_memberAccess) << "number()\n";
1779 		else if (member == "gaslimit")
1780 			define(_memberAccess) << "gaslimit()\n";
1781 		else if (member == "sender")
1782 			define(_memberAccess) << "caller()\n";
1783 		else if (member == "value")
1784 			define(_memberAccess) << "callvalue()\n";
1785 		else if (member == "origin")
1786 			define(_memberAccess) << "origin()\n";
1787 		else if (member == "gasprice")
1788 			define(_memberAccess) << "gasprice()\n";
1789 		else if (member == "chainid")
1790 			define(_memberAccess) << "chainid()\n";
1791 		else if (member == "basefee")
1792 			define(_memberAccess) << "basefee()\n";
1793 		else if (member == "data")
1794 		{
1795 			IRVariable var(_memberAccess);
1796 			define(var.part("offset")) << "0\n";
1797 			define(var.part("length")) << "calldatasize()\n";
1798 		}
1799 		else if (member == "sig")
1800 			define(_memberAccess) <<
1801 				"and(calldataload(0), " <<
1802 				formatNumber(u256(0xffffffff) << (256 - 32)) <<
1803 				")\n";
1804 		else if (member == "gas")
1805 			solAssert(false, "Gas has been removed.");
1806 		else if (member == "blockhash")
1807 			solAssert(false, "Blockhash has been removed.");
1808 		else if (member == "creationCode" || member == "runtimeCode")
1809 		{
1810 			Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
1811 			auto const& contractType = dynamic_cast<ContractType const&>(*arg);
1812 			solAssert(!contractType.isSuper(), "");
1813 			ContractDefinition const& contract = contractType.contractDefinition();
1814 			m_context.subObjectsCreated().insert(&contract);
1815 			appendCode() << Whiskers(R"(
1816 				let <size> := datasize("<objectName>")
1817 				let <result> := <allocationFunction>(add(<size>, 32))
1818 				mstore(<result>, <size>)
1819 				datacopy(add(<result>, 32), dataoffset("<objectName>"), <size>)
1820 			)")
1821 			("allocationFunction", m_utils.allocationFunction())
1822 			("size", m_context.newYulVariable())
1823 			("objectName", IRNames::creationObject(contract) + (member == "runtimeCode" ? "." + IRNames::deployedObject(contract) : ""))
1824 			("result", IRVariable(_memberAccess).commaSeparatedList()).render();
1825 		}
1826 		else if (member == "name")
1827 		{
1828 			Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
1829 			ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
1830 			define(IRVariable(_memberAccess)) << m_utils.copyLiteralToMemoryFunction(contract.name()) << "()\n";
1831 		}
1832 		else if (member == "interfaceId")
1833 		{
1834 			Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
1835 			auto const& contractType = dynamic_cast<ContractType const&>(*arg);
1836 			solAssert(!contractType.isSuper(), "");
1837 			ContractDefinition const& contract = contractType.contractDefinition();
1838 			define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n";
1839 		}
1840 		else if (member == "min" || member == "max")
1841 		{
1842 			MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
1843 
1844 			string requestedValue;
1845 			if (IntegerType const* integerType = dynamic_cast<IntegerType const*>(arg->typeArgument()))
1846 			{
1847 				if (member == "min")
1848 					requestedValue = formatNumber(integerType->min());
1849 				else
1850 					requestedValue = formatNumber(integerType->max());
1851 			}
1852 			else if (EnumType const* enumType = dynamic_cast<EnumType const*>(arg->typeArgument()))
1853 			{
1854 				if (member == "min")
1855 					requestedValue = to_string(enumType->minValue());
1856 				else
1857 					requestedValue = to_string(enumType->maxValue());
1858 			}
1859 			else
1860 				solAssert(false, "min/max requested on unexpected type.");
1861 
1862 			define(_memberAccess) << requestedValue << "\n";
1863 		}
1864 		else if (set<string>{"encode", "encodePacked", "encodeWithSelector", "encodeCall", "encodeWithSignature", "decode"}.count(member))
1865 		{
1866 			// no-op
1867 		}
1868 		else
1869 			solAssert(false, "Unknown magic member.");
1870 		break;
1871 	case Type::Category::Struct:
1872 	{
1873 		auto const& structType = dynamic_cast<StructType const&>(*_memberAccess.expression().annotation().type);
1874 
1875 		IRVariable expression(_memberAccess.expression());
1876 		switch (structType.location())
1877 		{
1878 		case DataLocation::Storage:
1879 		{
1880 			pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
1881 			string slot = m_context.newYulVariable();
1882 			appendCode() << "let " << slot << " := " <<
1883 				("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n");
1884 			setLValue(_memberAccess, IRLValue{
1885 				type(_memberAccess),
1886 				IRLValue::Storage{slot, offsets.second}
1887 			});
1888 			break;
1889 		}
1890 		case DataLocation::Memory:
1891 		{
1892 			string pos = m_context.newYulVariable();
1893 			appendCode() << "let " << pos << " := " <<
1894 				("add(" + expression.part("mpos").name() + ", " + structType.memoryOffsetOfMember(member).str() + ")\n");
1895 			setLValue(_memberAccess, IRLValue{
1896 				type(_memberAccess),
1897 				IRLValue::Memory{pos}
1898 			});
1899 			break;
1900 		}
1901 		case DataLocation::CallData:
1902 		{
1903 			string baseRef = expression.part("offset").name();
1904 			string offset = m_context.newYulVariable();
1905 			appendCode() << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n";
1906 			if (_memberAccess.annotation().type->isDynamicallyEncoded())
1907 				define(_memberAccess) <<
1908 					m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) <<
1909 					"(" <<
1910 					baseRef <<
1911 					", " <<
1912 					offset <<
1913 					")\n";
1914 			else if (
1915 				dynamic_cast<ArrayType const*>(_memberAccess.annotation().type) ||
1916 				dynamic_cast<StructType const*>(_memberAccess.annotation().type)
1917 			)
1918 				define(_memberAccess) << offset << "\n";
1919 			else
1920 				define(_memberAccess) <<
1921 					m_utils.readFromCalldata(*_memberAccess.annotation().type) <<
1922 					"(" <<
1923 					offset <<
1924 					")\n";
1925 			break;
1926 		}
1927 		default:
1928 			solAssert(false, "Illegal data location for struct.");
1929 		}
1930 		break;
1931 	}
1932 	case Type::Category::Enum:
1933 	{
1934 		EnumType const& type = dynamic_cast<EnumType const&>(*_memberAccess.expression().annotation().type);
1935 		define(_memberAccess) << to_string(type.memberValue(_memberAccess.memberName())) << "\n";
1936 		break;
1937 	}
1938 	case Type::Category::Array:
1939 	{
1940 		auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.expression().annotation().type);
1941 		if (member == "length")
1942 		{
1943 			// shortcut for <address>.code.length
1944 			if (
1945 				auto innerExpression = dynamic_cast<MemberAccess const*>(&_memberAccess.expression());
1946 				innerExpression &&
1947 				innerExpression->memberName() == "code" &&
1948 				innerExpression->expression().annotation().type->category() == Type::Category::Address
1949 			)
1950 				define(_memberAccess) <<
1951 					"extcodesize(" <<
1952 					expressionAsType(innerExpression->expression(), *TypeProvider::address()) <<
1953 					")\n";
1954 			else
1955 				define(_memberAccess) <<
1956 					m_utils.arrayLengthFunction(type) <<
1957 					"(" <<
1958 					IRVariable(_memberAccess.expression()).commaSeparatedList() <<
1959 					")\n";
1960 		}
1961 		else if (member == "pop" || member == "push")
1962 		{
1963 			solAssert(type.location() == DataLocation::Storage, "");
1964 			define(IRVariable{_memberAccess}.part("slot"), IRVariable{_memberAccess.expression()}.part("slot"));
1965 		}
1966 		else
1967 			solAssert(false, "Invalid array member access.");
1968 
1969 		break;
1970 	}
1971 	case Type::Category::FixedBytes:
1972 	{
1973 		auto const& type = dynamic_cast<FixedBytesType const&>(*_memberAccess.expression().annotation().type);
1974 		if (member == "length")
1975 			define(_memberAccess) << to_string(type.numBytes()) << "\n";
1976 		else
1977 			solAssert(false, "Illegal fixed bytes member.");
1978 		break;
1979 	}
1980 	case Type::Category::TypeType:
1981 	{
1982 		Type const& actualType = *dynamic_cast<TypeType const&>(
1983 			*_memberAccess.expression().annotation().type
1984 		).actualType();
1985 
1986 		if (actualType.category() == Type::Category::Contract)
1987 		{
1988 			ContractType const& contractType = dynamic_cast<ContractType const&>(actualType);
1989 			if (contractType.isSuper())
1990 			{
1991 				solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
1992 				ContractDefinition const* super = contractType.contractDefinition().superContract(m_context.mostDerivedContract());
1993 				solAssert(super, "Super contract not available.");
1994 				FunctionDefinition const& resolvedFunctionDef =
1995 					dynamic_cast<FunctionDefinition const&>(
1996 						*_memberAccess.annotation().referencedDeclaration
1997 					).resolveVirtual(m_context.mostDerivedContract(), super);
1998 
1999 				solAssert(resolvedFunctionDef.functionType(true), "");
2000 				solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
2001 				assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, resolvedFunctionDef);
2002 			}
2003 			else if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
2004 				handleVariableReference(*variable, _memberAccess);
2005 			else if (memberFunctionType)
2006 			{
2007 				switch (memberFunctionType->kind())
2008 				{
2009 				case FunctionType::Kind::Declaration:
2010 					break;
2011 				case FunctionType::Kind::Internal:
2012 					if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
2013 						assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, *function);
2014 					else
2015 						solAssert(false, "Function not found in member access");
2016 					break;
2017 				case FunctionType::Kind::Event:
2018 					solAssert(
2019 						dynamic_cast<EventDefinition const*>(_memberAccess.annotation().referencedDeclaration),
2020 						"Event not found"
2021 					);
2022 						// the call will do the resolving
2023 					break;
2024 				case FunctionType::Kind::Error:
2025 					solAssert(
2026 						dynamic_cast<ErrorDefinition const*>(_memberAccess.annotation().referencedDeclaration),
2027 						"Error not found"
2028 					);
2029 					// The function call will resolve the selector.
2030 					break;
2031 				case FunctionType::Kind::DelegateCall:
2032 					define(IRVariable(_memberAccess).part("address"), _memberAccess.expression());
2033 					define(IRVariable(_memberAccess).part("functionSelector")) << formatNumber(memberFunctionType->externalIdentifier()) << "\n";
2034 					break;
2035 				case FunctionType::Kind::External:
2036 				case FunctionType::Kind::Creation:
2037 				case FunctionType::Kind::Send:
2038 				case FunctionType::Kind::BareCall:
2039 				case FunctionType::Kind::BareCallCode:
2040 				case FunctionType::Kind::BareDelegateCall:
2041 				case FunctionType::Kind::BareStaticCall:
2042 				case FunctionType::Kind::Transfer:
2043 				case FunctionType::Kind::ECRecover:
2044 				case FunctionType::Kind::SHA256:
2045 				case FunctionType::Kind::RIPEMD160:
2046 				default:
2047 					solAssert(false, "unsupported member function");
2048 				}
2049 			}
2050 			else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type))
2051 			{
2052 			// no-op
2053 			}
2054 			else
2055 				// The old code generator had a generic "else" case here
2056 				// without any specific code being generated,
2057 				// but it would still be better to have an exhaustive list.
2058 				solAssert(false, "");
2059 		}
2060 		else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
2061 			define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n";
2062 		else if (dynamic_cast<UserDefinedValueType const*>(&actualType))
2063 			solAssert(member == "wrap" || member == "unwrap", "");
2064 		else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType))
2065 			solAssert(arrayType->isByteArray() && member == "concat", "");
2066 		else
2067 			// The old code generator had a generic "else" case here
2068 			// without any specific code being generated,
2069 			// but it would still be better to have an exhaustive list.
2070 			solAssert(false, "");
2071 		break;
2072 	}
2073 	case Type::Category::Module:
2074 	{
2075 		Type::Category category = _memberAccess.annotation().type->category();
2076 		solAssert(
2077 			dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration) ||
2078 			dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration) ||
2079 			dynamic_cast<ErrorDefinition const*>(_memberAccess.annotation().referencedDeclaration) ||
2080 			category == Type::Category::TypeType ||
2081 			category == Type::Category::Module,
2082 			""
2083 		);
2084 		if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
2085 		{
2086 			solAssert(variable->isConstant(), "");
2087 			handleVariableReference(*variable, static_cast<Expression const&>(_memberAccess));
2088 		}
2089 		else if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
2090 		{
2091 			auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
2092 			solAssert(function && function->isFree(), "");
2093 			solAssert(function->functionType(true), "");
2094 			solAssert(function->functionType(true)->kind() == FunctionType::Kind::Internal, "");
2095 			solAssert(funType->kind() == FunctionType::Kind::Internal, "");
2096 			solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
2097 
2098 			assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, *function);
2099 		}
2100 		else if (auto const* contract = dynamic_cast<ContractDefinition const*>(_memberAccess.annotation().referencedDeclaration))
2101 		{
2102 			if (contract->isLibrary())
2103 				define(IRVariable(_memberAccess).part("address")) << linkerSymbol(*contract) << "\n";
2104 		}
2105 		break;
2106 	}
2107 	default:
2108 		solAssert(false, "Member access to unknown type.");
2109 	}
2110 }
2111 
visit(InlineAssembly const & _inlineAsm)2112 bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
2113 {
2114 	setLocation(_inlineAsm);
2115 	m_context.setInlineAssemblySeen();
2116 	CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
2117 
2118 	yul::Statement modified = bodyCopier(_inlineAsm.operations());
2119 
2120 	solAssert(holds_alternative<yul::Block>(modified), "");
2121 
2122 	// Do not provide dialect so that we get the full type information.
2123 	appendCode() << yul::AsmPrinter()(std::get<yul::Block>(modified)) << "\n";
2124 	return false;
2125 }
2126 
2127 
endVisit(IndexAccess const & _indexAccess)2128 void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
2129 {
2130 	setLocation(_indexAccess);
2131 	Type const& baseType = *_indexAccess.baseExpression().annotation().type;
2132 
2133 	if (baseType.category() == Type::Category::Mapping)
2134 	{
2135 		solAssert(_indexAccess.indexExpression(), "Index expression expected.");
2136 
2137 		MappingType const& mappingType = dynamic_cast<MappingType const&>(baseType);
2138 		Type const& keyType = *_indexAccess.indexExpression()->annotation().type;
2139 
2140 		string slot = m_context.newYulVariable();
2141 		Whiskers templ("let <slot> := <indexAccess>(<base><?+key>,<key></+key>)\n");
2142 		templ("slot", slot);
2143 		templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType));
2144 		templ("base", IRVariable(_indexAccess.baseExpression()).commaSeparatedList());
2145 		templ("key", IRVariable(*_indexAccess.indexExpression()).commaSeparatedList());
2146 		appendCode() << templ.render();
2147 		setLValue(_indexAccess, IRLValue{
2148 			*_indexAccess.annotation().type,
2149 			IRLValue::Storage{
2150 				slot,
2151 				0u
2152 			}
2153 		});
2154 	}
2155 	else if (baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice)
2156 	{
2157 		ArrayType const& arrayType =
2158 			baseType.category() == Type::Category::Array ?
2159 			dynamic_cast<ArrayType const&>(baseType) :
2160 			dynamic_cast<ArraySliceType const&>(baseType).arrayType();
2161 
2162 		if (baseType.category() == Type::Category::ArraySlice)
2163 			solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized(), "");
2164 
2165 		solAssert(_indexAccess.indexExpression(), "Index expression expected.");
2166 
2167 		switch (arrayType.location())
2168 		{
2169 			case DataLocation::Storage:
2170 			{
2171 				string slot = m_context.newYulVariable();
2172 				string offset = m_context.newYulVariable();
2173 
2174 				appendCode() << Whiskers(R"(
2175 					let <slot>, <offset> := <indexFunc>(<array>, <index>)
2176 				)")
2177 				("slot", slot)
2178 				("offset", offset)
2179 				("indexFunc", m_utils.storageArrayIndexAccessFunction(arrayType))
2180 				("array", IRVariable(_indexAccess.baseExpression()).part("slot").name())
2181 				("index", IRVariable(*_indexAccess.indexExpression()).name())
2182 				.render();
2183 
2184 				setLValue(_indexAccess, IRLValue{
2185 					*_indexAccess.annotation().type,
2186 					IRLValue::Storage{slot, offset}
2187 				});
2188 
2189 				break;
2190 			}
2191 			case DataLocation::Memory:
2192 			{
2193 				string const memAddress =
2194 					m_utils.memoryArrayIndexAccessFunction(arrayType) +
2195 					"(" +
2196 					IRVariable(_indexAccess.baseExpression()).part("mpos").name() +
2197 					", " +
2198 					expressionAsType(*_indexAccess.indexExpression(), *TypeProvider::uint256()) +
2199 					")";
2200 
2201 				setLValue(_indexAccess, IRLValue{
2202 					*arrayType.baseType(),
2203 					IRLValue::Memory{memAddress, arrayType.isByteArray()}
2204 				});
2205 				break;
2206 			}
2207 			case DataLocation::CallData:
2208 			{
2209 				string indexAccessFunction = m_utils.calldataArrayIndexAccessFunction(arrayType);
2210 				string const indexAccessFunctionCall =
2211 					indexAccessFunction +
2212 					"(" +
2213 					IRVariable(_indexAccess.baseExpression()).commaSeparatedList() +
2214 					", " +
2215 					expressionAsType(*_indexAccess.indexExpression(), *TypeProvider::uint256()) +
2216 					")";
2217 				if (arrayType.isByteArray())
2218 					define(_indexAccess) <<
2219 						m_utils.cleanupFunction(*arrayType.baseType()) <<
2220 						"(calldataload(" <<
2221 						indexAccessFunctionCall <<
2222 						"))\n";
2223 				else if (arrayType.baseType()->isValueType())
2224 					define(_indexAccess) <<
2225 						m_utils.readFromCalldata(*arrayType.baseType()) <<
2226 						"(" <<
2227 						indexAccessFunctionCall <<
2228 						")\n";
2229 				else
2230 					define(_indexAccess) << indexAccessFunctionCall << "\n";
2231 				break;
2232 			}
2233 		}
2234 	}
2235 	else if (baseType.category() == Type::Category::FixedBytes)
2236 	{
2237 		auto const& fixedBytesType = dynamic_cast<FixedBytesType const&>(baseType);
2238 		solAssert(_indexAccess.indexExpression(), "Index expression expected.");
2239 
2240 		IRVariable index{m_context.newYulVariable(), *TypeProvider::uint256()};
2241 		define(index, *_indexAccess.indexExpression());
2242 		appendCode() << Whiskers(R"(
2243 			if iszero(lt(<index>, <length>)) { <panic>() }
2244 			let <result> := <shl248>(byte(<index>, <array>))
2245 		)")
2246 		("index", index.name())
2247 		("length", to_string(fixedBytesType.numBytes()))
2248 		("panic", m_utils.panicFunction(PanicCode::ArrayOutOfBounds))
2249 		("array", IRVariable(_indexAccess.baseExpression()).name())
2250 		("shl248", m_utils.shiftLeftFunction(256 - 8))
2251 		("result", IRVariable(_indexAccess).name())
2252 		.render();
2253 	}
2254 	else if (baseType.category() == Type::Category::TypeType)
2255 	{
2256 		solAssert(baseType.sizeOnStack() == 0, "");
2257 		solAssert(_indexAccess.annotation().type->sizeOnStack() == 0, "");
2258 		// no-op - this seems to be a lone array type (`structType[];`)
2259 	}
2260 	else
2261 		solAssert(false, "Index access only allowed for mappings or arrays.");
2262 }
2263 
endVisit(IndexRangeAccess const & _indexRangeAccess)2264 void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAccess)
2265 {
2266 	setLocation(_indexRangeAccess);
2267 	Type const& baseType = *_indexRangeAccess.baseExpression().annotation().type;
2268 	solAssert(
2269 		baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice,
2270 		"Index range accesses is available only on arrays and array slices."
2271 	);
2272 
2273 	ArrayType const& arrayType =
2274 		baseType.category() == Type::Category::Array ?
2275 		dynamic_cast<ArrayType const &>(baseType) :
2276 		dynamic_cast<ArraySliceType const &>(baseType).arrayType();
2277 
2278 	switch (arrayType.location())
2279 	{
2280 		case DataLocation::CallData:
2281 		{
2282 			solAssert(baseType.isDynamicallySized(), "");
2283 			IRVariable sliceStart{m_context.newYulVariable(), *TypeProvider::uint256()};
2284 			if (_indexRangeAccess.startExpression())
2285 				define(sliceStart, IRVariable{*_indexRangeAccess.startExpression()});
2286 			else
2287 				define(sliceStart) << u256(0) << "\n";
2288 
2289 			IRVariable sliceEnd{
2290 				m_context.newYulVariable(),
2291 				*TypeProvider::uint256()
2292 			};
2293 			if (_indexRangeAccess.endExpression())
2294 				define(sliceEnd, IRVariable{*_indexRangeAccess.endExpression()});
2295 			else
2296 				define(sliceEnd, IRVariable{_indexRangeAccess.baseExpression()}.part("length"));
2297 
2298 			IRVariable range{_indexRangeAccess};
2299 			define(range) <<
2300 				m_utils.calldataArrayIndexRangeAccess(arrayType) << "(" <<
2301 				IRVariable{_indexRangeAccess.baseExpression()}.commaSeparatedList() << ", " <<
2302 				sliceStart.name() << ", " <<
2303 				sliceEnd.name() << ")\n";
2304 			break;
2305 		}
2306 		default:
2307 			solUnimplemented("Index range accesses is implemented only on calldata arrays.");
2308 	}
2309 }
2310 
endVisit(Identifier const & _identifier)2311 void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
2312 {
2313 	setLocation(_identifier);
2314 	Declaration const* declaration = _identifier.annotation().referencedDeclaration;
2315 	if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
2316 	{
2317 		switch (magicVar->type()->category())
2318 		{
2319 		case Type::Category::Contract:
2320 			solAssert(_identifier.name() == "this", "");
2321 			define(_identifier) << "address()\n";
2322 			break;
2323 		case Type::Category::Integer:
2324 			solAssert(_identifier.name() == "now", "");
2325 			define(_identifier) << "timestamp()\n";
2326 			break;
2327 		case Type::Category::TypeType:
2328 		{
2329 			auto typeType = dynamic_cast<TypeType const*>(magicVar->type());
2330 			if (auto contractType = dynamic_cast<ContractType const*>(typeType->actualType()))
2331 				solAssert(!contractType->isSuper() || _identifier.name() == "super", "");
2332 			break;
2333 		}
2334 		default:
2335 			break;
2336 		}
2337 		return;
2338 	}
2339 	else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
2340 	{
2341 		solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, "");
2342 		FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract());
2343 
2344 		solAssert(resolvedFunctionDef.functionType(true), "");
2345 		solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
2346 		assignInternalFunctionIDIfNotCalledDirectly(_identifier, resolvedFunctionDef);
2347 	}
2348 	else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
2349 		handleVariableReference(*varDecl, _identifier);
2350 	else if (auto const* contract = dynamic_cast<ContractDefinition const*>(declaration))
2351 	{
2352 		if (contract->isLibrary())
2353 			define(IRVariable(_identifier).part("address")) << linkerSymbol(*contract) << "\n";
2354 	}
2355 	else if (dynamic_cast<EventDefinition const*>(declaration))
2356 	{
2357 		// no-op
2358 	}
2359 	else if (dynamic_cast<ErrorDefinition const*>(declaration))
2360 	{
2361 		// no-op
2362 	}
2363 	else if (dynamic_cast<EnumDefinition const*>(declaration))
2364 	{
2365 		// no-op
2366 	}
2367 	else if (dynamic_cast<StructDefinition const*>(declaration))
2368 	{
2369 		// no-op
2370 	}
2371 	else if (dynamic_cast<ImportDirective const*>(declaration))
2372 	{
2373 		// no-op
2374 	}
2375 	else if (dynamic_cast<UserDefinedValueTypeDefinition const*>(declaration))
2376 	{
2377 		// no-op
2378 	}
2379 	else
2380 	{
2381 		solAssert(false, "Identifier type not expected in expression context.");
2382 	}
2383 }
2384 
visit(Literal const & _literal)2385 bool IRGeneratorForStatements::visit(Literal const& _literal)
2386 {
2387 	setLocation(_literal);
2388 	Type const& literalType = type(_literal);
2389 
2390 	switch (literalType.category())
2391 	{
2392 	case Type::Category::RationalNumber:
2393 	case Type::Category::Bool:
2394 	case Type::Category::Address:
2395 		define(_literal) << toCompactHexWithPrefix(literalType.literalValue(&_literal)) << "\n";
2396 		break;
2397 	case Type::Category::StringLiteral:
2398 		break; // will be done during conversion
2399 	default:
2400 		solUnimplemented("Only integer, boolean and string literals implemented for now.");
2401 	}
2402 	return false;
2403 }
2404 
handleVariableReference(VariableDeclaration const & _variable,Expression const & _referencingExpression)2405 void IRGeneratorForStatements::handleVariableReference(
2406 	VariableDeclaration const& _variable,
2407 	Expression const& _referencingExpression
2408 )
2409 {
2410 	if ((_variable.isStateVariable() || _variable.isFileLevelVariable()) && _variable.isConstant())
2411 		define(_referencingExpression) << constantValueFunction(_variable) << "()\n";
2412 	else if (_variable.isStateVariable() && _variable.immutable())
2413 		setLValue(_referencingExpression, IRLValue{
2414 			*_variable.annotation().type,
2415 			IRLValue::Immutable{&_variable}
2416 		});
2417 	else if (m_context.isLocalVariable(_variable))
2418 		setLValue(_referencingExpression, IRLValue{
2419 			*_variable.annotation().type,
2420 			IRLValue::Stack{m_context.localVariable(_variable)}
2421 		});
2422 	else if (m_context.isStateVariable(_variable))
2423 		setLValue(_referencingExpression, IRLValue{
2424 			*_variable.annotation().type,
2425 			IRLValue::Storage{
2426 				toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_variable).first),
2427 				m_context.storageLocationOfStateVariable(_variable).second
2428 			}
2429 		});
2430 	else
2431 		solAssert(false, "Invalid variable kind.");
2432 }
2433 
appendExternalFunctionCall(FunctionCall const & _functionCall,vector<ASTPointer<Expression const>> const & _arguments)2434 void IRGeneratorForStatements::appendExternalFunctionCall(
2435 	FunctionCall const& _functionCall,
2436 	vector<ASTPointer<Expression const>> const& _arguments
2437 )
2438 {
2439 	FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression()));
2440 	solAssert(!funType.takesArbitraryParameters(), "");
2441 	solAssert(_arguments.size() == funType.parameterTypes().size(), "");
2442 	solAssert(!funType.isBareCall(), "");
2443 	FunctionType::Kind const funKind = funType.kind();
2444 
2445 	solAssert(
2446 		funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall,
2447 		"Can only be used for regular external calls."
2448 	);
2449 
2450 	bool const isDelegateCall = funKind == FunctionType::Kind::DelegateCall;
2451 	bool const useStaticCall = funType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall();
2452 
2453 	ReturnInfo const returnInfo{m_context.evmVersion(), funType};
2454 
2455 	TypePointers parameterTypes = funType.parameterTypes();
2456 	TypePointers argumentTypes;
2457 	vector<string> argumentStrings;
2458 	if (funType.bound())
2459 	{
2460 		parameterTypes.insert(parameterTypes.begin(), funType.selfType());
2461 		argumentTypes.emplace_back(funType.selfType());
2462 		argumentStrings += IRVariable(_functionCall.expression()).part("self").stackSlots();
2463 	}
2464 
2465 	for (auto const& arg: _arguments)
2466 	{
2467 		argumentTypes.emplace_back(&type(*arg));
2468 		argumentStrings += IRVariable(*arg).stackSlots();
2469 	}
2470 
2471 
2472 	if (!m_context.evmVersion().canOverchargeGasForCall())
2473 	{
2474 		// Touch the end of the output area so that we do not pay for memory resize during the call
2475 		// (which we would have to subtract from the gas left)
2476 		// We could also just use MLOAD; POP right before the gas calculation, but the optimizer
2477 		// would remove that, so we use MSTORE here.
2478 		if (!funType.gasSet() && returnInfo.estimatedReturnSize > 0)
2479 			appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
2480 	}
2481 
2482 	Whiskers templ(R"(
2483 		<?checkExtcodesize>
2484 			if iszero(extcodesize(<address>)) { <revertNoCode>() }
2485 		</checkExtcodesize>
2486 		// storage for arguments and returned data
2487 		let <pos> := <allocateUnbounded>()
2488 		mstore(<pos>, <shl28>(<funSel>))
2489 		let <end> := <encodeArgs>(add(<pos>, 4) <argumentString>)
2490 
2491 		let <success> := <call>(<gas>, <address>, <?hasValue> <value>, </hasValue> <pos>, sub(<end>, <pos>), <pos>, <reservedReturnSize>)
2492 		<?noTryCall>
2493 			if iszero(<success>) { <forwardingRevert>() }
2494 		</noTryCall>
2495 		<?+retVars> let <retVars> </+retVars>
2496 		if <success> {
2497 			<?dynamicReturnSize>
2498 				// copy dynamic return data out
2499 				returndatacopy(<pos>, 0, returndatasize())
2500 			</dynamicReturnSize>
2501 
2502 			// update freeMemoryPointer according to dynamic return size
2503 			<finalizeAllocation>(<pos>, <returnSize>)
2504 
2505 			// decode return parameters from external try-call into retVars
2506 			<?+retVars> <retVars> := </+retVars> <abiDecode>(<pos>, add(<pos>, <returnSize>))
2507 		}
2508 	)");
2509 	templ("revertNoCode", m_utils.revertReasonIfDebugFunction("Target contract does not contain code"));
2510 
2511 	// We do not need to check extcodesize if we expect return data: If there is no
2512 	// code, the call will return empty data and the ABI decoder will revert.
2513 	size_t encodedHeadSize = 0;
2514 	for (auto const& t: returnInfo.returnTypes)
2515 		encodedHeadSize += t->decodingType()->calldataHeadSize();
2516 	bool const checkExtcodesize =
2517 		encodedHeadSize == 0 ||
2518 		!m_context.evmVersion().supportsReturndata() ||
2519 		m_context.revertStrings() >= RevertStrings::Debug;
2520 	templ("checkExtcodesize", checkExtcodesize);
2521 
2522 	templ("pos", m_context.newYulVariable());
2523 	templ("end", m_context.newYulVariable());
2524 	if (_functionCall.annotation().tryCall)
2525 		templ("success", IRNames::trySuccessConditionVariable(_functionCall));
2526 	else
2527 		templ("success", m_context.newYulVariable());
2528 	templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
2529 	templ("finalizeAllocation", m_utils.finalizeAllocationFunction());
2530 	templ("shl28", m_utils.shiftLeftFunction(8 * (32 - 4)));
2531 
2532 	templ("funSel", IRVariable(_functionCall.expression()).part("functionSelector").name());
2533 	templ("address", IRVariable(_functionCall.expression()).part("address").name());
2534 
2535 	// Always use the actual return length, and not our calculated expected length, if returndatacopy is supported.
2536 	// This ensures it can catch badly formatted input from external calls.
2537 	if (m_context.evmVersion().supportsReturndata())
2538 		templ("returnSize", "returndatasize()");
2539 	else
2540 		templ("returnSize", to_string(returnInfo.estimatedReturnSize));
2541 
2542 	templ("reservedReturnSize", returnInfo.dynamicReturnSize ? "0" : to_string(returnInfo.estimatedReturnSize));
2543 
2544 	string const retVars = IRVariable(_functionCall).commaSeparatedList();
2545 	templ("retVars", retVars);
2546 	solAssert(retVars.empty() == returnInfo.returnTypes.empty(), "");
2547 
2548 	templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true));
2549 	templ("dynamicReturnSize", returnInfo.dynamicReturnSize);
2550 
2551 	templ("noTryCall", !_functionCall.annotation().tryCall);
2552 
2553 	bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall;
2554 
2555 	solAssert(funType.padArguments(), "");
2556 	templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes, encodeForLibraryCall));
2557 	templ("argumentString", joinHumanReadablePrefixed(argumentStrings));
2558 
2559 	solAssert(!isDelegateCall || !funType.valueSet(), "Value set for delegatecall");
2560 	solAssert(!useStaticCall || !funType.valueSet(), "Value set for staticcall");
2561 
2562 	templ("hasValue", !isDelegateCall && !useStaticCall);
2563 	templ("value", funType.valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0");
2564 
2565 	if (funType.gasSet())
2566 		templ("gas", IRVariable(_functionCall.expression()).part("gas").name());
2567 	else if (m_context.evmVersion().canOverchargeGasForCall())
2568 		// Send all gas (requires tangerine whistle EVM)
2569 		templ("gas", "gas()");
2570 	else
2571 	{
2572 		// send all gas except the amount needed to execute "SUB" and "CALL"
2573 		// @todo this retains too much gas for now, needs to be fine-tuned.
2574 		u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10;
2575 		if (funType.valueSet())
2576 			gasNeededByCaller += evmasm::GasCosts::callValueTransferGas;
2577 		if (!checkExtcodesize)
2578 			gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know
2579 		templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")");
2580 	}
2581 	// Order is important here, STATICCALL might overlap with DELEGATECALL.
2582 	if (isDelegateCall)
2583 		templ("call", "delegatecall");
2584 	else if (useStaticCall)
2585 		templ("call", "staticcall");
2586 	else
2587 		templ("call", "call");
2588 
2589 	templ("forwardingRevert", m_utils.forwardingRevertFunction());
2590 
2591 	appendCode() << templ.render();
2592 }
2593 
appendBareCall(FunctionCall const & _functionCall,vector<ASTPointer<Expression const>> const & _arguments)2594 void IRGeneratorForStatements::appendBareCall(
2595 	FunctionCall const& _functionCall,
2596 	vector<ASTPointer<Expression const>> const& _arguments
2597 )
2598 {
2599 	FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression()));
2600 	solAssert(
2601 		!funType.bound() &&
2602 		!funType.takesArbitraryParameters() &&
2603 		_arguments.size() == 1 &&
2604 		funType.parameterTypes().size() == 1, ""
2605 	);
2606 	FunctionType::Kind const funKind = funType.kind();
2607 
2608 	solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), "");
2609 	solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed.");
2610 	solAssert(
2611 		funKind == FunctionType::Kind::BareCall ||
2612 		funKind == FunctionType::Kind::BareDelegateCall ||
2613 		funKind == FunctionType::Kind::BareStaticCall, ""
2614 	);
2615 
2616 	solAssert(!_functionCall.annotation().tryCall, "");
2617 	Whiskers templ(R"(
2618 		<?needsEncoding>
2619 			let <pos> := <allocateUnbounded>()
2620 			let <length> := sub(<encode>(<pos> <?+arg>,</+arg> <arg>), <pos>)
2621 		<!needsEncoding>
2622 			let <pos> := add(<arg>, 0x20)
2623 			let <length> := mload(<arg>)
2624 		</needsEncoding>
2625 
2626 		let <success> := <call>(<gas>, <address>, <?+value> <value>, </+value> <pos>, <length>, 0, 0)
2627 		let <returndataVar> := <extractReturndataFunction>()
2628 	)");
2629 
2630 	templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
2631 	templ("pos", m_context.newYulVariable());
2632 	templ("length", m_context.newYulVariable());
2633 
2634 	templ("arg", IRVariable(*_arguments.front()).commaSeparatedList());
2635 	Type const& argType = type(*_arguments.front());
2636 	if (argType == *TypeProvider::bytesMemory() || argType == *TypeProvider::stringMemory())
2637 		templ("needsEncoding", false);
2638 	else
2639 	{
2640 		templ("needsEncoding", true);
2641 		ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
2642 		templ("encode", abi.tupleEncoderPacked({&argType}, {TypeProvider::bytesMemory()}));
2643 	}
2644 
2645 	templ("success", IRVariable(_functionCall).tupleComponent(0).name());
2646 	templ("returndataVar", IRVariable(_functionCall).tupleComponent(1).commaSeparatedList());
2647 	templ("extractReturndataFunction", m_utils.extractReturndataFunction());
2648 
2649 	templ("address", IRVariable(_functionCall.expression()).part("address").name());
2650 
2651 	if (funKind == FunctionType::Kind::BareCall)
2652 	{
2653 		templ("value", funType.valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0");
2654 		templ("call", "call");
2655 	}
2656 	else
2657 	{
2658 		solAssert(!funType.valueSet(), "Value set for delegatecall or staticcall.");
2659 		templ("value", "");
2660 		if (funKind == FunctionType::Kind::BareStaticCall)
2661 			templ("call", "staticcall");
2662 		else
2663 			templ("call", "delegatecall");
2664 	}
2665 
2666 	if (funType.gasSet())
2667 		templ("gas", IRVariable(_functionCall.expression()).part("gas").name());
2668 	else if (m_context.evmVersion().canOverchargeGasForCall())
2669 		// Send all gas (requires tangerine whistle EVM)
2670 		templ("gas", "gas()");
2671 	else
2672 	{
2673 		// send all gas except the amount needed to execute "SUB" and "CALL"
2674 		// @todo this retains too much gas for now, needs to be fine-tuned.
2675 		u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10;
2676 		if (funType.valueSet())
2677 			gasNeededByCaller += evmasm::GasCosts::callValueTransferGas;
2678 		gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know
2679 		templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")");
2680 	}
2681 
2682 	appendCode() << templ.render();
2683 }
2684 
assignInternalFunctionIDIfNotCalledDirectly(Expression const & _expression,FunctionDefinition const & _referencedFunction)2685 void IRGeneratorForStatements::assignInternalFunctionIDIfNotCalledDirectly(
2686 	Expression const& _expression,
2687 	FunctionDefinition const& _referencedFunction
2688 )
2689 {
2690 	solAssert(
2691 		dynamic_cast<MemberAccess const*>(&_expression) ||
2692 		dynamic_cast<Identifier const*>(&_expression),
2693 		""
2694 	);
2695 	if (_expression.annotation().calledDirectly)
2696 		return;
2697 
2698 	define(IRVariable(_expression).part("functionIdentifier")) <<
2699 		to_string(m_context.internalFunctionID(_referencedFunction, false)) <<
2700 		"\n";
2701 	m_context.addToInternalDispatch(_referencedFunction);
2702 }
2703 
convert(IRVariable const & _from,Type const & _to)2704 IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const& _to)
2705 {
2706 	if (_from.type() == _to)
2707 		return _from;
2708 	else
2709 	{
2710 		IRVariable converted(m_context.newYulVariable(), _to);
2711 		define(converted, _from);
2712 		return converted;
2713 	}
2714 }
2715 
expressionAsType(Expression const & _expression,Type const & _to,bool _forceCleanup)2716 std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup)
2717 {
2718 	IRVariable from(_expression);
2719 	if (from.type() == _to)
2720 	{
2721 		if (_forceCleanup)
2722 			return m_utils.cleanupFunction(_to) + "(" + from.commaSeparatedList() + ")";
2723 		else
2724 			return from.commaSeparatedList();
2725 	}
2726 	else
2727 		return m_utils.conversionFunction(from.type(), _to) + "(" + from.commaSeparatedList() + ")";
2728 }
2729 
define(IRVariable const & _var)2730 std::ostream& IRGeneratorForStatements::define(IRVariable const& _var)
2731 {
2732 	if (_var.type().sizeOnStack() > 0)
2733 		appendCode() << "let " << _var.commaSeparatedList() << " := ";
2734 	return appendCode(false);
2735 }
2736 
declare(IRVariable const & _var)2737 void IRGeneratorForStatements::declare(IRVariable const& _var)
2738 {
2739 	if (_var.type().sizeOnStack() > 0)
2740 		appendCode() << "let " << _var.commaSeparatedList() << "\n";
2741 }
2742 
declareAssign(IRVariable const & _lhs,IRVariable const & _rhs,bool _declare)2743 void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare)
2744 {
2745 	string output;
2746 	if (_lhs.type() == _rhs.type())
2747 		for (auto const& [stackItemName, stackItemType]: _lhs.type().stackItems())
2748 			if (stackItemType)
2749 				declareAssign(_lhs.part(stackItemName), _rhs.part(stackItemName), _declare);
2750 			else
2751 				appendCode() << (_declare ? "let ": "") << _lhs.part(stackItemName).name() << " := " << _rhs.part(stackItemName).name() << "\n";
2752 	else
2753 	{
2754 		if (_lhs.type().sizeOnStack() > 0)
2755 			appendCode() <<
2756 				(_declare ? "let ": "") <<
2757 				_lhs.commaSeparatedList() <<
2758 				" := ";
2759 		appendCode() << m_context.utils().conversionFunction(_rhs.type(), _lhs.type()) <<
2760 			"(" <<
2761 			_rhs.commaSeparatedList() <<
2762 			")\n";
2763 	}
2764 }
2765 
zeroValue(Type const & _type,bool _splitFunctionTypes)2766 IRVariable IRGeneratorForStatements::zeroValue(Type const& _type, bool _splitFunctionTypes)
2767 {
2768 	IRVariable irVar{IRNames::zeroValue(_type, m_context.newYulVariable()), _type};
2769 	define(irVar) << m_utils.zeroValueFunction(_type, _splitFunctionTypes) << "()\n";
2770 	return irVar;
2771 }
2772 
appendSimpleUnaryOperation(UnaryOperation const & _operation,Expression const & _expr)2773 void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
2774 {
2775 	string func;
2776 
2777 	if (_operation.getOperator() == Token::Not)
2778 		func = "iszero";
2779 	else if (_operation.getOperator() == Token::BitNot)
2780 		func = "not";
2781 	else
2782 		solAssert(false, "Invalid Token!");
2783 
2784 	define(_operation) <<
2785 		m_utils.cleanupFunction(type(_expr)) <<
2786 		"(" <<
2787 			func <<
2788 			"(" <<
2789 			IRVariable(_expr).commaSeparatedList() <<
2790 			")" <<
2791 		")\n";
2792 }
2793 
binaryOperation(langutil::Token _operator,Type const & _type,string const & _left,string const & _right)2794 string IRGeneratorForStatements::binaryOperation(
2795 	langutil::Token _operator,
2796 	Type const& _type,
2797 	string const& _left,
2798 	string const& _right
2799 )
2800 {
2801 	solAssert(
2802 		!TokenTraits::isShiftOp(_operator),
2803 		"Have to use specific shift operation function for shifts."
2804 	);
2805 	string fun;
2806 	if (TokenTraits::isBitOp(_operator))
2807 	{
2808 		solAssert(
2809 			_type.category() == Type::Category::Integer ||
2810 			_type.category() == Type::Category::FixedBytes,
2811 			""
2812 		);
2813 		switch (_operator)
2814 		{
2815 		case Token::BitOr: fun = "or"; break;
2816 		case Token::BitXor: fun = "xor"; break;
2817 		case Token::BitAnd: fun = "and"; break;
2818 		default: break;
2819 		}
2820 	}
2821 	else if (TokenTraits::isArithmeticOp(_operator))
2822 	{
2823 		solUnimplementedAssert(
2824 			_type.category() != Type::Category::FixedPoint,
2825 			"Not yet implemented - FixedPointType."
2826 		);
2827 		IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
2828 		solAssert(type, "");
2829 		bool checked = m_context.arithmetic() == Arithmetic::Checked;
2830 		switch (_operator)
2831 		{
2832 		case Token::Add:
2833 			fun = checked ? m_utils.overflowCheckedIntAddFunction(*type) : m_utils.wrappingIntAddFunction(*type);
2834 			break;
2835 		case Token::Sub:
2836 			fun = checked ? m_utils.overflowCheckedIntSubFunction(*type) : m_utils.wrappingIntSubFunction(*type);
2837 			break;
2838 		case Token::Mul:
2839 			fun = checked ? m_utils.overflowCheckedIntMulFunction(*type) : m_utils.wrappingIntMulFunction(*type);
2840 			break;
2841 		case Token::Div:
2842 			fun = checked ? m_utils.overflowCheckedIntDivFunction(*type) : m_utils.wrappingIntDivFunction(*type);
2843 			break;
2844 		case Token::Mod:
2845 			fun = m_utils.intModFunction(*type);
2846 			break;
2847 		default:
2848 			break;
2849 		}
2850 	}
2851 
2852 	solUnimplementedAssert(!fun.empty(), "Type: " + _type.toString());
2853 	return fun + "(" + _left + ", " + _right + ")\n";
2854 }
2855 
shiftOperation(langutil::Token _operator,IRVariable const & _value,IRVariable const & _amountToShift)2856 std::string IRGeneratorForStatements::shiftOperation(
2857 	langutil::Token _operator,
2858 	IRVariable const& _value,
2859 	IRVariable const& _amountToShift
2860 )
2861 {
2862 	solUnimplementedAssert(
2863 		_amountToShift.type().category() != Type::Category::FixedPoint &&
2864 		_value.type().category() != Type::Category::FixedPoint,
2865 		"Not yet implemented - FixedPointType."
2866 	);
2867 	IntegerType const* amountType = dynamic_cast<IntegerType const*>(&_amountToShift.type());
2868 	solAssert(amountType, "");
2869 
2870 	solAssert(_operator == Token::SHL || _operator == Token::SAR, "");
2871 
2872 	return
2873 		Whiskers(R"(
2874 			<shift>(<value>, <amount>)
2875 		)")
2876 		("shift",
2877 			_operator == Token::SHL ?
2878 			m_utils.typedShiftLeftFunction(_value.type(), *amountType) :
2879 			m_utils.typedShiftRightFunction(_value.type(), *amountType)
2880 		)
2881 		("value", _value.name())
2882 		("amount", _amountToShift.name())
2883 		.render();
2884 }
2885 
appendAndOrOperatorCode(BinaryOperation const & _binOp)2886 void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
2887 {
2888 	langutil::Token const op = _binOp.getOperator();
2889 	solAssert(op == Token::Or || op == Token::And, "");
2890 
2891 	_binOp.leftExpression().accept(*this);
2892 	setLocation(_binOp);
2893 
2894 	IRVariable value(_binOp);
2895 	define(value, _binOp.leftExpression());
2896 	if (op == Token::Or)
2897 		appendCode() << "if iszero(" << value.name() << ") {\n";
2898 	else
2899 		appendCode() << "if " << value.name() << " {\n";
2900 	_binOp.rightExpression().accept(*this);
2901 	setLocation(_binOp);
2902 	assign(value, _binOp.rightExpression());
2903 	appendCode() << "}\n";
2904 }
2905 
writeToLValue(IRLValue const & _lvalue,IRVariable const & _value)2906 void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable const& _value)
2907 {
2908 	std::visit(
2909 		util::GenericVisitor{
2910 			[&](IRLValue::Storage const& _storage) {
2911 				string offsetArgument;
2912 				optional<unsigned> offsetStatic;
2913 
2914 				std::visit(GenericVisitor{
2915 					[&](unsigned _offset) { offsetStatic = _offset; },
2916 					[&](string const& _offset) { offsetArgument = ", " + _offset; }
2917 				}, _storage.offset);
2918 
2919 				appendCode() <<
2920 					m_utils.updateStorageValueFunction(_value.type(), _lvalue.type, offsetStatic) <<
2921 					"(" <<
2922 					_storage.slot <<
2923 					offsetArgument <<
2924 					_value.commaSeparatedListPrefixed() <<
2925 					")\n";
2926 
2927 			},
2928 			[&](IRLValue::Memory const& _memory) {
2929 				if (_lvalue.type.isValueType())
2930 				{
2931 					IRVariable prepared(m_context.newYulVariable(), _lvalue.type);
2932 					define(prepared, _value);
2933 
2934 					if (_memory.byteArrayElement)
2935 					{
2936 						solAssert(_lvalue.type == *TypeProvider::byte(), "");
2937 						appendCode() << "mstore8(" + _memory.address + ", byte(0, " + prepared.commaSeparatedList() + "))\n";
2938 					}
2939 					else
2940 						appendCode() << m_utils.writeToMemoryFunction(_lvalue.type) <<
2941 							"(" <<
2942 							_memory.address <<
2943 							", " <<
2944 							prepared.commaSeparatedList() <<
2945 							")\n";
2946 				}
2947 				else if (auto const* literalType = dynamic_cast<StringLiteralType const*>(&_value.type()))
2948 				{
2949 					string writeUInt = m_utils.writeToMemoryFunction(*TypeProvider::uint256());
2950 					appendCode() <<
2951 						writeUInt <<
2952 						"(" <<
2953 						_memory.address <<
2954 						", " <<
2955 						m_utils.copyLiteralToMemoryFunction(literalType->value()) + "()" <<
2956 						")\n";
2957 				}
2958 				else
2959 				{
2960 					solAssert(_lvalue.type.sizeOnStack() == 1, "");
2961 					auto const* valueReferenceType = dynamic_cast<ReferenceType const*>(&_value.type());
2962 					solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory), "");
2963 					appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n";
2964 				}
2965 			},
2966 			[&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); },
2967 			[&](IRLValue::Immutable const& _immutable)
2968 			{
2969 				solUnimplementedAssert(_lvalue.type.isValueType());
2970 				solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1);
2971 				solAssert(_lvalue.type == *_immutable.variable->type(), "");
2972 				size_t memOffset = m_context.immutableMemoryOffset(*_immutable.variable);
2973 
2974 				IRVariable prepared(m_context.newYulVariable(), _lvalue.type);
2975 				define(prepared, _value);
2976 
2977 				appendCode() << "mstore(" << to_string(memOffset) << ", " << prepared.commaSeparatedList() << ")\n";
2978 			},
2979 			[&](IRLValue::Tuple const& _tuple) {
2980 				auto components = std::move(_tuple.components);
2981 				for (size_t i = 0; i < components.size(); i++)
2982 				{
2983 					size_t idx = components.size() - i - 1;
2984 					if (components[idx])
2985 						writeToLValue(*components[idx], _value.tupleComponent(idx));
2986 				}
2987 			}
2988 		},
2989 		_lvalue.kind
2990 	);
2991 }
2992 
readFromLValue(IRLValue const & _lvalue)2993 IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue)
2994 {
2995 	IRVariable result{m_context.newYulVariable(), _lvalue.type};
2996 	std::visit(GenericVisitor{
2997 		[&](IRLValue::Storage const& _storage) {
2998 			if (!_lvalue.type.isValueType())
2999 				define(result) << _storage.slot << "\n";
3000 			else if (std::holds_alternative<string>(_storage.offset))
3001 				define(result) <<
3002 					m_utils.readFromStorageDynamic(_lvalue.type, true) <<
3003 					"(" <<
3004 					_storage.slot <<
3005 					", " <<
3006 					std::get<string>(_storage.offset) <<
3007 					")\n";
3008 			else
3009 				define(result) <<
3010 					m_utils.readFromStorage(_lvalue.type, std::get<unsigned>(_storage.offset), true) <<
3011 					"(" <<
3012 					_storage.slot <<
3013 					")\n";
3014 		},
3015 		[&](IRLValue::Memory const& _memory) {
3016 			if (_lvalue.type.isValueType())
3017 				define(result) <<
3018 					m_utils.readFromMemory(_lvalue.type) <<
3019 					"(" <<
3020 					_memory.address <<
3021 					")\n";
3022 			else
3023 				define(result) << "mload(" << _memory.address << ")\n";
3024 		},
3025 		[&](IRLValue::Stack const& _stack) {
3026 			define(result, _stack.variable);
3027 		},
3028 		[&](IRLValue::Immutable const& _immutable) {
3029 			solUnimplementedAssert(_lvalue.type.isValueType());
3030 			solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1);
3031 			solAssert(_lvalue.type == *_immutable.variable->type(), "");
3032 			if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation)
3033 			{
3034 				string readFunction = m_utils.readFromMemory(*_immutable.variable->type());
3035 				define(result) <<
3036 					readFunction <<
3037 					"(" <<
3038 					to_string(m_context.immutableMemoryOffset(*_immutable.variable)) <<
3039 					")\n";
3040 			}
3041 			else
3042 				define(result) << "loadimmutable(\"" << to_string(_immutable.variable->id()) << "\")\n";
3043 		},
3044 		[&](IRLValue::Tuple const&) {
3045 			solAssert(false, "Attempted to read from tuple lvalue.");
3046 		}
3047 	}, _lvalue.kind);
3048 	return result;
3049 }
3050 
setLValue(Expression const & _expression,IRLValue _lvalue)3051 void IRGeneratorForStatements::setLValue(Expression const& _expression, IRLValue _lvalue)
3052 {
3053 	solAssert(!m_currentLValue, "");
3054 
3055 	if (_expression.annotation().willBeWrittenTo)
3056 	{
3057 		m_currentLValue.emplace(std::move(_lvalue));
3058 		if (_lvalue.type.dataStoredIn(DataLocation::CallData))
3059 			solAssert(holds_alternative<IRLValue::Stack>(_lvalue.kind), "");
3060 	}
3061 	else
3062 		// Only define the expression, if it will not be written to.
3063 		define(_expression, readFromLValue(_lvalue));
3064 }
3065 
generateLoop(Statement const & _body,Expression const * _conditionExpression,Statement const * _initExpression,ExpressionStatement const * _loopExpression,bool _isDoWhile)3066 void IRGeneratorForStatements::generateLoop(
3067 	Statement const& _body,
3068 	Expression const* _conditionExpression,
3069 	Statement const*  _initExpression,
3070 	ExpressionStatement const* _loopExpression,
3071 	bool _isDoWhile
3072 )
3073 {
3074 	string firstRun;
3075 
3076 	if (_isDoWhile)
3077 	{
3078 		solAssert(_conditionExpression, "Expected condition for doWhile");
3079 		firstRun = m_context.newYulVariable();
3080 		appendCode() << "let " << firstRun << " := 1\n";
3081 	}
3082 
3083 	appendCode() << "for {\n";
3084 	if (_initExpression)
3085 		_initExpression->accept(*this);
3086 	appendCode() << "} 1 {\n";
3087 	if (_loopExpression)
3088 		_loopExpression->accept(*this);
3089 	appendCode() << "}\n";
3090 	appendCode() << "{\n";
3091 
3092 	if (_conditionExpression)
3093 	{
3094 		if (_isDoWhile)
3095 			appendCode() << "if iszero(" << firstRun << ") {\n";
3096 
3097 		_conditionExpression->accept(*this);
3098 		appendCode() <<
3099 			"if iszero(" <<
3100 			expressionAsType(*_conditionExpression, *TypeProvider::boolean()) <<
3101 			") { break }\n";
3102 
3103 		if (_isDoWhile)
3104 			appendCode() << "}\n" << firstRun << " := 0\n";
3105 	}
3106 
3107 	_body.accept(*this);
3108 
3109 	appendCode() << "}\n";
3110 }
3111 
type(Expression const & _expression)3112 Type const& IRGeneratorForStatements::type(Expression const& _expression)
3113 {
3114 	solAssert(_expression.annotation().type, "Type of expression not set.");
3115 	return *_expression.annotation().type;
3116 }
3117 
visit(TryStatement const & _tryStatement)3118 bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement)
3119 {
3120 	Expression const& externalCall = _tryStatement.externalCall();
3121 	externalCall.accept(*this);
3122 	setLocation(_tryStatement);
3123 
3124 	appendCode() << "switch iszero(" << IRNames::trySuccessConditionVariable(externalCall) << ")\n";
3125 
3126 	appendCode() << "case 0 { // success case\n";
3127 	TryCatchClause const& successClause = *_tryStatement.clauses().front();
3128 	if (successClause.parameters())
3129 	{
3130 		size_t i = 0;
3131 		for (ASTPointer<VariableDeclaration> const& varDecl: successClause.parameters()->parameters())
3132 		{
3133 			solAssert(varDecl, "");
3134 			define(m_context.addLocalVariable(*varDecl),
3135 				successClause.parameters()->parameters().size() == 1 ?
3136 				IRVariable(externalCall) :
3137 				IRVariable(externalCall).tupleComponent(i++)
3138 			);
3139 		}
3140 	}
3141 
3142 	successClause.block().accept(*this);
3143 	setLocation(_tryStatement);
3144 	appendCode() << "}\n";
3145 
3146 	appendCode() << "default { // failure case\n";
3147 	handleCatch(_tryStatement);
3148 	appendCode() << "}\n";
3149 
3150 	return false;
3151 }
3152 
handleCatch(TryStatement const & _tryStatement)3153 void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
3154 {
3155 	setLocation(_tryStatement);
3156 	string const runFallback = m_context.newYulVariable();
3157 	appendCode() << "let " << runFallback << " := 1\n";
3158 
3159 	// This function returns zero on "short returndata". We have to add a success flag
3160 	// once we implement custom error codes.
3161 	if (_tryStatement.errorClause() || _tryStatement.panicClause())
3162 		appendCode() << "switch " << m_utils.returnDataSelectorFunction() << "()\n";
3163 
3164 	if (TryCatchClause const* errorClause = _tryStatement.errorClause())
3165 	{
3166 		appendCode() << "case " << selectorFromSignature32("Error(string)") << " {\n";
3167 		setLocation(*errorClause);
3168 		string const dataVariable = m_context.newYulVariable();
3169 		appendCode() << "let " << dataVariable << " := " << m_utils.tryDecodeErrorMessageFunction() << "()\n";
3170 		appendCode() << "if " << dataVariable << " {\n";
3171 		appendCode() << runFallback << " := 0\n";
3172 		if (errorClause->parameters())
3173 		{
3174 			solAssert(errorClause->parameters()->parameters().size() == 1, "");
3175 			IRVariable const& var = m_context.addLocalVariable(*errorClause->parameters()->parameters().front());
3176 			define(var) << dataVariable << "\n";
3177 		}
3178 		errorClause->accept(*this);
3179 		setLocation(*errorClause);
3180 		appendCode() << "}\n";
3181 		setLocation(_tryStatement);
3182 		appendCode() << "}\n";
3183 	}
3184 	if (TryCatchClause const* panicClause = _tryStatement.panicClause())
3185 	{
3186 		appendCode() << "case " << selectorFromSignature32("Panic(uint256)") << " {\n";
3187 		setLocation(*panicClause);
3188 		string const success = m_context.newYulVariable();
3189 		string const code = m_context.newYulVariable();
3190 		appendCode() << "let " << success << ", " << code << " := " << m_utils.tryDecodePanicDataFunction() << "()\n";
3191 		appendCode() << "if " << success << " {\n";
3192 		appendCode() << runFallback << " := 0\n";
3193 		if (panicClause->parameters())
3194 		{
3195 			solAssert(panicClause->parameters()->parameters().size() == 1, "");
3196 			IRVariable const& var = m_context.addLocalVariable(*panicClause->parameters()->parameters().front());
3197 			define(var) << code << "\n";
3198 		}
3199 		panicClause->accept(*this);
3200 		setLocation(*panicClause);
3201 		appendCode() << "}\n";
3202 		setLocation(_tryStatement);
3203 		appendCode() << "}\n";
3204 	}
3205 
3206 	setLocation(_tryStatement);
3207 	appendCode() << "if " << runFallback << " {\n";
3208 	if (_tryStatement.fallbackClause())
3209 		handleCatchFallback(*_tryStatement.fallbackClause());
3210 	else
3211 		appendCode() << m_utils.forwardingRevertFunction() << "()\n";
3212 	setLocation(_tryStatement);
3213 	appendCode() << "}\n";
3214 }
3215 
handleCatchFallback(TryCatchClause const & _fallback)3216 void IRGeneratorForStatements::handleCatchFallback(TryCatchClause const& _fallback)
3217 {
3218 	setLocation(_fallback);
3219 	if (_fallback.parameters())
3220 	{
3221 		solAssert(m_context.evmVersion().supportsReturndata(), "");
3222 		solAssert(
3223 			_fallback.parameters()->parameters().size() == 1 &&
3224 			_fallback.parameters()->parameters().front() &&
3225 			*_fallback.parameters()->parameters().front()->annotation().type == *TypeProvider::bytesMemory(),
3226 			""
3227 		);
3228 
3229 		VariableDeclaration const& paramDecl = *_fallback.parameters()->parameters().front();
3230 		define(m_context.addLocalVariable(paramDecl)) << m_utils.extractReturndataFunction() << "()\n";
3231 	}
3232 	_fallback.accept(*this);
3233 }
3234 
revertWithError(string const & _signature,vector<Type const * > const & _parameterTypes,vector<ASTPointer<Expression const>> const & _errorArguments)3235 void IRGeneratorForStatements::revertWithError(
3236 	string const& _signature,
3237 	vector<Type const*> const& _parameterTypes,
3238 	vector<ASTPointer<Expression const>> const& _errorArguments
3239 )
3240 {
3241 	Whiskers templ(R"({
3242 		let <pos> := <allocateUnbounded>()
3243 		mstore(<pos>, <hash>)
3244 		let <end> := <encode>(add(<pos>, 4) <argumentVars>)
3245 		revert(<pos>, sub(<end>, <pos>))
3246 	})");
3247 	templ("pos", m_context.newYulVariable());
3248 	templ("end", m_context.newYulVariable());
3249 	templ("hash", util::selectorFromSignature(_signature).str());
3250 	templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
3251 
3252 	vector<string> errorArgumentVars;
3253 	vector<Type const*> errorArgumentTypes;
3254 	for (ASTPointer<Expression const> const& arg: _errorArguments)
3255 	{
3256 		errorArgumentVars += IRVariable(*arg).stackSlots();
3257 		solAssert(arg->annotation().type, "");
3258 		errorArgumentTypes.push_back(arg->annotation().type);
3259 	}
3260 	templ("argumentVars", joinHumanReadablePrefixed(errorArgumentVars));
3261 	templ("encode", m_context.abiFunctions().tupleEncoder(errorArgumentTypes, _parameterTypes));
3262 
3263 	appendCode() << templ.render();
3264 }
3265 
3266 
visit(TryCatchClause const & _clause)3267 bool IRGeneratorForStatements::visit(TryCatchClause const& _clause)
3268 {
3269 	_clause.block().accept(*this);
3270 	return false;
3271 }
3272 
linkerSymbol(ContractDefinition const & _library) const3273 string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const
3274 {
3275 	solAssert(_library.isLibrary(), "");
3276 	return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")";
3277 }
3278