From 58609ef879e604d161f4ee6c612d6d127120e289 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 21:47:09 -0500 Subject: [PATCH] add Subtype predicate --- src/librustc/ich/impls_ty.rs | 4 +++ src/librustc/infer/mod.rs | 39 ++++++++++++++++++++++- src/librustc/middle/free_region.rs | 1 + src/librustc/traits/error_reporting.rs | 23 +++++++++++++ src/librustc/traits/fulfill.rs | 21 ++++++++++++ src/librustc/traits/object_safety.rs | 2 ++ src/librustc/traits/select.rs | 12 +++++++ src/librustc/traits/structural_impls.rs | 1 + src/librustc/traits/util.rs | 9 +++++- src/librustc/ty/mod.rs | 17 ++++++++++ src/librustc/ty/structural_impls.rs | 35 ++++++++++++++++++-- src/librustc/ty/util.rs | 1 + src/librustc/ty/wf.rs | 5 +++ src/librustc/util/ppaux.rs | 14 ++++++++ src/librustc_typeck/check/closure.rs | 1 + src/librustc_typeck/check/method/probe.rs | 1 + src/librustdoc/clean/mod.rs | 11 +++++++ 17 files changed, 193 insertions(+), 4 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b6f3af2a11..b8888eee9c6 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -170,6 +170,7 @@ fn hash_stable(&self, 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> for ty::OutlivesPredicate where A: HashStable>, @@ -200,6 +201,9 @@ fn hash_stable(&self, 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); } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 98c8ce0f031..999ebbfa20f 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -551,7 +551,7 @@ pub fn enter(&'tcx mut self, f: F) -> R } impl ExpectedFound { - 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 { @@ -1129,6 +1129,43 @@ pub fn equality_predicate(&self, }) } + pub fn subtype_predicate(&self, + cause: &ObligationCause<'tcx>, + predicate: &ty::PolySubtypePredicate<'tcx>) + -> Option> + { + // 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>) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab400..963cc4314ed 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -60,6 +60,7 @@ pub fn relate_free_regions_from_predicates(&mut self, ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 931c77badad..8a303a5da11 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -39,6 +39,7 @@ 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}; @@ -112,6 +113,13 @@ fn report_fulfillment_error(&self, 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(); + } } } @@ -555,6 +563,11 @@ pub fn report_selection_error(&self, 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, @@ -761,6 +774,16 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) { } } + 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, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index b87d1846437..64453f2983b 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -11,6 +11,7 @@ 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; @@ -496,6 +497,26 @@ fn process_predicate<'a, 'gcx, 'tcx>( 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)) + } + } + } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7cd0b26940d..d190635bec3 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -178,6 +178,7 @@ fn predicates_reference_self( ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Equate(..) => { false } @@ -209,6 +210,7 @@ fn generics_require_sized_self(self, def_id: DefId) -> bool { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 38ea1e4a19b..67d50210ba3 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -568,6 +568,18 @@ fn evaluate_predicate_recursively<'o>(&mut self, } } + 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) { diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 44ef461327d..fcaa29be963 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -130,6 +130,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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") } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 602f27a64d4..d4245ec9b24 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -42,7 +42,10 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, 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)), } } @@ -160,6 +163,10 @@ fn push(&mut self, predicate: &ty::Predicate<'tcx>) { // `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. } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41..d720911db39 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -755,6 +755,9 @@ pub enum Predicate<'tcx> { /// 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> { @@ -833,6 +836,8 @@ pub fn subst_supertrait(&self, tcx: TyCtxt<'a, 'gcx, '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)) => @@ -912,6 +917,14 @@ pub fn dep_node(&self) -> DepNode { &'tcx ty::Region>; pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'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>; + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1025,6 +1038,9 @@ pub fn walk_tys(&self) -> IntoIter> { 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] } @@ -1061,6 +1077,7 @@ pub fn to_opt_poly_trait_ref(&self) -> Option> { } Predicate::Projection(..) | Predicate::Equate(..) | + Predicate::Subtype(..) | Predicate::RegionOutlives(..) | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9126600e3f6..a4466d7d840 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -111,6 +111,18 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) } } +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> { + 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 { type Lifted = ty::OutlivesPredicate; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -167,6 +179,9 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { 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) } @@ -693,6 +708,8 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) 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) => @@ -712,6 +729,7 @@ fn super_visit_with>(&self, visitor: &mut V) -> bool { 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), @@ -776,8 +794,7 @@ fn super_visit_with>(&self, visitor: &mut V) -> bool { 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>(&self, visitor: &mut V) -> bool { @@ -785,6 +802,20 @@ fn super_visit_with>(&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>(&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 { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd8191303a9..2efefd750ae 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -312,6 +312,7 @@ pub fn required_region_bounds(self, ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 8a5bd6862cf..0b0e8a180cc 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,6 +94,10 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } ty::Predicate::ClosureKind(..) => { } + ty::Predicate::Subtype(ref data) => { + wf.compute(data.skip_binder().a); // (*) + wf.compute(data.skip_binder().b); // (*) + } } wf.normalize() @@ -156,6 +160,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( match obligation.predicate { ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::ObjectSafe(..) => diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6323f1dc0d4..2daf71d95ad 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -416,6 +416,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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), @@ -676,6 +677,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +impl<'tcx> fmt::Display for ty::Binder> { + 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> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) @@ -897,6 +904,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +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({:?})", @@ -949,6 +962,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 51fbc5aab6c..78176b15569 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -169,6 +169,7 @@ fn deduce_expectations_from_obligations 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, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 5b041892156..8071fe3cc28 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -576,6 +576,7 @@ fn assemble_inherent_candidates_from_param(&mut self, } } ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac72d7d29a2..1a194cd1254 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -875,6 +875,7 @@ fn clean(&self, cx: &DocContext) -> WherePredicate { 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), @@ -904,6 +905,16 @@ fn clean(&self, cx: &DocContext) -> WherePredicate { } } +impl<'tcx> Clean 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 for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::OutlivesPredicate(ref a, ref b) = *self; -- 2.44.0