Skip to content
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

Tuple support. #352

Merged
merged 1 commit into from
Apr 28, 2021
Merged

Tuple support. #352

merged 1 commit into from
Apr 28, 2021

Conversation

g-r-a-n-t
Copy link
Member

@g-r-a-n-t g-r-a-n-t commented Mar 31, 2021

To support tuples, we need the following lowerings:

1.) New struct definitions need to be added for each tuple that is used in the module.

For example, if (u256, bool) is used somewhere in a module, we must add the following struct definition to the module:

struct TUPLE_U256_BOOL:
  item0: u256
  item1: bool

2.) Tuple type descriptions need to be mapped to struct type descriptions.

my_tuple: (u256, bool) -> my_tuple: TUPLE_U256_BOOL

3.) Tuple constructions need to be mapped to struct constructions

(42, true) -> TUPLE_U256_BOOL(item0=42, item1=true)

bonus: Tuple deconstruction can be mapped to multiple assignments.

(foo, bar): (u256, bool) = my_tuple

->

foo: u256 = my_tuple.item0
bar: bool = my_tuple.item1

Included in this PR:

  • Lowerings 1, 2, and 3 mentioned above
  • Testing for lowered source files (added some coverage for aug assigns too)
  • Refactoring around "safe names". Basically, I'm trying to figure out how we should go about creating unique identifiers for generated code. In this PR, we're using the names provided by the SafeNames trait to to generate identifiers for the tuple structs. These names may conflict with user defined types, which is something that needs to be addressed.

One thing to note is that empty tuples are not lowered, since we don't have zero-sized structs. It's not a big deal, but it would be nice to have all tuple branches marked as unimplemented in the Yul codegen pass.

To-Do

  • Write an issue for tuple destructuring.
  • Write an issue for name collisions as mentioned in the 3rd bullet.
  • Add entry to the release notes (may forgo for trivial changes)
  • Clean up commit history

@g-r-a-n-t g-r-a-n-t force-pushed the tuple-support branch 2 times, most recently from 6a6bb93 to 3fe10c6 Compare April 22, 2021 19:05
analyzer/src/lib.rs Outdated Show resolved Hide resolved
analyzer/src/lib.rs Show resolved Hide resolved
analyzer/src/lib.rs Outdated Show resolved Hide resolved
analyzer/src/namespace/types.rs Outdated Show resolved Hide resolved
analyzer/src/namespace/types.rs Outdated Show resolved Hide resolved
compiler/src/lowering/mappers/module.rs Outdated Show resolved Hide resolved
compiler/src/lowering/mappers/module.rs Outdated Show resolved Hide resolved
compiler/tests/lowering/main.rs Show resolved Hide resolved
compiler/tests/lowering/main.rs Outdated Show resolved Hide resolved
compiler/tests/stress.rs Outdated Show resolved Hide resolved
@codecov-commenter
Copy link

codecov-commenter commented Apr 23, 2021

Codecov Report

Merging #352 (71f32a1) into master (e64b98e) will increase coverage by 0.33%.
The diff coverage is 89.12%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #352      +/-   ##
==========================================
+ Coverage   82.80%   83.14%   +0.33%     
==========================================
  Files          62       64       +2     
  Lines        3862     3980     +118     
==========================================
+ Hits         3198     3309     +111     
- Misses        664      671       +7     
Impacted Files Coverage Δ
analyzer/src/traversal/declarations.rs 96.66% <ø> (ø)
analyzer/src/traversal/expressions.rs 92.07% <ø> (ø)
compiler/src/yul/operations/abi.rs 94.02% <ø> (ø)
compiler/src/yul/operations/data.rs 100.00% <ø> (ø)
compiler/src/yul/runtime/functions/abi.rs 96.25% <ø> (ø)
compiler/src/abi/elements.rs 84.61% <60.00%> (-2.43%) ⬇️
analyzer/src/namespace/types.rs 87.22% <84.10%> (+1.09%) ⬆️
analyzer/src/lib.rs 77.43% <100.00%> (+1.78%) ⬆️
analyzer/src/namespace/events.rs 100.00% <100.00%> (ø)
analyzer/src/namespace/scopes.rs 95.43% <100.00%> (+0.02%) ⬆️
... and 23 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e64b98e...71f32a1. Read the comment docs.

