Skip to content

Commit 9ae116b

Browse files
committed
Only collect infer vars to error about in case infer vars are actually forbidden
1 parent 85bc5a7 commit 9ae116b

File tree

3 files changed

+111
-85
lines changed

3 files changed

+111
-85
lines changed

compiler/rustc_hir_analysis/src/collect.rs

+85-2
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;
@@ -531,6 +531,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
531531
fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
532532
self.tainted_by_errors.set(Some(err));
533533
}
534+
535+
fn lower_fn_sig(
536+
&self,
537+
decl: &hir::FnDecl<'tcx>,
538+
generics: Option<&hir::Generics<'_>>,
539+
hir_id: rustc_hir::HirId,
540+
hir_ty: Option<&hir::Ty<'_>>,
541+
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
542+
let tcx = self.tcx();
543+
// We proactively collect all the inferred type params to emit a single error per fn def.
544+
let mut visitor = HirPlaceholderCollector::default();
545+
let mut infer_replacements = vec![];
546+
547+
if let Some(generics) = generics {
548+
walk_generics(&mut visitor, generics);
549+
}
550+
551+
let input_tys = decl
552+
.inputs
553+
.iter()
554+
.enumerate()
555+
.map(|(i, a)| {
556+
if let hir::TyKind::Infer = a.kind {
557+
if let Some(suggested_ty) =
558+
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
559+
{
560+
infer_replacements.push((a.span, suggested_ty.to_string()));
561+
return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
562+
}
563+
}
564+
565+
// Only visit the type looking for `_` if we didn't fix the type above
566+
visitor.visit_ty(a);
567+
self.lowerer().lower_arg_ty(a, None)
568+
})
569+
.collect();
570+
571+
let output_ty = match decl.output {
572+
hir::FnRetTy::Return(output) => {
573+
if let hir::TyKind::Infer = output.kind
574+
&& let Some(suggested_ty) =
575+
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
576+
{
577+
infer_replacements.push((output.span, suggested_ty.to_string()));
578+
Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
579+
} else {
580+
visitor.visit_ty(output);
581+
self.lower_ty(output)
582+
}
583+
}
584+
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
585+
};
586+
587+
if !(visitor.0.is_empty() && infer_replacements.is_empty()) {
588+
// We check for the presence of
589+
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
590+
591+
let mut diag = crate::collect::placeholder_type_error_diag(
592+
tcx,
593+
generics,
594+
visitor.0,
595+
infer_replacements.iter().map(|(s, _)| *s).collect(),
596+
true,
597+
hir_ty,
598+
"function",
599+
);
600+
601+
if !infer_replacements.is_empty() {
602+
diag.multipart_suggestion(
603+
format!(
604+
"try replacing `_` with the type{} in the corresponding trait method signature",
605+
rustc_errors::pluralize!(infer_replacements.len()),
606+
),
607+
infer_replacements,
608+
Applicability::MachineApplicable,
609+
);
610+
}
611+
612+
self.set_tainted_by_errors(diag.emit());
613+
}
614+
615+
(input_tys, output_ty)
616+
}
534617
}
535618

536619
/// 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

+10-83
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.
@@ -2290,92 +2296,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22902296
let bound_vars = tcx.late_bound_vars(hir_id);
22912297
debug!(?bound_vars);
22922298

2293-
// We proactively collect all the inferred type params to emit a single error per fn def.
2294-
let mut visitor = HirPlaceholderCollector::default();
2295-
let mut infer_replacements = vec![];
2296-
2297-
if let Some(generics) = generics {
2298-
walk_generics(&mut visitor, generics);
2299-
}
2300-
2301-
let input_tys: Vec<_> = decl
2302-
.inputs
2303-
.iter()
2304-
.enumerate()
2305-
.map(|(i, a)| {
2306-
if let hir::TyKind::Infer = a.kind
2307-
&& !self.allow_infer()
2308-
{
2309-
if let Some(suggested_ty) =
2310-
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
2311-
{
2312-
infer_replacements.push((a.span, suggested_ty.to_string()));
2313-
return Ty::new_error_with_message(
2314-
self.tcx(),
2315-
a.span,
2316-
suggested_ty.to_string(),
2317-
);
2318-
}
2319-
}
2320-
2321-
// Only visit the type looking for `_` if we didn't fix the type above
2322-
visitor.visit_ty(a);
2323-
self.lower_arg_ty(a, None)
2324-
})
2325-
.collect();
2326-
2327-
let output_ty = match decl.output {
2328-
hir::FnRetTy::Return(output) => {
2329-
if let hir::TyKind::Infer = output.kind
2330-
&& !self.allow_infer()
2331-
&& let Some(suggested_ty) =
2332-
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
2333-
{
2334-
infer_replacements.push((output.span, suggested_ty.to_string()));
2335-
Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string())
2336-
} else {
2337-
visitor.visit_ty(output);
2338-
self.lower_ty(output)
2339-
}
2340-
}
2341-
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
2342-
};
2299+
let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty);
23432300

23442301
debug!(?output_ty);
23452302

23462303
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
23472304
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
23482305

2349-
if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
2350-
// We always collect the spans for placeholder types when evaluating `fn`s, but we
2351-
// only want to emit an error complaining about them if infer types (`_`) are not
2352-
// allowed. `allow_infer` gates this behavior. We check for the presence of
2353-
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
2354-
2355-
let mut diag = crate::collect::placeholder_type_error_diag(
2356-
tcx,
2357-
generics,
2358-
visitor.0,
2359-
infer_replacements.iter().map(|(s, _)| *s).collect(),
2360-
true,
2361-
hir_ty,
2362-
"function",
2363-
);
2364-
2365-
if !infer_replacements.is_empty() {
2366-
diag.multipart_suggestion(
2367-
format!(
2368-
"try replacing `_` with the type{} in the corresponding trait method signature",
2369-
rustc_errors::pluralize!(infer_replacements.len()),
2370-
),
2371-
infer_replacements,
2372-
Applicability::MachineApplicable,
2373-
);
2374-
}
2375-
2376-
self.set_tainted_by_errors(diag.emit());
2377-
}
2378-
23792306
// Find any late-bound regions declared in return type that do
23802307
// not appear in the arguments. These are not well-formed.
23812308
//
@@ -2405,7 +2332,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24052332
/// corresponding function in the trait that the impl implements, if it exists.
24062333
/// If arg_idx is Some, then it corresponds to an input type index, otherwise it
24072334
/// corresponds to the return type.
2408-
fn suggest_trait_fn_ty_for_impl_fn_infer(
2335+
pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer(
24092336
&self,
24102337
fn_hir_id: HirId,
24112338
arg_idx: Option<usize>,

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

+16
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)