From 9c0000cacac904a9b04c64ca349f54169b98f60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 15 Nov 2019 18:53:17 -0800 Subject: [PATCH 1/8] Point at opaque and closure type definitions in type errors --- src/librustc/infer/error_reporting/mod.rs | 97 ++++++++++++++++++- src/librustc_typeck/check/mod.rs | 3 +- .../dont-suggest-missing-await.stderr | 3 + .../suggest-missing-await-closure.stderr | 3 + .../async-await/suggest-missing-await.stderr | 3 + .../ui/closures/closure-reform-bad.stderr | 2 + src/test/ui/impl-trait/equality2.stderr | 12 +++ src/test/ui/issues/issue-24036.stderr | 2 + .../fn-or-tuple-struct-without-args.stderr | 2 +- .../ui/suggestions/opaque-type-error.stderr | 3 + ..._type_does_not_live_long_enough.nll.stderr | 3 + ...eric_type_does_not_live_long_enough.stderr | 3 + .../never_reveal_concrete_type.stderr | 3 + ...o_revealing_outside_defining_module.stderr | 6 ++ 14 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 92292b3d35f24..e134a6c17cc3d 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -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>, 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>, + expected: FxHashMap<&'static str, FxHashSet>, + found: FxHashMap<&'static str, FxHashSet>, + 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()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e6fbae09ba1a0..00ad00cf1b24c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index 239f801c39d4e..5bf10e0089207 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -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 | diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 1efc20082a08a..43366e6bbbfab 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -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) | ^ | | diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 7ab024434b2bf..c7fcbdd8138c1 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -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) | ^ | | diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 63236cf542464..16727b58e1ff6 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -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 | diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 312976b72d20e..4e1880f31dc2a 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:25:18 | +LL | fn hide(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(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(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(x: T) -> impl Foo { + | -------- this is the expected opaque type +... LL | x.0); | ^^^ expected `i32`, found `u32` | diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index b0e729a59eb22..670bf57067b56 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -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 | diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 2f0a457a79594..5b18c239b6ee3 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -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; | ----- ^^^^^^^ | | | diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr index 1465b9e49ef1a..3a7ea2bcdd2a4 100644 --- a/src/test/ui/suggestions/opaque-type-error.stderr +++ b/src/test/ui/suggestions/opaque-type-error.stderr @@ -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> { + | ------------------------------------ this is the found opaque type +... LL | / if true { LL | | thing_one() | | ----------- expected because of this diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr index dc41cbc5fe3f8..182a3c7e81e60 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr @@ -11,6 +11,9 @@ LL | let z: i32 = x; | --- ^ expected `i32`, found opaque type | | | expected due to this +... +LL | type WrongGeneric = impl 'static; + | ------------------------------------ this is the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index 24d23de797690..b061ec3fff8f4 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -11,6 +11,9 @@ LL | let z: i32 = x; | --- ^ expected `i32`, found opaque type | | | expected due to this +... +LL | type WrongGeneric = impl 'static; + | ------------------------------------ this is the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index 07962e36da1e6..415ac4bbdcba7 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -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 | | diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index a2081424ab497..3e67dc90dcb5c 100644 --- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -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 | "" From c55615155d161c8abb307db0019ab58545cd246b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Dec 2019 14:05:08 -0800 Subject: [PATCH 2/8] review comments --- src/librustc/infer/error_reporting/mod.rs | 40 +++++++++++-------- .../dont-suggest-missing-await.stderr | 2 +- .../suggest-missing-await-closure.stderr | 2 +- .../async-await/suggest-missing-await.stderr | 5 ++- .../ui/closures/closure-reform-bad.stderr | 2 +- .../extern/extern-types-distinct-types.stderr | 5 +++ src/test/ui/impl-trait/equality2.stderr | 14 +++++-- src/test/ui/issues/issue-24036.stderr | 2 +- .../fn-or-tuple-struct-without-args.stderr | 2 +- .../ui/suggestions/opaque-type-error.stderr | 2 +- ..._type_does_not_live_long_enough.nll.stderr | 2 +- ...eric_type_does_not_live_long_enough.stderr | 2 +- .../never_reveal_concrete_type.stderr | 2 +- ...o_revealing_outside_defining_module.stderr | 4 +- 14 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index e134a6c17cc3d..d0243dad700b6 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1339,16 +1339,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label( *sp, format!( - "{}this is {}the {} {}{}", + "{}the {} {}{}{}", + if count > 1 { "one of " } else { "" }, + target, + key, + pluralize!(count), if sp.is_desugaring(DesugaringKind::Async) { - "in the desugared `async fn`, " + " in the `Output` of this `async fn`" } else { "" }, - if count > 1 { "one of" } else { "" }, - target, - key, - pluralize!(count), ), ); } @@ -1364,18 +1364,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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); - } + if let ty::Closure(def_id, _) | ty::Opaque(def_id, _) = t.kind { + let span = self.tcx.def_span(def_id); + // Avoid cluttering the output when the "found" and error span overlap: + // + // error[E0308]: mismatched types + // --> $DIR/issue-20862.rs:2:5 + // | + // LL | |y| x + y + // | ^^^^^^^^^ + // | | + // | the found closure + // | expected `()`, found closure + // | + // = note: expected unit type `()` + // found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]` + if !self.ignore_span.overlaps(span) { + self.types.entry(kind).or_default().insert(span); } - _ => {} } t.super_visit_with(self) } diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index 5bf10e0089207..5c9b1d2c4d71c 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -2,7 +2,7 @@ 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 + | --- the found opaque type in the `Output` of this `async fn` ... LL | take_u32(x) | ^ expected `u32`, found opaque type diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 43366e6bbbfab..5926c8351ff3d 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -2,7 +2,7 @@ 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 + | --- the found opaque type in the `Output` of this `async fn` ... LL | take_u32(x) | ^ diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index c7fcbdd8138c1..c0dc32b83fb0b 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -2,7 +2,7 @@ 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 + | --- the found opaque type in the `Output` of this `async fn` ... LL | take_u32(x) | ^ @@ -16,6 +16,9 @@ LL | take_u32(x) error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:23:5 | +LL | async fn dummy() {} + | - the found opaque type in the `Output` of this `async fn` +... LL | dummy() | ^^^^^^^ expected `()`, found opaque type | diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 16727b58e1ff6..3c4ae450764da 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/closure-reform-bad.rs:11:15 | LL | let f = |s: &str| println!("{}{}", s, string); - | ------------------------------------- this is the found closure + | ------------------------------------- the found closure LL | call_bare(f) | ^ expected fn pointer, found closure | diff --git a/src/test/ui/extern/extern-types-distinct-types.stderr b/src/test/ui/extern/extern-types-distinct-types.stderr index 2e258d687d385..32b45ee10ad6f 100644 --- a/src/test/ui/extern/extern-types-distinct-types.stderr +++ b/src/test/ui/extern/extern-types-distinct-types.stderr @@ -1,6 +1,11 @@ error[E0308]: mismatched types --> $DIR/extern-types-distinct-types.rs:9:5 | +LL | type A; + | ------- the found foreign type +LL | type B; + | ------- the expected foreign type +... LL | r | ^ expected extern type `B`, found extern type `A` | diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 4e1880f31dc2a..b882514f61609 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:25:18 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the found opaque type + | -------- the found opaque type ... LL | let _: u32 = hide(0_u32); | --- ^^^^^^^^^^^ expected `u32`, found opaque type @@ -16,7 +16,7 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:31:18 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the found opaque type + | -------- the found opaque type ... LL | let _: i32 = Leak::leak(hide(0_i32)); | --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type @@ -32,7 +32,10 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:38:10 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the expected opaque type + | -------- + | | + | the expected opaque type + | the found opaque type ... LL | x = (x.1, | ^^^ expected `u32`, found `i32` @@ -44,7 +47,10 @@ error[E0308]: mismatched types --> $DIR/equality2.rs:41:10 | LL | fn hide(x: T) -> impl Foo { - | -------- this is the expected opaque type + | -------- + | | + | the expected opaque type + | the found opaque type ... LL | x.0); | ^^^ expected `i32`, found `u32` diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index 670bf57067b56..036c05fc848cf 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-24036.rs:3:9 | LL | let mut x = |c| c + 1; - | --------- this is the expected closure + | --------- the expected closure LL | x = |c| c + 1; | ^^^^^^^^^ expected closure, found a different closure | diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 5b18c239b6ee3..232e54b5d37b2 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -236,7 +236,7 @@ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:46:20 | LL | let closure = || 42; - | ----- this is the found closure + | ----- the found closure LL | let _: usize = closure; | ----- ^^^^^^^ | | | diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr index 3a7ea2bcdd2a4..167d61bdf7c70 100644 --- a/src/test/ui/suggestions/opaque-type-error.stderr +++ b/src/test/ui/suggestions/opaque-type-error.stderr @@ -2,7 +2,7 @@ error[E0308]: `if` and `else` have incompatible types --> $DIR/opaque-type-error.rs:20:9 | LL | fn thing_two() -> impl Future> { - | ------------------------------------ this is the found opaque type + | ------------------------------------ the found opaque type ... LL | / if true { LL | | thing_one() diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr index 182a3c7e81e60..9549074d4bf78 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr @@ -13,7 +13,7 @@ LL | let z: i32 = x; | expected due to this ... LL | type WrongGeneric = impl 'static; - | ------------------------------------ this is the found opaque type + | ------------------------------------ the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index b061ec3fff8f4..5a7f9d74eba5b 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -13,7 +13,7 @@ LL | let z: i32 = x; | expected due to this ... LL | type WrongGeneric = impl 'static; - | ------------------------------------ this is the found opaque type + | ------------------------------------ the found opaque type | = note: expected type `i32` found opaque type `WrongGeneric::<&{integer}>` diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index 415ac4bbdcba7..70c99c944d654 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -2,7 +2,7 @@ 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 + | ------------------------------------- the found opaque type ... LL | let _: &'static str = x; | ------------ ^ expected `&str`, found opaque type diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index 3e67dc90dcb5c..375c0bc7fe2ed 100644 --- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -2,7 +2,7 @@ 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 + | -------------------------------------- the found opaque type ... LL | let _: &str = bomp(); | ---- ^^^^^^ expected `&str`, found opaque type @@ -16,7 +16,7 @@ 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 + | -------------------------------------- the expected opaque type ... LL | fn bomp() -> boo::Boo { | -------- expected `Boo` because of return type From 0dcdbaec0b49a149316719b32241d8975bd192c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Dec 2019 22:20:30 -0800 Subject: [PATCH 3/8] Point at the def span of trait refs E0277 --- src/librustc/infer/error_reporting/mod.rs | 9 ++++- src/librustc/traits/error_reporting.rs | 34 ++++++++++++++++--- .../ui/async-await/issue-64130-3-other.stderr | 3 ++ src/test/ui/impl-trait/auto-trait-leak.stderr | 3 ++ .../ui/impl-trait/auto-trait-leak2.stderr | 6 ++++ .../ui/kindck/kindck-nonsendable-1.stderr | 4 ++- src/test/ui/no-send-res-ports.stderr | 15 +++++--- src/test/ui/not-clone-closure.stderr | 10 ++++-- 8 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d0243dad700b6..d736d45a5a485 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -71,6 +71,7 @@ use rustc_hir::Node; use errors::{ pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticStyledString, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_error_codes::*; use rustc_span::{DesugaringKind, Pos, Span}; use rustc_target::spec::abi; @@ -1362,9 +1363,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let kind = match t.kind { ty::Closure(..) => "closure", ty::Opaque(..) => "opaque type", + ty::Generator(..) => "generator", + ty::Foreign(..) => "foreign type", _ => "", }; - if let ty::Closure(def_id, _) | ty::Opaque(def_id, _) = t.kind { + if let ty::Closure(def_id, _) + | ty::Opaque(def_id, _) + | ty::Generator(def_id, ..) + | ty::Foreign(def_id) = t.kind + { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: // diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 00251d55706d7..8c2cc412a480b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -446,7 +446,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { flags.push((sym::from_method, Some(method.to_string()))); } } - if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) { + if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) { flags.push((sym::parent_trait, Some(t))); } @@ -665,13 +665,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Gets the parent trait chain start - fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option { + fn get_parent_trait_ref( + &self, + code: &ObligationCauseCode<'tcx>, + ) -> Option<(String, Option)> { match code { &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), - None => Some(parent_trait_ref.skip_binder().self_ty().to_string()), + None => { + let ty = parent_trait_ref.skip_binder().self_ty(); + let span = if let ty::Closure(def_id, _) + | ty::Opaque(def_id, _) + | ty::Generator(def_id, ..) + | ty::Foreign(def_id) = ty.kind + { + Some(self.tcx.def_span(def_id)) + } else { + None + }; + Some((ty.to_string(), span)) + } } } _ => None, @@ -719,9 +734,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return; } let trait_ref = trait_predicate.to_poly_trait_ref(); - let (post_message, pre_message) = self + let (post_message, pre_message, type_def) = self .get_parent_trait_ref(&obligation.cause.code) - .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t))) + .map(|(t, s)| { + ( + format!(" in `{}`", t), + format!("within `{}`, ", t), + s.map(|s| (format!("within this `{}`", t), s)), + ) + }) .unwrap_or_default(); let OnUnimplementedNote { message, label, note, enclosing_scope } = @@ -795,6 +816,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } else { err.span_label(span, explanation); } + if let Some((msg, span)) = type_def { + err.span_label(span, &msg); + } if let Some(ref s) = note { // If it has a custom `#[rustc_on_unimplemented]` note, let's display it err.note(s.as_str()); diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr index 155c5cc8ea137..d6828172928dd 100644 --- a/src/test/ui/async-await/issue-64130-3-other.stderr +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -3,6 +3,9 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future:: | LL | fn is_qux(t: T) { } | ------ --- required by this bound in `is_qux` +LL | +LL | async fn bar() { + | - within this `impl std::future::Future` ... LL | is_qux(bar()); | ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo` diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index d11941fee1824..20815e80acb89 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -77,6 +77,9 @@ LL | fn send(_: T) {} ... LL | send(cycle2().clone()); | ^^^^ `std::rc::Rc` cannot be sent between threads safely +... +LL | fn cycle2() -> impl Clone { + | ---------- within this `impl std::clone::Clone` | = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` = note: required because it appears within the type `impl std::clone::Clone` diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index d163e1dff7ac9..a93b3dbc71b60 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,6 +1,9 @@ error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:13:5 | +LL | fn before() -> impl Fn(i32) { + | ------------ within this `impl std::ops::Fn<(i32,)>` +... LL | fn send(_: T) {} | ---- ---- required by this bound in `send` ... @@ -19,6 +22,9 @@ LL | fn send(_: T) {} ... LL | send(after()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely +... +LL | fn after() -> impl Fn(i32) { + | ------------ within this `impl std::ops::Fn<(i32,)>` | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc>]` diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr index 40b67f8fe8cd7..39640e373991f 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.stderr +++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr @@ -5,7 +5,9 @@ LL | fn bar(_: F) { } | --- ---- required by this bound in `bar` ... LL | bar(move|| foo(x)); - | ^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` + | | + | `std::rc::Rc` cannot be sent between threads safely | = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr index 8cb690a35c874..65946ee8a20cf 100644 --- a/src/test/ui/no-send-res-ports.stderr +++ b/src/test/ui/no-send-res-ports.stderr @@ -1,13 +1,20 @@ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely --> $DIR/no-send-res-ports.rs:29:5 | -LL | thread::spawn(move|| { - | ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely +LL | thread::spawn(move|| { + | _____^^^^^^^^^^^^^_- + | | | + | | `std::rc::Rc<()>` cannot be sent between threads safely +LL | | +LL | | let y = x; +LL | | println!("{:?}", y); +LL | | }); + | |_____- within this `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]` | ::: $SRC_DIR/libstd/thread/mod.rs:LL:COL | -LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` +LL | F: Send + 'static, + | ---- required by this bound in `std::thread::spawn` | = help: within `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` = note: required because it appears within the type `Port<()>` diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr index b66391b83b8db..20c7f81cf5ef5 100644 --- a/src/test/ui/not-clone-closure.stderr +++ b/src/test/ui/not-clone-closure.stderr @@ -1,8 +1,14 @@ error[E0277]: the trait bound `S: std::clone::Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` --> $DIR/not-clone-closure.rs:11:23 | -LL | let hello = hello.clone(); - | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S` +LL | let hello = move || { + | _________________- +LL | | println!("Hello {}", a.0); +LL | | }; + | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` +LL | +LL | let hello = hello.clone(); + | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S` | = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` From 542be6fb6c3e3e3eae5aae04ac772aa0ab53b9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Dec 2019 22:48:45 -0800 Subject: [PATCH 4/8] review comment: wording --- src/librustc/infer/error_reporting/mod.rs | 14 ++++++++------ .../async-await/dont-suggest-missing-await.stderr | 2 +- .../suggest-missing-await-closure.stderr | 2 +- .../ui/async-await/suggest-missing-await.stderr | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d736d45a5a485..8a444b8d45263 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1340,16 +1340,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label( *sp, format!( - "{}the {} {}{}{}", - if count > 1 { "one of " } else { "" }, - target, - key, - pluralize!(count), + "{}{}{} {}{}", if sp.is_desugaring(DesugaringKind::Async) { - " in the `Output` of this `async fn`" + "the `Output` of this `async fn`'s " + } else if count == 1 { + "the " } else { "" }, + if count > 1 { "one of the " } else { "" }, + target, + key, + pluralize!(count), ), ); } diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index 5c9b1d2c4d71c..dc3a4752fb1f7 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/dont-suggest-missing-await.rs:14:18 | LL | async fn make_u32() -> u32 { - | --- the found opaque type in the `Output` of this `async fn` + | --- the `Output` of this `async fn`'s found opaque type ... LL | take_u32(x) | ^ expected `u32`, found opaque type diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 5926c8351ff3d..2703cec581ddf 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await-closure.rs:16:18 | LL | async fn make_u32() -> u32 { - | --- the found opaque type in the `Output` of this `async fn` + | --- the `Output` of this `async fn`'s found opaque type ... LL | take_u32(x) | ^ diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index c0dc32b83fb0b..6ac05a87aae80 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:13:14 | LL | async fn make_u32() -> u32 { - | --- the found opaque type in the `Output` of this `async fn` + | --- the `Output` of this `async fn`'s found opaque type ... LL | take_u32(x) | ^ @@ -17,7 +17,7 @@ error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:23:5 | LL | async fn dummy() {} - | - the found opaque type in the `Output` of this `async fn` + | - the `Output` of this `async fn`'s found opaque type ... LL | dummy() | ^^^^^^^ expected `()`, found opaque type From b522ba02374169372a80d867894818c92e8c534a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 7 Jan 2020 17:31:37 -0800 Subject: [PATCH 5/8] review comments --- src/librustc/infer/error_reporting/mod.rs | 50 +++++++++++++++-------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 8a444b8d45263..bc75e0a75f09d 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1303,10 +1303,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + enum TyKind { + Closure, + Opaque, + Generator, + Foreign, + } + + impl TyKind { + fn descr(&self) -> &'static str { + match self { + Self::Closure => "closure", + Self::Opaque => "opaque type", + Self::Generator => "generator", + Self::Foreign => "foreign type", + } + } + + fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { + match ty.kind { + ty::Closure(def_id, _) => Some((Self::Closure, def_id)), + ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), + ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), + ty::Foreign(def_id) => Some((Self::Foreign, def_id)), + _ => None, + } + } + } + struct OpaqueTypesVisitor<'tcx> { - types: FxHashMap<&'static str, FxHashSet>, - expected: FxHashMap<&'static str, FxHashSet>, - found: FxHashMap<&'static str, FxHashSet>, + types: FxHashMap>, + expected: FxHashMap>, + found: FxHashMap>, ignore_span: Span, tcx: TyCtxt<'tcx>, } @@ -1350,7 +1379,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, if count > 1 { "one of the " } else { "" }, target, - key, + key.descr(), pluralize!(count), ), ); @@ -1362,18 +1391,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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", - ty::Generator(..) => "generator", - ty::Foreign(..) => "foreign type", - _ => "", - }; - if let ty::Closure(def_id, _) - | ty::Opaque(def_id, _) - | ty::Generator(def_id, ..) - | ty::Foreign(def_id) = t.kind - { + if let Some((kind, def_id)) = TyKind::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: // From ffcdbad263fc2522696b3376627aca503fe0fe8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2020 09:09:43 -0800 Subject: [PATCH 6/8] review comments --- src/librustc/infer/error_reporting/mod.rs | 66 ++++++++++++++--------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index bc75e0a75f09d..b6d6ca0dcef72 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1303,15 +1303,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } + /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks + /// extra information about each type, but we only care about the category. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - enum TyKind { + enum TyCategory { Closure, Opaque, Generator, Foreign, } - impl TyKind { + impl TyCategory { fn descr(&self) -> &'static str { match self { Self::Closure => "closure", @@ -1334,8 +1336,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { struct OpaqueTypesVisitor<'tcx> { types: FxHashMap>, - expected: FxHashMap>, - found: FxHashMap>, + expected: FxHashMap>, + found: FxHashMap>, ignore_span: Span, tcx: TyCtxt<'tcx>, } @@ -1354,6 +1356,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ignore_span, tcx, }; + // The visitor puts all the relevant encountered types in `self.types`, but in + // here we want to visit two separate types with no relation to each other, so we + // move the results from `types` to `expected` or `found` as appropriate. expected.visit_with(&mut types_visitor); std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types); found.visit_with(&mut types_visitor); @@ -1362,28 +1367,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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!( - "{}{}{} {}{}", - if sp.is_desugaring(DesugaringKind::Async) { - "the `Output` of this `async fn`'s " - } else if count == 1 { - "the " - } else { - "" - }, - if count > 1 { "one of the " } else { "" }, - target, - key.descr(), - pluralize!(count), - ), - ); - } + self.add_labels_for_types(err, "expected", &self.expected); + self.add_labels_for_types(err, "found", &self.found); + } + + fn add_labels_for_types( + &self, + err: &mut DiagnosticBuilder<'_>, + target: &str, + types: &FxHashMap>, + ) { + for (key, values) in types.iter() { + let count = values.len(); + let kind = key.descr(); + for sp in values { + err.span_label( + *sp, + format!( + "{}{}{} {}{}", + if sp.is_desugaring(DesugaringKind::Async) { + "the `Output` of this `async fn`'s " + } else if count == 1 { + "the " + } else { + "" + }, + if count > 1 { "one of the " } else { "" }, + target, + key, + pluralize!(count), + ), + ); } } } From 705e0874de4787dd65eb8484fd67ad635e136c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2020 09:26:47 -0800 Subject: [PATCH 7/8] reduce code duplication --- src/librustc/infer/error_reporting/mod.rs | 70 +++++++++++------------ src/librustc/traits/error_reporting.rs | 13 +---- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index b6d6ca0dcef72..27523b1e689e2 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1303,39 +1303,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } - /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks - /// extra information about each type, but we only care about the category. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - enum TyCategory { - Closure, - Opaque, - Generator, - Foreign, - } - - impl TyCategory { - fn descr(&self) -> &'static str { - match self { - Self::Closure => "closure", - Self::Opaque => "opaque type", - Self::Generator => "generator", - Self::Foreign => "foreign type", - } - } - - fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { - match ty.kind { - ty::Closure(def_id, _) => Some((Self::Closure, def_id)), - ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), - ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), - ty::Foreign(def_id) => Some((Self::Foreign, def_id)), - _ => None, - } - } - } - struct OpaqueTypesVisitor<'tcx> { - types: FxHashMap>, + types: FxHashMap>, expected: FxHashMap>, found: FxHashMap>, ignore_span: Span, @@ -1375,7 +1344,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, target: &str, - types: &FxHashMap>, + types: &FxHashMap>, ) { for (key, values) in types.iter() { let count = values.len(); @@ -1394,7 +1363,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, if count > 1 { "one of the " } else { "" }, target, - key, + kind, pluralize!(count), ), ); @@ -1405,7 +1374,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - if let Some((kind, def_id)) = TyKind::from_ty(t) { + if let Some((kind, def_id)) = TyCategory::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: // @@ -2067,3 +2036,34 @@ impl<'tcx> ObligationCause<'tcx> { } } } + +/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks +/// extra information about each type, but we only care about the category. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +crate enum TyCategory { + Closure, + Opaque, + Generator, + Foreign, +} + +impl TyCategory { + fn descr(&self) -> &'static str { + match self { + Self::Closure => "closure", + Self::Opaque => "opaque type", + Self::Generator => "generator", + Self::Foreign => "foreign type", + } + } + + pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { + match ty.kind { + ty::Closure(def_id, _) => Some((Self::Closure, def_id)), + ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), + ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), + ty::Foreign(def_id) => Some((Self::Foreign, def_id)), + _ => None, + } + } +} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8c2cc412a480b..a42ddbbbcc6a3 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -6,7 +6,7 @@ use super::{ TraitNotObjectSafe, }; -use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode; +use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt}; use crate::mir::interpret::ErrorHandled; @@ -676,15 +676,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(t) => Some(t), None => { let ty = parent_trait_ref.skip_binder().self_ty(); - let span = if let ty::Closure(def_id, _) - | ty::Opaque(def_id, _) - | ty::Generator(def_id, ..) - | ty::Foreign(def_id) = ty.kind - { - Some(self.tcx.def_span(def_id)) - } else { - None - }; + let span = + TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id)); Some((ty.to_string(), span)) } } From 33ae3220b638551834fddf5c0658563d8a52e89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2020 09:28:01 -0800 Subject: [PATCH 8/8] remove unnecessary `Debug` --- src/librustc/infer/error_reporting/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 27523b1e689e2..5e5f39e6c7a22 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -2039,7 +2039,7 @@ impl<'tcx> ObligationCause<'tcx> { /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks /// extra information about each type, but we only care about the category. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] crate enum TyCategory { Closure, Opaque,