diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index ca8eee847d3..f6fd9f60e5c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1784,9 +1784,7 @@ impl LintPass for Stability { 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() } } } diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 1a1c810b278..4cbb1babf9a 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -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>> { + -> Option>> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); decoder::get_impl_trait(&*cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 0625c50d672..7f1df80da3c 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -425,11 +425,11 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec { pub fn get_impl_trait<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) - -> Option>> + -> Option>> { 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)) }) } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 0021533a2bb..69fbd59fd92 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -887,7 +887,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { 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 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { 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 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 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 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 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: { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 46c4de5c35e..939775e7507 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { .. }) => { let trait_item = ty::trait_item(self.tcx, - trait_ref.def_id(), + trait_ref.def_id, index); match trait_item { ty::MethodTraitItem(method) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8b0df4e69cd..901944cd016 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -265,7 +265,7 @@ impl OverloadedCallType { } 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 @@ impl OverloadedCallType { } 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) } } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index d1253e0b697..b4c1c0b396b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -395,7 +395,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn values_str(&self, values: &ValuePairs<'tcx>) -> Option { 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 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { } } +impl<'tcx> Resolvable<'tcx> for Rc> { + fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) + -> Rc> { + 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> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Rc> { diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 3a84890de4f..ab0f98ec74a 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -219,7 +219,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C 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 @@ impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { * * 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 Fn 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 = + 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 +} diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 29021c0cca6..f419f050cf5 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -137,7 +137,8 @@ impl Copy for TypeOrigin {} #[deriving(Clone, Show)] pub enum ValuePairs<'tcx> { Types(ty::expected_found>), - TraitRefs(ty::expected_found>>), + TraitRefs(ty::expected_found>>), + PolyTraitRefs(ty::expected_found>>), } /// 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Execute `f` then unroll any bindings it creates pub fn probe(&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,12 +684,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } - pub fn sub_poly_trait_refs(&self, - a_is_expected: bool, - origin: TypeOrigin, - a: Rc>, - b: Rc>) - -> ures<'tcx> + pub fn sub_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Rc>, + b: Rc>) + -> ures<'tcx> { debug!("sub_trait_refs({} <: {})", a.repr(self.tcx), @@ -696,8 +697,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.commit_if_ok(|| { let trace = TypeTrace { origin: origin, - values: TraitRefs(expected_found(a_is_expected, - a.clone(), b.clone())) + 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, + a: Rc>, + b: Rc>) + -> ures<'tcx> + { + debug!("sub_poly_trait_refs({} <: {})", + a.repr(self.tcx), + b.repr(self.tcx)); + self.commit_if_ok(|| { + let trace = TypeTrace { + origin: origin, + 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + pub fn plug_leaks(&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>) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 67e9d2fee58..8cce1321d72 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -257,8 +257,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, '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 { @@ -407,7 +407,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // 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")); } } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 1923142be9e..33701905aa1 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -108,7 +108,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { 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 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { 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); - }) - } } }); } diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 3b759b042f2..9804f6d222a 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,7 +17,7 @@ use super::util; 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 { diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 32d9056f7b7..213d97b4b34 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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( diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 0bda04237b6..6c7ae666ae0 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -289,7 +289,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } 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 { @@ -410,13 +410,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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(()) => { @@ -711,8 +716,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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( @@ -819,8 +823,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { 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)); } @@ -848,15 +855,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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), @@ -919,17 +919,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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() }) } @@ -1400,10 +1406,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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, @@ -1476,23 +1493,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - let substs = self.rematch_impl(impl_def_id, obligation); - debug!("confirm_impl_candidate substs={}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, obligation.recursion_depth + 1)) + 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 } @@ -1535,10 +1573,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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) } @@ -1582,9 +1619,52 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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>, + expected_trait_ref: Rc>) + -> 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)) + } } /////////////////////////////////////////////////////////////////////////// @@ -1599,10 +1679,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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>) -> 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 } @@ -1618,11 +1702,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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>) -> Result, ()> { - 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 @@ -1638,15 +1724,42 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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 @@ -1667,19 +1780,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - fn match_trait_refs(&mut self, - obligation: &TraitObligation<'tcx>, - trait_ref: Rc>) + fn match_where_clause(&mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: Rc>) -> 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(()), @@ -1754,78 +1867,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - /////////////////////////////////////////////////////////////////////////// - // 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 for Elems` using the following impl: - /// - /// impl Iterator for Elems { ... } - /// - /// 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>, - 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 Iterator for Vec { ... } - /// - /// and our obligation is `Iterator for Vec` (note the mismatch in the obligation - /// types). Up until this step, no error would be reported: the self type is `Vec`, and - /// that matches `Vec` 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 for Vec`, and the - /// `obligation_trait_ref` would be `Iterator for Vec`. - /// - /// 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>, - expected_trait_ref: Rc>) - -> 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 @@ -1857,11 +1898,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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> { 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) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 91247d8b73e..ee56d919fef 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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>, + // 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>, // 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>, + pub trait_ref: Rc>, // 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>>>>, - pub impl_trait_cache: RefCell>>>>, + pub impl_trait_cache: RefCell>>>>, pub trait_refs: RefCell>>>, pub trait_defs: RefCell>>>, @@ -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, 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> { + pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) + -> Rc> + { 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>> { + -> Option>> { 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,26 +6435,24 @@ 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| { - 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) } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 496a0badd82..cde0470ff48 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -730,14 +730,17 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where /// 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(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 { 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 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where _ => { 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) })) } diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 2162055f287..1a4f06663ef 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -941,14 +941,14 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { 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())) } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 192b0d63421..f8303a6f030 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -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 diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index a8f7323b4ae..f1c3c9be396 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -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!") }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d6438c4062e..4f4bebabead 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,8 +53,7 @@ use middle::def; 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> 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) } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 8ac58736f54..2c220f29826 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -222,17 +222,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // 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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { .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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ConfirmContext<'a,'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={}", diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 451058e5e21..ffaeceb3eed 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -166,12 +166,13 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Construct a trait-reference `self_ty : Trait` 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 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, '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, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index fc1aa59c4de..b5776f9aeb3 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -19,7 +19,6 @@ use middle::subst; 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>, + ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), + ExtensionImplCandidate(/* Impl */ ast::DefId, Rc>, subst::Substs<'tcx>, MethodIndex), UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex), WhereClauseCandidate(Rc>, 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // 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 @@ impl<'a,'tcx> ProbeContext<'a,'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(()) => { } @@ -1033,8 +1027,8 @@ impl<'tcx> Candidate<'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 @@ impl<'tcx> Candidate<'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 @@ impl<'tcx> Candidate<'tcx> { 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 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { 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), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 18f009fe6c4..9e249cc449d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // 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 compare_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={} \ diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index a90422cd309..c09ce3db6dd 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -166,11 +166,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // 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 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { 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 diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index e79eac90508..5d0bb6622c2 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { 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 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } 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) { diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 6a24bdbb9f0..07a84846c47 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -45,7 +45,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { } 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( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 485f0ca8430..280b42f0959 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -43,8 +43,8 @@ use middle::resolve_lifetime; 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,11 +1580,11 @@ fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -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(), @@ -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)); - - // The "base type" comes from the impl. It may have late-bound - // regions from the impl or the method. - 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(required_type))); + + // 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 = + liberate_early_bound_regions( + crate_context.tcx, body_scope, + &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 + } + }) + } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 49e45c9e56c..d0988af1cb4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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 } diff --git a/src/test/compile-fail/hrtb-conflate-regions.rs b/src/test/compile-fail/hrtb-conflate-regions.rs new file mode 100644 index 00000000000..670e8710847 --- /dev/null +++ b/src/test/compile-fail/hrtb-conflate-regions.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , 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 { + fn foo(&self, x: X) { } +} + +fn want_foo2() + where T : for<'a,'b> Foo<(&'a int, &'b int)> +{ +} + +fn want_foo1() + 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::(); } // OK -- foo wants just one region +fn b() { want_foo2::(); } //~ ERROR not implemented + +fn main() { } diff --git a/src/test/compile-fail/hrtb-just-for-static.rs b/src/test/compile-fail/hrtb-just-for-static.rs new file mode 100644 index 00000000000..b21bae5653e --- /dev/null +++ b/src/test/compile-fail/hrtb-just-for-static.rs @@ -0,0 +1,37 @@ +// 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 or the MIT license +// , 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` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo { + fn foo(&self, x: X) { } +} + +fn want_hrtb() + 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::() +} + +// 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::() //~ ERROR `for<'a> Foo<&'a int>` is not implemented +} + +fn main() { } diff --git a/src/test/compile-fail/hrtb-perfect-forwarding.rs b/src/test/compile-fail/hrtb-perfect-forwarding.rs new file mode 100644 index 00000000000..a8ee2154fc3 --- /dev/null +++ b/src/test/compile-fail/hrtb-perfect-forwarding.rs @@ -0,0 +1,66 @@ +// 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 or the MIT license +// , 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` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo { + fn foo(&mut self, x: X) { } +} + +trait Bar { + fn bar(&mut self, x: X) { } +} + +impl<'a,X,F> Foo for &'a mut F + where F : Foo + Bar +{ +} + +impl<'a,X,F> Bar for &'a mut F + where F : Bar +{ +} + +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(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(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() { } diff --git a/src/test/compile-fail/hrtb-type-outlives.rs b/src/test/compile-fail/hrtb-type-outlives.rs new file mode 100644 index 00000000000..9a326aadc6a --- /dev/null +++ b/src/test/compile-fail/hrtb-type-outlives.rs @@ -0,0 +1,59 @@ +// 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 or the MIT license +// , 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 { + fn foo(&self, x: X) { } +} + +fn want_foo() + where T : for<'a> Foo<&'a int> +{ +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as a where clause + +struct SomeStruct { + x: X +} + +impl<'a,X> Foo<&'a int> for SomeStruct + 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::>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as shorthand + +struct AnotherStruct { + x: X +} + +impl<'a,X:'a> Foo<&'a int> for AnotherStruct +{ +} + +fn two() { + want_foo::>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +fn main() { } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 01a15023fba..d03885ca713 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -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` } diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 51ee38d5cfe..f5740992af4 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -21,10 +21,15 @@ impl Foo for T { fn take_param(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() { } diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index a82689b1649..b0b37d077c1 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -20,9 +20,16 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: 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() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index 920e91958ee..20a4ab85d7b 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -20,9 +20,17 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: 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() { } + diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index a7a7b1c6762..f08cff3cd68 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -21,9 +21,16 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: 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() { }