Skip to content

Commit 0938e16

Browse files
committed
Auto merge of rust-lang#101679 - compiler-errors:rpitit-default-body, r=nikomatsakis
Support default-body trait functions with return-position `impl Trait` in traits Introduce a new `Trait` candidate kind for the `ImplTraitInTrait` projection candidate, which just projects an RPITIT down to its opaque type form. This is a hack until we lower RPITITs to regular associated types, after which we will need to rework how these default bodies are type-checked, so comments are left in a few places for us to clean up later. Fixes rust-lang#101665
2 parents c0983a9 + 0eeeea9 commit 0938e16

14 files changed

+163
-126
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+33-23
Original file line numberDiff line numberDiff line change
@@ -522,23 +522,33 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
522522

523523
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
524524
/// projections that would result in "inheriting lifetimes".
525-
pub(super) fn check_opaque<'tcx>(
526-
tcx: TyCtxt<'tcx>,
527-
def_id: LocalDefId,
528-
substs: SubstsRef<'tcx>,
529-
origin: &hir::OpaqueTyOrigin,
530-
) {
531-
let span = tcx.def_span(def_id);
532-
check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
533-
if tcx.type_of(def_id).references_error() {
525+
fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
526+
let item = tcx.hir().item(id);
527+
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
528+
tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item");
529+
return;
530+
};
531+
532+
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
533+
// `async-std` (and `pub async fn` in general).
534+
// Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
535+
// See https://github.com/rust-lang/rust/issues/75100
536+
if tcx.sess.opts.actually_rustdoc {
534537
return;
535538
}
536-
if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
539+
540+
let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id());
541+
let span = tcx.def_span(item.def_id.def_id);
542+
543+
check_opaque_for_inheriting_lifetimes(tcx, item.def_id.def_id, span);
544+
if tcx.type_of(item.def_id.def_id).references_error() {
545+
return;
546+
}
547+
if check_opaque_for_cycles(tcx, item.def_id.def_id, substs, span, &origin).is_err() {
537548
return;
538549
}
539-
check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
550+
check_opaque_meets_bounds(tcx, item.def_id.def_id, substs, span, &origin);
540551
}
541-
542552
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
543553
/// in "inheriting lifetimes".
544554
#[instrument(level = "debug", skip(tcx, span))]
@@ -857,17 +867,17 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
857867
check_union(tcx, id.def_id.def_id);
858868
}
859869
DefKind::OpaqueTy => {
860-
let item = tcx.hir().item(id);
861-
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
862-
return;
863-
};
864-
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
865-
// `async-std` (and `pub async fn` in general).
866-
// Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
867-
// See https://github.com/rust-lang/rust/issues/75100
868-
if !tcx.sess.opts.actually_rustdoc {
869-
let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id());
870-
check_opaque(tcx, item.def_id.def_id, substs, &origin);
870+
check_opaque(tcx, id);
871+
}
872+
DefKind::ImplTraitPlaceholder => {
873+
let parent = tcx.impl_trait_in_trait_parent(id.def_id.to_def_id());
874+
// Only check the validity of this opaque type if the function has a default body
875+
if let hir::Node::TraitItem(hir::TraitItem {
876+
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
877+
..
878+
}) = tcx.hir().get_by_def_id(parent.expect_local())
879+
{
880+
check_opaque(tcx, id);
871881
}
872882
}
873883
DefKind::TyAlias => {

compiler/rustc_hir_analysis/src/collect/type_of.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
340340
..
341341
}) => {
342342
if in_trait {
343-
span_bug!(item.span, "impl-trait in trait has no default")
344-
} else {
345-
find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
343+
assert!(tcx.impl_defaultness(owner).has_value());
346344
}
345+
find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
347346
}
348347
ItemKind::Trait(..)
349348
| ItemKind::TraitAlias(..)

