diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 07c5b319970f..a2d5af675160 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -181,6 +181,9 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. region_obligations: RefCell)>>, + + // true if trait selection in this context should emit `default impl` candiates + pub emit_defaul_impl_candidates: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -452,6 +455,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), region_obligations: RefCell::new(vec![]), + emit_defaul_impl_candidates: Cell::new(false) })) } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d436..b58a154275ca 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1296,6 +1296,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return false; } + // Using local cache if the infcx can emit `default impls` + if self.infcx.emit_defaul_impl_candidates.get() { + return false; + } + + // Otherwise, we can use the global cache. true } @@ -1714,18 +1720,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); + if self.infcx().emit_defaul_impl_candidates.get() || + !self.tcx().impl_is_default(impl_def_id) { + self.probe(|this, snapshot| { /* [1] */ + match this.match_impl(impl_def_id, obligation, snapshot) { + Ok(skol_map) => { + candidates.vec.push(ImplCandidate(impl_def_id)); - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); + } + Err(_) => { } } - Err(_) => { } - } - }); + }); + } } ); diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 33972df97fb6..0fbf9f1bd587 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -92,16 +92,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self_ty: Ty<'tcx>, mut f: F) { - let mut emit_impl = |impl_def_id: DefId| { - if !self.impl_is_default(impl_def_id) { - f(impl_def_id); - } - }; - let impls = self.trait_impls_of(def_id); for &impl_def_id in impls.blanket_impls.iter() { - emit_impl(impl_def_id); + f(impl_def_id); } // simplify_type(.., false) basically replaces type parameters and @@ -132,13 +126,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { - emit_impl(impl_def_id); + f(impl_def_id); } } } else { for v in impls.non_blanket_impls.values() { for &impl_def_id in v { - emit_impl(impl_def_id); + f(impl_def_id); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4fe2f5b574e6..a622f0b67322 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1745,6 +1745,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { + FnCtxt::set_emit_default_impl_candidates(inh, body_id); + FnCtxt { body_id, param_env, @@ -1763,6 +1765,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + fn set_emit_default_impl_candidates(inh: &'a Inherited<'a, 'gcx, 'tcx>, + body_id: ast::NodeId) { + inh.infcx.emit_defaul_impl_candidates.set( + match inh.tcx.hir.find(body_id) { + Some(Node::NodeItem(..)) => { + if inh.tcx.impl_is_default(inh.tcx.hir.local_def_id(body_id)) { + true + } else { + false + } + }, + _ => false + } + ); + } + pub fn sess(&self) -> &Session { &self.tcx.sess } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 78113bdcc0e4..3668fc46ddc2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -343,18 +343,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx.body_id, &trait_ref, ast_trait_ref.path.span); - - // not registering predicates associcated with a `default impl` - let impl_is_default = fcx.tcx.impl_is_default(item_def_id); for obligation in obligations { - let register = match obligation.predicate { - ty::Predicate::Trait(..) => !impl_is_default, - _ => true - }; - - if register { - fcx.register_predicate(obligation); - } + fcx.register_predicate(obligation); } } None => { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs new file mode 100644 index 000000000000..5f6844d0c828 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -0,0 +1,18 @@ +// Copyright 2015 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. + +#![feature(specialization)] + +trait Foo<'a, T: Eq + 'a> { } + +default impl Foo<'static, U> for () {} +//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied + +fn main(){} \ No newline at end of file