Skip to content

Commit

Permalink
Auto merge of #130444 - matthiaskrgr:rollup-onlrjva, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 3 pull requests

Successful merges:

 - #130033 (Don't call `fn_arg_names` query for non-`fn` foreign items in resolver)
 - #130282 (Do not report an excessive number of overflow errors for an ever-growing deref impl)
 - #130437 (Avoid crashing on variadic functions when producing arg-mismatch errors)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Sep 16, 2024
2 parents fd2c811 + 14ee69c commit c52c23b
Show file tree
Hide file tree
Showing 17 changed files with 196 additions and 94 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// trait or region sub-obligations. (presumably we could, but it's not
/// particularly important for diagnostics...)
pub(crate) fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
self.autoderef(DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
self.autoderef(DUMMY_SP, expr_ty).silence_errors().nth(1).and_then(|(deref_ty, _)| {
self.infcx
.type_implements_trait(
self.tcx.lang_items().deref_mut_trait()?,
Expand Down
47 changes: 31 additions & 16 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2864,13 +2864,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(expr_t, "")
};
for (found_fields, args) in
self.get_field_candidates_considering_privacy(span, ty, mod_id, id)
self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, id)
{
let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>();
let mut candidate_fields: Vec<_> = found_fields
.into_iter()
.filter_map(|candidate_field| {
self.check_for_nested_field_satisfying(
self.check_for_nested_field_satisfying_condition_for_diag(
span,
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
candidate_field,
Expand Down Expand Up @@ -2933,7 +2933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.with_span_label(field.span, "private field")
}

pub(crate) fn get_field_candidates_considering_privacy(
pub(crate) fn get_field_candidates_considering_privacy_for_diag(
&self,
span: Span,
base_ty: Ty<'tcx>,
Expand All @@ -2942,7 +2942,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);

self.autoderef(span, base_ty)
let mut autoderef = self.autoderef(span, base_ty).silence_errors();
let deref_chain: Vec<_> = autoderef.by_ref().collect();

// Don't probe if we hit the recursion limit, since it may result in
// quadratic blowup if we then try to further deref the results of this
// function. This is a best-effort method, after all.
if autoderef.reached_recursion_limit() {
return vec![];
}

deref_chain
.into_iter()
.filter_map(move |(base_t, _)| {
match base_t.kind() {
ty::Adt(base_def, args) if !base_def.is_enum() => {
Expand Down Expand Up @@ -2975,7 +2986,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

/// This method is called after we have encountered a missing field error to recursively
/// search for the field
pub(crate) fn check_for_nested_field_satisfying(
pub(crate) fn check_for_nested_field_satisfying_condition_for_diag(
&self,
span: Span,
matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
Expand All @@ -3000,20 +3011,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if matches(candidate_field, field_ty) {
return Some(field_path);
} else {
for (nested_fields, subst) in
self.get_field_candidates_considering_privacy(span, field_ty, mod_id, hir_id)
for (nested_fields, subst) in self
.get_field_candidates_considering_privacy_for_diag(
span, field_ty, mod_id, hir_id,
)
{
// recursively search fields of `candidate_field` if it's a ty::Adt
for field in nested_fields {
if let Some(field_path) = self.check_for_nested_field_satisfying(
span,
matches,
field,
subst,
field_path.clone(),
mod_id,
hir_id,
) {
if let Some(field_path) = self
.check_for_nested_field_satisfying_condition_for_diag(
span,
matches,
field,
subst,
field_path.clone(),
mod_id,
hir_id,
)
{
return Some(field_path);
}
}
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2619,9 +2619,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
is_method: bool,
) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> {
let fn_node = self.tcx.hir().get_if_local(def_id)?;
let fn_decl = fn_node.fn_decl()?;

let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
.fn_decl()?
let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_decl
.inputs
.into_iter()
.skip(if is_method { 1 } else { 0 })
Expand All @@ -2642,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
.collect();

let params: Vec<&hir::Param<'_>> = self
let mut params: Vec<&hir::Param<'_>> = self
.tcx
.hir()
.body(fn_node.body_id()?)
Expand All @@ -2651,7 +2651,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.skip(if is_method { 1 } else { 0 })
.collect();

Some(generic_params.into_iter().zip_eq(params).collect())
// The surrounding code expects variadic functions to not have a parameter representing
// the "..." parameter. This is already true of the FnDecl but not of the body params, so
// we drop it if it exists.

if fn_decl.c_variadic {
params.pop();
}

debug_assert_eq!(params.len(), generic_params.len());
Some(generic_params.into_iter().zip(params).collect())
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If our autoderef loop had reached the recursion limit,
// report an overflow error, but continue going on with
// the truncated autoderef list.
if steps.reached_recursion_limit {
if steps.reached_recursion_limit && !is_suggestion.0 {
self.probe(|_| {
let ty = &steps
.steps
Expand Down
49 changes: 28 additions & 21 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// It might seem that we can use `predicate_must_hold_modulo_regions`,
// but since a Dummy binder is used to fill in the FnOnce trait's arguments,
// type resolution always gives a "maybe" here.
if self.autoderef(span, ty).any(|(ty, _)| {
if self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
info!("check deref {:?} error", ty);
matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
}) {
return false;
}

self.autoderef(span, ty).any(|(ty, _)| {
self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
info!("check deref {:?} impl FnOnce", ty);
self.probe(|_| {
let trait_ref =
Expand All @@ -90,7 +90,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
self.autoderef(span, ty)
.silence_errors()
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
}

fn impl_into_iterator_should_be_iterator(
Expand Down Expand Up @@ -672,7 +674,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut ty_str_reported = ty_str.clone();
if let ty::Adt(_, generics) = rcvr_ty.kind() {
if generics.len() > 0 {
let mut autoderef = self.autoderef(span, rcvr_ty);
let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors();
let candidate_found = autoderef.any(|(ty, _)| {
if let ty::Adt(adt_def, _) = ty.kind() {
self.tcx
Expand Down Expand Up @@ -2237,6 +2239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity();
let target_ty = self
.autoderef(sugg_span, rcvr_ty)
.silence_errors()
.find(|(rcvr_ty, _)| {
DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty)
})
Expand Down Expand Up @@ -2352,17 +2355,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err: &mut Diag<'_>,
) -> bool {
let tcx = self.tcx;
let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
ty::Adt(def, args) if !def.is_enum() => {
let variant = &def.non_enum_variant();
tcx.find_field_index(item_name, variant).map(|index| {
let field = &variant.fields[index];
let field_ty = field.ty(tcx, args);
(field, field_ty)
})
}
_ => None,
});
let field_receiver =
self.autoderef(span, rcvr_ty).silence_errors().find_map(|(ty, _)| match ty.kind() {
ty::Adt(def, args) if !def.is_enum() => {
let variant = &def.non_enum_variant();
tcx.find_field_index(item_name, variant).map(|index| {
let field = &variant.fields[index];
let field_ty = field.ty(tcx, args);
(field, field_ty)
})
}
_ => None,
});
if let Some((field, field_ty)) = field_receiver {
let scope = tcx.parent_module_from_def_id(self.body_id);
let is_accessible = field.vis.is_accessible_from(scope, tcx);
Expand Down Expand Up @@ -2675,9 +2679,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
if let SelfSource::MethodCall(expr) = source {
let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
for (fields, args) in
self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id)
{
for (fields, args) in self.get_field_candidates_considering_privacy_for_diag(
span,
actual,
mod_id,
expr.hir_id,
) {
let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));

let lang_items = self.tcx.lang_items();
Expand All @@ -2693,7 +2700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut candidate_fields: Vec<_> = fields
.into_iter()
.filter_map(|candidate_field| {
self.check_for_nested_field_satisfying(
self.check_for_nested_field_satisfying_condition_for_diag(
span,
&|_, field_ty| {
self.lookup_probe_for_diagnostic(
Expand Down Expand Up @@ -3195,7 +3202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let SelfSource::QPath(ty) = self_source else {
return;
};
for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).skip(1) {
for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).silence_errors().skip(1) {
if let Ok(pick) = self.probe_for_name(
Mode::Path,
item_name,
Expand Down Expand Up @@ -4221,7 +4228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return is_local(rcvr_ty);
}

self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
self.autoderef(span, rcvr_ty).silence_errors().any(|(ty, _)| is_local(ty))
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2533,6 +2533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.help("the semantics of slice patterns changed recently; see issue #62254");
} else if self
.autoderef(span, expected_ty)
.silence_errors()
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
&& let Some(span) = ti.span
&& let Some(_) = ti.origin_expr
Expand Down
49 changes: 25 additions & 24 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2068,33 +2068,34 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
) {
let res = binding.res();
if filter_fn(res) {
let def_id = res.def_id();
let has_self = match def_id.as_local() {
Some(def_id) => {
self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self)
}
None => self
.r
.tcx
.fn_arg_names(def_id)
.first()
.is_some_and(|ident| ident.name == kw::SelfLower),
};
if has_self {
return Some(AssocSuggestion::MethodWithSelf { called });
} else {
match res {
Res::Def(DefKind::AssocFn, _) => {
match res {
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => {
let has_self = match def_id.as_local() {
Some(def_id) => self
.r
.delegation_fn_sigs
.get(&def_id)
.map_or(false, |sig| sig.has_self),
None => self
.r
.tcx
.fn_arg_names(def_id)
.first()
.is_some_and(|ident| ident.name == kw::SelfLower),
};
if has_self {
return Some(AssocSuggestion::MethodWithSelf { called });
} else {
return Some(AssocSuggestion::AssocFn { called });
}
Res::Def(DefKind::AssocConst, _) => {
return Some(AssocSuggestion::AssocConst);
}
Res::Def(DefKind::AssocTy, _) => {
return Some(AssocSuggestion::AssocType);
}
_ => {}
}
Res::Def(DefKind::AssocConst, _) => {
return Some(AssocSuggestion::AssocConst);
}
Res::Def(DefKind::AssocTy, _) => {
return Some(AssocSuggestion::AssocType);
}
_ => {}
}
}
}
Expand Down
9 changes: 0 additions & 9 deletions tests/crashes/130372-1.rs

This file was deleted.

11 changes: 0 additions & 11 deletions tests/crashes/130372-2.rs

This file was deleted.

7 changes: 0 additions & 7 deletions tests/crashes/130372-3.rs

This file was deleted.

16 changes: 16 additions & 0 deletions tests/ui/methods/probe-error-on-infinite-deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::ops::Deref;

// Make sure that method probe error reporting doesn't get too tangled up
// on this infinite deref impl. See #130224.

struct Wrap<T>(T);
impl<T> Deref for Wrap<T> {
type Target = Wrap<Wrap<T>>;
fn deref(&self) -> &Wrap<Wrap<T>> { todo!() }
}

fn main() {
Wrap(1).lmao();
//~^ ERROR reached the recursion limit
//~| ERROR no method named `lmao`
}
Loading

0 comments on commit c52c23b

Please sign in to comment.