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>
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-11-28 11:17:30 +00:00
2018-11-14 13:59:30 +00:00
# include <liblangutil/ErrorReporter.h>
2018-11-28 11:17:30 +00:00
2018-07-12 18:11:32 +00:00
# include <libdevcore/Algorithms.h>
2018-11-28 11:17:30 +00:00
# include <libdevcore/StringUtils.h>
# include <boost/algorithm/cxx11/all_of.hpp>
# include <boost/algorithm/string/predicate.hpp>
# include <boost/algorithm/string/join.hpp>
# include <memory>
# include <vector>
2015-09-16 14:56:30 +00:00
using namespace std ;
using namespace dev ;
2018-11-14 16:11:55 +00:00
using namespace langutil ;
2015-09-16 14:56:30 +00:00
using namespace dev : : solidity ;
2018-02-19 17:21:02 +00:00
namespace
{
bool typeSupportedByOldABIEncoder ( Type const & _type )
{
if ( _type . dataStoredIn ( DataLocation : : Storage ) )
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 ( ) ;
2018-06-14 18:19:36 +00:00
if ( ! typeSupportedByOldABIEncoder ( * base ) | | ( base - > category ( ) = = Type : : Category : : Array & & base - > isDynamicallySized ( ) ) )
2018-02-19 17:21:02 +00:00
return false ;
}
return true ;
}
}
2015-09-16 14:56:30 +00:00
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 )
{
ReferenceType const * ref = dynamic_cast < ReferenceType const * > ( lhs . components ( ) [ i ] . get ( ) ) ;
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. "
) ;
2018-09-13 20:29:12 +00:00
if ( arguments . size ( ) > = 1 & & ! type ( * arguments . front ( ) ) - > isImplicitlyConvertibleTo ( ArrayType : : bytesMemory ( ) ) )
2018-06-30 16:09:13 +00:00
m_errorReporter . typeError (
arguments . front ( ) - > location ( ) ,
" Invalid type for argument in function call. "
" Invalid implicit conversion from " +
type ( * arguments . front ( ) ) - > toString ( ) +
" to bytes memory requested. "
) ;
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 , " " ) ;
if ( TypeType const * argTypeType = dynamic_cast < TypeType const * > ( type ( * typeArgument ) . get ( ) ) )
{
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.
actualType = ReferenceType : : copyForLocationIfReference ( DataLocation : : Memory , actualType ) ;
2018-09-05 15:59:55 +00:00
// We force address payable for address types.
if ( actualType - > category ( ) = = Type : : Category : : Address )
actualType = make_shared < AddressType > ( StateMutability : : Payable ) ;
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. " ) ;
components . push_back ( make_shared < TupleType > ( ) ) ;
}
}
2018-09-04 14:24:21 +00:00
return components ;
2018-06-30 16:09:13 +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. " ) ;
2017-02-07 22:13:03 +00:00
if ( m_scope - > contractKind ( ) = = ContractDefinition : : ContractKind : : Interface )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _inheritance . location ( ) , " Interfaces cannot inherit. " ) ;
2017-02-07 22:13:03 +00:00
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 ;
if ( base - > contractKind ( ) ! = ContractDefinition : : ContractKind : : Interface )
// 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 )
2018-04-04 18:53:23 +00:00
if ( ! type ( * ( * arguments ) [ i ] ) - > isImplicitlyConvertibleTo ( * parameterTypes [ i ] ) )
m_errorReporter . typeError (
( * arguments ) [ i ] - > location ( ) ,
" Invalid type for argument in constructor call. "
" Invalid implicit conversion from " +
type ( * ( * arguments ) [ i ] ) - > toString ( ) +
" to " +
parameterTypes [ i ] - > toString ( ) +
" requested. "
) ;
}
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 ( ) )
if ( ! type ( * member ) - > canBeStored ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( member - > location ( ) , " 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 ( ) )
{
Type const * memberType = type ( * member ) . get ( ) ;
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 ;
memberType = arrayType - > baseType ( ) . get ( ) ;
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
2018-08-10 09:51:41 +00:00
bool insideStruct = true ;
swap ( insideStruct , m_insideStruct ) ;
2015-09-16 14:56:30 +00:00
ASTNode : : listAccept ( _struct . members ( ) , * this ) ;
2018-08-10 09:51:41 +00:00
m_insideStruct = insideStruct ;
2015-09-16 14:56:30 +00:00
return false ;
}
bool TypeChecker : : visit ( FunctionDefinition const & _function )
{
2018-07-26 19:45:24 +00:00
bool isLibraryFunction = _function . inContractKind ( ) = = ContractDefinition : : ContractKind : : Library ;
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. " ) ;
2017-07-27 19:55:55 +00:00
if ( ! _function . isConstructor ( ) & & ! _function . isFallback ( ) & & ! _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
}
2015-09-16 14:56:30 +00:00
for ( ASTPointer < VariableDeclaration > const & var : _function . parameters ( ) + _function . returnParameters ( ) )
{
2018-11-08 10:22:57 +00:00
if ( type ( * var ) - > category ( ) = = Type : : Category : : Mapping )
{
if ( ! type ( * var ) - > dataStoredIn ( DataLocation : : Storage ) )
m_errorReporter . typeError ( var - > location ( ) , " Mapping types can only have a data location of \" storage \" . " ) ;
else if ( ! isLibraryFunction & & _function . isPublic ( ) )
m_errorReporter . typeError ( var - > location ( ) , " Mapping types for parameters or return variables can only be used in internal or library functions. " ) ;
}
else
{
if ( ! type ( * var ) - > canLiveOutsideStorage ( ) & & _function . isPublic ( ) )
m_errorReporter . typeError ( var - > location ( ) , " Type is required to live outside storage. " ) ;
if ( _function . isPublic ( ) & & ! ( type ( * var ) - > interfaceType ( isLibraryFunction ) ) )
m_errorReporter . fatalTypeError ( var - > location ( ) , " Internal or recursive type is not allowed for public or external functions. " ) ;
}
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 ) & &
! typeSupportedByOldABIEncoder ( * type ( * var ) )
2017-12-02 01:01:55 +00:00
)
m_errorReporter . typeError (
var - > location ( ) ,
2018-02-19 17:21:02 +00:00
" This type is only supported in the new experimental ABI encoder. "
2017-12-02 01:01:55 +00:00
" Use \" pragma experimental ABIEncoderV2; \" to enable the feature. "
) ;
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
{
2015-09-16 14:56:30 +00:00
visitManually (
* modifier ,
_function . isConstructor ( ) ?
2015-09-21 16:55:58 +00:00
dynamic_cast < ContractDefinition const & > ( * _function . scope ( ) ) . annotation ( ) . linearizedBaseContracts :
2015-09-16 14:56:30 +00:00
vector < ContractDefinition const * > ( )
) ;
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 ) ;
}
2017-03-17 17:01:13 +00:00
if ( m_scope - > contractKind ( ) = = ContractDefinition : : ContractKind : : Interface )
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
if ( _function . visibility ( ) ! = FunctionDefinition : : Visibility : : External )
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
}
2017-08-16 21:19:08 +00:00
else if ( m_scope - > contractKind ( ) = = ContractDefinition : : ContractKind : : Library )
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. " ) ;
2017-08-08 10:59:55 +00:00
else if ( isLibraryFunction & & _function . visibility ( ) < = FunctionDefinition : : Visibility : : Internal )
m_errorReporter . typeError ( _function . location ( ) , " Internal library function must be implemented if declared. " ) ;
2015-09-16 14:56:30 +00:00
return false ;
}
bool TypeChecker : : visit ( VariableDeclaration const & _variable )
{
2017-06-15 15:36:14 +00:00
// Forbid any variable declarations inside interfaces unless they are part of
2018-08-10 09:51:41 +00:00
// * a function's input/output parameters,
// * or inside of a struct definition.
2017-06-15 15:36:14 +00:00
if (
m_scope - > contractKind ( ) = = ContractDefinition : : ContractKind : : Interface
& & ! _variable . isCallableParameter ( )
2018-08-10 09:51:41 +00:00
& & ! m_insideStruct
2017-06-15 15:36:14 +00:00
)
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Variables cannot be declared in interfaces. " ) ;
2017-02-07 22:13:03 +00:00
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
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 ;
if ( auto arrayType = dynamic_cast < ArrayType const * > ( _variable . type ( ) . get ( ) ) )
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
}
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
}
2018-11-28 11:17:30 +00:00
else if ( _variable . visibility ( ) > = VariableDeclaration : : Visibility : : Public )
{
FunctionType getter ( _variable ) ;
if ( ! _variable . sourceUnit ( ) . annotation ( ) . experimentalFeatures . count ( ExperimentalFeature : : ABIEncoderV2 ) )
{
vector < string > unsupportedTypes ;
for ( auto const & param : getter . parameterTypes ( ) + getter . returnParameterTypes ( ) )
if ( ! typeSupportedByOldABIEncoder ( * param ) )
unsupportedTypes . emplace_back ( param - > toString ( ) ) ;
if ( ! unsupportedTypes . empty ( ) )
m_errorReporter . typeError ( _variable . location ( ) ,
" The following types are only supported for getters in the new experimental ABI encoder: " +
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 :
2017-07-11 20:56:09 +00:00
if ( auto arrayType = dynamic_cast < ArrayType const * > ( varType . get ( ) ) )
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 ;
case Type : : Category : : Mapping :
if ( auto mappingType = dynamic_cast < MappingType const * > ( varType . get ( ) ) )
if (
mappingType - > keyType ( ) - > isDynamicallySized ( ) & &
_variable . visibility ( ) = = Declaration : : Visibility : : Public
)
m_errorReporter . typeError ( _variable . location ( ) , " Dynamically-sized keys for public mappings are not supported. " ) ;
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 ) ;
_modifier . name ( ) - > accept ( * this ) ;
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 )
2015-09-16 14:56:30 +00:00
if ( ! type ( * arguments [ i ] ) - > isImplicitlyConvertibleTo ( * type ( * ( * parameters ) [ i ] ) ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
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 ( ) +
" requested. "
) ;
}
bool TypeChecker : : visit ( EventDefinition const & _eventDef )
{
2018-08-01 17:01:50 +00:00
solAssert ( _eventDef . visibility ( ) > Declaration : : Visibility : : Internal , " " ) ;
2015-09-16 14:56:30 +00:00
unsigned numIndexed = 0 ;
for ( ASTPointer < VariableDeclaration > const & var : _eventDef . parameters ( ) )
{
if ( var - > isIndexed ( ) )
2018-08-15 10:30:29 +00:00
{
2015-09-16 14:56:30 +00:00
numIndexed + + ;
2018-08-15 10:30:29 +00:00
if (
2018-08-15 14:58:41 +00:00
_eventDef . sourceUnit ( ) . annotation ( ) . experimentalFeatures . count ( ExperimentalFeature : : ABIEncoderV2 ) & &
dynamic_cast < ReferenceType const * > ( type ( * var ) . get ( ) )
2018-08-15 10:30:29 +00:00
)
m_errorReporter . typeError (
var - > location ( ) ,
2018-08-15 14:58:41 +00:00
" Indexed reference types cannot yet be used with ABIEncoderV2. "
2018-08-15 10:30:29 +00:00
) ;
}
2015-09-16 14:56:30 +00:00
if ( ! type ( * var ) - > canLiveOutsideStorage ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( var - > location ( ) , " Type is required to live outside storage. " ) ;
2015-10-02 11:11:38 +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 ) & &
! typeSupportedByOldABIEncoder ( * type ( * var ) )
)
m_errorReporter . typeError (
var - > location ( ) ,
" This type is only supported in the new experimental ABI encoder. "
" 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 )
2016-11-11 11:07:30 +00:00
if ( ! fun . canBeUsedExternally ( false ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _funType . location ( ) , " 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 ) )
{
2018-02-19 18:21:33 +00:00
if ( var - > isConstant ( ) )
{
m_errorReporter . typeError ( _identifier . location , " Constant variables not supported by inline assembly. " ) ;
return size_t ( - 1 ) ;
}
2018-08-07 12:17:56 +00:00
else if ( requiresStorage )
2017-04-11 19:12:17 +00:00
{
2017-04-21 17:13:46 +00:00
if ( ! var - > isStateVariable ( ) & & ! var - > type ( ) - > dataStoredIn ( DataLocation : : Storage ) )
{
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 ) ;
}
2018-10-15 09:58:51 +00:00
else if ( _context ! = yul : : IdentifierContext : : RValue )
2017-04-21 17:13:46 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _identifier . location , " Storage variables cannot be assigned to. " ) ;
2017-04-21 17:13:46 +00:00
return size_t ( - 1 ) ;
}
}
else if ( ! var - > isLocalVariable ( ) )
{
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
{
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 ,
2018-02-23 10:42:53 +00:00
m_evmVersion ,
2018-07-03 09:51:44 +00:00
Error : : Type : : SyntaxError ,
2018-12-03 14:49:23 +00:00
yul : : Dialect : : looseAssemblyForEVM ( ) ,
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 )
{
expectType ( _ifStatement . condition ( ) , BoolType ( ) ) ;
_ifStatement . trueStatement ( ) . accept ( * this ) ;
if ( _ifStatement . falseStatement ( ) )
_ifStatement . falseStatement ( ) - > accept ( * this ) ;
return false ;
}
bool TypeChecker : : visit ( WhileStatement const & _whileStatement )
{
expectType ( _whileStatement . condition ( ) , BoolType ( ) ) ;
_whileStatement . body ( ) . accept ( * this ) ;
return false ;
}
bool TypeChecker : : visit ( ForStatement const & _forStatement )
{
if ( _forStatement . initializationExpression ( ) )
_forStatement . initializationExpression ( ) - > accept ( * this ) ;
if ( _forStatement . condition ( ) )
expectType ( * _forStatement . condition ( ) , BoolType ( ) ) ;
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 ) ) ;
if ( auto tupleType = dynamic_cast < TupleType const * > ( type ( * _return . expression ( ) ) . get ( ) ) )
{
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. " ) ;
2015-10-12 21:02:35 +00:00
else if ( ! tupleType - > isImplicitlyConvertibleTo ( TupleType ( returnTypes ) ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_return . expression ( ) - > location ( ) ,
2015-10-12 21:02:35 +00:00
" Return argument type " +
type ( * _return . expression ( ) ) - > toString ( ) +
" is not implicitly convertible to expected type " +
TupleType ( returnTypes ) . toString ( false ) +
" . "
) ;
}
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 ( ) ) ;
if ( ! type ( * _return . expression ( ) ) - > isImplicitlyConvertibleTo ( * expected ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
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) " +
expected - > toString ( ) +
" . "
) ;
}
}
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. " ) ;
m_insideEmitStatement = false ;
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 ;
2018-07-02 15:00:09 +00:00
if ( auto functionType = dynamic_cast < FunctionType const * > ( decl - > annotation ( ) . type . get ( ) ) )
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. " ) ;
2015-10-12 21:02:35 +00:00
if ( auto ref = dynamic_cast < ReferenceType const * > ( type ( varDecl ) . get ( ) ) )
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. " } ;
2018-08-17 23:09:31 +00:00
if ( varDecl . referenceLocation ( ) = = VariableDeclaration : : Location : : Unspecified )
2017-07-05 17:38:00 +00:00
errorText + = " Did you mean '<type> memory " + varDecl . name ( ) + " '? " ;
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
}
2017-03-03 17:44:35 +00:00
else if ( dynamic_cast < MappingType const * > ( type ( varDecl ) . get ( ) ) )
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 ;
2015-10-12 21:02:35 +00:00
if ( auto tupleType = dynamic_cast < TupleType const * > ( type ( * _statement . initialValue ( ) ) . get ( ) ) )
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
}
2017-03-01 14:42:53 +00:00
else if ( * var . annotation ( ) . type = = TupleType ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2017-03-01 14:42:53 +00:00
var . location ( ) ,
" 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 ;
if ( auto type = dynamic_cast < IntegerType const * > ( var . annotation ( ) . type . get ( ) ) )
{
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
solAssert ( dynamic_cast < FixedPointType const * > ( var . annotation ( ) . type . get ( ) ) , " Unknown type. " ) ;
}
2015-10-09 17:35:41 +00:00
var . accept ( * this ) ;
}
else
{
var . accept ( * this ) ;
if ( ! valueComponentType - > isImplicitlyConvertibleTo ( * var . annotation ( ) . type ) )
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
)
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2016-05-05 22:47:08 +00:00
_statement . location ( ) ,
" Type " +
valueComponentType - > toString ( ) +
" is not implicitly convertible to expected type " +
var . annotation ( ) . type - > toString ( ) +
" . Try converting to type " +
valueComponentType - > mobileType ( ) - > toString ( ) +
2017-10-05 13:28:25 +00:00
" or use an explicit conversion. "
2016-05-05 22:47:08 +00:00
) ;
else
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2016-05-05 22:47:08 +00:00
_statement . location ( ) ,
" Type " +
valueComponentType - > toString ( ) +
" is not implicitly convertible to expected type " +
var . annotation ( ) . type - > toString ( ) +
" . "
) ;
}
2015-10-09 17:35:41 +00:00
}
2015-10-08 16:01:12 +00:00
}
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 ( ) ) )
{
if ( auto callType = dynamic_cast < FunctionType const * > ( type ( call - > expression ( ) ) . get ( ) ) )
{
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
{
2016-01-07 09:01:46 +00:00
expectType ( _conditional . condition ( ) , BoolType ( ) ) ;
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 ( ) ;
2016-10-21 10:30:58 +00:00
if ( ! trueType )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _conditional . trueExpression ( ) . location ( ) , " Invalid mobile type. " ) ;
2016-10-21 10:30:58 +00:00
if ( ! falseType )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _conditional . falseExpression ( ) . location ( ) , " Invalid mobile type. " ) ;
2016-01-07 09:01:46 +00:00
2016-01-11 16:00:14 +00:00
TypePointer commonType = Type : : commonType ( trueType , falseType ) ;
2016-01-11 07:08:28 +00:00
if ( ! commonType )
2016-01-07 09:01:46 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2016-01-11 07:08:28 +00:00
_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-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 ) ;
auto const & types = tupleType ? tupleType - > components ( ) : vector < TypePointer > { _type . shared_from_this ( ) } ;
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 ( ) ) ;
2015-10-14 13:19:50 +00:00
if ( TupleType const * tupleType = dynamic_cast < TupleType const * > ( t . get ( ) ) )
{
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.
_assignment . annotation ( ) . type = make_shared < TupleType > ( ) ;
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.
2018-07-10 09:59:09 +00:00
if ( dynamic_cast < TupleType const * > ( type ( _assignment . rightHandSide ( ) ) . get ( ) ) )
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
_tuple . annotation ( ) . type = make_shared < TupleType > ( 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 ;
2016-01-12 05:41:20 +00:00
TypePointer inlineArrayType ;
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-01-11 20:25:59 +00:00
if ( _tuple . isInlineArray ( ) )
solAssert ( ! ! types [ i ] , " Inline array cannot have empty components " ) ;
2016-10-21 10:30:58 +00:00
if ( _tuple . isInlineArray ( ) )
{
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. " ) ;
2016-01-11 20:25:59 +00:00
_tuple . annotation ( ) . type = make_shared < ArrayType > ( DataLocation : : Memory , inlineArrayType , types . size ( ) ) ;
}
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
_tuple . annotation ( ) . type = make_shared < TupleType > ( 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 ( ) ) ?
2015-09-16 14:56:30 +00:00
make_shared < BoolType > ( ) :
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. "
) ;
}
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
{
2018-10-18 21:53:59 +00:00
TypePointer const & argType = type ( * arguments . front ( ) ) ;
// 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 ;
if ( auto argRefType = dynamic_cast < ReferenceType const * > ( argType . get ( ) ) )
dataLoc = argRefType - > location ( ) ;
if ( auto type = dynamic_cast < ReferenceType const * > ( resultType . get ( ) ) )
resultType = type - > copyForLocation ( dataLoc , type - > isPointer ( ) ) ;
if ( argType - > isExplicitlyConvertibleTo ( * resultType ) )
2015-09-16 14:56:30 +00:00
{
2018-10-18 21:53:59 +00:00
if ( auto argArrayType = dynamic_cast < ArrayType const * > ( argType . get ( ) ) )
2018-09-12 10:01:34 +00:00
{
2018-10-18 21:53:59 +00:00
auto resultArrayType = dynamic_cast < ArrayType const * > ( resultType . get ( ) ) ;
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
{
2018-10-18 21:53:59 +00:00
solAssert ( dynamic_cast < ContractType const * > ( resultType . get ( ) ) - > isPayable ( ) , " " ) ;
solAssert (
dynamic_cast < AddressType const * > ( argType . get ( ) ) - > stateMutability ( ) <
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 (
_functionCall . location ( ) , ssl ,
" 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
}
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 ( ) +
" \" . "
) ;
}
if ( resultType - > category ( ) = = Type : : Category : : Address )
{
bool const payable = argType - > isExplicitlyConvertibleTo ( AddressType : : addressPayable ( ) ) ;
resultType = make_shared < AddressType > (
payable ? StateMutability : : Payable : StateMutability : : NonPayable
) ;
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
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. "
) ;
// Check for event outside of emit statement
if ( ! m_insideEmitStatement & & _functionType - > kind ( ) = = FunctionType : : Kind : : Event )
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Event invocations have to be prefixed by \" emit \" . "
) ;
// Perform standard function call type checking
typeCheckFunctionGeneralChecks ( _functionCall , _functionType ) ;
}
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
{
2018-10-18 21:53:59 +00:00
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
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 ( ) ;
// Check for expected number of named arguments
if ( parameterNames . size ( ) ! = argumentNames . size ( ) )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_functionCall . location ( ) ,
2018-10-18 21:53:59 +00:00
parameterNames . size ( ) > argumentNames . size ( ) ?
" Some argument names are missing. " :
" Too many arguments. "
2015-09-16 14:56:30 +00:00
) ;
2018-10-18 21:53:59 +00:00
return ;
}
// 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 ;
}
// For positional calls only, store argument types
if ( _functionCall . names ( ) . empty ( ) )
{
shared_ptr < TypePointers > argumentTypes = make_shared < TypePointers > ( ) ;
for ( ASTPointer < Expression const > const & argument : arguments )
argumentTypes - > push_back ( type ( * argument ) ) ;
_functionCall . expression ( ) . annotation ( ) . argumentTypes = move ( argumentTypes ) ;
}
_functionCall . expression ( ) . accept ( * this ) ;
TypePointer const & expressionType = type ( _functionCall . expression ( ) ) ;
// Determine function call kind and function type for this FunctionCall node
FunctionCallAnnotation & funcCallAnno = _functionCall . annotation ( ) ;
FunctionTypePointer functionType ;
// Determine and assign function call kind, purity and function type for this FunctionCall node
switch ( expressionType - > category ( ) )
{
case Type : : Category : : Function :
functionType = dynamic_pointer_cast < FunctionType const > ( expressionType ) ;
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 ( ) ;
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 :
m_errorReporter . typeError ( _functionCall . location ( ) , " Type is not callable " ) ;
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 ;
}
default :
{
typeCheckFunctionCall ( _functionCall , functionType ) ;
returnTypes = m_evmVersion . supportsReturndata ( ) ?
functionType - > returnParameterTypes ( ) :
functionType - > returnParameterTypesWithoutDynamicTypes ( ) ;
break ;
}
}
funcCallAnno . type = returnTypes . size ( ) = = 1 ?
move ( returnTypes . front ( ) ) :
make_shared < TupleType > ( move ( returnTypes ) ) ;
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 ;
funcCallAnno . type = make_shared < TupleType > ( ) ;
break ;
}
2018-09-04 14:24:21 +00:00
2015-09-16 14:56:30 +00:00
return false ;
}
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. " ) ;
2017-08-11 23:45:37 +00:00
if ( contract - > contractKind ( ) = = ContractDefinition : : ContractKind : : Interface )
2018-09-25 17:40:39 +00:00
m_errorReporter . fatalTypeError ( _newExpression . location ( ) , " Cannot instantiate an interface. " ) ;
2017-07-10 09:47:12 +00:00
if ( ! contract - > annotation ( ) . unimplementedFunctions . empty ( ) )
2017-09-12 09:59:56 +00:00
{
SecondarySourceLocation ssl ;
for ( auto function : contract - > annotation ( ) . unimplementedFunctions )
ssl . append ( " Missing implementation: " , function - > location ( ) ) ;
2017-12-12 09:10:29 +00:00
string msg = " Trying to create an instance of an abstract contract. " ;
ssl . limitSize ( msg ) ;
2017-08-02 10:26:43 +00:00
m_errorReporter . typeError (
_newExpression . location ( ) ,
2017-09-12 09:59:56 +00:00
ssl ,
2017-12-12 09:10:29 +00:00
msg
2017-08-02 10:26:43 +00:00
) ;
2017-09-12 09:59:56 +00:00
}
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. " ) ;
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. "
) ;
type = ReferenceType : : copyForLocationIfReference ( DataLocation : : Memory , type ) ;
_newExpression . annotation ( ) . type = make_shared < FunctionType > (
TypePointers { make_shared < IntegerType > ( 256 ) } ,
TypePointers { type } ,
strings ( ) ,
strings ( ) ,
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.
auto const & argumentTypes = _memberAccess . annotation ( ) . argumentTypes ;
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 ( ) ;
if ( initialMemberCount > 1 & & argumentTypes )
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 & &
2015-11-27 21:24:00 +00:00
! dynamic_cast < FunctionType const & > ( * it - > type ) . canTakeArguments ( * argumentTypes , 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.
auto storageType = ReferenceType : : copyForLocationIfReference (
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 ( ) + " . " ;
if ( memberName = = " value " )
{
errorMsg . pop_back ( ) ;
errorMsg + = " - did you forget the \" payable \" modifier? " ;
}
else if ( exprType - > category ( ) = = Type : : Category : : Function )
{
if ( auto const & funType = dynamic_pointer_cast < FunctionType const > ( exprType ) )
{
auto const & t = funType - > returnParameterTypes ( ) ;
if ( t . size ( ) = = 1 )
if (
t . front ( ) - > category ( ) = = Type : : Category : : Contract | |
t . front ( ) - > category ( ) = = Type : : Category : : Struct
)
errorMsg + = " Did you intend to call the function? " ;
}
}
2018-07-17 12:31:21 +00:00
if ( exprType - > category ( ) = = Type : : Category : : Contract )
2018-09-13 20:29:12 +00:00
for ( auto const & addressMember : AddressType : : addressPayable ( ) . 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 ;
}
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
if ( auto funType = dynamic_cast < FunctionType const * > ( annotation . type . get ( ) ) )
if ( funType - > bound ( ) & & ! exprType - > isImplicitlyConvertibleTo ( * funType - > selfType ( ) ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-27 21:24:00 +00:00
_memberAccess . location ( ) ,
" Function \" " + memberName + " \" cannot be called on an object of type " +
2018-07-16 15:11:39 +00:00
exprType - > toString ( ) + " (expected " + funType - > selfType ( ) - > toString ( ) + " ). "
2015-11-27 21:24:00 +00:00
) ;
2015-09-16 14:56:30 +00:00
if ( exprType - > category ( ) = = Type : : Category : : Struct )
annotation . isLValue = true ;
else if ( exprType - > category ( ) = = Type : : Category : : Array )
{
auto const & arrayType ( dynamic_cast < ArrayType const & > ( * exprType ) ) ;
annotation . isLValue = (
memberName = = " length " & &
arrayType . location ( ) = = DataLocation : : Storage & &
arrayType . isDynamicallySized ( )
) ;
}
2016-02-03 20:34:24 +00:00
else if ( exprType - > category ( ) = = Type : : Category : : FixedBytes )
annotation . isLValue = false ;
2016-10-24 17:22:09 +00:00
else if ( TypeType const * typeType = dynamic_cast < decltype ( typeType ) > ( exprType . get ( ) ) )
{
if ( ContractType const * contractType = dynamic_cast < decltype ( contractType ) > ( typeType - > actualType ( ) . get ( ) ) )
annotation . isLValue = annotation . referencedDeclaration - > isLValue ( ) ;
}
2015-09-16 14:56:30 +00:00
2017-07-09 01:42:42 +00:00
if ( exprType - > category ( ) = = Type : : Category : : Contract )
{
2017-09-20 13:54:41 +00:00
// Warn about using send or transfer with a non-payable fallback function.
2017-07-09 01:42:42 +00:00
if ( auto callType = dynamic_cast < FunctionType const * > ( type ( _memberAccess ) . get ( ) ) )
{
auto kind = callType - > kind ( ) ;
auto contractType = dynamic_cast < ContractType const * > ( exprType . get ( ) ) ;
solAssert ( ! ! contractType , " Should be contract type. " ) ;
if (
( kind = = FunctionType : : Kind : : Send | | kind = = FunctionType : : Kind : : Transfer ) & &
! contractType - > isPayable ( )
)
m_errorReporter . typeError (
_memberAccess . location ( ) ,
" Value transfer to a contract without a payable fallback function. "
) ;
}
}
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.
if ( auto tt = dynamic_cast < TypeType const * > ( exprType . get ( ) ) )
if ( tt - > actualType ( ) - > category ( ) = = Type : : Category : : Enum )
annotation . isPure = true ;
2018-05-15 11:04:49 +00:00
if ( auto magicType = dynamic_cast < MagicType const * > ( exprType . get ( ) ) )
if ( magicType - > kind ( ) = = MagicType : : Kind : : ABI )
annotation . isPure = true ;
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 ( ) ) ;
TypePointer resultType ;
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 ( ) )
{
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
{
2018-11-29 08:34:17 +00:00
expectType ( * index , IntegerType : : uint256 ( ) ) ;
2018-08-30 03:08:49 +00:00
if ( ! m_errorReporter . hasErrors ( ) )
if ( auto numberType = dynamic_cast < RationalNumberType const * > ( type ( * index ) . get ( ) ) )
{
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 ) ;
if ( ! index )
resultType = make_shared < TypeType > ( make_shared < ArrayType > ( DataLocation : : Memory , typeType . actualType ( ) ) ) ;
else
{
2018-11-29 08:34:17 +00:00
expectType ( * index , IntegerType : : uint256 ( ) ) ;
2016-03-29 20:08:51 +00:00
if ( auto length = dynamic_cast < RationalNumberType const * > ( type ( * index ) . get ( ) ) )
2015-09-16 14:56:30 +00:00
resultType = make_shared < TypeType > ( make_shared < ArrayType > (
DataLocation : : Memory ,
typeType . actualType ( ) ,
length - > literalValue ( nullptr )
) ) ;
else
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( index - > location ( ) , " Integer constant expected. " ) ;
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
{
2018-11-29 08:34:17 +00:00
if ( ! expectType ( * index , IntegerType : : uint256 ( ) ) )
2018-10-10 17:33:45 +00:00
m_errorReporter . fatalTypeError ( _access . location ( ) , " Index expression cannot be represented as an unsigned integer. " ) ;
2016-03-29 20:08:51 +00:00
if ( auto integerType = dynamic_cast < RationalNumberType const * > ( type ( * index ) . get ( ) ) )
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
}
resultType = make_shared < FixedBytesType > ( 1 ) ;
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 ( ) + " ) "
) ;
}
_access . annotation ( ) . type = move ( resultType ) ;
_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 ;
}
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 )
{
if ( ! annotation . argumentTypes )
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. " ) ;
if ( functionType - > canTakeArguments ( * annotation . argumentTypes ) )
2015-09-16 14:56:30 +00:00
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 argument-dependent lookup. " ) ;
2015-09-16 14:56:30 +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 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 ( ) ;
2015-09-16 14:56:30 +00:00
if ( ! annotation . type )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _identifier . location ( ) , " 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 ) )
2017-04-21 09:13:10 +00:00
if ( dynamic_cast < FunctionType const * > ( annotation . type . get ( ) ) )
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.
if ( FunctionType const * fType = dynamic_cast < FunctionType const * > ( _identifier . annotation ( ) . type . get ( ) ) )
{
if ( _identifier . name ( ) = = " sha3 " & & fType - > kind ( ) = = FunctionType : : Kind : : KECCAK256 )
m_errorReporter . typeError (
_identifier . location ( ) ,
" \" sha3 \" has been deprecated in favour of \" keccak256 \" "
) ;
else if ( _identifier . name ( ) = = " suicide " & & fType - > kind ( ) = = FunctionType : : Kind : : Selfdestruct )
m_errorReporter . typeError (
_identifier . location ( ) ,
" \" suicide \" has been deprecated in favour of \" selfdestruct \" "
) ;
}
2015-09-16 14:56:30 +00:00
return false ;
}
void TypeChecker : : endVisit ( ElementaryTypeNameExpression const & _expr )
{
2016-02-08 21:43:22 +00:00
_expr . annotation ( ) . type = make_shared < TypeType > ( Type : : fromElementaryTypeName ( _expr . typeName ( ) ) ) ;
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
2018-09-05 15:59:55 +00:00
_literal . annotation ( ) . type = make_shared < AddressType > ( StateMutability : : Payable ) ;
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 )
_literal . annotation ( ) . type = Type : : forLiteral ( _literal ) ;
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
{
if (
type ( _expression ) - > category ( ) = = Type : : Category : : RationalNumber & &
2016-05-10 12:30:24 +00:00
dynamic_pointer_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
)
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2016-05-05 22:47:08 +00:00
_expression . location ( ) ,
" Type " +
type ( _expression ) - > toString ( ) +
" is not implicitly convertible to expected type " +
_expectedType . toString ( ) +
" . Try converting to type " +
type ( _expression ) - > mobileType ( ) - > toString ( ) +
2016-05-10 08:26:53 +00:00
" or use an explicit conversion. "
2016-05-05 22:47:08 +00:00
) ;
else
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2016-05-05 22:47:08 +00:00
_expression . location ( ) ,
" Type " +
type ( _expression ) - > toString ( ) +
" is not implicitly convertible to expected type " +
_expectedType . toString ( ) +
" . "
) ;
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
if ( _expression . annotation ( ) . isConstant )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _expression . location ( ) , " Cannot assign to a constant variable. " ) ;
2016-12-13 02:59:53 +00:00
else if ( ! _expression . annotation ( ) . isLValue )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _expression . location ( ) , " Expression has to be an lvalue. " ) ;
2015-09-16 14:56:30 +00:00
}