method_num: index,
..
}) => {
- ty::trait_item(cx.tcx,
- trait_ref.def_id(),
- index).def_id()
+ ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id()
}
}
}
// if there is one.
pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
def: ast::DefId)
- -> Option<Rc<ty::PolyTraitRef<'tcx>>> {
+ -> Option<Rc<ty::TraitRef<'tcx>>> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
decoder::get_impl_trait(&*cdata, def.node, tcx)
pub fn get_impl_trait<'tcx>(cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)
- -> Option<Rc<ty::PolyTraitRef<'tcx>>>
+ -> Option<Rc<ty::TraitRef<'tcx>>>
{
let item_doc = lookup_item(id, cdata.data());
reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
- Rc::new(ty::Binder(doc_trait_ref(tp, tcx, cdata)))
+ Rc::new(doc_trait_ref(tp, tcx, cdata))
})
}
this.emit_enum_variant("MethodTypeParam", 2, 1, |this| {
this.emit_struct("MethodParam", 2, |this| {
try!(this.emit_struct_field("trait_ref", 0, |this| {
- Ok(this.emit_trait_ref(ecx, &p.trait_ref.0))
+ Ok(this.emit_trait_ref(ecx, &*p.trait_ref))
}));
try!(this.emit_struct_field("method_num", 0, |this| {
this.emit_uint(p.method_num)
this.emit_enum_variant("MethodTraitObject", 3, 1, |this| {
this.emit_struct("MethodObject", 2, |this| {
try!(this.emit_struct_field("trait_ref", 0, |this| {
- Ok(this.emit_trait_ref(ecx, &o.trait_ref.0))
+ Ok(this.emit_trait_ref(ecx, &*o.trait_ref))
}));
try!(this.emit_struct_field("object_trait_id", 0, |this| {
Ok(this.emit_def_id(o.object_trait_id))
ty::MethodParam {
trait_ref: {
this.read_struct_field("trait_ref", 0, |this| {
- Ok(this.read_poly_trait_ref(dcx))
+ Ok(this.read_trait_ref(dcx))
}).unwrap()
},
method_num: {
ty::MethodObject {
trait_ref: {
this.read_struct_field("trait_ref", 0, |this| {
- Ok(this.read_poly_trait_ref(dcx))
+ Ok(this.read_trait_ref(dcx))
}).unwrap()
},
object_trait_id: {
..
}) => {
let trait_item = ty::trait_item(self.tcx,
- trait_ref.def_id(),
+ trait_ref.def_id,
index);
match trait_item {
ty::MethodTraitItem(method) => {
}
Some(ref trait_ref) => (*trait_ref).clone(),
};
- OverloadedCallType::from_trait_id(tcx, trait_ref.def_id())
+ OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
}
fn from_unboxed_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
}
MethodTypeParam(MethodParam { ref trait_ref, .. }) |
MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
- OverloadedCallType::from_trait_id(tcx, trait_ref.def_id())
+ OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
}
}
}
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String> {
match *values {
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
- infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found)
+ infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
+ infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found)
}
}
}
}
+impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
+ fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
+ -> Rc<ty::TraitRef<'tcx>> {
+ Rc::new(infcx.resolve_type_vars_if_possible(&**self))
+ }
+ fn contains_error(&self) -> bool {
+ ty::trait_ref_contains_error(&**self)
+ }
+}
+
impl<'tcx> Resolvable<'tcx> for Rc<ty::PolyTraitRef<'tcx>> {
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
-> Rc<ty::PolyTraitRef<'tcx>> {
self.infcx().resolve_type_vars_if_possible(&result0);
debug!("glb result0 = {}", result0.repr(self.tcx()));
- // Generalize the regions appearing in fn_ty0 if possible
+ // Generalize the regions appearing in result0 if possible
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
let span = self.trace().origin.span();
let result1 =
where T : Combineable<'tcx>,
F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
{
- unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, |region, current_depth| {
+ unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {
// we should only be encountering "escaping" late-bound regions here,
// because the ones at the current level should have been replaced
// with fresh variables
*
* The reason is that when we walk through the subtyping
* algorith, we begin by replacing `'a` with a skolemized
- * variable `'0`. We then have `fn(_#0t) <: fn(&'0 int)`. This
- * can be made true by unifying `_#0t` with `&'0 int`. In the
+ * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
+ * can be made true by unifying `_#0t` with `&'1 int`. In the
* process, we create a fresh variable for the skolemized
- * region, `'$0`, and hence we have that `_#0t == &'$0
- * int`. However, because `'$0` was created during the sub
+ * region, `'$2`, and hence we have that `_#0t == &'$2
+ * int`. However, because `'$2` was created during the sub
* computation, if we're not careful we will erroneously
* assume it is one of the transient region variables
* representing a lub/glb internally. Not good.
}
Ok(())
}
+
+/// This code converts from skolemized regions back to late-bound
+/// regions. It works by replacing each region in the taint set of a
+/// skolemized region with a bound-region. The bound region will be bound
+/// by the outer-most binder in `value`; the caller must ensure that there is
+/// such a binder and it is the right place.
+///
+/// This routine is only intended to be used when the leak-check has
+/// passed; currently, it's used in the trait matching code to create
+/// a set of nested obligations frmo an impl that matches against
+/// something higher-ranked. More details can be found in
+/// `middle::traits::doc.rs`.
+///
+/// As a brief example, consider the obligation `for<'a> Fn(&'a int)
+/// -> &'a int`, and the impl:
+///
+/// impl<A,R> Fn<A,R> for SomethingOrOther
+/// where A : Clone
+/// { ... }
+///
+/// Here we will have replaced `'a` with a skolemized region
+/// `'0`. This means that our substitution will be `{A=>&'0
+/// int, R=>&'0 int}`.
+///
+/// When we apply the substitution to the bounds, we will wind up with
+/// `&'0 int : Clone` as a predicate. As a last step, we then go and
+/// replace `'0` with a late-bound region `'a`. The depth is matched
+/// to the depth of the predicate, in this case 1, so that the final
+/// predicate is `for<'a> &'a int : Clone`.
+pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
+ skol_map: SkolemizationMap,
+ snapshot: &CombinedSnapshot,
+ value: &T)
+ -> T
+ where T : TypeFoldable<'tcx> + Repr<'tcx>
+{
+ debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok());
+
+ debug!("plug_leaks(skol_map={}, value={})",
+ skol_map.repr(infcx.tcx),
+ value.repr(infcx.tcx));
+
+ // Compute a mapping from the "taint set" of each skolemized
+ // region back to the `ty::BoundRegion` that it originally
+ // represented. Because `leak_check` passed, we know that that
+ // these taint sets are mutually disjoint.
+ let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
+ skol_map
+ .into_iter()
+ .flat_map(|(skol_br, skol)| {
+ infcx.tainted_regions(snapshot, skol)
+ .into_iter()
+ .map(move |tainted_region| (tainted_region, skol_br))
+ })
+ .collect();
+
+ debug!("plug_leaks: inv_skol_map={}",
+ inv_skol_map.repr(infcx.tcx));
+
+ // Remove any instantiated type variables from `value`; those can hide
+ // references to regions from the `fold_regions` code below.
+ let value = infcx.resolve_type_vars_if_possible(value);
+
+ // Map any skolemization byproducts back to a late-bound
+ // region. Put that late-bound region at whatever the outermost
+ // binder is that we encountered in `value`. The caller is
+ // responsible for ensuring that (a) `value` contains at least one
+ // binder and (b) that binder is the one we want to use.
+ let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| {
+ match inv_skol_map.get(&r) {
+ None => r,
+ Some(br) => {
+ // It is the responsibility of the caller to ensure
+ // that each skolemized region appears within a
+ // binder. In practice, this routine is only used by
+ // trait checking, and all of the skolemized regions
+ // appear inside predicates, which always have
+ // binders, so this assert is satisfied.
+ assert!(current_depth > 1);
+
+ ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone())
+ }
+ }
+ });
+
+ debug!("plug_leaks: result={}",
+ result.repr(infcx.tcx));
+
+ result
+}
#[deriving(Clone, Show)]
pub enum ValuePairs<'tcx> {
Types(ty::expected_found<Ty<'tcx>>),
- TraitRefs(ty::expected_found<Rc<ty::PolyTraitRef<'tcx>>>),
+ TraitRefs(ty::expected_found<Rc<ty::TraitRef<'tcx>>>),
+ PolyTraitRefs(ty::expected_found<Rc<ty::PolyTraitRef<'tcx>>>),
}
/// The trace designates the path through inference that we took to
b: Ty<'tcx>)
-> ures<'tcx> {
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
- cx.probe(|| {
+ cx.probe(|_| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
a: Ty<'tcx>, b: Ty<'tcx>)
-> ures<'tcx> {
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
- cx.probe(|| {
+ cx.probe(|_| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
/// Execute `f` then unroll any bindings it creates
pub fn probe<R, F>(&self, f: F) -> R where
- F: FnOnce() -> R,
+ F: FnOnce(&CombinedSnapshot) -> R,
{
debug!("probe()");
let snapshot = self.start_snapshot();
- let r = f();
+ let r = f(&snapshot);
self.rollback_to(snapshot);
r
}
})
}
+ pub fn sub_trait_refs(&self,
+ a_is_expected: bool,
+ origin: TypeOrigin,
+ a: Rc<ty::TraitRef<'tcx>>,
+ b: Rc<ty::TraitRef<'tcx>>)
+ -> ures<'tcx>
+ {
+ debug!("sub_trait_refs({} <: {})",
+ a.repr(self.tcx),
+ b.repr(self.tcx));
+ self.commit_if_ok(|| {
+ let trace = TypeTrace {
+ origin: origin,
+ values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
+ };
+ self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures()
+ })
+ }
+
pub fn sub_poly_trait_refs(&self,
a_is_expected: bool,
origin: TypeOrigin,
b: Rc<ty::PolyTraitRef<'tcx>>)
-> ures<'tcx>
{
- debug!("sub_trait_refs({} <: {})",
+ debug!("sub_poly_trait_refs({} <: {})",
a.repr(self.tcx),
b.repr(self.tcx));
self.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
- values: TraitRefs(expected_found(a_is_expected,
- a.clone(), b.clone()))
+ values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures()
})
}
}
+ pub fn plug_leaks<T>(&self,
+ skol_map: SkolemizationMap,
+ snapshot: &CombinedSnapshot,
+ value: &T)
+ -> T
+ where T : TypeFoldable<'tcx> + Repr<'tcx>
+ {
+ /*! See `higher_ranked::leak_check` */
+
+ higher_ranked::plug_leaks(self, skol_map, snapshot, value)
+ }
+
pub fn equality_predicate(&self,
span: Span,
predicate: &ty::PolyEquatePredicate<'tcx>)
};
let tr = ty::impl_trait_ref(self.tcx, local_def(item.id));
let public_trait = tr.clone().map_or(false, |tr| {
- !is_local(tr.def_id()) ||
- self.exported_items.contains(&tr.def_id().node)
+ !is_local(tr.def_id) ||
+ self.exported_items.contains(&tr.def_id.node)
});
if public_ty || public_trait {
match ty::impl_trait_ref(self.tcx, id) {
Some(t) => {
debug!("privacy - impl of trait {}", id);
- self.def_privacy(t.def_id())
+ self.def_privacy(t.def_id)
}
None => {
debug!("privacy - found a method {}",
match ty::impl_trait_ref(self.tcx, id) {
Some(t) => {
debug!("privacy - impl of trait {}", id);
- self.def_privacy(t.def_id())
+ self.def_privacy(t.def_id)
}
None => {
debug!("privacy - found a typedef {}",
// is whether the trait itself is accessible or not.
MethodTypeParam(MethodParam { ref trait_ref, .. }) |
MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
- self.report_error(self.ensure_public(span, trait_ref.def_id(),
+ self.report_error(self.ensure_public(span, trait_ref.def_id,
None, "source trait"));
}
}
ast::ItemTy(_, ref generics) |
ast::ItemEnum(_, ref generics) |
ast::ItemStruct(_, ref generics) |
- ast::ItemTrait(_, ref generics, _, _, _) => {
+ ast::ItemTrait(_, ref generics, _, _, _) |
+ ast::ItemImpl(_, ref generics, _, _, _) => {
// These kinds of items have only early bound lifetime parameters.
let lifetimes = &generics.lifetimes;
let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
visit::walk_item(this, item);
});
}
- ast::ItemImpl(_, ref generics, _, _, _) => {
- // Impls have both early- and late-bound lifetimes.
- this.visit_early_late(subst::TypeSpace, generics, |this| {
- visit::walk_item(this, item);
- })
- }
}
});
}
use middle::subst;
use middle::subst::Subst;
use middle::ty::{mod, Ty};
-use middle::infer::{mod, InferCtxt};
+use middle::infer::InferCtxt;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::DUMMY_SP;
let impl1_substs =
util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id);
let impl1_trait_ref =
- ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()
- .subst(infcx.tcx, &impl1_substs);
- let impl1_trait_ref =
- infcx.replace_late_bound_regions_with_fresh_var(DUMMY_SP,
- infer::FnCall,
- &*impl1_trait_ref).0;
+ (*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs);
// Determine whether `impl2` can provide an implementation for those
// same types.
debug!("trait_ref={}", trait_ref.repr(tcx));
// If the trait is local to the crate, ok.
- if trait_ref.def_id().krate == ast::LOCAL_CRATE {
+ if trait_ref.def_id.krate == ast::LOCAL_CRATE {
debug!("trait {} is local to current crate",
- trait_ref.def_id().repr(tcx));
+ trait_ref.def_id.repr(tcx));
return true;
}
// Otherwise, at least one of the input types must be local to the
// crate.
- trait_ref.0.input_types().iter().any(|&t| ty_is_local(tcx, t))
+ trait_ref.input_types().iter().any(|&t| ty_is_local(tcx, t))
}
pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
// For now, we just check that there are no higher-ranked
// regions. If there are, we will call this obligation an
// error. Eventually we should be able to support some
- // cases here, I imagine (e.g., `for<'a> &'a int : 'a`).
- //
- // TODO This is overly conservative, but good enough for
- // now.
+ // cases here, I imagine (e.g., `for<'a> int : 'a`).
if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 {
errors.push(
FulfillmentError::new(
}
ty::Predicate::Equate(ref p) => {
- let result = self.infcx.probe(|| {
+ let result = self.infcx.probe(|_| {
self.infcx.equality_predicate(obligation.cause.span, p)
});
match result {
impl_def_id.repr(self.tcx()),
obligation.repr(self.tcx()));
- self.infcx.probe(|| {
- match self.match_impl(impl_def_id, obligation) {
+ self.infcx.probe(|snapshot| {
+ let (skol_obligation_trait_ref, skol_map) =
+ self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot);
+ match self.match_impl(impl_def_id, obligation, snapshot,
+ &skol_map, Rc::new(skol_obligation_trait_ref)) {
Ok(substs) => {
let vtable_impl = self.vtable_impl(impl_def_id,
substs,
obligation.cause,
- obligation.recursion_depth + 1);
+ obligation.recursion_depth + 1,
+ skol_map,
+ snapshot);
self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
}
Err(()) => {
let matching_bounds =
all_bounds.filter(
|bound| self.infcx.probe(
- || self.match_trait_refs(obligation,
- (*bound).clone())).is_ok());
+ |_| self.match_where_clause(obligation, bound.clone())).is_ok());
let param_candidates =
matching_bounds.map(
{
let all_impls = self.all_impls(obligation.trait_ref.def_id());
for &impl_def_id in all_impls.iter() {
- self.infcx.probe(|| {
- match self.match_impl(impl_def_id, obligation) {
+ self.infcx.probe(|snapshot| {
+ let (skol_obligation_trait_ref, skol_map) =
+ self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot);
+ match self.match_impl(impl_def_id, obligation, snapshot,
+ &skol_map, Rc::new(skol_obligation_trait_ref)) {
Ok(_) => {
candidates.vec.push(ImplCandidate(impl_def_id));
}
candidate: &Candidate<'tcx>)
-> EvaluationResult<'tcx>
{
- /*!
- * Further evaluate `candidate` to decide whether all type parameters match
- * and whether nested obligations are met. Returns true if `candidate` remains
- * viable after this further scrutiny.
- */
-
- debug!("winnow_candidate: depth={} candidate={}",
- stack.obligation.recursion_depth, candidate.repr(self.tcx()));
- let result = self.infcx.probe(|| {
+ debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx()));
+ let result = self.infcx.probe(|_| {
let candidate = (*candidate).clone();
match self.confirm_candidate(stack.obligation, candidate) {
Ok(selection) => self.winnow_selection(Some(stack), selection),
candidate_i.repr(self.tcx()),
candidate_j.repr(self.tcx()));
- self.infcx.probe(|| {
+ self.infcx.probe(|snapshot| {
+ let (skol_obligation_trait_ref, skol_map) =
+ self.infcx().skolemize_late_bound_regions(
+ &*stack.obligation.trait_ref, snapshot);
let impl_substs =
- self.rematch_impl(impl_def_id, stack.obligation);
+ self.rematch_impl(impl_def_id, stack.obligation, snapshot,
+ &skol_map, Rc::new(skol_obligation_trait_ref));
let impl_trait_ref =
ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
let impl_trait_ref =
impl_trait_ref.subst(self.tcx(), &impl_substs);
+ let poly_impl_trait_ref =
+ Rc::new(ty::Binder((*impl_trait_ref).clone()));
let origin =
infer::RelateOutputImplTypes(stack.obligation.cause.span);
self.infcx
- .sub_poly_trait_refs(false, origin, impl_trait_ref, vt.bound.clone())
+ .sub_poly_trait_refs(false, origin, poly_impl_trait_ref, vt.bound.clone())
.is_ok()
})
}
obligation.repr(self.tcx()),
param.repr(self.tcx()));
- let () = try!(self.confirm(obligation.cause,
- obligation.trait_ref.clone(),
- param.bound.clone()));
- Ok(param)
+ // During evaluation, we already checked that this
+ // where-clause trait-ref could be unified with the obligation
+ // trait-ref. Repeat that unification now without any
+ // transactional boundary; it should not fail.
+ match self.confirm_poly_trait_refs(obligation.cause,
+ obligation.trait_ref.clone(),
+ param.bound.clone()) {
+ Ok(()) => Ok(param),
+ Err(_) => {
+ self.tcx().sess.bug(
+ format!("Where clause `{}` was applicable to `{}` but now is not",
+ param.bound.repr(self.tcx()),
+ obligation.repr(self.tcx())).as_slice());
+ }
+ }
}
fn confirm_builtin_candidate(&mut self,
// 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))
+ self.infcx.try(|snapshot| {
+ let (skol_obligation_trait_ref, skol_map) =
+ self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot);
+ let substs = self.rematch_impl(impl_def_id, obligation,
+ snapshot, &skol_map, Rc::new(skol_obligation_trait_ref));
+ debug!("confirm_impl_candidate substs={}", substs);
+ Ok(self.vtable_impl(impl_def_id, substs, obligation.cause,
+ obligation.recursion_depth + 1, skol_map, snapshot))
+ })
}
fn vtable_impl(&mut self,
impl_def_id: ast::DefId,
substs: Substs<'tcx>,
cause: ObligationCause<'tcx>,
- recursion_depth: uint)
+ recursion_depth: uint,
+ skol_map: infer::SkolemizationMap,
+ snapshot: &infer::CombinedSnapshot)
-> VtableImplData<'tcx, PredicateObligation<'tcx>>
{
+ debug!("vtable_impl(impl_def_id={}, substs={}, recursion_depth={}, skol_map={})",
+ impl_def_id.repr(self.tcx()),
+ substs.repr(self.tcx()),
+ recursion_depth,
+ skol_map.repr(self.tcx()));
+
let impl_predicates =
self.impl_predicates(cause,
recursion_depth,
impl_def_id,
- &substs);
+ &substs,
+ skol_map,
+ snapshot);
+
+ debug!("vtable_impl: impl_def_id={} impl_predicates={}",
+ impl_def_id.repr(self.tcx()),
+ impl_predicates.repr(self.tcx()));
+
VtableImplData { impl_def_id: impl_def_id,
substs: substs,
nested: impl_predicates }
substs: substs,
}));
- let () =
- try!(self.confirm(obligation.cause,
- obligation.trait_ref.clone(),
- trait_ref));
+ try!(self.confirm_poly_trait_refs(obligation.cause,
+ obligation.trait_ref.clone(),
+ trait_ref));
Ok(self_ty)
}
closure_def_id.repr(self.tcx()),
trait_ref.repr(self.tcx()));
- self.confirm(obligation.cause,
- obligation.trait_ref.clone(),
- trait_ref)
+ self.confirm_poly_trait_refs(obligation.cause,
+ obligation.trait_ref.clone(),
+ trait_ref)
+ }
+
+ /// In the case of unboxed closure types and fn pointers,
+ /// we currently treat the input type parameters on the trait as
+ /// outputs. This means that when we have a match we have only
+ /// considered the self type, so we have to go back and make sure
+ /// to relate the argument types too. This is kind of wrong, but
+ /// since we control the full set of impls, also not that wrong,
+ /// and it DOES yield better error messages (since we don't report
+ /// errors as if there is no applicable impl, but rather report
+ /// errors are about mismatched argument types.
+ ///
+ /// Here is an example. Imagine we have an unboxed closure expression
+ /// and we desugared it so that the type of the expression is
+ /// `Closure`, and `Closure` expects an int as argument. Then it
+ /// is "as if" the compiler generated this impl:
+ ///
+ /// impl Fn(int) for Closure { ... }
+ ///
+ /// Now imagine our obligation is `Fn(uint) for Closure`. So far
+ /// we have matched the self-type `Closure`. At this point we'll
+ /// compare the `int` to `uint` and generate an error.
+ ///
+ /// Note that this checking occurs *after* the impl has selected,
+ /// because these output type parameters should not affect the
+ /// selection of the impl. Therefore, if there is a mismatch, we
+ /// report an error to the user.
+ fn confirm_poly_trait_refs(&mut self,
+ obligation_cause: ObligationCause,
+ obligation_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
+ expected_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
+ -> Result<(), SelectionError<'tcx>>
+ {
+ let origin = infer::RelateOutputImplTypes(obligation_cause.span);
+
+ let obligation_trait_ref = obligation_trait_ref.clone();
+ match self.infcx.sub_poly_trait_refs(false,
+ origin,
+ expected_trait_ref.clone(),
+ obligation_trait_ref.clone()) {
+ Ok(()) => Ok(()),
+ Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
+ }
}
///////////////////////////////////////////////////////////////////////////
fn rematch_impl(&mut self,
impl_def_id: ast::DefId,
- obligation: &TraitObligation<'tcx>)
+ obligation: &TraitObligation<'tcx>,
+ snapshot: &infer::CombinedSnapshot,
+ skol_map: &infer::SkolemizationMap,
+ skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
-> Substs<'tcx>
{
- match self.match_impl(impl_def_id, obligation) {
+ match self.match_impl(impl_def_id, obligation, snapshot,
+ skol_map, skol_obligation_trait_ref) {
Ok(substs) => {
substs
}
fn match_impl(&mut self,
impl_def_id: ast::DefId,
- obligation: &TraitObligation<'tcx>)
+ obligation: &TraitObligation<'tcx>,
+ snapshot: &infer::CombinedSnapshot,
+ skol_map: &infer::SkolemizationMap,
+ skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
-> Result<Substs<'tcx>, ()>
{
- let impl_trait_ref = ty::impl_trait_ref(self.tcx(),
- impl_def_id).unwrap();
+ let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
// Before we create the substitutions and everything, first
// consider a "quick reject". This avoids creating more types
let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
&impl_substs);
- match self.match_trait_refs(obligation, impl_trait_ref) {
- Ok(()) => Ok(impl_substs),
- Err(()) => Err(())
+ debug!("match_impl(impl_def_id={}, obligation={}, \
+ impl_trait_ref={}, skol_obligation_trait_ref={})",
+ impl_def_id.repr(self.tcx()),
+ obligation.repr(self.tcx()),
+ impl_trait_ref.repr(self.tcx()),
+ skol_obligation_trait_ref.repr(self.tcx()));
+
+ let origin = infer::RelateOutputImplTypes(obligation.cause.span);
+ match self.infcx.sub_trait_refs(false,
+ origin,
+ impl_trait_ref,
+ skol_obligation_trait_ref) {
+ Ok(()) => { }
+ Err(e) => {
+ debug!("match_impl: failed sub_trait_refs due to `{}`",
+ ty::type_err_to_str(self.tcx(), &e));
+ return Err(());
+ }
+ }
+
+ match self.infcx.leak_check(skol_map, snapshot) {
+ Ok(()) => { }
+ Err(e) => {
+ debug!("match_impl: failed leak check due to `{}`",
+ ty::type_err_to_str(self.tcx(), &e));
+ return Err(());
+ }
}
+
+ debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx()));
+ Ok(impl_substs)
}
fn fast_reject_trait_refs(&mut self,
obligation: &TraitObligation,
- impl_trait_ref: &ty::PolyTraitRef)
+ impl_trait_ref: &ty::TraitRef)
-> bool
{
// We can avoid creating type variables and doing the full
})
}
- fn match_trait_refs(&mut self,
- obligation: &TraitObligation<'tcx>,
- trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
+ fn match_where_clause(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ where_clause_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> Result<(),()>
{
- debug!("match_trait_refs: obligation={} trait_ref={}",
+ debug!("match_where_clause: obligation={} where_clause_trait_ref={}",
obligation.repr(self.tcx()),
- trait_ref.repr(self.tcx()));
+ where_clause_trait_ref.repr(self.tcx()));
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
match self.infcx.sub_poly_trait_refs(false,
origin,
- trait_ref,
+ where_clause_trait_ref,
obligation.trait_ref.clone()) {
Ok(()) => Ok(()),
Err(_) => Err(()),
}
}
- ///////////////////////////////////////////////////////////////////////////
- // Confirmation
- //
- // The final step of selection: once we know how an obligation is
- // is resolved, we confirm that selection in order to have
- // side-effects on the typing environment. This step also unifies
- // the output type parameters from the obligation with those found
- // on the impl/bound, which may yield type errors.
-
- /// Relates the output type parameters from an impl to the
- /// trait. This may lead to type errors. The confirmation step
- /// is separated from the main match procedure because these
- /// type errors do not cause us to select another impl.
- ///
- /// As an example, consider matching the obligation
- /// `Iterator<char> for Elems<int>` using the following impl:
- ///
- /// impl<T> Iterator<T> for Elems<T> { ... }
- ///
- /// The match phase will succeed with substitution `T=int`.
- /// The confirm step will then try to unify `int` and `char`
- /// and yield an error.
- fn confirm_impl_vtable(&mut self,
- impl_def_id: ast::DefId,
- obligation_cause: ObligationCause<'tcx>,
- obligation_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
- substs: &Substs<'tcx>)
- -> Result<(), SelectionError<'tcx>>
- {
- let impl_trait_ref = ty::impl_trait_ref(self.tcx(),
- impl_def_id).unwrap();
- let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
- substs);
- self.confirm(obligation_cause, obligation_trait_ref, impl_trait_ref)
- }
-
- /// After we have determined which impl applies, and with what substitutions, there is one last
- /// step. We have to go back and relate the "output" type parameters from the obligation to the
- /// types that are specified in the impl.
- ///
- /// For example, imagine we have:
- ///
- /// impl<T> Iterator<T> for Vec<T> { ... }
- ///
- /// and our obligation is `Iterator<Foo> for Vec<int>` (note the mismatch in the obligation
- /// types). Up until this step, no error would be reported: the self type is `Vec<int>`, and
- /// that matches `Vec<T>` with the substitution `T=int`. At this stage, we could then go and
- /// check that the type parameters to the `Iterator` trait match. (In terms of the parameters,
- /// the `expected_trait_ref` here would be `Iterator<int> for Vec<int>`, and the
- /// `obligation_trait_ref` would be `Iterator<Foo> for Vec<int>`.
- ///
- /// Note that this checking occurs *after* the impl has selected, because these output type
- /// parameters should not affect the selection of the impl. Therefore, if there is a mismatch,
- /// we report an error to the user.
- fn confirm(&mut self,
- obligation_cause: ObligationCause,
- obligation_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
- expected_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
- -> Result<(), SelectionError<'tcx>>
- {
- let origin = infer::RelateOutputImplTypes(obligation_cause.span);
-
- let obligation_trait_ref = obligation_trait_ref.clone();
- match self.infcx.sub_poly_trait_refs(false,
- origin,
- expected_trait_ref.clone(),
- obligation_trait_ref.clone()) {
- Ok(()) => Ok(()),
- Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
- }
- }
-
///////////////////////////////////////////////////////////////////////////
// Miscellany
cause: ObligationCause<'tcx>,
recursion_depth: uint,
impl_def_id: ast::DefId,
- impl_substs: &Substs<'tcx>)
+ impl_substs: &Substs<'tcx>,
+ skol_map: infer::SkolemizationMap,
+ snapshot: &infer::CombinedSnapshot)
-> 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);
+ let bounds = self.infcx().plug_leaks(skol_map, snapshot, &bounds);
util::predicates_for_generics(self.tcx(), cause, recursion_depth, &bounds)
}
#[deriving(Clone, Show)]
pub struct MethodParam<'tcx> {
// the precise trait reference that occurs as a bound -- this may
- // be a supertrait of what the user actually typed.
- pub trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
+ // be a supertrait of what the user actually typed. Note that it
+ // never contains bound regions; those regions should have been
+ // instantiated with fresh variables at this point.
+ pub trait_ref: Rc<ty::TraitRef<'tcx>>,
// index of uint in the list of methods for the trait
pub method_num: uint,
#[deriving(Clone, Show)]
pub struct MethodObject<'tcx> {
// the (super)trait containing the method to be invoked
- pub trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
+ pub trait_ref: Rc<ty::TraitRef<'tcx>>,
// the actual base trait id of the object
pub object_trait_id: ast::DefId,
/// A cache for the trait_items() routine
pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItem<'tcx>>>>>,
- pub impl_trait_cache: RefCell<DefIdMap<Option<Rc<ty::PolyTraitRef<'tcx>>>>>,
+ pub impl_trait_cache: RefCell<DefIdMap<Option<Rc<ty::TraitRef<'tcx>>>>>,
pub trait_refs: RefCell<NodeMap<Rc<TraitRef<'tcx>>>>,
pub trait_defs: RefCell<DefIdMap<Rc<TraitDef<'tcx>>>>,
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
pub struct TyTrait<'tcx> {
// Principal trait reference.
- pub principal: PolyTraitRef<'tcx>, // would use Rc<TraitRef>, but it runs afoul of some static rules
+ pub principal: PolyTraitRef<'tcx>,
pub bounds: ExistentialBounds
}
/// we convert the principal trait-ref into a normal trait-ref,
/// you must give *some* self-type. A common choice is `mk_err()`
/// or some skolemized type.
- pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) -> Rc<ty::PolyTraitRef<'tcx>> {
+ pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>)
+ -> Rc<ty::PolyTraitRef<'tcx>>
+ {
Rc::new(ty::Binder(ty::TraitRef {
def_id: self.principal.def_id(),
substs: self.principal.substs().with_self_ty(self_ty),
}
pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
- -> Option<Rc<PolyTraitRef<'tcx>>> {
+ -> Option<Rc<TraitRef<'tcx>>> {
memoized(&cx.impl_trait_cache, id, |id: ast::DefId| {
if id.krate == ast::LOCAL_CRATE {
debug!("(impl_trait_ref) searching for trait impl {}", id);
ast::ItemImpl(_, _, ref opt_trait, _, _) => {
match opt_trait {
&Some(ref t) => {
- let trait_ref =
- (*ty::node_id_to_trait_ref(cx, t.ref_id)).clone();
- Some(Rc::new(ty::Binder(trait_ref)))
+ let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id);
+ Some(trait_ref)
}
&None => None
}
// Record the trait->implementation mappings, if applicable.
let associated_traits = csearch::get_impl_trait(tcx, impl_def_id);
for trait_ref in associated_traits.iter() {
- record_trait_implementation(tcx, trait_ref.def_id(), impl_def_id);
+ record_trait_implementation(tcx, trait_ref.def_id, impl_def_id);
}
// For any methods that use a default implementation, add them to
debug!("replace_late_bound_regions({})", binder.repr(tcx));
let mut map = FnvHashMap::new();
- let value = {
- let mut f = ty_fold::RegionFolder::new(tcx, |region, current_depth| {
- debug!("region={}", region.repr(tcx));
- match region {
- ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
- * match map.entry(br) {
- Vacant(entry) => entry.set(mapf(br, debruijn)),
- Occupied(entry) => entry.into_mut(),
- }
- }
- _ => {
- region
+
+ // Note: fold the field `0`, not the binder, so that late-bound
+ // regions bound by `binder` are considered free.
+ let value = ty_fold::fold_regions(tcx, &binder.0, |region, current_depth| {
+ debug!("region={}", region.repr(tcx));
+ match region {
+ ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
+ * match map.entry(br) {
+ Vacant(entry) => entry.set(mapf(br, debruijn)),
+ Occupied(entry) => entry.into_mut(),
}
}
- });
+ _ => {
+ region
+ }
+ }
+ });
- // Note: fold the field `0`, not the binder, so that late-bound
- // regions bound by `binder` are considered free.
- binder.0.fold_with(&mut f)
- };
debug!("resulting map: {} value: {}", map, value.repr(tcx));
(value, map)
}
/// regions (aka "lifetimes") that are bound within a type are not
/// visited by this folder; only regions that occur free will be
/// visited by `fld_r`.
-pub struct RegionFolder<'a, 'tcx: 'a, F> where F: FnMut(ty::Region, uint) -> ty::Region {
+
+pub struct RegionFolder<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
current_depth: uint,
- fld_r: F,
+ fld_r: &'a mut (FnMut(ty::Region, uint) -> ty::Region + 'a),
}
-impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> ty::Region {
- pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: F) -> RegionFolder<'a, 'tcx, F> {
+impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
+ pub fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx>
+ where F : FnMut(ty::Region, uint) -> ty::Region
+ {
RegionFolder {
tcx: tcx,
current_depth: 1,
where T : TypeFoldable<'tcx>
{
let mut vec = Vec::new();
- {
- let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r });
- value.fold_with(&mut folder);
- }
+ fold_regions(tcx, value, |r, _| { vec.push(r); r });
vec
}
-impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where
- F: FnMut(ty::Region, uint) -> ty::Region,
+pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
+ value: &T,
+ mut f: F)
+ -> T
+ where F : FnMut(ty::Region, uint) -> ty::Region,
+ T : TypeFoldable<'tcx>,
+{
+ value.fold_with(&mut RegionFolder::new(tcx, &mut f))
+}
+
+impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
{
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx }
_ => {
debug!("RegionFolder.fold_region({}) folding free region (current_depth={})",
r.repr(self.tcx()), self.current_depth);
- (self.fld_r)(r, self.current_depth)
+ self.fld_r.call_mut((r, self.current_depth))
}
}
}
debug!("shift_regions(value={}, amount={})",
value.repr(tcx), amount);
- value.fold_with(&mut RegionFolder::new(tcx, |region, _current_depth| {
+ value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| {
shift_region(region, amount)
}))
}
ty::MethodTypeParam(ref mp) => {
// method invoked on a type parameter
let trait_item = ty::trait_item(&self.analysis.ty_cx,
- mp.trait_ref.def_id(),
+ mp.trait_ref.def_id,
mp.method_num);
(None, Some(trait_item.def_id()))
}
ty::MethodTraitObject(ref mo) => {
// method invoked on a trait instance
let trait_item = ty::trait_item(&self.analysis.ty_cx,
- mo.trait_ref.def_id(),
+ mo.trait_ref.def_id,
mo.method_num);
(None, Some(trait_item.def_id()))
}
let impl_or_trait_item = ty::impl_or_trait_item(tcx, source_id);
match impl_or_trait_item {
ty::MethodTraitItem(method) => {
- let poly_trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap();
- let trait_ref = ty::erase_late_bound_regions(tcx, &*poly_trait_ref);
+ let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap();
// Compute the first substitution
let first_subst =
- ty::make_substs_for_receiver_types(tcx, &trait_ref, &*method)
+ ty::make_substs_for_receiver_types(tcx, &*trait_ref, &*method)
.erase_regions();
// And compose them
method_num
}) => {
let trait_ref =
- Rc::new(trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs));
+ Rc::new(ty::Binder((**trait_ref).subst(bcx.tcx(), bcx.fcx.param_substs)));
let span = bcx.tcx().map.span(method_call.expr_id);
debug!("method_call={} trait_ref={}",
method_call,
trait_ref.repr(bcx.tcx()));
let origin = fulfill_obligation(bcx.ccx(),
span,
- (*trait_ref).clone());
+ trait_ref.clone());
debug!("origin = {}", origin.repr(bcx.tcx()));
trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(),
method_num, origin)
let tcx = ccx.tcx();
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
- Some(t_id) => t_id.def_id(),
+ Some(t_id) => t_id.def_id,
None => ccx.sess().bug("make_impl_vtable: don't know how to \
make a vtable for a type impl!")
};
use middle::resolve_lifetime as rl;
use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
use middle::subst::{VecPerParamSpace};
-use middle::ty::{mod, Ty};
-use middle::ty_fold;
+use middle::ty::{mod, RegionEscape, Ty};
use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope,
ShiftedRscope, BindingRscope};
use TypeAndSubsts;
-> Rc<ty::PolyTraitRef<'tcx>>
where AC: AstConv<'tcx>, RS: RegionScope
{
- let trait_ref = instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq);
+ let trait_ref =
+ instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq);
let trait_ref = (*trait_ref).clone();
Rc::new(ty::Binder(trait_ref)) // Ugh.
}
let (self_ty, mut implied_output_region) = match opt_self_info {
None => (None, None),
Some(self_info) => {
- // Shift regions in the self type by 1 to account for the binding
- // level introduced by the function itself.
- let untransformed_self_ty =
- ty_fold::shift_regions(this.tcx(), 1, &self_info.untransformed_self_ty);
+ // This type comes from an impl or trait; no late-bound
+ // regions should be present.
+ assert!(!self_info.untransformed_self_ty.has_escaping_regions());
// Figure out and record the explicit self category.
let explicit_self_category =
(None, None)
}
ty::ByValueExplicitSelfCategory => {
- (Some(untransformed_self_ty), None)
+ (Some(self_info.untransformed_self_ty), None)
}
ty::ByReferenceExplicitSelfCategory(region, mutability) => {
(Some(ty::mk_rptr(this.tcx(),
region,
ty::mt {
- ty: untransformed_self_ty,
+ ty: self_info.untransformed_self_ty,
mutbl: mutability
})),
Some(region))
}
ty::ByBoxExplicitSelfCategory => {
- (Some(ty::mk_uniq(this.tcx(), untransformed_self_ty)), None)
+ (Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)), None)
}
}
}
// argument type), but those cases have already
// been ruled out when we deemed the trait to be
// "object safe".
- let original_trait_ref =
+ let original_poly_trait_ref =
data.principal_trait_ref_with_self_ty(object_ty);
+ let upcast_poly_trait_ref =
+ this.upcast(original_poly_trait_ref.clone(), trait_def_id);
let upcast_trait_ref =
- this.upcast(original_trait_ref.clone(), trait_def_id);
- debug!("original_trait_ref={} upcast_trait_ref={} target_trait={}",
- original_trait_ref.repr(this.tcx()),
+ this.replace_late_bound_regions_with_fresh_var(&*upcast_poly_trait_ref);
+ debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}",
+ original_poly_trait_ref.repr(this.tcx()),
upcast_trait_ref.repr(this.tcx()),
trait_def_id.repr(this.tcx()));
- let substs = upcast_trait_ref.substs().clone();
+ let substs = upcast_trait_ref.substs.clone();
let origin = MethodTraitObject(MethodObject {
- trait_ref: upcast_trait_ref,
+ trait_ref: Rc::new(upcast_trait_ref),
object_trait_id: trait_def_id,
method_num: method_num,
real_index: real_index,
.subst(self.tcx(), &impl_polytype.substs);
let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(),
method_num: method_num });
- (impl_trait_ref.substs().clone(), origin)
+ (impl_trait_ref.substs.clone(), origin)
}
probe::TraitPick(trait_def_id, method_num) => {
self.infcx().next_ty_var());
let trait_ref =
- Rc::new(ty::Binder(ty::TraitRef::new(trait_def_id, substs.clone())));
+ Rc::new(ty::TraitRef::new(trait_def_id, substs.clone()));
let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
method_num: method_num });
(substs, origin)
}
- probe::WhereClausePick(ref trait_ref, method_num) => {
- let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref.clone(),
+ probe::WhereClausePick(ref poly_trait_ref, method_num) => {
+ // Where clauses can have bound regions in them. We need to instantiate
+ // those to convert from a poly-trait-ref to a trait-ref.
+ let trait_ref = self.replace_late_bound_regions_with_fresh_var(&**poly_trait_ref);
+ let substs = trait_ref.substs.clone();
+ let origin = MethodTypeParam(MethodParam { trait_ref: Rc::new(trait_ref),
method_num: method_num });
- (trait_ref.substs().clone(), origin)
+ (substs, origin)
}
}
}
all_substs: subst::Substs<'tcx>)
-> InstantiatedMethodSig<'tcx>
{
- // If this method comes from an impl (as opposed to a trait),
- // it may have late-bound regions from the impl that appear in
- // the substitutions, method signature, and
- // bounds. Instantiate those at this point. (If it comes from
- // a trait, this step has no effect, as there are no
- // late-bound regions to instantiate.)
- //
- // The binder level here corresponds to the impl.
- let (all_substs, (method_sig, method_generics)) =
- self.replace_late_bound_regions_with_fresh_var(
- &ty::Binder((all_substs,
- (pick.method_ty.fty.sig.clone(),
- pick.method_ty.generics.clone()))));
-
- debug!("late-bound lifetimes from impl instantiated, \
- all_substs={} method_sig={} method_generics={}",
- all_substs.repr(self.tcx()),
- method_sig.repr(self.tcx()),
- method_generics.repr(self.tcx()));
+ debug!("instantiate_method_sig(pick={}, all_substs={})",
+ pick.repr(self.tcx()),
+ all_substs.repr(self.tcx()));
// Instantiate the bounds on the method with the
// type/early-bound-regions substitutions performed. The only
all_substs.clone()
}
};
- let method_bounds =
- method_generics.to_bounds(self.tcx(), &method_bounds_substs);
+ let method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &method_bounds_substs);
debug!("method_bounds after subst = {}",
method_bounds.repr(self.tcx()));
// Substitute the type/early-bound-regions into the method
// signature. In addition, the method signature may bind
// late-bound regions, so instantiate those.
- let method_sig = method_sig.subst(self.tcx(), &all_substs);
+ let method_sig = pick.method_ty.fty.sig.subst(self.tcx(), &all_substs);
let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig);
debug!("late-bound lifetimes from method instantiated, method_sig={}",
// Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = subst::Substs::new_trait(input_types, Vec::new(), assoc_types, self_ty);
- let trait_ref = Rc::new(ty::Binder(ty::TraitRef::new(trait_def_id, substs)));
+ let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
// Construct an obligation
+ let poly_trait_ref = Rc::new(ty::Binder((*trait_ref).clone()));
let obligation = traits::Obligation::misc(span,
fcx.body_id,
- ty::Predicate::Trait(trait_ref.clone()));
+ poly_trait_ref.as_predicate());
// Now we want to know if this can be matched
let mut selcx = traits::SelectionContext::new(fcx.infcx(),
// Substitute the trait parameters into the method type and
// instantiate late-bound regions to get the actual method type.
- //
- // Note that as the method comes from a trait, it can only have
- // late-bound regions from the fn itself, not the impl.
let ref bare_fn_ty = method_ty.fty;
- let fn_sig = bare_fn_ty.sig.subst(tcx, trait_ref.substs());
+ let fn_sig = bare_fn_ty.sig.subst(tcx, &trait_ref.substs);
let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
infer::FnCall,
&fn_sig).0;
//
// Note that as the method comes from a trait, it should not have
// any late-bound regions appearing in its bounds.
- let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), trait_ref.substs());
+ let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), &trait_ref.substs);
assert!(!method_bounds.has_escaping_regions());
fcx.add_obligations_for_parameters(
traits::ObligationCause::misc(span, fcx.body_id),
origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(),
method_num: method_num}),
ty: fty,
- substs: trait_ref.substs().clone()
+ substs: trait_ref.substs.clone()
};
debug!("callee = {}", callee.repr(fcx.tcx()));
None => format!(""),
Some(trait_ref) => format!(" of the trait `{}`",
ty::item_path_str(fcx.tcx(),
- trait_ref.def_id())),
+ trait_ref.def_id)),
};
span_note!(fcx.sess(), method_span,
use middle::subst::Subst;
use middle::traits;
use middle::ty::{mod, Ty};
-use middle::ty::{MethodObject};
use middle::ty_fold::TypeFoldable;
use middle::infer;
use middle::infer::InferCtxt;
enum CandidateKind<'tcx> {
InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
- ObjectCandidate(MethodObject<'tcx>),
- ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::PolyTraitRef<'tcx>>,
+ ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint),
+ ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
subst::Substs<'tcx>, MethodIndex),
UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
WhereClauseCandidate(Rc<ty::PolyTraitRef<'tcx>>, MethodIndex),
// this creates one big transaction so that all type variables etc
// that we create during the probe process are removed later
let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures
- fcx.infcx().probe(|| {
+ fcx.infcx().probe(|_| {
let (steps, opt_simplified_steps) = dummy.take().unwrap();
let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps);
probe_cx.assemble_inherent_candidates();
this.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
method_ty: m,
- kind: ObjectCandidate(MethodObject {
- trait_ref: new_trait_ref,
- object_trait_id: trait_ref.def_id(),
- method_num: method_num,
- real_index: vtable_index
- })
+ kind: ObjectCandidate(new_trait_ref.def_id(), method_num, vtable_index)
});
});
}
// Determine the receiver type that the method itself expects.
let xform_self_ty =
- self.xform_self_ty(&method, impl_trait_ref.substs());
+ self.xform_self_ty(&method, &impl_trait_ref.substs);
debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx()));
self_ty.repr(self.tcx()),
probe.repr(self.tcx()));
- self.infcx().probe(|| {
+ self.infcx().probe(|_| {
// First check that the self type can be related.
match self.make_sub_ty(self_ty, probe.xform_self_ty) {
Ok(()) => { }
InherentImplCandidate(def_id, _) => {
InherentImplPick(def_id)
}
- ObjectCandidate(ref data) => {
- ObjectPick(data.trait_ref.def_id(), data.method_num, data.real_index)
+ ObjectCandidate(def_id, method_num, real_index) => {
+ ObjectPick(def_id, method_num, real_index)
}
ExtensionImplCandidate(def_id, _, _, index) => {
ExtensionImplPick(def_id, index)
fn to_source(&self) -> CandidateSource {
match self.kind {
InherentImplCandidate(def_id, _) => ImplSource(def_id),
- ObjectCandidate(ref obj) => TraitSource(obj.trait_ref.def_id()),
+ ObjectCandidate(def_id, _, _) => TraitSource(def_id),
ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id),
UnboxedClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
UnboxedClosureCandidate(trait_def_id, method_num) => {
Some((trait_def_id, method_num))
}
- ExtensionImplCandidate(_, ref trait_ref, _, method_num) |
+ ExtensionImplCandidate(_, ref trait_ref, _, method_num) => {
+ Some((trait_ref.def_id, method_num))
+ }
WhereClauseCandidate(ref trait_ref, method_num) => {
Some((trait_ref.def_id(), method_num))
}
match *self {
InherentImplCandidate(ref a, ref b) =>
format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)),
- ObjectCandidate(ref a) =>
- format!("ObjectCandidate({})", a.repr(tcx)),
+ ObjectCandidate(a, b, c) =>
+ format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c),
ExtensionImplCandidate(ref a, ref b, ref c, ref d) =>
format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx),
c.repr(tcx), d),
let param_env = ParameterEnvironment::for_item(ccx.tcx, method.id);
let fty = ty::node_id_to_type(ccx.tcx, method.id);
- debug!("fty (raw): {}", fty.repr(ccx.tcx));
-
- let body_id = method.pe_body().id;
- let fty = liberate_late_bound_regions(
- ccx.tcx, CodeExtent::from_node_id(body_id), &ty::Binder(fty));
- debug!("fty (liberated): {}", fty.repr(ccx.tcx));
+ debug!("check_method_body: fty={}", fty.repr(ccx.tcx));
check_bare_fn(ccx,
&*method.pe_fn_decl(),
fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_span: Span,
- impl_trait_ref: &ty::PolyTraitRef<'tcx>,
+ impl_trait_ref: &ty::TraitRef<'tcx>,
impl_items: &[ast::ImplItem]) {
// Locate trait methods
let tcx = ccx.tcx;
- let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id());
+ let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id);
// Check existing impl methods to see if they are both present in trait
// and compatible with trait signature
}
// Check for missing items from trait
- let provided_methods = ty::provided_trait_methods(tcx,
- impl_trait_ref.def_id());
+ let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
let mut missing_methods = Vec::new();
for trait_item in trait_items.iter() {
match *trait_item {
impl_m_span: Span,
impl_m_body_id: ast::NodeId,
trait_m: &ty::Method<'tcx>,
- impl_trait_ref: &ty::PolyTraitRef<'tcx>) {
+ impl_trait_ref: &ty::TraitRef<'tcx>) {
debug!("compare_impl_method(impl_trait_ref={})",
impl_trait_ref.repr(tcx));
- let impl_m_body_scope = CodeExtent::from_node_id(impl_m_body_id);
-
- // The impl's trait ref may bind late-bound regions from the impl.
- // Liberate them and assign them the scope of the method body.
- //
- // An example would be:
- //
- // impl<'a> Foo<&'a T> for &'a U { ... }
- //
- // Here, the region parameter `'a` is late-bound, so the
- // trait reference associated with the impl will be
- //
- // for<'a> Foo<&'a T>
- //
- // liberating will convert this into:
- //
- // Foo<&'A T>
- //
- // where `'A` is the `ReFree` version of `'a`.
- let impl_trait_ref = liberate_late_bound_regions(tcx, impl_m_body_scope, impl_trait_ref);
-
debug!("impl_trait_ref (liberated) = {}",
impl_trait_ref.repr(tcx));
let infcx = infer::new_infer_ctxt(tcx);
- let trait_to_impl_substs = impl_trait_ref.substs;
+ let trait_to_impl_substs = &impl_trait_ref.substs;
// Try to give more informative error messages about self typing
// mismatches. Note that any mismatch will also be detected
if !check_region_bounds_on_impl_method(tcx,
impl_m_span,
impl_m,
- impl_m_body_scope,
&trait_m.generics,
&impl_m.generics,
&trait_to_skol_substs,
.map(|trait_param_def| &trait_param_def.bounds);
let impl_bounds =
impl_m.generics.types.get_slice(subst::FnSpace).iter()
- .map(|impl_param_def|
- liberate_late_bound_regions(
- tcx,
- impl_m_body_scope,
- &ty::Binder(ty::Binder(impl_param_def.bounds.clone()))).0);
+ .map(|impl_param_def| &impl_param_def.bounds);
for (i, (trait_param_bounds, impl_param_bounds)) in
trait_bounds.zip(impl_bounds).enumerate()
{
}
}
- // Compute skolemized form of impl and trait method tys. Note
- // that we must liberate the late-bound regions from the impl.
+ // Compute skolemized form of impl and trait method tys.
let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs);
- let impl_fty = liberate_late_bound_regions(
- tcx, impl_m_body_scope, &ty::Binder(impl_fty));
let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
impl_m: &ty::Method<'tcx>,
- impl_m_body_scope: CodeExtent,
trait_generics: &ty::Generics<'tcx>,
impl_generics: &ty::Generics<'tcx>,
trait_to_skol_substs: &Substs<'tcx>,
let impl_bounds =
impl_param.bounds.subst(tcx, impl_to_skol_substs);
- // The bounds may reference late-bound regions from the
- // impl declaration. In that case, we want to replace
- // those with the liberated variety so as to match the
- // versions appearing in the `trait_to_skol_substs`.
- // There are two-levels of binder to be aware of: the
- // impl, and the method.
- let impl_bounds =
- ty::liberate_late_bound_regions(
- tcx, impl_m_body_scope, &ty::Binder(ty::Binder(impl_bounds))).0;
-
debug!("check_region_bounds_on_impl_method: \
trait_param={} \
impl_param={} \
// Find the impl self type as seen from the "inside" --
// that is, with all type parameters converted from bound
- // to free, and any late-bound regions on the impl
- // liberated.
+ // to free.
let self_ty = ty::node_id_to_type(fcx.tcx(), item.id);
let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
- let self_ty = liberate_late_bound_regions(fcx.tcx(), item_scope, &ty::Binder(self_ty));
bounds_checker.check_traits_in_ty(self_ty);
Some(t) => { t }
};
let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
- let trait_ref = liberate_late_bound_regions(fcx.tcx(), item_scope, &trait_ref);
// There are special rules that apply to drop.
if
use metadata::csearch::{each_impl, get_impl_trait};
use metadata::csearch;
-use middle::region;
use middle::subst::{mod, Subst};
+use middle::ty::RegionEscape;
use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type};
use middle::ty::{Ty, ty_bool, ty_char, ty_closure, ty_enum, ty_err};
// Record all the trait items.
for trait_ref in associated_traits.iter() {
- self.add_trait_impl(trait_ref.def_id(), impl_def_id);
+ self.add_trait_impl(trait_ref.def_id, impl_def_id);
}
// For any methods that use a default implementation, add them to
let trait_impls = trait_impls.borrow().clone();
for &impl_did in trait_impls.iter() {
+ debug!("check_implementations_of_copy: impl_did={}",
+ impl_did.repr(tcx));
+
if impl_did.krate != ast::LOCAL_CRATE {
debug!("check_implementations_of_copy(): impl not in this \
crate");
}
let self_type = self.get_self_type_for_implementation(impl_did);
+ debug!("check_implementations_of_copy: self_type={} (bound)",
+ self_type.repr(tcx));
+
let span = tcx.map.span(impl_did.node);
- let param_env = ParameterEnvironment::for_item(tcx,
- impl_did.node);
+ let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs);
+ assert!(!self_type.has_escaping_regions());
- // the self-type may have late-bound regions bound in the
- // impl; liberate them.
- let item_scope = region::CodeExtent::from_node_id(impl_did.node);
- let self_type =
- ty::liberate_late_bound_regions(tcx,
- item_scope,
- &ty::Binder(self_type));
-
- debug!("can_type_implement_copy(self_type={})",
+ debug!("check_implementations_of_copy: self_type={} (free)",
self_type.repr(tcx));
match ty::can_type_implement_copy(tcx, self_type, ¶m_env) {
}
Some(trait_ref) => {
- let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id());
+ let trait_def = ty::lookup_trait_def(self.tcx, trait_ref.def_id);
match (trait_def.unsafety, unsafety) {
(ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
self.tcx.sess.span_err(
use middle::subst;
use middle::subst::{Substs};
use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
-use middle::ty::{mod, Ty, Polytype};
-use middle::ty_fold::{mod, TypeFolder};
+use middle::ty::{mod, RegionEscape, Ty, Polytype};
+use middle::ty_fold::{mod, TypeFolder, TypeFoldable};
use middle::infer;
use rscope::*;
use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
ast::StructVariantKind(ref struct_def) => {
let pty = Polytype {
- generics: ty_generics_for_type(
+ generics: ty_generics_for_type_or_impl(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
};
let pty = Polytype {
- generics: ty_generics_for_type(
+ generics: ty_generics_for_type_or_impl(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
ref selfty,
ref impl_items) => {
// Create generics from the generics specified in the impl head.
- let ty_generics = ty_generics_for_impl(
+ let ty_generics = ty_generics_for_type_or_impl(
ccx,
generics,
CreateTypeParametersForAssociatedTypes);
let pty = {
let ty = ccx.to_ty(&ExplicitRscope, &**t);
Polytype {
- generics: ty_generics_for_type(
+ generics: ty_generics_for_type_or_impl(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
}
ast::ItemEnum(_, ref generics) => {
// Create a new generic polytype.
- let ty_generics = ty_generics_for_type(
+ let ty_generics = ty_generics_for_type_or_impl(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes);
tcx.sess.span_bug(it.span, "invoked ty_of_item on trait");
}
ast::ItemStruct(_, ref generics) => {
- let ty_generics = ty_generics_for_type(
+ let ty_generics = ty_generics_for_type_or_impl(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes);
}
}
-fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- generics: &ast::Generics,
- create_type_parameters_for_associated_types:
- CreateTypeParametersForAssociatedTypesFlag)
- -> ty::Generics<'tcx> {
+fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ generics: &ast::Generics,
+ create_type_parameters_for_associated_types:
+ CreateTypeParametersForAssociatedTypesFlag)
+ -> ty::Generics<'tcx> {
ty_generics(ccx,
subst::TypeSpace,
generics.lifetimes.as_slice(),
generics
}
-fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- generics: &ast::Generics,
- create_type_parameters_for_associated_types:
- CreateTypeParametersForAssociatedTypesFlag)
- -> ty::Generics<'tcx>
-{
- let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
- debug!("ty_generics_for_impl: early_lifetimes={}",
- early_lifetimes);
- ty_generics(ccx,
- subst::TypeSpace,
- early_lifetimes.as_slice(),
- generics.ty_params.as_slice(),
- ty::Generics::empty(),
- &generics.where_clause,
- create_type_parameters_for_associated_types)
-}
-
fn ty_generics_for_fn_or_method<'tcx,AC>(
this: &AC,
generics: &ast::Generics,
subst::Substs::new(types, regions)
}
-/// Verifies that the explicit self type of a method matches the impl or
-/// trait.
+/// Verifies that the explicit self type of a method matches the impl
+/// or trait. This is a bit weird but basically because right now we
+/// don't handle the general case, but instead map it to one of
+/// several pre-defined options using various heuristics, this method
+/// comes back to check after the fact that explicit type the user
+/// wrote actually matches what the pre-defined option said.
fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
crate_context: &CrateCtxt<'a, 'tcx>,
rs: &RS,
// contain late-bound regions from the method, but not the
// trait (since traits only have early-bound region
// parameters).
- assert!(!ty::type_escapes_depth(required_type, 1));
+ assert!(!base_type.has_regions_escaping_depth(1));
let required_type_free =
- ty::liberate_late_bound_regions(
- crate_context.tcx, body_scope, &ty::Binder(required_type));
+ liberate_early_bound_regions(
+ crate_context.tcx, body_scope,
+ &ty::liberate_late_bound_regions(
+ crate_context.tcx, body_scope, &ty::Binder(required_type)));
- // The "base type" comes from the impl. It may have late-bound
- // regions from the impl or the method.
+ // The "base type" comes from the impl. It too may have late-bound
+ // regions from the method.
+ assert!(!base_type.has_regions_escaping_depth(1));
let base_type_free =
- ty::liberate_late_bound_regions( // liberate impl regions:
+ liberate_early_bound_regions(
crate_context.tcx, body_scope,
- &ty::liberate_late_bound_regions( // liberate method regions:
- crate_context.tcx, body_scope,
- &ty::Binder(ty::Binder(base_type))));
+ &ty::liberate_late_bound_regions(
+ crate_context.tcx, body_scope, &ty::Binder(base_type)));
debug!("required_type={} required_type_free={} \
base_type={} base_type_free={}",
}));
infcx.resolve_regions_and_report_errors(body_id);
}
+
+ fn liberate_early_bound_regions<'tcx,T>(
+ tcx: &ty::ctxt<'tcx>,
+ scope: region::CodeExtent,
+ value: &T)
+ -> T
+ where T : TypeFoldable<'tcx> + Repr<'tcx>
+ {
+ /*!
+ * Convert early-bound regions into free regions; normally this is done by
+ * applying the `free_substs` from the `ParameterEnvironment`, but this particular
+ * method-self-type check is kind of hacky and done very early in the process,
+ * before we really have a `ParameterEnvironment` to check.
+ */
+
+ ty_fold::fold_regions(tcx, value, |region, _| {
+ match region {
+ ty::ReEarlyBound(id, _, _, name) => {
+ let def_id = local_def(id);
+ ty::ReFree(ty::FreeRegion { scope: scope,
+ bound_region: ty::BrNamed(def_id, name) })
+ }
+ _ => region
+ }
+ })
+ }
}
// If this is an impl for a #[doc(hidden)] trait, be sure to not inline it.
match associated_trait {
Some(ref t) => {
- let trait_attrs = load_attrs(cx, tcx, t.def_id());
+ let trait_attrs = load_attrs(cx, tcx, t.def_id);
if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
return None
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test what an impl with only one bound region `'a` cannot be used to
+// satisfy a constraint whre there are two bound regions.
+
+trait Foo<X> {
+ fn foo(&self, x: X) { }
+}
+
+fn want_foo2<T>()
+ where T : for<'a,'b> Foo<(&'a int, &'b int)>
+{
+}
+
+fn want_foo1<T>()
+ where T : for<'z> Foo<(&'z int, &'z int)>
+{
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Expressed as a where clause
+
+struct SomeStruct;
+
+impl<'a> Foo<(&'a int, &'a int)> for SomeStruct
+{
+}
+
+fn a() { want_foo1::<SomeStruct>(); } // OK -- foo wants just one region
+fn b() { want_foo2::<SomeStruct>(); } //~ ERROR not implemented
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test a case where you have an impl of `Foo<X>` for all `X` that
+// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
+
+trait Foo<X> {
+ fn foo(&self, x: X) { }
+}
+
+fn want_hrtb<T>()
+ where T : for<'a> Foo<&'a int>
+{
+}
+
+// AnyInt implements Foo<&'a int> for any 'a, so it is a match.
+struct AnyInt;
+impl<'a> Foo<&'a int> for AnyInt { }
+fn give_any() {
+ want_hrtb::<AnyInt>()
+}
+
+// StaticInt only implements Foo<&'a int> for 'a, so it is an error.
+struct StaticInt;
+impl Foo<&'static int> for StaticInt { }
+fn give_static() {
+ want_hrtb::<StaticInt>() //~ ERROR `for<'a> Foo<&'a int>` is not implemented
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test a case where you have an impl of `Foo<X>` for all `X` that
+// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
+
+trait Foo<X> {
+ fn foo(&mut self, x: X) { }
+}
+
+trait Bar<X> {
+ fn bar(&mut self, x: X) { }
+}
+
+impl<'a,X,F> Foo<X> for &'a mut F
+ where F : Foo<X> + Bar<X>
+{
+}
+
+impl<'a,X,F> Bar<X> for &'a mut F
+ where F : Bar<X>
+{
+}
+
+fn no_hrtb<'b,T>(mut t: T)
+ where T : Bar<&'b int>
+{
+ // OK -- `T : Bar<&'b int>`, and thus the impl above ensures that
+ // `&mut T : Bar<&'b int>`.
+ no_hrtb(&mut t);
+}
+
+fn bar_hrtb<T>(mut t: T)
+ where T : for<'b> Bar<&'b int>
+{
+ // OK -- `T : for<'b> Bar<&'b int>`, and thus the impl above
+ // ensures that `&mut T : for<'b> Bar<&'b int>`. This is an
+ // example of a "perfect forwarding" impl.
+ bar_hrtb(&mut t);
+}
+
+fn foo_hrtb_bar_not<'b,T>(mut t: T)
+ where T : for<'a> Foo<&'a int> + Bar<&'b int>
+{
+ // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
+ // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a
+ // int>`, we require `T : for<'a> Bar<&'a int>`, but the where
+ // clause only specifies `T : Bar<&'b int>`.
+ foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> Bar<&'a int>` is not implemented for the type `T`
+}
+
+fn foo_hrtb_bar_hrtb<T>(mut t: T)
+ where T : for<'a> Foo<&'a int> + for<'b> Bar<&'b int>
+{
+ // OK -- now we have `T : for<'b> Bar&'b int>`.
+ foo_hrtb_bar_hrtb(&mut t);
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test what happens when a HR obligation is applie to an impl with
+// "outlives" bounds. Currently we're pretty conservative here; this
+// will probably improve in time.
+
+trait Foo<X> {
+ fn foo(&self, x: X) { }
+}
+
+fn want_foo<T>()
+ where T : for<'a> Foo<&'a int>
+{
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Expressed as a where clause
+
+struct SomeStruct<X> {
+ x: X
+}
+
+impl<'a,X> Foo<&'a int> for SomeStruct<X>
+ where X : 'a
+{
+}
+
+fn one() {
+ // In fact there is no good reason for this to be an error, but
+ // whatever, I'm mostly concerned it doesn't ICE right now:
+ want_foo::<SomeStruct<uint>>();
+ //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Expressed as shorthand
+
+struct AnotherStruct<X> {
+ x: X
+}
+
+impl<'a,X:'a> Foo<&'a int> for AnotherStruct<X>
+{
+}
+
+fn two() {
+ want_foo::<AnotherStruct<uint>>();
+ //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied
+}
+
+fn main() { }
fn main() {
let _x = "test" as &::std::any::Any;
//~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str`
-//~^^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str`
}
fn take_param<T:Foo>(foo: &T) { }
-fn main() {
+fn a() {
let x = box 3i;
take_param(&x); //~ ERROR `core::kinds::Copy` is not implemented
+}
+fn b() {
+ let x = box 3i;
let y = &x;
let z = &x as &Foo; //~ ERROR `core::kinds::Copy` is not implemented
}
+
+fn main() { }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
-fn main() {
+fn a() {
let x = call_it(&square, 22); //~ ERROR not implemented
+}
+
+fn b() {
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
+}
+
+fn c() {
let z = call_it_once(square, 22); //~ ERROR not implemented
}
+fn main() { }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
-fn main() {
+fn a() {
let x = call_it(&square, 22); //~ ERROR not implemented
+}
+
+fn b() {
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
+}
+
+fn c() {
let z = call_it_once(square, 22); //~ ERROR not implemented
}
+fn main() { }
+
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
-fn main() {
+fn a() {
let x = call_it(&square, 22); //~ ERROR not implemented
+}
+
+fn b() {
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
+}
+
+fn c() {
let z = call_it_once(square, 22); //~ ERROR not implemented
}
+fn main() { }