Skip to content

Rollup of 3 pull requests #130444

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

Merged
merged 8 commits into from
Sep 16, 2024
Merged
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
@@ -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()?,
47 changes: 31 additions & 16 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
@@ -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,
@@ -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>,
@@ -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() => {
@@ -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,
@@ -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);
}
}
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
@@ -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 })
@@ -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()?)
@@ -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())
}
}

2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
@@ -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
49 changes: 28 additions & 21 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
@@ -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 =
@@ -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(
@@ -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
@@ -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)
})
@@ -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);
@@ -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();
@@ -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(
@@ -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,
@@ -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))
}
}

1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
@@ -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
49 changes: 25 additions & 24 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -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);
}
_ => {}
}
}
}
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`
}
21 changes: 21 additions & 0 deletions tests/ui/methods/probe-error-on-infinite-deref.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0055]: reached the recursion limit while auto-dereferencing `Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<{integer}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/probe-error-on-infinite-deref.rs:13:13
|
LL | Wrap(1).lmao();
| ^^^^ deref recursion limit reached
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`probe_error_on_infinite_deref`)

error[E0599]: no method named `lmao` found for struct `Wrap<{integer}>` in the current scope
--> $DIR/probe-error-on-infinite-deref.rs:13:13
|
LL | struct Wrap<T>(T);
| -------------- method `lmao` not found for this struct
...
LL | Wrap(1).lmao();
| ^^^^ method not found in `Wrap<{integer}>`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0055, E0599.
For more information about an error, try `rustc --explain E0055`.
12 changes: 12 additions & 0 deletions tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![feature(c_variadic)]

// Regression test that covers all 3 cases of https://github.com/rust-lang/rust/issues/130372

unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {}

pub fn main() {
unsafe {
test_va_copy();
//~^ ERROR this function takes at least 1 argument but 0 arguments were supplied
}
}
19 changes: 19 additions & 0 deletions tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0060]: this function takes at least 1 argument but 0 arguments were supplied
--> $DIR/mismatch-args-vargs-issue-130372.rs:9:9
|
LL | test_va_copy();
| ^^^^^^^^^^^^-- argument #1 of type `u64` is missing
|
note: function defined here
--> $DIR/mismatch-args-vargs-issue-130372.rs:5:22
|
LL | unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {}
| ^^^^^^^^^^^^ ------
help: provide the argument
|
LL | test_va_copy(/* u64 */);
| ~~~~~~~~~~~

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0060`.
3 changes: 3 additions & 0 deletions tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub trait Foo {
type Bar;
}
11 changes: 11 additions & 0 deletions tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//@ aux-build:foreign-trait-with-assoc.rs

extern crate foreign_trait_with_assoc;
use foreign_trait_with_assoc::Foo;

// Make sure we don't try to call `fn_arg_names` on a non-fn item.

impl Foo for Bar {}
//~^ ERROR cannot find type `Bar` in this scope

fn main() {}
14 changes: 14 additions & 0 deletions tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0412]: cannot find type `Bar` in this scope
--> $DIR/dont-compute-arg-names-for-non-fn.rs:8:14
|
LL | impl Foo for Bar {}
| ^^^
|
help: you might have meant to use the associated type
|
LL | impl Foo for Self::Bar {}
| ++++++

error: aborting due to 1 previous error

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