Skip to content

Commit ed52376

Browse files
authored
Merge pull request #14510 from ethereum/newAnalysis
Type inference experiments.
2 parents 1b5c6f6 + 194b114 commit ed52376

File tree

93 files changed

+6536
-133
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+6536
-133
lines changed

Diff for: .circleci/osx_install_dependencies.sh

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ then
5959
brew install wget
6060
brew install coreutils
6161
brew install diffutils
62+
brew install grep
6263
./scripts/install_obsolete_jsoncpp_1_7_4.sh
6364

6465
# z3

Diff for: liblangutil/Scanner.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ void Scanner::scanToken()
665665
case '.':
666666
// . Number
667667
advance();
668-
if (isDecimalDigit(m_char))
668+
if (m_kind != ScannerKind::ExperimentalSolidity && isDecimalDigit(m_char))
669669
token = scanNumber('.');
670670
else
671671
token = Token::Period;

Diff for: liblangutil/Token.h

+23-6
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,15 @@ namespace solidity::langutil
269269
T(Leave, "leave", 0) \
270270
\
271271
T(NonExperimentalEnd, nullptr, 0) /* used as non-experimental enum end marker */ \
272+
/* Experimental Solidity specific keywords. */ \
273+
K(Class, "class", 0) \
274+
K(Instantiation, "instantiation", 0) \
275+
K(Integer, "Integer", 0) \
276+
K(Itself, "itself", 0) \
277+
K(StaticAssert, "static_assert", 0) \
278+
K(Builtin, "__builtin", 0) \
272279
T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \
280+
\
273281
/* Illegal token - not able to scan. */ \
274282
T(Illegal, "ILLEGAL", 0) \
275283
\
@@ -292,7 +300,7 @@ namespace TokenTraits
292300
constexpr size_t count() { return static_cast<size_t>(Token::NUM_TOKENS); }
293301

294302
// Predicates
295-
constexpr bool isElementaryTypeName(Token tok) { return Token::Int <= tok && tok < Token::TypesEnd; }
303+
constexpr bool isElementaryTypeName(Token _token) { return Token::Int <= _token && _token < Token::TypesEnd; }
296304
constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; }
297305
constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; }
298306
constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd ||
@@ -325,6 +333,16 @@ namespace TokenTraits
325333
tok == Token::TrueLiteral || tok == Token::FalseLiteral || tok == Token::HexStringLiteral || tok == Token::Hex;
326334
}
327335

336+
constexpr bool isBuiltinTypeClassName(Token _token)
337+
{
338+
return
339+
_token == Token::Integer ||
340+
(isBinaryOp(_token) && _token != Token::Comma) ||
341+
isCompareOp(_token) ||
342+
isUnaryOp(_token) ||
343+
(isAssignmentOp(_token) && _token != Token::Assign);
344+
}
345+
328346
constexpr bool isExperimentalSolidityKeyword(Token token)
329347
{
330348
return
@@ -345,17 +363,16 @@ namespace TokenTraits
345363
token == Token::While ||
346364
token == Token::For ||
347365
token == Token::Continue ||
348-
token == Token::Break;
349-
// TODO: see isExperimentalSolidityKeyword below
350-
// || (token > Token::NonExperimentalEnd && token < Token::ExperimentalEnd);
366+
token == Token::Break ||
367+
(token > Token::NonExperimentalEnd && token< Token::ExperimentalEnd);
351368
}
352369

353-
constexpr bool isExperimentalSolidityOnlyKeyword(Token)
370+
constexpr bool isExperimentalSolidityOnlyKeyword(Token _token)
354371
{
355372
// TODO: use token > Token::NonExperimentalEnd && token < Token::ExperimentalEnd
356373
// as soon as other experimental tokens are added. For now the comparison generates
357374
// a warning from clang because it is always false.
358-
return false;
375+
return _token > Token::NonExperimentalEnd && _token < Token::ExperimentalEnd;
359376
}
360377

361378
bool isYulKeyword(std::string const& _literal);

Diff for: libsolidity/CMakeLists.txt

