-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
[Compiler-v2][Feature] Index notation #13695
Conversation
⏱️ 19h 2m total CI duration on this PR
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #13695 +/- ##
========================================
Coverage 59.0% 59.0%
========================================
Files 821 821
Lines 197883 198127 +244
========================================
+ Hits 116785 117008 +223
- Misses 81098 81119 +21 ☔ View full report in Codecov by Sentry. |
bb7762d
to
de2c263
Compare
third_party/move/move-compiler-v2/tests/checking/typing/index_err.exp
Outdated
Show resolved
Hide resolved
third_party/move/move-prover/tests/sources/functional/resource_index.exp
Outdated
Show resolved
Hide resolved
ced14fb
to
2f21675
Compare
third_party/move/move-prover/tests/sources/functional/resource_index.exp
Outdated
Show resolved
Hide resolved
third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-conflicts/Move.exp
Outdated
Show resolved
Hide resolved
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 mostly good, but we need to gate this feature on language version 2. See uses of check_language_version
in exp_builder.rs
for examples. Also add a test to tests/checking-lang-v1/.
I have been using |
third_party/move/move-compiler-v2/tests/checking/typing/index_err.exp
Outdated
Show resolved
Hide resolved
third_party/move/move-compiler/tests/move_check/v2-not-supported/index.exp
Outdated
Show resolved
Hide resolved
third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-conflicts/Move.exp
Outdated
Show resolved
Hide resolved
That means you need to pass language version into the move-compiler. See how Wolfgang uses a modified parser for enums. |
I update this further because |
if let EA::Exp_::Name(m, _) = &target.value { | ||
let (is_struct, is_schema) = self.is_struct_or_schema(m); | ||
if is_struct { | ||
self.check_language_version(loc, "resource indexing", LanguageVersion::V2_0); |
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.
removed check_language_version
@@ -1774,6 +1774,13 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo | |||
let target_ty = self.fresh_type_var(); | |||
let ty = Type::Reference(ref_kind, Box::new(target_ty.clone())); | |||
let result_ty = self.check_type(&loc, &ty, expected_type, context); | |||
if let EA::Exp_::Index(target, index) = &exp.value { |
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.
removed check_language_version
call = Some(self.new_error_exp()); | ||
} | ||
} | ||
if !self.is_spec_mode() { |
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.
The logic here is that, 1) if it is a resource, create resource indexing; 2) if it is a schema, generate error; 3) otherwise, exp builder is in impl mode, we will create vector indexing (call is none for sure).
true, | ||
); | ||
if let Some(call) = index_call_opt { | ||
if !self.is_spec_mode() { |
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.
done
expected_type: &Type, | ||
context: &ErrorMessageContext, | ||
) -> ExpData { | ||
fn convert_name_to_type( |
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.
Refactored borrow_global as you suggested. I also refactored vector_borrow but due to the issue #13888, I keep vector_borrow as it is for now.
┌─ tests/checking-lang-v1/index.move:10:19 | ||
│ | ||
10 │ use 0x42::test; | ||
│ ^^^^ Unused 'use' of alias 'test'. Consider removing it |
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.
done
.env | ||
.add_diag(diag!(Syntax::SpecContextRestricted, (loc, msg))); | ||
context.env.add_diag(diag!( | ||
Syntax::SpecContextRestricted, |
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.
done
@@ -3236,6 +3243,156 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo | |||
} | |||
} | |||
|
|||
fn call_to_borrow_global( |
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.
done
) | ||
} | ||
|
||
fn call_to_vector_borrow( |
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.
done
) -> Option<ExpData> { | ||
let mut call = None; | ||
if let EA::Exp_::Name(m, _) = &target.value { | ||
let (is_struct, is_schema) = self.is_struct_or_schema(m); |
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.
refactored the code
I haven't read the whole thread, sorry if I missed the discussion before. Do I understand correctly that with this PR,
looks not much worse than
Could be instead somehow get the |
Hi @mkurnikov, you can use |
assert!(test::R[@0x1].value == true, 0); | ||
R[@0x1] = R{value: false}; | ||
assert!(test::R[@0x1].value == false, 0); | ||
} |
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.
@rahxephon89 Are those two tests roughtly equal in the operations performed? Is the R[@0x1] = R{value: false};
is sugar over (&mut R[@0x1]).value = false
?
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.
yes
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.
You can use R[@0x1].value = false
as well.
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.
Isn't that too much sugar? I honestly thought the R[@0x1] = R { value: false }
equals to the move_to(@0x1, R { value: false } )
first, before I remembered that the first parameter is a &signer
.
If the goal is to remove boilerplate from the borrow_global
and borrow_global_mut
calls, I'd suggest instead to go with
borrow_global<Res>(@0x1) -> Res[@0x1]
borrow_global_mut<Res>(@0x1) -> Res[mut @0x1]
We're special casing things anyway, and mut
without ref never used in Move, so it could be easy distinguished. And it won't mess the prioritisation rules, so you could write
Res[mut @0x1].value = false
without any parens.
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.
You can use
R[@0x1].value = false
as well.
Oh, so the compiler knows that we're trying to set a value, and automatically replaces borrow_global
with borrow_global_mut
in the translator?
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.
For standalone R[@0x1]
, it depends on whether it appears on lhs (to update the value) or rhs (to get the value). If we are going to update the value, R[@0x1] = R {value: 1}
is equivalent to *(borrow_global_mut<R>(@0x1)) = R {value: 1}
. When appearing on the rhs, R[@0x1]
is equivalent to *(borrow_global<R>(@0x1))
to get the actual value.
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.
(borrow_global_mut<R>(@0x1)) = R {value: 1}
I didn't know you can assign resources like that.
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.
Still, isn't it too much sugar though, too many implicit rules? I can understand the magic of vector v[0]
considering that it's restricted only to the items with copy
, so you can do auto-borrow/auto-deref without issues.
But here, there's a lot of magic where it's been none before.
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.
Not sure whether it is a typo but you need to use *(borrow_global_mut<R>(@0x1)) = R {value: 1}
to update the value
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.
Thanks for the feedback @mkurnikov! Any comments/suggestions on this? @wrwg @vineethk
I would suggest splitting the PR into two: one for the vector indexing, and another one for the resource access. Those are different features of the compiler v2, and from my POV the design work for them needs to happen separately. |
Lets not overcomplicate things here and create extra work for no value. The features have some relation (both based on index notation). Makes perfect sense to be in one PR. |
@@ -0,0 +1,6 @@ | |||
Move prover returns: exiting with model building errors | |||
error: not supported before language version `2.0-unstable`: resource indexing |
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.
Can you align the error message with those emitted by parser/expansion elsewhere? You have some tests which show how they look like in this PR. It mentions 'Move 2' instead of unstable.
In general it appears though the prover tests should turn on language version 2 to get rid of those errors?
@@ -168,6 +169,7 @@ fn test_runner_for_feature(path: &Path, feature: &Feature) -> datatest_stable::R | |||
|
|||
let mut error_writer = Buffer::no_color(); | |||
let result = if feature.v2 { | |||
options.language_version = Some(LanguageVersion::V2_0); |
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.
So why do we see the resource index error then?
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.
By adding this, error will only be generated for the newly added test case third_party/move/move-prover/tests/sources/functional/resource_index.move
when running prover with V1. No error is generated for V2.
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.
Updated the code so that the error disappears.
lgtm |
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.
Generally pretty good, could use a little more abstraction in the code. Helper function for function lookup.
@@ -0,0 +1,7 @@ | |||
|
|||
Diagnostics: | |||
error: resource indexing can only applied to a resource type |
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.
Are we all supposed to know that "resource type" is the same as "struct type which has key"? Or can we add that clarification?
error: resource indexing can only applied to a resource type (a struct type which has key)
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.
done
@@ -487,7 +487,7 @@ pub enum Exp_ { | |||
|
|||
Borrow(bool, Box<Exp>), | |||
ExpDotted(Box<ExpDotted>), | |||
Index(Box<Exp>, Box<Exp>), // spec only (no mutation needed right now) | |||
Index(Box<Exp>, Box<Exp>), // spec only for language version V1 |
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.
Comment would be clearer as
spec only unless language >= v2
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.
done
} else { | ||
"vector::borrow" | ||
}; | ||
// TODO: comment out because of #13888 |
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.
Is this TODO obsolete now that #13888 is closed?
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.
done
if self.had_errors { | ||
return self.new_error_exp(); | ||
} | ||
let target_str = if mutable { |
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.
Please abstract out a function get_vector_borrow(bool) -> FunctionId
or similar to make this code more intelligible. We might want to add a TODO to make a Lazy const for the 2 options so that we don't go searching in case this happens to be common.
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.
done
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
15 │ let addr = @0x1; | ||
16 │ assert!((&0x42::test::Y<0x42::test::X<bool>>[addr]).field.value == true, 1); | ||
│ ------------------------------------------- called here |
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.
It would be useful to be specific about the operation here. global resource test::Y<..> at addr borrowed here
. Or even borrow_global<0x42::test::Y<0x42::test::X<bool>>(addr)
called here. With the use of []
it's really unclear what could be "called" here.
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.
Currently we don't distinguish different storage operations: https://github.com/aptos-labs/aptos-core/blob/main/third_party/move/move-compiler-v2/src/function_checker.rs#L106. We want to revisit this later but I don't think we need to address it in this PR.
┌─ tests/checking-lang-v1/index.move:11:17 | ||
│ | ||
11 │ assert!((test::R[@0x1]).value == true, 0); | ||
│ ^^^^^^^^^^^^^^^ `_[_]` index operator in non-specification code only allowed in Move 2 |
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.
It might be nice if we could stop giving these errors after giving a few (5, maybe). The general idea has been received; the user must have run the wrong compiler or had the wrong idea.
But I guess that's pretty low priority.
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.
Repeated error messages is a general issue which definitely should to be addressed but maybe separately.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ Forge suite
|
✅ Forge suite
|
✅ Forge suite
|
Description
This PR adds the index notation syntactic sugar to Move 2 for accessing vector elements and resources.
Example use of this feature:
Example:
Example:
Type of Change
Which Components or Systems Does This Change Impact?
How Has This Been Tested?
checking-lang-v1
to show the error message when compiled using V1;Key Areas to Review
whether the rewrite logic is correctly applied to vector and resource.
Checklist