Skip to content

Commit

Permalink
spell out nested self type
Browse files Browse the repository at this point in the history
  • Loading branch information
csmoe committed Feb 12, 2021
1 parent 05704ec commit ed40b95
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 9 deletions.
47 changes: 38 additions & 9 deletions compiler/rustc_typeck/src/check/check.rs
Expand Up @@ -7,6 +7,7 @@ use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemKind, Node};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
Expand Down Expand Up @@ -557,6 +558,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
);

if let Some(ty) = prohibit_opaque.break_value() {
let mut visitor = SelfTySpanVisitor { tcx, selfty_spans: vec![] };
visitor.visit_item(&item);
let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
Expand All @@ -573,15 +576,13 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
if is_async { "async fn" } else { "impl Trait" },
);

if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
if snippet == "Self" {
err.span_suggestion(
span,
"consider spelling out the type instead",
format!("{:?}", ty),
Applicability::MaybeIncorrect,
);
}
for span in visitor.selfty_spans {
err.span_suggestion(
span,
"consider spelling out the type instead",
format!("{:?}", ty),
Applicability::MaybeIncorrect,
);
}
err.emit();
}
Expand Down Expand Up @@ -1590,3 +1591,31 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
}
err.emit();
}

struct SelfTySpanVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
selfty_spans: Vec<Span>,
}

impl Visitor<'tcx> for SelfTySpanVisitor<'tcx> {
type Map = rustc_middle::hir::map::Map<'tcx>;

fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
}

fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
[segment]
if segment.res.map(|res| matches!(res, Res::SelfTy(_, _))).unwrap_or(false) =>
{
self.selfty_spans.push(path.span);
}
_ => {}
},
_ => {}
}
hir::intravisit::walk_ty(self, arg);
}
}
11 changes: 11 additions & 0 deletions src/test/ui/async-await/issues/issue-78600.stderr
@@ -0,0 +1,11 @@
error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
--> $DIR/issue-78600.rs:6:33
|
LL | async fn new(i: &'a i32) -> Result<Self, ()> {
| ^^^^^^^----^^^^^
| |
| help: consider spelling out the type instead: `std::result::Result<S<'a>, ()>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0760`.

0 comments on commit ed40b95

Please sign in to comment.