Switch to using predicates to drive checking. Correct various tests --
in most cases, just the error message changed, but in some cases we are reporting new errors that OUGHT to have been reported before but we're overlooked (mostly involving the `'static` bound on `Send`).
This commit is contained in:
parent
2be6c4f1ca
commit
9f492fefef
39 changed files with 1064 additions and 870 deletions
|
@ -19,7 +19,7 @@
|
|||
|
||||
/// Types able to be transferred across task boundaries.
|
||||
#[lang="send"]
|
||||
pub trait Send for Sized? {
|
||||
pub trait Send for Sized? : 'static {
|
||||
// empty.
|
||||
}
|
||||
|
||||
|
|
|
@ -251,3 +251,7 @@ pub const tag_type_param_def: uint = 0xa5;
|
|||
|
||||
pub const tag_item_generics: uint = 0xa6;
|
||||
pub const tag_method_ty_generics: uint = 0xa7;
|
||||
|
||||
pub const tag_predicate: uint = 0xa8;
|
||||
pub const tag_predicate_space: uint = 0xa9;
|
||||
pub const tag_predicate_data: uint = 0xb0;
|
||||
|
|
|
@ -23,7 +23,8 @@ use metadata::csearch;
|
|||
use metadata::cstore;
|
||||
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
|
||||
parse_type_param_def_data, parse_bounds_data,
|
||||
parse_bare_fn_ty_data, parse_trait_ref_data};
|
||||
parse_bare_fn_ty_data, parse_trait_ref_data,
|
||||
parse_predicate_data};
|
||||
use middle::def;
|
||||
use middle::lang_items;
|
||||
use middle::resolve::{TraitItemKind, TypeTraitItemKind};
|
||||
|
@ -1437,7 +1438,18 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc,
|
|||
true
|
||||
});
|
||||
|
||||
let predicates = subst::VecPerParamSpace::empty(); // TODO fix in later commit
|
||||
let mut predicates = subst::VecPerParamSpace::empty();
|
||||
reader::tagged_docs(doc, tag_predicate, |predicate_doc| {
|
||||
let space_doc = reader::get_doc(predicate_doc, tag_predicate_space);
|
||||
let space = subst::ParamSpace::from_uint(reader::doc_as_u8(space_doc) as uint);
|
||||
|
||||
let data_doc = reader::get_doc(predicate_doc, tag_predicate_data);
|
||||
let data = parse_predicate_data(data_doc.data, data_doc.start, cdata.cnum, tcx,
|
||||
|_, did| translate_def_id(cdata, did));
|
||||
|
||||
predicates.push(space, data);
|
||||
true
|
||||
});
|
||||
|
||||
ty::Generics { types: types, regions: regions, predicates: predicates }
|
||||
}
|
||||
|
|
|
@ -803,6 +803,18 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
|
|||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
for (space, _, predicate) in generics.predicates.iter_enumerated() {
|
||||
rbml_w.start_tag(tag_predicate);
|
||||
|
||||
rbml_w.wr_tagged_u8(tag_predicate_space, space as u8);
|
||||
|
||||
rbml_w.start_tag(tag_predicate_data);
|
||||
tyencode::enc_predicate(rbml_w.writer, ty_str_ctxt, predicate);
|
||||
rbml_w.end_tag();
|
||||
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
|
|
|
@ -470,7 +470,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
|
|||
st.tcx.rcache.borrow_mut().insert(key, tt);
|
||||
return tt;
|
||||
}
|
||||
'"' => {
|
||||
'\"' => {
|
||||
let _ = parse_def(st, TypeWithId, |x,y| conv(x,y));
|
||||
let inner = parse_ty(st, |x,y| conv(x,y));
|
||||
inner
|
||||
|
@ -646,6 +646,33 @@ pub fn parse_def_id(buf: &[u8]) -> ast::DefId {
|
|||
ast::DefId { krate: crate_num, node: def_num }
|
||||
}
|
||||
|
||||
pub fn parse_predicate_data<'tcx>(data: &[u8],
|
||||
start: uint,
|
||||
crate_num: ast::CrateNum,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
conv: conv_did)
|
||||
-> ty::Predicate<'tcx>
|
||||
{
|
||||
let mut st = parse_state_from_data(data, crate_num, start, tcx);
|
||||
parse_predicate(&mut st, conv)
|
||||
}
|
||||
|
||||
pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>,
|
||||
conv: conv_did)
|
||||
-> ty::Predicate<'tcx>
|
||||
{
|
||||
match next(st) {
|
||||
't' => ty::Predicate::Trait(Rc::new(parse_trait_ref(st, conv))),
|
||||
'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)),
|
||||
parse_ty(st, |x,y| conv(x,y))),
|
||||
'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)),
|
||||
parse_region(st, |x,y| conv(x,y))),
|
||||
'o' => ty::Predicate::TypeOutlives(parse_ty(st, |x,y| conv(x,y)),
|
||||
parse_region(st, |x,y| conv(x,y))),
|
||||
c => panic!("Encountered invalid character in metadata: {}", c)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_type_param_def_data<'tcx>(data: &[u8], start: uint,
|
||||
crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>,
|
||||
conv: conv_did) -> ty::TypeParameterDef<'tcx>
|
||||
|
|
|
@ -413,3 +413,30 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
|
|||
enc_bounds(w, cx, &v.bounds);
|
||||
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
||||
}
|
||||
|
||||
pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||
cx: &ctxt<'a, 'tcx>,
|
||||
p: &ty::Predicate<'tcx>)
|
||||
{
|
||||
match *p {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
mywrite!(w, "t");
|
||||
enc_trait_ref(w, cx, &**trait_ref);
|
||||
}
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
mywrite!(w, "e");
|
||||
enc_ty(w, cx, a);
|
||||
enc_ty(w, cx, b);
|
||||
}
|
||||
ty::Predicate::RegionOutlives(a, b) => {
|
||||
mywrite!(w, "r");
|
||||
enc_region(w, cx, a);
|
||||
enc_region(w, cx, b);
|
||||
}
|
||||
ty::Predicate::TypeOutlives(a, b) => {
|
||||
mywrite!(w, "o");
|
||||
enc_ty(w, cx, a);
|
||||
enc_region(w, cx, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ use middle::infer;
|
|||
use middle::traits;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::expr_use_visitor as euv;
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::NodeSet;
|
||||
|
||||
use syntax::ast;
|
||||
|
@ -119,15 +120,17 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> {
|
|||
let ty = ty::node_id_to_type(self.tcx, e.id);
|
||||
let infcx = infer::new_infer_ctxt(self.tcx);
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
let obligation = traits::obligation_for_builtin_bound(self.tcx, cause, ty,
|
||||
ty::BoundSync);
|
||||
fulfill_cx.register_obligation(self.tcx, obligation.unwrap());
|
||||
let env = ty::empty_parameter_environment();
|
||||
let result = fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok();
|
||||
if !result {
|
||||
self.tcx.sess.span_err(e.span, "shared static items must have a \
|
||||
type which implements Sync");
|
||||
match traits::trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) {
|
||||
Ok(trait_ref) => {
|
||||
fulfill_cx.register_trait_ref(self.tcx, trait_ref,
|
||||
traits::ObligationCause::dummy());
|
||||
let env = ty::empty_parameter_environment();
|
||||
if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() {
|
||||
self.tcx.sess.span_err(e.span, "shared static items must have a \
|
||||
type which implements Sync");
|
||||
}
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,22 +10,26 @@
|
|||
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::infer::{mod, InferCtxt, ures};
|
||||
use middle::infer::{mod, InferCtxt};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::hash_map::{Occupied, Vacant};
|
||||
use std::default::Default;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use util::common::ErrorReported;
|
||||
use util::ppaux::Repr;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
use super::CodeAmbiguity;
|
||||
use super::CodeSelectionError;
|
||||
use super::FulfillmentError;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
use super::TraitObligation;
|
||||
use super::FulfillmentError;
|
||||
use super::CodeSelectionError;
|
||||
use super::PredicateObligation;
|
||||
use super::Selection;
|
||||
use super::select::SelectionContext;
|
||||
use super::trait_ref_for_builtin_bound;
|
||||
use super::Unimplemented;
|
||||
|
||||
/// The fulfillment context is used to drive trait resolution. It
|
||||
/// consists of a list of obligations that must be (eventually)
|
||||
|
@ -43,11 +47,11 @@ pub struct FulfillmentContext<'tcx> {
|
|||
// than the `SelectionCache`: it avoids duplicate errors and
|
||||
// permits recursive obligations, which are often generated from
|
||||
// traits like `Send` et al.
|
||||
duplicate_set: HashSet<Rc<ty::TraitRef<'tcx>>>,
|
||||
duplicate_set: HashSet<ty::Predicate<'tcx>>,
|
||||
|
||||
// A list of all obligations that have been registered with this
|
||||
// fulfillment context.
|
||||
trait_obligations: Vec<TraitObligation<'tcx>>,
|
||||
predicates: Vec<PredicateObligation<'tcx>>,
|
||||
|
||||
// Remembers the count of trait obligations that we have already
|
||||
// attempted to select. This is used to avoid repeating work
|
||||
|
@ -91,63 +95,61 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
pub fn new() -> FulfillmentContext<'tcx> {
|
||||
FulfillmentContext {
|
||||
duplicate_set: HashSet::new(),
|
||||
trait_obligations: Vec::new(),
|
||||
predicates: Vec::new(),
|
||||
attempted_mark: 0,
|
||||
region_obligations: NodeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_predicate<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
predicate: &Obligation<'tcx, ty::Predicate<'tcx>>)
|
||||
-> ures<'tcx>
|
||||
pub fn register_builtin_bound(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
match predicate.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_obligation = Obligation { cause: predicate.cause,
|
||||
recursion_depth: predicate.recursion_depth,
|
||||
trait_ref: (*trait_ref).clone() };
|
||||
Ok(self.register_obligation(infcx.tcx, trait_obligation))
|
||||
}
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
let origin = infer::EquatePredicate(predicate.cause.span);
|
||||
infer::mk_eqty(infcx, false, origin, a, b) // `a == b` ==> ``
|
||||
}
|
||||
ty::Predicate::RegionOutlives(r_a, r_b) => {
|
||||
let origin = infer::RelateRegionParamBound(predicate.cause.span);
|
||||
Ok(infer::mk_subr(infcx, origin, r_b, r_a)) // `b : a` ==> `a <= b`
|
||||
}
|
||||
ty::Predicate::TypeOutlives(t_a, r_b) => {
|
||||
Ok(self.register_region_obligation(t_a, r_b, predicate.cause))
|
||||
match trait_ref_for_builtin_bound(tcx, builtin_bound, ty) {
|
||||
Ok(trait_ref) => {
|
||||
self.register_trait_ref(tcx, trait_ref, cause);
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_obligation(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
obligation: TraitObligation<'tcx>)
|
||||
pub fn register_trait_ref<'a>(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
if self.duplicate_set.insert(obligation.trait_ref.clone()) {
|
||||
debug!("register_obligation({})", obligation.repr(tcx));
|
||||
assert!(!obligation.trait_ref.has_escaping_regions());
|
||||
self.trait_obligations.push(obligation);
|
||||
} else {
|
||||
debug!("register_obligation({}) -- already seen, skip", obligation.repr(tcx));
|
||||
}
|
||||
/*!
|
||||
* A convenience function for registering trait obligations.
|
||||
*/
|
||||
|
||||
let trait_obligation = Obligation { cause: cause,
|
||||
recursion_depth: 0,
|
||||
trait_ref: ty::Predicate::Trait(trait_ref) };
|
||||
self.register_predicate(tcx, trait_obligation)
|
||||
}
|
||||
|
||||
pub fn register_region_obligation(&mut self,
|
||||
sup_type: Ty<'tcx>,
|
||||
sub_region: ty::Region,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
t_a: Ty<'tcx>,
|
||||
r_b: ty::Region,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
let region_obligation = RegionObligation { sup_type: sup_type,
|
||||
sub_region: sub_region,
|
||||
cause: cause };
|
||||
match self.region_obligations.entry(cause.body_id) {
|
||||
Vacant(entry) => { entry.set(vec![region_obligation]); },
|
||||
Occupied(mut entry) => { entry.get_mut().push(region_obligation); },
|
||||
register_region_obligation(tcx, t_a, r_b, cause, &mut self.region_obligations);
|
||||
}
|
||||
|
||||
pub fn register_predicate<'a>(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
predicate: PredicateObligation<'tcx>)
|
||||
{
|
||||
if !self.duplicate_set.insert(predicate.trait_ref.clone()) {
|
||||
debug!("register_predicate({}) -- already seen, skip", predicate.repr(tcx));
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("register_predicate({})", predicate.repr(tcx));
|
||||
self.predicates.push(predicate);
|
||||
}
|
||||
|
||||
pub fn region_obligations(&self,
|
||||
|
@ -170,7 +172,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
|
||||
// Anything left is ambiguous.
|
||||
let errors: Vec<FulfillmentError> =
|
||||
self.trait_obligations
|
||||
self.predicates
|
||||
.iter()
|
||||
.map(|o| FulfillmentError::new((*o).clone(), CodeAmbiguity))
|
||||
.collect();
|
||||
|
@ -206,8 +208,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
self.select(&mut selcx, false)
|
||||
}
|
||||
|
||||
pub fn pending_trait_obligations(&self) -> &[TraitObligation<'tcx>] {
|
||||
self.trait_obligations[]
|
||||
pub fn pending_obligations(&self) -> &[PredicateObligation<'tcx>] {
|
||||
self.predicates[]
|
||||
}
|
||||
|
||||
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
|
||||
|
@ -218,14 +220,14 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||
{
|
||||
debug!("select({} obligations, only_new_obligations={}) start",
|
||||
self.trait_obligations.len(),
|
||||
self.predicates.len(),
|
||||
only_new_obligations);
|
||||
|
||||
let tcx = selcx.tcx();
|
||||
let mut errors = Vec::new();
|
||||
|
||||
loop {
|
||||
let count = self.trait_obligations.len();
|
||||
let count = self.predicates.len();
|
||||
|
||||
debug!("select_where_possible({} obligations) iteration",
|
||||
count);
|
||||
|
@ -243,37 +245,24 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
|
||||
// First pass: walk each obligation, retaining
|
||||
// only those that we cannot yet process.
|
||||
self.trait_obligations.retain(|obligation| {
|
||||
// Hack: Retain does not pass in the index, but we want
|
||||
// to avoid processing the first `start_count` entries.
|
||||
if skip > 0 {
|
||||
skip -= 1;
|
||||
true
|
||||
} else {
|
||||
match selcx.select(obligation) {
|
||||
Ok(None) => {
|
||||
true
|
||||
}
|
||||
Ok(Some(s)) => {
|
||||
selections.push(s);
|
||||
false
|
||||
}
|
||||
Err(selection_err) => {
|
||||
debug!("obligation: {} error: {}",
|
||||
obligation.repr(tcx),
|
||||
selection_err.repr(tcx));
|
||||
errors.push(FulfillmentError::new(
|
||||
(*obligation).clone(),
|
||||
CodeSelectionError(selection_err)));
|
||||
false
|
||||
}
|
||||
{
|
||||
let region_obligations = &mut self.region_obligations;
|
||||
self.predicates.retain(|predicate| {
|
||||
// Hack: Retain does not pass in the index, but we want
|
||||
// to avoid processing the first `start_count` entries.
|
||||
if skip == 0 {
|
||||
retain_predicate(selcx, predicate,
|
||||
&mut selections, &mut errors, region_obligations)
|
||||
} else {
|
||||
skip -= 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
self.attempted_mark = self.trait_obligations.len();
|
||||
self.attempted_mark = self.predicates.len();
|
||||
|
||||
if self.trait_obligations.len() == count {
|
||||
if self.predicates.len() == count {
|
||||
// Nothing changed.
|
||||
break;
|
||||
}
|
||||
|
@ -281,13 +270,12 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
// Now go through all the successful ones,
|
||||
// registering any nested obligations for the future.
|
||||
for selection in selections.into_iter() {
|
||||
selection.map_move_nested(
|
||||
|o| self.register_obligation(tcx, o));
|
||||
selection.map_move_nested(|p| self.register_predicate(tcx, p));
|
||||
}
|
||||
}
|
||||
|
||||
debug!("select({} obligations, {} errors) done",
|
||||
self.trait_obligations.len(),
|
||||
self.predicates.len(),
|
||||
errors.len());
|
||||
|
||||
if errors.len() == 0 {
|
||||
|
@ -298,6 +286,76 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn retain_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
||||
predicate: &PredicateObligation<'tcx>,
|
||||
selections: &mut Vec<Selection<'tcx>>,
|
||||
errors: &mut Vec<FulfillmentError<'tcx>>,
|
||||
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
|
||||
-> bool
|
||||
{
|
||||
/*!
|
||||
* Evaluates a predicate obligation and modifies the appropriate
|
||||
* output array. Returns `true` if the predicate must be retained
|
||||
* because it could not be fully evaluated yet due to insufficient
|
||||
* type inference.
|
||||
*/
|
||||
|
||||
let tcx = selcx.tcx();
|
||||
match predicate.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_obligation = Obligation { cause: predicate.cause,
|
||||
recursion_depth: predicate.recursion_depth,
|
||||
trait_ref: trait_ref.clone() };
|
||||
match selcx.select(&trait_obligation) {
|
||||
Ok(None) => {
|
||||
true
|
||||
}
|
||||
Ok(Some(s)) => {
|
||||
selections.push(s);
|
||||
false
|
||||
}
|
||||
Err(selection_err) => {
|
||||
debug!("predicate: {} error: {}",
|
||||
predicate.repr(tcx),
|
||||
selection_err.repr(tcx));
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
predicate.clone(),
|
||||
CodeSelectionError(selection_err)));
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
let origin = infer::EquatePredicate(predicate.cause.span);
|
||||
match infer::mk_eqty(selcx.infcx(), false, origin, a, b) {
|
||||
Ok(()) => {
|
||||
false
|
||||
}
|
||||
Err(_) => {
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
predicate.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(r_a, r_b) => {
|
||||
let origin = infer::RelateRegionParamBound(predicate.cause.span);
|
||||
let () = infer::mk_subr(selcx.infcx(), origin, r_b, r_a); // `b : a` ==> `a <= b`
|
||||
false
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(t_a, r_b) => {
|
||||
register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
format!("RegionObligation(sub_region={}, sup_type={})",
|
||||
|
@ -305,3 +363,23 @@ impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> {
|
|||
self.sup_type.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
t_a: Ty<'tcx>,
|
||||
r_b: ty::Region,
|
||||
cause: ObligationCause<'tcx>,
|
||||
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
|
||||
{
|
||||
let region_obligation = RegionObligation { sup_type: t_a,
|
||||
sub_region: r_b,
|
||||
cause: cause };
|
||||
|
||||
debug!("register_region_obligation({})",
|
||||
region_obligation.repr(tcx));
|
||||
|
||||
match region_obligations.entry(region_obligation.cause.body_id) {
|
||||
Vacant(entry) => { entry.set(vec![region_obligation]); },
|
||||
Occupied(mut entry) => { entry.get_mut().push(region_obligation); },
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ pub use self::FulfillmentErrorCode::*;
|
|||
pub use self::Vtable::*;
|
||||
pub use self::ObligationCauseCode::*;
|
||||
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::infer::InferCtxt;
|
||||
|
@ -23,13 +22,13 @@ use std::rc::Rc;
|
|||
use std::slice::Items;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util::common::ErrorReported;
|
||||
|
||||
pub use self::fulfill::{FulfillmentContext, RegionObligation};
|
||||
pub use self::select::SelectionContext;
|
||||
pub use self::select::SelectionCache;
|
||||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
|
||||
pub use self::util::elaborate_predicates;
|
||||
pub use self::util::supertraits;
|
||||
pub use self::util::Supertraits;
|
||||
pub use self::util::search_trait_and_supertraits_from_bound;
|
||||
|
@ -54,6 +53,7 @@ pub struct Obligation<'tcx, T> {
|
|||
pub trait_ref: T,
|
||||
}
|
||||
|
||||
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
||||
pub type TraitObligation<'tcx> = Obligation<'tcx, Rc<ty::TraitRef<'tcx>>>;
|
||||
|
||||
/// Why did we incur this obligation? Used for error reporting.
|
||||
|
@ -91,7 +91,7 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
|
||||
// Captures of variable the given id by a closure (span is the
|
||||
// span of the closure)
|
||||
ClosureCapture(ast::NodeId, Span),
|
||||
ClosureCapture(ast::NodeId, Span, ty::BuiltinBound),
|
||||
|
||||
// Types of fields (other than the last) in a struct must be sized.
|
||||
FieldSized,
|
||||
|
@ -101,20 +101,20 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
}
|
||||
|
||||
pub type Obligations<'tcx, O> = subst::VecPerParamSpace<Obligation<'tcx, O>>;
|
||||
|
||||
pub type PredicateObligations<'tcx> = subst::VecPerParamSpace<PredicateObligation<'tcx>>;
|
||||
pub type TraitObligations<'tcx> = subst::VecPerParamSpace<TraitObligation<'tcx>>;
|
||||
|
||||
pub type Selection<'tcx> = Vtable<'tcx, TraitObligation<'tcx>>;
|
||||
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
|
||||
|
||||
#[deriving(Clone,Show)]
|
||||
pub enum SelectionError<'tcx> {
|
||||
Unimplemented,
|
||||
Overflow,
|
||||
OutputTypeParameterMismatch(Rc<ty::TraitRef<'tcx>>, ty::type_err<'tcx>)
|
||||
OutputTypeParameterMismatch(Rc<ty::TraitRef<'tcx>>, Rc<ty::TraitRef<'tcx>>, ty::type_err<'tcx>),
|
||||
}
|
||||
|
||||
pub struct FulfillmentError<'tcx> {
|
||||
pub obligation: TraitObligation<'tcx>,
|
||||
pub obligation: PredicateObligation<'tcx>,
|
||||
pub code: FulfillmentErrorCode<'tcx>
|
||||
}
|
||||
|
||||
|
@ -224,33 +224,6 @@ pub struct VtableParamData<'tcx> {
|
|||
pub bound: Rc<ty::TraitRef<'tcx>>,
|
||||
}
|
||||
|
||||
/// Matches the self type of the inherent impl `impl_def_id`
|
||||
/// against `self_ty` and returns the resulting resolution. This
|
||||
/// routine may modify the surrounding type context (for example,
|
||||
/// it may unify variables).
|
||||
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &Typer<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
impl_def_id: ast::DefId,
|
||||
self_ty: Ty<'tcx>)
|
||||
-> SelectionResult<'tcx,
|
||||
VtableImplData<'tcx, TraitObligation<'tcx>>>
|
||||
{
|
||||
// This routine is only suitable for inherent impls. This is
|
||||
// because it does not attempt to unify the output type parameters
|
||||
// from the trait ref against the values from the obligation.
|
||||
// (These things do not apply to inherent impls, for which there
|
||||
// is no trait ref nor obligation.)
|
||||
//
|
||||
// Matching against non-inherent impls should be done with
|
||||
// `try_resolve_obligation()`.
|
||||
assert!(ty::impl_trait_ref(infcx.tcx, impl_def_id).is_none());
|
||||
|
||||
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
|
||||
selcx.select_inherent_impl(impl_def_id, cause, self_ty)
|
||||
}
|
||||
|
||||
/// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl
|
||||
/// of a trait, not an inherent impl.
|
||||
pub fn is_orphan_impl(tcx: &ty::ctxt,
|
||||
|
@ -270,32 +243,13 @@ pub fn overlapping_impls(infcx: &InferCtxt,
|
|||
coherence::impl_can_satisfy(infcx, impl2_def_id, impl1_def_id)
|
||||
}
|
||||
|
||||
/// Given generic bounds from an impl like:
|
||||
///
|
||||
/// impl<A:Foo, B:Bar+Qux> ...
|
||||
///
|
||||
/// along with the bindings for the types `A` and `B` (e.g., `<A=A0, B=B0>`), yields a result like
|
||||
///
|
||||
/// [[Foo for A0, Bar for B0, Qux for B0], [], []]
|
||||
///
|
||||
/// Expects that `generic_bounds` have already been fully substituted, late-bound regions liberated
|
||||
/// and so forth, so that they are in the same namespace as `type_substs`.
|
||||
pub fn obligations_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
generic_bounds: &ty::GenericBounds<'tcx>,
|
||||
type_substs: &subst::VecPerParamSpace<Ty<'tcx>>)
|
||||
-> subst::VecPerParamSpace<TraitObligation<'tcx>>
|
||||
/// Creates predicate obligations from the generic bounds.
|
||||
pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
generic_bounds: &ty::GenericBounds<'tcx>)
|
||||
-> PredicateObligations<'tcx>
|
||||
{
|
||||
util::obligations_for_generics(tcx, cause, 0, generic_bounds, type_substs)
|
||||
}
|
||||
|
||||
pub fn obligation_for_builtin_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
source_ty: Ty<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound)
|
||||
-> Result<TraitObligation<'tcx>, ErrorReported>
|
||||
{
|
||||
util::obligation_for_builtin_bound(tcx, cause, builtin_bound, 0, source_ty)
|
||||
util::predicates_for_generics(tcx, cause, 0, generic_bounds)
|
||||
}
|
||||
|
||||
impl<'tcx,O> Obligation<'tcx,O> {
|
||||
|
@ -311,6 +265,12 @@ impl<'tcx,O> Obligation<'tcx,O> {
|
|||
pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> {
|
||||
Obligation::new(ObligationCause::misc(span, body_id), trait_ref)
|
||||
}
|
||||
|
||||
pub fn with<P>(&self, value: P) -> Obligation<'tcx,P> {
|
||||
Obligation { cause: self.cause.clone(),
|
||||
recursion_depth: self.recursion_depth,
|
||||
trait_ref: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Obligation<'tcx,Rc<ty::TraitRef<'tcx>>> {
|
||||
|
@ -417,7 +377,7 @@ impl<N> VtableBuiltinData<N> {
|
|||
}
|
||||
|
||||
impl<'tcx> FulfillmentError<'tcx> {
|
||||
fn new(obligation: TraitObligation<'tcx>,
|
||||
fn new(obligation: PredicateObligation<'tcx>,
|
||||
code: FulfillmentErrorCode<'tcx>)
|
||||
-> FulfillmentError<'tcx>
|
||||
{
|
||||
|
|
|
@ -17,9 +17,8 @@ use self::Candidate::*;
|
|||
use self::BuiltinBoundConditions::*;
|
||||
use self::EvaluationResult::*;
|
||||
|
||||
use super::{TraitObligation, ObligationCause};
|
||||
use super::{SelectionError, Unimplemented, Overflow,
|
||||
OutputTypeParameterMismatch};
|
||||
use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
|
||||
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
|
||||
use super::{Selection};
|
||||
use super::{SelectionResult};
|
||||
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer};
|
||||
|
@ -191,6 +190,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> {
|
||||
self.infcx
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
@ -225,29 +228,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn select_inherent_impl(&mut self,
|
||||
impl_def_id: ast::DefId,
|
||||
obligation_cause: ObligationCause<'tcx>,
|
||||
obligation_self_ty: Ty<'tcx>)
|
||||
-> SelectionResult<'tcx, VtableImplData<'tcx, TraitObligation<'tcx>>>
|
||||
{
|
||||
debug!("select_inherent_impl(impl_def_id={}, obligation_self_ty={})",
|
||||
impl_def_id.repr(self.tcx()),
|
||||
obligation_self_ty.repr(self.tcx()));
|
||||
|
||||
match self.match_inherent_impl(impl_def_id,
|
||||
obligation_cause,
|
||||
obligation_self_ty) {
|
||||
Ok(substs) => {
|
||||
let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation_cause, 0);
|
||||
Ok(Some(vtable_impl))
|
||||
}
|
||||
Err(()) => {
|
||||
Err(Unimplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EVALUATION
|
||||
//
|
||||
|
@ -260,15 +240,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
/// Evaluates whether the obligation `obligation` can be satisfied (by any means).
|
||||
pub fn evaluate_obligation(&mut self,
|
||||
obligation: &TraitObligation<'tcx>)
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
debug!("evaluate_obligation({})",
|
||||
obligation.repr(self.tcx()));
|
||||
assert!(!obligation.trait_ref.has_escaping_regions());
|
||||
|
||||
let stack = self.push_stack(None, obligation);
|
||||
self.evaluate_stack(&stack).may_apply()
|
||||
self.evaluate_predicate_recursively(None, obligation).may_apply()
|
||||
}
|
||||
|
||||
fn evaluate_builtin_bound_recursively<'o>(&mut self,
|
||||
|
@ -278,7 +256,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
-> EvaluationResult<'tcx>
|
||||
{
|
||||
let obligation =
|
||||
util::obligation_for_builtin_bound(
|
||||
util::predicate_for_builtin_bound(
|
||||
self.tcx(),
|
||||
previous_stack.obligation.cause,
|
||||
bound,
|
||||
|
@ -287,7 +265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
match obligation {
|
||||
Ok(obligation) => {
|
||||
self.evaluate_obligation_recursively(Some(previous_stack), &obligation)
|
||||
self.evaluate_predicate_recursively(Some(previous_stack), &obligation)
|
||||
}
|
||||
Err(ErrorReported) => {
|
||||
EvaluatedToOk
|
||||
|
@ -295,6 +273,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn evaluate_predicate_recursively<'o>(&mut self,
|
||||
previous_stack: Option<&TraitObligationStack<'o, 'tcx>>,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
-> EvaluationResult<'tcx>
|
||||
{
|
||||
debug!("evaluate_predicate_recursively({})",
|
||||
obligation.repr(self.tcx()));
|
||||
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref t) => {
|
||||
assert!(!t.has_escaping_regions());
|
||||
let obligation = obligation.with(t.clone());
|
||||
self.evaluate_obligation_recursively(previous_stack, &obligation)
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
match infer::can_mk_eqty(self.infcx, a, b) {
|
||||
Ok(()) => EvaluatedToOk,
|
||||
Err(_) => EvaluatedToErr(Unimplemented),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
|
||||
// we do not consider region relationships when
|
||||
// evaluating trait matches
|
||||
EvaluatedToOk
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_obligation_recursively<'o>(&mut self,
|
||||
previous_stack: Option<&TraitObligationStack<'o, 'tcx>>,
|
||||
obligation: &TraitObligation<'tcx>)
|
||||
|
@ -347,7 +355,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
stack.iter().skip(1).any(
|
||||
|prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id))
|
||||
{
|
||||
debug!("evaluate_stack_intracrate({}) --> unbound argument, recursion --> ambiguous",
|
||||
debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous",
|
||||
stack.skol_trait_ref.repr(self.tcx()));
|
||||
return EvaluatedToAmbig;
|
||||
}
|
||||
|
@ -376,7 +384,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
.skip(1) // skip top-most frame
|
||||
.any(|prev| stack.skol_trait_ref == prev.skol_trait_ref)
|
||||
{
|
||||
debug!("evaluate_stack_intracrate({}) --> recursive",
|
||||
debug!("evaluate_stack({}) --> recursive",
|
||||
stack.skol_trait_ref.repr(self.tcx()));
|
||||
return EvaluatedToOk;
|
||||
}
|
||||
|
@ -595,8 +603,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// common case, then we can use the global environment.
|
||||
// See the discussion in doc.rs for more details.
|
||||
if
|
||||
!self.param_env.caller_obligations.is_empty()
|
||||
&&
|
||||
!self.param_env.caller_bounds.is_empty() &&
|
||||
cache_skol_trait_ref.input_types().iter().any(
|
||||
|&t| ty::type_has_ty_infer(t))
|
||||
{
|
||||
|
@ -690,8 +697,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation.repr(self.tcx()));
|
||||
|
||||
let caller_trait_refs: Vec<Rc<ty::TraitRef>> =
|
||||
self.param_env.caller_obligations.iter()
|
||||
.map(|o| o.trait_ref.clone())
|
||||
self.param_env.caller_bounds.predicates.iter()
|
||||
.filter_map(|o| o.to_trait())
|
||||
.collect();
|
||||
|
||||
let all_bounds =
|
||||
|
@ -852,7 +859,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
{
|
||||
let mut result = EvaluatedToOk;
|
||||
for obligation in selection.iter_nested() {
|
||||
match self.evaluate_obligation_recursively(stack, obligation) {
|
||||
match self.evaluate_predicate_recursively(stack, obligation) {
|
||||
EvaluatedToErr(e) => { return EvaluatedToErr(e); }
|
||||
EvaluatedToAmbig => { result = EvaluatedToAmbig; }
|
||||
EvaluatedToOk => { }
|
||||
|
@ -932,8 +939,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
candidates: &mut CandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
match self.builtin_bound(bound, stack.obligation.self_ty()) {
|
||||
Ok(If(_)) => {
|
||||
match self.builtin_bound(bound, stack.obligation) {
|
||||
Ok(If(..)) => {
|
||||
debug!("builtin_bound: bound={}",
|
||||
bound.repr(self.tcx()));
|
||||
candidates.vec.push(BuiltinCandidate(bound));
|
||||
|
@ -947,10 +954,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
fn builtin_bound(&mut self,
|
||||
bound: ty::BuiltinBound,
|
||||
self_ty: Ty<'tcx>)
|
||||
obligation: &TraitObligation<'tcx>)
|
||||
-> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
|
||||
{
|
||||
let self_ty = self.infcx.shallow_resolve(self_ty);
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.trait_ref.self_ty());
|
||||
return match self_ty.sty {
|
||||
ty::ty_infer(ty::IntVar(_)) |
|
||||
ty::ty_infer(ty::FloatVar(_)) |
|
||||
|
@ -1023,8 +1030,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match bound {
|
||||
ty::BoundCopy => {
|
||||
match mutbl {
|
||||
ast::MutMutable => Err(Unimplemented), // &mut T is affine
|
||||
ast::MutImmutable => Ok(If(Vec::new())), // &T is copyable
|
||||
ast::MutMutable => {
|
||||
// &mut T is affine
|
||||
Err(Unimplemented)
|
||||
}
|
||||
ast::MutImmutable => {
|
||||
// &T is copyable, no matter what T is
|
||||
Ok(If(Vec::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1083,10 +1096,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ty::BoundCopy => {
|
||||
match mutbl {
|
||||
// &mut T is affine and hence never `Copy`
|
||||
ast::MutMutable => Err(Unimplemented),
|
||||
ast::MutMutable => {
|
||||
Err(Unimplemented)
|
||||
}
|
||||
|
||||
// &T is always copyable
|
||||
ast::MutImmutable => Ok(If(Vec::new())),
|
||||
ast::MutImmutable => {
|
||||
Ok(If(Vec::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1122,8 +1139,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match bound {
|
||||
ty::BoundCopy => {
|
||||
match *len {
|
||||
Some(_) => Ok(If(vec![element_ty])), // [T, ..n] is copy iff T is copy
|
||||
None => Err(Unimplemented), // [T] is unsized and hence affine
|
||||
Some(_) => {
|
||||
// [T, ..n] is copy iff T is copy
|
||||
Ok(If(vec![element_ty]))
|
||||
}
|
||||
None => {
|
||||
// [T] is unsized and hence affine
|
||||
Err(Unimplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1256,7 +1279,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Some(def_id) == tcx.lang_items.no_send_bound() ||
|
||||
Some(def_id) == tcx.lang_items.managed_bound()
|
||||
{
|
||||
return Err(Unimplemented);
|
||||
return Err(Unimplemented)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1274,7 +1297,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Some(def_id) == tcx.lang_items.no_sync_bound() ||
|
||||
Some(def_id) == tcx.lang_items.managed_bound()
|
||||
{
|
||||
return Err(Unimplemented);
|
||||
return Err(Unimplemented)
|
||||
} else if
|
||||
Some(def_id) == tcx.lang_items.unsafe_type()
|
||||
{
|
||||
|
@ -1361,13 +1384,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
fn confirm_builtin_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
bound: ty::BuiltinBound)
|
||||
-> Result<VtableBuiltinData<TraitObligation<'tcx>>,
|
||||
-> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
|
||||
SelectionError<'tcx>>
|
||||
{
|
||||
debug!("confirm_builtin_candidate({})",
|
||||
obligation.repr(self.tcx()));
|
||||
|
||||
match try!(self.builtin_bound(bound, obligation.self_ty())) {
|
||||
match try!(self.builtin_bound(bound, obligation)) {
|
||||
If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)),
|
||||
AmbiguousBuiltin | ParameterBuiltin => {
|
||||
self.tcx().sess.span_bug(
|
||||
|
@ -1382,29 +1405,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation: &TraitObligation<'tcx>,
|
||||
bound: ty::BuiltinBound,
|
||||
nested: Vec<Ty<'tcx>>)
|
||||
-> VtableBuiltinData<TraitObligation<'tcx>>
|
||||
-> VtableBuiltinData<PredicateObligation<'tcx>>
|
||||
{
|
||||
let obligations = nested.iter().map(|&t| {
|
||||
util::obligation_for_builtin_bound(
|
||||
util::predicate_for_builtin_bound(
|
||||
self.tcx(),
|
||||
obligation.cause,
|
||||
bound,
|
||||
obligation.recursion_depth + 1,
|
||||
t)
|
||||
}).collect::<Result<_, _>>();
|
||||
let obligations = match obligations {
|
||||
let mut obligations = match obligations {
|
||||
Ok(o) => o,
|
||||
Err(ErrorReported) => Vec::new()
|
||||
};
|
||||
|
||||
// as a special case, `Send` requires `'static`
|
||||
if bound == ty::BoundSend {
|
||||
obligations.push(Obligation {
|
||||
cause: obligation.cause,
|
||||
recursion_depth: obligation.recursion_depth+1,
|
||||
trait_ref: ty::Predicate::TypeOutlives(obligation.self_ty(),
|
||||
ty::ReStatic)
|
||||
});
|
||||
}
|
||||
|
||||
let obligations = VecPerParamSpace::new(obligations, Vec::new(),
|
||||
Vec::new(), Vec::new());
|
||||
|
||||
debug!("vtable_builtin_data: obligations={}",
|
||||
obligations.repr(self.tcx()));
|
||||
|
||||
VtableBuiltinData { nested: obligations }
|
||||
}
|
||||
|
||||
fn confirm_impl_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
impl_def_id: ast::DefId)
|
||||
-> Result<VtableImplData<'tcx, TraitObligation<'tcx>>,
|
||||
-> Result<VtableImplData<'tcx, PredicateObligation<'tcx>>,
|
||||
SelectionError<'tcx>>
|
||||
{
|
||||
debug!("confirm_impl_candidate({},{})",
|
||||
|
@ -1414,6 +1452,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// First, create the substitutions by matching the impl again,
|
||||
// this time not in a probe.
|
||||
let substs = self.rematch_impl(impl_def_id, obligation);
|
||||
debug!("confirm_impl_candidate substs={}", substs);
|
||||
Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, obligation.recursion_depth + 1))
|
||||
}
|
||||
|
||||
|
@ -1422,16 +1461,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
substs: Substs<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint)
|
||||
-> VtableImplData<'tcx, TraitObligation<'tcx>>
|
||||
-> VtableImplData<'tcx, PredicateObligation<'tcx>>
|
||||
{
|
||||
let impl_obligations =
|
||||
self.impl_obligations(cause,
|
||||
recursion_depth,
|
||||
impl_def_id,
|
||||
&substs);
|
||||
let impl_predicates =
|
||||
self.impl_predicates(cause,
|
||||
recursion_depth,
|
||||
impl_def_id,
|
||||
&substs);
|
||||
VtableImplData { impl_def_id: impl_def_id,
|
||||
substs: substs,
|
||||
nested: impl_obligations }
|
||||
nested: impl_predicates }
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate(&mut self,
|
||||
|
@ -1752,9 +1791,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match self.infcx.sub_trait_refs(false,
|
||||
origin,
|
||||
expected_trait_ref.clone(),
|
||||
obligation_trait_ref) {
|
||||
obligation_trait_ref.clone()) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, e))
|
||||
Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1785,17 +1824,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn impl_obligations(&self,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint,
|
||||
impl_def_id: ast::DefId,
|
||||
impl_substs: &Substs<'tcx>)
|
||||
-> VecPerParamSpace<TraitObligation<'tcx>>
|
||||
fn impl_predicates(&self,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint,
|
||||
impl_def_id: ast::DefId,
|
||||
impl_substs: &Substs<'tcx>)
|
||||
-> VecPerParamSpace<PredicateObligation<'tcx>>
|
||||
{
|
||||
let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
|
||||
let bounds = impl_generics.to_bounds(self.tcx(), impl_substs);
|
||||
util::obligations_for_generics(self.tcx(), cause, recursion_depth,
|
||||
&bounds, &impl_substs.types)
|
||||
util::predicates_for_generics(self.tcx(), cause, recursion_depth, &bounds)
|
||||
}
|
||||
|
||||
fn fn_family_trait_kind(&self,
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::subst;
|
||||
use middle::subst::{ParamSpace, Substs, VecPerParamSpace, Subst};
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::ty::{mod, Ty};
|
||||
use std::collections::HashSet;
|
||||
|
@ -21,115 +20,130 @@ use syntax::codemap::Span;
|
|||
use util::common::ErrorReported;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use super::{Obligation, ObligationCause, TraitObligation, VtableImpl,
|
||||
VtableParam, VtableParamData, VtableImplData};
|
||||
use super::{Obligation, ObligationCause, PredicateObligation,
|
||||
VtableImpl, VtableParam, VtableParamData, VtableImplData};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Supertrait iterator
|
||||
// Elaboration iterator
|
||||
|
||||
pub struct Supertraits<'cx, 'tcx:'cx> {
|
||||
pub struct Elaborator<'cx, 'tcx:'cx> {
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
stack: Vec<SupertraitEntry<'tcx>>,
|
||||
visited: HashSet<Rc<ty::TraitRef<'tcx>>>,
|
||||
stack: Vec<StackEntry<'tcx>>,
|
||||
visited: HashSet<ty::Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
struct SupertraitEntry<'tcx> {
|
||||
struct StackEntry<'tcx> {
|
||||
position: uint,
|
||||
supertraits: Vec<Rc<ty::TraitRef<'tcx>>>,
|
||||
predicates: Vec<ty::Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>)
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
pub fn elaborate_trait_ref<'cx, 'tcx>(
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>)
|
||||
-> Elaborator<'cx, 'tcx>
|
||||
{
|
||||
//! Returns an iterator over the trait reference `T` and all of its supertrait references. May
|
||||
//! contain duplicates. In general the ordering is not defined.
|
||||
//!
|
||||
//! Example:
|
||||
//!
|
||||
//! ```
|
||||
//! trait Foo { ... }
|
||||
//! trait Bar : Foo { ... }
|
||||
//! trait Baz : Bar+Foo { ... }
|
||||
//! ```
|
||||
//!
|
||||
//! `supertraits(Baz)` yields `[Baz, Bar, Foo, Foo]` in some order.
|
||||
|
||||
transitive_bounds(tcx, &[trait_ref])
|
||||
elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)])
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
bounds: &[Rc<ty::TraitRef<'tcx>>])
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
pub fn elaborate_trait_refs<'cx, 'tcx>(
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_refs: &[Rc<ty::TraitRef<'tcx>>])
|
||||
-> Elaborator<'cx, 'tcx>
|
||||
{
|
||||
let bounds = Vec::from_fn(bounds.len(), |i| bounds[i].clone());
|
||||
|
||||
let visited: HashSet<Rc<ty::TraitRef>> =
|
||||
bounds.iter()
|
||||
.map(|b| (*b).clone())
|
||||
.collect();
|
||||
|
||||
let entry = SupertraitEntry { position: 0, supertraits: bounds };
|
||||
Supertraits { tcx: tcx, stack: vec![entry], visited: visited }
|
||||
let predicates = trait_refs.iter()
|
||||
.map(|trait_ref| ty::Predicate::Trait((*trait_ref).clone()))
|
||||
.collect();
|
||||
elaborate_predicates(tcx, predicates)
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Supertraits<'cx, 'tcx> {
|
||||
fn push(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
|
||||
let ty::ParamBounds { builtin_bounds, mut trait_bounds, .. } =
|
||||
ty::bounds_for_trait_ref(self.tcx, trait_ref);
|
||||
for builtin_bound in builtin_bounds.iter() {
|
||||
let bound_trait_ref = trait_ref_for_builtin_bound(self.tcx,
|
||||
builtin_bound,
|
||||
trait_ref.self_ty());
|
||||
match bound_trait_ref {
|
||||
Ok(trait_ref) => { trait_bounds.push(trait_ref); }
|
||||
Err(ErrorReported) => { }
|
||||
pub fn elaborate_predicates<'cx, 'tcx>(
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
predicates: Vec<ty::Predicate<'tcx>>)
|
||||
-> Elaborator<'cx, 'tcx>
|
||||
{
|
||||
let visited: HashSet<ty::Predicate<'tcx>> =
|
||||
predicates.iter()
|
||||
.map(|b| (*b).clone())
|
||||
.collect();
|
||||
|
||||
let entry = StackEntry { position: 0, predicates: predicates };
|
||||
Elaborator { tcx: tcx, stack: vec![entry], visited: visited }
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
|
||||
fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let mut predicates =
|
||||
ty::predicates_for_trait_ref(self.tcx, &**trait_ref);
|
||||
|
||||
// Only keep those bounds that we haven't already
|
||||
// seen. This is necessary to prevent infinite
|
||||
// recursion in some cases. One common case is when
|
||||
// people define `trait Sized { }` rather than `trait
|
||||
// Sized for Sized? { }`.
|
||||
predicates.retain(|r| self.visited.insert((*r).clone()));
|
||||
|
||||
self.stack.push(StackEntry { position: 0,
|
||||
predicates: predicates });
|
||||
}
|
||||
ty::Predicate::Equate(..) => {
|
||||
}
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
// Currently, we do not "elaborate" predicates like
|
||||
// `'a : 'b` or `T : 'a`. We could conceivably do
|
||||
// more here. For example,
|
||||
//
|
||||
// &'a int : 'b
|
||||
//
|
||||
// implies that
|
||||
//
|
||||
// 'a : 'b
|
||||
//
|
||||
// and we could get even more if we took WF
|
||||
// constraints into account. For example,
|
||||
//
|
||||
// &'a &'b int : 'c
|
||||
//
|
||||
// implies that
|
||||
//
|
||||
// 'b : 'a
|
||||
// 'a : 'c
|
||||
}
|
||||
}
|
||||
|
||||
// Only keep those bounds that we haven't already seen. This
|
||||
// is necessary to prevent infinite recursion in some cases.
|
||||
// One common case is when people define `trait Sized { }`
|
||||
// rather than `trait Sized for Sized? { }`.
|
||||
trait_bounds.retain(|r| self.visited.insert((*r).clone()));
|
||||
|
||||
let entry = SupertraitEntry { position: 0, supertraits: trait_bounds };
|
||||
self.stack.push(entry);
|
||||
}
|
||||
|
||||
/// Returns the path taken through the trait supertraits to reach the current point.
|
||||
pub fn indices(&self) -> Vec<uint> {
|
||||
self.stack.iter().map(|e| e.position).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Iterator<Rc<ty::TraitRef<'tcx>>> for Supertraits<'cx, 'tcx> {
|
||||
fn next(&mut self) -> Option<Rc<ty::TraitRef<'tcx>>> {
|
||||
impl<'cx, 'tcx> Iterator<ty::Predicate<'tcx>> for Elaborator<'cx, 'tcx> {
|
||||
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
|
||||
loop {
|
||||
// Extract next item from top-most stack frame, if any.
|
||||
let next_trait = match self.stack.last_mut() {
|
||||
let next_predicate = match self.stack.last_mut() {
|
||||
None => {
|
||||
// No more stack frames. Done.
|
||||
return None;
|
||||
}
|
||||
Some(entry) => {
|
||||
let p = entry.position;
|
||||
if p < entry.supertraits.len() {
|
||||
// Still more supertraits left in the top stack frame.
|
||||
if p < entry.predicates.len() {
|
||||
// Still more predicates left in the top stack frame.
|
||||
entry.position += 1;
|
||||
|
||||
let next_trait = entry.supertraits[p].clone();
|
||||
Some(next_trait)
|
||||
let next_predicate =
|
||||
entry.predicates[p].clone();
|
||||
|
||||
Some(next_predicate)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match next_trait {
|
||||
Some(next_trait) => {
|
||||
self.push(&*next_trait);
|
||||
return Some(next_trait);
|
||||
match next_predicate {
|
||||
Some(next_predicate) => {
|
||||
self.push(&next_predicate);
|
||||
return Some(next_predicate);
|
||||
}
|
||||
|
||||
None => {
|
||||
|
@ -141,6 +155,50 @@ impl<'cx, 'tcx> Iterator<Rc<ty::TraitRef<'tcx>>> for Supertraits<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Supertrait iterator
|
||||
|
||||
pub struct Supertraits<'cx, 'tcx:'cx> {
|
||||
elaborator: Elaborator<'cx, 'tcx>,
|
||||
}
|
||||
|
||||
pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>)
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
{
|
||||
let elaborator = elaborate_trait_ref(tcx, trait_ref);
|
||||
Supertraits { elaborator: elaborator }
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
bounds: &[Rc<ty::TraitRef<'tcx>>])
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
{
|
||||
let elaborator = elaborate_trait_refs(tcx, bounds);
|
||||
Supertraits { elaborator: elaborator }
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Iterator<Rc<ty::TraitRef<'tcx>>> for Supertraits<'cx, 'tcx> {
|
||||
fn next(&mut self) -> Option<Rc<ty::TraitRef<'tcx>>> {
|
||||
loop {
|
||||
match self.elaborator.next() {
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
Some(ty::Predicate::Trait(trait_ref)) => {
|
||||
return Some(trait_ref);
|
||||
}
|
||||
Some(ty::Predicate::Equate(..)) |
|
||||
Some(ty::Predicate::RegionOutlives(..)) |
|
||||
Some(ty::Predicate::TypeOutlives(..)) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// determine the `self` type, using fresh variables for all variables
|
||||
// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
|
||||
// would return ($0, $1) where $0 and $1 are freshly instantiated type
|
||||
|
@ -179,64 +237,20 @@ impl<'tcx> fmt::Show for VtableParamData<'tcx> {
|
|||
}
|
||||
|
||||
/// See `super::obligations_for_generics`
|
||||
pub fn obligations_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint,
|
||||
generic_bounds: &ty::GenericBounds<'tcx>,
|
||||
type_substs: &VecPerParamSpace<Ty<'tcx>>)
|
||||
-> VecPerParamSpace<TraitObligation<'tcx>>
|
||||
pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint,
|
||||
generic_bounds: &ty::GenericBounds<'tcx>)
|
||||
-> VecPerParamSpace<PredicateObligation<'tcx>>
|
||||
{
|
||||
debug!("predicates_for_generics(generic_bounds={})",
|
||||
generic_bounds.repr(tcx));
|
||||
|
||||
debug!("obligations_for_generics(generic_bounds={}, type_substs={})",
|
||||
generic_bounds.repr(tcx), type_substs.repr(tcx));
|
||||
|
||||
let mut obligations = VecPerParamSpace::empty();
|
||||
|
||||
for (space, index, bounds) in generic_bounds.types.iter_enumerated() {
|
||||
push_obligations_for_param_bounds(tcx,
|
||||
cause,
|
||||
recursion_depth,
|
||||
space,
|
||||
index,
|
||||
bounds,
|
||||
type_substs,
|
||||
&mut obligations);
|
||||
}
|
||||
|
||||
debug!("obligations() ==> {}", obligations.repr(tcx));
|
||||
|
||||
return obligations;
|
||||
}
|
||||
|
||||
fn push_obligations_for_param_bounds<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: uint,
|
||||
space: subst::ParamSpace,
|
||||
index: uint,
|
||||
param_bounds: &ty::ParamBounds<'tcx>,
|
||||
param_type_substs: &VecPerParamSpace<Ty<'tcx>>,
|
||||
obligations: &mut VecPerParamSpace<TraitObligation<'tcx>>)
|
||||
{
|
||||
let param_ty = *param_type_substs.get(space, index);
|
||||
for builtin_bound in param_bounds.builtin_bounds.iter() {
|
||||
let obligation = obligation_for_builtin_bound(tcx,
|
||||
cause,
|
||||
builtin_bound,
|
||||
recursion_depth,
|
||||
param_ty);
|
||||
if let Ok(ob) = obligation {
|
||||
obligations.push(space, ob);
|
||||
}
|
||||
}
|
||||
|
||||
for bound_trait_ref in param_bounds.trait_bounds.iter() {
|
||||
obligations.push(
|
||||
space,
|
||||
Obligation { cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
trait_ref: (*bound_trait_ref).clone() });
|
||||
}
|
||||
generic_bounds.predicates.map(|predicate| {
|
||||
Obligation { cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
trait_ref: predicate.clone() }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn trait_ref_for_builtin_bound<'tcx>(
|
||||
|
@ -259,19 +273,19 @@ pub fn trait_ref_for_builtin_bound<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn obligation_for_builtin_bound<'tcx>(
|
||||
pub fn predicate_for_builtin_bound<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
recursion_depth: uint,
|
||||
param_ty: Ty<'tcx>)
|
||||
-> Result<TraitObligation<'tcx>, ErrorReported>
|
||||
-> Result<PredicateObligation<'tcx>, ErrorReported>
|
||||
{
|
||||
let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
|
||||
Ok(Obligation {
|
||||
cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
trait_ref: trait_ref
|
||||
trait_ref: ty::Predicate::Trait(trait_ref),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -358,10 +372,11 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
|
|||
super::Unimplemented =>
|
||||
format!("Unimplemented"),
|
||||
|
||||
super::OutputTypeParameterMismatch(ref t, ref e) =>
|
||||
format!("OutputTypeParameterMismatch({}, {})",
|
||||
t.repr(tcx),
|
||||
e.repr(tcx)),
|
||||
super::OutputTypeParameterMismatch(ref a, ref b, ref c) =>
|
||||
format!("OutputTypeParameterMismatch({},{},{})",
|
||||
a.repr(tcx),
|
||||
b.repr(tcx),
|
||||
c.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ use back::svh::Svh;
|
|||
use session::Session;
|
||||
use lint;
|
||||
use metadata::csearch;
|
||||
use middle;
|
||||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::dependency_format;
|
||||
|
@ -60,13 +61,14 @@ use middle::traits::ObligationCause;
|
|||
use middle::traits;
|
||||
use middle::ty;
|
||||
use middle::ty_fold::{mod, TypeFoldable, TypeFolder, HigherRankedFoldable};
|
||||
use middle;
|
||||
use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
|
||||
use util::ppaux::{trait_store_to_string, ty_to_string};
|
||||
use util::ppaux::{Repr, UserString};
|
||||
use util::common::{indenter, memoized};
|
||||
use util::common::{indenter, memoized, ErrorReported};
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||
|
||||
use arena::TypedArena;
|
||||
use std::borrow::BorrowFrom;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cmp;
|
||||
|
@ -75,8 +77,8 @@ use std::hash::{Hash, sip, Writer};
|
|||
use std::mem;
|
||||
use std::ops;
|
||||
use std::rc::Rc;
|
||||
use std::collections::enum_set::{EnumSet, CLike};
|
||||
use std::collections::hash_map::{HashMap, Occupied, Vacant};
|
||||
use arena::TypedArena;
|
||||
use syntax::abi;
|
||||
use syntax::ast::{CrateNum, DefId, DUMMY_NODE_ID, FnStyle, Ident, ItemTrait, LOCAL_CRATE};
|
||||
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
|
||||
|
@ -87,7 +89,6 @@ use syntax::attr::{mod, AttrMetaMethods};
|
|||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
use syntax::parse::token::{mod, InternedString};
|
||||
use syntax::{ast, ast_map};
|
||||
use std::collections::enum_set::{EnumSet, CLike};
|
||||
|
||||
pub type Disr = u64;
|
||||
|
||||
|
@ -1613,8 +1614,14 @@ pub struct RegionParameterDef {
|
|||
pub bounds: Vec<ty::Region>,
|
||||
}
|
||||
|
||||
/// Information about the formal type/lifetime parameters associated with an
|
||||
/// item or method. Analogous to ast::Generics.
|
||||
impl RegionParameterDef {
|
||||
pub fn to_early_bound_region(&self) -> ty::Region {
|
||||
ty::ReEarlyBound(self.def_id.node, self.space, self.index, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about the formal type/lifetime parameters associated
|
||||
/// with an item or method. Analogous to ast::Generics.
|
||||
#[deriving(Clone, Show)]
|
||||
pub struct Generics<'tcx> {
|
||||
pub types: VecPerParamSpace<TypeParameterDef<'tcx>>,
|
||||
|
@ -1622,21 +1629,6 @@ pub struct Generics<'tcx> {
|
|||
pub predicates: VecPerParamSpace<Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
#[deriving(Clone, Show)]
|
||||
pub enum Predicate<'tcx> {
|
||||
/// where Foo : Bar
|
||||
Trait(Rc<TraitRef<'tcx>>),
|
||||
|
||||
/// where Foo == Bar
|
||||
Equate(Ty<'tcx>, Ty<'tcx>),
|
||||
|
||||
/// where 'a : 'b
|
||||
RegionOutlives(Region, Region),
|
||||
|
||||
/// where T : 'a
|
||||
TypeOutlives(Ty<'tcx>, Region),
|
||||
}
|
||||
|
||||
impl<'tcx> Generics<'tcx> {
|
||||
pub fn empty() -> Generics<'tcx> {
|
||||
Generics {
|
||||
|
@ -1657,8 +1649,47 @@ impl<'tcx> Generics<'tcx> {
|
|||
pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>)
|
||||
-> GenericBounds<'tcx> {
|
||||
GenericBounds {
|
||||
types: self.types.map(|d| d.bounds.subst(tcx, substs)),
|
||||
regions: self.regions.map(|d| d.bounds.subst(tcx, substs)),
|
||||
predicates: self.predicates.subst(tcx, substs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub enum Predicate<'tcx> {
|
||||
/// where Foo : Bar
|
||||
Trait(Rc<TraitRef<'tcx>>),
|
||||
|
||||
/// where Foo == Bar
|
||||
Equate(Ty<'tcx>, Ty<'tcx>),
|
||||
|
||||
/// where 'a : 'b
|
||||
RegionOutlives(Region, Region),
|
||||
|
||||
/// where T : 'a
|
||||
TypeOutlives(Ty<'tcx>, Region),
|
||||
}
|
||||
|
||||
impl<'tcx> Predicate<'tcx> {
|
||||
pub fn has_escaping_regions(&self) -> bool {
|
||||
match *self {
|
||||
Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(),
|
||||
Predicate::Equate(a, b) => (ty::type_has_escaping_regions(a) ||
|
||||
ty::type_has_escaping_regions(b)),
|
||||
Predicate::RegionOutlives(a, b) => a.escapes_depth(0) || b.escapes_depth(0),
|
||||
Predicate::TypeOutlives(a, b) => ty::type_has_escaping_regions(a) || b.escapes_depth(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_trait(&self) -> Option<Rc<TraitRef<'tcx>>> {
|
||||
match *self {
|
||||
Predicate::Trait(ref t) => {
|
||||
Some(t.clone())
|
||||
}
|
||||
Predicate::Equate(..) |
|
||||
Predicate::RegionOutlives(..) |
|
||||
Predicate::TypeOutlives(..) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1684,19 +1715,20 @@ impl<'tcx> Generics<'tcx> {
|
|||
/// [uint:Bar<int>]]`.
|
||||
#[deriving(Clone, Show)]
|
||||
pub struct GenericBounds<'tcx> {
|
||||
pub types: VecPerParamSpace<ParamBounds<'tcx>>,
|
||||
pub regions: VecPerParamSpace<Vec<Region>>,
|
||||
pub predicates: VecPerParamSpace<Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> GenericBounds<'tcx> {
|
||||
pub fn empty() -> GenericBounds<'tcx> {
|
||||
GenericBounds { types: VecPerParamSpace::empty(),
|
||||
regions: VecPerParamSpace::empty() }
|
||||
GenericBounds { predicates: VecPerParamSpace::empty() }
|
||||
}
|
||||
|
||||
pub fn has_escaping_regions(&self) -> bool {
|
||||
self.types.any(|pb| pb.trait_bounds.iter().any(|tr| tr.has_escaping_regions())) ||
|
||||
self.regions.any(|rs| rs.iter().any(|r| r.escapes_depth(0)))
|
||||
self.predicates.any(|p| p.has_escaping_regions())
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.predicates.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1747,9 +1779,6 @@ pub struct ParameterEnvironment<'tcx> {
|
|||
/// parameters in the same way, this only has an effect on regions.
|
||||
pub free_substs: Substs<'tcx>,
|
||||
|
||||
/// Bounds on the various type parameters
|
||||
pub bounds: VecPerParamSpace<ParamBounds<'tcx>>,
|
||||
|
||||
/// Each type parameter has an implicit region bound that
|
||||
/// indicates it must outlive at least the function body (the user
|
||||
/// may specify stronger requirements). This field indicates the
|
||||
|
@ -1759,10 +1788,7 @@ pub struct ParameterEnvironment<'tcx> {
|
|||
/// Obligations that the caller must satisfy. This is basically
|
||||
/// the set of bounds on the in-scope type parameters, translated
|
||||
/// into Obligations.
|
||||
///
|
||||
/// Note: This effectively *duplicates* the `bounds` array for
|
||||
/// now.
|
||||
pub caller_obligations: VecPerParamSpace<traits::TraitObligation<'tcx>>,
|
||||
pub caller_bounds: ty::GenericBounds<'tcx>,
|
||||
|
||||
/// Caches the results of trait selection. This cache is used
|
||||
/// for things that have to do with the parameters in scope.
|
||||
|
@ -3160,7 +3186,8 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
|
|||
pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>)
|
||||
-> bool {
|
||||
-> bool
|
||||
{
|
||||
if !type_has_params(ty) && !type_has_self(ty) {
|
||||
match cx.type_moves_by_default_cache.borrow().get(&ty) {
|
||||
None => {}
|
||||
|
@ -3181,20 +3208,20 @@ pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
|
|||
// (there shouldn't really be any anyhow)
|
||||
let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
|
||||
|
||||
let obligation = traits::obligation_for_builtin_bound(
|
||||
cx,
|
||||
cause,
|
||||
ty,
|
||||
ty::BoundCopy).unwrap();
|
||||
fulfill_cx.register_obligation(cx, obligation);
|
||||
let result = !fulfill_cx.select_all_or_error(&infcx,
|
||||
param_env,
|
||||
cx).is_ok();
|
||||
cx.type_moves_by_default_cache.borrow_mut().insert(ty, result);
|
||||
fulfill_cx.register_builtin_bound(cx, ty, ty::BoundCopy, cause);
|
||||
|
||||
// Note: we only assuming something is `Copy` if we can
|
||||
// *definitively* show that it implements `Copy`. Otherwise,
|
||||
// assume it is move; linear is always ok.
|
||||
let is_copy = fulfill_cx.select_all_or_error(&infcx, param_env, cx).is_ok();
|
||||
let is_move = !is_copy;
|
||||
|
||||
debug!("determined whether {} moves by default: {}",
|
||||
ty_to_string(cx, ty),
|
||||
result);
|
||||
result
|
||||
is_move);
|
||||
|
||||
cx.type_moves_by_default_cache.borrow_mut().insert(ty, is_move);
|
||||
is_move
|
||||
}
|
||||
|
||||
pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
|
@ -5006,9 +5033,9 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
|
|||
|
||||
/// Given a reference to a trait, returns the bounds declared on the
|
||||
/// trait, with appropriate substitutions applied.
|
||||
pub fn bounds_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
||||
trait_ref: &TraitRef<'tcx>)
|
||||
-> ty::ParamBounds<'tcx>
|
||||
pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
||||
trait_ref: &TraitRef<'tcx>)
|
||||
-> Vec<ty::Predicate<'tcx>>
|
||||
{
|
||||
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
|
||||
|
||||
|
@ -5099,11 +5126,39 @@ pub fn bounds_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
|||
let builtin_bounds =
|
||||
trait_def.bounds.builtin_bounds.subst(tcx, &trait_ref.substs);
|
||||
|
||||
ty::ParamBounds {
|
||||
let bounds = ty::ParamBounds {
|
||||
trait_bounds: trait_bounds,
|
||||
region_bounds: region_bounds,
|
||||
builtin_bounds: builtin_bounds,
|
||||
};
|
||||
|
||||
predicates(tcx, trait_ref.self_ty(), &bounds)
|
||||
}
|
||||
|
||||
pub fn predicates<'tcx>(
|
||||
tcx: &ctxt<'tcx>,
|
||||
param_ty: Ty<'tcx>,
|
||||
bounds: &ParamBounds<'tcx>)
|
||||
-> Vec<Predicate<'tcx>>
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
|
||||
for builtin_bound in bounds.builtin_bounds.iter() {
|
||||
match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) {
|
||||
Ok(trait_ref) => { vec.push(Predicate::Trait(trait_ref)); }
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
|
||||
for ®ion_bound in bounds.region_bounds.iter() {
|
||||
vec.push(Predicate::TypeOutlives(param_ty, region_bound));
|
||||
}
|
||||
|
||||
for bound_trait_ref in bounds.trait_bounds.iter() {
|
||||
vec.push(Predicate::Trait((*bound_trait_ref).clone()));
|
||||
}
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
/// Iterate over attributes of a definition.
|
||||
|
@ -5461,56 +5516,62 @@ pub fn each_bound_trait_and_supertraits<'tcx>(tcx: &ctxt<'tcx>,
|
|||
return true;
|
||||
}
|
||||
|
||||
pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
|
||||
opt_principal: Option<&TraitRef<'tcx>>, // None for boxed closures
|
||||
others: BuiltinBounds)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
// Since we don't actually *know* the self type for an object,
|
||||
// this "open(err)" serves as a kind of dummy standin -- basically
|
||||
// a skolemized type.
|
||||
let open_ty = ty::mk_infer(tcx, SkolemizedTy(0));
|
||||
|
||||
let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
|
||||
let substs = principal.substs.with_self_ty(open_ty);
|
||||
vec!(Rc::new(ty::TraitRef::new(principal.def_id, substs)))
|
||||
});
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: others,
|
||||
trait_bounds: opt_trait_ref,
|
||||
};
|
||||
|
||||
let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
|
||||
ty::required_region_bounds(tcx, open_ty, predicates)
|
||||
}
|
||||
|
||||
/// Given a type which must meet the builtin bounds and trait bounds, returns a set of lifetimes
|
||||
/// which the type must outlive.
|
||||
///
|
||||
/// Requires that trait definitions have been processed.
|
||||
pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
|
||||
region_bounds: &[ty::Region],
|
||||
builtin_bounds: BuiltinBounds,
|
||||
trait_bounds: &[Rc<TraitRef<'tcx>>])
|
||||
param_ty: Ty<'tcx>,
|
||||
predicates: Vec<ty::Predicate<'tcx>>)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
let mut all_bounds = Vec::new();
|
||||
debug!("required_region_bounds(param_ty={}, predicates={})",
|
||||
param_ty.repr(tcx),
|
||||
predicates.repr(tcx));
|
||||
|
||||
debug!("required_region_bounds(builtin_bounds={}, trait_bounds={})",
|
||||
builtin_bounds.repr(tcx),
|
||||
trait_bounds.repr(tcx));
|
||||
|
||||
all_bounds.push_all(region_bounds);
|
||||
|
||||
push_region_bounds(&[],
|
||||
builtin_bounds,
|
||||
&mut all_bounds);
|
||||
|
||||
debug!("from builtin bounds: all_bounds={}", all_bounds.repr(tcx));
|
||||
|
||||
each_bound_trait_and_supertraits(
|
||||
tcx,
|
||||
trait_bounds,
|
||||
|trait_ref| {
|
||||
let bounds = ty::bounds_for_trait_ref(tcx, &*trait_ref);
|
||||
push_region_bounds(bounds.region_bounds.as_slice(),
|
||||
bounds.builtin_bounds,
|
||||
&mut all_bounds);
|
||||
debug!("from {}: bounds={} all_bounds={}",
|
||||
trait_ref.repr(tcx),
|
||||
bounds.repr(tcx),
|
||||
all_bounds.repr(tcx));
|
||||
true
|
||||
});
|
||||
|
||||
return all_bounds;
|
||||
|
||||
fn push_region_bounds(region_bounds: &[ty::Region],
|
||||
builtin_bounds: ty::BuiltinBounds,
|
||||
all_bounds: &mut Vec<ty::Region>) {
|
||||
all_bounds.push_all(region_bounds.as_slice());
|
||||
|
||||
if builtin_bounds.contains(&ty::BoundSend) {
|
||||
all_bounds.push(ty::ReStatic);
|
||||
}
|
||||
}
|
||||
traits::elaborate_predicates(tcx, predicates)
|
||||
.filter_map(|predicate| {
|
||||
match predicate {
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
None
|
||||
}
|
||||
ty::Predicate::TypeOutlives(t, r) => {
|
||||
if t == param_ty {
|
||||
Some(r)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_tydesc_ty<'tcx>(tcx: &ctxt<'tcx>) -> Result<Ty<'tcx>, String> {
|
||||
|
@ -5860,8 +5921,7 @@ impl Variance {
|
|||
/// are no free type/lifetime parameters in scope.
|
||||
pub fn empty_parameter_environment<'tcx>() -> ParameterEnvironment<'tcx> {
|
||||
ty::ParameterEnvironment { free_substs: Substs::empty(),
|
||||
bounds: VecPerParamSpace::empty(),
|
||||
caller_obligations: VecPerParamSpace::empty(),
|
||||
caller_bounds: GenericBounds::empty(),
|
||||
implicit_region_bound: ty::ReEmpty,
|
||||
selection_cache: traits::SelectionCache::new(), }
|
||||
}
|
||||
|
@ -5906,11 +5966,6 @@ pub fn construct_parameter_environment<'tcx>(
|
|||
|
||||
let bounds = generics.to_bounds(tcx, &free_substs);
|
||||
let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value;
|
||||
let obligations = traits::obligations_for_generics(tcx,
|
||||
traits::ObligationCause::dummy(),
|
||||
&bounds,
|
||||
&free_substs.types);
|
||||
let type_bounds = bounds.types.subst(tcx, &free_substs);
|
||||
|
||||
//
|
||||
// Compute region bounds. For now, these relations are stored in a
|
||||
|
@ -5918,23 +5973,17 @@ pub fn construct_parameter_environment<'tcx>(
|
|||
// crazy about this scheme, but it's convenient, at least.
|
||||
//
|
||||
|
||||
for &space in subst::ParamSpace::all().iter() {
|
||||
record_region_bounds(tcx, space, &free_substs, bounds.regions.get_slice(space));
|
||||
}
|
||||
record_region_bounds(tcx, &bounds);
|
||||
|
||||
|
||||
debug!("construct_parameter_environment: free_id={} free_subst={} \
|
||||
obligations={} type_bounds={}",
|
||||
debug!("construct_parameter_environment: free_id={} free_subst={} bounds={}",
|
||||
free_id,
|
||||
free_substs.repr(tcx),
|
||||
obligations.repr(tcx),
|
||||
type_bounds.repr(tcx));
|
||||
bounds.repr(tcx));
|
||||
|
||||
return ty::ParameterEnvironment {
|
||||
free_substs: free_substs,
|
||||
bounds: bounds.types,
|
||||
implicit_region_bound: ty::ReScope(free_id_scope),
|
||||
caller_obligations: obligations,
|
||||
caller_bounds: bounds,
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
};
|
||||
|
||||
|
@ -5963,31 +6012,24 @@ pub fn construct_parameter_environment<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
space: subst::ParamSpace,
|
||||
free_substs: &Substs<'tcx>,
|
||||
bound_sets: &[Vec<ty::Region>]) {
|
||||
for (subst_region, bound_set) in
|
||||
free_substs.regions().get_slice(space).iter().zip(
|
||||
bound_sets.iter())
|
||||
{
|
||||
// For each region parameter 'subst...
|
||||
for bound_region in bound_set.iter() {
|
||||
// Which is declared with a bound like 'subst:'bound...
|
||||
match (subst_region, bound_region) {
|
||||
(&ty::ReFree(subst_fr), &ty::ReFree(bound_fr)) => {
|
||||
// Record that 'subst outlives 'bound. Or, put
|
||||
// another way, 'bound <= 'subst.
|
||||
tcx.region_maps.relate_free_regions(bound_fr, subst_fr);
|
||||
},
|
||||
_ => {
|
||||
// All named regions are instantiated with free regions.
|
||||
tcx.sess.bug(
|
||||
format!("record_region_bounds: \
|
||||
non free region: {} / {}",
|
||||
subst_region.repr(tcx),
|
||||
bound_region.repr(tcx)).as_slice());
|
||||
}
|
||||
fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, bounds: &GenericBounds<'tcx>) {
|
||||
debug!("record_region_bounds(bounds={})", bounds.repr(tcx));
|
||||
|
||||
for predicate in bounds.predicates.iter() {
|
||||
match *predicate {
|
||||
Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => {
|
||||
// No region bounds here
|
||||
}
|
||||
Predicate::RegionOutlives(ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
|
||||
// Record that `'a:'b`. Or, put another way, `'b <= 'a`.
|
||||
tcx.region_maps.relate_free_regions(fr_b, fr_a);
|
||||
}
|
||||
Predicate::RegionOutlives(r_a, r_b) => {
|
||||
// All named regions are instantiated with free regions.
|
||||
tcx.sess.bug(
|
||||
format!("record_region_bounds: non free region: {} / {}",
|
||||
r_a.repr(tcx),
|
||||
r_b.repr(tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6306,6 +6348,17 @@ impl<'tcx> Repr<'tcx> for TyTrait<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
Predicate::Trait(ref a) => a.repr(tcx),
|
||||
Predicate::Equate(a, b) => format!("Equate({},{})", a.repr(tcx), b.repr(tcx)),
|
||||
Predicate::RegionOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)),
|
||||
Predicate::TypeOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for vtable_origin<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
|
|
|
@ -425,8 +425,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
|
|||
impl<'tcx> TypeFoldable<'tcx> for ty::GenericBounds<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericBounds<'tcx> {
|
||||
ty::GenericBounds {
|
||||
types: self.types.fold_with(folder),
|
||||
regions: self.regions.fold_with(folder),
|
||||
predicates: self.predicates.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -914,17 +914,17 @@ impl<'tcx> Repr<'tcx> for ty::Polytype<'tcx> {
|
|||
|
||||
impl<'tcx> Repr<'tcx> for ty::Generics<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("Generics(types: {}, regions: {})",
|
||||
format!("Generics(types: {}, regions: {}, predicates: {})",
|
||||
self.types.repr(tcx),
|
||||
self.regions.repr(tcx))
|
||||
self.regions.repr(tcx),
|
||||
self.predicates.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::GenericBounds<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("GenericBounds(types: {}, regions: {})",
|
||||
self.types.repr(tcx),
|
||||
self.regions.repr(tcx))
|
||||
format!("GenericBounds({})",
|
||||
self.predicates.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -827,8 +827,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// fully bound. It could be a slight optimization to stop
|
||||
// iterating early.
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
let vtable = selection.map_move_nested(|obligation| {
|
||||
fulfill_cx.register_obligation(tcx, obligation);
|
||||
let vtable = selection.map_move_nested(|predicate| {
|
||||
fulfill_cx.register_predicate(infcx.tcx, predicate);
|
||||
});
|
||||
match fulfill_cx.select_all_or_error(&infcx, ¶m_env, tcx) {
|
||||
Ok(()) => { }
|
||||
|
|
|
@ -800,7 +800,7 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
|
|||
let existential_bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
&[Rc::new(trait_ref.clone())],
|
||||
Some(&trait_ref),
|
||||
bounds);
|
||||
|
||||
let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds);
|
||||
|
@ -918,7 +918,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
let bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
ast_ty.span,
|
||||
[].as_slice(),
|
||||
None,
|
||||
f.bounds.as_slice());
|
||||
let fn_decl = ty_of_closure(this,
|
||||
f.fn_style,
|
||||
|
@ -935,9 +935,10 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
ast::TyProc(ref f) => {
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
let bounds = conv_existential_bounds(this, rscope,
|
||||
let bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
ast_ty.span,
|
||||
[].as_slice(),
|
||||
None,
|
||||
f.bounds.as_slice());
|
||||
|
||||
let fn_decl = ty_of_closure(this,
|
||||
|
@ -1370,7 +1371,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
|||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
main_trait_refs: &[Rc<ty::TraitRef<'tcx>>],
|
||||
principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures
|
||||
ast_bounds: &[ast::TyParamBound])
|
||||
-> ty::ExistentialBounds
|
||||
{
|
||||
|
@ -1381,7 +1382,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
|||
partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
|
||||
|
||||
conv_existential_bounds_from_partitioned_bounds(
|
||||
this, rscope, span, main_trait_refs, partitioned_bounds)
|
||||
this, rscope, span, principal_trait_ref, partitioned_bounds)
|
||||
}
|
||||
|
||||
fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
|
||||
|
@ -1411,11 +1412,12 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
|
|||
}
|
||||
};
|
||||
|
||||
let bounds = conv_existential_bounds_from_partitioned_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
main_trait_bound.as_slice(),
|
||||
partitioned_bounds);
|
||||
let bounds =
|
||||
conv_existential_bounds_from_partitioned_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
main_trait_bound.as_ref().map(|tr| &**tr),
|
||||
partitioned_bounds);
|
||||
|
||||
match main_trait_bound {
|
||||
None => ty::mk_err(),
|
||||
|
@ -1427,7 +1429,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
|
|||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
main_trait_refs: &[Rc<ty::TraitRef<'tcx>>],
|
||||
principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures
|
||||
partitioned_bounds: PartitionedBounds)
|
||||
-> ty::ExistentialBounds
|
||||
where AC: AstConv<'tcx>, RS:RegionScope
|
||||
|
@ -1445,28 +1447,12 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
|
|||
as closure or object bounds").as_slice());
|
||||
}
|
||||
|
||||
// The "main trait refs", rather annoyingly, have no type
|
||||
// specified for the `Self` parameter of the trait. The reason for
|
||||
// this is that they are, after all, *existential* types, and
|
||||
// hence that type is unknown. However, leaving this type missing
|
||||
// causes the substitution code to go all awry when walking the
|
||||
// bounds, so here we clone those trait refs and insert ty::err as
|
||||
// the self type. Perhaps we should do this more generally, it'd
|
||||
// be convenient (or perhaps something else, i.e., ty::erased).
|
||||
let main_trait_refs: Vec<Rc<ty::TraitRef>> =
|
||||
main_trait_refs.iter()
|
||||
.map(|t|
|
||||
Rc::new(ty::TraitRef {
|
||||
def_id: t.def_id,
|
||||
substs: t.substs.with_self_ty(ty::mk_err()) }))
|
||||
.collect();
|
||||
|
||||
let region_bound = compute_region_bound(this,
|
||||
rscope,
|
||||
span,
|
||||
builtin_bounds,
|
||||
region_bounds.as_slice(),
|
||||
main_trait_refs.as_slice());
|
||||
principal_trait_ref,
|
||||
builtin_bounds);
|
||||
|
||||
ty::ExistentialBounds {
|
||||
region_bound: region_bound,
|
||||
|
@ -1478,33 +1464,35 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
|
|||
/// (if any) we can use to summarize this type. The basic idea is that we will use the bound the
|
||||
/// user provided, if they provided one, and otherwise search the supertypes of trait bounds for
|
||||
/// region bounds. It may be that we can derive no bound at all, in which case we return `None`.
|
||||
pub fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
span: Span,
|
||||
builtin_bounds: ty::BuiltinBounds,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
trait_bounds: &[Rc<ty::TraitRef<'tcx>>])
|
||||
-> Option<ty::Region>
|
||||
fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
span: Span,
|
||||
explicit_region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<&ty::TraitRef<'tcx>>,
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> Option<ty::Region>
|
||||
{
|
||||
if region_bounds.len() > 1 {
|
||||
debug!("compute_opt_region_bound(explicit_region_bounds={}, \
|
||||
principal_trait_ref={}, builtin_bounds={})",
|
||||
explicit_region_bounds,
|
||||
principal_trait_ref.repr(tcx),
|
||||
builtin_bounds.repr(tcx));
|
||||
|
||||
if explicit_region_bounds.len() > 1 {
|
||||
tcx.sess.span_err(
|
||||
region_bounds[1].span,
|
||||
explicit_region_bounds[1].span,
|
||||
format!("only a single explicit lifetime bound is permitted").as_slice());
|
||||
}
|
||||
|
||||
if region_bounds.len() != 0 {
|
||||
if explicit_region_bounds.len() != 0 {
|
||||
// Explicitly specified region bound. Use that.
|
||||
let r = region_bounds[0];
|
||||
let r = explicit_region_bounds[0];
|
||||
return Some(ast_region_to_region(tcx, r));
|
||||
}
|
||||
|
||||
// No explicit region bound specified. Therefore, examine trait
|
||||
// bounds and see if we can derive region bounds from those.
|
||||
let derived_region_bounds =
|
||||
ty::required_region_bounds(
|
||||
tcx,
|
||||
&[],
|
||||
builtin_bounds,
|
||||
trait_bounds);
|
||||
ty::object_region_bounds(tcx, principal_trait_ref, builtin_bounds);
|
||||
|
||||
// If there are no derived region bounds, then report back that we
|
||||
// can find no region bound.
|
||||
|
@ -1538,13 +1526,13 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
|||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
builtin_bounds: ty::BuiltinBounds,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
trait_bounds: &[Rc<ty::TraitRef<'tcx>>])
|
||||
principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for closures
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> ty::Region
|
||||
{
|
||||
match compute_opt_region_bound(this.tcx(), span, builtin_bounds,
|
||||
region_bounds, trait_bounds) {
|
||||
match compute_opt_region_bound(this.tcx(), span, region_bounds,
|
||||
principal_trait_ref, builtin_bounds) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
match rscope.default_region_bound(span) {
|
||||
|
|
|
@ -232,16 +232,24 @@ fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
|
|||
-> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)>
|
||||
{
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
for obligation in fcx.inh.fulfillment_cx.borrow().pending_trait_obligations().iter() {
|
||||
let obligation_self_ty = fcx.infcx().shallow_resolve(obligation.self_ty());
|
||||
match obligation_self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
|
||||
_ => { continue; }
|
||||
}
|
||||
for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
|
||||
match self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
|
||||
_ => { continue; }
|
||||
}
|
||||
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &*obligation.trait_ref) {
|
||||
Some(e) => { return Some(e); }
|
||||
None => { }
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &**trait_ref) {
|
||||
Some(e) => { return Some(e); }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -463,7 +463,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::misc(self.span, self.fcx.body_id),
|
||||
method_bounds_substs,
|
||||
method_bounds);
|
||||
|
||||
self.fcx.add_default_region_param_bounds(
|
||||
|
|
|
@ -169,7 +169,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
|
||||
|
||||
// Construct an obligation
|
||||
let obligation = traits::Obligation::misc(span, fcx.body_id, trait_ref.clone());
|
||||
let obligation = traits::Obligation::misc(span,
|
||||
fcx.body_id,
|
||||
ty::Predicate::Trait(trait_ref.clone()));
|
||||
|
||||
// Now we want to know if this can be matched
|
||||
let mut selcx = traits::SelectionContext::new(fcx.infcx(),
|
||||
|
@ -187,6 +189,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
|
||||
assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
|
||||
|
||||
debug!("lookup_in_trait_adjusted: method_num={} method_ty={}",
|
||||
method_num, method_ty.repr(fcx.tcx()));
|
||||
|
||||
// Substitute the trait parameters into the method type and
|
||||
// instantiate late-bound regions to get the actual method type.
|
||||
//
|
||||
|
@ -204,7 +209,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
abi: bare_fn_ty.abi.clone(),
|
||||
});
|
||||
|
||||
debug!("matched method fty={} obligation={}",
|
||||
debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}",
|
||||
fty.repr(fcx.tcx()),
|
||||
obligation.repr(fcx.tcx()));
|
||||
|
||||
|
@ -220,7 +225,6 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
assert!(!method_bounds.has_escaping_regions());
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::misc(span, fcx.body_id),
|
||||
&trait_ref.substs,
|
||||
&method_bounds);
|
||||
|
||||
// FIXME(#18653) -- Try to resolve obligations, giving us more
|
||||
|
@ -233,8 +237,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
None => { }
|
||||
|
||||
Some(self_expr) => {
|
||||
debug!("inserting adjustment if needed (self-id = {}, \
|
||||
base adjustment = {}, explicit self = {})",
|
||||
debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
|
||||
(self-id={}, base adjustment={}, explicit_self={})",
|
||||
self_expr.id, autoderefref, method_ty.explicit_self);
|
||||
|
||||
match method_ty.explicit_self {
|
||||
|
|
|
@ -353,11 +353,27 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
param_ty: ty::ParamTy) {
|
||||
// FIXME -- Do we want to commit to this behavior for param bounds?
|
||||
|
||||
let ty::ParamTy { space, idx: index, .. } = param_ty;
|
||||
let bounds =
|
||||
self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
|
||||
.as_slice();
|
||||
self.elaborate_bounds(bounds, true, |this, trait_ref, m, method_num| {
|
||||
let bounds: Vec<_> =
|
||||
self.fcx.inh.param_env.caller_bounds.predicates
|
||||
.iter()
|
||||
.filter_map(|predicate| {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
match trait_ref.self_ty().sty {
|
||||
ty::ty_param(ref p) if *p == param_ty => Some(trait_ref.clone()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.elaborate_bounds(bounds.as_slice(), true, |this, trait_ref, m, method_num| {
|
||||
let xform_self_ty =
|
||||
this.xform_self_ty(&m, &trait_ref.substs);
|
||||
|
||||
|
@ -400,6 +416,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
m: Rc<ty::Method<'tcx>>,
|
||||
method_num: uint|)
|
||||
{
|
||||
debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx()));
|
||||
|
||||
let tcx = self.tcx();
|
||||
let mut cache = HashSet::new();
|
||||
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
|
||||
|
@ -802,11 +820,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
// Convert the bounds into obligations.
|
||||
let obligations =
|
||||
traits::obligations_for_generics(
|
||||
traits::predicates_for_generics(
|
||||
self.tcx(),
|
||||
traits::ObligationCause::misc(self.span, self.fcx.body_id),
|
||||
&impl_bounds,
|
||||
&substs.types);
|
||||
&impl_bounds);
|
||||
debug!("impl_obligations={}", obligations.repr(self.tcx()));
|
||||
|
||||
// Evaluate those obligations to see if they might possibly hold.
|
||||
|
|
|
@ -104,6 +104,7 @@ use {CrateCtxt, lookup_def_ccx, no_params, require_same_types};
|
|||
use TypeAndSubsts;
|
||||
use middle::lang_items::TypeIdLangItem;
|
||||
use lint;
|
||||
use util::common::ErrorReported;
|
||||
use util::common::{block_query, indenter, loop_query};
|
||||
use util::ppaux::{mod, UserString, Repr};
|
||||
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||
|
@ -1761,7 +1762,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span,
|
||||
self.body_id,
|
||||
traits::ItemObligation(def_id)),
|
||||
&substs,
|
||||
&bounds);
|
||||
let monotype =
|
||||
polytype.ty.subst(self.tcx(), &substs);
|
||||
|
@ -1785,14 +1785,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
code: traits::ObligationCauseCode<'tcx>,
|
||||
bound: ty::BuiltinBound)
|
||||
{
|
||||
let obligation = traits::obligation_for_builtin_bound(
|
||||
self.tcx(),
|
||||
traits::ObligationCause::new(span, self.body_id, code),
|
||||
self.register_builtin_bound(
|
||||
ty,
|
||||
bound);
|
||||
if let Ok(ob) = obligation {
|
||||
self.register_obligation(ob);
|
||||
}
|
||||
bound,
|
||||
traits::ObligationCause::new(span, self.body_id, code));
|
||||
}
|
||||
|
||||
pub fn require_type_is_sized(&self,
|
||||
|
@ -1810,15 +1806,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
|
||||
}
|
||||
|
||||
pub fn register_obligation(&self,
|
||||
obligation: traits::TraitObligation<'tcx>)
|
||||
pub fn register_builtin_bound(&self,
|
||||
ty: Ty<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
cause: traits::ObligationCause<'tcx>)
|
||||
{
|
||||
debug!("register_obligation({})",
|
||||
self.inh.fulfillment_cx.borrow_mut()
|
||||
.register_builtin_bound(self.tcx(), ty, builtin_bound, cause);
|
||||
}
|
||||
|
||||
pub fn register_predicate(&self,
|
||||
obligation: traits::PredicateObligation<'tcx>)
|
||||
{
|
||||
debug!("register_predicate({})",
|
||||
obligation.repr(self.tcx()));
|
||||
|
||||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.register_obligation(self.tcx(), obligation);
|
||||
.register_predicate(self.tcx(), obligation);
|
||||
}
|
||||
|
||||
pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> {
|
||||
|
@ -1958,7 +1963,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
cause: traits::ObligationCause<'tcx>)
|
||||
{
|
||||
let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
|
||||
fulfillment_cx.register_region_obligation(ty, region, cause);
|
||||
fulfillment_cx.register_region_obligation(self.tcx(), ty, region, cause);
|
||||
}
|
||||
|
||||
pub fn add_default_region_param_bounds(&self,
|
||||
|
@ -1993,90 +1998,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
|
||||
pub fn add_obligations_for_parameters(&self,
|
||||
cause: traits::ObligationCause<'tcx>,
|
||||
substs: &Substs<'tcx>,
|
||||
generic_bounds: &ty::GenericBounds<'tcx>)
|
||||
{
|
||||
assert!(!generic_bounds.has_escaping_regions());
|
||||
|
||||
debug!("add_obligations_for_parameters(substs={}, generic_bounds={})",
|
||||
substs.repr(self.tcx()),
|
||||
debug!("add_obligations_for_parameters(generic_bounds={})",
|
||||
generic_bounds.repr(self.tcx()));
|
||||
|
||||
self.add_trait_obligations_for_generics(cause, substs, generic_bounds);
|
||||
self.add_region_obligations_for_generics(cause, substs, generic_bounds);
|
||||
}
|
||||
let obligations = traits::predicates_for_generics(self.tcx(),
|
||||
cause,
|
||||
generic_bounds);
|
||||
|
||||
fn add_trait_obligations_for_generics(&self,
|
||||
cause: traits::ObligationCause<'tcx>,
|
||||
substs: &Substs<'tcx>,
|
||||
generic_bounds: &ty::GenericBounds<'tcx>) {
|
||||
assert!(!generic_bounds.has_escaping_regions());
|
||||
assert!(!substs.has_regions_escaping_depth(0));
|
||||
|
||||
let obligations =
|
||||
traits::obligations_for_generics(self.tcx(),
|
||||
cause,
|
||||
generic_bounds,
|
||||
&substs.types);
|
||||
obligations.map_move(|o| self.register_obligation(o));
|
||||
}
|
||||
|
||||
fn add_region_obligations_for_generics(&self,
|
||||
cause: traits::ObligationCause<'tcx>,
|
||||
substs: &Substs<'tcx>,
|
||||
generic_bounds: &ty::GenericBounds<'tcx>)
|
||||
{
|
||||
assert!(!generic_bounds.has_escaping_regions());
|
||||
assert_eq!(generic_bounds.types.iter().len(), substs.types.iter().len());
|
||||
|
||||
for (type_bounds, &type_param) in
|
||||
generic_bounds.types.iter().zip(
|
||||
substs.types.iter())
|
||||
{
|
||||
self.add_region_obligations_for_type_parameter(
|
||||
cause.span, type_bounds, type_param);
|
||||
}
|
||||
|
||||
assert_eq!(generic_bounds.regions.iter().len(),
|
||||
substs.regions().iter().len());
|
||||
for (region_bounds, ®ion_param) in
|
||||
generic_bounds.regions.iter().zip(
|
||||
substs.regions().iter())
|
||||
{
|
||||
self.add_region_obligations_for_region_parameter(
|
||||
cause.span, region_bounds.as_slice(), region_param);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_region_obligations_for_type_parameter(&self,
|
||||
span: Span,
|
||||
param_bound: &ty::ParamBounds<'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
{
|
||||
// For each declared region bound `T:r`, `T` must outlive `r`.
|
||||
let region_bounds =
|
||||
ty::required_region_bounds(
|
||||
self.tcx(),
|
||||
param_bound.region_bounds.as_slice(),
|
||||
param_bound.builtin_bounds,
|
||||
param_bound.trait_bounds.as_slice());
|
||||
for &r in region_bounds.iter() {
|
||||
let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
|
||||
self.register_region_obligation(ty, r, cause);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_region_obligations_for_region_parameter(&self,
|
||||
span: Span,
|
||||
region_bounds: &[ty::Region],
|
||||
region_param: ty::Region)
|
||||
{
|
||||
for &b in region_bounds.iter() {
|
||||
// For each bound `region:b`, `b <= region` must hold
|
||||
// (i.e., `region` must outlive `b`).
|
||||
let origin = infer::RelateRegionParamBound(span);
|
||||
self.mk_subr(origin, b, region_param);
|
||||
}
|
||||
obligations.map_move(|o| self.register_predicate(o));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4029,6 +3962,9 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
let typ = lookup_method_for_for_loop(fcx, &**head, expr.id);
|
||||
vtable::select_new_fcx_obligations(fcx);
|
||||
|
||||
debug!("ExprForLoop each item has type {}",
|
||||
fcx.infcx().resolve_type_vars_if_possible(typ).repr(fcx.tcx()));
|
||||
|
||||
let pcx = pat_ctxt {
|
||||
fcx: fcx,
|
||||
map: pat_id_map(&tcx.def_map, &**pat),
|
||||
|
@ -5162,7 +5098,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())),
|
||||
&substs,
|
||||
&bounds);
|
||||
|
||||
// Substitute the values for the type parameters into the type of
|
||||
|
|
|
@ -932,14 +932,9 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
|
||||
// Check that the type meets the criteria of the existential bounds:
|
||||
for builtin_bound in bounds.builtin_bounds.iter() {
|
||||
let code = traits::ClosureCapture(var_node_id, expr.span);
|
||||
let code = traits::ClosureCapture(var_node_id, expr.span, builtin_bound);
|
||||
let cause = traits::ObligationCause::new(freevar.span, rcx.fcx.body_id, code);
|
||||
let obligation = traits::obligation_for_builtin_bound(rcx.tcx(), cause,
|
||||
var_ty, builtin_bound);
|
||||
if let Ok(obligation) = obligation {
|
||||
rcx.fcx.inh.fulfillment_cx.borrow_mut().register_obligation(rcx.tcx(),
|
||||
obligation)
|
||||
}
|
||||
rcx.fcx.register_builtin_bound(var_ty, builtin_bound, cause);
|
||||
}
|
||||
type_must_outlive(
|
||||
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
|
||||
|
@ -1859,20 +1854,14 @@ fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
region.repr(rcx.tcx()),
|
||||
param_ty.repr(rcx.tcx()));
|
||||
|
||||
// Collect all regions that `param_ty` is known to outlive into
|
||||
// this vector:
|
||||
let mut param_bounds;
|
||||
|
||||
// To start, collect bounds from user:
|
||||
let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx);
|
||||
param_bounds =
|
||||
let mut param_bounds =
|
||||
ty::required_region_bounds(rcx.tcx(),
|
||||
param_bound.region_bounds.as_slice(),
|
||||
param_bound.builtin_bounds,
|
||||
param_bound.trait_bounds.as_slice());
|
||||
param_ty.to_ty(rcx.tcx()),
|
||||
param_env.caller_bounds.predicates.as_slice().to_vec());
|
||||
|
||||
// Collect default bound of fn body that applies to all in scope
|
||||
// type parameters:
|
||||
// Add in the default bound of fn body that applies to all in
|
||||
// scope type parameters:
|
||||
param_bounds.push(param_env.implicit_region_bound);
|
||||
|
||||
// Finally, collect regions we scraped from the well-formedness
|
||||
|
|
|
@ -97,7 +97,9 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::ty_trait(ref t) => {
|
||||
self.accumulate_from_object_ty(ty, &t.bounds)
|
||||
let required_region_bounds =
|
||||
ty::object_region_bounds(self.tcx, Some(&t.principal), t.bounds.builtin_bounds);
|
||||
self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
|
||||
}
|
||||
|
||||
ty::ty_enum(def_id, ref substs) |
|
||||
|
@ -321,12 +323,15 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
|||
ty::UniqTraitStore => { }
|
||||
}
|
||||
|
||||
self.accumulate_from_object_ty(ty, &c.bounds)
|
||||
let required_region_bounds =
|
||||
ty::object_region_bounds(self.tcx, None, c.bounds.builtin_bounds);
|
||||
self.accumulate_from_object_ty(ty, c.bounds.region_bound, required_region_bounds);
|
||||
}
|
||||
|
||||
fn accumulate_from_object_ty(&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
bounds: &ty::ExistentialBounds)
|
||||
region_bound: ty::Region,
|
||||
required_region_bounds: Vec<ty::Region>)
|
||||
{
|
||||
// Imagine a type like this:
|
||||
//
|
||||
|
@ -362,17 +367,12 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
|||
|
||||
// The content of this object type must outlive
|
||||
// `bounds.region_bound`:
|
||||
let r_c = bounds.region_bound;
|
||||
let r_c = region_bound;
|
||||
self.push_region_constraint_from_top(r_c);
|
||||
|
||||
// And then, in turn, to be well-formed, the
|
||||
// `region_bound` that user specified must imply the
|
||||
// region bounds required from all of the trait types:
|
||||
let required_region_bounds =
|
||||
ty::required_region_bounds(self.tcx,
|
||||
&[],
|
||||
bounds.builtin_bounds,
|
||||
&[]);
|
||||
for &r_d in required_region_bounds.iter() {
|
||||
// Each of these is an instance of the `'c <= 'b`
|
||||
// constraint above
|
||||
|
|
|
@ -12,15 +12,14 @@ use check::{FnCtxt, structurally_resolved_type};
|
|||
use middle::subst::{SelfSpace, FnSpace};
|
||||
use middle::traits;
|
||||
use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented};
|
||||
use middle::traits::{Obligation, ObligationCause, obligation_for_builtin_bound};
|
||||
use middle::traits::{Obligation, ObligationCause};
|
||||
use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity};
|
||||
use middle::traits::{TraitObligation};
|
||||
use middle::traits::{PredicateObligation};
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::infer;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use util::common::ErrorReported;
|
||||
use util::ppaux::{UserString, Repr, ty_to_string};
|
||||
|
||||
pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
@ -249,18 +248,10 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
-> Rc<ty::TraitRef<'tcx>>
|
||||
{
|
||||
// We can only make objects from sized types.
|
||||
let sized_obligation =
|
||||
traits::obligation_for_builtin_bound(
|
||||
fcx.tcx(),
|
||||
traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized),
|
||||
referent_ty,
|
||||
ty::BoundSized);
|
||||
match sized_obligation {
|
||||
Ok(sized_obligation) => {
|
||||
fcx.register_obligation(sized_obligation);
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
fcx.register_builtin_bound(
|
||||
referent_ty,
|
||||
ty::BoundSized,
|
||||
traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized));
|
||||
|
||||
// This is just for better error reporting. Kinda goofy. The object type stuff
|
||||
// needs some refactoring so there is a more convenient type to pass around.
|
||||
|
@ -289,24 +280,18 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty)),
|
||||
object_trait_ref.clone());
|
||||
fcx.register_obligation(object_obligation);
|
||||
ty::Predicate::Trait(object_trait_ref.clone()));
|
||||
fcx.register_predicate(object_obligation);
|
||||
|
||||
// Create additional obligations for all the various builtin
|
||||
// bounds attached to the object cast. (In other words, if the
|
||||
// object type is Foo+Send, this would create an obligation
|
||||
// for the Send check.)
|
||||
for builtin_bound in object_trait.bounds.builtin_bounds.iter() {
|
||||
let obligation = obligation_for_builtin_bound(
|
||||
fcx.tcx(),
|
||||
ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty)),
|
||||
referent_ty,
|
||||
builtin_bound);
|
||||
if let Ok(obligation) = obligation {
|
||||
fcx.register_obligation(obligation);
|
||||
}
|
||||
fcx.register_builtin_bound(
|
||||
referent_ty,
|
||||
builtin_bound,
|
||||
ObligationCause::new(span, fcx.body_id, traits::ObjectCastObligation(object_trait_ty)));
|
||||
}
|
||||
|
||||
object_trait_ref
|
||||
|
@ -325,17 +310,6 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &TraitObligation<'tcx>)
|
||||
-> (Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)
|
||||
{
|
||||
let trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||
&*obligation.trait_ref);
|
||||
let self_ty =
|
||||
trait_ref.substs.self_ty().unwrap();
|
||||
(Rc::new(trait_ref), self_ty)
|
||||
}
|
||||
|
||||
pub fn report_fulfillment_errors<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
errors: &Vec<FulfillmentError<'tcx>>) {
|
||||
for error in errors.iter() {
|
||||
|
@ -356,18 +330,42 @@ pub fn report_fulfillment_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>)
|
||||
{
|
||||
match *error {
|
||||
Overflow => {
|
||||
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"overflow evaluating the trait `{}` for the type `{}`",
|
||||
trait_ref.user_string(fcx.tcx()),
|
||||
self_ty.user_string(fcx.tcx())).as_slice());
|
||||
// We could track the stack here more precisely if we wanted, I imagine.
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref);
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"overflow evaluating the trait `{}` for the type `{}`",
|
||||
trait_ref.user_string(fcx.tcx()),
|
||||
trait_ref.self_ty().user_string(fcx.tcx())).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
let a = fcx.infcx().resolve_type_vars_if_possible(a);
|
||||
let b = fcx.infcx().resolve_type_vars_if_possible(b);
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"overflow checking whether the types `{}` and `{}` are equal",
|
||||
a.user_string(fcx.tcx()),
|
||||
b.user_string(fcx.tcx())).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!("overflow evaluating lifetime predicate").as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
let current_limit = fcx.tcx().sess.recursion_limit.get();
|
||||
let suggested_limit = current_limit * 2;
|
||||
|
@ -380,31 +378,63 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
note_obligation_cause(fcx, obligation);
|
||||
}
|
||||
Unimplemented => {
|
||||
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
||||
if !ty::type_is_error(self_ty) {
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the trait `{}` is not implemented for the type `{}`",
|
||||
trait_ref.user_string(fcx.tcx()),
|
||||
self_ty.user_string(fcx.tcx())).as_slice());
|
||||
note_obligation_cause(fcx, obligation);
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||
&**trait_ref);
|
||||
if !ty::type_is_error(trait_ref.self_ty()) {
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the trait `{}` is not implemented for the type `{}`",
|
||||
trait_ref.user_string(fcx.tcx()),
|
||||
trait_ref.self_ty().user_string(fcx.tcx())).as_slice());
|
||||
note_obligation_cause(fcx, obligation);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
let a = fcx.infcx().resolve_type_vars_if_possible(a);
|
||||
let b = fcx.infcx().resolve_type_vars_if_possible(b);
|
||||
let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err();
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"mismatched types: the types `{}` and `{}` are not equal ({})",
|
||||
a.user_string(fcx.tcx()),
|
||||
b.user_string(fcx.tcx()),
|
||||
ty::type_err_to_str(fcx.tcx(), &err)).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
// these kinds of predicates turn into
|
||||
// constraints, and hence errors show up in region
|
||||
// inference.
|
||||
fcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("region predicate error {}",
|
||||
obligation.repr(fcx.tcx())).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
|
||||
OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
|
||||
let expected_trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||
&**expected_trait_ref);
|
||||
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
||||
if !ty::type_is_error(self_ty) {
|
||||
let actual_trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||
&**actual_trait_ref);
|
||||
if !ty::type_is_error(actual_trait_ref.self_ty()) {
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"type mismatch: the type `{}` implements the trait `{}`, \
|
||||
but the trait `{}` is required ({})",
|
||||
self_ty.user_string(fcx.tcx()),
|
||||
expected_trait_ref.self_ty().user_string(fcx.tcx()),
|
||||
expected_trait_ref.user_string(fcx.tcx()),
|
||||
trait_ref.user_string(fcx.tcx()),
|
||||
actual_trait_ref.user_string(fcx.tcx()),
|
||||
ty::type_err_to_str(fcx.tcx(), e)).as_slice());
|
||||
note_obligation_cause(fcx, obligation);
|
||||
}
|
||||
|
@ -413,12 +443,25 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
obligation: &TraitObligation<'tcx>) {
|
||||
obligation: &PredicateObligation<'tcx>) {
|
||||
// Unable to successfully determine, probably means
|
||||
// insufficient type information, but could mean
|
||||
// ambiguous impls. The latter *ought* to be a
|
||||
// coherence violation, so we don't report it here.
|
||||
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
||||
|
||||
let trait_ref = match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref)
|
||||
}
|
||||
_ => {
|
||||
fcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("ambiguity from something other than a trait: {}",
|
||||
obligation.trait_ref.repr(fcx.tcx())).as_slice());
|
||||
}
|
||||
};
|
||||
let self_ty = trait_ref.self_ty();
|
||||
|
||||
debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
|
||||
trait_ref.repr(fcx.tcx()),
|
||||
self_ty.repr(fcx.tcx()),
|
||||
|
@ -475,8 +518,8 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
/// Select as many obligations as we can at present.
|
||||
pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) {
|
||||
|
||||
pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
|
||||
{
|
||||
match
|
||||
fcx.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
|
@ -502,9 +545,8 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
|
|||
}
|
||||
|
||||
fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
obligation: &TraitObligation<'tcx>) {
|
||||
obligation: &PredicateObligation<'tcx>) {
|
||||
let tcx = fcx.tcx();
|
||||
let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id);
|
||||
match obligation.cause.code {
|
||||
traits::MiscObligation => { }
|
||||
traits::ItemObligation(item_def_id) => {
|
||||
|
@ -512,17 +554,14 @@ fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the trait `{}` must be implemented because it is required by `{}`",
|
||||
trait_name,
|
||||
"required by `{}`",
|
||||
item_name).as_slice());
|
||||
}
|
||||
traits::ObjectCastObligation(object_ty) => {
|
||||
tcx.sess.span_note(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the trait `{}` must be implemented for the cast \
|
||||
to the object type `{}`",
|
||||
trait_name,
|
||||
"required for the cast to the object type `{}`",
|
||||
fcx.infcx().ty_to_string(object_ty)).as_slice());
|
||||
}
|
||||
traits::RepeatVec => {
|
||||
|
@ -560,7 +599,9 @@ fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
"use \"#[unsafe_destructor]\" on the implementation \
|
||||
to force the compiler to allow this");
|
||||
}
|
||||
traits::ClosureCapture(var_id, closure_span) => {
|
||||
traits::ClosureCapture(var_id, closure_span, builtin_bound) => {
|
||||
let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
|
||||
let trait_name = ty::item_path_str(tcx, def_id);
|
||||
let name = ty::local_var_name_str(tcx, var_id);
|
||||
span_note!(tcx.sess, closure_span,
|
||||
"the closure that captures `{}` requires that all captured variables \"
|
||||
|
|
|
@ -122,16 +122,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
// For DST, all intermediate types must be sized.
|
||||
if variant.fields.len() > 0 {
|
||||
for field in variant.fields.init().iter() {
|
||||
let cause = traits::ObligationCause::new(field.span,
|
||||
fcx.body_id,
|
||||
traits::FieldSized);
|
||||
let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
|
||||
cause,
|
||||
field.ty,
|
||||
ty::BoundSized);
|
||||
if let Ok(obligation) = obligation {
|
||||
fcx.register_obligation(obligation);
|
||||
}
|
||||
fcx.register_builtin_bound(
|
||||
field.ty,
|
||||
ty::BoundSized,
|
||||
traits::ObligationCause::new(field.span,
|
||||
fcx.body_id,
|
||||
traits::FieldSized));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,8 +216,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
// the same way as we treat the self-type.
|
||||
bounds_checker.check_trait_ref(&trait_ref);
|
||||
|
||||
let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_ref.def_id);
|
||||
|
||||
let cause =
|
||||
traits::ObligationCause::new(
|
||||
item.span,
|
||||
|
@ -229,25 +223,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
traits::ItemObligation(trait_ref.def_id));
|
||||
|
||||
// Find the supertrait bounds. This will add `int:Bar`.
|
||||
//
|
||||
// FIXME -- This is a bit ill-factored. There is very similar
|
||||
// code in traits::util::obligations_for_generics.
|
||||
fcx.add_region_obligations_for_type_parameter(item.span,
|
||||
&trait_def.bounds,
|
||||
trait_ref.self_ty());
|
||||
for builtin_bound in trait_def.bounds.builtin_bounds.iter() {
|
||||
let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
|
||||
cause,
|
||||
trait_ref.self_ty(),
|
||||
builtin_bound);
|
||||
if let Ok(obligation) = obligation {
|
||||
fcx.register_obligation(obligation);
|
||||
}
|
||||
}
|
||||
for trait_bound in trait_def.bounds.trait_bounds.iter() {
|
||||
let trait_bound = trait_bound.subst(fcx.tcx(), &trait_ref.substs);
|
||||
fcx.register_obligation(
|
||||
traits::Obligation::new(cause, trait_bound));
|
||||
let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &trait_ref);
|
||||
for predicate in predicates.into_iter() {
|
||||
fcx.register_predicate(traits::Obligation::new(cause, predicate));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -296,7 +274,6 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
|
|||
self.span,
|
||||
self.fcx.body_id,
|
||||
traits::ItemObligation(trait_ref.def_id)),
|
||||
&trait_ref.substs,
|
||||
&bounds);
|
||||
|
||||
for &ty in trait_ref.substs.types.iter() {
|
||||
|
@ -347,7 +324,6 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
|||
traits::ObligationCause::new(self.span,
|
||||
self.fcx.body_id,
|
||||
traits::ItemObligation(type_id)),
|
||||
substs,
|
||||
&polytype.generics.to_bounds(self.tcx(), substs));
|
||||
} else {
|
||||
// There are two circumstances in which we ignore
|
||||
|
@ -372,12 +348,13 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
|||
//
|
||||
// (I believe we should do the same for traits, but
|
||||
// that will require an RFC. -nmatsakis)
|
||||
self.fcx.add_trait_obligations_for_generics(
|
||||
let bounds = polytype.generics.to_bounds(self.tcx(), substs);
|
||||
let bounds = filter_to_trait_obligations(bounds);
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
self.fcx.body_id,
|
||||
traits::ItemObligation(type_id)),
|
||||
substs,
|
||||
&polytype.generics.to_bounds(self.tcx(), substs));
|
||||
&bounds);
|
||||
}
|
||||
|
||||
self.fold_substs(substs);
|
||||
|
@ -464,6 +441,24 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>)
|
||||
-> ty::GenericBounds<'tcx>
|
||||
{
|
||||
let mut result = ty::GenericBounds::empty();
|
||||
for (space, _, predicate) in bounds.predicates.iter_enumerated() {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(..) => {
|
||||
result.predicates.push(space, predicate.clone())
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Special drop trait checking
|
||||
|
||||
|
@ -476,13 +471,7 @@ fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
&& !struct_tpt.generics.has_region_params(subst::TypeSpace)
|
||||
{
|
||||
let cause = traits::ObligationCause::new(span, fcx.body_id, traits::DropTrait);
|
||||
let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
|
||||
cause,
|
||||
self_ty,
|
||||
ty::BoundSend);
|
||||
if let Ok(obligation) = obligation {
|
||||
fcx.register_obligation(obligation);
|
||||
}
|
||||
fcx.register_builtin_bound(self_ty, ty::BoundSend, cause);
|
||||
} else {
|
||||
span_err!(fcx.tcx().sess, span, E0141,
|
||||
"cannot implement a destructor on a structure \
|
||||
|
|
|
@ -42,7 +42,6 @@ use middle::region;
|
|||
use middle::resolve_lifetime;
|
||||
use middle::subst;
|
||||
use middle::subst::{Substs};
|
||||
use middle::traits;
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer};
|
||||
use middle::ty::{Polytype};
|
||||
use middle::ty::{mod, Ty};
|
||||
|
@ -50,7 +49,6 @@ use middle::ty_fold::TypeFolder;
|
|||
use middle::infer;
|
||||
use rscope::*;
|
||||
use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||
use util::ppaux;
|
||||
use util::ppaux::{Repr,UserString};
|
||||
|
@ -1409,14 +1407,15 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
.collect();
|
||||
|
||||
// ...and also create generics synthesized from the associated types.
|
||||
let mut index = 0;
|
||||
let assoc_types: Vec<_> =
|
||||
items.iter()
|
||||
.flat_map(|item| match *item {
|
||||
ast::TypeTraitItem(ref trait_item) => {
|
||||
let index = types.len();
|
||||
index += 1;
|
||||
Some(ty::mk_param(ccx.tcx,
|
||||
subst::AssocSpace,
|
||||
index,
|
||||
index - 1,
|
||||
local_def(trait_item.ty_param.id))).into_iter()
|
||||
}
|
||||
ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {
|
||||
|
@ -1598,7 +1597,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
substs: &subst::Substs<'tcx>,
|
||||
ast_generics: &ast::Generics,
|
||||
items: &[ast::TraitItem])
|
||||
-> ty::Generics<'tcx> {
|
||||
-> ty::Generics<'tcx>
|
||||
{
|
||||
let mut generics =
|
||||
ty_generics(ccx,
|
||||
subst::TypeSpace,
|
||||
|
@ -1646,7 +1646,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
bounds: ty::ParamBounds {
|
||||
region_bounds: vec!(),
|
||||
builtin_bounds: ty::empty_builtin_bounds(),
|
||||
trait_bounds: vec!(self_trait_ref),
|
||||
trait_bounds: vec!(self_trait_ref.clone()),
|
||||
},
|
||||
associated_with: None,
|
||||
default: None
|
||||
|
@ -1656,6 +1656,9 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
|
||||
generics.types.push(subst::SelfSpace, def);
|
||||
|
||||
generics.predicates.push(subst::SelfSpace,
|
||||
ty::Predicate::Trait(self_trait_ref));
|
||||
|
||||
generics
|
||||
}
|
||||
|
||||
|
@ -1904,24 +1907,18 @@ fn ty_generics<'tcx,AC>(this: &AC,
|
|||
result: &mut ty::Generics<'tcx>,
|
||||
space: subst::ParamSpace)
|
||||
{
|
||||
for (index, type_param_def) in result.types.get_slice(space).iter().enumerate() {
|
||||
let param_ty = ty::mk_param(tcx, space, index, type_param_def.def_id);
|
||||
|
||||
for builtin_bound in type_param_def.bounds.builtin_bounds.iter() {
|
||||
match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) {
|
||||
Ok(trait_ref) => {
|
||||
result.predicates.push(space, ty::Predicate::Trait(trait_ref));
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
for type_param_def in result.types.get_slice(space).iter() {
|
||||
let param_ty = ty::mk_param_from_def(tcx, type_param_def);
|
||||
for predicate in ty::predicates(tcx, param_ty, &type_param_def.bounds).into_iter() {
|
||||
result.predicates.push(space, predicate);
|
||||
}
|
||||
}
|
||||
|
||||
for ®ion_bound in type_param_def.bounds.region_bounds.iter() {
|
||||
result.predicates.push(space, ty::Predicate::TypeOutlives(param_ty, region_bound));
|
||||
}
|
||||
|
||||
for bound_trait_ref in type_param_def.bounds.trait_bounds.iter() {
|
||||
result.predicates.push(space, ty::Predicate::Trait((*bound_trait_ref).clone()));
|
||||
for region_param_def in result.regions.get_slice(space).iter() {
|
||||
let region = region_param_def.to_early_bound_region();
|
||||
for &bound_region in region_param_def.bounds.iter() {
|
||||
result.predicates.push(space, ty::Predicate::RegionOutlives(region,
|
||||
bound_region));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2178,8 +2175,7 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
|
||||
let regions =
|
||||
ty_generics.regions.map(
|
||||
|def| ty::ReEarlyBound(def.def_id.node, def.space,
|
||||
def.index, def.name));
|
||||
|def| def.to_early_bound_region());
|
||||
|
||||
subst::Substs::new(types, regions)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ trait Foo : Sync+'static {
|
|||
|
||||
impl <T: Sync> Foo for T { }
|
||||
//~^ ERROR the parameter type `T` may not live long enough
|
||||
//~^^ ERROR the parameter type `T` may not live long enough
|
||||
|
||||
fn main() {
|
||||
let (tx, rx) = channel();
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
trait Foo : Send { }
|
||||
|
||||
impl <'a> Foo for &'a mut () { }
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -34,6 +34,7 @@ fn g<T>(val: T) {
|
|||
fn foo<'a>() {
|
||||
let t: S<&'a int> = S;
|
||||
let a = &t as &Gettable<&'a int>;
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn foo2<'a>() {
|
||||
|
|
|
@ -22,7 +22,7 @@ fn test51<'a>() {
|
|||
}
|
||||
fn test52<'a>() {
|
||||
assert_send::<&'a (Dummy+Send)>();
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
// ...unless they are properly bounded
|
||||
|
|
|
@ -19,7 +19,7 @@ fn test32() { assert_send::<Vec<int> >(); }
|
|||
|
||||
// but not if they own a bad thing
|
||||
fn test40<'a>(_: &'a int) {
|
||||
assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<Box<&'a int>>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -22,13 +22,13 @@ fn test10() { assert_send::<&'static mut int>(); }
|
|||
|
||||
// otherwise lifetime pointers are not ok
|
||||
fn test20<'a>(_: &'a int) {
|
||||
assert_send::<&'a int>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<&'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
fn test21<'a>(_: &'a int) {
|
||||
assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
fn test22<'a>(_: &'a int) {
|
||||
assert_send::<&'a [int]>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<&'a [int]>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -15,7 +15,7 @@ fn test70() {
|
|||
assert_send::<*mut int>();
|
||||
}
|
||||
fn test71<'a>() {
|
||||
assert_send::<*mut &'a int>(); //~ ERROR does not fulfill the required lifetime
|
||||
assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -44,8 +44,8 @@ fn main() {
|
|||
is_send::<A>();
|
||||
//~^ ERROR overflow evaluating
|
||||
//~^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
|
||||
//~^^^ NOTE must be implemented
|
||||
//~^^^ NOTE required by `is_send`
|
||||
//~^^^^ ERROR overflow evaluating
|
||||
//~^^^^^ NOTE consider adding a `#![recursion_limit="20"]` attribute to your crate
|
||||
//~^^^^^^ NOTE must be implemented
|
||||
//~^^^^^^ NOTE required by `is_send`
|
||||
}
|
||||
|
|
|
@ -15,12 +15,12 @@ trait Foo {}
|
|||
impl<'a> Foo for &'a [u8] {}
|
||||
|
||||
fn a(v: &[u8]) -> Box<Foo + 'static> {
|
||||
let x: Box<Foo + 'static> = box v; //~ ERROR does not outlive
|
||||
let x: Box<Foo + 'static> = box v; //~ ERROR declared lifetime bound not satisfied
|
||||
x
|
||||
}
|
||||
|
||||
fn b(v: &[u8]) -> Box<Foo + 'static> {
|
||||
box v //~ ERROR does not outlive
|
||||
box v //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn c(v: &[u8]) -> Box<Foo> {
|
||||
|
@ -28,7 +28,7 @@ fn c(v: &[u8]) -> Box<Foo> {
|
|||
}
|
||||
|
||||
fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
|
||||
box v //~ ERROR does not outlive
|
||||
box v //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn e<'a:'b,'b>(v: &'a [u8]) -> Box<Foo+'b> {
|
||||
|
|
|
@ -29,15 +29,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a int) {
|
|||
// otherwise lifetime pointers are not ok
|
||||
|
||||
fn param_not_ok<'a>(x: &'a int) {
|
||||
assert_send::<&'a int>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn param_not_ok1<'a>(_: &'a int) {
|
||||
assert_send::<&'a str>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn param_not_ok2<'a>(_: &'a int) {
|
||||
assert_send::<&'a [int]>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a [int]>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
// boxes are ok
|
||||
|
@ -51,7 +51,7 @@ fn box_ok() {
|
|||
// but not if they own a bad thing
|
||||
|
||||
fn box_with_region_not_ok<'a>() {
|
||||
assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill
|
||||
assert_send::<Box<&'a int>>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
// objects with insufficient bounds no ok
|
||||
|
@ -63,7 +63,7 @@ fn object_with_random_bound_not_ok<'a>() {
|
|||
|
||||
fn object_with_send_bound_not_ok<'a>() {
|
||||
assert_send::<&'a (Dummy+Send)>();
|
||||
//~^ ERROR does not fulfill
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn proc_with_lifetime_not_ok<'a>() {
|
||||
|
@ -84,11 +84,11 @@ fn unsafe_ok1<'a>(_: &'a int) {
|
|||
}
|
||||
|
||||
fn unsafe_ok2<'a>(_: &'a int) {
|
||||
assert_send::<*const &'a int>(); //~ ERROR does not fulfill
|
||||
assert_send::<*const &'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn unsafe_ok3<'a>(_: &'a int) {
|
||||
assert_send::<*mut &'a int>(); //~ ERROR does not fulfill
|
||||
assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -29,15 +29,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a int) {
|
|||
// otherwise lifetime pointers are not ok
|
||||
|
||||
fn param_not_ok<'a>(x: &'a int) {
|
||||
assert_send::<&'a int>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn param_not_ok1<'a>(_: &'a int) {
|
||||
assert_send::<&'a str>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn param_not_ok2<'a>(_: &'a int) {
|
||||
assert_send::<&'a [int]>(); //~ ERROR does not fulfill
|
||||
assert_send::<&'a [int]>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
// boxes are ok
|
||||
|
@ -51,7 +51,7 @@ fn box_ok() {
|
|||
// but not if they own a bad thing
|
||||
|
||||
fn box_with_region_not_ok<'a>() {
|
||||
assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill
|
||||
assert_send::<Box<&'a int>>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
// unsafe pointers are ok unless they point at unsendable things
|
||||
|
@ -62,11 +62,11 @@ fn unsafe_ok1<'a>(_: &'a int) {
|
|||
}
|
||||
|
||||
fn unsafe_ok2<'a>(_: &'a int) {
|
||||
assert_send::<*const &'a int>(); //~ ERROR does not fulfill
|
||||
assert_send::<*const &'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn unsafe_ok3<'a>(_: &'a int) {
|
||||
assert_send::<*mut &'a int>(); //~ ERROR does not fulfill
|
||||
assert_send::<*mut &'a int>(); //~ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -20,7 +20,7 @@ impl Foo {
|
|||
|
||||
fn caller<'a>(x: &int) {
|
||||
Foo.some_method::<&'a int>();
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -12,7 +12,7 @@ fn is_static<T: 'static>() {}
|
|||
|
||||
fn foo<'a>() {
|
||||
is_static::<proc():'a>();
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
|
||||
is_static::<proc():'static>();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue