Skip to content

Commit 5b279c8

Browse files
committed
Check opaque types satisfy their bounds
1 parent b3057f4 commit 5b279c8

22 files changed

+158
-36
lines changed

compiler/rustc_trait_selection/src/opaque_types.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,8 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
11701170
// This also instantiates nested instances of `impl Trait`.
11711171
let predicate = self.instantiate_opaque_types_in_map(&predicate);
11721172

1173-
let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType);
1173+
let cause =
1174+
traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
11741175

11751176
// Require that the predicate holds for the concrete type.
11761177
debug!("instantiate_opaque_types: predicate={:?}", predicate);

compiler/rustc_typeck/src/check/check.rs

+66-2
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,10 @@ pub(super) fn check_opaque<'tcx>(
387387
) {
388388
check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
389389
tcx.ensure().type_of(def_id);
390-
check_opaque_for_cycles(tcx, def_id, substs, span, origin);
390+
if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
391+
return;
392+
}
393+
check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
391394
}
392395

393396
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -504,7 +507,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
504507
substs: SubstsRef<'tcx>,
505508
span: Span,
506509
origin: &hir::OpaqueTyOrigin,
507-
) {
510+
) -> Result<(), ErrorReported> {
508511
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
509512
{
510513
match origin {
@@ -514,7 +517,68 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
514517
}
515518
_ => opaque_type_cycle_error(tcx, def_id, span),
516519
}
520+
Err(ErrorReported)
521+
} else {
522+
Ok(())
523+
}
524+
}
525+
526+
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
527+
fn check_opaque_meets_bounds<'tcx>(
528+
tcx: TyCtxt<'tcx>,
529+
def_id: LocalDefId,
530+
substs: SubstsRef<'tcx>,
531+
span: Span,
532+
origin: &hir::OpaqueTyOrigin,
533+
) {
534+
match origin {
535+
// Checked when type checking the function containing them.
536+
hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return,
537+
// Can have different predicates to their defining use
538+
hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => {}
517539
}
540+
541+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
542+
let param_env = tcx.param_env(def_id);
543+
544+
tcx.infer_ctxt().enter(move |infcx| {
545+
let inh = Inherited::new(infcx, def_id);
546+
let infcx = &inh.infcx;
547+
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
548+
549+
let misc_cause = traits::ObligationCause::misc(span, hir_id);
550+
551+
let (_, opaque_type_map) = inh.register_infer_ok_obligations(
552+
infcx.instantiate_opaque_types(def_id.to_def_id(), hir_id, param_env, &opaque_ty, span),
553+
);
554+
555+
for (def_id, opaque_defn) in opaque_type_map {
556+
match infcx
557+
.at(&misc_cause, param_env)
558+
.eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
559+
{
560+
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
561+
Err(ty_err) => tcx.sess.delay_span_bug(
562+
opaque_defn.definition_span,
563+
&format!(
564+
"could not unify `{}` with revealed type:\n{}",
565+
opaque_defn.concrete_ty, ty_err,
566+
),
567+
),
568+
}
569+
}
570+
571+
// Check that all obligations are satisfied by the implementation's
572+
// version.
573+
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
574+
infcx.report_fulfillment_errors(errors, None, false);
575+
}
576+
577+
// Finally, resolve all regions. This catches wily misuses of
578+
// lifetime parameters.
579+
let fcx = FnCtxt::new(&inh, param_env, hir_id);
580+
fcx.regionck_item(hir_id, span, &[]);
581+
});
518582
}
519583

