未验证 提交 aabb0376 编写于 作者: M Mazdak Farrokhzad 提交者: GitHub

Rollup merge of #66463 - estebank:point-at-closure-and-opaque-types, r=Centril

Point at opaque and closure type definitions in type errors

Fixes #57266, fixes #67117.
......@@ -68,9 +68,12 @@
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_data_structures::fx::{FxHashMap, FxHashSet};
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 +1292,8 @@ pub fn note_type_err(
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 +1303,100 @@ pub fn note_type_err(
_ => {}
}
struct OpaqueTypesVisitor<'tcx> {
types: FxHashMap<TyCategory, FxHashSet<Span>>,
expected: FxHashMap<TyCategory, FxHashSet<Span>>,
found: FxHashMap<TyCategory, 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,
};
// 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);
std::mem::swap(&mut types_visitor.found, &mut types_visitor.types);
types_visitor
}
fn report(&self, err: &mut DiagnosticBuilder<'_>) {
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<TyCategory, FxHashSet<Span>>,
) {
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,
kind,
pluralize!(count),
),
);
}
}
}
}
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
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:
//
// 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)
}
}
debug!("note_type_err(diag={:?})", diag);
let (expected_found, exp_found, is_simple_error) = match values {
None => (None, None, false),
......@@ -1306,6 +1405,13 @@ pub fn note_type_err(
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 +1429,6 @@ pub fn note_type_err(
}
};
let span = cause.span(self.tcx);
// Ignore msg for object safe coercion
// since E0038 message will be printed
match terr {
......@@ -1336,7 +1440,6 @@ pub fn note_type_err(
}
}
};
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());
......@@ -1933,3 +2036,34 @@ fn as_requirement_str(&self) -> &'static str {
}
}
}
/// 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(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,
}
}
}
......@@ -6,7 +6,7 @@
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;
......@@ -446,7 +446,7 @@ fn on_unimplemented_note(
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,21 @@ pub fn report_extra_impl_obligation(
}
/// Gets the parent trait chain start
fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option<String> {
fn get_parent_trait_ref(
&self,
code: &ObligationCauseCode<'tcx>,
) -> Option<(String, Option<Span>)> {
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 =
TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
Some((ty.to_string(), span))
}
}
}
_ => None,
......@@ -719,9 +727,15 @@ pub fn report_selection_error(
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 +809,9 @@ pub fn report_selection_error(
} 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());
......
......@@ -4746,14 +4746,13 @@ fn suggest_fn_call(
.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
......
error[E0308]: mismatched types
--> $DIR/dont-suggest-missing-await.rs:14:18
|
LL | async fn make_u32() -> u32 {
| --- the `Output` of this `async fn`'s found opaque type
...
LL | take_u32(x)
| ^ expected `u32`, found opaque type
|
......
......@@ -3,6 +3,9 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::
|
LL | fn is_qux<T: 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`
......
error[E0308]: mismatched types
--> $DIR/suggest-missing-await-closure.rs:16:18
|
LL | async fn make_u32() -> u32 {
| --- the `Output` of this `async fn`'s found opaque type
...
LL | take_u32(x)
| ^
| |
......
error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:13:14
|
LL | async fn make_u32() -> u32 {
| --- the `Output` of this `async fn`'s found opaque type
...
LL | take_u32(x)
| ^
| |
......@@ -13,6 +16,9 @@ LL | take_u32(x)
error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:23:5
|
LL | async fn dummy() {}
| - the `Output` of this `async fn`'s found opaque type
...
LL | dummy()
| ^^^^^^^ expected `()`, found opaque type
|
......
error[E0308]: mismatched types
--> $DIR/closure-reform-bad.rs:11:15
|
LL | let f = |s: &str| println!("{}{}", s, string);
| ------------------------------------- the found closure
LL | call_bare(f)
| ^ expected fn pointer, found closure
|
......
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`
|
......
......@@ -112,6 +112,9 @@ LL | fn send<T: Send>(_: T) {}
...
LL | send(cycle2().clone());
| ^^^^ `std::rc::Rc<std::string::String>` 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<std::string::String>`
= note: required because it appears within the type `impl std::clone::Clone`
......
error[E0277]: `std::rc::Rc<std::cell::Cell<i32>>` 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: Send>(_: T) {}
| ---- ---- required by this bound in `send`
...
......@@ -19,6 +22,9 @@ LL | fn send<T: Send>(_: T) {}
...
LL | send(after());
| ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` 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<std::cell::Cell<i32>>`
= 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>>]`
......
error[E0308]: mismatched types
--> $DIR/equality2.rs:25:18
|
LL | fn hide<T: Foo>(x: T) -> impl Foo {
| -------- 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 {
| -------- the found opaque type
...
LL | let _: i32 = Leak::leak(hide(0_i32));
| --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
| |
......@@ -25,6 +31,12 @@ 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 {
| --------
| |
| the expected opaque type
| the found opaque type
...
LL | x = (x.1,
| ^^^ expected `u32`, found `i32`
|
......@@ -34,6 +46,12 @@ LL | x = (x.1,
error[E0308]: mismatched types
--> $DIR/equality2.rs:41:10
|
LL | fn hide<T: Foo>(x: T) -> impl Foo {
| --------
| |
| the expected opaque type
| the found opaque type
...
LL | x.0);
| ^^^ expected `i32`, found `u32`
|
......
error[E0308]: mismatched types
--> $DIR/issue-24036.rs:3:9
|
LL | let mut x = |c| c + 1;
| --------- the expected closure
LL | x = |c| c + 1;
| ^^^^^^^^^ expected closure, found a different closure
|
......
......@@ -5,7 +5,9 @@ LL | fn bar<F:FnOnce() + Send>(_: F) { }
| --- ---- required by this bound in `bar`
...
LL | bar(move|| foo(x));
| ^^^ `std::rc::Rc<usize>` cannot be sent between threads safely
| ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`
| |
| `std::rc::Rc<usize>` cannot be sent between threads safely
|
= help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<usize>`
= note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`
......
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<()>`
......
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]`
......
......@@ -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
| ----- the found closure
LL | let _: usize = closure;
| ----- ^^^^^^^
| | |
......
error[E0308]: `if` and `else` have incompatible types
--> $DIR/opaque-type-error.rs:20:9
|
LL | fn thing_two() -> impl Future<Output = Result<(), ()>> {
| ------------------------------------ the found opaque type
...
LL | / if true {
LL | | thing_one()
| | ----------- expected because of this
......
......@@ -11,6 +11,9 @@ LL | let z: i32 = x;
| --- ^ expected `i32`, found opaque type
| |
| expected due to this
...
LL | type WrongGeneric<T> = impl 'static;
| ------------------------------------ the found opaque type
|
= note: expected type `i32`
found opaque type `WrongGeneric::<&{integer}>`
......
......@@ -11,6 +11,9 @@ LL | let z: i32 = x;
| --- ^ expected `i32`, found opaque type
| |
| expected due to this
...
LL | type WrongGeneric<T> = impl 'static;
| ------------------------------------ the found opaque type
|
= note: expected type `i32`
found opaque type `WrongGeneric::<&{integer}>`
......
error[E0308]: mismatched types
--> $DIR/never_reveal_concrete_type.rs:13:27
|
LL | type NoReveal = impl std::fmt::Debug;
| ------------------------------------- the found opaque type
...
LL | let _: &'static str = x;
| ------------ ^ expected `&str`, found opaque type
| |
......
error[E0308]: mismatched types
--> $DIR/no_revealing_outside_defining_module.rs:15:19
|
LL | pub type Boo = impl ::std::fmt::Debug;
| -------------------------------------- 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;
| -------------------------------------- the expected opaque type
...
LL | fn bomp() -> boo::Boo {
| -------- expected `Boo` because of return type
LL | ""
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册