compiler/rustc_middle/src/ty/sty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,7 @@ impl<'tcx> ProjectionTy<'tcx> {
11611161
tcx: TyCtxt<'tcx>,
11621162
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
11631163
let def_id = tcx.parent(self.item_def_id);
1164+
assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
11641165
let trait_generics = tcx.generics_of(def_id);
11651166
(
11661167
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },

compiler/rustc_privacy/src/lib.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,20 @@ where
122122
&mut self,
123123
projection: ty::ProjectionTy<'tcx>,
124124
) -> ControlFlow<V::BreakTy> {
125-
let (trait_ref, assoc_substs) =
126-
projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
125+
let tcx = self.def_id_visitor.tcx();
126+
let (trait_ref, assoc_substs) = if tcx.def_kind(projection.item_def_id)
127+
!= DefKind::ImplTraitPlaceholder
128+
{
129+
projection.trait_ref_and_own_substs(tcx)
130+
} else {
131+
// HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
132+
let def_id = tcx.impl_trait_in_trait_parent(projection.item_def_id);
133+
let trait_generics = tcx.generics_of(def_id);
134+
(
135+
ty::TraitRef { def_id, substs: projection.substs.truncate_to(tcx, trait_generics) },
136+
&projection.substs[trait_generics.count()..],
137+
)
138+
};
127139
self.visit_trait(trait_ref)?;
128140
if self.def_id_visitor.shallow() {
129141
ControlFlow::CONTINUE

compiler/rustc_trait_selection/src/traits/project.rs

+45-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,15 @@ enum ProjectionCandidate<'tcx> {
7272
/// From an "impl" (or a "pseudo-impl" returned by select)
7373
Select(Selection<'tcx>),
7474

75-
ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
75+
ImplTraitInTrait(ImplTraitInTraitCandidate<'tcx>),
76+
}
77+
78+
#[derive(PartialEq, Eq, Debug)]
79+
enum ImplTraitInTraitCandidate<'tcx> {
80+
// The `impl Trait` from a trait function's default body
81+
Trait,
82+
// A concrete type provided from a trait's `impl Trait` from an impl
83+
Impl(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
7684
}
7785

7886
enum ProjectionCandidateSet<'tcx> {
@@ -1319,6 +1327,19 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
13191327
let tcx = selcx.tcx();
13201328
if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
13211329
let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
1330+
// If we are trying to project an RPITIT with trait's default `Self` parameter,
1331+
// then we must be within a default trait body.
1332+
if obligation.predicate.self_ty()
1333+
== ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.item_def_id)
1334+
.type_at(0)
1335+
&& tcx.associated_item(trait_fn_def_id).defaultness(tcx).has_value()
1336+
{
1337+
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
1338+
ImplTraitInTraitCandidate::Trait,
1339+
));
1340+
return;
1341+
}
1342+
13221343
let trait_def_id = tcx.parent(trait_fn_def_id);
13231344
let trait_substs =
13241345
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
@@ -1330,7 +1351,9 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
13301351
let _ =
13311352
selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
13321353
Ok(Some(super::ImplSource::UserDefined(data))) => {
1333-
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
1354+
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
1355+
ImplTraitInTraitCandidate::Impl(data),
1356+
));
13341357
Ok(())
13351358
}
13361359
Ok(None) => {
@@ -1792,9 +1815,18 @@ fn confirm_candidate<'cx, 'tcx>(
17921815
ProjectionCandidate::Select(impl_source) => {
17931816
confirm_select_candidate(selcx, obligation, impl_source)
17941817
}
1795-
ProjectionCandidate::ImplTraitInTrait(data) => {
1818+
ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Impl(data)) => {
17961819
confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
17971820
}
1821+
// If we're projecting an RPITIT for a default trait body, that's just
1822+
// the same def-id, but as an opaque type (with regular RPIT semantics).
1823+
ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Trait) => Progress {
1824+
term: selcx
1825+
.tcx()
1826+
.mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
1827+
.into(),
1828+
obligations: vec![],
1829+
},
17981830
};
17991831

18001832
// When checking for cycle during evaluation, we compare predicates with
@@ -2211,6 +2243,16 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
22112243
return Progress { term: tcx.ty_error().into(), obligations };
22122244
}
22132245

2246+
// Use the default `impl Trait` for the trait, e.g., for a default trait body
2247+
if leaf_def.item.container == ty::AssocItemContainer::TraitContainer {
2248+
return Progress {
2249+
term: tcx
2250+
.mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
2251+
.into(),
2252+
obligations,
2253+
};
2254+
}
2255+
22142256
let impl_fn_def_id = leaf_def.item.def_id;
22152257
let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
22162258

