mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Ensure that associated types for trait objects satisfy their bounds
This commit is contained in:
parent
0a76584dcc
commit
2bdf723da7
@ -9,7 +9,7 @@
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_infer::infer::{self, InferOk};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
|
||||
@ -342,21 +342,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> {
|
||||
debug!("confirm_object_candidate({:?})", obligation);
|
||||
|
||||
// FIXME(nmatsakis) skipping binder here seems wrong -- we should
|
||||
// probably flatten the binder from the obligation and the binder
|
||||
// from the object. Have to try to make a broken test case that
|
||||
// results.
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
|
||||
let poly_trait_ref = match self_ty.kind() {
|
||||
ty::Dynamic(data, ..) => data
|
||||
.principal()
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(obligation.cause.span, "object candidate with no principal")
|
||||
})
|
||||
.with_self_ty(self.tcx(), self_ty),
|
||||
let self_ty = self.infcx.replace_bound_vars_with_placeholders(&obligation.self_ty());
|
||||
let data = match self_ty.kind() {
|
||||
ty::Dynamic(data, ..) => data,
|
||||
_ => span_bug!(obligation.cause.span, "object candidate with non-object"),
|
||||
};
|
||||
|
||||
let poly_trait_ref = data
|
||||
.principal()
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(obligation.cause.span, "object candidate with no principal")
|
||||
})
|
||||
.with_self_ty(self.tcx(), self_ty);
|
||||
|
||||
let mut upcast_trait_ref = None;
|
||||
let mut nested = vec![];
|
||||
let vtable_base;
|
||||
@ -388,6 +386,46 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
|
||||
}
|
||||
|
||||
for bound in data.skip_binder() {
|
||||
match bound {
|
||||
ty::ExistentialPredicate::Projection(projection) => {
|
||||
// This maybe belongs in wf, but that can't (doesn't) handle
|
||||
// higher-ranked things.
|
||||
// Prevent, e.g., `dyn Iterator<Item = str>`.
|
||||
// FIXME(generic_associated_types): We need some way to
|
||||
// ensure that for `dyn for<'a> X<Item<'a> = &'a ()>` the
|
||||
// bound holds for all `'a`.
|
||||
let (infer_projection, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
infer::HigherRankedType,
|
||||
&ty::Binder::bind(projection),
|
||||
);
|
||||
let substs: Vec<_> =
|
||||
iter::once(self_ty.into()).chain(infer_projection.substs).collect();
|
||||
let bounds =
|
||||
self.tcx().item_bounds(projection.item_def_id).iter().map(|bound| {
|
||||
// In the example above, `bound` is `<Self as Iterator>::Item: Sized`
|
||||
// `subst_bound` is `str: Sized`.
|
||||
let subst_bound = util::subst_assoc_item_bound(
|
||||
self.tcx(),
|
||||
bound,
|
||||
infer_projection.ty,
|
||||
&substs,
|
||||
);
|
||||
Obligation::new(
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env.clone(),
|
||||
subst_bound,
|
||||
)
|
||||
});
|
||||
debug!("confirm_object_candidate: adding bounds: {:?}", bounds);
|
||||
nested.extend(bounds);
|
||||
}
|
||||
ty::ExistentialPredicate::Trait(_) | ty::ExistentialPredicate::AutoTrait(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("confirm_object_candidate: nested: {:?}", nested);
|
||||
ImplSourceObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ trait Trait {}
|
||||
fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait { panic!("") }
|
||||
|
||||
fn main() {
|
||||
// This isn't great. The issue here is that `dyn Trait` is not sized, so
|
||||
// `dyn Fn() -> dyn Trait` is not well-formed.
|
||||
let t : &dyn Trait = &get_function()();
|
||||
//~^ ERROR cannot move a value of type dyn Trait
|
||||
//~^ ERROR expected function, found `&dyn std::ops::Fn() -> (dyn Trait + 'static)`
|
||||
}
|
||||
|
@ -1,9 +1,14 @@
|
||||
error[E0161]: cannot move a value of type dyn Trait: the size of dyn Trait cannot be statically determined
|
||||
--> $DIR/issue-41139.rs:6:27
|
||||
error[E0618]: expected function, found `&dyn std::ops::Fn() -> (dyn Trait + 'static)`
|
||||
--> $DIR/issue-41139.rs:8:27
|
||||
|
|
||||
LL | fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait { panic!("") }
|
||||
| ----------------------------------------------------------------- `get_function` defined here returns `&dyn std::ops::Fn() -> (dyn Trait + 'static)`
|
||||
...
|
||||
LL | let t : &dyn Trait = &get_function()();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^--
|
||||
| |
|
||||
| call expression requires function
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0161`.
|
||||
For more information about this error, try `rustc --explain E0618`.
|
||||
|
14
src/test/ui/traits/check-trait-object-bounds-1.rs
Normal file
14
src/test/ui/traits/check-trait-object-bounds-1.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Check that we validate associated type bounds for trait objects
|
||||
|
||||
trait X {
|
||||
type Y: Clone;
|
||||
}
|
||||
|
||||
fn f<T: X + ?Sized>() {
|
||||
None::<T::Y>.clone();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f::<dyn X<Y = str>>();
|
||||
//~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied
|
||||
}
|
12
src/test/ui/traits/check-trait-object-bounds-1.stderr
Normal file
12
src/test/ui/traits/check-trait-object-bounds-1.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied
|
||||
--> $DIR/check-trait-object-bounds-1.rs:12:5
|
||||
|
|
||||
LL | fn f<T: X + ?Sized>() {
|
||||
| - required by this bound in `f`
|
||||
...
|
||||
LL | f::<dyn X<Y = str>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
15
src/test/ui/traits/check-trait-object-bounds-2-ok.rs
Normal file
15
src/test/ui/traits/check-trait-object-bounds-2-ok.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Make sure that we're handling bound lifetimes correctly when validating trait
|
||||
// bounds.
|
||||
// run-pass
|
||||
|
||||
trait X<'a> {
|
||||
type F: FnOnce(&i32) -> &'a i32;
|
||||
}
|
||||
|
||||
fn f<T: for<'r> X<'r> + ?Sized>() {
|
||||
None::<T::F>.map(|f| f(&0));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f::<dyn for<'x> X<'x, F = fn(&i32) -> &'x i32>>();
|
||||
}
|
15
src/test/ui/traits/check-trait-object-bounds-2.rs
Normal file
15
src/test/ui/traits/check-trait-object-bounds-2.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Check that we validate associated type bounds for trait objects when they
|
||||
// have bound lifetimes
|
||||
|
||||
trait X<'a> {
|
||||
type F: FnOnce(&i32) -> &'a i32;
|
||||
}
|
||||
|
||||
fn f<T: for<'r> X<'r> + ?Sized>() {
|
||||
None::<T::F>.map(|f| f(&0));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f::<dyn for<'x> X<'x, F = i32>>();
|
||||
//~^ expected a `std::ops::FnOnce<(&i32,)>` closure, found `i32`
|
||||
}
|
14
src/test/ui/traits/check-trait-object-bounds-2.stderr
Normal file
14
src/test/ui/traits/check-trait-object-bounds-2.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0277]: expected a `std::ops::FnOnce<(&i32,)>` closure, found `i32`
|
||||
--> $DIR/check-trait-object-bounds-2.rs:13:5
|
||||
|
|
||||
LL | fn f<T: for<'r> X<'r> + ?Sized>() {
|
||||
| ------------- required by this bound in `f`
|
||||
...
|
||||
LL | f::<dyn for<'x> X<'x, F = i32>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&i32,)>` closure, found `i32`
|
||||
|
|
||||
= help: the trait `for<'r> std::ops::FnOnce<(&'r i32,)>` is not implemented for `i32`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
21
src/test/ui/traits/check-trait-object-bounds-3.rs
Normal file
21
src/test/ui/traits/check-trait-object-bounds-3.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Check that we validate associated type bounds for trait objects
|
||||
|
||||
trait X<'a> {
|
||||
type Y: Into<&'static str> + From<&'a str>;
|
||||
}
|
||||
|
||||
fn f<'a, T: X<'a> + ?Sized>(s: &'a str) -> &'static str {
|
||||
T::Y::from(s).into()
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let z;
|
||||
{
|
||||
let s = String::from("abcdef");
|
||||
z = f::<dyn X<Y = &str>>(&s);
|
||||
//~^ ERROR `s` does not live long enough
|
||||
}
|
||||
|
||||
println!("{}", z)
|
||||
}
|
||||
|
12
src/test/ui/traits/check-trait-object-bounds-3.stderr
Normal file
12
src/test/ui/traits/check-trait-object-bounds-3.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied
|
||||
--> $DIR/check-trait-object-bounds-3.rs:12:5
|
||||
|
|
||||
LL | fn f<T: X + ?Sized>() {
|
||||
| - required by this bound in `f`
|
||||
...
|
||||
LL | f::<dyn X<Y = str>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user