impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
+impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b });
impl<'a, 'tcx, A, B> HashStable<StableHashingContext<'a, 'tcx>> for ty::OutlivesPredicate<A, B>
where A: HashStable<StableHashingContext<'a, 'tcx>>,
ty::Predicate::Equate(ref pred) => {
pred.hash_stable(hcx, hasher);
}
+ ty::Predicate::Subtype(ref pred) => {
+ pred.hash_stable(hcx, hasher);
+ }
ty::Predicate::RegionOutlives(ref pred) => {
pred.hash_stable(hcx, hasher);
}
}
impl<T> ExpectedFound<T> {
- fn new(a_is_expected: bool, a: T, b: T) -> Self {
+ pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
if a_is_expected {
ExpectedFound {expected: a, found: b}
} else {
})
}
+ pub fn subtype_predicate(&self,
+ cause: &ObligationCause<'tcx>,
+ predicate: &ty::PolySubtypePredicate<'tcx>)
+ -> Option<InferResult<'tcx, ()>>
+ {
+ // Subtle: it's ok to skip the binder here and resolve because
+ // `shallow_resolve` just ignores anything that is not a type
+ // variable, and because type variable's can't (at present, at
+ // least) capture any of the things bound by this binder.
+ //
+ // Really, there is no *particular* reason to do this
+ // `shallow_resolve` here except as a
+ // micro-optimization. Naturally I could not
+ // resist. -nmatsakis
+ let two_unbound_type_vars = {
+ let a = self.shallow_resolve(predicate.skip_binder().a);
+ let b = self.shallow_resolve(predicate.skip_binder().b);
+ a.is_ty_var() && b.is_ty_var()
+ };
+
+ if two_unbound_type_vars {
+ // Two unbound type variables? Can't make progress.
+ return None;
+ }
+
+ Some(self.commit_if_ok(|snapshot| {
+ let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) =
+ self.skolemize_late_bound_regions(predicate, snapshot);
+
+ let cause_span = cause.span;
+ let ok = self.sub_types(a_is_expected, cause, a, b)?;
+ self.leak_check(false, cause_span, &skol_map, snapshot)?;
+ self.pop_skolemized(skol_map, snapshot);
+ Ok(ok.unit())
+ }))
+ }
+
pub fn region_outlives_predicate(&self,
cause: &traits::ObligationCause<'tcx>,
predicate: &ty::PolyRegionOutlivesPredicate<'tcx>)
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Equate(..) |
+ ty::Predicate::Subtype(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) |
use ty::fast_reject;
use ty::fold::TypeFolder;
use ty::subst::Subst;
+use ty::SubtypePredicate;
use util::nodemap::{FxHashMap, FxHashSet};
use syntax_pos::{DUMMY_SP, Span};
FulfillmentErrorCode::CodeAmbiguity => {
self.maybe_report_ambiguity(&error.obligation);
}
+ FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
+ self.report_mismatched_types(&error.obligation.cause,
+ expected_found.expected,
+ expected_found.found,
+ err.clone())
+ .emit();
+ }
}
}
err
}
+ ty::Predicate::Subtype(ref predicate) => {
+ // TODO
+ panic!("subtype requirement not satisfied {:?}", predicate)
+ }
+
ty::Predicate::Equate(ref predicate) => {
let predicate = self.resolve_type_vars_if_possible(predicate);
let err = self.equality_predicate(&obligation.cause,
}
}
+ ty::Predicate::Subtype(ref data) => {
+ if data.references_error() || self.tcx.sess.has_errors() {
+ // no need to overload user in such cases
+ } else {
+ let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
+ assert!(a.is_ty_var() && b.is_ty_var()); // else other would've been instantiated
+ self.need_type_info(obligation, a);
+ }
+ }
+
_ => {
if !self.tcx.sess.has_errors() {
let mut err = struct_span_err!(self.tcx.sess,
use dep_graph::DepGraph;
use infer::{InferCtxt, InferOk};
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
+use ty::error::ExpectedFound;
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
use std::marker::PhantomData;
s => Ok(s)
}
}
+
+ ty::Predicate::Subtype(ref subtype) => {
+ match selcx.infcx().subtype_predicate(&obligation.cause, subtype) {
+ None => {
+ // none means that both are unresolved
+ pending_obligation.stalled_on = vec![subtype.skip_binder().a,
+ subtype.skip_binder().b];
+ Ok(None)
+ }
+ Some(Ok(ok)) => {
+ Ok(Some(ok.obligations))
+ }
+ Some(Err(err)) => {
+ let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected,
+ subtype.skip_binder().a,
+ subtype.skip_binder().b);
+ Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err))
+ }
+ }
+ }
}
}
ty::Predicate::TypeOutlives(..) |
ty::Predicate::RegionOutlives(..) |
ty::Predicate::ClosureKind(..) |
+ ty::Predicate::Subtype(..) |
ty::Predicate::Equate(..) => {
false
}
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Equate(..) |
+ ty::Predicate::Subtype(..) |
ty::Predicate::RegionOutlives(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
}
}
+ ty::Predicate::Subtype(ref p) => {
+ // does this code ever run?
+ match self.infcx.subtype_predicate(&obligation.cause, p) {
+ Some(Ok(InferOk { obligations, .. })) => {
+ self.inferred_obligations.extend(obligations);
+ EvaluatedToOk
+ },
+ Some(Err(_)) => EvaluatedToErr,
+ None => EvaluatedToAmbig,
+ }
+ }
+
ty::Predicate::WellFormed(ty) => {
match ty::wf::obligations(self.infcx, obligation.cause.body_id,
ty, obligation.cause.span) {
match *self {
super::CodeSelectionError(ref e) => write!(f, "{:?}", e),
super::CodeProjectionError(ref e) => write!(f, "{:?}", e),
+ super::CodeSubtypeError(ref a, ref b) => write!(f, "CodeSubtypeError({:?}, {:?})", a, b),
super::CodeAmbiguity => write!(f, "Ambiguity")
}
}
ty::Predicate::ObjectSafe(data),
ty::Predicate::ClosureKind(closure_def_id, kind) =>
- ty::Predicate::ClosureKind(closure_def_id, kind)
+ ty::Predicate::ClosureKind(closure_def_id, kind),
+
+ ty::Predicate::Subtype(ref data) =>
+ ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)),
}
}
// `X == Y`, though conceivably we might. For example,
// `&X == &Y` implies that `X == Y`.
}
+ ty::Predicate::Subtype(..) => {
+ // Currently, we do not "elaborate" predicates like `X
+ // <: Y`, though conceivably we might.
+ }
ty::Predicate::Projection(..) => {
// Nothing to elaborate in a projection predicate.
}
/// for some substitutions `...` and T being a closure type.
/// Satisfied (or refuted) once we know the closure's kind.
ClosureKind(DefId, ClosureKind),
+
+ /// `T1 <: T2`
+ Subtype(PolySubtypePredicate<'tcx>),
}
impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
Predicate::Trait(ty::Binder(data.subst(tcx, substs))),
Predicate::Equate(ty::Binder(ref data)) =>
Predicate::Equate(ty::Binder(data.subst(tcx, substs))),
+ Predicate::Subtype(ty::Binder(ref data)) =>
+ Predicate::Subtype(ty::Binder(data.subst(tcx, substs))),
Predicate::RegionOutlives(ty::Binder(ref data)) =>
Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))),
Predicate::TypeOutlives(ty::Binder(ref data)) =>
&'tcx ty::Region>;
pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>;
+#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+pub struct SubtypePredicate<'tcx> {
+ pub a_is_expected: bool,
+ pub a: Ty<'tcx>,
+ pub b: Ty<'tcx>
+}
+pub type PolySubtypePredicate<'tcx> = ty::Binder<SubtypePredicate<'tcx>>;
+
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
ty::Predicate::Equate(ty::Binder(ref data)) => {
vec![data.0, data.1]
}
+ ty::Predicate::Subtype(ty::Binder(SubtypePredicate { a, b, a_is_expected: _ })) => {
+ vec![a, b]
+ }
ty::Predicate::TypeOutlives(ty::Binder(ref data)) => {
vec![data.0]
}
}
Predicate::Projection(..) |
Predicate::Equate(..) |
+ Predicate::Subtype(..) |
Predicate::RegionOutlives(..) |
Predicate::WellFormed(..) |
Predicate::ObjectSafe(..) |
}
}
+impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> {
+ type Lifted = ty::SubtypePredicate<'tcx>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
+ -> Option<ty::SubtypePredicate<'tcx>> {
+ tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate {
+ a_is_expected: self.a_is_expected,
+ a: a,
+ b: b,
+ })
+ }
+}
+
impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
ty::Predicate::Equate(ref binder) => {
tcx.lift(binder).map(ty::Predicate::Equate)
}
+ ty::Predicate::Subtype(ref binder) => {
+ tcx.lift(binder).map(ty::Predicate::Subtype)
+ }
ty::Predicate::RegionOutlives(ref binder) => {
tcx.lift(binder).map(ty::Predicate::RegionOutlives)
}
ty::Predicate::Trait(a.fold_with(folder)),
ty::Predicate::Equate(ref binder) =>
ty::Predicate::Equate(binder.fold_with(folder)),
+ ty::Predicate::Subtype(ref binder) =>
+ ty::Predicate::Subtype(binder.fold_with(folder)),
ty::Predicate::RegionOutlives(ref binder) =>
ty::Predicate::RegionOutlives(binder.fold_with(folder)),
ty::Predicate::TypeOutlives(ref binder) =>
match *self {
ty::Predicate::Trait(ref a) => a.visit_with(visitor),
ty::Predicate::Equate(ref binder) => binder.visit_with(visitor),
+ ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor),
ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor),
ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
ty::Predicate::Projection(ref binder) => binder.visit_with(visitor),
impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- ty::EquatePredicate(self.0.fold_with(folder),
- self.1.fold_with(folder))
+ ty::EquatePredicate(self.0.fold_with(folder), self.1.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
+impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ ty::SubtypePredicate {
+ a_is_expected: self.a_is_expected,
+ a: self.a.fold_with(folder),
+ b: self.b.fold_with(folder)
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.a.visit_with(visitor) || self.b.visit_with(visitor)
+ }
+}
+
impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::TraitPredicate {
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Equate(..) |
+ ty::Predicate::Subtype(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) |
}
ty::Predicate::ClosureKind(..) => {
}
+ ty::Predicate::Subtype(ref data) => {
+ wf.compute(data.skip_binder().a); // (*)
+ wf.compute(data.skip_binder().b); // (*)
+ }
}
wf.normalize()
match obligation.predicate {
ty::Predicate::Trait(..) |
ty::Predicate::Equate(..) |
+ ty::Predicate::Subtype(..) |
ty::Predicate::Projection(..) |
ty::Predicate::ClosureKind(..) |
ty::Predicate::ObjectSafe(..) =>
match *self {
ty::Predicate::Trait(ref a) => write!(f, "{:?}", a),
ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
+ ty::Predicate::Subtype(ref pair) => write!(f, "{:?}", pair),
ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
}
}
+impl<'tcx> fmt::Display for ty::Binder<ty::SubtypePredicate<'tcx>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
+ }
+}
+
impl<'tcx> fmt::Display for ty::Binder<ty::ProjectionPredicate<'tcx>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
+impl<'tcx> fmt::Display for ty::SubtypePredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} <: {}", self.a, self.b)
+ }
+}
+
impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TraitPredicate({:?})",
match *self {
ty::Predicate::Trait(ref data) => write!(f, "{}", data),
ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate),
+ ty::Predicate::Subtype(ref predicate) => write!(f, "{}", predicate),
ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate),
ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate),
ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate),
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
ty::Predicate::Equate(..) => None,
+ ty::Predicate::Subtype(..) => None,
ty::Predicate::RegionOutlives(..) => None,
ty::Predicate::TypeOutlives(..) => None,
ty::Predicate::WellFormed(..) => None,
}
}
ty::Predicate::Equate(..) |
+ ty::Predicate::Subtype(..) |
ty::Predicate::Projection(..) |
ty::Predicate::RegionOutlives(..) |
ty::Predicate::WellFormed(..) |
match *self {
Predicate::Trait(ref pred) => pred.clean(cx),
Predicate::Equate(ref pred) => pred.clean(cx),
+ Predicate::Subtype(ref pred) => pred.clean(cx),
Predicate::RegionOutlives(ref pred) => pred.clean(cx),
Predicate::TypeOutlives(ref pred) => pred.clean(cx),
Predicate::Projection(ref pred) => pred.clean(cx),
}
}
+impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
+ fn clean(&self, cx: &DocContext) -> WherePredicate {
+ let ty::SubtypePredicate { a_is_expected: _, a, b } = *self;
+ WherePredicate::EqPredicate { // TODO This is obviously wrong :P
+ lhs: a.clean(cx),
+ rhs: b.clean(cx)
+ }
+ }
+}
+
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref a, ref b) = *self;