Point at opaque and closure type definitions in type errors

This commit is contained in:
Esteban Küber 2019-11-15 18:53:17 -08:00
parent ed6468da16
commit 9c0000caca
14 changed files with 137 additions and 8 deletions

View file

@ -68,9 +68,11 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::Node;
use errors::{struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString};
use errors::{
pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString,
};
use rustc_error_codes::*;
use rustc_span::{Pos, Span};
use rustc_span::{DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::{cmp, fmt};
@ -1289,6 +1291,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
mut values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>,
) {
let span = cause.span(self.tcx);
// For some types of errors, expected-found does not make
// sense, so just ignore the values we were given.
match terr {
@ -1298,6 +1302,85 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => {}
}
struct OpaqueTypesVisitor<'tcx> {
types: FxHashMap<&'static str, FxHashSet<Span>>,
expected: FxHashMap<&'static str, FxHashSet<Span>>,
found: FxHashMap<&'static str, FxHashSet<Span>>,
ignore_span: Span,
tcx: TyCtxt<'tcx>,
}
impl<'tcx> OpaqueTypesVisitor<'tcx> {
fn visit_expected_found(
tcx: TyCtxt<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
ignore_span: Span,
) -> Self {
let mut types_visitor = OpaqueTypesVisitor {
types: Default::default(),
expected: Default::default(),
found: Default::default(),
ignore_span,
tcx,
};
expected.visit_with(&mut types_visitor);
std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types);
found.visit_with(&mut types_visitor);
std::mem::swap(&mut types_visitor.found, &mut types_visitor.types);
types_visitor
}
fn report(&self, err: &mut DiagnosticBuilder<'_>) {
for (target, types) in &[("expected", &self.expected), ("found", &self.found)] {
for (key, values) in types.iter() {
let count = values.len();
for sp in values {
err.span_label(
*sp,
format!(
"{}this is {}the {} {}{}",
if sp.is_desugaring(DesugaringKind::Async) {
"in the desugared `async fn`, "
} else {
""
},
if count > 1 { "one of" } else { "" },
target,
key,
pluralize!(count),
),
);
}
}
}
}
}
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
let kind = match t.kind {
ty::Closure(..) => "closure",
ty::Opaque(..) => "opaque type",
_ => "",
};
match t.kind {
ty::Closure(def_id, _) | ty::Opaque(def_id, _) => {
let span = self.tcx.def_span(def_id);
debug!("note_type_err visit_ty {:?}", span.macro_backtrace());
if !self.ignore_span.overlaps(span)
&& !self.expected.values().any(|exp| exp.iter().any(|sp| *sp == span))
{
let entry = self.types.entry(kind).or_default();
entry.insert(span);
}
}
_ => {}
}
t.super_visit_with(self)
}
}
debug!("note_type_err(diag={:?})", diag);
let (expected_found, exp_found, is_simple_error) = match values {
None => (None, None, false),
@ -1306,6 +1389,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
ValuePairs::Types(exp_found) => {
let is_simple_err =
exp_found.expected.is_simple_text() && exp_found.found.is_simple_text();
OpaqueTypesVisitor::visit_expected_found(
self.tcx,
exp_found.expected,
exp_found.found,
span,
)
.report(diag);
(is_simple_err, Some(exp_found))
}
@ -1323,8 +1413,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
};
let span = cause.span(self.tcx);
// Ignore msg for object safe coercion
// since E0038 message will be printed
match terr {
@ -1336,7 +1424,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
};
if let Some((expected, found)) = expected_found {
let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());

View file

