Refactored Type Checking and Analysis Annotations
Currently, the Solidity AST is const after parsing and then annotation()-annotated by the analysis steps in CompilerStack::analyze.
However, some AST nodes and some Types have interfaces that implicitly depend on annotations. (e.g. for types: ContractType::stateVariables, StructType::nativeMembers; e.g. for AST nodes: StructDefinition::type, VariableDeclaration::hasReferenceOrMappingType, etc.).
In the past we regularly had ICEs due to such implicit dependencies. That has gotten better recently, but it's still an easy source of error.
This issue is going to get worse, once we want to move to compile-time constant expression evaluation, since this will probably entail switching multiple analysis steps to simultaneous cycle-resistant lazy-evaluation.
So we need to come up with a nicer way to:
- Make all implicit dependencies of AST node and Type interfaces explicit. If possible, even syntactically prohibit errors (as in "too early use").
- Make the relevant parts of type checking and analysis procedure robust against out-of-order lazy evaluation.
- Since array lengths should be allowed to be calculated using compile-time constant expressions, this at least entails
DeclarationTypeCheckerandTypeChecker, with implicit interactions withContractLevelChecker.
- Since array lengths should be allowed to be calculated using compile-time constant expressions, this at least entails
Prerequisite of https://github.com/ethereum/solidity/issues/13318
Given https://github.com/ethereum/solidity/issues/12932 there may be cause to do something similar even as early as the NameAndTypeResolver - this does not necessarily have to be done in one go, but it's something to keep in mind here.
This is actually superseded by https://github.com/ethereum/solidity/issues/14284 now, so we won't try to fix this in current analysis, but rather keep this in mind as an issue to consider when writing experimental analysis.
This reminds me that I recently found something that seems to solve both tracking of dependencies and out of order evaluation: Attribute grammars. The nice thing about it is that it's not inventing anything new - seems to be a well known and researched subject.
Basically it's a formalization of the simple concept where AST nodes have attributes and these attributes are calculated based on rules. Rules can depend on nodes above (producing inherited attributes) or below (producing synthesized attributes). Instead of walking the AST and setting attributes ad-hoc like we do, you have an evaluator that determines the order and executes the rules. In our case the rules could be just functions that take already computed attributes or other AST nodes (or maybe just whole nodes) as input.
Dropped in favor of #14284 .