suggest on Self return type

This commit is contained in:
csmoe 2020-05-16 16:08:56 +08:00
parent 008d90a66a
commit 633e4aafe6
2 changed files with 43 additions and 36 deletions

View file

@ -1639,51 +1639,56 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
struct ProhibitOpaqueVisitor<'tcx> {
opaque_identity_ty: Ty<'tcx>,
generics: &'tcx ty::Generics,
ty: Option<Ty<'tcx>>,
};
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
self.ty = Some(t);
if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
return *index < self.generics.parent_count as u32;
let found_lifetime = *index < self.generics.parent_count as u32;
if !found_lifetime {
self.ty = None;
}
return found_lifetime;
}
r.super_visit_with(self)
}
}
let mut visitor = ProhibitOpaqueVisitor {
opaque_identity_ty: tcx.mk_opaque(
def_id.to_def_id(),
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
),
generics: tcx.generics_of(def_id),
ty: None,
};
debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
let prohibit_opaque = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy {
bounds,
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
..
}) => {
let mut visitor = ProhibitOpaqueVisitor {
opaque_identity_ty: tcx.mk_opaque(
def_id.to_def_id(),
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
),
generics: tcx.generics_of(def_id),
};
debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
for bound in bounds {
debug!("check_opaque_for_inheriting_lifetimes: {:?}", bound.trait_ref());
}
tcx.predicates_of(def_id)
.predicates
.iter()
.any(|(predicate, _)| predicate.visit_with(&mut visitor))
}
}) => tcx
.predicates_of(def_id)
.predicates
.iter()
.any(|(predicate, _)| predicate.visit_with(&mut visitor)),
_ => false,
};
debug!(
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
prohibit_opaque, visitor
);
debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
if prohibit_opaque {
let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
@ -1693,14 +1698,28 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
_ => unreachable!(),
};
tcx.sess.span_err(
let mut err = struct_span_err!(
tcx.sess,
span,
&format!(
E0754,
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
a parent scope",
if is_async { "async fn" } else { "impl Trait" },
)
);
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
if snippet == "Self" {
if let Some(ty) = visitor.ty {
err.span_suggestion(
span,
"consider spelling out the type instead",
format!("{:?}", ty),
Applicability::MaybeIncorrect,
);
}
}
}
err.emit();
}
}

View file

@ -1,12 +0,0 @@
// edition:2018
struct S<'a>(&'a i32);
impl<'a> S<'a> {
async fn new(i: &'a i32) -> Self {
//~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
S(&22)
}
}
fn main() {}