提交 66e41bc6 编写于 作者: G Giles Cope

Improved error message when type must be bound due to generator.

Error now mentions type var name and span is highlighted.
上级 3bee49f4
......@@ -2043,6 +2043,36 @@ struct Foo {
transparent wrapper around a float. This can make a difference for the ABI.
"##,
E0698: r##"
When using generators (or async) all type variables must be bound so a
generator can be constructed.
Erroneous code example:
```edition2018,compile-fail,E0698
#![feature(futures_api, async_await, await_macro)]
async fn bar<T>() -> () {}
async fn foo() {
await!(bar()); // error: cannot infer type for `T`
}
```
In the above example `T` is unknowable by the compiler.
To fix this you must bind `T` to a concrete type such as `String`
so that a generator can then be constructed:
```edition2018
#![feature(futures_api, async_await, await_macro)]
async fn bar<T>() -> () {}
async fn foo() {
await!(bar::<String>());
// ^^^^^^^^ specify type explicitly
}
```
"##,
E0700: r##"
The `impl Trait` return type captures lifetime parameters that do not
appear within the `impl Trait` itself.
......
......@@ -88,23 +88,17 @@ pub fn extract_type_name(
s
}
pub fn need_type_info_err(&self,
body_id: Option<hir::BodyId>,
span: Span,
ty: Ty<'tcx>)
-> DiagnosticBuilder<'gcx> {
pub fn need_type_info_err(
&self,
body_id: Option<hir::BodyId>,
span: Span,
ty: Ty<'tcx>
) -> DiagnosticBuilder<'gcx> {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = self.extract_type_name(&ty, None);
let mut err_span = span;
let mut labels = vec![(
span,
if &name == "_" {
"cannot infer type".to_owned()
} else {
format!("cannot infer type for `{}`", name)
},
)];
let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
let mut local_visitor = FindLocalByTypeVisitor {
infcx: &self,
......@@ -166,4 +160,28 @@ pub fn need_type_info_err(&self,
err
}
pub fn need_type_info_err_in_generator(
&self,
span: Span,
ty: Ty<'tcx>
) -> DiagnosticBuilder<'gcx> {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = self.extract_type_name(&ty, None);
let mut err = struct_span_err!(self.tcx.sess,
span,
E0698,
"type inside generator must be known in this context");
err.span_label(span, InferCtxt::missing_type_msg(&name));
err
}
fn missing_type_msg(type_name: &str) -> String {
if type_name == "_" {
"cannot infer type".to_owned()
} else {
format!("cannot infer type for `{}`", type_name)
}
}
}
......@@ -1312,17 +1312,18 @@ pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
value.fold_with(&mut r)
}
/// Returns `true` if `T` contains unresolved type variables. In the
/// Returns first unresolved variable contained in `T`. In the
/// process of visiting `T`, this will resolve (where possible)
/// type variables in `T`, but it never constructs the final,
/// resolved type, so it's more efficient than
/// `resolve_type_vars_if_possible()`.
pub fn any_unresolved_type_vars<T>(&self, value: &T) -> bool
pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)>
where
T: TypeFoldable<'tcx>,
{
let mut r = resolve::UnresolvedTypeFinder::new(self);
value.visit_with(&mut r)
value.visit_with(&mut r);
r.first_unresolved
}
pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
......
use super::{InferCtxt, FixupError, FixupResult};
use super::{InferCtxt, FixupError, FixupResult, Span, type_variable::TypeVariableOrigin};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::fold::{TypeFolder, TypeVisitor};
......@@ -77,17 +77,20 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
///////////////////////////////////////////////////////////////////////////
// UNRESOLVED TYPE FINDER
/// The unresolved type **finder** walks your type and searches for
/// type variables that don't yet have a value. They get pushed into a
/// vector. It does not construct the fully resolved type (which might
/// The unresolved type **finder** walks a type searching for
/// type variables that don't yet have a value. The first unresolved type is stored.
/// It does not construct the fully resolved type (which might
/// involve some hashing and so forth).
pub struct UnresolvedTypeFinder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
/// Used to find the type parameter name and location for error reporting.
pub first_unresolved: Option<(Ty<'tcx>,Option<Span>)>,
}
impl<'a, 'gcx, 'tcx> UnresolvedTypeFinder<'a, 'gcx, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
UnresolvedTypeFinder { infcx }
UnresolvedTypeFinder { infcx, first_unresolved: None }
}
}
......@@ -95,22 +98,37 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'gcx, 'tcx>
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
let t = self.infcx.shallow_resolve(t);
if t.has_infer_types() {
if let ty::Infer(_) = t.sty {
if let ty::Infer(infer_ty) = t.sty {
// Since we called `shallow_resolve` above, this must
// be an (as yet...) unresolved inference variable.
true
let ty_var_span =
if let ty::TyVar(ty_vid) = infer_ty {
let ty_vars = self.infcx.type_variables.borrow();
if let TypeVariableOrigin::TypeParameterDefinition(span, _name)
= *ty_vars.var_origin(ty_vid)
{
Some(span)
} else {
None
}
} else {
None
};
self.first_unresolved = Some((t, ty_var_span));
true // Halt visiting.
} else {
// Otherwise, visit its contents.
t.super_visit_with(self)
}
} else {
// Micro-optimize: no inference types at all Can't have unresolved type
// variables, no need to visit the contents.
// All type variables in inference types must already be resolved,
// - no need to visit the contents, continue visiting.
false
}
}
}
///////////////////////////////////////////////////////////////////////////
// FULL TYPE RESOLUTION
......
......@@ -594,7 +594,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
// Once we have inferred everything we need to know, we
// can ignore the `obligations` from that point on.
if !infcx.any_unresolved_type_vars(&ty.value) {
if infcx.unresolved_type_vars(&ty.value).is_none() {
infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty);
// No need to extend `obligations`.
} else {
......@@ -704,7 +704,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
result: &NormalizedTy<'tcx>)
-> NormalizedTy<'tcx> {
if !infcx.any_unresolved_type_vars(&result.value) {
if infcx.unresolved_type_vars(&result.value).is_none() {
return NormalizedTy { value: result.value, obligations: vec![] };
}
......@@ -722,7 +722,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
// but we have `T: Foo<X = ?1>` and `?1: Bar<X =
// ?0>`).
ty::Predicate::Projection(ref data) =>
infcx.any_unresolved_type_vars(&data.ty()),
infcx.unresolved_type_vars(&data.ty()).is_some(),
// We are only interested in `T: Foo<X = U>` predicates, whre
// `U` references one of `unresolved_type_vars`. =)
......
......@@ -54,12 +54,16 @@ fn record(&mut self,
debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
expr, scope, ty, self.expr_count, yield_span);
if self.fcx.any_unresolved_type_vars(&ty) {
let mut err = struct_span_err!(self.fcx.tcx.sess, source_span, E0698,
"type inside generator must be known in this context");
err.span_note(yield_span,
"the type is part of the generator because of this `yield`");
err.emit();
if let Some((unresolved_type, unresolved_type_span)) =
self.fcx.unresolved_type_vars(&ty)
{
// If unresolved type isn't a ty_var then unresolved_type_span is None
self.fcx.need_type_info_err_in_generator(
unresolved_type_span.unwrap_or(yield_span),
unresolved_type)
.span_note(yield_span,
"the type is part of the generator because of this `yield`")
.emit();
} else {
// Map the type to the number of types added before it
let entries = self.types.len();
......
......@@ -4728,7 +4728,6 @@ fn make_recursive_type() -> impl Sized {
E0640, // infer outlives requirements
E0641, // cannot cast to/from a pointer with an unknown kind
E0645, // trait aliases not finished
E0698, // type inside generator must be known in this context
E0719, // duplicate values for associated type binding
E0722, // Malformed #[optimize] attribute
E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions
......
// Provoke an unresolved type error (T).
// Error message should pinpoint the type parameter T as needing to be bound
// (rather than give a general error message)
// edition:2018
#![feature(futures_api, async_await, await_macro)]
async fn bar<T>() -> () {}
async fn foo() {
await!(bar());
//~^ ERROR type inside generator must be known in this context
//~| NOTE cannot infer type for `T`
//~| NOTE the type is part of the generator because of this `yield`
}
fn main() {}
error[E0698]: type inside generator must be known in this context
--> $DIR/unresolved_type_param.rs:9:16
|
LL | await!(bar());
| ^^^ cannot infer type for `T`
|
note: the type is part of the generator because of this `yield`
--> $DIR/unresolved_type_param.rs:9:9
|
LL | await!(bar());
| ^^^^^^^^^^^^^^
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0698`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册