mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-10 14:02:57 +00:00
Make traits with assoc types invariant in their inputs.
This commit is contained in:
parent
0bd15657d9
commit
db6ae66764
@ -265,13 +265,7 @@ pub trait Combine<'tcx> : Sized {
|
||||
Err(ty::terr_projection_name_mismatched(
|
||||
expected_found(self, a.item_name, b.item_name)))
|
||||
} else {
|
||||
// Note that the trait refs for the projection must be
|
||||
// *equal*. This is because there is no inherent
|
||||
// relationship between `<T as Foo>::Bar` and `<U as
|
||||
// Foo>::Bar` that we can derive based on how `T` relates
|
||||
// to `U`. Issue #21726 contains further discussion and
|
||||
// in-depth examples.
|
||||
let trait_ref = try!(self.equate().trait_refs(&*a.trait_ref, &*b.trait_ref));
|
||||
let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref));
|
||||
Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
|
||||
}
|
||||
}
|
||||
|
@ -203,6 +203,56 @@
|
||||
//! failure, but rather because the target type `Foo<Y>` is itself just
|
||||
//! not well-formed. Basically we get to assume well-formedness of all
|
||||
//! types involved before considering variance.
|
||||
//!
|
||||
//! ### Associated types
|
||||
//!
|
||||
//! Any trait with an associated type is invariant with respect to all
|
||||
//! of its inputs. To see why this makes sense, consider what
|
||||
//! subtyping for a trait reference means:
|
||||
//!
|
||||
//! <T as Trait> <: <U as Trait>
|
||||
//!
|
||||
//! means that if I know that `T as Trait`,
|
||||
//! I also know that `U as
|
||||
//! Trait`. Moreover, if you think of it as
|
||||
//! dictionary passing style, it means that
|
||||
//! a dictionary for `<T as Trait>` is safe
|
||||
//! to use where a dictionary for `<U as
|
||||
//! Trait>` is expected.
|
||||
//!
|
||||
//! The problem is that when you can
|
||||
//! project types out from `<T as Trait>`,
|
||||
//! the relationship to types projected out
|
||||
//! of `<U as Trait>` is completely unknown
|
||||
//! unless `T==U` (see #21726 for more
|
||||
//! details). Making `Trait` invariant
|
||||
//! ensures that this is true.
|
||||
//!
|
||||
//! *Historical note: we used to preserve this invariant another way,
|
||||
//! by tweaking the subtyping rules and requiring that when a type `T`
|
||||
//! appeared as part of a projection, that was considered an invariant
|
||||
//! location, but this version does away with the need for those
|
||||
//! somewhat "special-case-feeling" rules.*
|
||||
//!
|
||||
//! Another related reason is that if we didn't make traits with
|
||||
//! associated types invariant, then projection is no longer a
|
||||
//! function with a single result. Consider:
|
||||
//!
|
||||
//! ```
|
||||
//! trait Identity { type Out; fn foo(&self); }
|
||||
//! impl<T> Identity for T { type Out = T; ... }
|
||||
//! ```
|
||||
//!
|
||||
//! Now if I have `<&'static () as Identity>::Out`, this can be
|
||||
//! validly derived as `&'a ()` for any `'a`:
|
||||
//!
|
||||
//! <&'a () as Identity> <: <&'static () as Identity>
|
||||
//! if &'static () < : &'a () -- Identity is contravariant in Self
|
||||
//! if 'static : 'a -- Subtyping rules for relations
|
||||
//!
|
||||
//! This change otoh means that `<'static () as Identity>::Out` is
|
||||
//! always `&'static ()` (which might then be upcast to `'a ()`,
|
||||
//! separately). This was helpful in solving #21750.
|
||||
|
||||
use self::VarianceTerm::*;
|
||||
use self::ParamKind::*;
|
||||
@ -613,7 +663,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
|
||||
&method.fty.sig,
|
||||
self.covariant);
|
||||
}
|
||||
ty::TypeTraitItem(_) => {}
|
||||
ty::TypeTraitItem(ref data) => {
|
||||
// Any trait with an associated type is
|
||||
// invariant with respect to all of its
|
||||
// inputs. See length discussion in the comment
|
||||
// on this module.
|
||||
let projection_ty = ty::mk_projection(tcx,
|
||||
trait_def.trait_ref.clone(),
|
||||
data.name);
|
||||
self.add_constraints_from_ty(&trait_def.generics,
|
||||
projection_ty,
|
||||
self.invariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -893,7 +954,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
trait_def.generics.types.as_slice(),
|
||||
trait_def.generics.regions.as_slice(),
|
||||
trait_ref.substs,
|
||||
self.invariant);
|
||||
variance);
|
||||
}
|
||||
|
||||
ty::ty_trait(ref data) => {
|
||||
|
Loading…
Reference in New Issue
Block a user