提交 f45c0ef5 编写于 作者: N Niko Matsakis

Implement "perfect forwarding" for HR impls (#19730).

上级 c2ca1a4b
......@@ -1784,9 +1784,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
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()
}
}
}
......
......@@ -262,7 +262,7 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
// 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)
......
......@@ -425,11 +425,11 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
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))
})
}
......
......@@ -887,7 +887,7 @@ fn emit_method_origin<'b>(&mut self,
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)
......@@ -901,7 +901,7 @@ fn emit_method_origin<'b>(&mut self,
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))
......@@ -1457,7 +1457,7 @@ fn read_method_origin<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
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: {
......@@ -1475,7 +1475,7 @@ fn read_method_origin<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
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: {
......
......@@ -112,7 +112,7 @@ fn lookup_and_handle_method(&mut self, id: ast::NodeId,
..
}) => {
let trait_item = ty::trait_item(self.tcx,
trait_ref.def_id(),
trait_ref.def_id,
index);
match trait_item {
ty::MethodTraitItem(method) => {
......
......@@ -265,7 +265,7 @@ fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
}
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)
......@@ -292,7 +292,7 @@ fn from_method_origin(tcx: &ty::ctxt, origin: &MethodOrigin)
}
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)
}
}
}
......
......@@ -395,7 +395,8 @@ fn report_and_explain_type_error(&self,
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)
}
}
......@@ -1647,6 +1648,16 @@ fn contains_error(&self) -> bool {
}
}
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>> {
......
......@@ -219,7 +219,7 @@ fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binde
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 =
......@@ -358,7 +358,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
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
......@@ -414,11 +414,11 @@ fn region_vars_confined_to_snapshot(&self,
*
* 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.
......@@ -522,3 +522,93 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
}
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
}
......@@ -137,7 +137,8 @@ impl Copy for TypeOrigin {}
#[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
......@@ -349,7 +350,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, '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))
......@@ -362,7 +363,7 @@ pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
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))
......@@ -634,11 +635,11 @@ pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
/// 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
}
......@@ -683,6 +684,25 @@ pub fn eq_types(&self,
})
}
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,
......@@ -690,14 +710,13 @@ pub fn sub_poly_trait_refs(&self,
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()
})
......@@ -727,6 +746,18 @@ pub fn leak_check(&self,
}
}
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>)
......
......@@ -257,8 +257,8 @@ fn visit_item(&mut self, item: &ast::Item) {
};
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 {
......@@ -407,7 +407,7 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
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 {}",
......@@ -432,7 +432,7 @@ fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
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 {}",
......@@ -811,7 +811,7 @@ fn check_method(&mut self, span: Span, origin: &MethodOrigin,
// 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"));
}
}
......
......@@ -108,7 +108,8 @@ fn visit_item(&mut self, item: &ast::Item) {
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);
......@@ -117,12 +118,6 @@ fn visit_item(&mut self, item: &ast::Item) {
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);
})
}
}
});
}
......
......@@ -17,7 +17,7 @@
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;
......@@ -38,12 +38,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
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.
......@@ -67,15 +62,15 @@ pub fn impl_is_local(tcx: &ty::ctxt,
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 {
......
......@@ -360,10 +360,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
// 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(
......
......@@ -478,8 +478,10 @@ pub enum MethodOrigin<'tcx> {
#[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,
......@@ -489,7 +491,7 @@ pub struct MethodParam<'tcx> {
#[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,
......@@ -665,7 +667,7 @@ pub struct ctxt<'tcx> {
/// 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>>>>,
......@@ -1306,7 +1308,7 @@ pub enum sty<'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
}
......@@ -1315,7 +1317,9 @@ impl<'tcx> TyTrait<'tcx> {
/// 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),
......@@ -4818,7 +4822,7 @@ pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId)
}
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);
......@@ -4828,9 +4832,8 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
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
}
......@@ -5736,7 +5739,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
// 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
......@@ -6432,8 +6435,10 @@ pub fn replace_late_bound_regions<'tcx, T, F>(
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| {
// 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 => {
......@@ -6448,10 +6453,6 @@ pub fn replace_late_bound_regions<'tcx, T, F>(
}
});
// 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)
}
......
......@@ -730,14 +730,17 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
/// 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,
......@@ -750,15 +753,21 @@ pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Regio
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 }
......@@ -780,7 +789,7 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
_ => {
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))
}
}
}
......@@ -836,7 +845,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>>(tcx: &ty::ctxt<'tcx>
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)
}))
}
......
......@@ -941,14 +941,14 @@ fn process_method_call(&mut self,
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()))
}
......
......@@ -421,12 +421,11 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
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
......
......@@ -133,14 +133,14 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
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)
......@@ -618,7 +618,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
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!")
};
......
......@@ -53,8 +53,7 @@
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;
......@@ -533,7 +532,8 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
-> 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.
}
......@@ -1200,10 +1200,9 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
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 =
......@@ -1214,19 +1213,19 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
(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)
}
}
}
......
......@@ -222,17 +222,19 @@ fn fresh_receiver_substs(&mut self,
// 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,
......@@ -257,7 +259,7 @@ fn fresh_receiver_substs(&mut self,
.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) => {
......@@ -273,16 +275,20 @@ fn fresh_receiver_substs(&mut self,
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)
}
}
}
......@@ -379,25 +385,9 @@ fn instantiate_method_sig(&mut self,
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
......@@ -427,8 +417,7 @@ fn instantiate_method_sig(&mut self,
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()));
......@@ -436,7 +425,7 @@ fn instantiate_method_sig(&mut self,
// 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={}",
......
......@@ -166,12 +166,13 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
// 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(),
......@@ -194,11 +195,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
// 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;
......@@ -221,7 +219,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
//
// 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),
......@@ -293,7 +291,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
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()));
......@@ -379,7 +377,7 @@ fn report_candidates(fcx: &FnCtxt,
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,
......
......@@ -19,7 +19,6 @@
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;
......@@ -58,8 +57,8 @@ struct Candidate<'tcx> {
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),
......@@ -149,7 +148,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// 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();
......@@ -313,12 +312,7 @@ fn assemble_inherent_candidates_from_object(&mut self,
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)
});
});
}
......@@ -502,7 +496,7 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
// 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()));
......@@ -748,7 +742,7 @@ fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool {
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(()) => { }
......@@ -1033,8 +1027,8 @@ fn to_unadjusted_pick(&self) -> Pick<'tcx> {
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)
......@@ -1059,7 +1053,7 @@ fn to_unadjusted_pick(&self) -> Pick<'tcx> {
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()),
......@@ -1075,7 +1069,9 @@ fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
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))
}
......@@ -1096,8 +1092,8 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
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),
......
......@@ -719,12 +719,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
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(),
......@@ -736,11 +731,11 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
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
......@@ -834,8 +829,7 @@ trait `{}`",
}
// 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 {
......@@ -894,37 +888,16 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
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
......@@ -1060,7 +1033,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
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,
......@@ -1099,11 +1071,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
.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()
{
......@@ -1164,12 +1132,9 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
}
}
// 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);
......@@ -1231,7 +1196,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
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>,
......@@ -1281,16 +1245,6 @@ fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'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={} \
......
......@@ -166,11 +166,9 @@ fn check_impl(&mut self,
// 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);
......@@ -181,7 +179,6 @@ fn check_impl(&mut self,
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
......
......@@ -18,8 +18,8 @@
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};
......@@ -339,7 +339,7 @@ fn add_external_impl(&self,
// 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
......@@ -459,6 +459,9 @@ fn check_implementations_of_copy(&self) {
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");
......@@ -466,20 +469,15 @@ fn check_implementations_of_copy(&self) {
}
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, &param_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, &param_env) {
......
......@@ -45,7 +45,7 @@ fn visit_item(&mut self, item: &'v ast::Item) {
}
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(
......
......@@ -43,8 +43,8 @@
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};
......@@ -226,7 +226,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ast::StructVariantKind(ref struct_def) => {
let pty = Polytype {
generics: ty_generics_for_type(
generics: ty_generics_for_type_or_impl(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
......@@ -239,7 +239,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
};
let pty = Polytype {
generics: ty_generics_for_type(
generics: ty_generics_for_type_or_impl(
ccx,
generics,
DontCreateTypeParametersForAssociatedTypes),
......@@ -1050,7 +1050,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
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);
......@@ -1482,7 +1482,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
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),
......@@ -1495,7 +1495,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
}
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);
......@@ -1513,7 +1513,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
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);
......@@ -1580,7 +1580,7 @@ fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}
}
fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
generics: &ast::Generics,
create_type_parameters_for_associated_types:
CreateTypeParametersForAssociatedTypesFlag)
......@@ -1664,24 +1664,6 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
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,
......@@ -2186,8 +2168,12 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
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,
......@@ -2209,19 +2195,21 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
// 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:
crate_context.tcx, body_scope,
&ty::liberate_late_bound_regions( // liberate method regions:
liberate_early_bound_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={}",
......@@ -2242,4 +2230,30 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
}));
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
}
})
}
}
......@@ -281,7 +281,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
// 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
}
......
// 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() { }
// 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() { }
// 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() { }
// 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() { }
......@@ -11,5 +11,4 @@
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`
}
......@@ -21,10 +21,15 @@ impl<T:Copy> Foo for T {
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() { }
......@@ -20,9 +20,16 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
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() { }
......@@ -20,9 +20,17 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
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() { }
......@@ -21,9 +21,16 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
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() { }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册