Skip to content

Commit 6a9db39

Browse files
authored
Rollup merge of rust-lang#98761 - lcnr:need_type_info-cont, r=estebank
more `need_type_info` improvements this now deals with macros in suggestions and the source cost computation does what I want for `channel` 🎉 r? ``@estebank``
2 parents d26ccf7 + f475e88 commit 6a9db39

File tree

14 files changed

+167
-90
lines changed

14 files changed

+167
-90
lines changed

compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

+76-31
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
315315
body_id: Option<hir::BodyId>,
316316
failure_span: Span,
317317
arg: GenericArg<'tcx>,
318-
// FIXME(#94483): Either use this or remove it.
319-
_impl_candidates: Vec<ty::TraitRef<'tcx>>,
320318
error_code: TypeAnnotationNeeded,
321319
should_label_span: bool,
322320
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
@@ -534,6 +532,23 @@ enum InferSourceKind<'tcx> {
534532
},
535533
}
536534

535+
impl<'tcx> InferSource<'tcx> {
536+
fn from_expansion(&self) -> bool {
537+
let source_from_expansion = match self.kind {
538+
InferSourceKind::LetBinding { insert_span, .. }
539+
| InferSourceKind::ClosureArg { insert_span, .. }
540+
| InferSourceKind::GenericArg { insert_span, .. } => insert_span.from_expansion(),
541+
InferSourceKind::FullyQualifiedMethodCall { receiver, .. } => {
542+
receiver.span.from_expansion()
543+
}
544+
InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => {
545+
data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion)
546+
}
547+
};
548+
source_from_expansion || self.span.from_expansion()
549+
}
550+
}
551+
537552
impl<'tcx> InferSourceKind<'tcx> {
538553
fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
539554
match *self {
@@ -604,57 +619,85 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
604619
/// Sources with a small cost are prefer and should result
605620
/// in a clearer and idiomatic suggestion.
606621
fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
607-
let tcx = self.infcx.tcx;
608-
609-
fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
610-
match arg.unpack() {
611-
GenericArgKind::Lifetime(_) => 0, // erased
612-
GenericArgKind::Type(ty) => ty_cost(ty),
613-
GenericArgKind::Const(_) => 3, // some non-zero value
614-
}
622+
#[derive(Clone, Copy)]
623+
struct CostCtxt<'tcx> {
624+
tcx: TyCtxt<'tcx>,
615625
}
616-
fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
617-
match ty.kind() {
618-
ty::Closure(..) => 100,
619-
ty::FnDef(..) => 20,
620-
ty::FnPtr(..) => 10,
621-
ty::Infer(..) => 0,
622-
_ => 1,
626+
impl<'tcx> CostCtxt<'tcx> {
627+
fn arg_cost(self, arg: GenericArg<'tcx>) -> usize {
628+
match arg.unpack() {
629+
GenericArgKind::Lifetime(_) => 0, // erased
630+
GenericArgKind::Type(ty) => self.ty_cost(ty),
631+
GenericArgKind::Const(_) => 3, // some non-zero value
632+
}
633+
}
634+
fn ty_cost(self, ty: Ty<'tcx>) -> usize {
635+
match *ty.kind() {
636+
ty::Closure(..) => 1000,
637+
ty::FnDef(..) => 150,
638+
ty::FnPtr(..) => 30,
639+
ty::Adt(def, substs) => {
640+
5 + self
641+
.tcx
642+
.generics_of(def.did())
643+
.own_substs_no_defaults(self.tcx, substs)
644+
.iter()
645+
.map(|&arg| self.arg_cost(arg))
646+
.sum::<usize>()
647+
}
648+
ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(),
649+
ty::Ref(_, ty, _) => 2 + self.ty_cost(ty),
650+
ty::Infer(..) => 0,
651+
_ => 1,
652+
}
623653
}
624654
}
625655

626656
// The sources are listed in order of preference here.
627-
match source.kind {
628-
InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
629-
InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
657+
let tcx = self.infcx.tcx;
658+
let ctx = CostCtxt { tcx };
659+
let base_cost = match source.kind {
660+
InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
661+
InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty),
630662
InferSourceKind::GenericArg { def_id, generic_args, .. } => {
631663
let variant_cost = match tcx.def_kind(def_id) {
632-
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
633-
_ => 12,
664+
// `None::<u32>` and friends are ugly.
665+
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15,
666+
_ => 10,
634667
};
635-
variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
668+
variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>()
636669
}
637670
InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
638-
20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
671+
20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>()
639672
}
640673
InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
641-
30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
674+
30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
642675
}
643-
}
676+
};
677+
678+
let suggestion_may_apply = if source.from_expansion() { 10000 } else { 0 };
679+
680+
base_cost + suggestion_may_apply
644681
}
645682

