Skip to content

Commit f667e95

Browse files
committed
Check hidden types for well formedness at the definition site instead of only at the opaque type itself
1 parent 12d3f10 commit f667e95

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)