2323#include < libsolidity/analysis/PostTypeContractLevelChecker.h>
2424
2525#include < fmt/format.h>
26+ #include < libsolidity/analysis/ConstantEvaluator.h>
2627#include < libsolidity/ast/AST.h>
2728#include < libsolidity/ast/ASTUtils.h>
2829#include < libsolidity/ast/TypeProvider.h>
@@ -101,29 +102,53 @@ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinitio
101102 }
102103
103104 auto const * baseSlotExpressionType = type (baseSlotExpression);
104- auto const * rationalType = dynamic_cast <RationalNumberType const *>(baseSlotExpressionType);
105- if (!rationalType)
105+ if (
106+ !dynamic_cast <IntegerType const *>(baseSlotExpressionType) &&
107+ !dynamic_cast <RationalNumberType const *>(baseSlotExpressionType)
108+ )
106109 {
107110 m_errorReporter.typeError (
108111 6396_error,
109112 baseSlotExpression.location (),
110- " The base slot of the storage layout must evaluate to a rational number."
113+ " The base slot of the storage layout must evaluate to an integer number."
111114 );
112115 return ;
113116 }
114117
115- if (rationalType->isFractional ())
118+ rational baseSlotRationalValue;
119+ if (auto const integerType = dynamic_cast <IntegerType const *>(baseSlotExpressionType))
116120 {
117- m_errorReporter.typeError (
118- 1763_error,
119- baseSlotExpression.location (),
120- " The base slot of the storage layout must evaluate to an integer."
121- );
122- return ;
121+ std::optional<ConstantEvaluator::TypedRational> typedRational = ConstantEvaluator::evaluate (m_errorReporter, baseSlotExpression);
122+ if (!typedRational)
123+ {
124+ m_errorReporter.typeError (
125+ 1505_error,
126+ baseSlotExpression.location (),
127+ " The base slot expression contains elements that are not yet supported "
128+ " by the internal constant evaluator and therefore cannot be evaluated at compilation time."
129+ );
130+ return ;
131+ }
132+ baseSlotRationalValue = typedRational->value ;
133+ }
134+ else
135+ {
136+ auto const * rationalType = dynamic_cast <RationalNumberType const *>(baseSlotExpressionType);
137+ solAssert (rationalType);
138+ if (rationalType->isFractional ())
139+ {
140+ m_errorReporter.typeError (
141+ 1763_error,
142+ baseSlotExpression.location (),
143+ " The base slot of the storage layout must evaluate to an integer."
144+ );
145+ return ;
146+ }
147+ baseSlotRationalValue = rationalType->value ();
123148 }
124- solAssert (rationalType->value ().denominator () == 1 );
125149
126- bigint baseSlot = rationalType->value ().numerator ();
150+ solAssert (baseSlotRationalValue.denominator () == 1 );
151+ bigint baseSlot = baseSlotRationalValue.numerator ();
127152 if (!(0 <= baseSlot && baseSlot <= std::numeric_limits<u256>::max ()))
128153 {
129154 m_errorReporter.typeError (
@@ -137,7 +162,18 @@ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinitio
137162 return ;
138163 }
139164
140- solAssert (baseSlotExpressionType->isImplicitlyConvertibleTo (*TypeProvider::uint256 ()));
165+ if (!baseSlotExpressionType->isImplicitlyConvertibleTo (*TypeProvider::uint256 ()))
166+ {
167+ m_errorReporter.typeError (
168+ 1481_error,
169+ baseSlotExpression.location (),
170+ fmt::format (
171+ " The base slot expression type {} is not convertible to type uint256." ,
172+ baseSlotExpressionType->humanReadableName ()
173+ )
174+ );
175+ return ;
176+ }
141177 storageLayoutSpecifier->annotation ().baseSlot = u256 (baseSlot);
142178
143179 bigint size = contractStorageSizeUpperBound (_contract, VariableDeclaration::Location::Unspecified);
0 commit comments