646683
/// Uses `fn source_cost` to determine whether this inference source is preferable to
647684
/// previous sources. We generally prefer earlier sources.
648685
#[instrument(level = "debug", skip(self))]
649686
fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
650687
let cost = self.source_cost(&new_source) + self.attempt;
688+
debug!(?cost);
651689
self.attempt += 1;
652690
if cost < self.infer_source_cost {
653691
self.infer_source_cost = cost;
654692
self.infer_source = Some(new_source);
655693
}
656694
}
657695

696+
fn node_substs_opt(&self, hir_id: HirId) -> Option<SubstsRef<'tcx>> {
697+
let substs = self.typeck_results.node_substs_opt(hir_id);
698+
self.infcx.resolve_vars_if_possible(substs)
699+
}
700+
658701
fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
659702
let ty = self.typeck_results.node_type_opt(hir_id);
660703
self.infcx.resolve_vars_if_possible(ty)
@@ -737,7 +780,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
737780
let tcx = self.infcx.tcx;
738781
match expr.kind {
739782
hir::ExprKind::Path(ref path) => {
740-
if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) {
783+
if let Some(substs) = self.node_substs_opt(expr.hir_id) {
741784
return self.path_inferred_subst_iter(expr.hir_id, substs, path);
742785
}
743786
}
@@ -765,7 +808,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
765808
if generics.has_impl_trait() {
766809
None?
767810
}
768-
let substs = self.typeck_results.node_substs_opt(expr.hir_id)?;
811+
let substs = self.node_substs_opt(expr.hir_id)?;
769812
let span = tcx.hir().span(segment.hir_id?);
770813
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
771814
InsertableGenericArgs {
@@ -980,8 +1023,10 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
9801023
debug!(?args);
9811024
let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args;
9821025
let generics = tcx.generics_of(generics_def_id);
983-
if let Some(argument_index) =
984-
generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg))
1026+
if let Some(argument_index) = generics
1027+
.own_substs(substs)
1028+
.iter()
1029+
.position(|&arg| self.generic_arg_contains_target(arg))
9851030
{
9861031
let substs = self.infcx.resolve_vars_if_possible(substs);
9871032
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
@@ -1037,7 +1082,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
10371082
.any(|generics| generics.has_impl_trait())
10381083
};
10391084
if let ExprKind::MethodCall(path, args, span) = expr.kind
1040-
&& let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id)
1085+
&& let Some(substs) = self.node_substs_opt(expr.hir_id)
10411086
&& substs.iter().any(|arg| self.generic_arg_contains_target(arg))
10421087
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
10431088
&& self.infcx.tcx.trait_of_item(def_id).is_some()

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+3-24
Original file line numberDiff line numberDiff line change
@@ -1980,7 +1980,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
19801980
body_id,
19811981
span,
19821982
trait_ref.self_ty().skip_binder().into(),
1983-
vec![],
19841983
ErrorCode::E0282,
19851984
false,
19861985
)
@@ -2005,19 +2004,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
20052004
let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts());
20062005

20072006
let mut err = if let Some(subst) = subst {
2008-
let impl_candidates = self
2009-
.find_similar_impl_candidates(trait_ref)
2010-
.into_iter()
2011-
.map(|candidate| candidate.trait_ref)
2012-
.collect();
2013-
self.emit_inference_failure_err(
2014-
body_id,
2015-
span,
2016-
subst,
2017-
impl_candidates,
2018-
ErrorCode::E0283,
2019-
true,
2020-
)
2007+
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true)
20212008
} else {
20222009
struct_span_err!(
20232010
self.tcx.sess,
@@ -2117,7 +2104,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
21172104
return;
21182105
}
21192106

2120-
self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282, false)
2107+
self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false)
21212108
}
21222109