src/test/ui/async-await/async-trait-fn.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
// edition:2018
22
trait T {
33
async fn foo() {} //~ ERROR functions in traits cannot be declared `async`
4-
//~^ ERROR mismatched types
54
async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async`
6-
//~^ ERROR mismatched types
75
async fn baz() { //~ ERROR functions in traits cannot be declared `async`
8-
//~^ ERROR mismatched types
96
// Nested item must not ICE.
107
fn a() {}
118
}

src/test/ui/async-await/async-trait-fn.stderr

+4-52
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ LL | async fn foo() {}
1212
= help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
1313

1414
error[E0706]: functions in traits cannot be declared `async`
15-
--> $DIR/async-trait-fn.rs:5:5
15+
--> $DIR/async-trait-fn.rs:4:5
1616
|
1717
LL | async fn bar(&self) {}
1818
| -----^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL | async fn bar(&self) {}
2525
= help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
2626

2727
error[E0706]: functions in traits cannot be declared `async`
28-
--> $DIR/async-trait-fn.rs:7:5
28+
--> $DIR/async-trait-fn.rs:5:5
2929
|
3030
LL | async fn baz() {
3131
| -----^^^^^^^^^
@@ -37,54 +37,6 @@ LL | async fn baz() {
3737
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
3838
= help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
3939

40-
error[E0308]: mismatched types
41-
--> $DIR/async-trait-fn.rs:3:20
42-
|
43-
LL | async fn foo() {}
44-
| ^^ expected associated type, found opaque type
45-
|
46-
::: $SRC_DIR/core/src/future/mod.rs:LL:COL
47-
|
48-
LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
49-
| ------------------------------- the found opaque type
50-
|
51-
= note: expected associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/async-trait-fn.rs:3:20>)
52-
found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
53-
54-
error[E0308]: mismatched types
55-
--> $DIR/async-trait-fn.rs:5:25
56-
|
57-
LL | async fn bar(&self) {}
58-
| ^^ expected associated type, found opaque type
59-
|
60-
::: $SRC_DIR/core/src/future/mod.rs:LL:COL
61-
|
62-
LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
63-
| ------------------------------- the found opaque type
64-
|
65-
= note: expected associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/async-trait-fn.rs:5:25>)
66-
found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
67-
68-
error[E0308]: mismatched types
69-
--> $DIR/async-trait-fn.rs:7:20
70-
|
71-
LL | async fn baz() {
72-
| ____________________^
73-
LL | |
74-
LL | | // Nested item must not ICE.
75-
LL | | fn a() {}
76-
LL | | }
77-
| |_____^ expected associated type, found opaque type
78-
|
79-
::: $SRC_DIR/core/src/future/mod.rs:LL:COL
80-
|
81-
LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
82-
| ------------------------------- the found opaque type
83-
|
84-
= note: expected associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/async-trait-fn.rs:7:20>)
85-
found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
86-
87-
error: aborting due to 6 previous errors
40+
error: aborting due to 3 previous errors
8841

89-
Some errors have detailed explanations: E0308, E0706.
90-
For more information about an error, try `rustc --explain E0308`.
42+
For more information about this error, try `rustc --explain E0706`.

src/test/ui/async-await/edition-deny-async-fns-2015.rs

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ impl Foo {
1717
trait Bar {
1818
async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
1919
//~^ ERROR functions in traits cannot be declared `async`
20-
//~| ERROR mismatched types
2120
}
2221

2322
fn main() {

src/test/ui/async-await/edition-deny-async-fns-2015.stderr

+6-20
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ LL | async fn foo() {}
5353
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
5454

5555
error[E0670]: `async fn` is not permitted in Rust 2015
56-
--> $DIR/edition-deny-async-fns-2015.rs:37:9
56+
--> $DIR/edition-deny-async-fns-2015.rs:36:9
5757
|
5858
LL | async fn bar() {}
5959
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -62,7 +62,7 @@ LL | async fn bar() {}
6262
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
6363

6464
error[E0670]: `async fn` is not permitted in Rust 2015
65-
--> $DIR/edition-deny-async-fns-2015.rs:27:9
65+
--> $DIR/edition-deny-async-fns-2015.rs:26:9
6666
|
6767
LL | async fn foo() {}
6868
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -71,7 +71,7 @@ LL | async fn foo() {}
7171
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
7272

7373
error[E0670]: `async fn` is not permitted in Rust 2015
74-
--> $DIR/edition-deny-async-fns-2015.rs:32:13
74+
--> $DIR/edition-deny-async-fns-2015.rs:31:13
7575
|
7676
LL | async fn bar() {}
7777
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -92,21 +92,7 @@ LL | async fn foo() {}
9292
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
9393
= help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable
9494

95-
error[E0308]: mismatched types
96-
--> $DIR/edition-deny-async-fns-2015.rs:18:20
97-
|
98-
LL | async fn foo() {}
99-
| ^^ expected associated type, found opaque type
100-
|
101-
::: $SRC_DIR/core/src/future/mod.rs:LL:COL
102-
|
103-
LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
104-
| ------------------------------- the found opaque type
105-
|
106-
= note: expected associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/edition-deny-async-fns-2015.rs:18:20>)
107-
found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
108-
109-
error: aborting due to 11 previous errors
95+
error: aborting due to 10 previous errors
11096

111-
Some errors have detailed explanations: E0308, E0670, E0706.
112-
For more information about an error, try `rustc --explain E0308`.
97+
Some errors have detailed explanations: E0670, E0706.
98+
For more information about an error, try `rustc --explain E0670`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// known-bug: #102688
2+
// edition:2021
3+
4+
#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
5+
#![allow(incomplete_features)]
6+
7+
use std::fmt::Debug;
8+
9+
trait Foo {
10+
async fn baz(&self) -> impl Debug {
11+
""
12+
}
13+
}
14+
15+
struct Bar;
16+
17+
impl Foo for Bar {}
18+
19+
fn main() {
20+
let _ = Bar.baz();
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0720]: cannot resolve opaque type
2+
--> $DIR/default-body-with-rpit.rs:10:28
3+
|
4+
LL | async fn baz(&self) -> impl Debug {
5+
| ^^^^^^^^^^ cannot resolve opaque type
6+
|
7+
= note: these returned values have a concrete "never" type
8+
= help: this error will resolve once the item's body returns a concrete type
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0720`.

0 commit comments

Comments
 (0)