name async generators something more human friendly in type error diagnostics

This commit is contained in:
Gus Wynn 2021-01-28 18:16:52 -08:00
parent b05fd2a15d
commit c28d86c53b
8 changed files with 103 additions and 17 deletions

View File

@ -1274,7 +1274,7 @@ pub fn generator_kind(&self) -> Option<GeneratorKind> {
}
/// The type of source expression that caused this generator to be created.
#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
pub enum GeneratorKind {
/// An explicit `async` block or the body of an async function.
Async(AsyncGeneratorKind),
@ -1292,12 +1292,21 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
impl GeneratorKind {
pub fn descr(&self) -> &'static str {
match self {
GeneratorKind::Async(ask) => ask.descr(),
GeneratorKind::Gen => "generator",
}
}
}
/// In the case of a generator created as part of an async construct,
/// which kind of async construct caused it to be created?
///
/// This helps error messages but is also used to drive coercions in
/// type-checking (see #60424).
#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
pub enum AsyncGeneratorKind {
/// An explicit `async` block written by the user.
Block,
@ -1319,6 +1328,16 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
impl AsyncGeneratorKind {
pub fn descr(&self) -> &'static str {
match self {
AsyncGeneratorKind::Block => "`async` block",
AsyncGeneratorKind::Closure => "`async` closure body",
AsyncGeneratorKind::Fn => "`async fn` body",
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum BodyOwnerKind {
/// Functions and methods.

View File

@ -1509,7 +1509,7 @@ fn add_labels_for_types(
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let Some((kind, def_id)) = TyCategory::from_ty(t) {
if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
let span = self.tcx.def_span(def_id);
// Avoid cluttering the output when the "found" and error span overlap:
//
@ -1582,11 +1582,11 @@ enum Mismatch<'a> {
};
if let Some((expected, found)) = expected_found {
let expected_label = match exp_found {
Mismatch::Variable(ef) => ef.expected.prefix_string(),
Mismatch::Variable(ef) => ef.expected.prefix_string(self.tcx),
Mismatch::Fixed(s) => s.into(),
};
let found_label = match exp_found {
Mismatch::Variable(ef) => ef.found.prefix_string(),
Mismatch::Variable(ef) => ef.found.prefix_string(self.tcx),
Mismatch::Fixed(s) => s.into(),
};
let exp_found = match exp_found {
@ -2436,7 +2436,7 @@ fn as_requirement_str(&self) -> &'static str {
pub enum TyCategory {
Closure,
Opaque,
Generator,
Generator(hir::GeneratorKind),
Foreign,
}
@ -2445,16 +2445,18 @@ fn descr(&self) -> &'static str {
match self {
Self::Closure => "closure",
Self::Opaque => "opaque type",
Self::Generator => "generator",
Self::Generator(gk) => gk.descr(),
Self::Foreign => "foreign type",
}
}
pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
pub fn from_ty(tcx: TyCtxt<'_>, 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::Generator(def_id, ..) => {
Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
}
ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
_ => None,
}

View File

@ -383,7 +383,7 @@ pub fn extract_inference_diagnostics_data(
InferenceDiagnosticsData {
name: s,
span: None,
kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() },
kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
parent: None,
}
}

View File

@ -264,7 +264,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
}
}
ty::Closure(..) => "closure".into(),
ty::Generator(..) => "generator".into(),
ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
ty::GeneratorWitness(..) => "generator witness".into(),
ty::Tuple(..) => "tuple".into(),
ty::Infer(ty::TyVar(_)) => "inferred type".into(),
@ -282,7 +282,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
}
}
pub fn prefix_string(&self) -> Cow<'static, str> {
pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
match *self.kind() {
ty::Infer(_)
| ty::Error(_)
@ -308,7 +308,7 @@ pub fn prefix_string(&self) -> Cow<'static, str> {
ty::FnPtr(_) => "fn pointer".into(),
ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) => "closure".into(),
ty::Generator(..) => "generator".into(),
ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
ty::GeneratorWitness(..) => "generator witness".into(),
ty::Tuple(..) => "tuple".into(),
ty::Placeholder(..) => "higher-ranked type".into(),

View File

@ -1366,8 +1366,8 @@ fn get_parent_trait_ref(
Some(t) => Some(t),
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));
let span = TyCategory::from_ty(self.tcx, ty)
.map(|(_, def_id)| self.tcx.def_span(def_id));
Some((ty.to_string(), span))
}
}

View File

@ -390,7 +390,7 @@ pub fn report_method_error<'b>(
"no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
actual.prefix_string(),
actual.prefix_string(self.tcx),
ty_str,
);
if let Mode::MethodCall = mode {
@ -728,7 +728,7 @@ trait bound{s}",
.map(|(_, path)| path)
.collect::<Vec<_>>()
.join("\n");
let actual_prefix = actual.prefix_string();
let actual_prefix = actual.prefix_string(self.tcx);
err.set_primary_message(&format!(
"the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
));

View File

@ -0,0 +1,16 @@
// edition:2018
#![feature(async_closure)]
use std::future::Future;
async fn one() {}
async fn two() {}
fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
fn main() {
fun(async {}, async {});
//~^ ERROR mismatched types
fun(one(), two());
//~^ ERROR mismatched types
fun((async || {})(), (async || {})());
//~^ ERROR mismatched types
}

View File

@ -0,0 +1,49 @@
error[E0308]: mismatched types
--> $DIR/generator-desc.rs:10:25
|
LL | fun(async {}, async {});
| -- ^^ expected `async` block, found a different `async` block
| |
| the expected `async` block
|
= note: expected `async` block `[static generator@$DIR/generator-desc.rs:10:15: 10:17]`
found `async` block `[static generator@$DIR/generator-desc.rs:10:25: 10:27]`
error[E0308]: mismatched types
--> $DIR/generator-desc.rs:12:16
|
LL | async fn one() {}
| - the `Output` of this `async fn`'s expected opaque type
LL | async fn two() {}
| - the `Output` of this `async fn`'s found opaque type
...
LL | fun(one(), two());
| ^^^^^ expected opaque type, found a different opaque type
|
= note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
= help: consider `await`ing on both `Future`s
= note: distinct uses of `impl Trait` result in different opaque types
error[E0308]: mismatched types
--> $DIR/generator-desc.rs:14:26
|
LL | fun((async || {})(), (async || {})());
| -- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
| |
| the expected `async` closure body
|
::: $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| -------------------------------
| |
| the expected opaque type
| the found opaque type
|
= note: expected opaque type `impl Future` (`async` closure body)
found opaque type `impl Future` (`async` closure body)
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.