-
Notifications
You must be signed in to change notification settings - Fork 179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enum support #770
Enum support #770
Conversation
ce2d8ea
to
0bfa687
Compare
06b77a2
to
4c3f471
Compare
3ed56cc
to
05309ef
Compare
// harness.test_function( | ||
// &mut executor, | ||
// "enum_storage", | ||
// &[uint_token(1), uint_token(2), bool_token(false)], | ||
// Some(&uint_token(100)), | ||
// ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@g-r-a-n-t
When these lines are uncommented, the test fails with the message thread 'features::enum_match' panicked at 'attempt to subtract with overflow', crates/test-utils/src/lib.rs:158:24
.
This seems to be a bug related to GasReporter
or evm::StackExecutor
, but I didn't look into it yet.
fn select_switch_merge_block( | ||
&self, | ||
cands: &IndexSet<BasicBlockId>, | ||
dests: impl Iterator<Item = BasicBlockId>, | ||
) -> Option<BasicBlockId> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This heuristic is necessary to select a switch
's exit or merge block because multiple merge block candidates cannot be distinguished only by looking at a MIR
CFG. This is because of the existence of a default
arm.
Please consider the following example and the corresponding MIR.
pub enum MyEnum {
Unit
UnitTuple()
Tuple(u32, u256)
}
pub enum Tuple2{
Value(MyEnum, MyEnum)
}
contract Foo {
pub fn bar() -> u256 {
let tup: Tuple2 = Tuple2::Value(MyEnum::Tuple(1, 2), MyEnum::UnitTuple())
let res: u256 = 0
match tup {
Tuple2::Value(MyEnum::Unit, MyEnum::Tuple(x, y)) | Tuple2::Value(MyEnum::Tuple(x, y), MyEnum::UnitTuple()) => {
res = u256(x) + y
}
_ => {
return 0
}
}
return res
}
}
Here, the "original" exit block is bb1
(or bb5
which can be seen as the exit block because it's the immediate dominator of bb1
). But only by looking at the MIR we can't distinguish it from bb7
, because both of them are in the union of dominance frontiers of bb3
, bb9
, and bb12
.
NOTE:
- This algorithm is deterministic.
- This algorithm doesn't change the semantics of the original code even if it fails to find the original exit block. But if it fails to find the original exit block, the generated yul would be much greater than the optimal code.
- If there is no
return
in all arms, this algorithm can certainly find the original exit block.
787b2e4
to
7722b04
Compare
92c9010
to
7d5d627
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Epic work! I just skimmed over the code. A lot of it is way over my head so I didn't do a deep dive. What I looked at looked great 👍 🥷
@@ -427,32 +435,34 @@ fn expr_named_thing( | |||
panic!("const type must be fixed size") | |||
} | |||
|
|||
// Check visibility of constant. | |||
if !id.is_public(context.db()) && id.module(context.db()) != context.module() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is now covered by more generalized code 👍
@@ -0,0 +1,60 @@ | |||
# `match` statement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to see the PR covering a spec update, too! ❤️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is amazing, as usual @Y-Nak. Sorry it took me so long to read through!
Add
enum
andmatch
supportOverview
Enum
enum
types can be defined using theenum
keyword.Variants can contain any number of types inside them with
tuple
like syntax.Constructors for each variant are automatically implemented, and constructors look like below.
Match
In
fe
,match
is a statement, not an expression. But this can be changed.match
syntax is almost the same as theRust
, e.g.,Currently below patterns are allowed,
_
), which matches all patterns:_
a
,b
andc
inMyEnum::Tuple(a, b, c)
true
andfalse
)MyEnum::Tuple(a, b, c)
(a, b, c)
..
), which matches the rest of the pattern. e.g.,MyEnum::Tuple(.., true)
|
). e.g.,MyEnum::Unit | MyEnum::Tuple(.., true)
Also
fe
compiler checks for exhaustiveness and reachability for pattern matching, and will emit an error when all patterns are not covered or unreachable arms are detected.Exhaustiveness check example
↓
Reachability check example
↓
Implementation details
Exhaustiveness and Reachability
The algorithm to check exhaustiveness and reachability is based on Warnings for pattern matching. The implementation is found in
analyzer/src/traversal/pattern_analysis
. In this paper, there are only three types of patterns defined.In the implementation,
SimplifiedPattern
represents them, and high-level patterns infe
are properly lowered into it in thesimplify_pattern
function in the module.match
loweringmatch
statement should be lowered into MIR, which has aswitch
instruction but can no longer represent such a high-level control flow.switch
instruction represents branching to multiple destinations according to the target(scrutinee) value, but the target value should be a primitive type(integer or boolean). So this lowering can basically be regarded as the decision tree construction. But multiple decision trees can be constructed from the samematch
statement, so we need to construct a better one. To achieve this, I implemented the method which is described in Compiling Pattern Matching to Good Decision Trees. The implementation can be found inmir/src/lower/pattern_matching
.E.g.,
↓ Decision tree construction
↓ MIR construction from the decision tree
To-Do