mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Properly generate multiple candidates for trait upcasting coercion.
This commit is contained in:
parent
adf1688447
commit
1e605023ec
@ -135,6 +135,11 @@ pub enum SelectionCandidate<'tcx> {
|
||||
/// `rustc_infer::traits::util::supertraits`.
|
||||
ObjectCandidate(usize),
|
||||
|
||||
/// Perform trait upcasting coercion of `dyn Trait` to a supertrait of `Trait`.
|
||||
/// The index is the position in the iterator returned by
|
||||
/// `rustc_infer::traits::util::supertraits`.
|
||||
TraitUpcastingUnsizeCandidate(usize),
|
||||
|
||||
BuiltinObjectCandidate,
|
||||
|
||||
BuiltinUnsizeCandidate,
|
||||
|
@ -690,19 +690,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
debug!(?source, ?target, "assemble_candidates_for_unsizing");
|
||||
|
||||
let may_apply = match (source.kind(), target.kind()) {
|
||||
match (source.kind(), target.kind()) {
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
|
||||
// See `confirm_builtin_unsize_candidate` for more info.
|
||||
// Upcast coercions permit several things:
|
||||
//
|
||||
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
|
||||
// 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
|
||||
//
|
||||
// Note that neither of the first two of these changes requires any
|
||||
// change at runtime. The third needs to change pointer metadata at runtime.
|
||||
//
|
||||
// We always perform upcasting coercions when we can because of reason
|
||||
// #2 (region bounds).
|
||||
let auto_traits_compatible = data_b
|
||||
.auto_traits()
|
||||
// All of a's auto traits need to be in b's auto traits.
|
||||
.all(|b| data_a.auto_traits().any(|a| a == b));
|
||||
auto_traits_compatible
|
||||
if auto_traits_compatible {
|
||||
let principal_def_id_a = data_a.principal_def_id();
|
||||
let principal_def_id_b = data_b.principal_def_id();
|
||||
if principal_def_id_a == principal_def_id_b {
|
||||
// no cyclic
|
||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||
} else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
|
||||
// not casual unsizing, now check whether this is trait upcasting coercion.
|
||||
let principal_a = data_a.principal().unwrap();
|
||||
let target_trait_did = principal_def_id_b.unwrap();
|
||||
let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
|
||||
for (idx, upcast_trait_ref) in
|
||||
util::supertraits(self.tcx(), source_trait_ref).enumerate()
|
||||
{
|
||||
if upcast_trait_ref.def_id() == target_trait_did {
|
||||
candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `T` -> `Trait`
|
||||
(_, &ty::Dynamic(..)) => true,
|
||||
(_, &ty::Dynamic(..)) => {
|
||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||
}
|
||||
|
||||
// Ambiguous handling is below `T` -> `Trait`, because inference
|
||||
// variables can still implement `Unsize<Trait>` and nested
|
||||
@ -710,26 +741,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
(&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
|
||||
debug!("assemble_candidates_for_unsizing: ambiguous");
|
||||
candidates.ambiguous = true;
|
||||
false
|
||||
}
|
||||
|
||||
// `[T; n]` -> `[T]`
|
||||
(&ty::Array(..), &ty::Slice(_)) => true,
|
||||
(&ty::Array(..), &ty::Slice(_)) => {
|
||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||
}
|
||||
|
||||
// `Struct<T>` -> `Struct<U>`
|
||||
(&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
|
||||
def_id_a == def_id_b
|
||||
if def_id_a == def_id_b {
|
||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
// `(.., T)` -> `(.., U)`
|
||||
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
|
||||
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
|
||||
if tys_a.len() == tys_b.len() {
|
||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
_ => false,
|
||||
_ => {}
|
||||
};
|
||||
|
||||
if may_apply {
|
||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_candidates_for_trait_alias(
|
||||
|
@ -118,6 +118,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let data = self.confirm_builtin_unsize_candidate(obligation)?;
|
||||
Ok(ImplSource::Builtin(data))
|
||||
}
|
||||
|
||||
TraitUpcastingUnsizeCandidate(idx) => {
|
||||
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
|
||||
Ok(ImplSource::Builtin(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,6 +690,81 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
|
||||
}
|
||||
|
||||
fn confirm_trait_upcasting_unsize_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
idx: usize,
|
||||
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
|
||||
// regions here. See the comment there for more details.
|
||||
let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
|
||||
let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
|
||||
let target = self.infcx.shallow_resolve(target);
|
||||
|
||||
debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate");
|
||||
|
||||
let mut nested = vec![];
|
||||
match (source.kind(), target.kind()) {
|
||||
// TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
|
||||
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
||||
// See `assemble_candidates_for_unsizing` for more info.
|
||||
// We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
|
||||
let principal_a = data_a.principal().unwrap();
|
||||
let source_trait_ref = principal_a.with_self_ty(tcx, source);
|
||||
let target_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
|
||||
assert_eq!(data_b.principal_def_id(), Some(target_trait_ref.def_id()));
|
||||
let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
|
||||
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
|
||||
tcx, trait_ref,
|
||||
))
|
||||
});
|
||||
let iter = Some(existential_predicate)
|
||||
.into_iter()
|
||||
.chain(
|
||||
data_a
|
||||
.projection_bounds()
|
||||
.map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
|
||||
)
|
||||
.chain(
|
||||
data_b
|
||||
.auto_traits()
|
||||
.map(ty::ExistentialPredicate::AutoTrait)
|
||||
.map(ty::Binder::dummy),
|
||||
);
|
||||
let existential_predicates = tcx.mk_poly_existential_predicates(iter);
|
||||
let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
|
||||
|
||||
// Require that the traits involved in this upcast are **equal**;
|
||||
// only the **lifetime bound** is changed.
|
||||
let InferOk { obligations, .. } = self
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(target, source_trait)
|
||||
.map_err(|_| Unimplemented)?;
|
||||
nested.extend(obligations);
|
||||
|
||||
// Register one obligation for 'a: 'b.
|
||||
let cause = ObligationCause::new(
|
||||
obligation.cause.span,
|
||||
obligation.cause.body_id,
|
||||
ObjectCastObligation(target),
|
||||
);
|
||||
let outlives = ty::OutlivesPredicate(r_a, r_b);
|
||||
nested.push(Obligation::with_depth(
|
||||
cause,
|
||||
obligation.recursion_depth + 1,
|
||||
obligation.param_env,
|
||||
obligation.predicate.rebind(outlives).to_predicate(tcx),
|
||||
));
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
Ok(ImplSourceBuiltinData { nested })
|
||||
}
|
||||
|
||||
fn confirm_builtin_unsize_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
@ -701,58 +781,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
let mut nested = vec![];
|
||||
match (source.kind(), target.kind()) {
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
|
||||
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
||||
// Upcast coercions permit several things:
|
||||
//
|
||||
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
|
||||
// 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
|
||||
//
|
||||
// Note that neither of the first two of these changes requires any
|
||||
// change at runtime. The third needs to change pointer metadata at runtime.
|
||||
//
|
||||
// We always perform upcasting coercions when we can because of reason
|
||||
// #2 (region bounds).
|
||||
|
||||
// See `assemble_candidates_for_unsizing` for more info.
|
||||
// We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
|
||||
|
||||
let principal_a = data_a.principal();
|
||||
let principal_def_id_b = data_b.principal_def_id();
|
||||
|
||||
let existential_predicate = if let Some(principal_a) = principal_a {
|
||||
let source_trait_ref = principal_a.with_self_ty(tcx, source);
|
||||
let target_trait_did = principal_def_id_b.ok_or_else(|| Unimplemented)?;
|
||||
let upcast_idx = util::supertraits(tcx, source_trait_ref)
|
||||
.position(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
|
||||
.ok_or_else(|| Unimplemented)?;
|
||||
// FIXME(crlf0710): This is less than ideal, for example,
|
||||
// if the trait is defined as `trait Foo: Bar<u32> + Bar<i32>`,
|
||||
// the coercion from Box<Foo> to Box<dyn Bar<_>> is actually ambiguous.
|
||||
// We currently make this coercion fail for now.
|
||||
//
|
||||
// see #65991 for more information.
|
||||
if util::supertraits(tcx, source_trait_ref)
|
||||
.skip(upcast_idx + 1)
|
||||
.any(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
|
||||
{
|
||||
return Err(Unimplemented);
|
||||
}
|
||||
let target_trait_ref =
|
||||
util::supertraits(tcx, source_trait_ref).nth(upcast_idx).unwrap();
|
||||
let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
|
||||
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
|
||||
tcx, trait_ref,
|
||||
))
|
||||
});
|
||||
Some(existential_predicate)
|
||||
} else if principal_def_id_b.is_none() {
|
||||
None
|
||||
} else {
|
||||
return Err(Unimplemented);
|
||||
};
|
||||
|
||||
let iter = existential_predicate
|
||||
let iter = data_a
|
||||
.principal()
|
||||
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
|
||||
.into_iter()
|
||||
.chain(
|
||||
data_a
|
||||
|
@ -1500,6 +1500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..)
|
||||
| ObjectCandidate(_)
|
||||
@ -1517,6 +1518,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
ParamCandidate(ref cand),
|
||||
@ -1546,6 +1548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..),
|
||||
) => true,
|
||||
@ -1557,6 +1560,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate(..),
|
||||
ObjectCandidate(_) | ProjectionCandidate(_),
|
||||
@ -1630,6 +1634,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
ImplCandidate(_)
|
||||
@ -1638,6 +1643,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
| FnPointerCandidate
|
||||
| BuiltinObjectCandidate
|
||||
| BuiltinUnsizeCandidate
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { has_nested: true }
|
||||
| TraitAliasCandidate(..),
|
||||
) => false,
|
||||
|
@ -9,12 +9,8 @@ trait Bar<T> {
|
||||
}
|
||||
|
||||
fn test_specific(x: &dyn Foo) {
|
||||
let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<i32>` is not satisfied
|
||||
let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
let _ = x as &dyn Bar<i32>; // OK
|
||||
let _ = x as &dyn Bar<u32>; // OK
|
||||
}
|
||||
|
||||
fn test_unknown_version(x: &dyn Foo) {
|
||||
@ -24,9 +20,7 @@ fn test_unknown_version(x: &dyn Foo) {
|
||||
}
|
||||
|
||||
fn test_infer_version(x: &dyn Foo) {
|
||||
let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
let a = x as &dyn Bar<_>; // OK
|
||||
let _: Option<u32> = a.bar();
|
||||
}
|
||||
|
||||
|
@ -1,43 +1,5 @@
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<i32>`
|
||||
--> $DIR/type-checking-test-1.rs:12:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| +
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
|
||||
--> $DIR/type-checking-test-1.rs:15:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
| +
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<i32>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:12:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<i32>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<i32>`
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:15:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
|
||||
--> $DIR/type-checking-test-1.rs:21:13
|
||||
--> $DIR/type-checking-test-1.rs:17:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||
@ -48,33 +10,14 @@ LL | let _ = &x as &dyn Bar<_>; // Ambiguous
|
||||
| +
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:21:13
|
||||
--> $DIR/type-checking-test-1.rs:17:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<_>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
|
||||
--> $DIR/type-checking-test-1.rs:27:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let a = &x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
| +
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:27:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0605.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
@ -13,9 +13,7 @@ fn test_specific(x: &dyn Foo<i32>) {
|
||||
}
|
||||
|
||||
fn test_specific2(x: &dyn Foo<u32>) {
|
||||
let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
|
||||
let _ = x as &dyn Bar<i32>; // OK
|
||||
}
|
||||
|
||||
fn test_specific3(x: &dyn Foo<i32>) {
|
||||
|
@ -1,24 +1,5 @@
|
||||
error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<i32>`
|
||||
--> $DIR/type-checking-test-2.rs:16:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| +
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
|
||||
--> $DIR/type-checking-test-2.rs:16:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<i32>` is not implemented for `&dyn Foo<u32>`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<i32>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
|
||||
--> $DIR/type-checking-test-2.rs:22:13
|
||||
--> $DIR/type-checking-test-2.rs:20:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // Error
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
@ -29,7 +10,7 @@ LL | let _ = &x as &dyn Bar<u32>; // Error
|
||||
| +
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
|
||||
--> $DIR/type-checking-test-2.rs:22:13
|
||||
--> $DIR/type-checking-test-2.rs:20:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // Error
|
||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>`
|
||||
@ -37,7 +18,7 @@ LL | let _ = x as &dyn Bar<u32>; // Error
|
||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
|
||||
--> $DIR/type-checking-test-2.rs:28:13
|
||||
--> $DIR/type-checking-test-2.rs:26:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||
@ -48,14 +29,14 @@ LL | let a = &x as &dyn Bar<_>; // Ambiguous
|
||||
| +
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
|
||||
--> $DIR/type-checking-test-2.rs:28:13
|
||||
--> $DIR/type-checking-test-2.rs:26:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<_>`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0605.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user