@g-r-a-n-t g-r-a-n-t force-pushed the tuple-support branch 2 times, most recently from 76ec902 to eeb4e42 Compare April 27, 2021 17:19
@@ -82,30 +82,24 @@ pub struct AbiComponent {
}
Copy link
Member Author

@g-r-a-n-t g-r-a-n-t Apr 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I grouped trait implementations together in this file, so there is some noise.


/// The ABI type of a Fe type.
fn abi_type(&self) -> AbiType;
}

/// Names that can be used to build identifiers.
pub trait SafeNames {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new trait

Copy link
Collaborator

@cburgdorf cburgdorf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heroic effort! ⚔️ 👷
Left a few comments inline but just tiny suggestions. The most important thing I think is opening issues for a few things left and right.

@@ -297,6 +318,8 @@ impl Context {
contracts: HashMap::new(),
calls: HashMap::new(),
events: HashMap::new(),
type_descs: HashMap::new(),
module: None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider using ModuleAttributes instead of Option<ModuleAttributes> and using ModuleAttributes::new() which would in turn initialize with an empty HashMap and BTreeSet. This would feel slightly more symmetric with the rest of the Context and eliminate checking for Some(_) down the road. But it may make other things trickier so I'm just curious if you considered it and deliberately went for this design.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I went for initially, but then realized fe::Module isn't wrapped in a node and therefore doesn't have a nodeId.

analyzer/src/traversal/expressions.rs Outdated Show resolved Hide resolved
@@ -670,6 +711,19 @@ fn expr_call_value_attribute(
Location::Memory,
))
}
Type::Tuple(tuple) => {
if value_attributes.final_location() != Location::Memory {
todo!("encode tuple from storage")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to create an issue for this.

compiler/src/lowering/mappers/module.rs Outdated Show resolved Hide resolved
let typ = context.get_type_desc(&desc).expect("missing attributes");

match typ {
Type::Tuple(tuple) if !tuple.is_empty() => {
Copy link
Collaborator

@cburgdorf cburgdorf Apr 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should allow to define zero sized structs probably just as struct Something. That's struct followed by the name and then not followed by a :. Rust has support for empty structs, too so we are in good company.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not saying that has to be in this PR so. But worth creating an issue for.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I was thinking too 👍

num2=self.reserve1,
num3=self.block_timestamp_last
)
pub def get_reserves() -> (u256, u256, u256):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super cool to see it in action and leading to this code cleanup 👍

@@ -0,0 +1,43 @@
contract Foo:
my_sto_tuple: (u256, i32)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's this todo!("encode tuple from storage") in the analyzer...what exactly is it doesn't yet work with tuples in storage yet. Is it that we can not yet move an entire tuple from storage to memory?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now someone would need to do self.my_sto_tuple.to_mem().abi_encode() instead of self.my_sto_tuple.abi_encode(). It's a low priority todo imo, we might not event want to support encoding values from storage.

@@ -0,0 +1,68 @@
struct tuple_u256_bool:
Copy link
Collaborator

@cburgdorf cburgdorf Apr 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the naming collisions. We could suffix all of them with an uuid and call it a day (e.g. tuple_u256_bool_ce6819ea_e0a1_4af2_92f5_7d3be21437d1). Alternatively I guess we could try to generate the most human readable name possible (so, tuple_u256_bool) unless we detect that the user has also used the same name in which case we just append something like _1. In any case, we should create an issue for that as it should have a high priority.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, super cool that we have these lowering tests now!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to have a solution that does not involve checking to see if a name is already take. Something to discuss in the issue once it's written..


pub def bing():
foo: tuple_address_address_u16_i32_bool = tuple_address_address_u16_i32_bool(
item0=address(0),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random fact, C# also exposes tuple items as item0, item1 etc (just with a capitalized I) so we are in good company.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Correct decision for sure 😆

@g-r-a-n-t g-r-a-n-t merged commit 5412b97 into ethereum:master Apr 28, 2021
@sbillig sbillig mentioned this pull request May 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants