Skip to content

Commit 6a2e15a

Browse files
committed
Only collect infer vars to error about in case infer vars are actually forbidden
1 parent abd308b commit 6a2e15a

File tree

3 files changed

+111
-85
lines changed

3 files changed

+111
-85
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ use rustc_data_structures::captures::Captures;
1919
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
2020
use rustc_data_structures::unord::UnordMap;
2121
use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
22-
use rustc_hir as hir;
2322
use rustc_hir::def::DefKind;
2423
use rustc_hir::def_id::{DefId, LocalDefId};
25-
use rustc_hir::intravisit::{self, Visitor};
24+
use rustc_hir::intravisit::{self, walk_generics, Visitor};
25+
use rustc_hir::{self as hir};
2626
use rustc_hir::{GenericParamKind, Node};
2727
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
2828
use rustc_infer::traits::ObligationCause;
@@ -529,6 +529,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
529529
fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
530530
self.tainted_by_errors.set(Some(err));
531531
}
532+
533+
fn lower_fn_sig(
534+
&self,
535+
decl: &hir::FnDecl<'tcx>,
536+
generics: Option<&hir::Generics<'_>>,
537+
hir_id: rustc_hir::HirId,
538+
hir_ty: Option<&hir::Ty<'_>>,
539+
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
540+
let tcx = self.tcx();
541+
// We proactively collect all the inferred type params to emit a single error per fn def.
542+
let mut visitor = HirPlaceholderCollector::default();
543+
let mut infer_replacements = vec![];
544+
545+
if let Some(generics) = generics {
546+
walk_generics(&mut visitor, generics);
547+
}
548+
549+
let input_tys = decl
550+
.inputs
551+
.iter()
552+
.enumerate()
553+
.map(|(i, a)| {
554+
if let hir::TyKind::Infer = a.kind {
555+
if let Some(suggested_ty) =
556+
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
557+
{
558+
infer_replacements.push((a.span, suggested_ty.to_string()));
559+
return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
560+
}
561+
}
562+
563+
// Only visit the type looking for `_` if we didn't fix the type above
564+
visitor.visit_ty(a);
565+
self.lowerer().lower_arg_ty(a, None)
566+
})
567+
.collect();
568+
569+
let output_ty = match decl.output {
570+
hir::FnRetTy::Return(output) => {
571+
if let hir::TyKind::Infer = output.kind
572+
&& let Some(suggested_ty) =
573+
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
574+
{
575+
infer_replacements.push((output.span, suggested_ty.to_string()));
576+
Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
577+
} else {
578+
visitor.visit_ty(output);
579+
self.lower_ty(output)
580+
}
581+
}
582+
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
583+
};
584+
585+
if !(visitor.0.is_empty() && infer_replacements.is_empty()) {
586+
// We check for the presence of
587+
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
588+
589+
let mut diag = crate::collect::placeholder_type_error_diag(
590+
tcx,
591+
generics,
592+
visitor.0,
593+
infer_replacements.iter().map(|(s, _)| *s).collect(),
594+
true,
595+
hir_ty,
596+
"function",
597+
);
598+
599+
if !infer_replacements.is_empty() {
600+
diag.multipart_suggestion(
601+
format!(
602+
"try replacing `_` with the type{} in the corresponding trait method signature",
603+
rustc_errors::pluralize!(infer_replacements.len()),
604+
),
605+
infer_replacements,
606+
Applicability::MachineApplicable,
607+
);
608+
}
609+
610+
self.set_tainted_by_errors(diag.emit());
611+
}
612+
613+
(input_tys, output_ty)
614+
}
532615
}
533616

534617
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 10 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ mod lint;
2020
mod object_safety;
2121

2222
use crate::bounds::Bounds;
23-
use crate::collect::HirPlaceholderCollector;
2423
use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
2524
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
2625
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
@@ -34,7 +33,6 @@ use rustc_errors::{
3433
use rustc_hir as hir;
3534
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
3635
use rustc_hir::def_id::{DefId, LocalDefId};
37-
use rustc_hir::intravisit::{walk_generics, Visitor as _};
3836
use rustc_hir::{GenericArg, GenericArgs, HirId};
3937
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
4038
use rustc_infer::traits::ObligationCause;
@@ -157,6 +155,14 @@ pub trait HirTyLowerer<'tcx> {
157155
poly_trait_ref: ty::PolyTraitRef<'tcx>,
158156
) -> Ty<'tcx>;
159157

158+
fn lower_fn_sig(
159+
&self,
160+
decl: &hir::FnDecl<'tcx>,
161+
generics: Option<&hir::Generics<'_>>,
162+
hir_id: HirId,
163+
hir_ty: Option<&hir::Ty<'_>>,
164+
) -> (Vec<Ty<'tcx>>, Ty<'tcx>);
165+
160166
/// Returns `AdtDef` if `ty` is an ADT.
161167
///
162168
/// Note that `ty` might be a alias type that needs normalization.
@@ -2306,92 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23062312
let bound_vars = tcx.late_bound_vars(hir_id);
23072313
debug!(?bound_vars);
23082314

2309-
// We proactively collect all the inferred type params to emit a single error per fn def.
2310-
let mut visitor = HirPlaceholderCollector::default();
2311-
let mut infer_replacements = vec![];
2312-
2313-
if let Some(generics) = generics {
2314-
walk_generics(&mut visitor, generics);
2315-
}
2316-
2317-
let input_tys: Vec<_> = decl
2318-
.inputs
2319-
.iter()
2320-
.enumerate()
2321-
.map(|(i, a)| {
2322-
if let hir::TyKind::Infer = a.kind
2323-
&& !self.allow_infer()
2324-
{
2325-
if let Some(suggested_ty) =
2326-
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
2327-
{
2328-
infer_replacements.push((a.span, suggested_ty.to_string()));
2329-
return Ty::new_error_with_message(
2330-
self.tcx(),
2331-
a.span,
2332-
suggested_ty.to_string(),
2333-
);
2334-
}
2335-
}
2336-
2337-
// Only visit the type looking for `_` if we didn't fix the type above
2338-
visitor.visit_ty(a);
2339-
self.lower_arg_ty(a, None)
2340-
})
2341-
.collect();
2342-
2343-
let output_ty = match decl.output {
2344-
hir::FnRetTy::Return(output) => {
2345-
if let hir::TyKind::Infer = output.kind
2346-
&& !self.allow_infer()
2347-
&& let Some(suggested_ty) =
2348-
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
2349-
{
2350-
infer_replacements.push((output.span, suggested_ty.to_string()));
2351-
Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string())
2352-
} else {
2353-
visitor.visit_ty(output);
2354-
self.lower_ty(output)
2355-
}
2356-
}
2357-
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
2358-
};
2315+
let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty);
23592316

23602317
debug!(?output_ty);
23612318

23622319
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
23632320
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
23642321

2365-
if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
2366-
// We always collect the spans for placeholder types when evaluating `fn`s, but we
2367-
// only want to emit an error complaining about them if infer types (`_`) are not
2368-
// allowed. `allow_infer` gates this behavior. We check for the presence of
2369-
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
2370-
2371-
let mut diag = crate::collect::placeholder_type_error_diag(
2372-
tcx,
2373-
generics,
2374-
visitor.0,
2375-
infer_replacements.iter().map(|(s, _)| *s).collect(),
2376-
true,
2377-
hir_ty,
2378-
"function",
2379-
);
2380-
2381-
if !infer_replacements.is_empty() {
2382-
diag.multipart_suggestion(
2383-
format!(
2384-
"try replacing `_` with the type{} in the corresponding trait method signature",
2385-
rustc_errors::pluralize!(infer_replacements.len()),
2386-
),
2387-
infer_replacements,
2388-
Applicability::MachineApplicable,
2389-
);
2390-
}
2391-
2392-
self.set_tainted_by_errors(diag.emit());
2393-
}
2394-
23952322
// Find any late-bound regions declared in return type that do
23962323
// not appear in the arguments. These are not well-formed.
23972324
//
@@ -2421,7 +2348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24212348
/// corresponding function in the trait that the impl implements, if it exists.
24222349
/// If arg_idx is Some, then it corresponds to an input type index, otherwise it
24232350
/// corresponds to the return type.
2424-
fn suggest_trait_fn_ty_for_impl_fn_infer(
2351+
pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer(
24252352
&self,
24262353
fn_hir_id: HirId,
24272354
arg_idx: Option<usize>,

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,22 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
355355
fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
356356
self.infcx.set_tainted_by_errors(e)
357357
}
358+
359+
fn lower_fn_sig(
360+
&self,
361+
decl: &rustc_hir::FnDecl<'tcx>,
362+
_generics: Option<&rustc_hir::Generics<'_>>,
363+
_hir_id: rustc_hir::HirId,
364+
_hir_ty: Option<&hir::Ty<'_>>,
365+
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
366+
let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect();
367+
368+
let output_ty = match decl.output {
369+
hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
370+
hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
371+
};
372+
(input_tys, output_ty)
373+
}
358374
}
359375

360376
/// The `ty` representation of a user-provided type. Depending on the use-site

0 commit comments

Comments
 (0)