21232110
ty::PredicateKind::Subtype(data) => {
@@ -2131,14 +2118,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
21312118
let SubtypePredicate { a_is_expected: _, a, b } = data;
21322119
// both must be type variables, or the other would've been instantiated
21332120
assert!(a.is_ty_var() && b.is_ty_var());
2134-
self.emit_inference_failure_err(
2135-
body_id,
2136-
span,
2137-
a.into(),
2138-
vec![],
2139-
ErrorCode::E0282,
2140-
true,
2141-
)
2121+
self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true)
21422122
}
21432123
ty::PredicateKind::Projection(data) => {
21442124
if predicate.references_error() || self.is_tainted_by_errors() {
@@ -2155,7 +2135,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
21552135
body_id,
21562136
span,
21572137
subst,
2158-
vec![],
21592138
ErrorCode::E0284,
21602139
true,
21612140
);

compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -1538,15 +1538,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15381538
ty
15391539
} else {
15401540
if !self.is_tainted_by_errors() {
1541-
self.emit_inference_failure_err(
1542-
(**self).body_id,
1543-
sp,
1544-
ty.into(),
1545-
vec![],
1546-
E0282,
1547-
true,
1548-
)
1549-
.emit();
1541+
self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
1542+
.emit();
15501543
}
15511544
let err = self.tcx.ty_error();
15521545
self.demand_suptype(sp, err, ty);

compiler/rustc_typeck/src/check/writeback.rs

-2
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
692692
Some(self.body.id()),
693693
self.span.to_span(self.tcx),
694694
t.into(),
695-
vec![],
696695
E0282,
697696
false,
698697
)
@@ -707,7 +706,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
707706
Some(self.body.id()),
708707
self.span.to_span(self.tcx),
709708
c.into(),
710-
vec![],
711709
E0282,
712710
false,
713711
)

src/test/ui/inference/ambiguous_type_parameter.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
22
--> $DIR/ambiguous_type_parameter.rs:16:19
33
|
44
LL | InMemoryStore.get_raw(&String::default());
5-
| ^^^^^^^ cannot infer type for type parameter `K`
5+
| ^^^^^^^
6+
|
7+
help: try using a fully qualified path to specify the expected types
8+
|
9+
LL | <InMemoryStore as Store<String, HashMap<K, String>>>::get_raw(&InMemoryStore, &String::default());
10+
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~
611

712
error: aborting due to previous error
813

src/test/ui/inference/cannot-infer-partial-try-return.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ fn infallible() -> Result<(), std::convert::Infallible> {
1616

1717
fn main() {
1818
let x = || -> Result<_, QualifiedError<_>> {
19-
//~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>`
2019
infallible()?;
2120
Ok(())
21+
//~^ ERROR type annotations needed
2222
};
2323
}

src/test/ui/inference/cannot-infer-partial-try-return.stderr

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>`
2-
--> $DIR/cannot-infer-partial-try-return.rs:18:13
1+
error[E0282]: type annotations needed
2+
--> $DIR/cannot-infer-partial-try-return.rs:20:9
33
|
4-
LL | let x = || -> Result<_, QualifiedError<_>> {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6-
LL |
74
LL | infallible()?;
85
| ------------- type must be known at this point
6+
LL | Ok(())
7+
| ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
98
|
10-
help: try giving this closure an explicit return type
9+
help: consider specifying the generic arguments
1110
|
12-
LL | let x = || -> Result<(), QualifiedError<_>> {
13-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11+
LL | Ok::<(), QualifiedError<_>>(())
12+
| +++++++++++++++++++++++++
1413

1514
error: aborting due to previous error
1615

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Test that we suggest specifying the generic argument of `channel`
2+
// instead of the return type of that function, which is a lot more
3+
// complex.
4+
use std::sync::mpsc::channel;
5+
6+
fn no_tuple() {
7+
let _data =
8+
channel(); //~ ERROR type annotations needed
9+
}
10+
11+
fn tuple() {
12+
let (_sender, _receiver) =
13+
channel(); //~ ERROR type annotations needed
14+
}
15+
16+
fn main() {
17+
no_tuple();
18+
tuple();
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/channel.rs:8:9
3+
|
4+
LL | channel();
5+
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
6+
|
7+
help: consider specifying the generic argument
8+
|
9+
LL | channel::<T>();
10+
| +++++
11+
12+
error[E0282]: type annotations needed
13+
--> $DIR/channel.rs:13:9
14+
|
15+
LL | channel();
16+
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
17+
|
18+
help: consider specifying the generic argument
19+
|
20+
LL | channel::<T>();
21+
| +++++
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0282`.

src/test/ui/issues/issue-23041.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
error[E0282]: type annotations needed
2-
--> $DIR/issue-23041.rs:6:22
2+
--> $DIR/issue-23041.rs:6:7
33
|
44
LL | b.downcast_ref::<fn(_)->_>();
5-
| ^^^^^^^^ cannot infer type
5+
| ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref`
6+
|
7+
help: consider specifying the generic arguments
8+
|
9+
LL | b.downcast_ref::<fn(_) -> _>();
10+
| ~~~~~~~~~~~~~~
611

712
error: aborting due to previous error
813

0 commit comments

Comments
 (0)