From b1963154a10fd22d16a5eddd751046cc897e909c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Aug 2015 09:30:19 -0400 Subject: [PATCH] Add two new kinds of predicates, WellFormed and ObjectSafe. --- src/librustc/metadata/tydecode.rs | 6 ++++ src/librustc/metadata/tyencode.rs | 7 ++++ src/librustc/middle/free_region.rs | 2 ++ src/librustc/middle/implicator.rs | 5 ++- src/librustc/middle/traits/fulfill.rs | 38 ++++++++++++++++++--- src/librustc/middle/traits/object_safety.rs | 6 +++- src/librustc/middle/traits/select.rs | 20 +++++++++++ src/librustc/middle/traits/util.rs | 22 +++++++++++- src/librustc/middle/ty.rs | 30 ++++++++++++++++ src/librustc/middle/ty_fold.rs | 4 +++ src/librustc/util/ppaux.rs | 5 +++ src/librustc_typeck/check/closure.rs | 2 ++ src/librustc_typeck/check/dropck.rs | 6 ++-- src/librustc_typeck/collect.rs | 2 ++ src/librustdoc/clean/mod.rs | 4 ++- src/libsyntax/ast.rs | 2 +- 16 files changed, 149 insertions(+), 12 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 679213874f9..a8b22846b78 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -790,6 +790,12 @@ fn parse_predicate_<'a,'tcx, F>(st: &mut PState<'a, 'tcx>, 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty_(st, conv), parse_region_(st, conv))).to_predicate(), 'p' => ty::Binder(parse_projection_predicate_(st, conv)).to_predicate(), + 'w' => ty::Predicate::WellFormed(parse_ty_(st, conv)), + 'O' => { + let def_id = parse_def_(st, NominalType, conv); + assert_eq!(next(st), '|'); + ty::Predicate::ObjectSafe(def_id) + } c => panic!("Encountered invalid character in metadata: {}", c) } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 88666be6c2c..7170a368171 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -457,6 +457,13 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Encoder, mywrite!(w, "p"); enc_projection_predicate(w, cx, data) } + ty::Predicate::WellFormed(data) => { + mywrite!(w, "w"); + enc_ty(w, cx, data); + } + ty::Predicate::ObjectSafe(trait_def_id) => { + mywrite!(w, "O{}|", (cx.ds)(trait_def_id)); + } } } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 9a5f0367231..5af37e9530c 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -57,6 +57,8 @@ impl FreeRegionMap { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::TypeOutlives(..) => { // No region bounds here } diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index 21f09574a3f..1961c15d6e6 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -13,7 +13,7 @@ use middle::infer::{InferCtxt, GenericKind}; use middle::subst::Substs; use middle::traits; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, ToPredicate, Ty}; +use middle::ty::{self, RegionEscape, ToPredicate, Ty}; use middle::ty_fold::{TypeFoldable, TypeFolder}; use syntax::ast; @@ -299,6 +299,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { } } } + ty::Predicate::ObjectSafe(_) | + ty::Predicate::WellFormed(_) => { + } } } diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 44fc6b6b8ab..96637b92cef 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -10,6 +10,7 @@ use middle::infer::InferCtxt; use middle::ty::{self, RegionEscape, Ty, HasTypeFlags}; +use middle::wf; use std::collections::HashSet; use std::fmt; @@ -20,8 +21,10 @@ use util::nodemap::NodeMap; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; +use super::is_object_safe; use super::FulfillmentError; use super::ObligationCause; +use super::ObligationCauseCode; use super::PredicateObligation; use super::project; use super::select::SelectionContext; @@ -472,6 +475,32 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } } } + + ty::Predicate::ObjectSafe(trait_def_id) => { + if !is_object_safe(selcx.tcx(), trait_def_id) { + errors.push(FulfillmentError::new( + obligation.clone(), + CodeSelectionError(Unimplemented))); + } + true + } + + ty::Predicate::WellFormed(ty) => { + let rfc1214 = match obligation.cause.code { + ObligationCauseCode::RFC1214(_) => true, + _ => false, + }; + match wf::obligations(selcx.infcx(), obligation.cause.body_id, + ty, obligation.cause.span, rfc1214) { + Some(obligations) => { + new_obligations.extend(obligations); + true + } + None => { + false + } + } + } } } @@ -492,11 +521,12 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, sub_region: r_b, cause: cause }; - debug!("register_region_obligation({:?})", - region_obligation); + debug!("register_region_obligation({:?}, cause={:?})", + region_obligation, region_obligation.cause); - region_obligations.entry(region_obligation.cause.body_id).or_insert(vec![]) - .push(region_obligation); + region_obligations.entry(region_obligation.cause.body_id) + .or_insert(vec![]) + .push(region_obligation); } diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index e7f11b06bd1..9d300c09731 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -40,7 +40,7 @@ pub enum ObjectSafetyViolation<'tcx> { } /// Reasons a method might not be object-safe. -#[derive(Copy,Clone,Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum MethodViolationCode { /// e.g., `fn foo()` StaticMethod, @@ -140,6 +140,8 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, .any(is_self) } ty::Predicate::Projection(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::Equate(..) => { @@ -181,6 +183,8 @@ fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::TypeOutlives(..) => { false } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 0c9cf1a68b7..6c568b656c0 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -44,6 +44,7 @@ use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; use middle::ty_match; use middle::ty_relate::TypeRelation; +use middle::wf; use std::cell::RefCell; use std::fmt; @@ -465,12 +466,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::Predicate::WellFormed(ty) => { + match wf::obligations(self.infcx, obligation.cause.body_id, + ty, obligation.cause.span, + obligation.cause.code.is_rfc1214()) { + Some(obligations) => + self.evaluate_predicates_recursively(previous_stack, obligations.iter()), + None => + EvaluatedToAmbig, + } + } + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { // we do not consider region relationships when // evaluating trait matches EvaluatedToOk } + ty::Predicate::ObjectSafe(trait_def_id) => { + if object_safety::is_object_safe(self.tcx(), trait_def_id) { + EvaluatedToOk + } else { + EvaluatedToErr(Unimplemented) + } + } + ty::Predicate::Projection(ref data) => { self.infcx.probe(|_| { let project_obligation = obligation.with(data.clone()); diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index af9d5e5157d..6df13a3bdaf 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -10,7 +10,7 @@ use middle::subst::Substs; use middle::infer::InferCtxt; -use middle::ty::{self, Ty, ToPredicate, ToPolyTraitRef}; +use middle::ty::{self, HasTypeFlags, Ty, ToPredicate, ToPolyTraitRef}; use std::fmt; use syntax::ast; use syntax::codemap::Span; @@ -56,6 +56,12 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> { ty::Predicate::Projection(ref data) => ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::WellFormed(data) => + ty::Predicate::WellFormed(data), + + ty::Predicate::ObjectSafe(data) => + ty::Predicate::ObjectSafe(data), }; self.set.insert(normalized_pred) } @@ -136,6 +142,14 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { self.stack.extend(predicates); } + ty::Predicate::WellFormed(..) => { + // Currently, we do not elaborate WF predicates, + // although we easily could. + } + ty::Predicate::ObjectSafe(..) => { + // Currently, we do not elaborate object-safe + // predicates. + } ty::Predicate::Equate(..) => { // Currently, we do not "elaborate" predicates like // `X == Y`, though conceivably we might. For example, @@ -562,3 +576,9 @@ impl<'tcx> fmt::Debug for super::MismatchedProjectionTypes<'tcx> { write!(f, "MismatchedProjectionTypes({:?})", self.err) } } + +impl<'tcx, T: HasTypeFlags> HasTypeFlags for Obligation<'tcx, T> { + fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { + self.predicate.has_type_flags(flags) + } +} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 7d807bf2431..393bb83067c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2417,6 +2417,12 @@ pub enum Predicate<'tcx> { /// where ::Name == X, approximately. /// See `ProjectionPredicate` struct for details. Projection(PolyProjectionPredicate<'tcx>), + + /// no syntax: T WF + WellFormed(Ty<'tcx>), + + /// trait must be object-safe + ObjectSafe(ast::DefId), } impl<'tcx> Predicate<'tcx> { @@ -2502,6 +2508,10 @@ impl<'tcx> Predicate<'tcx> { Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), Predicate::Projection(ty::Binder(ref data)) => Predicate::Projection(ty::Binder(data.subst(tcx, substs))), + Predicate::WellFormed(data) => + Predicate::WellFormed(data.subst(tcx, substs)), + Predicate::ObjectSafe(trait_def_id) => + Predicate::ObjectSafe(trait_def_id), } } } @@ -2689,6 +2699,12 @@ impl<'tcx> Predicate<'tcx> { .chain(Some(data.0.ty)) .collect() } + ty::Predicate::WellFormed(data) => { + vec![data] + } + ty::Predicate::ObjectSafe(_trait_def_id) => { + vec![] + } }; // The only reason to collect into a vector here is that I was @@ -2706,6 +2722,8 @@ impl<'tcx> Predicate<'tcx> { Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), Predicate::Projection(ref p) => p.has_escaping_regions(), + Predicate::WellFormed(p) => p.has_escaping_regions(), + Predicate::ObjectSafe(_trait_def_id) => false, } } @@ -2717,6 +2735,8 @@ impl<'tcx> Predicate<'tcx> { Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | + Predicate::WellFormed(..) | + Predicate::ObjectSafe(..) | Predicate::TypeOutlives(..) => { None } @@ -6211,6 +6231,8 @@ impl<'tcx> ctxt<'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::RegionOutlives(..) => { None } @@ -6712,6 +6734,8 @@ impl<'tcx> ctxt<'tcx> { ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::TypeOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::Projection(..) => { // For now, assume all these where-clauses // may give drop implementation capabilty @@ -6956,6 +6980,8 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), Predicate::Projection(ref pair) => write!(f, "{:?}", pair), + Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty), + Predicate::ObjectSafe(trait_def_id) => write!(f, "ObjectSafe({:?})", trait_def_id), } } } @@ -7080,6 +7106,8 @@ impl<'tcx> RegionEscape for Predicate<'tcx> { Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth), Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth), Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth), + Predicate::WellFormed(ty) => ty.has_regions_escaping_depth(depth), + Predicate::ObjectSafe(_trait_def_id) => false, } } } @@ -7238,6 +7266,8 @@ impl<'tcx> HasTypeFlags for Predicate<'tcx> { Predicate::RegionOutlives(ref data) => data.has_type_flags(flags), Predicate::TypeOutlives(ref data) => data.has_type_flags(flags), Predicate::Projection(ref data) => data.has_type_flags(flags), + Predicate::WellFormed(data) => data.has_type_flags(flags), + Predicate::ObjectSafe(_trait_def_id) => false, } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index cc1efeaea08..809ee8928af 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -394,6 +394,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::TypeOutlives(binder.fold_with(folder)), ty::Predicate::Projection(ref binder) => ty::Predicate::Projection(binder.fold_with(folder)), + ty::Predicate::WellFormed(data) => + ty::Predicate::WellFormed(data.fold_with(folder)), + ty::Predicate::ObjectSafe(trait_def_id) => + ty::Predicate::ObjectSafe(trait_def_id), } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index da20f730bab..3e9a64a8eb6 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -831,6 +831,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { 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::WellFormed(ty) => write!(f, "{} well-formed", ty), + ty::Predicate::ObjectSafe(trait_def_id) => + ty::tls::with(|tcx| { + write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id)) + }), } } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index cb5875ec8bc..9098b241e5b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -177,6 +177,8 @@ fn deduce_expectations_from_obligations<'a,'tcx>( ty::Predicate::Equate(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::WellFormed(..) => None, + ty::Predicate::ObjectSafe(..) => None, }; opt_trait_ref .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid)) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 39e67beab58..30a9d65661a 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -254,9 +254,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( /// This function is meant to by applied to the type for every /// expression in the program. pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, - typ: ty::Ty<'tcx>, - span: Span, - scope: region::CodeExtent) { + typ: ty::Ty<'tcx>, + span: Span, + scope: region::CodeExtent) { debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", typ, scope); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index dabc09db68d..3c315e335c6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -490,6 +490,8 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { } ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::Projection(..) => { false } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 52f69784b5c..04b1f8ee1b1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -818,7 +818,9 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::Equate(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) + Predicate::Projection(ref pred) => pred.clean(cx), + Predicate::WellFormed(_) => panic!("not user writable"), + Predicate::ObjectSafe(_) => panic!("not user writable"), } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index bcc90dc47d9..08c6dcc7f87 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -475,7 +475,7 @@ pub enum WherePredicate { /// A lifetime predicate, e.g. `'a: 'b+'c` RegionPredicate(WhereRegionPredicate), /// An equality predicate (unsupported) - EqPredicate(WhereEqPredicate) + EqPredicate(WhereEqPredicate), } /// A type bound, eg `for<'c> Foo: Send+Clone+'c`