Skip to content

Commit 14dc34d

Browse files
authored
Rollup merge of #72260 - csmoe:issue-69276, r=estebank
Spell out `Self` in async function return Closes #69276 r? @tmandry
2 parents 219380d + 9be6353 commit 14dc34d

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+
E0760: include_str!("./error_codes/E0760.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,E0760,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
@@ -1623,12 +1623,17 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
16231623
struct ProhibitOpaqueVisitor<'tcx> {
16241624
opaque_identity_ty: Ty<'tcx>,
16251625
generics: &'tcx ty::Generics,
1626+
ty: Option<Ty<'tcx>>,
16261627
};
16271628

16281629
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
16291630
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
16301631
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
1631-
if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
1632+
if t != self.opaque_identity_ty && t.super_visit_with(self) {
1633+
self.ty = Some(t);
1634+
return true;
1635+
}
1636+
false
16321637
}
16331638

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

1654-
let prohibit_opaque = match item.kind {
1655-
ItemKind::OpaqueTy(hir::OpaqueTy {
1656-
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
1657-
..
1658-
}) => {
1659-
let mut visitor = ProhibitOpaqueVisitor {
1660-
opaque_identity_ty: tcx.mk_opaque(
1661-
def_id.to_def_id(),
1662-
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
1663-
),
1664-
generics: tcx.generics_of(def_id),
1665-
};
1666-
debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
1667-
1668-
tcx.predicates_of(def_id)
1669-
.predicates
1670-
.iter()
1671-
.any(|(predicate, _)| predicate.visit_with(&mut visitor))
1672-
}
1673-
_ => false,
1674-
};
1675-
1676-
debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
1677-
if prohibit_opaque {
1678-
let is_async = match item.kind {
1679-
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
1680-
hir::OpaqueTyOrigin::AsyncFn => true,
1681-
_ => false,
1682-
},
1683-
_ => unreachable!(),
1659+
if let ItemKind::OpaqueTy(hir::OpaqueTy {
1660+
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
1661+
..
1662+
}) = item.kind
1663+
{
1664+
let mut visitor = ProhibitOpaqueVisitor {
1665+
opaque_identity_ty: tcx.mk_opaque(
1666+
def_id.to_def_id(),
1667+
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
1668+
),
1669+
generics: tcx.generics_of(def_id),
1670+
ty: None,
16841671
};
1672+
let prohibit_opaque = tcx
1673+
.predicates_of(def_id)
1674+
.predicates
1675+
.iter()
1676+
.any(|(predicate, _)| predicate.visit_with(&mut visitor));
1677+
debug!(
1678+
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
1679+
prohibit_opaque, visitor
1680+
);
16851681

1686-
tcx.sess.span_err(
1687-
span,
1688-
&format!(
1689-
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
1682+
if prohibit_opaque {
1683+
let is_async = match item.kind {
1684+
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
1685+
hir::OpaqueTyOrigin::AsyncFn => true,
1686+
_ => false,
1687+
},
1688+
_ => unreachable!(),
1689+
};
1690+
1691+
let mut err = struct_span_err!(
1692+
tcx.sess,
1693+
span,
1694+
E0760,
1695+
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
16901696
a parent scope",
1691-
if is_async { "async fn" } else { "impl Trait" },
1692-
),
1693-
);
1697+
if is_async { "async fn" } else { "impl Trait" },
1698+
);
1699+
1700+
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
1701+
if snippet == "Self" {
1702+
if let Some(ty) = visitor.ty {
1703+
err.span_suggestion(
1704+
span,
1705+
"consider spelling out the type instead",
1706+
format!("{:?}", ty),
1707+
Applicability::MaybeIncorrect,
1708+
);
1709+
}
1710+
}
1711+
}
1712+
err.emit();
1713+
}
16941714
}
16951715
}
16961716

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[E0760]: `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 E0760`.

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[E0760]: `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, E0760.
47+
For more information about an error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)