Skip to content

Commit eead58e

Browse files
committed
Auto merge of #96736 - oli-obk:tait_missing_wf_check, r=davidtwco
Check hidden types for well formedness at the definition site instead of only at the opaque type itself work towards #90409 . We'll need to look into closure and generator bodies of closures and generators nested inside the hidden type in order to fix that. In hindsight this PR is not necessary for that, but it may be a bit easier with it and we'll get better diagnostics from it on its own.
2 parents c51871c + f667e95 commit eead58e

32 files changed

+301
-140
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
110110
let remapped_type = infcx.infer_opaque_definition_from_instantiation(
111111
opaque_type_key,
112112
universal_concrete_type,
113+
origin,
113114
);
114115
let ty = if check_opaque_type_parameter_valid(
115116
infcx.tcx,

compiler/rustc_trait_selection/src/opaque_types.rs

+71-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
use crate::traits;
2+
use crate::traits::error_reporting::InferCtxtExt as _;
3+
use crate::traits::TraitEngineExt as _;
24
use rustc_data_structures::fx::FxHashMap;
35
use rustc_hir::def_id::DefId;
6+
use rustc_hir::OpaqueTyOrigin;
47
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
5-
use rustc_infer::infer::InferCtxt;
8+
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt as _};
9+
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
610
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
711
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
8-
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt};
12+
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt};
913
use rustc_span::Span;
1014

1115
pub trait InferCtxtExt<'tcx> {
1216
fn infer_opaque_definition_from_instantiation(
1317
&self,
1418
opaque_type_key: OpaqueTypeKey<'tcx>,
1519
instantiated_ty: OpaqueHiddenType<'tcx>,
20+
origin: OpaqueTyOrigin,
1621
) -> Ty<'tcx>;
1722
}
1823

@@ -45,6 +50,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
4550
&self,
4651
opaque_type_key: OpaqueTypeKey<'tcx>,
4752
instantiated_ty: OpaqueHiddenType<'tcx>,
53+
origin: OpaqueTyOrigin,
4854
) -> Ty<'tcx> {
4955
if self.is_tainted_by_errors() {
5056
return self.tcx.ty_error();
@@ -76,7 +82,69 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
7682
));
7783
debug!(?definition_ty);
7884

79-
definition_ty
85+
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
86+
// on stable and we'd break that.
87+
if let OpaqueTyOrigin::TyAlias = origin {
88+
// This logic duplicates most of `check_opaque_meets_bounds`.
89+
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
90+
let param_env = self.tcx.param_env(def_id);
91+
let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap());
92+
self.tcx.infer_ctxt().enter(move |infcx| {
93+
// Require the hidden type to be well-formed with only the generics of the opaque type.
94+
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
95+
// hidden type is well formed even without those bounds.
96+
let predicate =
97+
ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
98+
.to_predicate(infcx.tcx);
99+
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
100+
101+
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
102+
// the bounds that the function supplies.
103+
match infcx.register_hidden_type(
104+
OpaqueTypeKey { def_id, substs: id_substs },
105+
ObligationCause::misc(instantiated_ty.span, body_id),
106+
param_env,
107+
definition_ty,
108+
origin,
109+
) {
110+
Ok(infer_ok) => {
111+
for obligation in infer_ok.obligations {
112+
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
113+
}
114+
}
115+
Err(err) => {
116+
infcx
117+
.report_mismatched_types(
118+
&ObligationCause::misc(instantiated_ty.span, body_id),
119+
self.tcx.mk_opaque(def_id, id_substs),
120+
definition_ty,
121+
err,
122+
)
123+
.emit();
124+
}
125+
}
126+
127+
fulfillment_cx.register_predicate_obligation(
128+
&infcx,
129+
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
130+
);
131+
132+
// Check that all obligations are satisfied by the implementation's
133+
// version.
134+
let errors = fulfillment_cx.select_all_or_error(&infcx);
135+
136+
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
137+
138+
if errors.is_empty() {
139+
definition_ty
140+
} else {
141+
infcx.report_fulfillment_errors(&errors, None, false);
142+
self.tcx.ty_error()
143+
}
144+
})
145+
} else {
146+
definition_ty
147+
}
80148
}
81149
}
82150

src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
#![feature(type_alias_impl_trait)]
55

66
type X<T> = impl Clone;
7-
//~^ ERROR the trait bound `T: Clone` is not satisfied
87

98
fn f<T: Clone>(t: T) -> X<T> {
109
t
10+
//~^ ERROR the trait bound `T: Clone` is not satisfied
1111
}
1212