520584
pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {

src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ LL | fn baz() -> impl Bar<Item = i32> {
99
|
1010
= note: expected associated type `<impl Bar as Foo>::Item`
1111
found type `i32`
12-
= note: the return type of a function must have a statically known size
1312
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
1413
|
1514
LL | fn bar() -> impl Bar<Item = i32> {

src/test/ui/async-await/async-error-span.stderr

-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ error[E0277]: `()` is not a future
33
|
44
LL | fn get_future() -> impl Future<Output = ()> {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
6-
LL |
7-
LL | panic!()
8-
| -------- this returned value is of type `!`
96
|
107
= help: the trait `Future` is not implemented for `()`
118
= note: the return type of a function must have a statically known size

src/test/ui/async-await/issue-64130-4-async-move.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ help: consider moving this into a `let` binding to create a shorter lived borrow
3030
|
3131
LL | match client.status() {
3232
| ^^^^^^^^^^^^^^^
33-
= note: the return type of a function must have a statically known size
3433

3534
error: aborting due to previous error
3635

src/test/ui/async-await/issue-70818.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ note: captured value is not `Send`
1212
|
1313
LL | async { (ty, ty1) }
1414
| ^^^ has type `U` which is not `Send`
15-
= note: the return type of a function must have a statically known size
1615
help: consider restricting type parameter `U`
1716
|
1817
LL | fn foo<T: Send, U: Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {

src/test/ui/generator/type-mismatch-signature-deduction.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ LL | fn foo() -> impl Generator<Return = i32> {
1515
|
1616
= note: expected enum `std::result::Result<{integer}, _>`
1717
found type `i32`
18-
= note: the return type of a function must have a statically known size
1918

2019
error: aborting due to 2 previous errors
2120

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

-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
1515
|
1616
= note: expected type `()`
1717
found associated type `<T as impl_trait::Trait>::Assoc`
18-
= note: the return type of a function must have a statically known size
1918
help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
2019
|
2120
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
@@ -35,7 +34,6 @@ LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
3534
|
3635
= note: expected type `()`
3736
found associated type `<T as lifetimes::Trait<'static>>::Assoc`
38-
= note: the return type of a function must have a statically known size
3937
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
4038
|
4139
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {

src/test/ui/impl-trait/issue-55872-1.stderr

-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ LL | type E = impl Copy;
1414
| ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
1515
|
1616
= note: required because it appears within the type `(S, T)`
17-
= note: the return type of a function must have a statically known size
1817
help: consider further restricting this bound
1918
|
2019
LL | impl<S: Default + Copy> Bar for S {
@@ -27,7 +26,6 @@ LL | type E = impl Copy;
2726
| ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
2827
|
2928
= note: required because it appears within the type `(S, T)`
30-
= note: the return type of a function must have a statically known size
3129
help: consider further restricting this bound
3230
|
3331
LL | fn foo<T: Default + Copy>() -> Self::E {

src/test/ui/issues-71798.stderr

-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ error[E0277]: `u32` is not a future
99
|
1010
LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
12-
LL | *x
13-
| -- this returned value is of type `u32`
1412
|
1513
= help: the trait `Future` is not implemented for `u32`
1614
= note: the return type of a function must have a statically known size

src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr

-5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@ error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisf
33
|
44
LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>`
6-
LL |
7-
LL | Ok(())
8-
| ------ this returned value is of type `std::result::Result<(), _>`
9-
|
10-
= note: the return type of a function must have a statically known size
116

127
error: aborting due to previous error
138

src/test/ui/never_type/feature-gate-never_type_fallback.stderr

-5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@ error[E0277]: the trait bound `(): T` is not satisfied
33
|
44
LL | fn should_ret_unit() -> impl T {
55
| ^^^^^^ the trait `T` is not implemented for `()`
6-
LL |
7-
LL | panic!()
8-
| -------- this returned value is of type `!`
9-
|
10-
= note: the return type of a function must have a statically known size
116

127
error: aborting due to previous error
138

src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr

-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ LL | fn foo() -> impl Bar {
55
| ^^^^^^^^ the trait `Bar` is not implemented for `()`
66
LL | 5;
77
| - consider removing this semicolon
8-
|
9-
= note: the return type of a function must have a statically known size
108

119
error: aborting due to previous error
1210

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Make sure that we check that impl trait types implement the traits that they
2+
// claim to.
3+
4+
#![feature(type_alias_impl_trait)]
5+
6+
type X<T> = impl Clone;
7+
//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
8+
9+
fn f<T: Clone>(t: T) -> X<T> {
10+
t
11+
}
12+
13+
fn g<T>(o : Option<X<T>>) -> Option<X<T>> {
14+
o.clone()
15+
}
16+
17+
fn main() {
18+
g(None::<X<&mut ()>>);
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
2+
--> $DIR/bounds-are-checked-2.rs:6:13
3+
|
4+
LL | type X<T> = impl Clone;
5+
| ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `T`
6+
|
7+
help: consider restricting type parameter `T`
8+
|
9+
LL | type X<T: std::clone::Clone> = impl Clone;
10+
| ^^^^^^^^^^^^^^^^^^^
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Make sure that we check that impl trait types implement the traits that they
2+
// claim to.
3+
4+
#![feature(type_alias_impl_trait)]
5+
6+
type X<'a> = impl Into<&'static str> + From<&'a str>;
7+
//~^ ERROR mismatched types
8+
9+
fn f<'a: 'static>(t: &'a str) -> X<'a> {
10+
//~^ WARNING unnecessary lifetime parameter
11+
t
12+
}
13+
14+
fn extend_lt<'a>(o: &'a str) -> &'static str {
15+
X::<'_>::from(o).into()
16+
}
17+
18+
fn main() {
19+
let r =
20+
{
21+
let s = "abcdef".to_string();
22+
extend_lt(&s)
23+
};
24+
println!("{}", r);
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
warning: unnecessary lifetime parameter `'a`
2+
--> $DIR/bounds-are-checked.rs:9:6
3+
|
4+
LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
5+
| ^^^^^^^^^^^
6+
|
7+
= help: you can use the `'static` lifetime directly, in place of `'a`
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/bounds-are-checked.rs:6:14
11+
|
12+
LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
14+
|
15+
= note: expected type `std::convert::From<&'a str>`
16+
found type `std::convert::From<&'static str>`
17+
note: the lifetime `'a` as defined on the item at 6:8...
18+
--> $DIR/bounds-are-checked.rs:6:8
19+
|
20+
LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
21+
| ^^
22+
= note: ...does not necessarily outlive the static lifetime
23+
24+
error: aborting due to previous error; 1 warning emitted
25+
26+
For more information about this error, try `rustc --explain E0308`.

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// build-pass (FIXME(62277): could be check-pass?)
1+
// check-pass
22
#![feature(type_alias_impl_trait)]
33

44
use std::fmt::Debug;
55

66
fn main() {}
77

8-
type Two<T, U> = impl Debug;
8+
type Two<T: Debug, U> = impl Debug;
99

1010
fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
1111
(t, 4u32)

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// build-pass (FIXME(62277): could be check-pass?)
1+
// check-pass
22
#![feature(type_alias_impl_trait)]
33

44
use std::fmt::Debug;
55

66
fn main() {}
77

8-
type Two<A, B> = impl Debug;
8+
type Two<A: Debug, B> = impl Debug;
99

1010
fn two<T: Debug + Copy, U>(t: T, u: U) -> Two<T, U> {
1111
(t, t)

src/test/ui/type-alias-impl-trait/issue-60371.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ LL | type Item = impl Bug;
1515
|
1616
= help: the following implementations were found:
1717
<&() as Bug>
18-
= note: the return type of a function must have a statically known size
1918

2019
error: could not find defining uses
2120
--> $DIR/issue-60371.rs:8:17

src/test/ui/type-alias-impl-trait/issue-63279.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ LL | type Closure = impl FnOnce();
66
|
77
= note: expected opaque type `impl FnOnce<()>`
88
found unit type `()`
9-
= note: the return type of a function must have a statically known size
109

1110
error: aborting due to previous error
1211

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
7070
}
7171

7272
trait Trait {}
73-
type GenericBound<'a, T: Trait> = impl Sized + 'a;
73+
type GenericBound<'a, T: Trait + 'a> = impl Sized + 'a;
7474

7575
fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
7676
t
7777
}
7878

7979
mod pass_through {
80-
pub type Passthrough<T> = impl Sized + 'static;
80+
pub type Passthrough<T: 'static> = impl Sized + 'static;
8181

8282
fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
8383
t

0 commit comments

Comments
 (0)