-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Extend QueryStability
to handle IntoIterator
implementations
#139345
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
base: master
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
7c51ef9
to
1a2c5a3
Compare
This comment has been minimized.
This comment has been minimized.
Apologies, I was not aware of the But in your opinion, @fmease, should I keep the |
I think it would make sense to merge Note that |
I think this is good to go, @fmease. Thank you for your suggestions. EDIT: Nits are welcome, BTW. |
@fmease Are there any questions I could answer about this PR? |
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.
Sorry for the delay. I've had an initial scan. Not all of my comments are actionable unfortunately, I'll try to come back to it later.
ExpectedValues::Some(v) if !values_any_specified => { | ||
ExpectedValues::Some(v) if !values_any_specified => | ||
{ | ||
#[allow(rustc::potential_query_instability)] |
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'm torn between comment vs. no comment. I've tracked down all uses of ExpectedValues::Some
(etc.) and have learnt that we sort unstably (by &str
) everywhere before outputting the list, so all is well. Even without that context, this potential instability is transitive anyway, so a comment is probably superfluous.
(At some point in the future I might experiment with using UnordMap
for psess.check_cfg.expecteds
and UnordSet
for ExpectedValues::Some
leveraging the fact that Symbol
impls ToStableHashKey
1 allowing us to use to_sorted
which would arguably make it easier to see that there's no risk of instability)
Footnotes
-
Well, it's
KeyType
isString
, not<'call> &'call str
which may impact performance, so we might need to GAT-ifyKeyType
totype KeyType<'a>: …;
and so on ↩
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'm torn between comment vs. no comment.
The comment would be "FIXME" or something like that?
It looks like ExpectedValues
could be made to contain an FxIndexMap
(and I don't know why I didn't make that change). Should I just make that change?
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 don't know why I didn't make that change
I think I was trying to change only the data structure I had initially set out out to.
} | ||
|
||
fn check_into_iter_stability<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { | ||
let Some(into_iterator_def_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else { |
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 base/existing impl never hard-codes any specific items and looks anything labeled #[rustc_lint_query_instability]
. It would be very nice if we could continue doing so 🤔
We could of course mark trait IntoIterator
in the stdlib with #[cfg_attr(not(boostrap), rustc_lint_query_instability)]
and then look for any traits with this attr but I guess the rest of the code is quite tailored to IntoIterator
..
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.
and then look for any traits with this attr
To be clear, this would be an enhancement to the existing rustc_lint_query_instability
detection logic?
I could make this change if you think it would be best.
let Some(into_iterator_def_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else { | ||
return; | ||
}; | ||
if expr.span.from_expansion() { |
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 suppresses the lint from firing for code like this?
fn iter<T>(x: impl IntoIterator<Item = T>) = impl Iterator<Item = T> { x.into_iter() }
macro_rules! iter { ($e:expr) => { iter($e) } }
fn take(map: std::collections::HashMap<i32, i32>) { _ = iter!(map); }
I think we should fire regardless. Internal lints can be a lot more aggressive than Clippy lints. There's a reason why rustc::potential_query_instability
is marked report_in_external_macro: true
.
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.
Without that condition, an additional warning is produced here:
rust/tests/ui-fulldeps/internal-lints/query_stability.rs
Lines 22 to 23 in dfec3c0
for _ in x {} | |
//~^ ERROR using `into_iter` |
+ error: using `into_iter` can result in unstable query results
+ --> $DIR/query_stability.rs:22:14
+ |
+ LL | for _ in x {}
+ | ^
+ |
+ = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
Not linting expanded code seemed like the most straightforward way of avoiding the duplicate warnings.
Would you prefer that the lint check the context in which the expression appears, e.g., something along these lines? https://doc.rust-lang.org/beta/nightly-rustc/src/clippy_utils/higher.rs.html#34-54
compiler/rustc_lint/src/internal.rs
Outdated
if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, args) | ||
impl<'tcx> LateLintPass<'tcx> for QueryStability { | ||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { | ||
if let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) |
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 awesome if we could somehow unify typeck_results_of_method_fn
and get_callee_generic_args_and_args
.
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 in commit ae437dd.
This comment has been minimized.
This comment has been minimized.
2a4d30f
to
ae437dd
Compare
|
Apologies. The force push was to remove an unnecessary change I included accidentally. EDIT: Note that another commit (085312b re #139345 (comment)) has been since been pushed. |
Hi @fmease, it looks like the author has responded to all of your review feedback so this is ready for another look when you get a chance. Thanks! |
r? rust-lang/compiler |
ExpectedValues::Some(v) if !values_any_specified => | ||
{ |
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.
ExpectedValues::Some(v) if !values_any_specified => | |
{ | |
ExpectedValues::Some(v) if !values_any_specified => { |
why does this formatting change happen?
@@ -3934,12 +3934,14 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | |||
// Move up the non-overlapping bindings to the or-pattern. | |||
// Existing bindings just get "merged". | |||
let collected = bindings.pop().unwrap().1; | |||
#[allow(rustc::potential_query_instability)] // FIXME |
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.
How much effort is it to change bindings
to &mut SmallVec<[(PatBoundCtx, UnordSet<Ident>); 1]>
?
use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy}; | ||
use rustc_hir::{Expr, ExprKind, HirId}; | ||
use rustc_middle::ty::{ | ||
self, ClauseKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty as MiddleTy, |
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.
self, ClauseKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty as MiddleTy, | |
self, ClauseKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, |
please avoid importing hir::Ty
instead. We generally always uses Ty
for ty::Ty
else { | ||
return; | ||
}; | ||
let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder(); |
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 feels fairly iffy to me 🤔 we're doing this check in the context of the called functions definition (we're using instantiate_identity
and I feel like we shouldn't 🤔)
what we could do instead is:
- get the instantiated predicates of the function
predicates_of(callee_def_id).instantiate(generic_args)
- search for a predicate
wahtever: IntoIterator
predicate - resolve the instance for that predicat eand look for the
rustc_lint_query_instability
attr - if so, lint.
- i personally wouldn't do any manually try to match function arg to predicate lookup, but instead print the type whose
IntoIterator
impl is not stable
my general perspective if that such sort of manual lookup is fairly undesirable and has a fairly high cost, so even if an alternative has slightly worse output, it's still worth it for the sake of maintainability
This PR extends the
rustc::potential_query_instability
lint to check values passed asIntoIterator
implementations.Full disclosure: I want the lint to warn about this line (please see #138871 for why):
rust/src/librustdoc/json/mod.rs
Line 261 in aa8f0fd
However, the lint warns about several other lines as well.
Final note: the functions
get_callee_generic_args_and_args
andget_input_traits_and_projections
were copied directly from Clippy's source code.