1313
fn g<T>(o: Option<X<T>>) -> Option<X<T>> {

src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the trait bound `T: Clone` is not satisfied
2-
--> $DIR/bounds-are-checked-2.rs:6:13
2+
--> $DIR/bounds-are-checked-2.rs:9:5
33
|
4-
LL | type X<T> = impl Clone;
5-
| ^^^^^^^^^^ the trait `Clone` is not implemented for `T`
4+
LL | t
5+
| ^ the trait `Clone` is not implemented for `T`
66
|
77
help: consider restricting type parameter `T`
88
|

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type TwoConsts<const X: usize, const Y: usize> = impl Debug;
1515
fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
1616
t
1717
//~^ ERROR non-defining opaque type use in defining scope
18+
//~| ERROR `U` doesn't implement `Debug`
1819
}
1920

2021
fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
error[E0277]: `U` doesn't implement `Debug`
2+
--> $DIR/generic_duplicate_param_use.rs:16:5
3+
|
4+
LL | t
5+
| ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
6+
|
7+
help: consider restricting type parameter `U`
8+
|
9+
LL | type TwoTys<T, U: std::fmt::Debug> = impl Debug;
10+
| +++++++++++++++++
11+
112
error: non-defining opaque type use in defining scope
213
--> $DIR/generic_duplicate_param_use.rs:16:5
314
|
@@ -11,7 +22,7 @@ LL | type TwoTys<T, U> = impl Debug;
1122
| ^ ^
1223

1324
error: non-defining opaque type use in defining scope
14-
--> $DIR/generic_duplicate_param_use.rs:21:5
25+
--> $DIR/generic_duplicate_param_use.rs:22:5
1526
|
1627
LL | t
1728
| ^
@@ -23,7 +34,7 @@ LL | type TwoLifetimes<'a, 'b> = impl Debug;
2334
| ^^ ^^
2435

2536
error: non-defining opaque type use in defining scope
26-
--> $DIR/generic_duplicate_param_use.rs:26:5
37+
--> $DIR/generic_duplicate_param_use.rs:27:5
2738
|
2839
LL | t
2940
| ^
@@ -34,5 +45,6 @@ note: constant used multiple times
3445
LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
3546
| ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
3647

37-
error: aborting due to 3 previous errors
48+
error: aborting due to 4 previous errors
3849

50+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ fn main() {}
66

77
// test that unused generic parameters are ok
88
type Two<T, U> = impl Debug;
9-
//~^ ERROR `T` doesn't implement `Debug`
109

1110
fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
1211
t
12+
//~^ ERROR `T` doesn't implement `Debug`
1313
}

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: `T` doesn't implement `Debug`
2-
--> $DIR/generic_duplicate_param_use2.rs:8:18
2+
--> $DIR/generic_duplicate_param_use2.rs:11:5
33
|
4-
LL | type Two<T, U> = impl Debug;
5-
| ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
4+
LL | t
5+
| ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
66
|
77
help: consider restricting type parameter `T`
88
|

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ fn main() {}
66

77
// test that unused generic parameters are ok
88
type Two<T, U> = impl Debug;
9-
//~^ ERROR `T` doesn't implement `Debug`
109

1110
fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
1211
t
12+
//~^ ERROR `T` doesn't implement `Debug`
1313
}
1414

1515
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
1616
u
17-
//~^ ERROR concrete type differs from previous defining opaque type use
17+
//~^ ERROR `U` doesn't implement `Debug`
1818
}
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1-
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/generic_duplicate_param_use3.rs:16:5
3-
|
4-
LL | u
5-
| ^ expected `T`, got `U`
6-
|
7-
note: previous use here
8-
--> $DIR/generic_duplicate_param_use3.rs:12:5
9-
|
10-
LL | t
11-
| ^
12-
131
error[E0277]: `T` doesn't implement `Debug`
14-
--> $DIR/generic_duplicate_param_use3.rs:8:18
2+
--> $DIR/generic_duplicate_param_use3.rs:11:5
153
|
16-
LL | type Two<T, U> = impl Debug;
17-
| ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
4+
LL | t
5+
| ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
186
|
197
help: consider restricting type parameter `T`
208
|
219
LL | type Two<T: std::fmt::Debug, U> = impl Debug;
2210
| +++++++++++++++++
2311

12+
error[E0277]: `U` doesn't implement `Debug`
13+
--> $DIR/generic_duplicate_param_use3.rs:16:5
14+
|
15+
LL | u
16+
| ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
17+
|
18+
help: consider restricting type parameter `U`
19+
|
20+
LL | type Two<T, U: std::fmt::Debug> = impl Debug;
21+
| +++++++++++++++++
22+
2423
error: aborting due to 2 previous errors
2524

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

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ fn main() {}
66

