Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,10 +415,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
infcx.instantiate_canonical(span, &query_input.canonical);
let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value;
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
let prev_opaque_entries = self.inner.borrow_mut().opaque_types().num_entries();
MethodAutoderefStepsResult {
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
self_ty: self
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
self_ty: self.make_query_response_ignoring_pending_obligations(
var_values,
self_ty,
prev_opaque_entries,
),
self_ty_is_opaque: false,
autoderefs: 0,
from_unsafe_deref: false,
Expand Down Expand Up @@ -607,6 +611,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
}
}
let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries();

// We accept not-yet-defined opaque types in the autoderef
// chain to support recursive calls. We do error if the final
Expand Down Expand Up @@ -650,8 +655,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
.zip(reachable_via_deref)
.map(|((ty, d), reachable_via_deref)| {
let step = CandidateStep {
self_ty: infcx
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
self_ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
ty,
prev_opaque_entries,
),
self_ty_is_opaque: self_ty_is_opaque(ty),
autoderefs: d,
from_unsafe_deref: reached_raw_pointer,
Expand All @@ -671,8 +679,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
.by_ref()
.map(|(ty, d)| {
let step = CandidateStep {
self_ty: infcx
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
self_ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
ty,
prev_opaque_entries,
),
self_ty_is_opaque: self_ty_is_opaque(ty),
autoderefs: d,
from_unsafe_deref: reached_raw_pointer,
Expand All @@ -692,18 +703,27 @@ pub(crate) fn method_autoderef_steps<'tcx>(
let opt_bad_ty = match final_ty.kind() {
ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy {
reached_raw_pointer,
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
final_ty,
prev_opaque_entries,
),
}),
ty::Error(_) => Some(MethodAutoderefBadTy {
reached_raw_pointer,
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
final_ty,
prev_opaque_entries,
),
}),
ty::Array(elem_ty, _) => {
let autoderefs = steps.iter().filter(|s| s.reachable_via_deref).count() - 1;
steps.push(CandidateStep {
self_ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
Ty::new_slice(infcx.tcx, *elem_ty),
prev_opaque_entries,
),
self_ty_is_opaque: false,
autoderefs,
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ use crate::infer::canonical::{
};
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::{
DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin, TypeOutlivesConstraint,
DefineOpaqueTypes, InferCtxt, InferOk, InferResult, OpaqueTypeStorageEntries, SubregionOrigin,
TypeOutlivesConstraint,
};
use crate::traits::query::NoSolution;
use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine};
Expand Down Expand Up @@ -81,6 +82,7 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
inference_vars: CanonicalVarValues<'tcx>,
answer: T,
prev_entries: OpaqueTypeStorageEntries,
) -> Canonical<'tcx, QueryResponse<'tcx, T>>
where
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
Expand All @@ -96,7 +98,7 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner
.borrow_mut()
.opaque_type_storage
.iter_opaque_types()
.opaque_types_added_since(prev_entries)
.map(|(k, v)| (k, v.ty))
.collect()
} else {
Expand Down
39 changes: 18 additions & 21 deletions compiler/rustc_query_impl/src/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ use rustc_span::def_id::LOCAL_CRATE;

use crate::QueryConfigRestored;

/// Implements [`QueryContext`] for use by [`rustc_query_system`], since that
/// crate does not have direct access to [`TyCtxt`].
#[derive(Copy, Clone)]
pub struct QueryCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
Expand All @@ -47,15 +49,6 @@ impl<'tcx> QueryCtxt<'tcx> {
}
}

impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
type Target = TyCtxt<'tcx>;

#[inline]
fn deref(&self) -> &Self::Target {
&self.tcx
}
}

impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
type Deps = rustc_middle::dep_graph::DepsType;
type DepContext = TyCtxt<'tcx>;
Expand All @@ -69,14 +62,16 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
impl QueryContext for QueryCtxt<'_> {
#[inline]
fn jobserver_proxy(&self) -> &Proxy {
&*self.jobserver_proxy
&self.tcx.jobserver_proxy
}