+28
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,34 @@ set(sources
184184
parsing/Parser.cpp
185185
parsing/Parser.h
186186
parsing/Token.h
187+
experimental/analysis/Analysis.cpp
188+
experimental/analysis/Analysis.h
189+
experimental/analysis/DebugWarner.cpp
190+
experimental/analysis/DebugWarner.h
191+
experimental/analysis/FunctionDependencyAnalysis.cpp
192+
experimental/analysis/FunctionDependencyAnalysis.h
193+
experimental/analysis/TypeClassRegistration.cpp
194+
experimental/analysis/TypeClassRegistration.h
195+
experimental/analysis/TypeInference.cpp
196+
experimental/analysis/TypeInference.h
197+
experimental/analysis/TypeRegistration.cpp
198+
experimental/analysis/TypeRegistration.h
199+
experimental/analysis/SyntaxRestrictor.cpp
200+
experimental/analysis/SyntaxRestrictor.h
201+
experimental/ast/FunctionCallGraph.h
202+
experimental/ast/Type.cpp
203+
experimental/ast/Type.h
204+
experimental/ast/TypeSystem.cpp
205+
experimental/ast/TypeSystem.h
206+
experimental/ast/TypeSystemHelper.cpp
207+
experimental/ast/TypeSystemHelper.h
208+
experimental/codegen/Common.h
209+
experimental/codegen/Common.cpp
210+
experimental/codegen/IRGenerationContext.h
211+
experimental/codegen/IRGenerator.cpp
212+
experimental/codegen/IRGenerator.h
213+
experimental/codegen/IRGeneratorForStatements.cpp
214+
experimental/codegen/IRGeneratorForStatements.h
187215
)
188216

189217
add_library(solidity ${sources})

Diff for: libsolidity/analysis/NameAndTypeResolver.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ namespace solidity::frontend
3838
NameAndTypeResolver::NameAndTypeResolver(
3939
GlobalContext& _globalContext,
4040
langutil::EVMVersion _evmVersion,
41-
ErrorReporter& _errorReporter
41+
ErrorReporter& _errorReporter,
42+
bool _experimentalSolidity
4243
):
4344
m_evmVersion(_evmVersion),
4445
m_errorReporter(_errorReporter),
45-
m_globalContext(_globalContext)
46+
m_globalContext(_globalContext),
47+
m_experimentalSolidity(_experimentalSolidity)
4648
{
4749
m_scopes[nullptr] = std::make_shared<DeclarationContainer>();
4850
for (Declaration const* declaration: _globalContext.declarations())

Diff for: libsolidity/analysis/NameAndTypeResolver.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class NameAndTypeResolver
5959
NameAndTypeResolver(
6060
GlobalContext& _globalContext,
6161
langutil::EVMVersion _evmVersion,
62-
langutil::ErrorReporter& _errorReporter
62+
langutil::ErrorReporter& _errorReporter,
63+
bool _experimentalSolidity
6364
);
6465
/// Registers all declarations found in the AST node, usually a source unit.
6566
/// @returns false in case of error.
@@ -107,6 +108,7 @@ class NameAndTypeResolver
107108
/// Sets the current scope.
108109
void setScope(ASTNode const* _node);
109110

111+
bool experimentalSolidity() const { return m_experimentalSolidity; }
110112
private:
111113
/// Internal version of @a resolveNamesAndTypes (called from there) throws exceptions on fatal errors.
112114
bool resolveNamesAndTypesInternal(ASTNode& _node, bool _resolveInsideCode = true);
@@ -132,6 +134,7 @@ class NameAndTypeResolver
132134
DeclarationContainer* m_currentScope = nullptr;
133135
langutil::ErrorReporter& m_errorReporter;
134136
GlobalContext& m_globalContext;
137+
bool m_experimentalSolidity = false;
135138
};
136139