77
// test that unused generic parameters are ok
88
type Two<T, U> = impl Debug;
9-
//~^ ERROR `U` doesn't implement `Debug`
109

1110
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
1211
u
12+
//~^ ERROR `U` doesn't implement `Debug`
1313
}

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: `U` doesn't implement `Debug`
2-
--> $DIR/generic_duplicate_param_use4.rs:8:18
2+
--> $DIR/generic_duplicate_param_use4.rs:11:5
33
|
4-
LL | type Two<T, U> = impl Debug;
5-
| ^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
4+
LL | u
5+
| ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
66
|
77
help: consider restricting type parameter `U`
88
|

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ fn main() {}
66

77
// test that unused generic parameters are ok
88
type Two<T, U> = impl Debug;
9-
//~^ ERROR `T` doesn't implement `Debug`
10-
//~| ERROR `U` doesn't implement `Debug`
119

1210
fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
1311
(t, u)
12+
//~^ ERROR `T` doesn't implement `Debug`
13+
//~| ERROR `U` doesn't implement `Debug`
1414
}
1515

1616
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
1717
(u, t)
18-
//~^ concrete type differs from previous
18+
//~^ ERROR `T` doesn't implement `Debug`
19+
//~| ERROR `U` doesn't implement `Debug`
1920
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
1-
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/generic_duplicate_param_use5.rs:17:5
3-
|
4-
LL | (u, t)
5-
| ^^^^^^ expected `(T, U)`, got `(U, T)`
6-
|
7-
note: previous use here
8-
--> $DIR/generic_duplicate_param_use5.rs:13:5
9-
|
10-
LL | (t, u)
11-
| ^^^^^^
12-
131
error[E0277]: `T` doesn't implement `Debug`
14-
--> $DIR/generic_duplicate_param_use5.rs:8:18
2+
--> $DIR/generic_duplicate_param_use5.rs:11:5
153
|
16-
LL | type Two<T, U> = impl Debug;
17-
| ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
4+
LL | (t, u)
5+
| ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
186
|
197
= note: required because of the requirements on the impl of `Debug` for `(T, U)`
208
help: consider restricting type parameter `T`
@@ -23,17 +11,41 @@ LL | type Two<T: std::fmt::Debug, U> = impl Debug;
2311
| +++++++++++++++++
2412

2513
error[E0277]: `U` doesn't implement `Debug`
26-
--> $DIR/generic_duplicate_param_use5.rs:8:18
14+
--> $DIR/generic_duplicate_param_use5.rs:11:5
2715
|
28-
LL | type Two<T, U> = impl Debug;
29-
| ^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
16+
LL | (t, u)
17+
| ^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
3018
|
3119
= note: required because of the requirements on the impl of `Debug` for `(T, U)`
3220
help: consider restricting type parameter `U`
3321
|
3422
LL | type Two<T, U: std::fmt::Debug> = impl Debug;
3523
| +++++++++++++++++
3624

37-
error: aborting due to 3 previous errors
25+
error[E0277]: `U` doesn't implement `Debug`
26+
--> $DIR/generic_duplicate_param_use5.rs:17:5
27+
|
28+
LL | (u, t)
29+
| ^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
30+
|
31+
= note: required because of the requirements on the impl of `Debug` for `(U, T)`
32+
help: consider restricting type parameter `U`
33+
|
34+
LL | type Two<T, U: std::fmt::Debug> = impl Debug;
35+
| +++++++++++++++++
36+
37+
error[E0277]: `T` doesn't implement `Debug`
38+
--> $DIR/generic_duplicate_param_use5.rs:17:5
39+
|
40+
LL | (u, t)
41+
| ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
42+
|
43+
= note: required because of the requirements on the impl of `Debug` for `(U, T)`
44+
help: consider restricting type parameter `T`
45+
|
46+
LL | type Two<T: std::fmt::Debug, U> = impl Debug;
47+
| +++++++++++++++++
48+
49+
error: aborting due to 4 previous errors
3850

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

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ fn main() {}
66

77
// test that unused generic parameters are ok
88
type Two<T, U> = impl Debug;
9-
//~^ ERROR `T` doesn't implement `Debug`
109

1110
fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
1211
(t, t)
12+
//~^ ERROR `T` doesn't implement `Debug`
1313
}
1414

1515
fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
1616
(u, t)
17-
//~^ ERROR concrete type differs from previous
17+
//~^ ERROR `T` doesn't implement `Debug`
18+
//~| ERROR `U` doesn't implement `Debug`
1819
}

0 commit comments

Comments
 (0)