Add two new kinds of predicates, WellFormed and ObjectSafe.

This commit is contained in:
Niko Matsakis 2015-08-07 09:30:19 -04:00
parent 928955296e
commit b1963154a1
16 changed files with 149 additions and 12 deletions

View file

@ -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)
}
}

View file

@ -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));
}
}
}

View file

@ -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
}

View file

@ -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(_) => {
}
}
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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());

View file

@ -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)
}
}

View file

@ -2417,6 +2417,12 @@ pub enum Predicate<'tcx> {
/// where <T as TraitRef>::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,
}
}
}

View file

@ -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),
}
}
}

View file

@ -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))
}),
}
}
}

View file

@ -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))

View file

@ -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);

View file

@ -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
}

View file

@ -818,7 +818,9 @@ impl<'a> Clean<WherePredicate> 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"),
}
}
}

View file

@ -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`