137140
/**

Diff for: libsolidity/analysis/ReferencesResolver.cpp

+85-8
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,21 @@ bool ReferencesResolver::visit(VariableDeclaration const& _varDecl)
112112
if (_varDecl.documentation())
113113
resolveInheritDoc(*_varDecl.documentation(), _varDecl.annotation());
114114

115+
if (m_resolver.experimentalSolidity())
116+
{
117+
solAssert(!_varDecl.hasTypeName());
118+
if (_varDecl.typeExpression())
119+
{
120+
ScopedSaveAndRestore typeContext{m_typeContext, true};
121+
_varDecl.typeExpression()->accept(*this);
122+
}
123+
if (_varDecl.overrides())
124+
_varDecl.overrides()->accept(*this);
125+
if (_varDecl.value())
126+
_varDecl.value()->accept(*this);
127+
return false;
128+
}
129+
115130
return true;
116131
}
117132

@@ -120,6 +135,8 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
120135
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
121136
if (declarations.empty())
122137
{
138+
if (m_resolver.experimentalSolidity() && m_typeContext)
139+
return false;
123140
std::string suggestions = m_resolver.similarNameSuggestions(_identifier.name());
124141
std::string errorMessage = "Undeclared identifier.";
125142
if (!suggestions.empty())
@@ -140,7 +157,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
140157

141158
bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
142159
{
143-
m_returnParameters.push_back(_functionDefinition.returnParameterList().get());
160+
m_functionDefinitions.push_back(&_functionDefinition);
144161

145162
if (_functionDefinition.documentation())
146163
resolveInheritDoc(*_functionDefinition.documentation(), _functionDefinition.annotation());
@@ -150,13 +167,13 @@ bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
150167

151168
void ReferencesResolver::endVisit(FunctionDefinition const&)
152169
{
153-
solAssert(!m_returnParameters.empty(), "");
154-
m_returnParameters.pop_back();
170+
solAssert(!m_functionDefinitions.empty(), "");
171+
m_functionDefinitions.pop_back();
155172
}
156173

157174
bool ReferencesResolver::visit(ModifierDefinition const& _modifierDefinition)
158175
{
159-
m_returnParameters.push_back(nullptr);
176+
m_functionDefinitions.push_back(nullptr);
160177

161178
if (_modifierDefinition.documentation())
162179
resolveInheritDoc(*_modifierDefinition.documentation(), _modifierDefinition.annotation());
@@ -166,8 +183,8 @@ bool ReferencesResolver::visit(ModifierDefinition const& _modifierDefinition)
166183

167184
void ReferencesResolver::endVisit(ModifierDefinition const&)
168185
{
169-
solAssert(!m_returnParameters.empty(), "");
170-
m_returnParameters.pop_back();
186+
solAssert(!m_functionDefinitions.empty(), "");
187+
m_functionDefinitions.pop_back();
171188
}
172189

173190
void ReferencesResolver::endVisit(IdentifierPath const& _path)
@@ -227,11 +244,30 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
227244

228245
bool ReferencesResolver::visit(Return const& _return)
229246
{
230-
solAssert(!m_returnParameters.empty(), "");
231-
_return.annotation().functionReturnParameters = m_returnParameters.back();
247+
solAssert(!m_functionDefinitions.empty(), "");
248+
_return.annotation().function = m_functionDefinitions.back();
249+
_return.annotation().functionReturnParameters = m_functionDefinitions.back() ? m_functionDefinitions.back()->returnParameterList().get() : nullptr;
232250
return true;
233251
}
234252

253+
bool ReferencesResolver::visit(BinaryOperation const& _binaryOperation)
254+
{
255+
if (m_resolver.experimentalSolidity())
256+
{
257+
_binaryOperation.leftExpression().accept(*this);
258+
if (_binaryOperation.getOperator() == Token::Colon)
259+
{
260+
ScopedSaveAndRestore typeContext(m_typeContext, !m_typeContext);
261+
_binaryOperation.rightExpression().accept(*this);
262+
}
263+
else
264+
_binaryOperation.rightExpression().accept(*this);
265+
return false;
266+
}
267+
else
268+
return ASTConstVisitor::visit(_binaryOperation);
269+
}
270+
235271
void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
236272
{
237273
solAssert(nativeLocationOf(_function) == originLocationOf(_function), "");
@@ -252,6 +288,47 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
252288
{
253289
solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");
254290

291+
if (m_resolver.experimentalSolidity())
292+
{
293+
std::vector<std::string> splitName;
294+
boost::split(splitName, _identifier.name.str(), boost::is_any_of("."));
295+
solAssert(!splitName.empty());
296+
if (splitName.size() > 2)
297+
{
298+
m_errorReporter.declarationError(
299+
4955_error,
300+
nativeLocationOf(_identifier),
301+
"Unsupported identifier in inline assembly."
302+
);
303+
return;
304+
}
305+
std::string name = splitName.front();
306+
auto declarations = m_resolver.nameFromCurrentScope(name);
307+
switch (declarations.size())
308+
{
309+
case 0:
310+
if (splitName.size() > 1)
311+
m_errorReporter.declarationError(
312+
7531_error,
313+
nativeLocationOf(_identifier),
314+
"Unsupported identifier in inline assembly."
315+
);
316+
break;
317+
case 1:
318+
m_yulAnnotation->externalReferences[&_identifier].declaration = declarations.front();
319+
m_yulAnnotation->externalReferences[&_identifier].suffix = splitName.size() > 1 ? splitName.back() : "";
320+
break;
321+
default:
322+
m_errorReporter.declarationError(
323+
5387_error,
324+
nativeLocationOf(_identifier),
325+
"Multiple matching identifiers. Resolving overloaded identifiers is not supported."
326+
);
327+
break;
328+
}
329+
return;
330+
}
331+
255332
static std::set<std::string> suffixes{"slot", "offset", "length", "address", "selector"};
256333
std::string suffix;
257334
for (std::string const& s: suffixes)

Diff for: libsolidity/analysis/ReferencesResolver.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class ReferencesResolver: private ASTConstVisitor, private yul::ASTWalker
8585
bool visit(InlineAssembly const& _inlineAssembly) override;
8686
bool visit(Return const& _return) override;
8787
bool visit(UsingForDirective const& _usingFor) override;
88+
bool visit(BinaryOperation const& _binaryOperation) override;
8889

8990
void operator()(yul::FunctionDefinition const& _function) override;
9091
void operator()(yul::Identifier const& _identifier) override;
@@ -98,12 +99,13 @@ class ReferencesResolver: private ASTConstVisitor, private yul::ASTWalker
9899
langutil::ErrorReporter& m_errorReporter;
99100
NameAndTypeResolver& m_resolver;
100101
langutil::EVMVersion m_evmVersion;
101-
/// Stack of return parameters.
102-
std::vector<ParameterList const*> m_returnParameters;
102+
/// Stack of function definitions.
103+
std::vector<FunctionDefinition const*> m_functionDefinitions;
103104
bool const m_resolveInsideCode;
104105

105106
InlineAssemblyAnnotation* m_yulAnnotation = nullptr;
106107
bool m_yulInsideFunction = false;
108+
bool m_typeContext = false;
107109
};
108110

109111
}

Diff for: libsolidity/analysis/SyntaxChecker.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,9 @@ bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
443443

444444
bool SyntaxChecker::visit(FunctionDefinition const& _function)
445445
{
446-
solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), "");
446+
if (m_sourceUnit && m_sourceUnit->experimentalSolidity())
447+
// Handled in experimental::SyntaxRestrictor instead.
448+
return true;
447449

448450
if (!_function.isFree() && !_function.isConstructor() && _function.noVisibilitySpecified())
449451
{
@@ -498,3 +500,13 @@ bool SyntaxChecker::visit(StructDefinition const& _struct)
498500

499501
return true;
500502
}
503+
504+
bool SyntaxChecker::visitNode(ASTNode const& _node)
505+
{
506+
if (_node.experimentalSolidityOnly())
507+
{
508+
solAssert(m_sourceUnit);
509+
solAssert(m_sourceUnit->experimentalSolidity());
510+
}
511+
return ASTConstVisitor::visitNode(_node);
512+
}

Diff for: libsolidity/analysis/SyntaxChecker.h

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ class SyntaxChecker: private ASTConstVisitor
9797
bool visit(StructDefinition const& _struct) override;
9898
bool visit(Literal const& _literal) override;
9999

100+
bool visitNode(ASTNode const&) override;
101+
100102
langutil::ErrorReporter& m_errorReporter;
101103

102104
bool m_useYulOptimizer = false;

Diff for: libsolidity/ast/AST.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -1057,3 +1057,15 @@ TryCatchClause const* TryStatement::errorClause() const {
10571057
TryCatchClause const* TryStatement::fallbackClause() const {
10581058
return findClause(m_clauses);
10591059
}
1060+
1061+
/// Experimental Solidity nodes
1062+
/// @{
1063+
TypeClassDefinitionAnnotation& TypeClassDefinition::annotation() const
1064+
{
1065+
return initAnnotation<TypeClassDefinitionAnnotation>();
1066+
}
1067+
TypeDeclarationAnnotation& TypeDefinition::annotation() const
1068+
{
1069+
return initAnnotation<TypeDeclarationAnnotation>();
1070+
}
1071+
/// @}

0 commit comments

Comments
 (0)