Skip to content

Commit fd9991c

Browse files
authored
Rollup merge of rust-lang#66463 - estebank:point-at-closure-and-opaque-types, r=Centril
Point at opaque and closure type definitions in type errors Fixes rust-lang#57266, fixes rust-lang#67117.
2 parents 72b2bd5 + 33ae322 commit fd9991c

22 files changed

+255
-21
lines changed

src/librustc/infer/error_reporting/mod.rs

+139-5
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,12 @@ use rustc_hir as hir;
6868
use rustc_hir::def_id::DefId;
6969
use rustc_hir::Node;
7070

71-
use errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString};
71+
use errors::{
72+
pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString,
73+
};
74+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7275
use rustc_error_codes::*;
73-
use rustc_span::{Pos, Span};
76+
use rustc_span::{DesugaringKind, Pos, Span};
7477
use rustc_target::spec::abi;
7578
use std::{cmp, fmt};
7679

@@ -1289,6 +1292,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12891292
mut values: Option<ValuePairs<'tcx>>,
12901293
terr: &TypeError<'tcx>,
12911294
) {
1295+
let span = cause.span(self.tcx);
1296+
12921297
// For some types of errors, expected-found does not make
12931298
// sense, so just ignore the values we were given.
12941299
match terr {
@@ -1298,6 +1303,100 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12981303
_ => {}
12991304
}
13001305

1306+
struct OpaqueTypesVisitor<'tcx> {
1307+
types: FxHashMap<TyCategory, FxHashSet<Span>>,
1308+
expected: FxHashMap<TyCategory, FxHashSet<Span>>,
1309+
found: FxHashMap<TyCategory, FxHashSet<Span>>,
1310+
ignore_span: Span,
1311+
tcx: TyCtxt<'tcx>,
1312+
}
1313+
1314+
impl<'tcx> OpaqueTypesVisitor<'tcx> {
1315+
fn visit_expected_found(
1316+
tcx: TyCtxt<'tcx>,
1317+
expected: Ty<'tcx>,
1318+
found: Ty<'tcx>,
1319+
ignore_span: Span,
1320+
) -> Self {
1321+
let mut types_visitor = OpaqueTypesVisitor {
1322+
types: Default::default(),
1323+
expected: Default::default(),
1324+
found: Default::default(),
1325+
ignore_span,
1326+
tcx,
1327+
};
1328+
// The visitor puts all the relevant encountered types in `self.types`, but in
1329+
// here we want to visit two separate types with no relation to each other, so we
1330+
// move the results from `types` to `expected` or `found` as appropriate.
1331+
expected.visit_with(&mut types_visitor);
1332+
std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types);
1333+
found.visit_with(&mut types_visitor);
1334+
std::mem::swap(&mut types_visitor.found, &mut types_visitor.types);
1335+
types_visitor
1336+
}
1337+
1338+
fn report(&self, err: &mut DiagnosticBuilder<'_>) {
1339+
self.add_labels_for_types(err, "expected", &self.expected);
1340+
self.add_labels_for_types(err, "found", &self.found);
1341+
}
1342+
1343+
fn add_labels_for_types(
1344+
&self,
1345+
err: &mut DiagnosticBuilder<'_>,
1346+
target: &str,
1347+
types: &FxHashMap<TyCategory, FxHashSet<Span>>,
1348+
) {
1349+
for (key, values) in types.iter() {
1350+
let count = values.len();
1351+
let kind = key.descr();
1352+
for sp in values {
1353+
err.span_label(
1354+
*sp,
1355+
format!(
1356+
"{}{}{} {}{}",
1357+
if sp.is_desugaring(DesugaringKind::Async) {
1358+
"the `Output` of this `async fn`'s "
1359+
} else if count == 1 {
1360+
"the "
1361+
} else {
1362+
""
1363+
},
1364+
if count > 1 { "one of the " } else { "" },
1365+
target,
1366+
kind,
1367+
pluralize!(count),
1368+
),
1369+
);
1370+
}
1371+
}
1372+
}
1373+
}
1374+
1375+
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
1376+
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
1377+
if let Some((kind, def_id)) = TyCategory::from_ty(t) {
1378+
let span = self.tcx.def_span(def_id);
1379+
// Avoid cluttering the output when the "found" and error span overlap:
1380+
//
1381+
// error[E0308]: mismatched types
1382+
// --> $DIR/issue-20862.rs:2:5
1383+
// |
1384+
// LL | |y| x + y
1385+
// | ^^^^^^^^^
1386+
// | |
1387+
// | the found closure
1388+
// | expected `()`, found closure
1389+
// |
1390+
// = note: expected unit type `()`
1391+
// found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]`
1392+
if !self.ignore_span.overlaps(span) {
1393+
self.types.entry(kind).or_default().insert(span);
1394+
}
1395+
}
1396+
t.super_visit_with(self)
1397+
}
1398+
}
1399+
13011400
debug!("note_type_err(diag={:?})", diag);
13021401
let (expected_found, exp_found, is_simple_error) = match values {
13031402
None => (None, None, false),
@@ -1306,6 +1405,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13061405
ValuePairs::Types(exp_found) => {
13071406
let is_simple_err =
13081407
exp_found.expected.is_simple_text() && exp_found.found.is_simple_text();
1408+
OpaqueTypesVisitor::visit_expected_found(
1409+
self.tcx,
1410+
exp_found.expected,
1411+
exp_found.found,
1412+
span,
1413+
)
1414+
.report(diag);
13091415

13101416
(is_simple_err, Some(exp_found))
13111417
}
@@ -1323,8 +1429,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13231429
}
13241430
};
13251431

