Skip to content

Commit

Permalink
Rollup merge of #72260 - csmoe:issue-69276, r=estebank
Browse files Browse the repository at this point in the history
Spell out `Self` in async function return

Closes #69276
r? @tmandry
  • Loading branch information
Dylan-DPC authored Jun 5, 2020
2 parents 219380d + 9be6353 commit 14dc34d
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 42 deletions.
1 change: 1 addition & 0 deletions src/librustc_error_codes/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ E0751: include_str!("./error_codes/E0751.md"),
E0752: include_str!("./error_codes/E0752.md"),
E0753: include_str!("./error_codes/E0753.md"),
E0754: include_str!("./error_codes/E0754.md"),
E0760: include_str!("./error_codes/E0760.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
Expand Down
32 changes: 32 additions & 0 deletions src/librustc_error_codes/error_codes/E0760.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
`async fn`/`impl trait` return type cannot contain a projection
or `Self` that references lifetimes from a parent scope.

Erroneous code example:

```compile_fail,E0760,edition2018
struct S<'a>(&'a i32);
impl<'a> S<'a> {
async fn new(i: &'a i32) -> Self {
S(&22)
}
}
```

To fix this error we need to spell out `Self` to `S<'a>`:

```edition2018
struct S<'a>(&'a i32);
impl<'a> S<'a> {
async fn new(i: &'a i32) -> S<'a> {
S(&22)
}
}
```

This will be allowed at some point in the future,
but the implementation is not yet complete.
See the [issue-61949] for this limitation.

[issue-61949]: https:/rust-lang/rust/issues/61949
96 changes: 58 additions & 38 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1623,12 +1623,17 @@ 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);
if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
if t != self.opaque_identity_ty && t.super_visit_with(self) {
self.ty = Some(t);
return true;
}
false
}

fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
Expand All @@ -1651,46 +1656,61 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
}
}

let prohibit_opaque = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy {
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);

tcx.predicates_of(def_id)
.predicates
.iter()
.any(|(predicate, _)| predicate.visit_with(&mut visitor))
}
_ => false,
};

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 {
hir::OpaqueTyOrigin::AsyncFn => true,
_ => false,
},
_ => unreachable!(),
if let ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
..
}) = item.kind
{
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,
};
let prohibit_opaque = tcx
.predicates_of(def_id)
.predicates
.iter()
.any(|(predicate, _)| predicate.visit_with(&mut visitor));
debug!(
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
prohibit_opaque, visitor
);

tcx.sess.span_err(
span,
&format!(
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
if prohibit_opaque {
let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
hir::OpaqueTyOrigin::AsyncFn => true,
_ => false,
},
_ => unreachable!(),
};

let mut err = struct_span_err!(
tcx.sess,
span,
E0760,
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
a parent scope",
if is_async { "async fn" } else { "impl Trait" },
),
);
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();
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/test/ui/async-await/issue-61949-self-return-type.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
--> $DIR/issue-61949-self-return-type.rs:11:40
|
LL | pub async fn new(_bar: &'a i32) -> Self {
| ^^^^
| ^^^^ help: consider spelling out the type instead: `Foo<'a>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0760`.
5 changes: 3 additions & 2 deletions src/test/ui/impl-trait/bound-normalization-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
| ^^^^^^^^^^^^

error: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
error[E0760]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
--> $DIR/bound-normalization-fail.rs:43:41
|
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
Expand All @@ -43,4 +43,5 @@ LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::

error: aborting due to 3 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0271`.
Some errors have detailed explanations: E0271, E0760.
For more information about an error, try `rustc --explain E0271`.

0 comments on commit 14dc34d

Please sign in to comment.