@ -4743,14 +4743,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.join(", ");
}
Some(Node::Expr(hir::Expr {
kind: ExprKind::Closure(_, _, body_id, closure_span, _),
kind: ExprKind::Closure(_, _, body_id, _, _),
span: full_closure_span,
..
})) => {
if *full_closure_span == expr.span {
return false;
}
err.span_label(*closure_span, "closure defined here");
msg = "call this closure";
let body = hir.body(*body_id);
sugg_call = body

View file

@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/dont-suggest-missing-await.rs:14:18
|
LL | async fn make_u32() -> u32 {
| --- in the desugared `async fn`, this is the found opaque type
...
LL | take_u32(x)
| ^ expected `u32`, found opaque type
|

View file

@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/suggest-missing-await-closure.rs:16:18
|
LL | async fn make_u32() -> u32 {
| --- in the desugared `async fn`, this is the found opaque type
...
LL | take_u32(x)
| ^
| |

View file

@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:13:14
|
LL | async fn make_u32() -> u32 {
| --- in the desugared `async fn`, this is the found opaque type
...
LL | take_u32(x)
| ^
| |

View file

@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/closure-reform-bad.rs:11:15
|
LL | let f = |s: &str| println!("{}{}", s, string);
| ------------------------------------- this is the found closure
LL | call_bare(f)
| ^ expected fn pointer, found closure
|

View file

@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/equality2.rs:25:18
|
LL | fn hide<T: Foo>(x: T) -> impl Foo {
| -------- this is the found opaque type
...
LL | let _: u32 = hide(0_u32);
| --- ^^^^^^^^^^^ expected `u32`, found opaque type
| |
@ -12,6 +15,9 @@ LL | let _: u32 = hide(0_u32);
error[E0308]: mismatched types
--> $DIR/equality2.rs:31:18
|
LL | fn hide<T: Foo>(x: T) -> impl Foo {
| -------- this is the found opaque type
...
LL | let _: i32 = Leak::leak(hide(0_i32));
| --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
| |
@ -25,6 +31,9 @@ LL | let _: i32 = Leak::leak(hide(0_i32));
error[E0308]: mismatched types
--> $DIR/equality2.rs:38:10
|
LL | fn hide<T: Foo>(x: T) -> impl Foo {
| -------- this is the expected opaque type
...
LL | x = (x.1,
| ^^^ expected `u32`, found `i32`
|
@ -34,6 +43,9 @@ LL | x = (x.1,
error[E0308]: mismatched types
--> $DIR/equality2.rs:41:10
|
LL | fn hide<T: Foo>(x: T) -> impl Foo {
| -------- this is the expected opaque type
...
LL | x.0);
| ^^^ expected `i32`, found `u32`
|

View file

@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/issue-24036.rs:3:9
|
LL | let mut x = |c| c + 1;
| --------- this is the expected closure
LL | x = |c| c + 1;
| ^^^^^^^^^ expected closure, found a different closure
|

View file

@ -236,7 +236,7 @@ error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:46:20
|
LL | let closure = || 42;
| -- closure defined here
| ----- this is the found closure
LL | let _: usize = closure;
| ----- ^^^^^^^
| | |

View file

@ -1,6 +1,9 @@
error[E0308]: `if` and `else` have incompatible types
--> $DIR/opaque-type-error.rs:20:9
|
LL | fn thing_two() -> impl Future<Output = Result<(), ()>> {
| ------------------------------------ this is the found opaque type
...
LL | / if true {
LL | | thing_one()
| | ----------- expected because of this

View file

@ -11,6 +11,9 @@ LL | let z: i32 = x;
| --- ^ expected `i32`, found opaque type
| |
| expected due to this
...
LL | type WrongGeneric<T> = impl 'static;
| ------------------------------------ this is the found opaque type
|
= note: expected type `i32`
found opaque type `WrongGeneric::<&{integer}>`

View file

@ -11,6 +11,9 @@ LL | let z: i32 = x;
| --- ^ expected `i32`, found opaque type
| |
| expected due to this
...
LL | type WrongGeneric<T> = impl 'static;
| ------------------------------------ this is the found opaque type
|
= note: expected type `i32`
found opaque type `WrongGeneric::<&{integer}>`

View file

@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/never_reveal_concrete_type.rs:13:27
|
LL | type NoReveal = impl std::fmt::Debug;
| ------------------------------------- this is the found opaque type
...
LL | let _: &'static str = x;
| ------------ ^ expected `&str`, found opaque type
| |

View file

@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/no_revealing_outside_defining_module.rs:15:19
|
LL | pub type Boo = impl ::std::fmt::Debug;
| -------------------------------------- this is the found opaque type
...
LL | let _: &str = bomp();
| ---- ^^^^^^ expected `&str`, found opaque type
| |
@ -12,6 +15,9 @@ LL | let _: &str = bomp();
error[E0308]: mismatched types
--> $DIR/no_revealing_outside_defining_module.rs:19:5
|
LL | pub type Boo = impl ::std::fmt::Debug;
| -------------------------------------- this is the expected opaque type
...
LL | fn bomp() -> boo::Boo {
| -------- expected `Boo` because of return type
LL | ""