1326-
let span = cause.span(self.tcx);
1327-
13281432
// Ignore msg for object safe coercion
13291433
// since E0038 message will be printed
13301434
match terr {
@@ -1336,7 +1440,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13361440
}
13371441
}
13381442
};
1339-
13401443
if let Some((expected, found)) = expected_found {
13411444
let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
13421445
let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());
@@ -1933,3 +2036,34 @@ impl<'tcx> ObligationCause<'tcx> {
19332036
}
19342037
}
19352038
}
2039+
2040+
/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
2041+
/// extra information about each type, but we only care about the category.
2042+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2043+
crate enum TyCategory {
2044+
Closure,
2045+
Opaque,
2046+
Generator,
2047+
Foreign,
2048+
}
2049+
2050+
impl TyCategory {
2051+
fn descr(&self) -> &'static str {
2052+
match self {
2053+
Self::Closure => "closure",
2054+
Self::Opaque => "opaque type",
2055+
Self::Generator => "generator",
2056+
Self::Foreign => "foreign type",
2057+
}
2058+
}
2059+
2060+
pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
2061+
match ty.kind {
2062+
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
2063+
ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
2064+
ty::Generator(def_id, ..) => Some((Self::Generator, def_id)),
2065+
ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
2066+
_ => None,
2067+
}
2068+
}
2069+
}

src/librustc/traits/error_reporting.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::{
66
TraitNotObjectSafe,
77
};
88

9-
use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode;
9+
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
1010
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1111
use crate::infer::{self, InferCtxt};
1212
use crate::mir::interpret::ErrorHandled;
@@ -446,7 +446,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
446446
flags.push((sym::from_method, Some(method.to_string())));
447447
}
448448
}
449-
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
449+
if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
450450
flags.push((sym::parent_trait, Some(t)));
451451
}
452452

@@ -665,13 +665,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
665665
}
666666

