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>
2015-09-16 14:56:30 +00:00
# include <memory>
2017-06-22 14:14:14 +00:00
# include <boost/algorithm/string/predicate.hpp>
2015-09-16 14:56:30 +00:00
# include <boost/range/adaptor/reversed.hpp>
2015-10-20 22:21:52 +00:00
# include <libsolidity/ast/AST.h>
2017-03-21 18:38:37 +00:00
# include <libsolidity/inlineasm/AsmAnalysis.h>
2017-04-26 13:41:08 +00:00
# include <libsolidity/inlineasm/AsmAnalysisInfo.h>
2017-04-11 19:12:17 +00:00
# include <libsolidity/inlineasm/AsmData.h>
2017-05-11 13:26:35 +00:00
# include <libsolidity/interface/ErrorReporter.h>
2015-09-16 14:56:30 +00:00
using namespace std ;
using namespace dev ;
using namespace dev : : solidity ;
2017-01-27 22:29:03 +00:00
bool TypeChecker : : checkTypeRequirements ( ASTNode const & _contract )
2015-09-16 14:56:30 +00:00
{
try
{
2017-01-27 22:29:03 +00:00
_contract . accept ( * this ) ;
2015-09-16 14:56:30 +00:00
}
2015-10-15 12:36:23 +00:00
catch ( FatalError const & )
2015-09-16 14:56:30 +00:00
{
// We got a fatal error which required to stop further type checking, but we can
// continue normally from here.
2017-05-11 13:26:35 +00:00
if ( m_errorReporter . errors ( ) . empty ( ) )
2015-09-16 14:56:30 +00:00
throw ; // Something is weird here, rather throw again.
}
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 ;
2017-03-21 14:05:59 +00:00
// We force our own visiting order here. The structs have to be excluded below.
set < ASTNode const * > visited ;
for ( auto const & s : _contract . definedStructs ( ) )
visited . insert ( s ) ;
2015-09-16 14:56:30 +00:00
ASTNode : : listAccept ( _contract . definedStructs ( ) , * this ) ;
ASTNode : : listAccept ( _contract . baseContracts ( ) , * this ) ;
checkContractDuplicateFunctions ( _contract ) ;
checkContractIllegalOverrides ( _contract ) ;
checkContractAbstractFunctions ( _contract ) ;
checkContractAbstractConstructors ( _contract ) ;
FunctionDefinition const * function = _contract . constructor ( ) ;
2017-01-20 18:21:43 +00:00
if ( function )
{
2016-09-06 01:50:47 +00:00
if ( ! function - > returnParameters ( ) . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( function - > returnParameterList ( ) - > location ( ) , " Non-empty \" returns \" directive for constructor. " ) ;
2016-09-06 01:50:47 +00:00
if ( function - > isDeclaredConst ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( function - > location ( ) , " Constructor cannot be defined as constant. " ) ;
2016-09-06 03:07:05 +00:00
if ( function - > visibility ( ) ! = FunctionDefinition : : Visibility : : Public & & function - > visibility ( ) ! = FunctionDefinition : : Visibility : : Internal )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( function - > location ( ) , " Constructor must be public or internal. " ) ;
2016-09-06 01:50:47 +00:00
}
2015-09-16 14:56:30 +00:00
FunctionDefinition const * fallbackFunction = nullptr ;
2015-11-23 22:57:17 +00:00
for ( FunctionDefinition const * function : _contract . definedFunctions ( ) )
2015-09-16 14:56:30 +00:00
{
if ( function - > name ( ) . empty ( ) )
{
if ( fallbackFunction )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . declarationError ( function - > location ( ) , " Only one fallback function is allowed. " ) ;
2015-09-16 14:56:30 +00:00
}
else
{
2015-11-23 22:57:17 +00:00
fallbackFunction = function ;
2016-08-25 21:53:03 +00:00
if ( _contract . isLibrary ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( fallbackFunction - > location ( ) , " Libraries cannot have fallback functions. " ) ;
2016-08-26 19:01:47 +00:00
if ( fallbackFunction - > isDeclaredConst ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( fallbackFunction - > location ( ) , " Fallback function cannot be declared constant. " ) ;
2015-09-16 14:56:30 +00:00
if ( ! fallbackFunction - > parameters ( ) . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( fallbackFunction - > parameterList ( ) . location ( ) , " Fallback function cannot take parameters. " ) ;
2016-08-25 11:25:30 +00:00
if ( ! fallbackFunction - > returnParameters ( ) . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( fallbackFunction - > returnParameterList ( ) - > location ( ) , " Fallback function cannot return values. " ) ;
2015-09-16 14:56:30 +00:00
}
}
if ( ! function - > isImplemented ( ) )
_contract . annotation ( ) . isFullyImplemented = false ;
}
2017-03-21 14:05:59 +00:00
for ( auto const & n : _contract . subNodes ( ) )
if ( ! visited . count ( n . get ( ) ) )
n - > accept ( * this ) ;
2015-09-16 14:56:30 +00:00
checkContractExternalTypeClashes ( _contract ) ;
// check for hash collisions in function signatures
set < FixedHash < 4 > > hashes ;
for ( auto const & it : _contract . interfaceFunctionList ( ) )
{
FixedHash < 4 > const & hash = it . first ;
if ( hashes . count ( hash ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_contract . location ( ) ,
2015-09-16 14:56:30 +00:00
string ( " Function signature hash collision for " ) + it . second - > externalSignature ( )
) ;
hashes . insert ( hash ) ;
}
if ( _contract . isLibrary ( ) )
checkLibraryRequirements ( _contract ) ;
return false ;
}
void TypeChecker : : checkContractDuplicateFunctions ( ContractDefinition const & _contract )
{
/// Checks that two functions with the same name defined in this contract have different
/// argument types and that there is at most one constructor.
map < string , vector < FunctionDefinition const * > > functions ;
2015-11-23 22:57:17 +00:00
for ( FunctionDefinition const * function : _contract . definedFunctions ( ) )
functions [ function - > name ( ) ] . push_back ( function ) ;
2015-09-16 14:56:30 +00:00
// Constructor
if ( functions [ _contract . name ( ) ] . size ( ) > 1 )
{
SecondarySourceLocation ssl ;
auto it = + + functions [ _contract . name ( ) ] . begin ( ) ;
for ( ; it ! = functions [ _contract . name ( ) ] . end ( ) ; + + it )
ssl . append ( " Another declaration is here: " , ( * it ) - > location ( ) ) ;
2017-05-11 13:26:35 +00:00
m_errorReporter . declarationError (
functions [ _contract . name ( ) ] . front ( ) - > location ( ) ,
ssl ,
" More than one constructor defined. "
) ;
2015-09-16 14:56:30 +00:00
}
for ( auto const & it : functions )
{
vector < FunctionDefinition const * > const & overloads = it . second ;
for ( size_t i = 0 ; i < overloads . size ( ) ; + + i )
for ( size_t j = i + 1 ; j < overloads . size ( ) ; + + j )
if ( FunctionType ( * overloads [ i ] ) . hasEqualArgumentTypes ( FunctionType ( * overloads [ j ] ) ) )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . declarationError (
overloads [ j ] - > location ( ) ,
SecondarySourceLocation ( ) . append (
" Other declaration is here: " ,
overloads [ i ] - > location ( )
) ,
" Function with same name and arguments defined twice. "
) ;
2015-09-16 14:56:30 +00:00
}
}
}
void TypeChecker : : checkContractAbstractFunctions ( ContractDefinition const & _contract )
{
// Mapping from name to function definition (exactly one per argument type equality class) and
// flag to indicate whether it is fully implemented.
using FunTypeAndFlag = std : : pair < FunctionTypePointer , bool > ;
map < string , vector < FunTypeAndFlag > > functions ;
2017-03-21 17:12:08 +00:00
bool allBaseConstructorsImplemented = true ;
2015-09-16 14:56:30 +00:00
// Search from base to derived
for ( ContractDefinition const * contract : boost : : adaptors : : reverse ( _contract . annotation ( ) . linearizedBaseContracts ) )
2015-11-23 22:57:17 +00:00
for ( FunctionDefinition const * function : contract - > definedFunctions ( ) )
2015-09-16 14:56:30 +00:00
{
2016-06-06 17:36:19 +00:00
// Take constructors out of overload hierarchy
if ( function - > isConstructor ( ) )
2017-03-21 17:12:08 +00:00
{
if ( ! function - > isImplemented ( ) )
// Base contract's constructor is not fully implemented, no way to get
// out of this.
allBaseConstructorsImplemented = false ;
2016-06-06 17:36:19 +00:00
continue ;
2017-03-21 17:12:08 +00:00
}
2015-09-16 14:56:30 +00:00
auto & overloads = functions [ function - > name ( ) ] ;
FunctionTypePointer funType = make_shared < FunctionType > ( * function ) ;
auto it = find_if ( overloads . begin ( ) , overloads . end ( ) , [ & ] ( FunTypeAndFlag const & _funAndFlag )
{
return funType - > hasEqualArgumentTypes ( * _funAndFlag . first ) ;
} ) ;
if ( it = = overloads . end ( ) )
overloads . push_back ( make_pair ( funType , function - > isImplemented ( ) ) ) ;
else if ( it - > second )
{
if ( ! function - > isImplemented ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( function - > location ( ) , " Redeclaring an already implemented function as abstract " ) ;
2015-09-16 14:56:30 +00:00
}
else if ( function - > isImplemented ( ) )
it - > second = true ;
}
2017-03-21 17:12:08 +00:00
if ( ! allBaseConstructorsImplemented )
_contract . annotation ( ) . isFullyImplemented = false ;
2015-09-16 14:56:30 +00:00
// Set to not fully implemented if at least one flag is false.
for ( auto const & it : functions )
for ( auto const & funAndFlag : it . second )
if ( ! funAndFlag . second )
{
_contract . annotation ( ) . isFullyImplemented = false ;
return ;
}
}
void TypeChecker : : checkContractAbstractConstructors ( ContractDefinition const & _contract )
{
set < ContractDefinition const * > argumentsNeeded ;
// check that we get arguments for all base constructors that need it.
// If not mark the contract as abstract (not fully implemented)
vector < ContractDefinition const * > const & bases = _contract . annotation ( ) . linearizedBaseContracts ;
for ( ContractDefinition const * contract : bases )
if ( FunctionDefinition const * constructor = contract - > constructor ( ) )
if ( contract ! = & _contract & & ! constructor - > parameters ( ) . empty ( ) )
argumentsNeeded . insert ( contract ) ;
for ( ContractDefinition const * contract : bases )
{
if ( FunctionDefinition const * constructor = contract - > constructor ( ) )
for ( auto const & modifier : constructor - > modifiers ( ) )
{
auto baseContract = dynamic_cast < ContractDefinition const * > (
& dereference ( * modifier - > name ( ) )
) ;
if ( baseContract )
argumentsNeeded . erase ( baseContract ) ;
}
for ( ASTPointer < InheritanceSpecifier > const & base : contract - > baseContracts ( ) )
{
auto baseContract = dynamic_cast < ContractDefinition const * > ( & dereference ( base - > name ( ) ) ) ;
solAssert ( baseContract , " " ) ;
if ( ! base - > arguments ( ) . empty ( ) )
argumentsNeeded . erase ( baseContract ) ;
}
}
if ( ! argumentsNeeded . empty ( ) )
_contract . annotation ( ) . isFullyImplemented = false ;
}
void TypeChecker : : checkContractIllegalOverrides ( ContractDefinition const & _contract )
{
// TODO unify this at a later point. for this we need to put the constness and the access specifier
// into the types
map < string , vector < FunctionDefinition const * > > functions ;
map < string , ModifierDefinition const * > modifiers ;
// We search from derived to base, so the stored item causes the error.
for ( ContractDefinition const * contract : _contract . annotation ( ) . linearizedBaseContracts )
{
2015-11-23 22:57:17 +00:00
for ( FunctionDefinition const * function : contract - > definedFunctions ( ) )
2015-09-16 14:56:30 +00:00
{
if ( function - > isConstructor ( ) )
continue ; // constructors can neither be overridden nor override anything
string const & name = function - > name ( ) ;
if ( modifiers . count ( name ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( modifiers [ name ] - > location ( ) , " Override changes function to modifier. " ) ;
2015-09-16 14:56:30 +00:00
FunctionType functionType ( * function ) ;
// function should not change the return type
for ( FunctionDefinition const * overriding : functions [ name ] )
{
FunctionType overridingType ( * overriding ) ;
if ( ! overridingType . hasEqualArgumentTypes ( functionType ) )
continue ;
if (
overriding - > visibility ( ) ! = function - > visibility ( ) | |
overriding - > isDeclaredConst ( ) ! = function - > isDeclaredConst ( ) | |
2016-08-26 18:37:10 +00:00
overriding - > isPayable ( ) ! = function - > isPayable ( ) | |
2015-09-16 14:56:30 +00:00
overridingType ! = functionType
)
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( overriding - > location ( ) , " Override changes extended function signature. " ) ;
2015-09-16 14:56:30 +00:00
}
2015-11-23 22:57:17 +00:00
functions [ name ] . push_back ( function ) ;
2015-09-16 14:56:30 +00:00
}
2015-11-23 22:57:17 +00:00
for ( ModifierDefinition const * modifier : contract - > functionModifiers ( ) )
2015-09-16 14:56:30 +00:00
{
string const & name = modifier - > name ( ) ;
ModifierDefinition const * & override = modifiers [ name ] ;
if ( ! override )
2015-11-23 22:57:17 +00:00
override = modifier ;
2015-09-16 14:56:30 +00:00
else if ( ModifierType ( * override ) ! = ModifierType ( * modifier ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( override - > location ( ) , " Override changes modifier signature. " ) ;
2015-09-16 14:56:30 +00:00
if ( ! functions [ name ] . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( override - > location ( ) , " Override changes modifier to function. " ) ;
2015-09-16 14:56:30 +00:00
}
}
}
void TypeChecker : : checkContractExternalTypeClashes ( ContractDefinition const & _contract )
{
map < string , vector < pair < Declaration const * , FunctionTypePointer > > > externalDeclarations ;
for ( ContractDefinition const * contract : _contract . annotation ( ) . linearizedBaseContracts )
{
2015-11-23 22:57:17 +00:00
for ( FunctionDefinition const * f : contract - > definedFunctions ( ) )
2015-09-16 14:56:30 +00:00
if ( f - > isPartOfExternalInterface ( ) )
{
auto functionType = make_shared < FunctionType > ( * f ) ;
2016-01-15 17:11:05 +00:00
// under non error circumstances this should be true
2016-01-15 16:36:06 +00:00
if ( functionType - > interfaceFunctionType ( ) )
externalDeclarations [ functionType - > externalSignature ( ) ] . push_back (
make_pair ( f , functionType )
) ;
2015-09-16 14:56:30 +00:00
}
2015-11-23 22:57:17 +00:00
for ( VariableDeclaration const * v : contract - > stateVariables ( ) )
2015-09-16 14:56:30 +00:00
if ( v - > isPartOfExternalInterface ( ) )
{
auto functionType = make_shared < FunctionType > ( * v ) ;
2016-01-15 17:11:05 +00:00
// under non error circumstances this should be true
2016-01-15 16:36:06 +00:00
if ( functionType - > interfaceFunctionType ( ) )
externalDeclarations [ functionType - > externalSignature ( ) ] . push_back (
make_pair ( v , functionType )
) ;
2015-09-16 14:56:30 +00:00
}
}
for ( auto const & it : externalDeclarations )
for ( size_t i = 0 ; i < it . second . size ( ) ; + + i )
for ( size_t j = i + 1 ; j < it . second . size ( ) ; + + j )
if ( ! it . second [ i ] . second - > hasEqualArgumentTypes ( * it . second [ j ] . second ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
it . second [ j ] . first - > location ( ) ,
2015-09-16 14:56:30 +00:00
" Function overload clash during conversion to external types for arguments. "
) ;
}
void TypeChecker : : checkLibraryRequirements ( ContractDefinition const & _contract )
{
solAssert ( _contract . isLibrary ( ) , " " ) ;
if ( ! _contract . baseContracts ( ) . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _contract . location ( ) , " Library is not allowed to inherit. " ) ;
2015-09-16 14:56:30 +00:00
for ( auto const & var : _contract . stateVariables ( ) )
if ( ! var - > isConstant ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( var - > location ( ) , " Library cannot have non-constant state variables " ) ;
2015-09-16 14:56:30 +00:00
}
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 ( ) ) ) ;
bool fillRight = ! lhs . components ( ) . empty ( ) & & ( ! lhs . components ( ) . back ( ) | | lhs . components ( ) . front ( ) ) ;
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 ;
size_t rhsPos = fillRight ? i : rhs . components ( ) . size ( ) - ( lhs . components ( ) . size ( ) - i ) ;
solAssert ( rhsPos < rhs . components ( ) . size ( ) , " " ) ;
toStorageCopies + + ;
if ( rhs . components ( ) [ rhsPos ] - > dataStoredIn ( DataLocation : : Storage ) )
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. "
) ;
}
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 ( ) ;
2016-08-31 18:43:24 +00:00
TypePointers parameterTypes = ContractType ( * base ) . newExpressionType ( ) - > parameterTypes ( ) ;
2015-09-16 14:56:30 +00:00
if ( ! arguments . empty ( ) & & parameterTypes . size ( ) ! = arguments . size ( ) )
2015-12-09 16:37:19 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_inheritance . location ( ) ,
2015-09-16 14:56:30 +00:00
" Wrong argument count for constructor call: " +
toString ( arguments . size ( ) ) +
" arguments given but expected " +
toString ( parameterTypes . size ( ) ) +
" . "
) ;
2015-12-09 16:37:19 +00:00
return ;
}
2015-09-16 14:56:30 +00:00
for ( size_t i = 0 ; i < arguments . size ( ) ; + + i )
if ( ! type ( * arguments [ i ] ) - > isImplicitlyConvertibleTo ( * parameterTypes [ 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 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-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _usingFor . libraryName ( ) . location ( ) , " Library name expected. " ) ;
2015-09-16 14:56:30 +00:00
}
bool TypeChecker : : visit ( StructDefinition const & _struct )
{
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 ( _struct . location ( ) , " Structs cannot be defined in interfaces. " ) ;
2017-02-07 22:13:03 +00:00
2015-09-16 14:56:30 +00:00
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.
using StructPointer = StructDefinition const * ;
using StructPointersSet = set < StructPointer > ;
function < void ( StructPointer , StructPointersSet const & ) > check = [ & ] ( StructPointer _struct , StructPointersSet const & _parents )
{
if ( _parents . count ( _struct ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _struct - > location ( ) , " Recursive struct definition. " ) ;
2015-09-16 14:56:30 +00:00
StructPointersSet parents = _parents ;
parents . insert ( _struct ) ;
for ( ASTPointer < VariableDeclaration > const & member : _struct - > members ( ) )
if ( type ( * member ) - > category ( ) = = Type : : Category : : Struct )
{
auto const & typeName = dynamic_cast < UserDefinedTypeName const & > ( * member - > typeName ( ) ) ;
check ( & dynamic_cast < StructDefinition const & > ( * typeName . annotation ( ) . referencedDeclaration ) , parents ) ;
}
} ;
check ( & _struct , StructPointersSet { } ) ;
ASTNode : : listAccept ( _struct . members ( ) , * this ) ;
return false ;
}
bool TypeChecker : : visit ( FunctionDefinition const & _function )
{
2017-02-14 12:32:48 +00:00
bool isLibraryFunction =
2017-01-31 22:12:40 +00:00
dynamic_cast < ContractDefinition const * > ( _function . scope ( ) ) & &
2017-02-14 12:32:48 +00:00
dynamic_cast < ContractDefinition const * > ( _function . scope ( ) ) - > isLibrary ( ) ;
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. " ) ;
2016-08-26 18:37:10 +00:00
if ( ! _function . isConstructor ( ) & & ! _function . name ( ) . empty ( ) & & ! _function . isPartOfExternalInterface ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Internal functions cannot be payable. " ) ;
2016-09-06 08:58:56 +00:00
if ( _function . isDeclaredConst ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Functions cannot be constant and payable at the same time. " ) ;
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 ( ) )
{
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 ( _function . visibility ( ) > = FunctionDefinition : : Visibility : : Public & & ! ( type ( * var ) - > interfaceType ( isLibraryFunction ) ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( var - > location ( ) , " Internal type is not allowed for public or external functions. " ) ;
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
m_errorReporter . declarationError ( modifier - > location ( ) , " Modifier already used for this function. " ) ;
}
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. " ) ;
2017-03-17 17:01:13 +00:00
if ( _function . visibility ( ) < FunctionDefinition : : Visibility : : Public )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _function . location ( ) , " Functions in interfaces cannot be internal or private. " ) ;
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
}
if ( _function . isImplemented ( ) )
_function . body ( ) . accept ( * this ) ;
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
// a function's input/output parameters.
if (
m_scope - > contractKind ( ) = = ContractDefinition : : ContractKind : : Interface
& & ! _variable . isCallableParameter ( )
)
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-09-16 14:56:30 +00:00
// Variables can be declared without type (with "var"), in which case the first assignment
// sets the type.
// Note that assignments before the first declaration are legal because of the special scoping
// rules inherited from JavaScript.
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 ;
2015-10-08 16:01:12 +00:00
solAssert ( ! ! varType , " Failed to infer variable type. " ) ;
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-01 18:12:40 +00:00
if ( ! _variable . isStateVariable ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Illegal use of \" constant \" specifier. " ) ;
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 ( ) ) )
allowed = arrayType - > isString ( ) ;
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
}
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 )
2017-05-11 13:26:35 +00:00
m_errorReporter . warning (
2017-03-01 18:12:40 +00:00
_variable . value ( ) - > location ( ) ,
2017-03-14 18:25:16 +00:00
" Initial value for constant variable has to be compile-time constant. "
" This will fail to compile with the next breaking version change. "
2017-03-01 18:12:40 +00:00
) ;
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
}
else if (
_variable . visibility ( ) > = VariableDeclaration : : Visibility : : Public & &
2015-10-02 11:11:38 +00:00
! FunctionType ( _variable ) . interfaceFunctionType ( )
2015-09-16 14:56:30 +00:00
)
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Internal type is not allowed for public state variables. " ) ;
2017-07-11 20:56:09 +00:00
if ( varType - > category ( ) = = Type : : Category : : Array )
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-07-11 20:56:09 +00:00
m_errorReporter . typeError ( _variable . location ( ) , " Array is too large to be encoded as calldata. " ) ;
2015-09-16 14:56:30 +00:00
return false ;
}
2017-03-15 22:12:31 +00:00
bool TypeChecker : : visit ( EnumDefinition const & _enum )
{
if ( m_scope - > contractKind ( ) = = ContractDefinition : : ContractKind : : Interface )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _enum . location ( ) , " Enumerable cannot be declared in interfaces. " ) ;
2017-03-15 22:12:31 +00:00
return false ;
}
2015-09-16 14:56:30 +00:00
void TypeChecker : : visitManually (
ModifierInvocation const & _modifier ,
vector < ContractDefinition const * > const & _bases
)
{
std : : vector < ASTPointer < Expression > > const & arguments = _modifier . arguments ( ) ;
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 ;
}
2015-09-16 14:56:30 +00:00
for ( size_t i = 0 ; i < _modifier . arguments ( ) . size ( ) ; + + i )
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 )
{
unsigned numIndexed = 0 ;
for ( ASTPointer < VariableDeclaration > const & var : _eventDef . parameters ( ) )
{
if ( var - > isIndexed ( ) )
numIndexed + + ;
2015-10-07 14:40:54 +00:00
if ( _eventDef . isAnonymous ( ) & & numIndexed > 4 )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _eventDef . location ( ) , " More than 4 indexed arguments for anonymous event. " ) ;
2015-10-07 14:40:54 +00:00
else if ( ! _eventDef . isAnonymous ( ) & & numIndexed > 3 )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _eventDef . location ( ) , " More than 3 indexed arguments for event. " ) ;
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-05-11 13:26:35 +00:00
m_errorReporter . typeError ( var - > location ( ) , " Internal type is not allowed as event parameter type. " ) ;
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.
2017-05-23 17:21:14 +00:00
julia : : ExternalIdentifierAccess : : Resolver identifierAccess = [ & ] (
2017-02-23 16:38:42 +00:00
assembly : : Identifier const & _identifier ,
2017-05-24 16:34:19 +00:00
julia : : IdentifierContext _context ,
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 , " " ) ;
2017-04-11 19:12:17 +00:00
if ( auto var = dynamic_cast < VariableDeclaration const * > ( declaration ) )
{
2017-04-21 17:13:46 +00:00
if ( ref - > second . isSlot | | ref - > second . isOffset )
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 ) ;
}
2017-05-23 17:21:14 +00:00
else if ( _context ! = julia : : 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 ) ;
}
}
2017-04-25 11:15:42 +00:00
else if ( var - > isConstant ( ) )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _identifier . location , " Constant variables not supported by inline assembly. " ) ;
2017-04-25 11:15:42 +00:00
return size_t ( - 1 ) ;
}
2017-04-21 17:13:46 +00:00
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
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _identifier . location , " You have to use the _slot or _offset prefix 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 ) ;
}
}
2017-05-23 17:21:14 +00:00
else if ( _context = = julia : : 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 ) ;
}
2017-05-23 17:21:14 +00:00
if ( _context = = julia : : 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 , " " ) ;
_inlineAssembly . annotation ( ) . analysisInfo = make_shared < assembly : : AsmAnalysisInfo > ( ) ;
assembly : : AsmAnalyzer analyzer (
* _inlineAssembly . annotation ( ) . analysisInfo ,
2017-05-11 13:26:35 +00:00
m_errorReporter ,
2017-05-25 00:59:57 +00:00
false ,
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 )
{
if ( ! _return . expression ( ) )
return ;
ParameterList const * params = _return . annotation ( ) . functionReturnParameters ;
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 ( ) +
" . "
) ;
}
}
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 ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _statement . location ( ) , " Assignment necessary for type detection. " ) ;
2015-10-09 17:35:41 +00:00
VariableDeclaration const & varDecl = * _statement . declarations ( ) . front ( ) ;
if ( ! varDecl . annotation ( ) . type )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _statement . location ( ) , " Assignment necessary for type detection. " ) ;
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. " } ;
if ( varDecl . referenceLocation ( ) = = VariableDeclaration : : Location : : Default )
errorText + = " Did you mean '<type> memory " + varDecl . name ( ) + " '? " ;
m_errorReporter . warning ( varDecl . location ( ) , errorText ) ;
}
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
// Determine which component is assigned to which variable.
2015-10-09 17:35:41 +00:00
// If numbers do not match, fill up if variables begin or end empty (not both).
2015-10-09 18:44:56 +00:00
vector < VariableDeclaration const * > & assignments = _statement . annotation ( ) . assignments ;
assignments . resize ( valueTypes . size ( ) , nullptr ) ;
vector < ASTPointer < VariableDeclaration > > const & variables = _statement . declarations ( ) ;
2015-10-13 12:31:24 +00:00
if ( variables . empty ( ) )
{
if ( ! valueTypes . empty ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-04 10:49:26 +00:00
_statement . location ( ) ,
2015-10-13 12:31:24 +00:00
" Too many components ( " +
toString ( valueTypes . size ( ) ) +
" ) in value for variable assignment (0) needed "
) ;
}
else if ( valueTypes . size ( ) ! = variables . size ( ) & & ! variables . front ( ) & & ! variables . back ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-04 10:49:26 +00:00
_statement . location ( ) ,
2015-10-09 18:44:56 +00:00
" Wildcard both at beginning and end of variable declaration list is only allowed "
" if the number of components is equal. "
) ;
size_t minNumValues = variables . size ( ) ;
2015-10-13 12:31:24 +00:00
if ( ! variables . empty ( ) & & ( ! variables . back ( ) | | ! variables . front ( ) ) )
2015-10-09 18:44:56 +00:00
- - minNumValues ;
if ( valueTypes . size ( ) < minNumValues )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-04 10:49:26 +00:00
_statement . location ( ) ,
2015-10-09 18:44:56 +00:00
" Not enough components ( " +
toString ( valueTypes . size ( ) ) +
" ) in value to assign all variables ( " +
toString ( minNumValues ) + " ). "
) ;
if ( valueTypes . size ( ) > variables . size ( ) & & variables . front ( ) & & variables . back ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError (
2015-11-04 10:49:26 +00:00
_statement . location ( ) ,
2015-10-09 18:44:56 +00:00
" Too many components ( " +
toString ( valueTypes . size ( ) ) +
" ) in value for variable assignment ( " +
toString ( minNumValues ) +
" needed). "
) ;
2015-10-13 12:31:24 +00:00
bool fillRight = ! variables . empty ( ) & & ( ! variables . back ( ) | | variables . front ( ) ) ;
2015-10-09 18:44:56 +00:00
for ( size_t i = 0 ; i < min ( variables . size ( ) , valueTypes . size ( ) ) ; + + i )
if ( fillRight )
assignments [ i ] = variables [ i ] . get ( ) ;
else
assignments [ assignments . size ( ) - i - 1 ] = variables [ variables . size ( ) - i - 1 ] . get ( ) ;
2015-10-09 17:35:41 +00:00
2015-10-09 18:44:56 +00:00
for ( size_t i = 0 ; i < assignments . size ( ) ; + + i )
2015-10-09 17:35:41 +00:00
{
2015-10-09 18:44:56 +00:00
if ( ! assignments [ i ] )
2015-10-09 17:35:41 +00:00
continue ;
2015-10-09 18:44:56 +00:00
VariableDeclaration const & var = * assignments [ 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 )
{
// 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 ( ) +
" (absolute value too large or divison by zero). "
) ;
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 ( ) ) )
{
int numBits = type - > numBits ( ) ;
bool isSigned = type - > isSigned ( ) ;
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. " ) ;
m_errorReporter . warning (
_statement . location ( ) ,
" The type of this variable was inferred as " +
typeName +
extension +
" . This is probably not desired. Use an explicit type to silence this warning. "
) ;
}
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 ( ) +
" or use an explicit conversion. "
) ;
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
}
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-03-16 11:58:17 +00:00
kind = = FunctionType : : Kind : : Bare | |
kind = = FunctionType : : Kind : : BareCallCode | |
kind = = FunctionType : : Kind : : BareDelegateCall
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
}
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 ;
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 > ( ) ;
2015-10-14 13:19:50 +00:00
expectType ( _assignment . rightHandSide ( ) , * tupleType ) ;
2017-06-21 17:32:56 +00:00
checkDoubleStorageAssignment ( _assignment ) ;
2015-10-14 13:19:50 +00:00
}
else if ( t - > category ( ) = = Type : : Category : : Mapping )
2015-09-16 14:56:30 +00:00
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _assignment . location ( ) , " Mappings cannot be assigned to. " ) ;
2015-09-16 14:56:30 +00:00
_assignment . rightHandSide ( ) . accept ( * this ) ;
}
else if ( _assignment . assignmentOperator ( ) = = Token : : Assign )
expectType ( _assignment . rightHandSide ( ) , * t ) ;
else
{
// compound assignment
_assignment . rightHandSide ( ) . accept ( * this ) ;
TypePointer resultType = t - > binaryOperatorResult (
Token : : AssignmentToBinaryOp ( _assignment . assignmentOperator ( ) ) ,
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 " +
string ( Token : : toString ( _assignment . assignmentOperator ( ) ) ) +
" 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 ;
2015-10-12 21:02:35 +00:00
for ( size_t i = 0 ; i < components . size ( ) ; + + i )
{
// Outside of an lvalue-context, the only situation where a component can be empty is (x,).
if ( ! components [ i ] & & ! ( i = = 1 & & components . size ( ) = = 2 ) )
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 ] ) ) ;
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 ( ) )
{
if ( ! inlineArrayType )
2017-05-11 13:26:35 +00:00
m_errorReporter . fatalTypeError ( _tuple . location ( ) , " Unable to deduce common type for array elements. " ) ;
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
{
if ( components . size ( ) = = 2 & & ! components [ 1 ] )
types . pop_back ( ) ;
_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
Token : : Value op = _operation . getOperator ( ) ;
2017-03-01 18:12:40 +00:00
bool const modifying = ( op = = Token : : Value : : Inc | | op = = Token : : Value : : Dec | | op = = Token : : Value : : Delete ) ;
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 " +
string ( Token : : toString ( op ) ) +
" 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 ( ) ) ;
TypePointer commonType = leftType - > binaryOperatorResult ( _operation . getOperator ( ) , rightType ) ;
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 " +
string ( Token : : toString ( _operation . getOperator ( ) ) ) +
" not compatible with types " +
leftType - > toString ( ) +
" and " +
rightType - > toString ( )
) ;
commonType = leftType ;
}
_operation . annotation ( ) . commonType = commonType ;
_operation . annotation ( ) . type =
Token : : isCompareOp ( _operation . getOperator ( ) ) ?
make_shared < BoolType > ( ) :
commonType ;
2017-03-01 18:12:40 +00:00
_operation . annotation ( ) . isPure =
_operation . leftExpression ( ) . annotation ( ) . isPure & &
_operation . rightExpression ( ) . annotation ( ) . isPure ;
2017-03-07 12:44:11 +00:00
if ( _operation . getOperator ( ) = = Token : : Exp )
{
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 ( ) ,
" Result of exponentiation has type " + commonType - > toString ( ) + " and thus "
" might overflow. Silence this warning by converting the literal to the "
" expected type. "
) ;
}
2015-09-16 14:56:30 +00:00
}
bool TypeChecker : : visit ( FunctionCall const & _functionCall )
{
bool isPositionalCall = _functionCall . names ( ) . empty ( ) ;
vector < ASTPointer < Expression const > > arguments = _functionCall . arguments ( ) ;
vector < ASTPointer < ASTString > > const & argumentNames = _functionCall . names ( ) ;
2017-03-01 18:12:40 +00:00
bool isPure = true ;
2015-09-16 14:56:30 +00:00
// We need to check arguments' type first as they will be needed for overload resolution.
shared_ptr < TypePointers > argumentTypes ;
if ( isPositionalCall )
argumentTypes = make_shared < TypePointers > ( ) ;
for ( ASTPointer < Expression const > const & argument : arguments )
{
argument - > accept ( * this ) ;
2017-03-01 18:12:40 +00:00
if ( ! argument - > annotation ( ) . isPure )
isPure = false ;
2015-09-16 14:56:30 +00:00
// only store them for positional calls
if ( isPositionalCall )
argumentTypes - > push_back ( type ( * argument ) ) ;
}
if ( isPositionalCall )
_functionCall . expression ( ) . annotation ( ) . argumentTypes = move ( argumentTypes ) ;
_functionCall . expression ( ) . accept ( * this ) ;
TypePointer expressionType = type ( _functionCall . expression ( ) ) ;
if ( auto const * typeType = dynamic_cast < TypeType const * > ( expressionType . get ( ) ) )
{
2017-05-19 13:45:01 +00:00
if ( typeType - > actualType ( ) - > category ( ) = = Type : : Category : : Struct )
_functionCall . annotation ( ) . kind = FunctionCallKind : : StructConstructorCall ;
else
_functionCall . annotation ( ) . kind = FunctionCallKind : : TypeConversion ;
2015-09-16 14:56:30 +00:00
}
else
2017-05-19 13:45:01 +00:00
_functionCall . annotation ( ) . kind = FunctionCallKind : : FunctionCall ;
2017-05-22 09:51:45 +00:00
solAssert ( _functionCall . annotation ( ) . kind ! = FunctionCallKind : : Unset , " " ) ;
2015-09-16 14:56:30 +00:00
2017-05-19 13:45:01 +00:00
if ( _functionCall . annotation ( ) . kind = = FunctionCallKind : : TypeConversion )
2015-09-16 14:56:30 +00:00
{
TypeType const & t = dynamic_cast < TypeType const & > ( * expressionType ) ;
TypePointer resultType = t . actualType ( ) ;
if ( arguments . size ( ) ! = 1 )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _functionCall . location ( ) , " Exactly one argument expected for explicit type conversion. " ) ;
2015-09-16 14:56:30 +00:00
else if ( ! isPositionalCall )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _functionCall . location ( ) , " Type conversion cannot allow named arguments. " ) ;
2015-09-16 14:56:30 +00:00
else
{
TypePointer const & argType = type ( * arguments . front ( ) ) ;
if ( auto argRefType = dynamic_cast < ReferenceType const * > ( argType . get ( ) ) )
// do not change the data location when converting
// (data location cannot yet be specified for type conversions)
resultType = ReferenceType : : copyForLocationIfReference ( argRefType - > location ( ) , resultType ) ;
if ( ! argType - > isExplicitlyConvertibleTo ( * resultType ) )
2017-07-11 20:08:39 +00:00
m_errorReporter . typeError (
_functionCall . location ( ) ,
" Explicit type conversion not allowed from \" " +
argType - > toString ( ) +
" \" to \" " +
resultType - > toString ( ) +
" \" . "
) ;
2015-09-16 14:56:30 +00:00
}
_functionCall . annotation ( ) . type = resultType ;
2017-03-01 18:12:40 +00:00
_functionCall . annotation ( ) . isPure = isPure ;
2015-09-16 14:56:30 +00:00
return false ;
}
// Actual function call or struct constructor call.
FunctionTypePointer functionType ;
/// For error message: Struct members that were removed during conversion to memory.
set < string > membersRemovedForStructConstructor ;
2017-05-19 13:45:01 +00:00
if ( _functionCall . annotation ( ) . kind = = FunctionCallKind : : StructConstructorCall )
2015-09-16 14:56:30 +00:00
{
TypeType const & t = dynamic_cast < TypeType const & > ( * expressionType ) ;
auto const & structType = dynamic_cast < StructType const & > ( * t . actualType ( ) ) ;
functionType = structType . constructorType ( ) ;
membersRemovedForStructConstructor = structType . membersMissingInMemory ( ) ;
2017-03-01 18:12:40 +00:00
_functionCall . annotation ( ) . isPure = isPure ;
2015-09-16 14:56:30 +00:00
}
2017-06-14 14:33:44 +00:00
else if ( ( functionType = dynamic_pointer_cast < FunctionType const > ( expressionType ) ) )
2017-03-01 18:12:40 +00:00
_functionCall . annotation ( ) . isPure =
isPure & &
_functionCall . expression ( ) . annotation ( ) . isPure & &
functionType - > isPure ( ) ;
2015-09-16 14:56:30 +00:00
if ( ! functionType )
{
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _functionCall . location ( ) , " Type is not callable " ) ;
2015-10-09 17:35:41 +00:00
_functionCall . annotation ( ) . type = make_shared < TupleType > ( ) ;
2015-09-16 14:56:30 +00:00
return false ;
}
2015-10-09 17:35:41 +00:00
else if ( functionType - > returnParameterTypes ( ) . size ( ) = = 1 )
_functionCall . annotation ( ) . type = functionType - > returnParameterTypes ( ) . front ( ) ;
2015-09-16 14:56:30 +00:00
else
2015-10-09 17:35:41 +00:00
_functionCall . annotation ( ) . type = make_shared < TupleType > ( functionType - > returnParameterTypes ( ) ) ;
2015-09-16 14:56:30 +00:00
2015-12-09 16:53:15 +00:00
TypePointers parameterTypes = functionType - > parameterTypes ( ) ;
2015-09-16 14:56:30 +00:00
if ( ! functionType - > takesArbitraryParameters ( ) & & parameterTypes . size ( ) ! = arguments . size ( ) )
{
string msg =
" Wrong argument count for function call: " +
toString ( arguments . size ( ) ) +
" arguments given but expected " +
toString ( parameterTypes . size ( ) ) +
" . " ;
// Extend error message in case we try to construct a struct with mapping member.
2017-05-19 13:45:01 +00:00
if ( _functionCall . annotation ( ) . kind = = FunctionCallKind : : StructConstructorCall & & ! membersRemovedForStructConstructor . empty ( ) )
2015-09-16 14:56:30 +00:00
{
msg + = " Members that have to be skipped in memory: " ;
for ( auto const & member : membersRemovedForStructConstructor )
msg + = " " + member ;
}
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _functionCall . location ( ) , msg ) ;
2015-09-16 14:56:30 +00:00
}
else if ( isPositionalCall )
{
// call by positional arguments
for ( size_t i = 0 ; i < arguments . size ( ) ; + + i )
2015-10-07 15:32:05 +00:00
{
auto const & argType = type ( * arguments [ i ] ) ;
if ( functionType - > takesArbitraryParameters ( ) )
{
2016-03-29 20:08:51 +00:00
if ( auto t = dynamic_cast < RationalNumberType const * > ( argType . get ( ) ) )
2016-05-10 08:26:53 +00:00
if ( ! t - > mobileType ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( arguments [ i ] - > location ( ) , " Invalid rational number (too large or division by zero). " ) ;
2015-10-07 15:32:05 +00:00
}
else if ( ! type ( * arguments [ i ] ) - > isImplicitlyConvertibleTo ( * parameterTypes [ 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 function call. "
" Invalid implicit conversion from " +
type ( * arguments [ i ] ) - > toString ( ) +
" to " +
parameterTypes [ i ] - > toString ( ) +
" requested. "
) ;
2015-10-07 15:32:05 +00:00
}
2015-09-16 14:56:30 +00:00
}
else
{
// call by named arguments
auto const & parameterNames = functionType - > parameterNames ( ) ;
if ( functionType - > takesArbitraryParameters ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_functionCall . location ( ) ,
2015-09-16 14:56:30 +00:00
" Named arguments cannnot be used for functions that take arbitrary parameters. "
) ;
else if ( parameterNames . size ( ) > argumentNames . size ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _functionCall . location ( ) , " Some argument names are missing. " ) ;
2015-09-16 14:56:30 +00:00
else if ( parameterNames . size ( ) < argumentNames . size ( ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _functionCall . location ( ) , " Too many arguments. " ) ;
2015-09-16 14:56:30 +00:00
else
{
// check duplicate names
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 ;
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( arguments [ i ] - > location ( ) , " Duplicate named argument. " ) ;
2015-09-16 14:56:30 +00:00
}
// check actual types
if ( ! duplication )
for ( size_t i = 0 ; i < argumentNames . size ( ) ; i + + )
{
bool found = false ;
for ( size_t j = 0 ; j < parameterNames . size ( ) ; j + + )
if ( parameterNames [ j ] = = * argumentNames [ i ] )
{
found = true ;
// check type convertible
if ( ! type ( * arguments [ i ] ) - > isImplicitlyConvertibleTo ( * parameterTypes [ j ] ) )
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 function call. "
" Invalid implicit conversion from " +
type ( * arguments [ i ] ) - > toString ( ) +
" to " +
parameterTypes [ i ] - > toString ( ) +
" requested. "
) ;
break ;
}
if ( ! found )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError (
2015-11-04 10:49:26 +00:00
_functionCall . location ( ) ,
2015-09-16 14:56:30 +00:00
" Named argument does not match function declaration. "
) ;
}
}
}
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. " ) ;
2015-11-16 23:06:57 +00:00
if ( ! contract - > annotation ( ) . isFullyImplemented )
2017-05-11 13:26:35 +00:00
m_errorReporter . typeError ( _newExpression . location ( ) , " Trying to create an instance of an abstract contract. " ) ;
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-03-16 11:58:17 +00:00
FunctionType : : Kind : : ObjectCreation
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 ) ;
2015-09-16 14:56:30 +00:00
if ( possibleMembers . size ( ) > 1 & & argumentTypes )
{
// 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 ;
}
if ( possibleMembers . size ( ) = = 0 )
{
auto storageType = ReferenceType : : copyForLocationIfReference (
DataLocation : : Storage ,
exprType
) ;
2015-11-19 17:02:04 +00:00
if ( ! storageType - > members ( m_scope ) . membersByName ( memberName ) . empty ( ) )
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 + " \" is not available in " +
exprType - > toString ( ) +
" outside of storage. "
) ;
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 found or not visible "
2016-08-26 18:37:10 +00:00
" after argument-dependent lookup in " + exprType - > toString ( ) +
( memberName = = " value " ? " - did you forget the \" payable \" modifier? " : " " )
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 ( ) +
( memberName = = " value " ? " - did you forget the \" payable \" modifier? " : " " )
2015-09-16 14:56:30 +00:00
) ;
auto & annotation = _memberAccess . annotation ( ) ;
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 " +
exprType - > toString ( ) + " (expected " + funType - > selfType ( ) - > toString ( ) + " ) "
) ;
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 )
{
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 ;
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
{
expectType ( * index , IntegerType ( 256 ) ) ;
2016-03-29 20:08:51 +00:00
if ( auto numberType = dynamic_cast < RationalNumberType const * > ( type ( * index ) . get ( ) ) )
2016-02-18 22:39:11 +00:00
{
2016-05-10 12:30:24 +00:00
if ( ! numberType - > isFractional ( ) ) // error is reported above
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. " ) ;
2016-05-10 08:26:53 +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
{
2016-04-12 17:36:34 +00:00
expectType ( * index , IntegerType ( 256 ) ) ;
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
{
expectType ( * index , IntegerType ( 256 ) ) ;
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 )
{
2015-11-19 17:02:04 +00:00
TypePointer function = declaration - > type ( ) ;
2015-09-16 14:56:30 +00:00
solAssert ( ! ! function , " Requested type not present. " ) ;
auto const * functionType = dynamic_cast < FunctionType const * > ( function . get ( ) ) ;
if ( functionType & & functionType - > canTakeArguments ( * annotation . argumentTypes ) )
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 ;
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 ( ) )
{
if ( _literal . passesAddressChecksum ( ) )
_literal . annotation ( ) . type = make_shared < IntegerType > ( 0 , IntegerType : : Modifier : : Address ) ;
else
2017-05-11 13:26:35 +00:00
m_errorReporter . warning (
2017-03-06 12:31:57 +00:00
_literal . location ( ) ,
" This looks like an address but has an invalid checksum. "
" If this is not used as an address, please prepend '00'. "
) ;
2017-01-24 16:38:06 +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 ;
}
2015-09-16 14:56:30 +00:00
void TypeChecker : : expectType ( Expression const & _expression , Type const & _expectedType )
{
_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 ( ) +
" . "
) ;
2017-06-22 14:14:14 +00:00
}
if (
type ( _expression ) - > category ( ) = = Type : : Category : : RationalNumber & &
_expectedType . category ( ) = = Type : : Category : : FixedBytes
)
{
auto literal = dynamic_cast < Literal const * > ( & _expression ) ;
2017-06-28 15:59:34 +00:00
if ( literal & & ! literal - > isHexNumber ( ) )
2017-06-22 14:14:14 +00:00
m_errorReporter . warning (
_expression . location ( ) ,
" Decimal literal assigned to bytesXX variable will be left-aligned. "
" Use an explicit conversion to silence this warning. "
) ;
}
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
}