#[inline]
fn next_job_id(self) -> QueryJobId {
QueryJobId(
NonZero::new(self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
.unwrap(),
NonZero::new(
self.tcx.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
)
.unwrap(),
)
}

Expand Down Expand Up @@ -113,7 +108,8 @@ impl QueryContext for QueryCtxt<'_> {
self,
prev_dep_node_index: SerializedDepNodeIndex,
) -> Option<QuerySideEffect> {
self.query_system
self.tcx
.query_system
.on_disk_cache
.as_ref()
.and_then(|c| c.load_side_effect(self.tcx, prev_dep_node_index))
Expand All @@ -122,7 +118,7 @@ impl QueryContext for QueryCtxt<'_> {
#[inline(never)]
#[cold]
fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) {
if let Some(c) = self.query_system.on_disk_cache.as_ref() {
if let Some(c) = self.tcx.query_system.on_disk_cache.as_ref() {
c.store_side_effect(dep_node_index, side_effect)
}
}
Expand All @@ -140,7 +136,9 @@ impl QueryContext for QueryCtxt<'_> {
// as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
// when accessing the `ImplicitCtxt`.
tls::with_related_context(self.tcx, move |current_icx| {
if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) {
if depth_limit
&& !self.tcx.recursion_limit().value_within_limit(current_icx.query_depth)
{
self.depth_limit_error(token);
}

Expand All @@ -161,16 +159,16 @@ impl QueryContext for QueryCtxt<'_> {
let query_map = self.collect_active_jobs(true).expect("failed to collect active queries");
let (info, depth) = job.find_dep_kind_root(query_map);

let suggested_limit = match self.recursion_limit() {
let suggested_limit = match self.tcx.recursion_limit() {
Limit(0) => Limit(2),
limit => limit * 2,
};

self.sess.dcx().emit_fatal(QueryOverflow {
self.tcx.sess.dcx().emit_fatal(QueryOverflow {
span: info.job.span,
note: QueryOverflowNote { desc: info.query.description, depth },
suggested_limit,
crate_name: self.crate_name(LOCAL_CRATE),
crate_name: self.tcx.crate_name(LOCAL_CRATE),
});
}
}
Expand Down Expand Up @@ -367,7 +365,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
Q: super::QueryConfigRestored<'tcx>,
Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
{
let _timer = qcx.profiler().generic_activity_with_arg("encode_query_results_for", query.name());
let _timer = qcx.tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name());

assert!(query.query_state(qcx).all_inactive());
let cache = query.query_cache(qcx);
Expand All @@ -389,8 +387,7 @@ pub(crate) fn query_key_hash_verify<'tcx>(
query: impl QueryConfig<QueryCtxt<'tcx>>,
qcx: QueryCtxt<'tcx>,
) {
let _timer =
qcx.profiler().generic_activity_with_arg("query_key_hash_verify_for", query.name());
let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name());

let mut map = UnordMap::default();

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ symbols! {
Into,
IntoFuture,
IntoIterator,
IntoIteratorItem,
IoBufRead,
IoLines,
IoRead,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4390,6 +4390,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
path_segment: &hir::PathSegment<'_>,
args: &[hir::Expr<'_>],
prev_ty: Ty<'_>,
err: &mut Diag<'_, G>,
) {
let tcx = self.tcx;
Expand All @@ -4403,6 +4404,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let TypeError::Sorts(expected_found) = diff else {
continue;
};
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
&& path_segment.ident.name == sym::iter
&& self.can_eq(
param_env,
Ty::new_ref(
tcx,
tcx.lifetimes.re_erased,
expected_found.found,
ty::Mutability::Not,
),
*ty,
)
&& let [] = args
{
// Used `.iter()` when `.into_iter()` was likely meant.
err.span_suggestion_verbose(
path_segment.ident.span,
format!("consider consuming the `{prev_ty}` to construct the `Iterator`"),
"into_iter".to_string(),
Applicability::MachineApplicable,
);
}
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
&& path_segment.ident.name == sym::into_iter
&& self.can_eq(
param_env,
expected_found.found,
Ty::new_ref(tcx, tcx.lifetimes.re_erased, *ty, ty::Mutability::Not),
)
&& let [] = args
{
// Used `.into_iter()` when `.iter()` was likely meant.
err.span_suggestion_verbose(
path_segment.ident.span,
format!(
"consider not consuming the `{prev_ty}` to construct the `Iterator`"
),
"iter".to_string(),
Applicability::MachineApplicable,
);
}
if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
&& path_segment.ident.name == sym::map
&& self.can_eq(param_env, expected_found.found, *ty)
Expand Down Expand Up @@ -4515,19 +4557,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
expr = rcvr_expr;
let assocs_in_this_method =
self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
);
self.look_for_iterator_item_mistakes(
&assocs_in_this_method,
typeck_results,
&type_diffs,
param_env,
path_segment,
args,
prev_ty,
err,
);
assocs.push(assocs_in_this_method);
prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
);

if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: Res::Local(hir_id), .. } = path
Expand Down
1 change: 1 addition & 0 deletions library/core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ pub trait FromIterator<A>: Sized {
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
/// The type of the elements being iterated over.
#[rustc_diagnostic_item = "IntoIteratorItem"]
#[stable(feature = "rust1", since = "1.0.0")]
type Item;

Expand Down
10 changes: 10 additions & 0 deletions tests/ui/iterators/into_iter-when-iter-was-intended.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//@ run-rustfix
//@ edition:2021
// Suggest using the right `IntoIterator` method. #68095
fn main() {
let _a = [0, 1, 2].iter().chain([3, 4, 5].iter()); //~ ERROR E0271
let _b = [0, 1, 2].into_iter().chain([3, 4, 5].into_iter()); //~ ERROR E0271
// These don't have appropriate suggestions yet.
// let c = [0, 1, 2].iter().chain([3, 4, 5]);
// let d = [0, 1, 2].iter().chain(vec![3, 4, 5]);
}
10 changes: 10 additions & 0 deletions tests/ui/iterators/into_iter-when-iter-was-intended.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//@ run-rustfix
//@ edition:2021
// Suggest using the right `IntoIterator` method. #68095
fn main() {
let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter()); //~ ERROR E0271
let _b = [0, 1, 2].into_iter().chain([3, 4, 5].iter()); //~ ERROR E0271
// These don't have appropriate suggestions yet.
// let c = [0, 1, 2].iter().chain([3, 4, 5]);
// let d = [0, 1, 2].iter().chain(vec![3, 4, 5]);
}
48 changes: 48 additions & 0 deletions tests/ui/iterators/into_iter-when-iter-was-intended.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
error[E0271]: type mismatch resolving `<IntoIter<{integer}, 3> as IntoIterator>::Item == &{integer}`
--> $DIR/into_iter-when-iter-was-intended.rs:5:37
|
LL | let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter());
| ----- ^^^^^^^^^^^^^^^^^^^^^ expected `&{integer}`, found integer
| |
| required by a bound introduced by this call
|
note: the method call chain might not have had the expected associated types
--> $DIR/into_iter-when-iter-was-intended.rs:5:47
|
LL | let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter());
| --------- ^^^^^^^^^^^ `IntoIterator::Item` is `{integer}` here
| |
| this expression has type `[{integer}; 3]`
note: required by a bound in `std::iter::Iterator::chain`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider not consuming the `[{integer}; 3]` to construct the `Iterator`
|
LL - let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter());
LL + let _a = [0, 1, 2].iter().chain([3, 4, 5].iter());
|

error[E0271]: type mismatch resolving `<Iter<'_, {integer}> as IntoIterator>::Item == {integer}`
--> $DIR/into_iter-when-iter-was-intended.rs:6:42
|
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].iter());
| ----- ^^^^^^^^^^^^^^^^ expected integer, found `&{integer}`
| |
| required by a bound introduced by this call
|
note: the method call chain might not have had the expected associated types
--> $DIR/into_iter-when-iter-was-intended.rs:6:52
|
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].iter());
| --------- ^^^^^^ `IntoIterator::Item` is `&{integer}` here
| |
| this expression has type `[{integer}; 3]`
note: required by a bound in `std::iter::Iterator::chain`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
help: consider consuming the `&[{integer}]` to construct the `Iterator`
|
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].into_iter());
| +++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0271`.
Loading
Loading