-
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] Check recursive definition for constants #14741
Conversation
⏱️ 6h 32m total CI duration on this PR
🚨 1 job on the last run was significantly faster/slower than expected
|
This stack of pull requests is managed by Graphite. Learn more about stacking. Join @rahxephon89 and the rest of your teammates on Graphite |
4da136c
to
63626eb
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #14741 +/- ##
===========================================
- Coverage 72.7% 59.9% -12.9%
===========================================
Files 2397 852 -1545
Lines 482334 207601 -274733
===========================================
- Hits 350819 124363 -226456
+ Misses 131515 83238 -48277
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
impl Exp_ { | ||
/// Get all names from an expression | ||
/// only recursively check on expression types supported in constant definition. | ||
pub fn get_names_for_const_exp(&self) -> HashSet<Name> { |
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.
Could we please use a BTreeSet
instead? Looks like we iterate through this hashset later, and such iteration order is not deterministic.
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.
pub fn get_names_for_const_exp(&self) -> HashSet<Name> { | |
pub fn get_names_from_const_exp(&self) -> HashSet<Name> { |
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
63626eb
to
7b47bab
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.
Assuming this is only called in the context of const expressions, would it be better to have an internal error/ICE 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.
If you decide to go the route of adding an error, then the Block
case has some silently skipped conditions 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.
I moved the function internally into analyze_constant
to make sure it will not be called by other functions. Then, all other cases will be handled by is_valid_for_constant
.
impl Exp_ { | ||
/// Get all names from an expression | ||
/// only recursively check on expression types supported in constant definition. | ||
pub fn get_names_for_const_exp(&self) -> HashSet<Name> { |
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.
pub fn get_names_for_const_exp(&self) -> HashSet<Name> { | |
pub fn get_names_from_const_exp(&self) -> HashSet<Name> { |
names.insert(*access.value.get_name()); | ||
}, | ||
Self::Call(_, _, _, exp_vec) | Self::Vector(_, _, exp_vec) => { | ||
let _ = exp_vec.value.iter().map(&mut add_names); |
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 for_each()
perhaps better suited 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.
done
key: &PA::ConstantName, | ||
constant_map: &UniqueMap<PA::ConstantName, EA::Constant>, | ||
visiting: &mut HashSet<PA::ConstantName>, | ||
visited: &mut HashSet<PA::ConstantName>, |
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.
Might be good to add a brief note about params like visiting
, visited
.
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.parent.const_table.contains_key(&qsym) { | ||
continue; | ||
} | ||
self.check_language_version( |
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.
Do we have this feature mentioned in the Move book (i.e., since 2.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.
no, in the move book we are still saying it is not supported.
LanguageVersion::V2_0, | ||
); | ||
if visited.contains(&const_name) { | ||
return; |
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.
Why would do this early return? Should we not continue instead, and see if the other names lead to errors? For example:
const X: u64 = 1;
const Y: u64 = X + Y;
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
self.parent | ||
.env | ||
.error(&loc, "Found recursive definition of a constant"); | ||
return; |
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.
Perhaps add a comment that we return early here before exploring other names to limit such errors to one per const definition?
error: Found recursive definition of a constant | ||
┌─ tests/checking/typing/recursive_constant.move:4:5 | ||
│ | ||
4 │ const Y: u64 = X; |
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.
Could we add some more tests for the recursive check?
- self recursion
- recursion with a more complicated cycle involving expressions
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
}, | ||
Self::Block(seq) => { | ||
for s in seq.iter() { | ||
if let SequenceItem_::Seq(exp) = &s.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.
Interesting that we allow sequences in const defintions. Is there any use case for this? Should it be disallowed?
Can this sequence contain local bindings that could clash with the const names?
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.
Sequence such a { 3 + 8; Z }
is allowed but the one with local bindings will be translated into a Block expression, which is not allowed according to here.
79a5bcf
to
794ea3d
Compare
@@ -328,9 +328,17 @@ impl<'env> ConstantFolder<'env> { | |||
O::Neq => val0 | |||
.equivalent(val1) | |||
.map(|equivalence| V(id, Bool(!equivalence)).into_exp()), | |||
_ => self.constant_folding_error(id, |_| { |
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 error can be raised when a constant is not evaluated. Thus modify the error msg 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.
LGTM, left minor comments.
self.parent.env.diag_with_labels( | ||
Severity::Error, | ||
&loc, | ||
&format!("Found recursive definition of a constant {}", 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.
&format!("Found recursive definition of a constant {}", key), | |
&format!("Found recursive definition of a constant `{}`", 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.
nit: Also may be add: "; cycle formed by definitions below" or similar.
visiting[index..] | ||
.to_vec() | ||
.iter() | ||
.map(|(name, loc)| (loc.clone(), format!("{} is defined", name))) |
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.
.map(|(name, loc)| (loc.clone(), format!("{} is defined", name))) | |
.map(|(name, loc)| (loc.clone(), format!("`{}` is defined here", name))) |
794ea3d
to
40be542
Compare
third_party/move/move-compiler-v2/tests/checking-lang-v1/v1-typing/refer_other_constants.exp
Outdated
Show resolved
Hide resolved
third_party/move/move-compiler-v2/tests/checking/typing/recursive_constant.move
Show resolved
Hide resolved
40be542
to
a9e5f45
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.
LGTM
a9e5f45
to
f5f1d26
Compare
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.
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
close #14648
Type of Change
Which Components or Systems Does This Change Impact?
How Has This Been Tested?
checking-lang-v1
Key Areas to Review
Checklist