2015-09-16 14:56:30 +00:00
/*
2016-11-18 23:13:20 +00:00
This file is part of solidity .
2015-09-16 14:56:30 +00:00
2016-11-18 23:13:20 +00:00
solidity is free software : you can redistribute it and / or modify
2015-09-16 14:56:30 +00:00
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
2016-11-18 23:13:20 +00:00
solidity is distributed in the hope that it will be useful ,
2015-09-16 14:56:30 +00:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2016-11-18 23:13:20 +00:00
along with solidity . If not , see < http : //www.gnu.org/licenses/>.
2015-09-16 14:56:30 +00:00
*/
/**
* @ author Christian < c @ ethdev . com >
* @ date 2015
* Type analyzer and checker .
*/
2015-10-20 22:21:52 +00:00
# include <libsolidity/analysis/TypeChecker.h>
# include <libsolidity/ast/AST.h>
2019-12-03 00:02:33 +00:00
# include <libsolidity/ast/ASTUtils.h>
2019-04-15 13:33:39 +00:00
# include <libsolidity/ast/TypeProvider.h>
2018-11-28 11:17:30 +00:00
2018-11-23 10:18:57 +00:00
# include <libyul/AsmAnalysis.h>
# include <libyul/AsmAnalysisInfo.h>
# include <libyul/AsmData.h>
2018-12-06 23:56:16 +00:00
2018-11-14 13:59:30 +00:00
# include <liblangutil/ErrorReporter.h>
2018-11-28 11:17:30 +00:00
2020-01-06 10:52:23 +00:00
# include <libsolutil/Algorithms.h>
# include <libsolutil/StringUtils.h>
2018-11-28 11:17:30 +00:00
# include <boost/algorithm/cxx11/all_of.hpp>
# include <boost/algorithm/string/join.hpp>
2018-12-17 11:30:08 +00:00
# include <boost/algorithm/string/predicate.hpp>
2018-11-28 11:17:30 +00:00
# include <memory>
# include <vector>
2015-09-16 14:56:30 +00:00
using namespace std ;
2019-12-11 16:31:36 +00:00
using namespace solidity ;
using namespace solidity : : util ;
using namespace solidity : : langutil ;
using namespace solidity : : frontend ;
2015-09-16 14:56:30 +00:00
2019-03-04 13:33:46 +00:00
bool TypeChecker : : typeSupportedByOldABIEncoder ( Type const & _type , bool _isLibraryCall )
2018-02-19 17:21:02 +00:00
{
2019-02-04 17:13:41 +00:00
if ( _isLibraryCall & & _type . dataStoredIn ( DataLocation : : Storage ) )
2018-02-19 17:21:02 +00:00
return true ;
2018-06-14 18:19:36 +00:00
if ( _type . category ( ) = = Type : : Category : : Struct )
2018-02-19 17:21:02 +00:00
return false ;
2018-06-14 18:19:36 +00:00
if ( _type . category ( ) = = Type : : Category : : Array )
2018-02-19 17:21:02 +00:00
{
auto const & arrayType = dynamic_cast < ArrayType const & > ( _type ) ;
auto base = arrayType . baseType ( ) ;
2019-02-04 17:13:41 +00:00
if ( ! typeSupportedByOldABIEncoder ( * base , _isLibraryCall ) | | ( base - > category ( ) = = Type : : Category : : Array & & base - > isDynamicallySized ( ) ) )
2018-02-19 17:21:02 +00:00
return false ;
}
return true ;
}
2017-01-27 22:29:03 +00:00
bool TypeChecker : : checkTypeRequirements ( ASTNode const & _contract )
2015-09-16 14:56:30 +00:00
{
2018-04-05 12:23:36 +00:00
_contract . accept ( * this ) ;
2017-05-11 13:26:35 +00:00
return Error : : containsOnlyWarnings ( m_errorReporter . errors ( ) ) ;
2015-09-16 14:56:30 +00:00
}
TypePointer const & TypeChecker : : type ( Expression const & _expression ) const
{
solAssert ( ! ! _expression . annotation ( ) . type , " Type requested but not present. " ) ;
return _expression . annotation ( ) . type ;
}
TypePointer const & TypeChecker : : type ( VariableDeclaration const & _variable ) const
{
solAssert ( ! ! _variable . annotation ( ) . type , " Type requested but not present. " ) ;
return _variable . annotation ( ) . type ;
}
bool TypeChecker : : visit ( ContractDefinition const & _contract )
{
2015-11-19 17:02:04 +00:00
m_scope = & _contract ;
2015-09-16 14:56:30 +00:00
ASTNode : : listAccept ( _contract . baseContracts ( ) , * this ) ;
2017-03-21 14:05:59 +00:00
for ( auto const & n : _contract . subNodes ( ) )
2018-11-29 17:18:17 +00:00
n - > accept ( * this ) ;
2015-09-16 14:56:30 +00:00
return false ;
}
2017-06-21 17:32:56 +00:00
void TypeChecker : : checkDoubleStorageAssignment ( Assignment const & _assignment )
{
TupleType const & lhs = dynamic_cast < TupleType const & > ( * type ( _assignment . leftHandSide ( ) ) ) ;
TupleType const & rhs = dynamic_cast < TupleType const & > ( * type ( _assignment . rightHandSide ( ) ) ) ;
2018-08-07 16:44:51 +00:00
if ( lhs . components ( ) . size ( ) ! = rhs . components ( ) . size ( ) )
{
solAssert ( m_errorReporter . hasErrors ( ) , " " ) ;
return ;
}
2017-06-21 17:32:56 +00:00
size_t storageToStorageCopies = 0 ;
size_t toStorageCopies = 0 ;
for ( size_t i = 0 ; i < lhs . components ( ) . size ( ) ; + + i )
{
2019-04-15 13:33:39 +00:00
ReferenceType const * ref = dynamic_cast < ReferenceType const * > ( lhs . components ( ) [ i ] ) ;
2017-06-21 17:32:56 +00:00
if ( ! ref | | ! ref - > dataStoredIn ( DataLocation : : Storage ) | | ref - > isPointer ( ) )
continue ;
toStorageCopies + + ;
2018-08-07 16:44:51 +00:00
if ( rhs . components ( ) [ i ] - > dataStoredIn ( DataLocation : : Storage ) )
2017-06-21 17:32:56 +00:00
storageToStorageCopies + + ;
}
if ( storageToStorageCopies > = 1 & & toStorageCopies > = 2 )
m_errorReporter . warning (
_assignment . location ( ) ,
" This assignment performs two copies to storage. Since storage copies do not first "
" copy to a temporary location, one of them might be overwritten before the second "
" is executed and thus may have unexpected effects. It is safer to perform the copies "
" separately or assign to storage pointers first. "
) ;
}
2018-09-04 14:24:21 +00:00
TypePointers TypeChecker : : typeCheckABIDecodeAndRetrieveReturnType ( FunctionCall const & _functionCall , bool _abiEncoderV2 )
2018-06-30 16:09:13 +00:00
{
vector < ASTPointer < Expression const > > arguments = _functionCall . arguments ( ) ;
if ( arguments . size ( ) ! = 2 )
m_errorReporter . typeError (
_functionCall . location ( ) ,
" This function takes two arguments, but " +
toString ( arguments . size ( ) ) +
" were provided. "
) ;
2019-03-04 17:59:03 +00:00
if ( arguments . size ( ) > = 1 )
2019-09-03 16:30:00 +00:00
if (
! type ( * arguments . front ( ) ) - > isImplicitlyConvertibleTo ( * TypeProvider : : bytesMemory ( ) ) & &
! type ( * arguments . front ( ) ) - > isImplicitlyConvertibleTo ( * TypeProvider : : bytesCalldata ( ) )
)
m_errorReporter . typeError (
2019-03-04 17:59:03 +00:00
arguments . front ( ) - > location ( ) ,
2019-09-03 16:30:00 +00:00
" The first argument to \" abi.decode \" must be implicitly convertible to "
" bytes memory or bytes calldata, but is of type " +
2019-03-04 17:59:03 +00:00
type ( * arguments . front ( ) ) - > toString ( ) +
2019-09-03 16:30:00 +00:00
" . "
2019-03-04 17:59:03 +00:00
) ;
2018-06-30 16:09:13 +00:00
if ( arguments . size ( ) < 2 )
2018-09-04 14:24:21 +00:00
return { } ;
2018-06-30 16:09:13 +00:00
// The following is a rather syntactic restriction, but we check it here anyway:
// The second argument has to be a tuple expression containing type names.
TupleExpression const * tupleExpression = dynamic_cast < TupleExpression const * > ( arguments [ 1 ] . get ( ) ) ;
if ( ! tupleExpression )
{
m_errorReporter . typeError (
arguments [ 1 ] - > location ( ) ,
" The second argument to \" abi.decode \" has to be a tuple of types. "
) ;
2018-09-04 14:24:21 +00:00
return { } ;
2018-06-30 16:09:13 +00:00
}
2018-09-04 14:24:21 +00:00
TypePointers components ;
2018-06-30 16:09:13 +00:00
for ( auto const & typeArgument : tupleExpression - > components ( ) )
{
solAssert ( typeArgument , " " ) ;
2019-04-15 13:33:39 +00:00
if ( TypeType const * argTypeType = dynamic_cast < TypeType const * > ( type ( * typeArgument ) ) )
2018-06-30 16:09:13 +00:00
{
TypePointer actualType = argTypeType - > actualType ( ) ;
solAssert ( actualType , " " ) ;
// We force memory because the parser currently cannot handle
// data locations. Furthermore, storage can be a little dangerous and
// calldata is not really implemented anyway.
2019-04-15 13:33:39 +00:00
actualType = TypeProvider : : withLocationIfReference ( DataLocation : : Memory , actualType ) ;
2018-09-05 15:59:55 +00:00
// We force address payable for address types.
if ( actualType - > category ( ) = = Type : : Category : : Address )
2019-04-17 11:40:50 +00:00
actualType = TypeProvider : : payableAddress ( ) ;
2018-06-30 16:09:13 +00:00
solAssert (
! actualType - > dataStoredIn ( DataLocation : : CallData ) & &
! actualType - > dataStoredIn ( DataLocation : : Storage ) ,
" "
) ;
if ( ! actualType - > fullEncodingType ( false , _abiEncoderV2 , false ) )
m_errorReporter . typeError (
typeArgument - > location ( ) ,
2018-10-18 21:53:59 +00:00
" Decoding type " + actualType - > toString ( false ) + " not supported. "
2018-06-30 16:09:13 +00:00
) ;
components . push_back ( actualType ) ;
}
else
{
m_errorReporter . typeError ( typeArgument - > location ( ) , " Argument has to be a type name. " ) ;
2019-04-17 11:40:50 +00:00
components . push_back ( TypeProvider : : emptyTuple ( ) ) ;
2018-06-30 16:09:13 +00:00
}
}
2018-09-04 14:24:21 +00:00
return components ;
2018-06-30 16:09:13 +00:00
}
2019-01-10 15:28:39 +00:00
TypePointers TypeChecker : : typeCheckMetaTypeFunctionAndRetrieveReturnType ( FunctionCall const & _functionCall )
{
vector < ASTPointer < Expression const > > arguments = _functionCall . arguments ( ) ;
if ( arguments . size ( ) ! = 1 )
{
m_errorReporter . typeError (
_functionCall . location ( ) ,
" This function takes one argument, but " +
toString ( arguments . size ( ) ) +
" were provided. "
) ;
return { } ;
}
TypePointer firstArgType = type ( * arguments . front ( ) ) ;
if (
firstArgType - > category ( ) ! = Type : : Category : : TypeType | |
dynamic_cast < TypeType const & > ( * firstArgType ) . actualType ( ) - > category ( ) ! = TypeType : : Category : : Contract
)
{
m_errorReporter . typeError (
arguments . front ( ) - > location ( ) ,
" Invalid type for argument in function call. "
" Contract type required, but " +
type ( * arguments . front ( ) ) - > toString ( true ) +
" provided. "
) ;
return { } ;
}
2019-04-17 11:40:50 +00:00
return { TypeProvider : : meta ( dynamic_cast < TypeType const & > ( * firstArgType ) . actualType ( ) ) } ;
2019-01-10 15:28:39 +00:00
}
2015-09-16 14:56:30 +00:00
void TypeChecker : : endVisit ( InheritanceSpecifier const & _inheritance )
{
auto base = dynamic_cast < ContractDefinition const * > ( & dereference ( _inheritance . name ( ) ) ) ;
solAssert ( base , " Base contract not available. " ) ;
2020-01-02 21:32:35 +00:00
if ( m_scope - > isInterface ( ) & & ! base - > isInterface ( ) )
m_errorReporter . typeError ( _inheritance . location ( ) , " Interfaces can only inherit from other interfaces. " ) ;
2015-09-16 14:56:30 +00:00
if ( base - > isLibrary ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _inheritance . location ( ) , " Libraries cannot be inherited from. " ) ;
2015-09-16 14:56:30 +00:00
auto const & arguments = _inheritance . arguments ( ) ;
2017-08-21 14:43:15 +00:00
TypePointers parameterTypes ;
2019-01-17 11:59:11 +00:00
if ( ! base - > isInterface ( ) )
2017-08-21 14:43:15 +00:00
// Interfaces do not have constructors, so there are zero parameters.
parameterTypes = ContractType ( * base ) . newExpressionType ( ) - > parameterTypes ( ) ;
2018-04-04 18:53:23 +00:00
if ( arguments )
2015-12-09 16:37:19 +00:00
{
2018-04-04 18:53:23 +00:00
if ( parameterTypes . size ( ) ! = arguments - > size ( ) )
{
2018-07-06 20:53:55 +00:00
m_errorReporter . typeError (
_inheritance . location ( ) ,
" Wrong argument count for constructor call: " +
toString ( arguments - > size ( ) ) +
" arguments given but expected " +
toString ( parameterTypes . size ( ) ) +
2018-07-10 23:44:51 +00:00
" . Remove parentheses if you do not want to provide arguments here. "
2018-07-06 20:53:55 +00:00
) ;
2018-04-04 18:53:23 +00:00
}
2018-07-10 10:05:41 +00:00
for ( size_t i = 0 ; i < std : : min ( arguments - > size ( ) , parameterTypes . size ( ) ) ; + + i )
2019-03-04 17:59:03 +00:00
{
BoolResult result = type ( * ( * arguments ) [ i ] ) - > isImplicitlyConvertibleTo ( * parameterTypes [ i ] ) ;
if ( ! result )
m_errorReporter . typeErrorConcatenateDescriptions (
2018-04-04 18:53:23 +00:00
( * arguments ) [ i ] - > location ( ) ,
" Invalid type for argument in constructor call. "
" Invalid implicit conversion from " +
type ( * ( * arguments ) [ i ] ) - > toString ( ) +
" to " +
parameterTypes [ i ] - > toString ( ) +
2019-03-04 17:59:03 +00:00
" requested. " ,
result . message ( )
2018-04-04 18:53:23 +00:00
) ;
2019-03-04 17:59:03 +00:00
}
2018-04-04 18:53:23 +00:00
}
2015-11-22 19:39:10 +00:00
}
void TypeChecker : : endVisit ( UsingForDirective const & _usingFor )
{
ContractDefinition const * library = dynamic_cast < ContractDefinition const * > (
_usingFor . libraryName ( ) . annotation ( ) . referencedDeclaration
) ;
if ( ! library | | ! library - > isLibrary ( ) )
2017-08-21 14:22:20 +00:00
m_errorReporter . fatalTypeError ( _usingFor . libraryName ( ) . location ( ) , " Library name expected. " ) ;
2015-09-16 14:56:30 +00:00
}
bool TypeChecker : : visit ( StructDefinition const & _struct )
{
for ( ASTPointer < VariableDeclaration > const & member : _struct . members ( ) )
2019-02-06 12:11:04 +00:00
solAssert ( type ( * member ) - > canBeStored ( ) , " Type cannot be used in struct. " ) ;
2015-09-16 14:56:30 +00:00
// Check recursion, fatal error if detected.
2018-07-31 14:18:00 +00:00
auto visitor = [ & ] ( StructDefinition const & _struct , CycleDetector < StructDefinition > & _cycleDetector , size_t _depth )
2015-09-16 14:56:30 +00:00
{
2018-07-31 14:18:00 +00:00
if ( _depth > = 256 )
m_errorReporter . fatalDeclarationError ( _struct . location ( ) , " Struct definition exhausting cyclic dependency validator. " ) ;
2018-07-12 18:11:32 +00:00
for ( ASTPointer < VariableDeclaration > const & member : _struct . members ( ) )
{
2019-04-15 13:33:39 +00:00
Type const * memberType = type ( * member ) ;
2018-07-12 18:11:32 +00:00
while ( auto arrayType = dynamic_cast < ArrayType const * > ( memberType ) )
2015-09-16 14:56:30 +00:00
{
2018-07-12 18:11:32 +00:00
if ( arrayType - > isDynamicallySized ( ) )
break ;
2019-04-15 13:33:39 +00:00
memberType = arrayType - > baseType ( ) ;
2015-09-16 14:56:30 +00:00
}
2018-07-12 18:11:32 +00:00
if ( auto structType = dynamic_cast < StructType const * > ( memberType ) )
if ( _cycleDetector . run ( structType - > structDefinition ( ) ) )
return ;
}
2015-09-16 14:56:30 +00:00
} ;
2018-07-12 18:11:32 +00:00
if ( CycleDetector < StructDefinition > ( visitor ) . run ( _struct ) ! = nullptr )
m_errorReporter . fatalTypeError ( _struct . location ( ) , " Recursive struct definition. " ) ;
2015-09-16 14:56:30 +00:00
ASTNode : : listAccept ( _struct . members ( ) , * this ) ;
return false ;
}
bool TypeChecker : : visit ( FunctionDefinition const & _function )
{
2020-01-07 14:11:29 +00:00
bool isLibraryFunction = _function . inContractKind ( ) = = ContractKind : : Library ;
2019-09-09 16:22:02 +00:00
2019-11-27 13:02:52 +00:00
if ( _function . markedVirtual ( ) )
{
if ( _function . annotation ( ) . contract - > isInterface ( ) )
m_errorReporter . warning ( _function . location ( ) , " Interface functions are implicitly \" virtual \" " ) ;
2019-12-10 14:54:09 +00:00
if ( _function . visibility ( ) = = Visibility : : Private )
2019-11-27 13:02:52 +00:00
m_errorReporter . typeError ( _function . location ( ) , " \" virtual \" and \" private \" cannot be used together. " ) ;
}
2019-11-05 17:25:34 +00:00
2016-08-26 18:37:10 +00:00
if ( _function . isPayable ( ) )
{
if ( isLibraryFunction )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Library functions cannot be payable. " ) ;
2019-09-09 16:22:02 +00:00
if ( _function . isOrdinary ( ) & & ! _function . isPartOfExternalInterface ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Internal functions cannot be payable. " ) ;
2016-08-26 18:37:10 +00:00
}
2019-01-17 15:37:36 +00:00
auto checkArgumentAndReturnParameter = [ & ] ( VariableDeclaration const & var ) {
if ( type ( var ) - > category ( ) = = Type : : Category : : Mapping )
2018-11-08 10:22:57 +00:00
{
2019-02-05 14:51:19 +00:00
if ( var . referenceLocation ( ) ! = VariableDeclaration : : Location : : Storage )
{
if ( ! isLibraryFunction & & _function . isPublic ( ) )
m_errorReporter . typeError ( var . location ( ) , " Mapping types can only have a data location of \" storage \" and thus only be parameters or return variables for internal or library functions. " ) ;
else
m_errorReporter . typeError ( var . location ( ) , " Mapping types can only have a data location of \" storage \" . " ) ;
}
else
{
solAssert ( isLibraryFunction | | ! _function . isPublic ( ) , " Mapping types for parameters or return variables can only be used in internal or library functions. " ) ;
}
2018-11-08 10:22:57 +00:00
}
else
{
2019-01-17 15:37:36 +00:00
if ( ! type ( var ) - > canLiveOutsideStorage ( ) & & _function . isPublic ( ) )
m_errorReporter . typeError ( var . location ( ) , " Type is required to live outside storage. " ) ;
2019-03-07 16:12:10 +00:00
if ( _function . isPublic ( ) )
{
auto iType = type ( var ) - > interfaceType ( isLibraryFunction ) ;
2019-04-15 13:33:39 +00:00
if ( ! iType )
2019-03-07 16:12:10 +00:00
{
solAssert ( ! iType . message ( ) . empty ( ) , " Expected detailed error message! " ) ;
m_errorReporter . fatalTypeError ( var . location ( ) , iType . message ( ) ) ;
}
}
2018-11-08 10:22:57 +00:00
}
2018-08-10 13:13:12 +00:00
if (
2018-11-08 10:22:57 +00:00
_function . isPublic ( ) & &
2018-02-19 17:21:02 +00:00
! _function . sourceUnit ( ) . annotation ( ) . experimentalFeatures . count ( ExperimentalFeature : : ABIEncoderV2 ) & &
2019-02-04 17:13:41 +00:00
! typeSupportedByOldABIEncoder ( * type ( var ) , isLibraryFunction )
2017-12-02 01:01:55 +00:00
)
m_errorReporter . typeError (
2019-01-17 15:37:36 +00:00
var . location ( ) ,
2019-12-11 16:05:44 +00:00
" This type is only supported in ABIEncoderV2. "
2017-12-02 01:01:55 +00:00
" Use \" pragma experimental ABIEncoderV2; \" to enable the feature. "
) ;
2019-01-17 15:37:36 +00:00
} ;
for ( ASTPointer < VariableDeclaration > const & var : _function . parameters ( ) )
{
checkArgumentAndReturnParameter ( * var ) ;
var - > accept ( * this ) ;
}
for ( ASTPointer < VariableDeclaration > const & var : _function . returnParameters ( ) )
{
checkArgumentAndReturnParameter ( * var ) ;
2017-06-15 15:36:14 +00:00
var - > accept ( * this ) ;
2015-09-16 14:56:30 +00:00
}
2017-06-23 16:55:47 +00:00
set < Declaration const * > modifiers ;
2015-09-16 14:56:30 +00:00
for ( ASTPointer < ModifierInvocation > const & modifier : _function . modifiers ( ) )
2017-06-23 16:55:47 +00:00
{
2019-10-22 10:26:26 +00:00
auto baseContracts = dynamic_cast < ContractDefinition const & > ( * _function . scope ( ) ) . annotation ( ) . linearizedBaseContracts ;
// Delete first base which is just the main contract itself
baseContracts . erase ( baseContracts . begin ( ) ) ;
2015-09-16 14:56:30 +00:00
visitManually (
* modifier ,
2019-10-22 10:26:26 +00:00
_function . isConstructor ( ) ? baseContracts : vector < ContractDefinition const * > ( )
2015-09-16 14:56:30 +00:00
) ;
2017-06-23 16:55:47 +00:00
Declaration const * decl = & dereference ( * modifier - > name ( ) ) ;
if ( modifiers . count ( decl ) )
{
if ( dynamic_cast < ContractDefinition const * > ( decl ) )
m_errorReporter . declarationError ( modifier - > location ( ) , " Base constructor already provided. " ) ;
}
else
modifiers . insert ( decl ) ;
}
2019-01-17 11:59:11 +00:00
if ( m_scope - > isInterface ( ) )
2017-02-07 22:13:03 +00:00
{
2017-03-17 17:01:13 +00:00
if ( _function . isImplemented ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Functions in interfaces cannot have an implementation. " ) ;
2018-07-12 12:57:42 +00:00
2019-12-10 14:54:09 +00:00
if ( _function . visibility ( ) ! = Visibility : : External )
2018-07-12 12:57:42 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Functions in interfaces must be declared external. " ) ;
2017-03-17 17:01:13 +00:00
if ( _function . isConstructor ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Constructor cannot be defined in interfaces. " ) ;
2017-03-17 17:01:13 +00:00
}
2020-01-07 14:11:29 +00:00
else if ( m_scope - > contractKind ( ) = = ContractKind : : Library )
2017-08-16 21:19:08 +00:00
if ( _function . isConstructor ( ) )
m_errorReporter . typeError ( _function . location ( ) , " Constructor cannot be defined in libraries. " ) ;
2017-03-17 17:01:13 +00:00
if ( _function . isImplemented ( ) )
_function . body ( ) . accept ( * this ) ;
2017-08-04 19:38:45 +00:00
else if ( _function . isConstructor ( ) )
m_errorReporter . typeError ( _function . location ( ) , " Constructor must be implemented if declared. " ) ;
2019-11-04 13:12:58 +00:00
else if ( isLibraryFunction )
m_errorReporter . typeError ( _function . location ( ) , " Library functions must be implemented if declared. " ) ;
2019-12-02 20:39:53 +00:00
else if ( ! _function . virtualSemantics ( ) )
m_errorReporter . typeError ( _function . location ( ) , " Functions without implementation must be marked virtual. " ) ;
2019-09-09 16:22:02 +00:00
if ( _function . isFallback ( ) )
typeCheckFallbackFunction ( _function ) ;
else if ( _function . isReceive ( ) )
typeCheckReceiveFunction ( _function ) ;
else if ( _function . isConstructor ( ) )
typeCheckConstructor ( _function ) ;
2015-09-16 14:56:30 +00:00
return false ;
}
bool TypeChecker : : visit ( VariableDeclaration const & _variable )
{
2019-02-27 10:55:59 +00:00
if ( _variable . typeName ( ) )
_variable . typeName ( ) - > accept ( * this ) ;
2015-10-08 16:01:12 +00:00
// type is filled either by ReferencesResolver directly from the type name or by
// TypeChecker at the VariableDeclarationStatement level.
2015-09-16 14:56:30 +00:00
TypePointer varType = _variable . annotation ( ) . type ;
2018-11-28 10:48:51 +00:00
solAssert ( ! ! varType , " Variable type not provided. " ) ;
2018-07-12 14:17:30 +00:00
2019-11-14 11:48:15 +00:00
if ( auto contractType = dynamic_cast < ContractType const * > ( varType ) )
if ( contractType - > contractDefinition ( ) . isLibrary ( ) )
m_errorReporter . typeError ( _variable . location ( ) , " The type of a variable cannot be a library. " ) ;
2017-03-01 18:12:40 +00:00
if ( _variable . value ( ) )
expectType ( * _variable . value ( ) , * varType ) ;
2015-09-16 14:56:30 +00:00
if ( _variable . isConstant ( ) )
{
2017-03-03 18:26:54 +00:00
if ( ! _variable . type ( ) - > isValueType ( ) )
{
bool allowed = false ;
2019-04-15 13:33:39 +00:00
if ( auto arrayType = dynamic_cast < ArrayType const * > ( _variable . type ( ) ) )
2017-09-18 10:31:55 +00:00
allowed = arrayType - > isByteArray ( ) ;
2017-03-03 18:26:54 +00:00
if ( ! allowed )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Constants of non-value type not yet implemented. " ) ;
2017-03-03 18:26:54 +00:00
}
2017-07-08 23:27:28 +00:00
2015-09-16 14:56:30 +00:00
if ( ! _variable . value ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Uninitialized \" constant \" variable. " ) ;
2017-03-01 18:12:40 +00:00
else if ( ! _variable . value ( ) - > annotation ( ) . isPure )
2018-07-03 21:03:26 +00:00
m_errorReporter . typeError (
_variable . value ( ) - > location ( ) ,
" Initial value for constant variable has to be compile-time constant. "
) ;
2015-09-16 14:56:30 +00:00
}
2020-02-27 15:13:55 +00:00
else if ( _variable . immutable ( ) )
if ( ! _variable . type ( ) - > isValueType ( ) )
m_errorReporter . typeError ( _variable . location ( ) , " Immutable variables cannot have a non-value type. " ) ;
2015-09-16 14:56:30 +00:00
if ( ! _variable . isStateVariable ( ) )
{
if ( varType - > dataStoredIn ( DataLocation : : Memory ) | | varType - > dataStoredIn ( DataLocation : : CallData ) )
if ( ! varType - > canLiveOutsideStorage ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Type " + varType - > toString ( ) + " is only valid in storage. " ) ;
2015-09-16 14:56:30 +00:00
}
2019-12-10 14:54:09 +00:00
else if ( _variable . visibility ( ) > = Visibility : : Public )
2018-11-28 11:17:30 +00:00
{
FunctionType getter ( _variable ) ;
if ( ! _variable . sourceUnit ( ) . annotation ( ) . experimentalFeatures . count ( ExperimentalFeature : : ABIEncoderV2 ) )
{
vector < string > unsupportedTypes ;
for ( auto const & param : getter . parameterTypes ( ) + getter . returnParameterTypes ( ) )
2019-02-04 17:13:41 +00:00
if ( ! typeSupportedByOldABIEncoder ( * param , false /* isLibrary */ ) )
2018-11-28 11:17:30 +00:00
unsupportedTypes . emplace_back ( param - > toString ( ) ) ;
if ( ! unsupportedTypes . empty ( ) )
m_errorReporter . typeError ( _variable . location ( ) ,
2019-12-11 16:05:44 +00:00
" The following types are only supported for getters in ABIEncoderV2: " +
2018-11-28 11:17:30 +00:00
joinHumanReadable ( unsupportedTypes ) +
" . Either remove \" public \" or use \" pragma experimental ABIEncoderV2; \" to enable the feature. "
) ;
}
if ( ! getter . interfaceFunctionType ( ) )
m_errorReporter . typeError ( _variable . location ( ) , " Internal or recursive type is not allowed for public state variables. " ) ;
}
2017-07-11 20:56:09 +00:00
2018-07-31 09:44:39 +00:00
switch ( varType - > category ( ) )
{
case Type : : Category : : Array :
2019-04-15 13:33:39 +00:00
if ( auto arrayType = dynamic_cast < ArrayType const * > ( varType ) )
2017-07-13 15:02:10 +00:00
if (
( ( arrayType - > location ( ) = = DataLocation : : Memory ) | |
( arrayType - > location ( ) = = DataLocation : : CallData ) ) & &
! arrayType - > validForCalldata ( )
)
2017-09-05 21:38:45 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Array is too large to be encoded. " ) ;
2018-07-31 09:44:39 +00:00
break ;
default :
break ;
}
2017-07-11 20:56:09 +00:00
2015-09-16 14:56:30 +00:00
return false ;
}
void TypeChecker : : visitManually (
ModifierInvocation const & _modifier ,
vector < ContractDefinition const * > const & _bases
)
{
2018-04-10 09:22:26 +00:00
std : : vector < ASTPointer < Expression > > const & arguments =
_modifier . arguments ( ) ? * _modifier . arguments ( ) : std : : vector < ASTPointer < Expression > > ( ) ;
2015-09-16 14:56:30 +00:00
for ( ASTPointer < Expression > const & argument : arguments )
argument - > accept ( * this ) ;
2019-10-21 11:18:19 +00:00
2019-12-17 15:18:58 +00:00
_modifier . name ( ) - > accept ( * this ) ;
2015-09-16 14:56:30 +00:00
auto const * declaration = & dereference ( * _modifier . name ( ) ) ;
vector < ASTPointer < VariableDeclaration > > emptyParameterList ;
vector < ASTPointer < VariableDeclaration > > const * parameters = nullptr ;
if ( auto modifierDecl = dynamic_cast < ModifierDefinition const * > ( declaration ) )
parameters = & modifierDecl - > parameters ( ) ;
else
// check parameters for Base constructors
for ( ContractDefinition const * base : _bases )
if ( declaration = = base )
{
if ( auto referencedConstructor = base - > constructor ( ) )
parameters = & referencedConstructor - > parameters ( ) ;
else
parameters = & emptyParameterList ;
break ;
}
if ( ! parameters )
2016-01-08 14:20:20 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _modifier . location ( ) , " Referenced declaration is neither modifier nor base class. " ) ;
2016-01-08 14:20:20 +00:00
return ;
}
2015-09-16 14:56:30 +00:00
if ( parameters - > size ( ) ! = arguments . size ( ) )
2016-02-11 16:10:35 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_modifier . location ( ) ,
2015-09-16 14:56:30 +00:00
" Wrong argument count for modifier invocation: " +
toString ( arguments . size ( ) ) +
" arguments given but expected " +
toString ( parameters - > size ( ) ) +
" . "
) ;
2016-02-11 16:10:35 +00:00
return ;
}
2018-04-10 09:22:26 +00:00
for ( size_t i = 0 ; i < arguments . size ( ) ; + + i )
2019-03-04 17:59:03 +00:00
{
BoolResult result = type ( * arguments [ i ] ) - > isImplicitlyConvertibleTo ( * type ( * ( * parameters ) [ i ] ) ) ;
if ( ! result )
m_errorReporter . typeErrorConcatenateDescriptions (
2015-11-04 10:49:26 +00:00
arguments [ i ] - > location ( ) ,
2015-09-16 14:56:30 +00:00
" Invalid type for argument in modifier invocation. "
" Invalid implicit conversion from " +
type ( * arguments [ i ] ) - > toString ( ) +
" to " +
type ( * ( * parameters ) [ i ] ) - > toString ( ) +
2019-03-04 17:59:03 +00:00
" requested. " ,
result . message ( )
2015-09-16 14:56:30 +00:00
) ;
2019-03-04 17:59:03 +00:00
}
2015-09-16 14:56:30 +00:00
}
bool TypeChecker : : visit ( EventDefinition const & _eventDef )
{
2019-12-10 14:54:09 +00:00
solAssert ( _eventDef . visibility ( ) > Visibility : : Internal , " " ) ;
2015-09-16 14:56:30 +00:00
unsigned numIndexed = 0 ;
for ( ASTPointer < VariableDeclaration > const & var : _eventDef . parameters ( ) )
{
if ( var - > isIndexed ( ) )
numIndexed + + ;
if ( ! type ( * var ) - > canLiveOutsideStorage ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( var - > location ( ) , " Type is required to live outside storage. " ) ;
2019-04-15 13:33:39 +00:00
if ( ! type ( * var ) - > interfaceType ( false ) )
2017-06-01 09:48:38 +00:00
m_errorReporter . typeError ( var - > location ( ) , " Internal or recursive type is not allowed as event parameter type. " ) ;
2018-08-01 17:01:50 +00:00
if (
! _eventDef . sourceUnit ( ) . annotation ( ) . experimentalFeatures . count ( ExperimentalFeature : : ABIEncoderV2 ) & &
2019-02-04 17:13:41 +00:00
! typeSupportedByOldABIEncoder ( * type ( * var ) , false /* isLibrary */ )
2018-08-01 17:01:50 +00:00
)
m_errorReporter . typeError (
var - > location ( ) ,
2019-12-11 16:05:44 +00:00
" This type is only supported in ABIEncoderV2. "
2018-08-01 17:01:50 +00:00
" Use \" pragma experimental ABIEncoderV2; \" to enable the feature. "
) ;
2015-09-16 14:56:30 +00:00
}
2017-08-28 20:05:47 +00:00
if ( _eventDef . isAnonymous ( ) & & numIndexed > 4 )
m_errorReporter . typeError ( _eventDef . location ( ) , " More than 4 indexed arguments for anonymous event. " ) ;
else if ( ! _eventDef . isAnonymous ( ) & & numIndexed > 3 )
m_errorReporter . typeError ( _eventDef . location ( ) , " More than 3 indexed arguments for event. " ) ;
2015-09-16 14:56:30 +00:00
return false ;
}
2016-11-11 11:07:30 +00:00
void TypeChecker : : endVisit ( FunctionTypeName const & _funType )
{
FunctionType const & fun = dynamic_cast < FunctionType const & > ( * _funType . annotation ( ) . type ) ;
2017-03-16 11:58:17 +00:00
if ( fun . kind ( ) = = FunctionType : : Kind : : External )
2019-04-15 13:33:39 +00:00
solAssert ( fun . interfaceType ( false ) , " External function type uses internal types. " ) ;
2016-11-11 11:07:30 +00:00
}
2016-03-01 21:56:39 +00:00
bool TypeChecker : : visit ( InlineAssembly const & _inlineAssembly )
{
// External references have already been resolved in a prior stage and stored in the annotation.
2017-03-14 14:41:23 +00:00
// We run the resolve step again regardless.
2018-10-15 09:58:51 +00:00
yul : : ExternalIdentifierAccess : : Resolver identifierAccess = [ & ] (
2018-11-21 11:42:34 +00:00
yul : : Identifier const & _identifier ,
2018-10-15 09:58:51 +00:00
yul : : IdentifierContext _context ,
2017-05-24 16:34:19 +00:00
bool
2017-02-23 16:38:42 +00:00
)
{
2016-03-01 21:56:39 +00:00
auto ref = _inlineAssembly . annotation ( ) . externalReferences . find ( & _identifier ) ;
if ( ref = = _inlineAssembly . annotation ( ) . externalReferences . end ( ) )
2017-03-14 14:41:23 +00:00
return size_t ( - 1 ) ;
Declaration const * declaration = ref - > second . declaration ;
2016-03-01 21:56:39 +00:00
solAssert ( ! ! declaration , " " ) ;
2018-08-07 12:17:56 +00:00
bool requiresStorage = ref - > second . isSlot | | ref - > second . isOffset ;
2017-04-11 19:12:17 +00:00
if ( auto var = dynamic_cast < VariableDeclaration const * > ( declaration ) )
{
2019-02-27 16:32:48 +00:00
solAssert ( var - > type ( ) , " Expected variable type! " ) ;
2020-02-27 15:13:55 +00:00
if ( var - > immutable ( ) )
{
m_errorReporter . typeError ( _identifier . location , " Assembly access to immutable variables is not supported. " ) ;
return size_t ( - 1 ) ;
}
2019-07-09 09:11:40 +00:00
if ( var - > isConstant ( ) )
2018-02-19 18:21:33 +00:00
{
2020-03-10 23:32:01 +00:00
var = rootConstVariableDeclaration ( * var ) ;
2019-12-03 00:02:33 +00:00
2020-03-10 23:32:01 +00:00
if ( var & & ! var - > value ( ) )
2019-07-09 09:11:40 +00:00
{
m_errorReporter . typeError ( _identifier . location , " Constant has no value. " ) ;
return size_t ( - 1 ) ;
}
2020-03-10 23:32:01 +00:00
else if ( ! var | | ! type ( * var ) - > isValueType ( ) | | (
2019-07-09 09:11:40 +00:00
dynamic_cast < Literal const * > ( var - > value ( ) . get ( ) ) = = nullptr & &
type ( * var - > value ( ) ) - > category ( ) ! = Type : : Category : : RationalNumber
) )
{
2019-12-03 00:02:33 +00:00
m_errorReporter . typeError ( _identifier . location , " Only direct number constants and references to such constants are supported by inline assembly. " ) ;
2019-07-09 09:11:40 +00:00
return size_t ( - 1 ) ;
}
else if ( _context = = yul : : IdentifierContext : : LValue )
{
m_errorReporter . typeError ( _identifier . location , " Constant variables cannot be assigned to. " ) ;
return size_t ( - 1 ) ;
}
else if ( requiresStorage )
2019-07-01 13:34:34 +00:00
{
m_errorReporter . typeError ( _identifier . location , " The suffixes _offset and _slot can only be used on non-constant storage variables. " ) ;
return size_t ( - 1 ) ;
}
2019-07-09 09:11:40 +00:00
}
if ( requiresStorage )
{
if ( ! var - > isStateVariable ( ) & & ! var - > type ( ) - > dataStoredIn ( DataLocation : : Storage ) )
2017-04-21 17:13:46 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _identifier . location , " The suffixes _offset and _slot can only be used on storage variables. " ) ;
2017-04-21 17:13:46 +00:00
return size_t ( - 1 ) ;
}
2020-02-24 14:53:32 +00:00
else if ( _context = = yul : : IdentifierContext : : LValue )
2017-04-21 17:13:46 +00:00
{
2020-02-24 14:53:32 +00:00
if ( var - > isStateVariable ( ) )
{
m_errorReporter . typeError ( _identifier . location , " State variables cannot be assigned to - you have to use \" sstore() \" . " ) ;
return size_t ( - 1 ) ;
}
else if ( ref - > second . isOffset )
{
m_errorReporter . typeError ( _identifier . location , " Only _slot can be assigned to. " ) ;
return size_t ( - 1 ) ;
}
else
solAssert ( ref - > second . isSlot , " " ) ;
2017-04-21 17:13:46 +00:00
}
}
2019-07-01 13:34:34 +00:00
else if ( ! var - > isConstant ( ) & & var - > isStateVariable ( ) )
2017-04-21 17:13:46 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _identifier . location , " Only local variables are supported. To access storage variables, use the _slot and _offset suffixes. " ) ;
2017-04-11 19:12:17 +00:00
return size_t ( - 1 ) ;
}
2017-04-21 17:13:46 +00:00
else if ( var - > type ( ) - > dataStoredIn ( DataLocation : : Storage ) )
2017-04-11 19:12:17 +00:00
{
2018-06-25 14:26:44 +00:00
m_errorReporter . typeError ( _identifier . location , " You have to use the _slot or _offset suffix to access storage reference variables. " ) ;
2017-04-11 19:12:17 +00:00
return size_t ( - 1 ) ;
}
2017-04-21 17:13:46 +00:00
else if ( var - > type ( ) - > sizeOnStack ( ) ! = 1 )
2017-04-11 19:12:17 +00:00
{
2017-07-11 11:37:34 +00:00
if ( var - > type ( ) - > dataStoredIn ( DataLocation : : CallData ) )
m_errorReporter . typeError ( _identifier . location , " Call data elements cannot be accessed directly. Copy to a local variable first or use \" calldataload \" or \" calldatacopy \" with manually determined offsets and sizes. " ) ;
else
m_errorReporter . typeError ( _identifier . location , " Only types that use one stack slot are supported. " ) ;
2017-04-11 19:12:17 +00:00
return size_t ( - 1 ) ;
}
}
2018-08-07 12:17:56 +00:00
else if ( requiresStorage )
{
m_errorReporter . typeError ( _identifier . location , " The suffixes _offset and _slot can only be used on storage variables. " ) ;
return size_t ( - 1 ) ;
}
2018-10-15 09:58:51 +00:00
else if ( _context = = yul : : IdentifierContext : : LValue )
2017-04-11 19:12:17 +00:00
{
2019-10-25 02:14:00 +00:00
if ( dynamic_cast < MagicVariableDeclaration const * > ( declaration ) )
return size_t ( - 1 ) ;
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _identifier . location , " Only local variables can be assigned to in inline assembly. " ) ;
2017-04-11 19:12:17 +00:00
return size_t ( - 1 ) ;
}
2018-10-15 09:58:51 +00:00
if ( _context = = yul : : IdentifierContext : : RValue )
2016-03-01 21:56:39 +00:00
{
solAssert ( ! ! declaration - > type ( ) , " Type of declaration required but not yet determined. " ) ;
if ( dynamic_cast < FunctionDefinition const * > ( declaration ) )
{
2017-04-11 19:12:17 +00:00
}
else if ( dynamic_cast < VariableDeclaration const * > ( declaration ) )
{
2016-03-01 21:56:39 +00:00
}
else if ( auto contract = dynamic_cast < ContractDefinition const * > ( declaration ) )
{
if ( ! contract - > isLibrary ( ) )
2017-04-11 19:12:17 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _identifier . location , " Expected a library. " ) ;
2017-03-14 14:41:23 +00:00
return size_t ( - 1 ) ;
2017-04-11 19:12:17 +00:00
}
2016-03-01 21:56:39 +00:00
}
else
2017-03-14 14:41:23 +00:00
return size_t ( - 1 ) ;
2016-03-01 21:56:39 +00:00
}
2017-04-11 19:12:17 +00:00
ref - > second . valueSize = 1 ;
return size_t ( 1 ) ;
2017-02-23 16:38:42 +00:00
} ;
2017-04-26 13:41:08 +00:00
solAssert ( ! _inlineAssembly . annotation ( ) . analysisInfo , " " ) ;
2018-11-21 11:42:34 +00:00
_inlineAssembly . annotation ( ) . analysisInfo = make_shared < yul : : AsmAnalysisInfo > ( ) ;
yul : : AsmAnalyzer analyzer (
2017-04-26 13:41:08 +00:00
* _inlineAssembly . annotation ( ) . analysisInfo ,
2017-05-11 13:26:35 +00:00
m_errorReporter ,
2019-05-22 11:57:48 +00:00
_inlineAssembly . dialect ( ) ,
2017-04-26 13:41:08 +00:00
identifierAccess
) ;
2017-03-21 18:38:37 +00:00
if ( ! analyzer . analyze ( _inlineAssembly . operations ( ) ) )
2017-02-15 15:47:54 +00:00
return false ;
return true ;
2016-03-01 21:56:39 +00:00
}
2015-09-16 14:56:30 +00:00
bool TypeChecker : : visit ( IfStatement const & _ifStatement )
{
2019-04-17 11:40:50 +00:00
expectType ( _ifStatement . condition ( ) , * TypeProvider : : boolean ( ) ) ;
2015-09-16 14:56:30 +00:00
_ifStatement . trueStatement ( ) . accept ( * this ) ;
if ( _ifStatement . falseStatement ( ) )
_ifStatement . falseStatement ( ) - > accept ( * this ) ;
return false ;
}
2019-09-05 18:02:34 +00:00
void TypeChecker : : endVisit ( TryStatement const & _tryStatement )
{
FunctionCall const * externalCall = dynamic_cast < FunctionCall const * > ( & _tryStatement . externalCall ( ) ) ;
if ( ! externalCall | | externalCall - > annotation ( ) . kind ! = FunctionCallKind : : FunctionCall )
{
m_errorReporter . typeError (
_tryStatement . externalCall ( ) . location ( ) ,
" Try can only be used with external function calls and contract creation calls. "
) ;
return ;
}
FunctionType const & functionType = dynamic_cast < FunctionType const & > ( * externalCall - > expression ( ) . annotation ( ) . type ) ;
if (
functionType . kind ( ) ! = FunctionType : : Kind : : External & &
functionType . kind ( ) ! = FunctionType : : Kind : : Creation & &
functionType . kind ( ) ! = FunctionType : : Kind : : DelegateCall
)
{
m_errorReporter . typeError (
_tryStatement . externalCall ( ) . location ( ) ,
" Try can only be used with external function calls and contract creation calls. "
) ;
return ;
}
externalCall - > annotation ( ) . tryCall = true ;
solAssert ( _tryStatement . clauses ( ) . size ( ) > = 2 , " " ) ;
solAssert ( _tryStatement . clauses ( ) . front ( ) , " " ) ;
TryCatchClause const & successClause = * _tryStatement . clauses ( ) . front ( ) ;
if ( successClause . parameters ( ) )
{
TypePointers returnTypes =
m_evmVersion . supportsReturndata ( ) ?
functionType . returnParameterTypes ( ) :
functionType . returnParameterTypesWithoutDynamicTypes ( ) ;
std : : vector < ASTPointer < VariableDeclaration > > const & parameters =
successClause . parameters ( ) - > parameters ( ) ;
if ( returnTypes . size ( ) ! = parameters . size ( ) )
m_errorReporter . typeError (
successClause . location ( ) ,
" Function returns " +
to_string ( functionType . returnParameterTypes ( ) . size ( ) ) +
" values, but returns clause has " +
to_string ( parameters . size ( ) ) +
" variables. "
) ;
size_t len = min ( returnTypes . size ( ) , parameters . size ( ) ) ;
for ( size_t i = 0 ; i < len ; + + i )
{
solAssert ( returnTypes [ i ] , " " ) ;
if ( parameters [ i ] & & * parameters [ i ] - > annotation ( ) . type ! = * returnTypes [ i ] )
m_errorReporter . typeError (
parameters [ i ] - > location ( ) ,
" Invalid type, expected " +
returnTypes [ i ] - > toString ( false ) +
" but got " +
parameters [ i ] - > annotation ( ) . type - > toString ( ) +
" . "
) ;
}
}
TryCatchClause const * errorClause = nullptr ;
TryCatchClause const * lowLevelClause = nullptr ;
for ( size_t i = 1 ; i < _tryStatement . clauses ( ) . size ( ) ; + + i )
{
TryCatchClause const & clause = * _tryStatement . clauses ( ) [ i ] ;
if ( clause . errorName ( ) = = " " )
{
if ( lowLevelClause )
m_errorReporter . typeError (
clause . location ( ) ,
SecondarySourceLocation { } . append ( " The first clause is here: " , lowLevelClause - > location ( ) ) ,
" This try statement already has a low-level catch clause. "
) ;
lowLevelClause = & clause ;
if ( clause . parameters ( ) & & ! clause . parameters ( ) - > parameters ( ) . empty ( ) )
{
if (
clause . parameters ( ) - > parameters ( ) . size ( ) ! = 1 | |
* clause . parameters ( ) - > parameters ( ) . front ( ) - > type ( ) ! = * TypeProvider : : bytesMemory ( )
)
m_errorReporter . typeError ( clause . location ( ) , " Expected `catch (bytes memory ...) { ... }` or `catch { ... }`. " ) ;
if ( ! m_evmVersion . supportsReturndata ( ) )
m_errorReporter . typeError (
clause . location ( ) ,
" This catch clause type cannot be used on the selected EVM version ( " +
m_evmVersion . name ( ) +
" ). You need at least a Byzantium-compatible EVM or use `catch { ... }`. "
) ;
}
}
else if ( clause . errorName ( ) = = " Error " )
{
if ( ! m_evmVersion . supportsReturndata ( ) )
m_errorReporter . typeError (
clause . location ( ) ,
" This catch clause type cannot be used on the selected EVM version ( " +
m_evmVersion . name ( ) +
" ). You need at least a Byzantium-compatible EVM or use `catch { ... }`. "
) ;
if ( errorClause )
m_errorReporter . typeError (
clause . location ( ) ,
SecondarySourceLocation { } . append ( " The first clause is here: " , errorClause - > location ( ) ) ,
" This try statement already has an \" Error \" catch clause. "
) ;
errorClause = & clause ;
if (
! clause . parameters ( ) | |
clause . parameters ( ) - > parameters ( ) . size ( ) ! = 1 | |
* clause . parameters ( ) - > parameters ( ) . front ( ) - > type ( ) ! = * TypeProvider : : stringMemory ( )
)
m_errorReporter . typeError ( clause . location ( ) , " Expected `catch Error(string memory ...) { ... }`. " ) ;
}
else
m_errorReporter . typeError (
clause . location ( ) ,
" Invalid catch clause name. Expected either `catch (...)` or `catch Error(...)`. "
) ;
}
}
2015-09-16 14:56:30 +00:00
bool TypeChecker : : visit ( WhileStatement const & _whileStatement )
{
2019-04-17 11:40:50 +00:00
expectType ( _whileStatement . condition ( ) , * TypeProvider : : boolean ( ) ) ;
2015-09-16 14:56:30 +00:00
_whileStatement . body ( ) . accept ( * this ) ;
return false ;
}
bool TypeChecker : : visit ( ForStatement const & _forStatement )
{
if ( _forStatement . initializationExpression ( ) )
_forStatement . initializationExpression ( ) - > accept ( * this ) ;
if ( _forStatement . condition ( ) )
2019-04-17 11:40:50 +00:00
expectType ( * _forStatement . condition ( ) , * TypeProvider : : boolean ( ) ) ;
2015-09-16 14:56:30 +00:00
if ( _forStatement . loopExpression ( ) )
_forStatement . loopExpression ( ) - > accept ( * this ) ;
_forStatement . body ( ) . accept ( * this ) ;
return false ;
}
void TypeChecker : : endVisit ( Return const & _return )
{
2018-08-07 18:47:23 +00:00
ParameterList const * params = _return . annotation ( ) . functionReturnParameters ;
2015-09-16 14:56:30 +00:00
if ( ! _return . expression ( ) )
2018-08-07 18:47:23 +00:00
{
if ( params & & ! params - > parameters ( ) . empty ( ) )
m_errorReporter . typeError ( _return . location ( ) , " Return arguments required. " ) ;
2015-09-16 14:56:30 +00:00
return ;
2018-08-07 18:47:23 +00:00
}
2015-09-16 14:56:30 +00:00
if ( ! params )
2015-10-12 21:02:35 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _return . location ( ) , " Return arguments not allowed. " ) ;
2015-10-12 21:02:35 +00:00
return ;
}
TypePointers returnTypes ;
for ( auto const & var : params - > parameters ( ) )
returnTypes . push_back ( type ( * var ) ) ;
2019-04-15 13:33:39 +00:00
if ( auto tupleType = dynamic_cast < TupleType const * > ( type ( * _return . expression ( ) ) ) )
2015-10-12 21:02:35 +00:00
{
if ( tupleType - > components ( ) . size ( ) ! = params - > parameters ( ) . size ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _return . location ( ) , " Different number of arguments in return statement than in returns declaration. " ) ;
2019-03-04 17:59:03 +00:00
else
{
BoolResult result = tupleType - > isImplicitlyConvertibleTo ( TupleType ( returnTypes ) ) ;
if ( ! result )
m_errorReporter . typeErrorConcatenateDescriptions (
_return . expression ( ) - > location ( ) ,
" Return argument type " +
type ( * _return . expression ( ) ) - > toString ( ) +
" is not implicitly convertible to expected type " +
TupleType ( returnTypes ) . toString ( false ) + " . " ,
result . message ( )
) ;
}
2015-10-12 21:02:35 +00:00
}
2015-09-16 14:56:30 +00:00
else if ( params - > parameters ( ) . size ( ) ! = 1 )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _return . location ( ) , " Different number of arguments in return statement than in returns declaration. " ) ;
2015-09-16 14:56:30 +00:00
else
{
TypePointer const & expected = type ( * params - > parameters ( ) . front ( ) ) ;
2019-03-04 17:59:03 +00:00
BoolResult result = type ( * _return . expression ( ) ) - > isImplicitlyConvertibleTo ( * expected ) ;
if ( ! result )
m_errorReporter . typeErrorConcatenateDescriptions (
2015-11-04 10:49:26 +00:00
_return . expression ( ) - > location ( ) ,
2015-09-16 14:56:30 +00:00
" Return argument type " +
type ( * _return . expression ( ) ) - > toString ( ) +
" is not implicitly convertible to expected type (type of first return variable) " +
2019-03-04 17:59:03 +00:00
expected - > toString ( ) + " . " ,
result . message ( )
2015-09-16 14:56:30 +00:00
) ;
}
}
2018-02-16 15:55:21 +00:00
void TypeChecker : : endVisit ( EmitStatement const & _emit )
{
if (
_emit . eventCall ( ) . annotation ( ) . kind ! = FunctionCallKind : : FunctionCall | |
2018-05-04 04:21:28 +00:00
type ( _emit . eventCall ( ) . expression ( ) ) - > category ( ) ! = Type : : Category : : Function | |
2018-02-16 15:55:21 +00:00
dynamic_cast < FunctionType const & > ( * type ( _emit . eventCall ( ) . expression ( ) ) ) . kind ( ) ! = FunctionType : : Kind : : Event
)
2018-02-16 16:32:41 +00:00
m_errorReporter . typeError ( _emit . eventCall ( ) . expression ( ) . location ( ) , " Expression has to be an event invocation. " ) ;
2018-02-16 15:55:21 +00:00
}
2018-07-10 20:20:10 +00:00
namespace
{
2018-07-02 15:00:09 +00:00
/**
2018-07-10 20:20:10 +00:00
* @ returns a suggested left - hand - side of a multi - variable declaration contairing
* the variable declarations given in @ a _decls .
2018-07-02 15:00:09 +00:00
*/
2018-07-04 16:34:24 +00:00
string createTupleDecl ( vector < ASTPointer < VariableDeclaration > > const & _decls )
2018-07-02 15:00:09 +00:00
{
vector < string > components ;
2018-07-04 16:34:24 +00:00
for ( ASTPointer < VariableDeclaration > const & decl : _decls )
2018-07-02 15:00:09 +00:00
if ( decl )
2018-08-04 13:16:23 +00:00
{
solAssert ( decl - > annotation ( ) . type , " " ) ;
2018-07-02 15:00:09 +00:00
components . emplace_back ( decl - > annotation ( ) . type - > toString ( false ) + " " + decl - > name ( ) ) ;
2018-08-04 13:16:23 +00:00
}
2018-07-02 15:00:09 +00:00
else
components . emplace_back ( ) ;
2018-07-10 20:20:10 +00:00
if ( _decls . size ( ) = = 1 )
2018-07-02 15:00:09 +00:00
return components . front ( ) ;
else
return " ( " + boost : : algorithm : : join ( components , " , " ) + " ) " ;
}
2018-07-04 16:34:24 +00:00
bool typeCanBeExpressed ( vector < ASTPointer < VariableDeclaration > > const & decls )
2018-07-02 15:00:09 +00:00
{
2018-07-04 16:34:24 +00:00
for ( ASTPointer < VariableDeclaration > const & decl : decls )
2018-07-02 15:00:09 +00:00
{
// skip empty tuples (they can be expressed of course)
if ( ! decl )
continue ;
2018-08-04 13:16:23 +00:00
if ( ! decl - > annotation ( ) . type )
return false ;
2019-04-15 13:33:39 +00:00
if ( auto functionType = dynamic_cast < FunctionType const * > ( decl - > annotation ( ) . type ) )
2018-07-02 15:00:09 +00:00
if (
functionType - > kind ( ) ! = FunctionType : : Kind : : Internal & &
functionType - > kind ( ) ! = FunctionType : : Kind : : External
)
return false ;
}
return true ;
}
2018-07-10 20:20:10 +00:00
}
2018-07-02 15:00:09 +00:00
2015-10-08 16:01:12 +00:00
bool TypeChecker : : visit ( VariableDeclarationStatement const & _statement )
{
2015-10-09 17:35:41 +00:00
if ( ! _statement . initialValue ( ) )
2015-10-08 16:01:12 +00:00
{
2015-10-09 17:35:41 +00:00
// No initial value is only permitted for single variables with specified type.
if ( _statement . declarations ( ) . size ( ) ! = 1 | | ! _statement . declarations ( ) . front ( ) )
2018-07-12 14:17:30 +00:00
{
if ( boost : : algorithm : : all_of_equal ( _statement . declarations ( ) , nullptr ) )
{
// The syntax checker has already generated an error for this case (empty LHS tuple).
solAssert ( m_errorReporter . hasErrors ( ) , " " ) ;
// It is okay to return here, as there are no named components on the
// left-hand-side that could cause any damage later.
return false ;
}
else
// Bailing out *fatal* here, as those (untyped) vars may be used later, and diagnostics wouldn't be helpful then.
m_errorReporter . fatalTypeError ( _statement . location ( ) , " Use of the \" var \" keyword is disallowed. " ) ;
}
2015-10-09 17:35:41 +00:00
VariableDeclaration const & varDecl = * _statement . declarations ( ) . front ( ) ;
if ( ! varDecl . annotation ( ) . type )
2018-07-12 14:17:30 +00:00
m_errorReporter . fatalTypeError ( _statement . location ( ) , " Use of the \" var \" keyword is disallowed. " ) ;
2019-04-15 13:33:39 +00:00
if ( auto ref = dynamic_cast < ReferenceType const * > ( type ( varDecl ) ) )
2015-10-09 17:35:41 +00:00
{
if ( ref - > dataStoredIn ( DataLocation : : Storage ) )
2017-07-05 17:38:00 +00:00
{
string errorText { " Uninitialized storage pointer. " } ;
2019-02-06 12:11:04 +00:00
solAssert ( varDecl . referenceLocation ( ) ! = VariableDeclaration : : Location : : Unspecified , " Expected a specified location at this point " ) ;
2018-02-15 10:58:50 +00:00
solAssert ( m_scope , " " ) ;
2018-07-03 13:10:59 +00:00
m_errorReporter . declarationError ( varDecl . location ( ) , errorText ) ;
2017-07-05 17:38:00 +00:00
}
2015-10-09 17:35:41 +00:00
}
2019-04-15 13:33:39 +00:00
else if ( dynamic_cast < MappingType const * > ( type ( varDecl ) ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2017-03-03 17:44:35 +00:00
varDecl . location ( ) ,
" Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable. "
) ;
2015-10-09 17:35:41 +00:00
varDecl . accept ( * this ) ;
2015-10-08 16:01:12 +00:00
return false ;
}
2015-10-09 17:35:41 +00:00
// Here we have an initial value and might have to derive some types before we can visit
// the variable declaration(s).
_statement . initialValue ( ) - > accept ( * this ) ;
2015-10-09 18:44:56 +00:00
TypePointers valueTypes ;
2019-04-15 13:33:39 +00:00
if ( auto tupleType = dynamic_cast < TupleType const * > ( type ( * _statement . initialValue ( ) ) ) )
2015-10-09 18:44:56 +00:00
valueTypes = tupleType - > components ( ) ;
else
2015-10-12 21:02:35 +00:00
valueTypes = TypePointers { type ( * _statement . initialValue ( ) ) } ;
2015-10-09 17:35:41 +00:00
2015-10-09 18:44:56 +00:00
vector < ASTPointer < VariableDeclaration > > const & variables = _statement . declarations ( ) ;
2015-10-13 12:31:24 +00:00
if ( variables . empty ( ) )
2018-07-04 16:34:24 +00:00
// We already have an error for this in the SyntaxChecker.
solAssert ( m_errorReporter . hasErrors ( ) , " " ) ;
2018-05-03 17:21:42 +00:00
else if ( valueTypes . size ( ) ! = variables . size ( ) )
2018-07-04 16:34:24 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_statement . location ( ) ,
2018-07-04 16:34:24 +00:00
" Different number of components on the left hand side ( " +
toString ( variables . size ( ) ) +
" ) than on the right hand side ( " +
2015-10-09 18:44:56 +00:00
toString ( valueTypes . size ( ) ) +
2018-07-04 16:34:24 +00:00
" ). "
2015-10-09 18:44:56 +00:00
) ;
2015-10-09 17:35:41 +00:00
2018-07-02 15:00:09 +00:00
bool autoTypeDeductionNeeded = false ;
2018-07-04 16:34:24 +00:00
for ( size_t i = 0 ; i < min ( variables . size ( ) , valueTypes . size ( ) ) ; + + i )
2015-10-09 17:35:41 +00:00
{
2018-07-04 16:34:24 +00:00
if ( ! variables [ i ] )
2015-10-09 17:35:41 +00:00
continue ;
2018-07-04 16:34:24 +00:00
VariableDeclaration const & var = * variables [ i ] ;
2015-10-09 17:35:41 +00:00
solAssert ( ! var . value ( ) , " Value has to be tied to statement. " ) ;
2015-10-09 18:44:56 +00:00
TypePointer const & valueComponentType = valueTypes [ i ] ;
2015-10-09 17:35:41 +00:00
solAssert ( ! ! valueComponentType , " " ) ;
if ( ! var . annotation ( ) . type )
{
2018-07-02 15:00:09 +00:00
autoTypeDeductionNeeded = true ;
2015-10-09 17:35:41 +00:00
// Infer type from value.
solAssert ( ! var . typeName ( ) , " " ) ;
var . annotation ( ) . type = valueComponentType - > mobileType ( ) ;
2016-05-10 08:26:53 +00:00
if ( ! var . annotation ( ) . type )
2016-05-10 12:57:29 +00:00
{
2016-05-10 08:26:53 +00:00
if ( valueComponentType - > category ( ) = = Type : : Category : : RationalNumber )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2016-05-10 08:26:53 +00:00
_statement . initialValue ( ) - > location ( ) ,
" Invalid rational " +
valueComponentType - > toString ( ) +
2017-10-05 13:23:25 +00:00
" (absolute value too large or division by zero). "
2016-05-10 08:26:53 +00:00
) ;
else
solAssert ( false , " " ) ;
2016-05-10 12:57:29 +00:00
}
2019-04-17 11:40:50 +00:00
else if ( * var . annotation ( ) . type = = * TypeProvider : : emptyTuple ( ) )
2019-02-06 12:11:04 +00:00
solAssert ( false , " Cannot declare variable with void (empty tuple) type. " ) ;
2017-06-22 14:08:59 +00:00
else if ( valueComponentType - > category ( ) = = Type : : Category : : RationalNumber )
{
string typeName = var . annotation ( ) . type - > toString ( true ) ;
string extension ;
2019-04-15 13:33:39 +00:00
if ( auto type = dynamic_cast < IntegerType const * > ( var . annotation ( ) . type ) )
2017-06-22 14:08:59 +00:00
{
2018-04-30 21:56:30 +00:00
unsigned numBits = type - > numBits ( ) ;
2017-06-22 14:08:59 +00:00
bool isSigned = type - > isSigned ( ) ;
2018-04-30 21:56:30 +00:00
solAssert ( numBits > 0 , " " ) ;
2017-06-26 07:49:45 +00:00
string minValue ;
string maxValue ;
2017-06-22 14:08:59 +00:00
if ( isSigned )
2017-06-26 07:49:45 +00:00
{
2017-06-22 14:08:59 +00:00
numBits - - ;
2017-06-26 07:49:45 +00:00
minValue = " - " + bigint ( bigint ( 1 ) < < numBits ) . str ( ) ;
}
else
minValue = " 0 " ;
maxValue = bigint ( ( bigint ( 1 ) < < numBits ) - 1 ) . str ( ) ;
extension = " , which can hold values between " + minValue + " and " + maxValue ;
2017-06-22 14:08:59 +00:00
}
else
2019-04-15 13:33:39 +00:00
solAssert ( dynamic_cast < FixedPointType const * > ( var . annotation ( ) . type ) , " Unknown type. " ) ;
2017-06-22 14:08:59 +00:00
}
2015-10-09 17:35:41 +00:00
var . accept ( * this ) ;
}
else
{
var . accept ( * this ) ;
2019-03-04 17:59:03 +00:00
BoolResult result = valueComponentType - > isImplicitlyConvertibleTo ( * var . annotation ( ) . type ) ;
if ( ! result )
2016-05-05 22:47:08 +00:00
{
2018-11-30 09:39:21 +00:00
auto errorMsg = " Type " +
valueComponentType - > toString ( ) +
" is not implicitly convertible to expected type " +
var . annotation ( ) . type - > toString ( ) ;
2016-05-05 22:47:08 +00:00
if (
valueComponentType - > category ( ) = = Type : : Category : : RationalNumber & &
2016-05-10 12:30:24 +00:00
dynamic_cast < RationalNumberType const & > ( * valueComponentType ) . isFractional ( ) & &
2016-05-10 08:26:53 +00:00
valueComponentType - > mobileType ( )
2016-05-05 22:47:08 +00:00
)
2018-11-30 09:39:21 +00:00
{
if ( var . annotation ( ) . type - > operator = = ( * valueComponentType - > mobileType ( ) ) )
m_errorReporter . typeError (
_statement . location ( ) ,
errorMsg + " , but it can be explicitly converted. "
) ;
else
m_errorReporter . typeError (
_statement . location ( ) ,
errorMsg +
" . Try converting to type " +
valueComponentType - > mobileType ( ) - > toString ( ) +
" or use an explicit conversion. "
) ;
}
2016-05-05 22:47:08 +00:00
else
2019-03-04 17:59:03 +00:00
m_errorReporter . typeErrorConcatenateDescriptions (
_statement . location ( ) ,
errorMsg + " . " ,
result . message ( )
) ;
2016-05-05 22:47:08 +00:00
}
2015-10-09 17:35:41 +00:00
}
2015-10-08 16:01:12 +00:00
}
2018-07-02 15:00:09 +00:00
2019-02-27 16:32:48 +00:00
if ( valueTypes . size ( ) ! = variables . size ( ) )
{
solAssert ( m_errorReporter . hasErrors ( ) , " Should have errors! " ) ;
for ( auto const & var : variables )
if ( var & & ! var - > annotation ( ) . type )
BOOST_THROW_EXCEPTION ( FatalError ( ) ) ;
}
2018-07-02 15:00:09 +00:00
if ( autoTypeDeductionNeeded )
{
2018-07-04 16:34:24 +00:00
if ( ! typeCanBeExpressed ( variables ) )
2018-07-10 20:20:10 +00:00
m_errorReporter . syntaxError (
_statement . location ( ) ,
2018-07-02 15:00:09 +00:00
" Use of the \" var \" keyword is disallowed. "
2018-07-10 20:20:10 +00:00
" Type cannot be expressed in syntax. "
) ;
2018-07-02 15:00:09 +00:00
else
2018-07-10 20:20:10 +00:00
m_errorReporter . syntaxError (
_statement . location ( ) ,
2018-07-02 15:00:09 +00:00
" Use of the \" var \" keyword is disallowed. "
2018-07-04 16:34:24 +00:00
" Use explicit declaration ` " + createTupleDecl ( variables ) + " = ...´ instead. "
2018-07-10 20:20:10 +00:00
) ;
2018-07-02 15:00:09 +00:00
}
2015-10-08 16:01:12 +00:00
return false ;
}
2015-09-16 14:56:30 +00:00
void TypeChecker : : endVisit ( ExpressionStatement const & _statement )
{
2016-03-29 20:08:51 +00:00
if ( type ( _statement . expression ( ) ) - > category ( ) = = Type : : Category : : RationalNumber )
2016-05-10 08:26:53 +00:00
if ( ! dynamic_cast < RationalNumberType const & > ( * type ( _statement . expression ( ) ) ) . mobileType ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _statement . expression ( ) . location ( ) , " Invalid rational number. " ) ;
2016-06-21 12:36:23 +00:00
2016-06-24 14:41:17 +00:00
if ( auto call = dynamic_cast < FunctionCall const * > ( & _statement . expression ( ) ) )
{
2019-04-15 13:33:39 +00:00
if ( auto callType = dynamic_cast < FunctionType const * > ( type ( call - > expression ( ) ) ) )
2016-06-24 14:41:17 +00:00
{
2017-03-16 11:58:17 +00:00
auto kind = callType - > kind ( ) ;
2016-06-24 14:41:17 +00:00
if (
2017-08-01 09:32:23 +00:00
kind = = FunctionType : : Kind : : BareCall | |
2017-03-16 11:58:17 +00:00
kind = = FunctionType : : Kind : : BareCallCode | |
2018-08-15 12:40:20 +00:00
kind = = FunctionType : : Kind : : BareDelegateCall | |
kind = = FunctionType : : Kind : : BareStaticCall
2016-06-24 14:41:17 +00:00
)
2017-05-11 13:26:35 +00:00
m_errorReporter . warning ( _statement . location ( ) , " Return value of low-level calls not used. " ) ;
2017-03-16 11:58:17 +00:00
else if ( kind = = FunctionType : : Kind : : Send )
2017-05-11 13:26:35 +00:00
m_errorReporter . warning ( _statement . location ( ) , " Failure condition of 'send' ignored. Consider using 'transfer' instead. " ) ;
2016-06-24 14:41:17 +00:00
}
}
2015-09-16 14:56:30 +00:00
}
2016-01-07 09:01:46 +00:00
bool TypeChecker : : visit ( Conditional const & _conditional )
2015-12-22 16:50:06 +00:00
{
2019-04-17 11:40:50 +00:00
expectType ( _conditional . condition ( ) , * TypeProvider : : boolean ( ) ) ;
2015-12-23 16:12:41 +00:00
2016-01-11 07:08:28 +00:00
_conditional . trueExpression ( ) . accept ( * this ) ;
_conditional . falseExpression ( ) . accept ( * this ) ;
2016-01-07 09:01:46 +00:00
2016-01-11 16:00:14 +00:00
TypePointer trueType = type ( _conditional . trueExpression ( ) ) - > mobileType ( ) ;
TypePointer falseType = type ( _conditional . falseExpression ( ) ) - > mobileType ( ) ;
2019-02-06 19:42:38 +00:00
2019-04-15 13:33:39 +00:00
TypePointer commonType = nullptr ;
2019-02-06 19:42:38 +00:00
2016-10-21 10:30:58 +00:00
if ( ! trueType )
2019-02-06 19:42:38 +00:00
m_errorReporter . typeError ( _conditional . trueExpression ( ) . location ( ) , " Invalid mobile type in true expression. " ) ;
else
commonType = trueType ;
2016-10-21 10:30:58 +00:00
if ( ! falseType )
2019-02-06 19:42:38 +00:00
m_errorReporter . typeError ( _conditional . falseExpression ( ) . location ( ) , " Invalid mobile type in false expression. " ) ;
else
commonType = falseType ;
2016-01-07 09:01:46 +00:00
2019-02-06 19:42:38 +00:00
if ( ! trueType & & ! falseType )
BOOST_THROW_EXCEPTION ( FatalError ( ) ) ;
else if ( trueType & & falseType )
2016-01-07 09:01:46 +00:00
{
2019-02-06 19:42:38 +00:00
commonType = Type : : commonType ( trueType , falseType ) ;
if ( ! commonType )
{
m_errorReporter . typeError (
_conditional . location ( ) ,
" True expression's type " +
trueType - > toString ( ) +
" doesn't match false expression's type " +
falseType - > toString ( ) +
" . "
) ;
// even we can't find a common type, we have to set a type here,
// otherwise the upper statement will not be able to check the type.
commonType = trueType ;
}
2016-01-11 07:08:28 +00:00
}
2016-01-07 09:01:46 +00:00
2016-01-11 07:08:28 +00:00
_conditional . annotation ( ) . type = commonType ;
2017-03-01 18:12:40 +00:00
_conditional . annotation ( ) . isPure =
_conditional . condition ( ) . annotation ( ) . isPure & &
_conditional . trueExpression ( ) . annotation ( ) . isPure & &
_conditional . falseExpression ( ) . annotation ( ) . isPure ;
2016-01-07 09:01:46 +00:00
2016-01-11 07:08:28 +00:00
if ( _conditional . annotation ( ) . lValueRequested )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2016-01-11 07:08:28 +00:00
_conditional . location ( ) ,
" Conditional expression as left value is not supported yet. "
) ;
2016-01-07 09:01:46 +00:00
return false ;
2015-12-22 16:50:06 +00:00
}
2018-08-03 12:32:37 +00:00
void TypeChecker : : checkExpressionAssignment ( Type const & _type , Expression const & _expression )
{
if ( auto const * tupleExpression = dynamic_cast < TupleExpression const * > ( & _expression ) )
{
2018-08-03 15:38:06 +00:00
auto const * tupleType = dynamic_cast < TupleType const * > ( & _type ) ;
2019-04-15 13:33:39 +00:00
auto const & types = tupleType ? tupleType - > components ( ) : vector < TypePointer > { & _type } ;
2018-08-03 15:38:06 +00:00
2018-10-05 13:38:14 +00:00
solAssert (
tupleExpression - > components ( ) . size ( ) = = types . size ( ) | | m_errorReporter . hasErrors ( ) ,
" Array sizes don't match or no errors generated. "
) ;
for ( size_t i = 0 ; i < min ( tupleExpression - > components ( ) . size ( ) , types . size ( ) ) ; i + + )
2018-08-03 15:38:06 +00:00
if ( types [ i ] )
{
solAssert ( ! ! tupleExpression - > components ( ) [ i ] , " " ) ;
checkExpressionAssignment ( * types [ i ] , * tupleExpression - > components ( ) [ i ] ) ;
}
2018-08-03 12:32:37 +00:00
}
else if ( _type . category ( ) = = Type : : Category : : Mapping )
2018-08-03 14:22:03 +00:00
{
bool isLocalOrReturn = false ;
if ( auto const * identifier = dynamic_cast < Identifier const * > ( & _expression ) )
if ( auto const * variableDeclaration = dynamic_cast < VariableDeclaration const * > ( identifier - > annotation ( ) . referencedDeclaration ) )
if ( variableDeclaration - > isLocalOrReturn ( ) )
isLocalOrReturn = true ;
if ( ! isLocalOrReturn )
m_errorReporter . typeError ( _expression . location ( ) , " Mappings cannot be assigned to. " ) ;
}
2018-08-03 12:32:37 +00:00
}
2015-09-16 14:56:30 +00:00
bool TypeChecker : : visit ( Assignment const & _assignment )
{
requireLValue ( _assignment . leftHandSide ( ) ) ;
TypePointer t = type ( _assignment . leftHandSide ( ) ) ;
_assignment . annotation ( ) . type = t ;
2018-08-03 12:32:37 +00:00
checkExpressionAssignment ( * t , _assignment . leftHandSide ( ) ) ;
2019-04-15 13:33:39 +00:00
if ( TupleType const * tupleType = dynamic_cast < TupleType const * > ( t ) )
2015-10-14 13:19:50 +00:00
{
2017-03-06 13:50:00 +00:00
if ( _assignment . assignmentOperator ( ) ! = Token : : Assign )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2017-03-06 13:50:00 +00:00
_assignment . location ( ) ,
" Compound assignment is not allowed for tuple types. "
) ;
2015-10-15 14:02:00 +00:00
// Sequenced assignments of tuples is not valid, make the result a "void" type.
2019-04-17 11:40:50 +00:00
_assignment . annotation ( ) . type = TypeProvider : : emptyTuple ( ) ;
2018-05-03 17:21:42 +00:00
2015-10-14 13:19:50 +00:00
expectType ( _assignment . rightHandSide ( ) , * tupleType ) ;
2017-06-21 17:32:56 +00:00
2017-07-26 12:19:46 +00:00
// expectType does not cause fatal errors, so we have to check again here.
2019-04-15 13:33:39 +00:00
if ( dynamic_cast < TupleType const * > ( type ( _assignment . rightHandSide ( ) ) ) )
2017-07-26 12:19:46 +00:00
checkDoubleStorageAssignment ( _assignment ) ;
2015-10-14 13:19:50 +00:00
}
2015-09-16 14:56:30 +00:00
else if ( _assignment . assignmentOperator ( ) = = Token : : Assign )
expectType ( _assignment . rightHandSide ( ) , * t ) ;
else
{
// compound assignment
_assignment . rightHandSide ( ) . accept ( * this ) ;
TypePointer resultType = t - > binaryOperatorResult (
2018-10-22 14:48:21 +00:00
TokenTraits : : AssignmentToBinaryOp ( _assignment . assignmentOperator ( ) ) ,
2015-09-16 14:56:30 +00:00
type ( _assignment . rightHandSide ( ) )
) ;
if ( ! resultType | | * resultType ! = * t )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_assignment . location ( ) ,
2015-09-16 14:56:30 +00:00
" Operator " +
2018-10-22 14:48:21 +00:00
string ( TokenTraits : : toString ( _assignment . assignmentOperator ( ) ) ) +
2015-09-16 14:56:30 +00:00
" not compatible with types " +
t - > toString ( ) +
" and " +
type ( _assignment . rightHandSide ( ) ) - > toString ( )
) ;
}
return false ;
}
2015-10-12 21:02:35 +00:00
bool TypeChecker : : visit ( TupleExpression const & _tuple )
{
vector < ASTPointer < Expression > > const & components = _tuple . components ( ) ;
TypePointers types ;
2016-01-11 20:25:59 +00:00
2015-10-12 21:02:35 +00:00
if ( _tuple . annotation ( ) . lValueRequested )
{
2016-01-11 20:25:59 +00:00
if ( _tuple . isInlineArray ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _tuple . location ( ) , " Inline array type cannot be declared as LValue. " ) ;
2015-10-12 21:02:35 +00:00
for ( auto const & component : components )
if ( component )
{
requireLValue ( * component ) ;
types . push_back ( type ( * component ) ) ;
}
else
types . push_back ( TypePointer ( ) ) ;
2016-01-04 08:11:04 +00:00
if ( components . size ( ) = = 1 )
_tuple . annotation ( ) . type = type ( * components [ 0 ] ) ;
else
2019-04-17 11:40:50 +00:00
_tuple . annotation ( ) . type = TypeProvider : : tuple ( move ( types ) ) ;
2015-10-12 21:02:35 +00:00
// If some of the components are not LValues, the error is reported above.
_tuple . annotation ( ) . isLValue = true ;
}
else
{
2017-03-01 18:12:40 +00:00
bool isPure = true ;
2019-04-15 13:33:39 +00:00
TypePointer inlineArrayType = nullptr ;
2018-04-23 14:20:37 +00:00
2015-10-12 21:02:35 +00:00
for ( size_t i = 0 ; i < components . size ( ) ; + + i )
{
2018-07-10 10:37:09 +00:00
if ( ! components [ i ] )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _tuple . location ( ) , " Tuple component cannot be empty. " ) ;
2015-10-12 21:02:35 +00:00
else if ( components [ i ] )
{
components [ i ] - > accept ( * this ) ;
types . push_back ( type ( * components [ i ] ) ) ;
2017-09-18 10:39:17 +00:00
2018-04-22 14:54:33 +00:00
if ( types [ i ] - > category ( ) = = Type : : Category : : Tuple )
if ( dynamic_cast < TupleType const & > ( * types [ i ] ) . components ( ) . empty ( ) )
2018-04-23 14:20:37 +00:00
{
2018-04-23 15:11:41 +00:00
if ( _tuple . isInlineArray ( ) )
m_errorReporter . fatalTypeError ( components [ i ] - > location ( ) , " Array component cannot be empty. " ) ;
2018-07-10 10:37:09 +00:00
m_errorReporter . typeError ( components [ i ] - > location ( ) , " Tuple component cannot be empty. " ) ;
2018-04-23 14:20:37 +00:00
}
2018-04-22 14:54:33 +00:00
2017-09-18 10:39:17 +00:00
// Note: code generation will visit each of the expression even if they are not assigned from.
2017-10-17 17:14:49 +00:00
if ( types [ i ] - > category ( ) = = Type : : Category : : RationalNumber & & components . size ( ) > 1 )
2017-09-18 10:39:17 +00:00
if ( ! dynamic_cast < RationalNumberType const & > ( * types [ i ] ) . mobileType ( ) )
m_errorReporter . fatalTypeError ( components [ i ] - > location ( ) , " Invalid rational number. " ) ;
2016-10-21 10:30:58 +00:00
if ( _tuple . isInlineArray ( ) )
{
2019-02-07 14:53:49 +00:00
solAssert ( ! ! types [ i ] , " Inline array cannot have empty components " ) ;
2016-10-21 10:30:58 +00:00
if ( ( i = = 0 | | inlineArrayType ) & & ! types [ i ] - > mobileType ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( components [ i ] - > location ( ) , " Invalid mobile type. " ) ;
2016-10-21 10:30:58 +00:00
if ( i = = 0 )
2017-03-06 13:38:29 +00:00
inlineArrayType = types [ i ] - > mobileType ( ) ;
2016-10-21 10:30:58 +00:00
else if ( inlineArrayType )
2016-10-26 13:57:42 +00:00
inlineArrayType = Type : : commonType ( inlineArrayType , types [ i ] ) ;
2016-10-21 10:30:58 +00:00
}
2017-03-01 18:12:40 +00:00
if ( ! components [ i ] - > annotation ( ) . isPure )
isPure = false ;
2015-10-12 21:02:35 +00:00
}
else
types . push_back ( TypePointer ( ) ) ;
}
2017-03-01 18:12:40 +00:00
_tuple . annotation ( ) . isPure = isPure ;
2016-01-11 20:25:59 +00:00
if ( _tuple . isInlineArray ( ) )
{
2017-10-05 13:28:25 +00:00
if ( ! inlineArrayType )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _tuple . location ( ) , " Unable to deduce common type for array elements. " ) ;
2018-11-29 18:44:33 +00:00
else if ( ! inlineArrayType - > canLiveOutsideStorage ( ) )
m_errorReporter . fatalTypeError ( _tuple . location ( ) , " Type " + inlineArrayType - > toString ( ) + " is only valid in storage. " ) ;
2019-04-17 11:40:50 +00:00
_tuple . annotation ( ) . type = TypeProvider : : array ( DataLocation : : Memory , inlineArrayType , types . size ( ) ) ;
2016-01-11 20:25:59 +00:00
}
2015-10-12 21:02:35 +00:00
else
{
2016-01-11 20:25:59 +00:00
if ( components . size ( ) = = 1 )
_tuple . annotation ( ) . type = type ( * components [ 0 ] ) ;
else
2019-04-17 11:40:50 +00:00
_tuple . annotation ( ) . type = TypeProvider : : tuple ( move ( types ) ) ;
2015-10-12 21:02:35 +00:00
}
2016-01-11 20:25:59 +00:00
2015-10-12 21:02:35 +00:00
}
return false ;
}
2015-09-16 14:56:30 +00:00
bool TypeChecker : : visit ( UnaryOperation const & _operation )
{
// Inc, Dec, Add, Sub, Not, BitNot, Delete
2018-10-22 14:48:21 +00:00
Token op = _operation . getOperator ( ) ;
bool const modifying = ( op = = Token : : Inc | | op = = Token : : Dec | | op = = Token : : Delete ) ;
2017-03-01 18:12:40 +00:00
if ( modifying )
2015-09-16 14:56:30 +00:00
requireLValue ( _operation . subExpression ( ) ) ;
else
_operation . subExpression ( ) . accept ( * this ) ;
TypePointer const & subExprType = type ( _operation . subExpression ( ) ) ;
TypePointer t = type ( _operation . subExpression ( ) ) - > unaryOperatorResult ( op ) ;
if ( ! t )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_operation . location ( ) ,
2015-09-16 14:56:30 +00:00
" Unary operator " +
2018-10-22 14:48:21 +00:00
string ( TokenTraits : : toString ( op ) ) +
2015-09-16 14:56:30 +00:00
" cannot be applied to type " +
subExprType - > toString ( )
) ;
t = subExprType ;
}
_operation . annotation ( ) . type = t ;
2017-03-01 18:12:40 +00:00
_operation . annotation ( ) . isPure = ! modifying & & _operation . subExpression ( ) . annotation ( ) . isPure ;
2015-09-16 14:56:30 +00:00
return false ;
}
void TypeChecker : : endVisit ( BinaryOperation const & _operation )
{
TypePointer const & leftType = type ( _operation . leftExpression ( ) ) ;
TypePointer const & rightType = type ( _operation . rightExpression ( ) ) ;
2018-12-05 13:34:27 +00:00
TypeResult result = leftType - > binaryOperatorResult ( _operation . getOperator ( ) , rightType ) ;
TypePointer commonType = result . get ( ) ;
2015-09-16 14:56:30 +00:00
if ( ! commonType )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_operation . location ( ) ,
2015-09-16 14:56:30 +00:00
" Operator " +
2018-10-22 14:48:21 +00:00
string ( TokenTraits : : toString ( _operation . getOperator ( ) ) ) +
2015-09-16 14:56:30 +00:00
" not compatible with types " +
leftType - > toString ( ) +
" and " +
2018-12-05 13:34:27 +00:00
rightType - > toString ( ) +
( ! result . message ( ) . empty ( ) ? " . " + result . message ( ) : " " )
2015-09-16 14:56:30 +00:00
) ;
commonType = leftType ;
}
_operation . annotation ( ) . commonType = commonType ;
_operation . annotation ( ) . type =
2018-10-22 14:48:21 +00:00
TokenTraits : : isCompareOp ( _operation . getOperator ( ) ) ?
2019-04-17 11:40:50 +00:00
TypeProvider : : boolean ( ) :
2015-09-16 14:56:30 +00:00
commonType ;
2017-03-01 18:12:40 +00:00
_operation . annotation ( ) . isPure =
_operation . leftExpression ( ) . annotation ( ) . isPure & &
_operation . rightExpression ( ) . annotation ( ) . isPure ;
2017-08-16 11:52:06 +00:00
if ( _operation . getOperator ( ) = = Token : : Exp | | _operation . getOperator ( ) = = Token : : SHL )
2017-03-07 12:44:11 +00:00
{
2017-08-16 11:52:06 +00:00
string operation = _operation . getOperator ( ) = = Token : : Exp ? " exponentiation " : " shift " ;
2017-03-07 12:44:11 +00:00
if (
leftType - > category ( ) = = Type : : Category : : RationalNumber & &
rightType - > category ( ) ! = Type : : Category : : RationalNumber
)
if ( (
commonType - > category ( ) = = Type : : Category : : Integer & &
dynamic_cast < IntegerType const & > ( * commonType ) . numBits ( ) ! = 256
) | | (
commonType - > category ( ) = = Type : : Category : : FixedPoint & &
dynamic_cast < FixedPointType const & > ( * commonType ) . numBits ( ) ! = 256
) )
2017-05-11 13:26:35 +00:00
m_errorReporter . warning (
2017-03-07 12:44:11 +00:00
_operation . location ( ) ,
2017-08-16 11:52:06 +00:00
" Result of " + operation + " has type " + commonType - > toString ( ) + " and thus "
2017-03-07 12:44:11 +00:00
" might overflow. Silence this warning by converting the literal to the "
" expected type. "
) ;
2019-07-07 15:53:03 +00:00
if (
commonType - > category ( ) = = Type : : Category : : Integer & &
rightType - > category ( ) = = Type : : Category : : Integer & &
dynamic_cast < IntegerType const & > ( * commonType ) . numBits ( ) <
dynamic_cast < IntegerType const & > ( * rightType ) . numBits ( )
)
m_errorReporter . warning (
_operation . location ( ) ,
" The result type of the " +
operation +
" operation is equal to the type of the first operand ( " +
commonType - > toString ( ) +
" ) ignoring the (larger) type of the second operand ( " +
rightType - > toString ( ) +
" ) which might be unexpected. Silence this warning by either converting "
" the first or the second operand to the type of the other. "
) ;
2017-03-07 12:44:11 +00:00
}
2015-09-16 14:56:30 +00:00
}
2018-10-18 21:53:59 +00:00
TypePointer TypeChecker : : typeCheckTypeConversionAndRetrieveReturnType (
FunctionCall const & _functionCall
)
2015-09-16 14:56:30 +00:00
{
2018-10-18 21:53:59 +00:00
solAssert ( _functionCall . annotation ( ) . kind = = FunctionCallKind : : TypeConversion , " " ) ;
TypePointer const & expressionType = type ( _functionCall . expression ( ) ) ;
2015-09-16 14:56:30 +00:00
2018-10-18 21:53:59 +00:00
vector < ASTPointer < Expression const > > const & arguments = _functionCall . arguments ( ) ;
bool const isPositionalCall = _functionCall . names ( ) . empty ( ) ;
2017-05-19 13:45:01 +00:00
2018-10-18 21:53:59 +00:00
TypePointer resultType = dynamic_cast < TypeType const & > ( * expressionType ) . actualType ( ) ;
if ( arguments . size ( ) ! = 1 )
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Exactly one argument expected for explicit type conversion. "
) ;
else if ( ! isPositionalCall )
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Type conversion cannot allow named arguments. "
) ;
2015-09-16 14:56:30 +00:00
else
{
2019-04-15 13:33:39 +00:00
Type const * argType = type ( * arguments . front ( ) ) ;
2018-10-18 21:53:59 +00:00
// Resulting data location is memory unless we are converting from a reference
// type with a different data location.
// (data location cannot yet be specified for type conversions)
DataLocation dataLoc = DataLocation : : Memory ;
2019-04-15 13:33:39 +00:00
if ( auto argRefType = dynamic_cast < ReferenceType const * > ( argType ) )
2018-10-18 21:53:59 +00:00
dataLoc = argRefType - > location ( ) ;
2019-04-15 13:33:39 +00:00
if ( auto type = dynamic_cast < ReferenceType const * > ( resultType ) )
resultType = TypeProvider : : withLocation ( type , dataLoc , type - > isPointer ( ) ) ;
2018-10-18 21:53:59 +00:00
if ( argType - > isExplicitlyConvertibleTo ( * resultType ) )
2015-09-16 14:56:30 +00:00
{
2019-04-15 13:33:39 +00:00
if ( auto argArrayType = dynamic_cast < ArrayType const * > ( argType ) )
2018-09-12 10:01:34 +00:00
{
2019-04-15 13:33:39 +00:00
auto resultArrayType = dynamic_cast < ArrayType const * > ( resultType ) ;
2018-10-18 21:53:59 +00:00
solAssert ( ! ! resultArrayType , " " ) ;
solAssert (
argArrayType - > location ( ) ! = DataLocation : : Storage | |
(
(
resultArrayType - > isPointer ( ) | |
( argArrayType - > isByteArray ( ) & & resultArrayType - > isByteArray ( ) )
) & &
resultArrayType - > location ( ) = = DataLocation : : Storage
) ,
" Invalid explicit conversion to storage type. "
) ;
2018-09-05 15:59:55 +00:00
}
2018-10-18 21:53:59 +00:00
}
else
{
if (
resultType - > category ( ) = = Type : : Category : : Contract & &
argType - > category ( ) = = Type : : Category : : Address
)
2018-09-05 15:59:55 +00:00
{
2019-04-15 13:33:39 +00:00
solAssert ( dynamic_cast < ContractType const * > ( resultType ) - > isPayable ( ) , " " ) ;
2018-10-18 21:53:59 +00:00
solAssert (
2019-04-15 13:33:39 +00:00
dynamic_cast < AddressType const * > ( argType ) - > stateMutability ( ) <
2018-10-18 21:53:59 +00:00
StateMutability : : Payable ,
" "
) ;
SecondarySourceLocation ssl ;
if (
auto const * identifier = dynamic_cast < Identifier const * > ( arguments . front ( ) . get ( ) )
)
if (
auto const * variableDeclaration = dynamic_cast < VariableDeclaration const * > (
identifier - > annotation ( ) . referencedDeclaration
)
)
ssl . append (
" Did you mean to declare this variable as \" address payable \" ? " ,
variableDeclaration - > location ( )
) ;
m_errorReporter . typeError (
2019-08-15 16:46:44 +00:00
_functionCall . location ( ) ,
ssl ,
2018-10-18 21:53:59 +00:00
" Explicit type conversion not allowed from non-payable \" address \" to \" " +
resultType - > toString ( ) +
" \" , which has a payable fallback function. "
) ;
2018-09-05 15:59:55 +00:00
}
2019-08-15 16:46:44 +00:00
else if (
auto const * functionType = dynamic_cast < FunctionType const * > ( argType ) ;
functionType & &
functionType - > kind ( ) = = FunctionType : : Kind : : External & &
resultType - > category ( ) = = Type : : Category : : Address
)
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Explicit type conversion not allowed from \" " +
argType - > toString ( ) +
" \" to \" " +
resultType - > toString ( ) +
" \" . To obtain the address of the contract of the function, " +
" you can use the .address member of the function. "
) ;
2018-10-18 21:53:59 +00:00
else
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Explicit type conversion not allowed from \" " +
argType - > toString ( ) +
" \" to \" " +
resultType - > toString ( ) +
" \" . "
) ;
}
2019-09-04 15:45:12 +00:00
if ( auto addressType = dynamic_cast < AddressType const * > ( resultType ) )
if ( addressType - > stateMutability ( ) ! = StateMutability : : Payable )
{
bool payable = false ;
if ( argType - > category ( ) ! = Type : : Category : : Address )
payable = argType - > isExplicitlyConvertibleTo ( * TypeProvider : : payableAddress ( ) ) ;
resultType = payable ? TypeProvider : : payableAddress ( ) : TypeProvider : : address ( ) ;
}
2015-09-16 14:56:30 +00:00
}
2018-10-18 21:53:59 +00:00
return resultType ;
}
2015-09-16 14:56:30 +00:00
2018-10-18 21:53:59 +00:00
void TypeChecker : : typeCheckFunctionCall (
FunctionCall const & _functionCall ,
FunctionTypePointer _functionType
)
{
2015-09-16 14:56:30 +00:00
// Actual function call or struct constructor call.
2018-10-18 21:53:59 +00:00
solAssert ( ! ! _functionType , " " ) ;
solAssert ( _functionType - > kind ( ) ! = FunctionType : : Kind : : ABIDecode , " " ) ;
2015-09-16 14:56:30 +00:00
2020-01-07 10:42:37 +00:00
if ( _functionType - > kind ( ) = = FunctionType : : Kind : : Declaration )
{
2020-03-06 09:44:51 +00:00
if (
m_scope - > derivesFrom ( * _functionType - > declaration ( ) . annotation ( ) . contract ) & &
! dynamic_cast < FunctionDefinition const & > ( _functionType - > declaration ( ) ) . isImplemented ( )
)
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Cannot call unimplemented base function. "
) ;
else
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Cannot call function via contract type name. "
) ;
2020-01-07 10:42:37 +00:00
return ;
}
2018-10-18 21:53:59 +00:00
// Check for unsupported use of bare static call
if (
_functionType - > kind ( ) = = FunctionType : : Kind : : BareStaticCall & &
! m_evmVersion . hasStaticCall ( )
)
m_errorReporter . typeError (
_functionCall . location ( ) ,
" \" staticcall \" is not supported by the VM version. "
) ;
// Perform standard function call type checking
typeCheckFunctionGeneralChecks ( _functionCall , _functionType ) ;
}
2019-09-09 16:22:02 +00:00
void TypeChecker : : typeCheckFallbackFunction ( FunctionDefinition const & _function )
{
solAssert ( _function . isFallback ( ) , " " ) ;
2020-01-07 14:11:29 +00:00
if ( _function . inContractKind ( ) = = ContractKind : : Library )
2019-09-09 16:22:02 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Libraries cannot have fallback functions. " ) ;
if ( _function . stateMutability ( ) ! = StateMutability : : NonPayable & & _function . stateMutability ( ) ! = StateMutability : : Payable )
m_errorReporter . typeError (
_function . location ( ) ,
" Fallback function must be payable or non-payable, but is \" " +
stateMutabilityToString ( _function . stateMutability ( ) ) +
" \" . "
) ;
2019-12-10 14:54:09 +00:00
if ( _function . visibility ( ) ! = Visibility : : External )
2019-09-09 16:22:02 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Fallback function must be defined as \" external \" . " ) ;
if ( ! _function . returnParameters ( ) . empty ( ) )
{
if ( _function . returnParameters ( ) . size ( ) > 1 | | * type ( * _function . returnParameters ( ) . front ( ) ) ! = * TypeProvider : : bytesMemory ( ) )
m_errorReporter . typeError ( _function . returnParameterList ( ) - > location ( ) , " Fallback function can only have a single \" bytes memory \" return value. " ) ;
else
m_errorReporter . typeError ( _function . returnParameterList ( ) - > location ( ) , " Return values for fallback functions are not yet implemented. " ) ;
}
if ( ! _function . parameters ( ) . empty ( ) )
m_errorReporter . typeError ( _function . parameterList ( ) . location ( ) , " Fallback function cannot take parameters. " ) ;
}
void TypeChecker : : typeCheckReceiveFunction ( FunctionDefinition const & _function )
{
solAssert ( _function . isReceive ( ) , " " ) ;
2020-01-07 14:11:29 +00:00
if ( _function . inContractKind ( ) = = ContractKind : : Library )
2019-09-09 16:22:02 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Libraries cannot have receive ether functions. " ) ;
if ( _function . stateMutability ( ) ! = StateMutability : : Payable )
m_errorReporter . typeError (
_function . location ( ) ,
" Receive ether function must be payable, but is \" " +
stateMutabilityToString ( _function . stateMutability ( ) ) +
" \" . "
) ;
2019-12-10 14:54:09 +00:00
if ( _function . visibility ( ) ! = Visibility : : External )
2019-09-09 16:22:02 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Receive ether function must be defined as \" external \" . " ) ;
if ( ! _function . returnParameters ( ) . empty ( ) )
m_errorReporter . typeError ( _function . returnParameterList ( ) - > location ( ) , " Receive ether function cannot return values. " ) ;
if ( ! _function . parameters ( ) . empty ( ) )
m_errorReporter . typeError ( _function . parameterList ( ) . location ( ) , " Receive ether function cannot take parameters. " ) ;
}
void TypeChecker : : typeCheckConstructor ( FunctionDefinition const & _function )
{
solAssert ( _function . isConstructor ( ) , " " ) ;
if ( ! _function . returnParameters ( ) . empty ( ) )
m_errorReporter . typeError ( _function . returnParameterList ( ) - > location ( ) , " Non-empty \" returns \" directive for constructor. " ) ;
if ( _function . stateMutability ( ) ! = StateMutability : : NonPayable & & _function . stateMutability ( ) ! = StateMutability : : Payable )
m_errorReporter . typeError (
_function . location ( ) ,
" Constructor must be payable or non-payable, but is \" " +
stateMutabilityToString ( _function . stateMutability ( ) ) +
" \" . "
) ;
2019-12-10 14:54:09 +00:00
if ( _function . visibility ( ) ! = Visibility : : Public & & _function . visibility ( ) ! = Visibility : : Internal )
2019-09-09 16:22:02 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Constructor must be public or internal. " ) ;
}
2018-10-18 21:53:59 +00:00
void TypeChecker : : typeCheckABIEncodeFunctions (
FunctionCall const & _functionCall ,
FunctionTypePointer _functionType
)
{
solAssert ( ! ! _functionType , " " ) ;
solAssert (
_functionType - > kind ( ) = = FunctionType : : Kind : : ABIEncode | |
_functionType - > kind ( ) = = FunctionType : : Kind : : ABIEncodePacked | |
_functionType - > kind ( ) = = FunctionType : : Kind : : ABIEncodeWithSelector | |
_functionType - > kind ( ) = = FunctionType : : Kind : : ABIEncodeWithSignature ,
" ABI function has unexpected FunctionType::Kind. "
) ;
solAssert ( _functionType - > takesArbitraryParameters ( ) , " ABI functions should be variadic. " ) ;
bool const isPacked = _functionType - > kind ( ) = = FunctionType : : Kind : : ABIEncodePacked ;
solAssert ( _functionType - > padArguments ( ) ! = isPacked , " ABI function with unexpected padding " ) ;
2018-08-15 12:40:20 +00:00
2018-10-18 21:53:59 +00:00
bool const abiEncoderV2 = m_scope - > sourceUnit ( ) . annotation ( ) . experimentalFeatures . count (
ExperimentalFeature : : ABIEncoderV2
) ;
// Check for named arguments
if ( ! _functionCall . names ( ) . empty ( ) )
2017-07-31 19:31:12 +00:00
{
2018-10-18 21:53:59 +00:00
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Named arguments cannot be used for functions that take arbitrary parameters. "
) ;
return ;
2017-07-31 19:31:12 +00:00
}
2018-10-18 21:53:59 +00:00
// Perform standard function call type checking
typeCheckFunctionGeneralChecks ( _functionCall , _functionType ) ;
2017-08-25 11:17:44 +00:00
2018-10-18 21:53:59 +00:00
// Check additional arguments for variadic functions
vector < ASTPointer < Expression const > > const & arguments = _functionCall . arguments ( ) ;
for ( size_t i = 0 ; i < arguments . size ( ) ; + + i )
2017-08-25 11:17:44 +00:00
{
2018-10-18 21:53:59 +00:00
auto const & argType = type ( * arguments [ i ] ) ;
if ( argType - > category ( ) = = Type : : Category : : RationalNumber )
2017-08-25 11:17:44 +00:00
{
2019-01-17 12:36:06 +00:00
auto const & rationalType = dynamic_cast < RationalNumberType const & > ( * argType ) ;
if ( rationalType . isFractional ( ) )
{
m_errorReporter . typeError (
arguments [ i ] - > location ( ) ,
2019-01-17 12:54:31 +00:00
" Fractional numbers cannot yet be encoded. "
2019-01-17 12:36:06 +00:00
) ;
continue ;
}
else if ( ! argType - > mobileType ( ) )
2017-08-25 11:17:44 +00:00
{
2018-10-18 21:53:59 +00:00
m_errorReporter . typeError (
arguments [ i ] - > location ( ) ,
" Invalid rational number (too large or division by zero). "
) ;
continue ;
}
else if ( isPacked )
{
m_errorReporter . typeError (
arguments [ i ] - > location ( ) ,
" Cannot perform packed encoding for a literal. "
" Please convert it to an explicit type first. "
) ;
continue ;
2017-08-25 11:17:44 +00:00
}
}
2018-10-18 21:53:59 +00:00
2019-02-04 17:13:41 +00:00
if ( isPacked & & ! typeSupportedByOldABIEncoder ( * argType , false /* isLibrary */ ) )
{
m_errorReporter . typeError (
arguments [ i ] - > location ( ) ,
" Type not supported in packed mode. "
) ;
continue ;
}
2018-10-18 21:53:59 +00:00
if ( ! argType - > fullEncodingType ( false , abiEncoderV2 , ! _functionType - > padArguments ( ) ) )
m_errorReporter . typeError (
arguments [ i ] - > location ( ) ,
" This type cannot be encoded. "
) ;
2017-08-25 11:17:44 +00:00
}
2018-10-18 21:53:59 +00:00
}
2017-08-25 11:17:44 +00:00
2018-10-18 21:53:59 +00:00
void TypeChecker : : typeCheckFunctionGeneralChecks (
FunctionCall const & _functionCall ,
FunctionTypePointer _functionType
)
{
// Actual function call or struct constructor call.
2018-06-30 16:09:13 +00:00
2018-10-18 21:53:59 +00:00
solAssert ( ! ! _functionType , " " ) ;
solAssert ( _functionType - > kind ( ) ! = FunctionType : : Kind : : ABIDecode , " " ) ;
2018-09-04 14:24:21 +00:00
2018-10-18 21:53:59 +00:00
bool const isPositionalCall = _functionCall . names ( ) . empty ( ) ;
bool const isVariadic = _functionType - > takesArbitraryParameters ( ) ;
solAssert (
! isVariadic | | _functionCall . annotation ( ) . kind = = FunctionCallKind : : FunctionCall ,
" Struct constructor calls cannot be variadic. "
) ;
TypePointers const & parameterTypes = _functionType - > parameterTypes ( ) ;
vector < ASTPointer < Expression const > > const & arguments = _functionCall . arguments ( ) ;
vector < ASTPointer < ASTString > > const & argumentNames = _functionCall . names ( ) ;
// Check number of passed in arguments
if (
arguments . size ( ) < parameterTypes . size ( ) | |
( ! isVariadic & & arguments . size ( ) > parameterTypes . size ( ) )
)
2015-09-16 14:56:30 +00:00
{
2018-10-18 21:53:59 +00:00
bool const isStructConstructorCall =
_functionCall . annotation ( ) . kind = = FunctionCallKind : : StructConstructorCall ;
string msg ;
if ( isVariadic )
msg + =
" Need at least " +
toString ( parameterTypes . size ( ) ) +
" arguments for " +
string ( isStructConstructorCall ? " struct constructor " : " function call " ) +
" , but provided only " +
toString ( arguments . size ( ) ) +
" . " ;
else
msg + =
" Wrong argument count for " +
string ( isStructConstructorCall ? " struct constructor " : " function call " ) +
" : " +
toString ( arguments . size ( ) ) +
" arguments given but " +
string ( isVariadic ? " need at least " : " expected " ) +
toString ( parameterTypes . size ( ) ) +
" . " ;
2018-01-04 10:24:39 +00:00
2015-09-16 14:56:30 +00:00
// Extend error message in case we try to construct a struct with mapping member.
2018-10-18 21:53:59 +00:00
if ( isStructConstructorCall )
2015-09-16 14:56:30 +00:00
{
2018-10-18 21:53:59 +00:00
/// For error message: Struct members that were removed during conversion to memory.
TypePointer const expressionType = type ( _functionCall . expression ( ) ) ;
TypeType const & t = dynamic_cast < TypeType const & > ( * expressionType ) ;
auto const & structType = dynamic_cast < StructType const & > ( * t . actualType ( ) ) ;
set < string > membersRemovedForStructConstructor = structType . membersMissingInMemory ( ) ;
if ( ! membersRemovedForStructConstructor . empty ( ) )
{
msg + = " Members that have to be skipped in memory: " ;
for ( auto const & member : membersRemovedForStructConstructor )
msg + = " " + member ;
}
2015-09-16 14:56:30 +00:00
}
2018-06-14 14:08:59 +00:00
else if (
2018-10-18 21:53:59 +00:00
_functionType - > kind ( ) = = FunctionType : : Kind : : BareCall | |
_functionType - > kind ( ) = = FunctionType : : Kind : : BareCallCode | |
_functionType - > kind ( ) = = FunctionType : : Kind : : BareDelegateCall | |
_functionType - > kind ( ) = = FunctionType : : Kind : : BareStaticCall
2018-06-14 14:08:59 +00:00
)
{
if ( arguments . empty ( ) )
2018-10-18 21:53:59 +00:00
msg + =
" This function requires a single bytes argument. "
" Use \" \" as argument to provide empty calldata. " ;
2018-06-14 14:08:59 +00:00
else
2018-10-18 21:53:59 +00:00
msg + =
" This function requires a single bytes argument. "
" If all your arguments are value types, you can use "
" abi.encode(...) to properly generate it. " ;
2018-06-14 14:08:59 +00:00
}
else if (
2018-10-18 21:53:59 +00:00
_functionType - > kind ( ) = = FunctionType : : Kind : : KECCAK256 | |
_functionType - > kind ( ) = = FunctionType : : Kind : : SHA256 | |
_functionType - > kind ( ) = = FunctionType : : Kind : : RIPEMD160
2018-06-14 14:08:59 +00:00
)
2018-06-27 13:00:34 +00:00
msg + =
" This function requires a single bytes argument. "
2018-10-18 21:53:59 +00:00
" Use abi.encodePacked(...) to obtain the pre-0.5.0 "
" behaviour or abi.encode(...) to use ABI encoding. " ;
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _functionCall . location ( ) , msg ) ;
2018-10-18 21:53:59 +00:00
return ;
2015-09-16 14:56:30 +00:00
}
2018-10-18 21:53:59 +00:00
// Parameter to argument map
std : : vector < Expression const * > paramArgMap ( parameterTypes . size ( ) ) ;
// Map parameters to arguments - trivially for positional calls, less so for named calls
if ( isPositionalCall )
for ( size_t i = 0 ; i < paramArgMap . size ( ) ; + + i )
paramArgMap [ i ] = arguments [ i ] . get ( ) ;
2015-09-16 14:56:30 +00:00
else
{
2018-10-18 21:53:59 +00:00
auto const & parameterNames = _functionType - > parameterNames ( ) ;
2019-02-07 14:53:11 +00:00
solAssert (
parameterNames . size ( ) = = argumentNames . size ( ) ,
" Unexpected parameter length mismatch! "
) ;
2018-10-18 21:53:59 +00:00
// Check for duplicate argument names
2015-09-16 14:56:30 +00:00
{
bool duplication = false ;
for ( size_t i = 0 ; i < argumentNames . size ( ) ; i + + )
for ( size_t j = i + 1 ; j < argumentNames . size ( ) ; j + + )
if ( * argumentNames [ i ] = = * argumentNames [ j ] )
{
duplication = true ;
2018-10-18 21:53:59 +00:00
m_errorReporter . typeError (
arguments [ i ] - > location ( ) ,
" Duplicate named argument \" " + * argumentNames [ i ] + " \" . "
) ;
2015-09-16 14:56:30 +00:00
}
2018-10-18 21:53:59 +00:00
if ( duplication )
return ;
}
2015-09-16 14:56:30 +00:00
2018-10-18 21:53:59 +00:00
// map parameter names to argument names
{
bool not_all_mapped = false ;
for ( size_t i = 0 ; i < paramArgMap . size ( ) ; i + + )
{
size_t j ;
for ( j = 0 ; j < argumentNames . size ( ) ; j + + )
if ( parameterNames [ i ] = = * argumentNames [ j ] )
break ;
if ( j < argumentNames . size ( ) )
paramArgMap [ i ] = arguments [ j ] . get ( ) ;
else
2015-09-16 14:56:30 +00:00
{
2018-10-18 21:53:59 +00:00
paramArgMap [ i ] = nullptr ;
not_all_mapped = true ;
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Named argument \" " +
* argumentNames [ i ] +
" \" does not match function declaration. "
) ;
2015-09-16 14:56:30 +00:00
}
2018-10-18 21:53:59 +00:00
}
if ( not_all_mapped )
return ;
2015-09-16 14:56:30 +00:00
}
}
2018-10-18 21:53:59 +00:00
// Check for compatible types between arguments and parameters
for ( size_t i = 0 ; i < paramArgMap . size ( ) ; + + i )
{
solAssert ( ! ! paramArgMap [ i ] , " unmapped parameter " ) ;
if ( ! type ( * paramArgMap [ i ] ) - > isImplicitlyConvertibleTo ( * parameterTypes [ i ] ) )
{
string msg =
" Invalid type for argument in function call. "
" Invalid implicit conversion from " +
type ( * paramArgMap [ i ] ) - > toString ( ) +
" to " +
parameterTypes [ i ] - > toString ( ) +
" requested. " ;
if (
_functionType - > kind ( ) = = FunctionType : : Kind : : BareCall | |
_functionType - > kind ( ) = = FunctionType : : Kind : : BareCallCode | |
_functionType - > kind ( ) = = FunctionType : : Kind : : BareDelegateCall | |
_functionType - > kind ( ) = = FunctionType : : Kind : : BareStaticCall
)
msg + =
" This function requires a single bytes argument. "
" If all your arguments are value types, you can "
" use abi.encode(...) to properly generate it. " ;
else if (
_functionType - > kind ( ) = = FunctionType : : Kind : : KECCAK256 | |
_functionType - > kind ( ) = = FunctionType : : Kind : : SHA256 | |
_functionType - > kind ( ) = = FunctionType : : Kind : : RIPEMD160
)
msg + =
" This function requires a single bytes argument. "
" Use abi.encodePacked(...) to obtain the pre-0.5.0 "
" behaviour or abi.encode(...) to use ABI encoding. " ;
m_errorReporter . typeError ( paramArgMap [ i ] - > location ( ) , msg ) ;
}
}
}
bool TypeChecker : : visit ( FunctionCall const & _functionCall )
{
vector < ASTPointer < Expression const > > const & arguments = _functionCall . arguments ( ) ;
bool argumentsArePure = true ;
// We need to check arguments' type first as they will be needed for overload resolution.
for ( ASTPointer < Expression const > const & argument : arguments )
{
argument - > accept ( * this ) ;
if ( ! argument - > annotation ( ) . isPure )
argumentsArePure = false ;
}
2019-03-19 16:12:21 +00:00
// Store argument types - and names if given - for overload resolution
2018-10-18 21:53:59 +00:00
{
2019-03-19 16:12:21 +00:00
FuncCallArguments funcCallArgs ;
funcCallArgs . names = _functionCall . names ( ) ;
2018-10-18 21:53:59 +00:00
for ( ASTPointer < Expression const > const & argument : arguments )
2019-03-19 16:12:21 +00:00
funcCallArgs . types . push_back ( type ( * argument ) ) ;
_functionCall . expression ( ) . annotation ( ) . arguments = std : : move ( funcCallArgs ) ;
2018-10-18 21:53:59 +00:00
}
_functionCall . expression ( ) . accept ( * this ) ;
2019-04-15 13:33:39 +00:00
Type const * expressionType = type ( _functionCall . expression ( ) ) ;
2018-10-18 21:53:59 +00:00
// Determine function call kind and function type for this FunctionCall node
FunctionCallAnnotation & funcCallAnno = _functionCall . annotation ( ) ;
2019-04-15 13:33:39 +00:00
FunctionTypePointer functionType = nullptr ;
2018-10-18 21:53:59 +00:00
2019-09-13 22:54:51 +00:00
// Determine and assign function call kind, lvalue, purity and function type for this FunctionCall node
2018-10-18 21:53:59 +00:00
switch ( expressionType - > category ( ) )
{
case Type : : Category : : Function :
2019-04-15 13:33:39 +00:00
functionType = dynamic_cast < FunctionType const * > ( expressionType ) ;
2018-10-18 21:53:59 +00:00
funcCallAnno . kind = FunctionCallKind : : FunctionCall ;
// Purity for function calls also depends upon the callee and its FunctionType
funcCallAnno . isPure =
argumentsArePure & &
_functionCall . expression ( ) . annotation ( ) . isPure & &
functionType & &
functionType - > isPure ( ) ;
2019-09-13 22:54:51 +00:00
if (
functionType - > kind ( ) = = FunctionType : : Kind : : ArrayPush | |
functionType - > kind ( ) = = FunctionType : : Kind : : ByteArrayPush
)
funcCallAnno . isLValue = functionType - > parameterTypes ( ) . empty ( ) ;
2018-10-18 21:53:59 +00:00
break ;
case Type : : Category : : TypeType :
{
// Determine type for type conversion or struct construction expressions
TypePointer const & actualType = dynamic_cast < TypeType const & > ( * expressionType ) . actualType ( ) ;
solAssert ( ! ! actualType , " " ) ;
if ( actualType - > category ( ) = = Type : : Category : : Struct )
{
functionType = dynamic_cast < StructType const & > ( * actualType ) . constructorType ( ) ;
funcCallAnno . kind = FunctionCallKind : : StructConstructorCall ;
funcCallAnno . isPure = argumentsArePure ;
}
else
{
funcCallAnno . kind = FunctionCallKind : : TypeConversion ;
funcCallAnno . isPure = argumentsArePure ;
}
break ;
}
default :
2020-02-13 13:33:27 +00:00
m_errorReporter . fatalTypeError ( _functionCall . location ( ) , " Type is not callable " ) ;
2018-10-18 21:53:59 +00:00
funcCallAnno . kind = FunctionCallKind : : Unset ;
funcCallAnno . isPure = argumentsArePure ;
break ;
}
// Determine return types
switch ( funcCallAnno . kind )
{
case FunctionCallKind : : TypeConversion :
funcCallAnno . type = typeCheckTypeConversionAndRetrieveReturnType ( _functionCall ) ;
break ;
case FunctionCallKind : : StructConstructorCall : // fall-through
case FunctionCallKind : : FunctionCall :
{
TypePointers returnTypes ;
switch ( functionType - > kind ( ) )
{
case FunctionType : : Kind : : ABIDecode :
{
bool const abiEncoderV2 =
m_scope - > sourceUnit ( ) . annotation ( ) . experimentalFeatures . count (
ExperimentalFeature : : ABIEncoderV2
) ;
returnTypes = typeCheckABIDecodeAndRetrieveReturnType ( _functionCall , abiEncoderV2 ) ;
break ;
}
case FunctionType : : Kind : : ABIEncode :
case FunctionType : : Kind : : ABIEncodePacked :
case FunctionType : : Kind : : ABIEncodeWithSelector :
case FunctionType : : Kind : : ABIEncodeWithSignature :
{
typeCheckABIEncodeFunctions ( _functionCall , functionType ) ;
returnTypes = functionType - > returnParameterTypes ( ) ;
break ;
}
2019-01-10 15:28:39 +00:00
case FunctionType : : Kind : : MetaType :
returnTypes = typeCheckMetaTypeFunctionAndRetrieveReturnType ( _functionCall ) ;
break ;
2018-10-18 21:53:59 +00:00
default :
{
typeCheckFunctionCall ( _functionCall , functionType ) ;
returnTypes = m_evmVersion . supportsReturndata ( ) ?
functionType - > returnParameterTypes ( ) :
functionType - > returnParameterTypesWithoutDynamicTypes ( ) ;
break ;
}
}
funcCallAnno . type = returnTypes . size ( ) = = 1 ?
move ( returnTypes . front ( ) ) :
2019-04-17 11:40:50 +00:00
TypeProvider : : tuple ( move ( returnTypes ) ) ;
2018-10-18 21:53:59 +00:00
break ;
}
case FunctionCallKind : : Unset : // fall-through
default :
// for non-callables, ensure error reported and annotate node to void function
solAssert ( m_errorReporter . hasErrors ( ) , " " ) ;
funcCallAnno . kind = FunctionCallKind : : FunctionCall ;
2019-04-17 11:40:50 +00:00
funcCallAnno . type = TypeProvider : : emptyTuple ( ) ;
2018-10-18 21:53:59 +00:00
break ;
}
2018-09-04 14:24:21 +00:00
2015-09-16 14:56:30 +00:00
return false ;
}
2020-01-22 14:42:50 +00:00
bool TypeChecker : : visit ( FunctionCallOptions const & _functionCallOptions )
{
solAssert ( _functionCallOptions . options ( ) . size ( ) = = _functionCallOptions . names ( ) . size ( ) , " Lengths of name & value arrays differ! " ) ;
_functionCallOptions . expression ( ) . accept ( * this ) ;
auto expressionFunctionType = dynamic_cast < FunctionType const * > ( type ( _functionCallOptions . expression ( ) ) ) ;
if ( ! expressionFunctionType )
{
m_errorReporter . fatalTypeError ( _functionCallOptions . location ( ) , " Expected callable expression before call options. " ) ;
return false ;
}
bool setSalt = false ;
bool setValue = false ;
bool setGas = false ;
FunctionType : : Kind kind = expressionFunctionType - > kind ( ) ;
if (
kind ! = FunctionType : : Kind : : Creation & &
kind ! = FunctionType : : Kind : : External & &
kind ! = FunctionType : : Kind : : BareCall & &
kind ! = FunctionType : : Kind : : BareCallCode & &
kind ! = FunctionType : : Kind : : BareDelegateCall & &
kind ! = FunctionType : : Kind : : BareStaticCall
)
{
m_errorReporter . fatalTypeError (
_functionCallOptions . location ( ) ,
" Function call options can only be set on external function calls or contract creations. "
) ;
return false ;
}
auto setCheckOption = [ & ] ( bool & _option , string const & & _name , bool _alreadySet = false )
{
if ( _option | | _alreadySet )
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
_alreadySet ?
" Option \" " + std : : move ( _name ) + " \" has already been set. " :
" Duplicate option \" " + std : : move ( _name ) + " \" . "
) ;
_option = true ;
} ;
for ( size_t i = 0 ; i < _functionCallOptions . names ( ) . size ( ) ; + + i )
{
string const & name = * ( _functionCallOptions . names ( ) [ i ] ) ;
if ( name = = " salt " )
{
if ( kind = = FunctionType : : Kind : : Creation )
{
setCheckOption ( setSalt , " salt " , expressionFunctionType - > saltSet ( ) ) ;
expectType ( * _functionCallOptions . options ( ) [ i ] , * TypeProvider : : fixedBytes ( 32 ) ) ;
}
else
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
" Function call option \" salt \" can only be used with \" new \" . "
) ;
}
else if ( name = = " value " )
{
if ( kind = = FunctionType : : Kind : : BareDelegateCall )
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
" Cannot set option \" value \" for delegatecall. "
) ;
else if ( kind = = FunctionType : : Kind : : BareStaticCall )
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
" Cannot set option \" value \" for staticcall. "
) ;
else if ( ! expressionFunctionType - > isPayable ( ) )
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
2020-03-03 11:15:59 +00:00
kind = = FunctionType : : Kind : : Creation ?
" Cannot set option \" value \" , since the constructor of " +
expressionFunctionType - > returnParameterTypes ( ) . front ( ) - > toString ( ) +
" is not payable. " :
" Cannot set option \" value \" on a non-payable function type. "
2020-01-22 14:42:50 +00:00
) ;
else
{
expectType ( * _functionCallOptions . options ( ) [ i ] , * TypeProvider : : uint256 ( ) ) ;
setCheckOption ( setValue , " value " , expressionFunctionType - > valueSet ( ) ) ;
}
}
else if ( name = = " gas " )
{
if ( kind = = FunctionType : : Kind : : Creation )
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
" Function call option \" gas \" cannot be used with \" new \" . "
) ;
else
{
expectType ( * _functionCallOptions . options ( ) [ i ] , * TypeProvider : : uint256 ( ) ) ;
setCheckOption ( setGas , " gas " , expressionFunctionType - > gasSet ( ) ) ;
}
}
else
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
" Unknown call option \" " + name + " \" . Valid options are \" salt \" , \" value \" and \" gas \" . "
) ;
}
if ( setSalt & & ! m_evmVersion . hasCreate2 ( ) )
m_errorReporter . typeError (
_functionCallOptions . location ( ) ,
" Unsupported call option \" salt \" (requires Constantinople-compatible VMs). "
) ;
_functionCallOptions . annotation ( ) . type = expressionFunctionType - > copyAndSetCallOptions ( setGas , setValue , setSalt ) ;
return false ;
}
2015-09-16 14:56:30 +00:00
void TypeChecker : : endVisit ( NewExpression const & _newExpression )
{
2015-11-17 00:47:47 +00:00
TypePointer type = _newExpression . typeName ( ) . annotation ( ) . type ;
solAssert ( ! ! type , " Type name not resolved. " ) ;
2015-11-16 23:06:57 +00:00
if ( auto contractName = dynamic_cast < UserDefinedTypeName const * > ( & _newExpression . typeName ( ) ) )
{
auto contract = dynamic_cast < ContractDefinition const * > ( & dereference ( * contractName ) ) ;
if ( ! contract )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _newExpression . location ( ) , " Identifier is not a contract. " ) ;
2019-01-17 11:59:11 +00:00
if ( contract - > isInterface ( ) )
2018-09-25 17:40:39 +00:00
m_errorReporter . fatalTypeError ( _newExpression . location ( ) , " Cannot instantiate an interface. " ) ;
2017-03-06 13:12:20 +00:00
if ( ! contract - > constructorIsPublic ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _newExpression . location ( ) , " Contract with internal constructor cannot be created directly. " ) ;
2019-11-04 13:12:58 +00:00
if ( contract - > abstract ( ) )
2019-09-04 22:01:13 +00:00
m_errorReporter . typeError ( _newExpression . location ( ) , " Cannot instantiate an abstract contract. " ) ;
2015-11-16 23:06:57 +00:00
2015-11-19 17:02:04 +00:00
solAssert ( ! ! m_scope , " " ) ;
m_scope - > annotation ( ) . contractDependencies . insert ( contract ) ;
2015-11-16 23:06:57 +00:00
solAssert (
! contract - > annotation ( ) . linearizedBaseContracts . empty ( ) ,
" Linearized base contracts not yet available. "
2015-09-16 14:56:30 +00:00
) ;
2015-11-19 17:02:04 +00:00
if ( contractDependenciesAreCyclic ( * m_scope ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-16 23:06:57 +00:00
_newExpression . location ( ) ,
" Circular reference for contract creation (cannot create instance of derived or same contract). "
) ;
2015-09-16 14:56:30 +00:00
2016-08-31 18:43:24 +00:00
_newExpression . annotation ( ) . type = FunctionType : : newExpressionType ( * contract ) ;
2015-11-16 23:06:57 +00:00
}
2015-11-17 00:47:47 +00:00
else if ( type - > category ( ) = = Type : : Category : : Array )
2015-11-16 23:06:57 +00:00
{
2015-11-17 00:47:47 +00:00
if ( ! type - > canLiveOutsideStorage ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-17 00:47:47 +00:00
_newExpression . typeName ( ) . location ( ) ,
" Type cannot live outside storage. "
) ;
if ( ! type - > isDynamicallySized ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-17 00:47:47 +00:00
_newExpression . typeName ( ) . location ( ) ,
" Length has to be placed in parentheses after the array type for new expression. "
) ;
2019-04-17 11:25:03 +00:00
type = TypeProvider : : withLocationIfReference ( DataLocation : : Memory , type ) ;
2019-04-17 11:40:50 +00:00
_newExpression . annotation ( ) . type = TypeProvider : : function (
2019-04-15 16:10:43 +00:00
TypePointers { TypeProvider : : uint256 ( ) } ,
2015-11-17 00:47:47 +00:00
TypePointers { type } ,
2019-02-07 14:53:11 +00:00
strings ( 1 , " " ) ,
strings ( 1 , " " ) ,
2017-08-28 12:35:28 +00:00
FunctionType : : Kind : : ObjectCreation ,
false ,
StateMutability : : Pure
2015-11-17 00:47:47 +00:00
) ;
2017-03-01 18:12:40 +00:00
_newExpression . annotation ( ) . isPure = true ;
2015-11-16 23:06:57 +00:00
}
else
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _newExpression . location ( ) , " Contract or array type expected. " ) ;
2015-09-16 14:56:30 +00:00
}
bool TypeChecker : : visit ( MemberAccess const & _memberAccess )
{
_memberAccess . expression ( ) . accept ( * this ) ;
TypePointer exprType = type ( _memberAccess . expression ( ) ) ;
ASTString const & memberName = _memberAccess . memberName ( ) ;
// Retrieve the types of the arguments if this is used to call a function.
2019-03-19 16:12:21 +00:00
auto const & arguments = _memberAccess . annotation ( ) . arguments ;
2015-11-19 17:02:04 +00:00
MemberList : : MemberMap possibleMembers = exprType - > members ( m_scope ) . membersByName ( memberName ) ;
2018-04-18 18:40:46 +00:00
size_t const initialMemberCount = possibleMembers . size ( ) ;
2019-03-19 16:12:21 +00:00
if ( initialMemberCount > 1 & & arguments )
2015-09-16 14:56:30 +00:00
{
// do overload resolution
for ( auto it = possibleMembers . begin ( ) ; it ! = possibleMembers . end ( ) ; )
if (
it - > type - > category ( ) = = Type : : Category : : Function & &
2019-03-19 16:12:21 +00:00
! dynamic_cast < FunctionType const & > ( * it - > type ) . canTakeArguments ( * arguments , exprType )
2015-09-16 14:56:30 +00:00
)
it = possibleMembers . erase ( it ) ;
else
+ + it ;
}
2018-07-17 12:31:21 +00:00
auto & annotation = _memberAccess . annotation ( ) ;
2018-10-09 03:29:37 +00:00
if ( possibleMembers . empty ( ) )
2015-09-16 14:56:30 +00:00
{
2018-04-18 18:40:46 +00:00
if ( initialMemberCount = = 0 )
{
// Try to see if the member was removed because it is only available for storage types.
2019-04-17 11:25:03 +00:00
auto storageType = TypeProvider : : withLocationIfReference (
2018-04-18 18:40:46 +00:00
DataLocation : : Storage ,
exprType
2015-09-16 14:56:30 +00:00
) ;
2018-04-18 18:40:46 +00:00
if ( ! storageType - > members ( m_scope ) . membersByName ( memberName ) . empty ( ) )
m_errorReporter . fatalTypeError (
_memberAccess . location ( ) ,
" Member \" " + memberName + " \" is not available in " +
exprType - > toString ( ) +
" outside of storage. "
) ;
}
2018-07-17 12:31:21 +00:00
string errorMsg = " Member \" " + memberName + " \" not found or not visible "
2018-10-04 15:31:52 +00:00
" after argument-dependent lookup in " + exprType - > toString ( ) + " . " ;
2019-02-12 15:09:16 +00:00
2019-04-15 13:33:39 +00:00
if ( auto const & funType = dynamic_cast < FunctionType const * > ( exprType ) )
2018-10-04 15:31:52 +00:00
{
2019-02-14 10:39:51 +00:00
auto const & t = funType - > returnParameterTypes ( ) ;
2019-02-12 15:09:16 +00:00
if ( memberName = = " value " )
{
if ( funType - > kind ( ) = = FunctionType : : Kind : : Creation )
errorMsg = " Constructor for " + t . front ( ) - > toString ( ) + " must be payable for member \" value \" to be available. " ;
2019-06-06 08:36:41 +00:00
else if (
funType - > kind ( ) = = FunctionType : : Kind : : DelegateCall | |
funType - > kind ( ) = = FunctionType : : Kind : : BareDelegateCall
)
errorMsg = " Member \" value \" is not allowed in delegated calls due to \" msg.value \" persisting. " ;
2019-02-12 15:09:16 +00:00
else
errorMsg = " Member \" value \" is only available for payable functions. " ;
}
else if (
t . size ( ) = = 1 & &
( t . front ( ) - > category ( ) = = Type : : Category : : Struct | |
t . front ( ) - > category ( ) = = Type : : Category : : Contract )
)
errorMsg + = " Did you intend to call the function? " ;
2018-10-04 15:31:52 +00:00
}
2019-02-12 15:56:22 +00:00
else if ( exprType - > category ( ) = = Type : : Category : : Contract )
{
2019-04-17 11:40:50 +00:00
for ( auto const & addressMember : TypeProvider : : payableAddress ( ) - > nativeMembers ( nullptr ) )
2018-07-17 12:31:21 +00:00
if ( addressMember . name = = memberName )
{
2018-07-18 17:51:24 +00:00
Identifier const * var = dynamic_cast < Identifier const * > ( & _memberAccess . expression ( ) ) ;
string varName = var ? var - > name ( ) : " ... " ;
errorMsg + = " Use \" address( " + varName + " ). " + memberName + " \" to access this address member. " ;
2018-07-17 12:31:21 +00:00
break ;
}
2019-02-12 15:56:22 +00:00
}
2019-04-15 13:33:39 +00:00
else if ( auto addressType = dynamic_cast < AddressType const * > ( exprType ) )
2019-02-12 15:56:22 +00:00
{
// Trigger error when using send or transfer with a non-payable fallback function.
if ( memberName = = " send " | | memberName = = " transfer " )
{
solAssert (
addressType - > stateMutability ( ) ! = StateMutability : : Payable ,
" Expected address not-payable as members were not found "
) ;
errorMsg = " \" send \" and \" transfer \" are only available for objects of type \" address payable \" , not \" " + exprType - > toString ( ) + " \" . " ;
}
}
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-04 10:49:26 +00:00
_memberAccess . location ( ) ,
2018-07-17 12:31:21 +00:00
errorMsg
2015-09-16 14:56:30 +00:00
) ;
}
else if ( possibleMembers . size ( ) > 1 )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-04 10:49:26 +00:00
_memberAccess . location ( ) ,
2015-09-16 14:56:30 +00:00
" Member \" " + memberName + " \" not unique "
2016-08-26 18:37:10 +00:00
" after argument-dependent lookup in " + exprType - > toString ( ) +
2018-07-16 15:11:39 +00:00
( memberName = = " value " ? " - did you forget the \" payable \" modifier? " : " . " )
2015-09-16 14:56:30 +00:00
) ;
annotation . referencedDeclaration = possibleMembers . front ( ) . declaration ;
annotation . type = possibleMembers . front ( ) . type ;
2015-11-27 21:24:00 +00:00
2019-04-15 13:33:39 +00:00
if ( auto funType = dynamic_cast < FunctionType const * > ( annotation . type ) )
2020-03-03 11:15:59 +00:00
{
2019-02-12 10:41:05 +00:00
solAssert (
! funType - > bound ( ) | | exprType - > isImplicitlyConvertibleTo ( * funType - > selfType ( ) ) ,
" Function \" " + memberName + " \" cannot be called on an object of type " +
exprType - > toString ( ) + " (expected " + funType - > selfType ( ) - > toString ( ) + " ). "
) ;
2015-11-27 21:24:00 +00:00
2020-03-03 11:15:59 +00:00
if (
dynamic_cast < FunctionType const * > ( exprType ) & &
! annotation . referencedDeclaration & &
( memberName = = " value " | | memberName = = " gas " )
)
m_errorReporter . warning (
_memberAccess . location ( ) ,
" Using \" . " + memberName + " (...) \" is deprecated. Use \" { " + memberName + " : ...} \" instead. "
) ;
}
2019-04-15 13:33:39 +00:00
if ( auto const * structType = dynamic_cast < StructType const * > ( exprType ) )
2019-02-05 19:29:57 +00:00
annotation . isLValue = ! structType - > dataStoredIn ( DataLocation : : CallData ) ;
2015-09-16 14:56:30 +00:00
else if ( exprType - > category ( ) = = Type : : Category : : Array )
2019-09-18 12:58:20 +00:00
annotation . isLValue = false ;
2016-02-03 20:34:24 +00:00
else if ( exprType - > category ( ) = = Type : : Category : : FixedBytes )
annotation . isLValue = false ;
2019-04-15 13:33:39 +00:00
else if ( TypeType const * typeType = dynamic_cast < decltype ( typeType ) > ( exprType ) )
2016-10-24 17:22:09 +00:00
{
2019-04-15 13:33:39 +00:00
if ( ContractType const * contractType = dynamic_cast < decltype ( contractType ) > ( typeType - > actualType ( ) ) )
2020-02-07 11:44:52 +00:00
{
2016-10-24 17:22:09 +00:00
annotation . isLValue = annotation . referencedDeclaration - > isLValue ( ) ;
2020-02-07 11:44:52 +00:00
if (
auto const * functionType = dynamic_cast < FunctionType const * > ( annotation . type ) ;
functionType & &
functionType - > kind ( ) = = FunctionType : : Kind : : Declaration
)
annotation . isPure = _memberAccess . expression ( ) . annotation ( ) . isPure ;
}
2016-10-24 17:22:09 +00:00
}
2015-09-16 14:56:30 +00:00
2017-03-01 18:12:40 +00:00
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
2017-03-01 18:49:15 +00:00
// although every subexpression is, so leaving this limited for now.
2019-04-15 13:33:39 +00:00
if ( auto tt = dynamic_cast < TypeType const * > ( exprType ) )
2017-03-01 18:49:15 +00:00
if ( tt - > actualType ( ) - > category ( ) = = Type : : Category : : Enum )
annotation . isPure = true ;
2020-02-07 11:44:52 +00:00
if (
auto const * functionType = dynamic_cast < FunctionType const * > ( exprType ) ;
functionType & &
functionType - > hasDeclaration ( ) & &
dynamic_cast < FunctionDefinition const * > ( & functionType - > declaration ( ) ) & &
memberName = = " selector "
)
if ( auto const * parentAccess = dynamic_cast < MemberAccess const * > ( & _memberAccess . expression ( ) ) )
{
annotation . isPure = parentAccess - > expression ( ) . annotation ( ) . isPure ;
if ( auto const * exprInt = dynamic_cast < Identifier const * > ( & parentAccess - > expression ( ) ) )
if ( exprInt - > name ( ) = = " this " | | exprInt - > name ( ) = = " super " )
annotation . isPure = true ;
}
2019-04-15 13:33:39 +00:00
if ( auto magicType = dynamic_cast < MagicType const * > ( exprType ) )
2019-01-10 15:28:39 +00:00
{
2018-05-15 11:04:49 +00:00
if ( magicType - > kind ( ) = = MagicType : : Kind : : ABI )
annotation . isPure = true ;
2019-01-14 23:14:10 +00:00
else if ( magicType - > kind ( ) = = MagicType : : Kind : : MetaType & & (
memberName = = " creationCode " | | memberName = = " runtimeCode "
) )
{
annotation . isPure = true ;
m_scope - > annotation ( ) . contractDependencies . insert (
& dynamic_cast < ContractType const & > ( * magicType - > typeArgument ( ) ) . contractDefinition ( )
) ;
if ( contractDependenciesAreCyclic ( * m_scope ) )
m_errorReporter . typeError (
_memberAccess . location ( ) ,
" Circular reference for contract code access. "
) ;
}
2019-01-22 16:15:55 +00:00
else if ( magicType - > kind ( ) = = MagicType : : Kind : : MetaType & & memberName = = " name " )
annotation . isPure = true ;
2019-01-10 15:28:39 +00:00
}
2017-03-01 18:12:40 +00:00
2015-09-16 14:56:30 +00:00
return false ;
}
bool TypeChecker : : visit ( IndexAccess const & _access )
{
_access . baseExpression ( ) . accept ( * this ) ;
TypePointer baseType = type ( _access . baseExpression ( ) ) ;
2019-04-15 13:33:39 +00:00
TypePointer resultType = nullptr ;
2015-09-16 14:56:30 +00:00
bool isLValue = false ;
2017-03-01 18:12:40 +00:00
bool isPure = _access . baseExpression ( ) . annotation ( ) . isPure ;
2015-09-16 14:56:30 +00:00
Expression const * index = _access . indexExpression ( ) ;
switch ( baseType - > category ( ) )
{
2019-09-03 16:30:00 +00:00
case Type : : Category : : ArraySlice :
{
auto const & arrayType = dynamic_cast < ArraySliceType const & > ( * baseType ) . arrayType ( ) ;
if ( arrayType . location ( ) ! = DataLocation : : CallData | | ! arrayType . isDynamicallySized ( ) )
m_errorReporter . typeError ( _access . location ( ) , " Index access is only implemented for slices of dynamic calldata arrays. " ) ;
baseType = & arrayType ;
[[fallthrough]] ;
}
2015-09-16 14:56:30 +00:00
case Type : : Category : : Array :
{
ArrayType const & actualType = dynamic_cast < ArrayType const & > ( * baseType ) ;
if ( ! index )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _access . location ( ) , " Index expression cannot be omitted. " ) ;
2015-09-16 14:56:30 +00:00
else if ( actualType . isString ( ) )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _access . location ( ) , " Index access for string is not possible. " ) ;
2015-09-16 14:56:30 +00:00
index - > accept ( * this ) ;
}
else
{
2019-04-15 16:10:43 +00:00
expectType ( * index , * TypeProvider : : uint256 ( ) ) ;
2018-08-30 03:08:49 +00:00
if ( ! m_errorReporter . hasErrors ( ) )
2019-04-15 13:33:39 +00:00
if ( auto numberType = dynamic_cast < RationalNumberType const * > ( type ( * index ) ) )
2018-08-30 03:08:49 +00:00
{
solAssert ( ! numberType - > isFractional ( ) , " " ) ;
2016-05-10 12:30:24 +00:00
if ( ! actualType . isDynamicallySized ( ) & & actualType . length ( ) < = numberType - > literalValue ( nullptr ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _access . location ( ) , " Out of bounds array access. " ) ;
2018-08-30 03:08:49 +00:00
}
2015-09-16 14:56:30 +00:00
}
resultType = actualType . baseType ( ) ;
isLValue = actualType . location ( ) ! = DataLocation : : CallData ;
break ;
}
case Type : : Category : : Mapping :
{
MappingType const & actualType = dynamic_cast < MappingType const & > ( * baseType ) ;
if ( ! index )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _access . location ( ) , " Index expression cannot be omitted. " ) ;
2015-09-16 14:56:30 +00:00
else
expectType ( * index , * actualType . keyType ( ) ) ;
resultType = actualType . valueType ( ) ;
isLValue = true ;
break ;
}
case Type : : Category : : TypeType :
{
TypeType const & typeType = dynamic_cast < TypeType const & > ( * baseType ) ;
2019-04-15 13:33:39 +00:00
if ( dynamic_cast < ContractType const * > ( typeType . actualType ( ) ) )
2019-02-21 15:38:02 +00:00
m_errorReporter . typeError ( _access . location ( ) , " Index access for contracts or libraries is not possible. " ) ;
2015-09-16 14:56:30 +00:00
if ( ! index )
2019-04-17 11:40:50 +00:00
resultType = TypeProvider : : typeType ( TypeProvider : : array ( DataLocation : : Memory , typeType . actualType ( ) ) ) ;
2015-09-16 14:56:30 +00:00
else
{
2019-02-05 12:32:01 +00:00
u256 length = 1 ;
2019-04-15 16:10:43 +00:00
if ( expectType ( * index , * TypeProvider : : uint256 ( ) ) )
2019-02-05 12:32:01 +00:00
{
2019-04-15 13:33:39 +00:00
if ( auto indexValue = dynamic_cast < RationalNumberType const * > ( type ( * index ) ) )
2019-02-05 12:32:01 +00:00
length = indexValue - > literalValue ( nullptr ) ;
else
m_errorReporter . fatalTypeError ( index - > location ( ) , " Integer constant expected. " ) ;
}
2015-09-16 14:56:30 +00:00
else
2019-02-05 12:32:01 +00:00
solAssert ( m_errorReporter . hasErrors ( ) , " Expected errors as expectType returned false " ) ;
2019-04-17 11:40:50 +00:00
resultType = TypeProvider : : typeType ( TypeProvider : : array (
2019-02-05 12:32:01 +00:00
DataLocation : : Memory ,
typeType . actualType ( ) ,
length
) ) ;
2015-09-16 14:56:30 +00:00
}
break ;
}
2016-02-03 20:34:24 +00:00
case Type : : Category : : FixedBytes :
{
FixedBytesType const & bytesType = dynamic_cast < FixedBytesType const & > ( * baseType ) ;
if ( ! index )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _access . location ( ) , " Index expression cannot be omitted. " ) ;
2016-02-03 20:34:24 +00:00
else
{
2019-04-15 16:10:43 +00:00
if ( ! expectType ( * index , * TypeProvider : : uint256 ( ) ) )
2018-10-10 17:33:45 +00:00
m_errorReporter . fatalTypeError ( _access . location ( ) , " Index expression cannot be represented as an unsigned integer. " ) ;
2019-04-15 13:33:39 +00:00
if ( auto integerType = dynamic_cast < RationalNumberType const * > ( type ( * index ) ) )
2016-02-03 20:34:24 +00:00
if ( bytesType . numBytes ( ) < = integerType - > literalValue ( nullptr ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _access . location ( ) , " Out of bounds array access. " ) ;
2016-02-03 20:34:24 +00:00
}
2019-04-17 11:40:50 +00:00
resultType = TypeProvider : : fixedBytes ( 1 ) ;
2016-02-03 20:34:24 +00:00
isLValue = false ; // @todo this heavily depends on how it is embedded
break ;
}
2015-09-16 14:56:30 +00:00
default :
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-04 10:49:26 +00:00
_access . baseExpression ( ) . location ( ) ,
2015-09-16 14:56:30 +00:00
" Indexed expression has to be a type, mapping or array (is " + baseType - > toString ( ) + " ) "
) ;
}
2019-04-15 13:33:39 +00:00
_access . annotation ( ) . type = resultType ;
2015-09-16 14:56:30 +00:00
_access . annotation ( ) . isLValue = isLValue ;
2017-03-01 18:12:40 +00:00
if ( index & & ! index - > annotation ( ) . isPure )
isPure = false ;
_access . annotation ( ) . isPure = isPure ;
2015-09-16 14:56:30 +00:00
return false ;
}
2019-09-03 16:30:00 +00:00
bool TypeChecker : : visit ( IndexRangeAccess const & _access )
{
_access . baseExpression ( ) . accept ( * this ) ;
bool isLValue = false ; // TODO: set this correctly when implementing slices for memory and storage arrays
bool isPure = _access . baseExpression ( ) . annotation ( ) . isPure ;
if ( Expression const * start = _access . startExpression ( ) )
{
expectType ( * start , * TypeProvider : : uint256 ( ) ) ;
if ( ! start - > annotation ( ) . isPure )
isPure = false ;
}
if ( Expression const * end = _access . endExpression ( ) )
{
expectType ( * end , * TypeProvider : : uint256 ( ) ) ;
if ( ! end - > annotation ( ) . isPure )
isPure = false ;
}
TypePointer exprType = type ( _access . baseExpression ( ) ) ;
if ( exprType - > category ( ) = = Type : : Category : : TypeType )
{
m_errorReporter . typeError ( _access . location ( ) , " Types cannot be sliced. " ) ;
_access . annotation ( ) . type = exprType ;
return false ;
}
ArrayType const * arrayType = nullptr ;
if ( auto const * arraySlice = dynamic_cast < ArraySliceType const * > ( exprType ) )
arrayType = & arraySlice - > arrayType ( ) ;
else if ( ! ( arrayType = dynamic_cast < ArrayType const * > ( exprType ) ) )
m_errorReporter . fatalTypeError ( _access . location ( ) , " Index range access is only possible for arrays and array slices. " ) ;
if ( arrayType - > location ( ) ! = DataLocation : : CallData | | ! arrayType - > isDynamicallySized ( ) )
m_errorReporter . typeError ( _access . location ( ) , " Index range access is only supported for dynamic calldata arrays. " ) ;
_access . annotation ( ) . type = TypeProvider : : arraySlice ( * arrayType ) ;
_access . annotation ( ) . isLValue = isLValue ;
_access . annotation ( ) . isPure = isPure ;
return false ;
}
2015-09-16 14:56:30 +00:00
bool TypeChecker : : visit ( Identifier const & _identifier )
{
2015-09-21 16:55:58 +00:00
IdentifierAnnotation & annotation = _identifier . annotation ( ) ;
2015-09-16 14:56:30 +00:00
if ( ! annotation . referencedDeclaration )
{
2019-03-19 16:12:21 +00:00
if ( ! annotation . arguments )
2016-12-02 15:24:53 +00:00
{
// The identifier should be a public state variable shadowing other functions
vector < Declaration const * > candidates ;
for ( Declaration const * declaration : annotation . overloadedDeclarations )
{
if ( VariableDeclaration const * variableDeclaration = dynamic_cast < decltype ( variableDeclaration ) > ( declaration ) )
candidates . push_back ( declaration ) ;
}
if ( candidates . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _identifier . location ( ) , " No matching declaration found after variable lookup. " ) ;
2016-12-02 15:24:53 +00:00
else if ( candidates . size ( ) = = 1 )
annotation . referencedDeclaration = candidates . front ( ) ;
else
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _identifier . location ( ) , " No unique declaration found after variable lookup. " ) ;
2016-12-02 15:24:53 +00:00
}
else if ( annotation . overloadedDeclarations . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _identifier . location ( ) , " No candidates for overload resolution found. " ) ;
2015-09-16 14:56:30 +00:00
else if ( annotation . overloadedDeclarations . size ( ) = = 1 )
annotation . referencedDeclaration = * annotation . overloadedDeclarations . begin ( ) ;
else
{
vector < Declaration const * > candidates ;
for ( Declaration const * declaration : annotation . overloadedDeclarations )
{
2017-12-30 12:46:53 +00:00
FunctionTypePointer functionType = declaration - > functionType ( true ) ;
solAssert ( ! ! functionType , " Requested type not present. " ) ;
2019-03-19 16:12:21 +00:00
if ( functionType - > canTakeArguments ( * annotation . arguments ) )
2015-09-16 14:56:30 +00:00
candidates . push_back ( declaration ) ;
}
2019-11-13 13:24:48 +00:00
if ( candidates . size ( ) = = 1 )
2015-09-16 14:56:30 +00:00
annotation . referencedDeclaration = candidates . front ( ) ;
else
2019-11-13 13:24:48 +00:00
{
SecondarySourceLocation ssl ;
for ( Declaration const * declaration : annotation . overloadedDeclarations )
2020-02-03 07:04:21 +00:00
if ( ! declaration - > location ( ) . isValid ( ) )
2019-11-13 17:06:50 +00:00
{
// Try to re-construct function definition
string description ;
for ( auto const & param : declaration - > functionType ( true ) - > parameterTypes ( ) )
description + = ( description . empty ( ) ? " " : " , " ) + param - > toString ( false ) ;
description = " function " + _identifier . name ( ) + " ( " + description + " ) " ;
ssl . append ( " Candidate: " + description , declaration - > location ( ) ) ;
}
else
ssl . append ( " Candidate: " , declaration - > location ( ) ) ;
2019-11-13 13:24:48 +00:00
if ( candidates . empty ( ) )
m_errorReporter . fatalTypeError ( _identifier . location ( ) , ssl , " No matching declaration found after argument-dependent lookup. " ) ;
else
m_errorReporter . fatalTypeError ( _identifier . location ( ) , ssl , " No unique declaration found after argument-dependent lookup. " ) ;
}
2015-09-16 14:56:30 +00:00
}
}
solAssert (
! ! annotation . referencedDeclaration ,
" Referenced declaration is null after overload resolution. "
) ;
annotation . isLValue = annotation . referencedDeclaration - > isLValue ( ) ;
2015-11-19 17:02:04 +00:00
annotation . type = annotation . referencedDeclaration - > type ( ) ;
2020-01-14 13:00:51 +00:00
solAssert ( annotation . type , " Declaration referenced before type could be determined. " ) ;
2017-03-01 18:12:40 +00:00
if ( auto variableDeclaration = dynamic_cast < VariableDeclaration const * > ( annotation . referencedDeclaration ) )
annotation . isPure = annotation . isConstant = variableDeclaration - > isConstant ( ) ;
else if ( dynamic_cast < MagicVariableDeclaration const * > ( annotation . referencedDeclaration ) )
2019-02-18 17:19:55 +00:00
{
2019-04-15 13:33:39 +00:00
if ( dynamic_cast < FunctionType const * > ( annotation . type ) )
2017-04-21 09:13:10 +00:00
annotation . isPure = true ;
2019-02-18 17:19:55 +00:00
}
2019-04-15 13:33:39 +00:00
else if ( dynamic_cast < TypeType const * > ( annotation . type ) )
2019-02-18 17:19:55 +00:00
annotation . isPure = true ;
2018-11-29 09:05:52 +00:00
// Check for deprecated function names.
// The check is done here for the case without an actual function call.
2019-04-15 13:33:39 +00:00
if ( FunctionType const * fType = dynamic_cast < FunctionType const * > ( _identifier . annotation ( ) . type ) )
2018-11-29 09:05:52 +00:00
{
if ( _identifier . name ( ) = = " sha3 " & & fType - > kind ( ) = = FunctionType : : Kind : : KECCAK256 )
m_errorReporter . typeError (
_identifier . location ( ) ,
2019-10-21 11:17:12 +00:00
" \" sha3 \" has been deprecated in favour of \" keccak256 \" . "
2018-11-29 09:05:52 +00:00
) ;
else if ( _identifier . name ( ) = = " suicide " & & fType - > kind ( ) = = FunctionType : : Kind : : Selfdestruct )
m_errorReporter . typeError (
_identifier . location ( ) ,
2019-10-21 11:17:12 +00:00
" \" suicide \" has been deprecated in favour of \" selfdestruct \" . "
2018-11-29 09:05:52 +00:00
) ;
}
2015-09-16 14:56:30 +00:00
return false ;
}
void TypeChecker : : endVisit ( ElementaryTypeNameExpression const & _expr )
{
2019-09-04 15:45:12 +00:00
_expr . annotation ( ) . type = TypeProvider : : typeType ( TypeProvider : : fromElementaryTypeName ( _expr . type ( ) . typeName ( ) , _expr . type ( ) . stateMutability ( ) ) ) ;
2017-03-01 18:12:40 +00:00
_expr . annotation ( ) . isPure = true ;
2015-09-16 14:56:30 +00:00
}
void TypeChecker : : endVisit ( Literal const & _literal )
{
2017-01-24 16:38:06 +00:00
if ( _literal . looksLikeAddress ( ) )
{
2018-07-05 13:48:57 +00:00
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
2019-04-17 11:40:50 +00:00
_literal . annotation ( ) . type = TypeProvider : : payableAddress ( ) ;
2018-02-16 04:24:32 +00:00
2018-06-25 14:25:21 +00:00
string msg ;
2018-10-01 12:36:57 +00:00
if ( _literal . valueWithoutUnderscores ( ) . length ( ) ! = 42 ) // "0x" + 40 hex digits
2018-06-11 10:45:39 +00:00
// looksLikeAddress enforces that it is a hex literal starting with "0x"
2018-06-25 14:25:21 +00:00
msg =
2018-06-11 10:45:39 +00:00
" This looks like an address but is not exactly 40 hex digits. It is " +
2018-10-01 12:36:57 +00:00
to_string ( _literal . valueWithoutUnderscores ( ) . length ( ) - 2 ) +
2018-06-25 14:25:21 +00:00
" hex digits. " ;
2018-02-16 04:24:32 +00:00
else if ( ! _literal . passesAddressChecksum ( ) )
2018-06-25 14:25:21 +00:00
{
msg = " This looks like an address but has an invalid checksum. " ;
if ( ! _literal . getChecksummedAddress ( ) . empty ( ) )
msg + = " Correct checksummed address: \" " + _literal . getChecksummedAddress ( ) + " \" . " ;
}
if ( ! msg . empty ( ) )
2018-02-16 04:24:32 +00:00
m_errorReporter . syntaxError (
2017-03-06 12:31:57 +00:00
_literal . location ( ) ,
2018-06-25 14:25:21 +00:00
msg +
" If this is not used as an address, please prepend '00'. " +
2017-10-05 13:28:25 +00:00
" For more information please see https://solidity.readthedocs.io/en/develop/types.html#address-literals "
2017-03-06 12:31:57 +00:00
) ;
2017-01-24 16:38:06 +00:00
}
2018-04-23 13:54:45 +00:00
2018-03-01 15:58:20 +00:00
if ( _literal . isHexNumber ( ) & & _literal . subDenomination ( ) ! = Literal : : SubDenomination : : None )
2018-07-05 13:48:57 +00:00
m_errorReporter . fatalTypeError (
_literal . location ( ) ,
" Hexadecimal numbers cannot be used with unit denominations. "
" You can use an expression of the form \" 0x1234 * 1 day \" instead. "
) ;
2018-04-23 13:54:45 +00:00
if ( _literal . subDenomination ( ) = = Literal : : SubDenomination : : Year )
2018-06-20 22:01:40 +00:00
m_errorReporter . typeError (
_literal . location ( ) ,
" Using \" years \" as a unit denomination is deprecated. "
) ;
2018-04-23 13:54:45 +00:00
2017-06-22 13:59:00 +00:00
if ( ! _literal . annotation ( ) . type )
2019-04-15 13:33:39 +00:00
_literal . annotation ( ) . type = TypeProvider : : forLiteral ( _literal ) ;
2017-06-22 13:59:00 +00:00
2015-09-16 14:56:30 +00:00
if ( ! _literal . annotation ( ) . type )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _literal . location ( ) , " Invalid literal value. " ) ;
2017-06-22 13:59:00 +00:00
_literal . annotation ( ) . isPure = true ;
2015-09-16 14:56:30 +00:00
}
2015-10-07 13:57:17 +00:00
bool TypeChecker : : contractDependenciesAreCyclic (
ContractDefinition const & _contract ,
std : : set < ContractDefinition const * > const & _seenContracts
) const
{
// Naive depth-first search that remembers nodes already seen.
if ( _seenContracts . count ( & _contract ) )
return true ;
set < ContractDefinition const * > seen ( _seenContracts ) ;
seen . insert ( & _contract ) ;
for ( auto const * c : _contract . annotation ( ) . contractDependencies )
if ( contractDependenciesAreCyclic ( * c , seen ) )
return true ;
return false ;
}
2015-11-24 15:34:02 +00:00
Declaration const & TypeChecker : : dereference ( Identifier const & _identifier ) const
2015-09-16 14:56:30 +00:00
{
solAssert ( ! ! _identifier . annotation ( ) . referencedDeclaration , " Declaration not stored. " ) ;
return * _identifier . annotation ( ) . referencedDeclaration ;
}
2015-11-24 15:34:02 +00:00
Declaration const & TypeChecker : : dereference ( UserDefinedTypeName const & _typeName ) const
2015-11-16 23:06:57 +00:00
{
solAssert ( ! ! _typeName . annotation ( ) . referencedDeclaration , " Declaration not stored. " ) ;
return * _typeName . annotation ( ) . referencedDeclaration ;
}
2018-10-10 17:33:45 +00:00
bool TypeChecker : : expectType ( Expression const & _expression , Type const & _expectedType )
2015-09-16 14:56:30 +00:00
{
_expression . accept ( * this ) ;
if ( ! type ( _expression ) - > isImplicitlyConvertibleTo ( _expectedType ) )
2016-05-05 22:47:08 +00:00
{
2018-11-30 09:39:21 +00:00
auto errorMsg = " Type " +
type ( _expression ) - > toString ( ) +
" is not implicitly convertible to expected type " +
_expectedType . toString ( ) ;
2016-05-05 22:47:08 +00:00
if (
type ( _expression ) - > category ( ) = = Type : : Category : : RationalNumber & &
2019-04-15 13:33:39 +00:00
dynamic_cast < RationalNumberType const * > ( type ( _expression ) ) - > isFractional ( ) & &
2016-05-10 08:26:53 +00:00
type ( _expression ) - > mobileType ( )
2016-05-05 22:47:08 +00:00
)
2018-11-30 09:39:21 +00:00
{
if ( _expectedType . operator = = ( * type ( _expression ) - > mobileType ( ) ) )
m_errorReporter . typeError (
_expression . location ( ) ,
errorMsg + " , but it can be explicitly converted. "
) ;
else
m_errorReporter . typeError (
_expression . location ( ) ,
errorMsg +
" . Try converting to type " +
type ( _expression ) - > mobileType ( ) - > toString ( ) +
" or use an explicit conversion. "
) ;
}
2016-05-05 22:47:08 +00:00
else
2018-11-30 09:39:21 +00:00
m_errorReporter . typeError ( _expression . location ( ) , errorMsg + " . " ) ;
2018-10-10 17:33:45 +00:00
return false ;
2017-06-22 14:14:14 +00:00
}
2018-10-10 17:33:45 +00:00
return true ;
2015-09-16 14:56:30 +00:00
}
void TypeChecker : : requireLValue ( Expression const & _expression )
{
2015-10-12 21:02:35 +00:00
_expression . annotation ( ) . lValueRequested = true ;
2015-09-16 14:56:30 +00:00
_expression . accept ( * this ) ;
2016-12-13 02:59:53 +00:00
2019-08-12 15:06:10 +00:00
if ( _expression . annotation ( ) . isLValue )
return ;
2019-08-13 16:58:50 +00:00
return m_errorReporter . typeError ( _expression . location ( ) , [ & ] ( ) {
if ( _expression . annotation ( ) . isConstant )
return " Cannot assign to a constant variable. " ;
2019-08-12 15:06:10 +00:00
2019-08-13 16:58:50 +00:00
if ( auto indexAccess = dynamic_cast < IndexAccess const * > ( & _expression ) )
2019-08-12 15:06:10 +00:00
{
2019-08-13 16:58:50 +00:00
if ( type ( indexAccess - > baseExpression ( ) ) - > category ( ) = = Type : : Category : : FixedBytes )
return " Single bytes in fixed bytes arrays cannot be modified. " ;
else if ( auto arrayType = dynamic_cast < ArrayType const * > ( type ( indexAccess - > baseExpression ( ) ) ) )
if ( arrayType - > dataStoredIn ( DataLocation : : CallData ) )
return " Calldata arrays are read-only. " ;
2019-08-12 15:06:10 +00:00
}
2019-08-13 16:58:50 +00:00
if ( auto memberAccess = dynamic_cast < MemberAccess const * > ( & _expression ) )
2019-08-12 15:06:10 +00:00
{
2019-08-13 16:58:50 +00:00
if ( auto structType = dynamic_cast < StructType const * > ( type ( memberAccess - > expression ( ) ) ) )
2019-08-12 15:06:10 +00:00
{
2019-08-13 16:58:50 +00:00
if ( structType - > dataStoredIn ( DataLocation : : CallData ) )
return " Calldata structs are read-only. " ;
2019-08-12 15:06:10 +00:00
}
2019-09-18 12:58:20 +00:00
else if ( dynamic_cast < ArrayType const * > ( type ( memberAccess - > expression ( ) ) ) )
if ( memberAccess - > memberName ( ) = = " length " )
return " Member \" length \" is read-only and cannot be used to resize arrays. " ;
2019-08-12 15:06:10 +00:00
}
2019-08-13 16:58:50 +00:00
if ( auto identifier = dynamic_cast < Identifier const * > ( & _expression ) )
if ( auto varDecl = dynamic_cast < VariableDeclaration const * > ( identifier - > annotation ( ) . referencedDeclaration ) )
if ( varDecl - > isExternalCallableParameter ( ) & & dynamic_cast < ReferenceType const * > ( identifier - > annotation ( ) . type ) )
return " External function arguments of reference type are read-only. " ;
2019-08-12 15:06:10 +00:00
2019-08-13 16:58:50 +00:00
return " Expression has to be an lvalue. " ;
} ( ) ) ;
2015-09-16 14:56:30 +00:00
}