Check opaque types satisfy their bounds
This commit is contained in:
parent
b3057f4d5f
commit
5b279c8016
@ -1170,7 +1170,8 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
// This also instantiates nested instances of `impl Trait`.
|
||||
let predicate = self.instantiate_opaque_types_in_map(&predicate);
|
||||
|
||||
let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType);
|
||||
let cause =
|
||||
traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
|
||||
|
||||
// Require that the predicate holds for the concrete type.
|
||||
debug!("instantiate_opaque_types: predicate={:?}", predicate);
|
||||
|
@ -387,7 +387,10 @@ pub(super) fn check_opaque<'tcx>(
|
||||
) {
|
||||
check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
|
||||
tcx.ensure().type_of(def_id);
|
||||
check_opaque_for_cycles(tcx, def_id, substs, span, origin);
|
||||
if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
|
||||
return;
|
||||
}
|
||||
check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
|
||||
}
|
||||
|
||||
/// 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>(
|
||||
substs: SubstsRef<'tcx>,
|
||||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
) -> Result<(), ErrorReported> {
|
||||
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
|
||||
{
|
||||
match origin {
|
||||
@ -514,9 +517,70 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
|
||||
}
|
||||
_ => opaque_type_cycle_error(tcx, def_id, span),
|
||||
}
|
||||
Err(ErrorReported)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
|
||||
fn check_opaque_meets_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
match origin {
|
||||
// Checked when type checking the function containing them.
|
||||
hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return,
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => {}
|
||||
}
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
tcx.infer_ctxt().enter(move |infcx| {
|
||||
let inh = Inherited::new(infcx, def_id);
|
||||
let infcx = &inh.infcx;
|
||||
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
||||
|
||||
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
||||
|
||||
let (_, opaque_type_map) = inh.register_infer_ok_obligations(
|
||||
infcx.instantiate_opaque_types(def_id.to_def_id(), hir_id, param_env, &opaque_ty, span),
|
||||
);
|
||||
|
||||
for (def_id, opaque_defn) in opaque_type_map {
|
||||
match infcx
|
||||
.at(&misc_cause, param_env)
|
||||
.eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
|
||||
{
|
||||
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
|
||||
Err(ty_err) => tcx.sess.delay_span_bug(
|
||||
opaque_defn.definition_span,
|
||||
&format!(
|
||||
"could not unify `{}` with revealed type:\n{}",
|
||||
opaque_defn.concrete_ty, ty_err,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(errors, None, false);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let fcx = FnCtxt::new(&inh, param_env, hir_id);
|
||||
fcx.regionck_item(hir_id, span, &[]);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
|
||||
debug!(
|
||||
"check_item_type(it.hir_id={}, it.name={})",
|
||||
|
@ -9,7 +9,6 @@ LL | fn baz() -> impl Bar<Item = i32> {
|
||||
|
|
||||
= note: expected associated type `<impl Bar as Foo>::Item`
|
||||
found type `i32`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
|
||||
|
|
||||
LL | fn bar() -> impl Bar<Item = i32> {
|
||||
|
@ -3,9 +3,6 @@ error[E0277]: `()` is not a future
|
||||
|
|
||||
LL | fn get_future() -> impl Future<Output = ()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
||||
LL |
|
||||
LL | panic!()
|
||||
| -------- this returned value is of type `!`
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `()`
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
@ -30,7 +30,6 @@ help: consider moving this into a `let` binding to create a shorter lived borrow
|
||||
|
|
||||
LL | match client.status() {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -12,7 +12,6 @@ note: captured value is not `Send`
|
||||
|
|
||||
LL | async { (ty, ty1) }
|
||||
| ^^^ has type `U` which is not `Send`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider restricting type parameter `U`
|
||||
|
|
||||
LL | fn foo<T: Send, U: Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
|
||||
|
@ -15,7 +15,6 @@ LL | fn foo() -> impl Generator<Return = i32> {
|
||||
|
|
||||
= note: expected enum `std::result::Result<{integer}, _>`
|
||||
found type `i32`
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -15,7 +15,6 @@ LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
|
||||
|
|
||||
= note: expected type `()`
|
||||
found associated type `<T as impl_trait::Trait>::Assoc`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
|
||||
|
|
||||
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> {
|
||||
|
|
||||
= note: expected type `()`
|
||||
found associated type `<T as lifetimes::Trait<'static>>::Assoc`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
|
||||
|
|
||||
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
|
||||
|
@ -14,7 +14,6 @@ LL | type E = impl Copy;
|
||||
| ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
|
||||
|
|
||||
= note: required because it appears within the type `(S, T)`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | impl<S: Default + Copy> Bar for S {
|
||||
@ -27,7 +26,6 @@ LL | type E = impl Copy;
|
||||
| ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
|
||||
|
|
||||
= note: required because it appears within the type `(S, T)`
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | fn foo<T: Default + Copy>() -> Self::E {
|
||||
|
@ -9,8 +9,6 @@ error[E0277]: `u32` is not a future
|
||||
|
|
||||
LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
|
||||
LL | *x
|
||||
| -- this returned value is of type `u32`
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `u32`
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
@ -3,11 +3,6 @@ error[E0277]: the trait bound `std::result::Result<(), _>: Future` is not satisf
|
||||
|
|
||||
LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>`
|
||||
LL |
|
||||
LL | Ok(())
|
||||
| ------ this returned value is of type `std::result::Result<(), _>`
|
||||
|
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -3,11 +3,6 @@ error[E0277]: the trait bound `(): T` is not satisfied
|
||||
|
|
||||
LL | fn should_ret_unit() -> impl T {
|
||||
| ^^^^^^ the trait `T` is not implemented for `()`
|
||||
LL |
|
||||
LL | panic!()
|
||||
| -------- this returned value is of type `!`
|
||||
|
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,8 +5,6 @@ LL | fn foo() -> impl Bar {
|
||||
| ^^^^^^^^ the trait `Bar` is not implemented for `()`
|
||||
LL | 5;
|
||||
| - consider removing this semicolon
|
||||
|
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
19
src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs
Normal file
19
src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Make sure that we check that impl trait types implement the traits that they
|
||||
// claim to.
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type X<T> = impl Clone;
|
||||
//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
|
||||
|
||||
fn f<T: Clone>(t: T) -> X<T> {
|
||||
t
|
||||
}
|
||||
|
||||
fn g<T>(o : Option<X<T>>) -> Option<X<T>> {
|
||||
o.clone()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
g(None::<X<&mut ()>>);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
|
||||
--> $DIR/bounds-are-checked-2.rs:6:13
|
||||
|
|
||||
LL | type X<T> = impl Clone;
|
||||
| ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `T`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | type X<T: std::clone::Clone> = impl Clone;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
25
src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
Normal file
25
src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Make sure that we check that impl trait types implement the traits that they
|
||||
// claim to.
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type X<'a> = impl Into<&'static str> + From<&'a str>;
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
fn f<'a: 'static>(t: &'a str) -> X<'a> {
|
||||
//~^ WARNING unnecessary lifetime parameter
|
||||
t
|
||||
}
|
||||
|
||||
fn extend_lt<'a>(o: &'a str) -> &'static str {
|
||||
X::<'_>::from(o).into()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let r =
|
||||
{
|
||||
let s = "abcdef".to_string();
|
||||
extend_lt(&s)
|
||||
};
|
||||
println!("{}", r);
|
||||
}
|
26
src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
Normal file
26
src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
Normal file
@ -0,0 +1,26 @@
|
||||
warning: unnecessary lifetime parameter `'a`
|
||||
--> $DIR/bounds-are-checked.rs:9:6
|
||||
|
|
||||
LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: you can use the `'static` lifetime directly, in place of `'a`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bounds-are-checked.rs:6:14
|
||||
|
|
||||
LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
||||
|
|
||||
= note: expected type `std::convert::From<&'a str>`
|
||||
found type `std::convert::From<&'static str>`
|
||||
note: the lifetime `'a` as defined on the item at 6:8...
|
||||
--> $DIR/bounds-are-checked.rs:6:8
|
||||
|
|
||||
LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
|
||||
| ^^
|
||||
= note: ...does not necessarily outlive the static lifetime
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -1,11 +1,11 @@
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// check-pass
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn main() {}
|
||||
|
||||
type Two<T, U> = impl Debug;
|
||||
type Two<T: Debug, U> = impl Debug;
|
||||
|
||||
fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
|
||||
(t, 4u32)
|
||||
|
@ -1,11 +1,11 @@
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// check-pass
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn main() {}
|
||||
|
||||
type Two<A, B> = impl Debug;
|
||||
type Two<A: Debug, B> = impl Debug;
|
||||
|
||||
fn two<T: Debug + Copy, U>(t: T, u: U) -> Two<T, U> {
|
||||
(t, t)
|
||||
|
@ -15,7 +15,6 @@ LL | type Item = impl Bug;
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<&() as Bug>
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/issue-60371.rs:8:17
|
||||
|
@ -6,7 +6,6 @@ LL | type Closure = impl FnOnce();
|
||||
|
|
||||
= note: expected opaque type `impl FnOnce<()>`
|
||||
found unit type `()`
|
||||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -70,14 +70,14 @@ fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
|
||||
}
|
||||
|
||||
trait Trait {}
|
||||
type GenericBound<'a, T: Trait> = impl Sized + 'a;
|
||||
type GenericBound<'a, T: Trait + 'a> = impl Sized + 'a;
|
||||
|
||||
fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
|
||||
t
|
||||
}
|
||||
|
||||
mod pass_through {
|
||||
pub type Passthrough<T> = impl Sized + 'static;
|
||||
pub type Passthrough<T: 'static> = impl Sized + 'static;
|
||||
|
||||
fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
|
||||
t
|
||||
|
Loading…
Reference in New Issue
Block a user