667667
/// Gets the parent trait chain start
668-
fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option<String> {
668+
fn get_parent_trait_ref(
669+
&self,
670+
code: &ObligationCauseCode<'tcx>,
671+
) -> Option<(String, Option<Span>)> {
669672
match code {
670673
&ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
671674
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
672675
match self.get_parent_trait_ref(&data.parent_code) {
673676
Some(t) => Some(t),
674-
None => Some(parent_trait_ref.skip_binder().self_ty().to_string()),
677+
None => {
678+
let ty = parent_trait_ref.skip_binder().self_ty();
679+
let span =
680+
TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
681+
Some((ty.to_string(), span))
682+
}
675683
}
676684
}
677685
_ => None,
@@ -719,9 +727,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
719727
return;
720728
}
721729
let trait_ref = trait_predicate.to_poly_trait_ref();
722-
let (post_message, pre_message) = self
730+
let (post_message, pre_message, type_def) = self
723731
.get_parent_trait_ref(&obligation.cause.code)
724-
.map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
732+
.map(|(t, s)| {
733+
(
734+
format!(" in `{}`", t),
735+
format!("within `{}`, ", t),
736+
s.map(|s| (format!("within this `{}`", t), s)),
737+
)
738+
})
725739
.unwrap_or_default();
726740

727741
let OnUnimplementedNote { message, label, note, enclosing_scope } =
@@ -795,6 +809,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
795809
} else {
796810
err.span_label(span, explanation);
797811
}
812+
if let Some((msg, span)) = type_def {
813+
err.span_label(span, &msg);
814+
}
798815
if let Some(ref s) = note {
799816
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
800817
err.note(s.as_str());

src/librustc_typeck/check/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -4746,14 +4746,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
47464746
.join(", ");
47474747
}
47484748
Some(Node::Expr(hir::Expr {
4749-
kind: ExprKind::Closure(_, _, body_id, closure_span, _),
4749+
kind: ExprKind::Closure(_, _, body_id, _, _),
47504750
span: full_closure_span,
47514751
..
47524752
})) => {
47534753
if *full_closure_span == expr.span {
47544754
return false;
47554755
}
4756-
err.span_label(*closure_span, "closure defined here");
47574756
msg = "call this closure";
47584757
let body = hir.body(*body_id);
47594758
sugg_call = body

src/test/ui/async-await/dont-suggest-missing-await.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/dont-suggest-missing-await.rs:14:18
33
|
4+
LL | async fn make_u32() -> u32 {
5+
| --- the `Output` of this `async fn`'s found opaque type
6+
...
47
LL | take_u32(x)
58
| ^ expected `u32`, found opaque type
69
|

src/test/ui/async-await/issue-64130-3-other.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::
33
|
44
LL | fn is_qux<T: Qux>(t: T) { }
55
| ------ --- required by this bound in `is_qux`
6+
LL |
7+
LL | async fn bar() {
8+
| - within this `impl std::future::Future`
69
...
710
LL | is_qux(bar());
811
| ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo`

src/test/ui/async-await/suggest-missing-await-closure.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/suggest-missing-await-closure.rs:16:18
33
|
4+
LL | async fn make_u32() -> u32 {
5+
| --- the `Output` of this `async fn`'s found opaque type
6+
...
47
LL | take_u32(x)
58
| ^
69
| |

src/test/ui/async-await/suggest-missing-await.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/suggest-missing-await.rs:13:14
33
|
4+
LL | async fn make_u32() -> u32 {
5+
| --- the `Output` of this `async fn`'s found opaque type
6+
...
47
LL | take_u32(x)
58
| ^
69
| |
@@ -13,6 +16,9 @@ LL | take_u32(x)
1316
error[E0308]: mismatched types
1417
--> $DIR/suggest-missing-await.rs:23:5
1518
|
19+
LL | async fn dummy() {}
20+
| - the `Output` of this `async fn`'s found opaque type
21+
...
1622
LL | dummy()
1723
| ^^^^^^^ expected `()`, found opaque type
1824
|

src/test/ui/closures/closure-reform-bad.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/closure-reform-bad.rs:11:15
33
|
4+
LL | let f = |s: &str| println!("{}{}", s, string);
5+
| ------------------------------------- the found closure
46
LL | call_bare(f)
57
| ^ expected fn pointer, found closure
68
|

src/test/ui/extern/extern-types-distinct-types.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
error[E0308]: mismatched types
22
--> $DIR/extern-types-distinct-types.rs:9:5
33
|
4+
LL | type A;
5+
| ------- the found foreign type
6+
LL | type B;
7+
| ------- the expected foreign type
8+
...
49
LL | r
510
| ^ expected extern type `B`, found extern type `A`
611
|

src/test/ui/impl-trait/auto-trait-leak.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ LL | fn send<T: Send>(_: T) {}
112112
...
113113
LL | send(cycle2().clone());
114114
| ^^^^ `std::rc::Rc<std::string::String>` cannot be sent between threads safely
115+
...
116+
LL | fn cycle2() -> impl Clone {
117+
| ---------- within this `impl std::clone::Clone`
115118
|
116119
= help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
117120
= note: required because it appears within the type `impl std::clone::Clone`

src/test/ui/impl-trait/auto-trait-leak2.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0277]: `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
22
--> $DIR/auto-trait-leak2.rs:13:5
33
|
4+
LL | fn before() -> impl Fn(i32) {
5+
| ------------ within this `impl std::ops::Fn<(i32,)>`
6+
...
47
LL | fn send<T: Send>(_: T) {}
58
| ---- ---- required by this bound in `send`
69
...
@@ -19,6 +22,9 @@ LL | fn send<T: Send>(_: T) {}
1922
...
2023
LL | send(after());
2124
| ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
25+
...
26+
LL | fn after() -> impl Fn(i32) {
27+
| ------------ within this `impl std::ops::Fn<(i32,)>`
2228
|
2329
= help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
2430
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc<std::cell::Cell<i32>>]`

0 commit comments

Comments
 (0)