Skip to content

Commit 0aecafa

Browse files
authored
Rollup merge of rust-lang#72260 - csmoe:issue-69276, r=tmandry
Spell out `Self` in async function return Closes rust-lang#69276 r? @tmandry
2 parents 96de37e + 2f311b0 commit 0aecafa

File tree

5 files changed

+97
-42
lines changed

5 files changed

+97
-42
lines changed

src/librustc_error_codes/error_codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ E0751: include_str!("./error_codes/E0751.md"),
437437
E0752: include_str!("./error_codes/E0752.md"),
438438
E0753: include_str!("./error_codes/E0753.md"),
439439
E0754: include_str!("./error_codes/E0754.md"),
440+
E0755: include_str!("./error_codes/E0755.md"),
440441
;
441442
// E0006, // merged with E0005
442443
// E0008, // cannot bind by-move into a pattern guard
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
`async fn`/`impl trait` return type cannot contain a projection
2+
or `Self` that references lifetimes from a parent scope.
3+
4+
Erroneous code example:
5+
6+
```compile_fail,E0755,edition2018
7+
struct S<'a>(&'a i32);
8+
9+
impl<'a> S<'a> {
10+
async fn new(i: &'a i32) -> Self {
11+
S(&22)
12+
}
13+
}
14+
```
15+
16+
To fix this error we need to spell out `Self` to `S<'a>`:
17+
18+
```edition2018
19+
struct S<'a>(&'a i32);
20+
21+
impl<'a> S<'a> {
22+
async fn new(i: &'a i32) -> S<'a> {
23+
S(&22)
24+
}
25+
}
26+
```
27+
28+
This will be allowed at some point in the future,
29+
but the implementation is not yet complete.
30+
See the [issue-61949] for this limitation.
31+
32+
[issue-61949]: https://github.com/rust-lang/rust/issues/61949

src/librustc_typeck/check/mod.rs

+58-38
Original file line numberDiff line numberDiff line change
@@ -1632,12 +1632,17 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
16321632
struct ProhibitOpaqueVisitor<'tcx> {
16331633
opaque_identity_ty: Ty<'tcx>,
16341634
generics: &'tcx ty::Generics,
1635+
ty: Option<Ty<'tcx>>,
16351636
};
16361637

16371638
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
16381639
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
16391640
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
1640-
if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
1641+
if t != self.opaque_identity_ty && t.super_visit_with(self) {
1642+
self.ty = Some(t);
1643+
return true;
1644+
}
1645+
false
16411646
}
16421647

16431648
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
@@ -1660,46 +1665,61 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
16601665
}
16611666
}
16621667

1663-
let prohibit_opaque = match item.kind {
1664-
ItemKind::OpaqueTy(hir::OpaqueTy {
1665-
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
1666-
..
1667-
}) => {
1668-
let mut visitor = ProhibitOpaqueVisitor {
1669-
opaque_identity_ty: tcx.mk_opaque(
1670-
def_id.to_def_id(),
1671-
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
1672-
),
1673-
generics: tcx.generics_of(def_id),
1674-
};
1675-
debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
1676-
1677-
tcx.predicates_of(def_id)
1678-
.predicates
1679-
.iter()
1680-
.any(|(predicate, _)| predicate.visit_with(&mut visitor))
1681-
}
1682-
_ => false,
1683-
};
1684-
1685-
debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
1686-
if prohibit_opaque {
1687-
let is_async = match item.kind {
1688-
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
1689-
hir::OpaqueTyOrigin::AsyncFn => true,
1690-
_ => false,
1691-
},
1692-
_ => unreachable!(),
1668+
if let ItemKind::OpaqueTy(hir::OpaqueTy {
1669+
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
1670+
..
1671+
}) = item.kind
1672+
{
1673+
let mut visitor = ProhibitOpaqueVisitor {
1674+
opaque_identity_ty: tcx.mk_opaque(
1675+
def_id.to_def_id(),
1676+
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
1677+
),
1678+
generics: tcx.generics_of(def_id),
1679+
ty: None,
16931680
};
1681+
let prohibit_opaque = tcx
1682+
.predicates_of(def_id)
1683+
.predicates
1684+
.iter()
1685+
.any(|(predicate, _)| predicate.visit_with(&mut visitor));
1686+
debug!(
1687+
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
1688+
prohibit_opaque, visitor
1689+
);
16941690

1695-
tcx.sess.span_err(
1696-
span,
1697-
&format!(
1698-
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
1691+
if prohibit_opaque {
1692+
let is_async = match item.kind {
1693+
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
1694+
hir::OpaqueTyOrigin::AsyncFn => true,
1695+
_ => false,
1696+
},
1697+
_ => unreachable!(),
1698+
};
1699+
1700+
let mut err = struct_span_err!(
1701+
tcx.sess,
1702+
span,
1703+
E0755,
1704+
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
16991705
a parent scope",
1700-
if is_async { "async fn" } else { "impl Trait" },
1701-
),
1702-
);
1706+
if is_async { "async fn" } else { "impl Trait" },
1707+
);
1708+
1709+
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
1710+
if snippet == "Self" {
1711+
if let Some(ty) = visitor.ty {
1712+
err.span_suggestion(
1713+
span,
1714+
"consider spelling out the type instead",
1715+
format!("{:?}", ty),
1716+
Applicability::MaybeIncorrect,
1717+
);
1718+
}
1719+
}
1720+
}
1721+
err.emit();
1722+
}
17031723
}
17041724
}
17051725

Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
1+
error[E0755]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
22
--> $DIR/issue-61949-self-return-type.rs:11:40
33
|
44
LL | pub async fn new(_bar: &'a i32) -> Self {
5-
| ^^^^
5+
| ^^^^ help: consider spelling out the type instead: `Foo<'a>`
66

77
error: aborting due to previous error
88

9+
For more information about this error, try `rustc --explain E0755`.

src/test/ui/impl-trait/bound-normalization-fail.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
2121
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
2222
| ^^^^^^^^^^^^
2323

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

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

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

0 commit comments

Comments
 (0)