--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::ty;
+use syntax::ast;
+
+/** See `simplify_type */
+#[deriving(Clone, PartialEq, Eq, Hash)]
+pub enum SimplifiedType {
+ BoolSimplifiedType,
+ CharSimplifiedType,
+ IntSimplifiedType(ast::IntTy),
+ UintSimplifiedType(ast::UintTy),
+ FloatSimplifiedType(ast::FloatTy),
+ EnumSimplifiedType(ast::DefId),
+ StrSimplifiedType,
+ VecSimplifiedType,
+ PtrSimplifiedType,
+ TupleSimplifiedType(uint),
+ TraitSimplifiedType(ast::DefId),
+ StructSimplifiedType(ast::DefId),
+ UnboxedClosureSimplifiedType(ast::DefId),
+ FunctionSimplifiedType(uint),
+ ParameterSimplifiedType,
+}
+
+pub fn simplify_type(tcx: &ty::ctxt,
+ ty: ty::t,
+ can_simplify_params: bool)
+ -> Option<SimplifiedType>
+{
+ /*!
+ * Tries to simplify a type by dropping type parameters, deref'ing
+ * away any reference types, etc. The idea is to get something
+ * simple that we can use to quickly decide if two types could
+ * unify during method lookup.
+ *
+ * If `can_simplify_params` is false, then we will fail to
+ * simplify type parameters entirely. This is useful when those
+ * type parameters would be instantiated with fresh type
+ * variables, since then we can't say much about whether two types
+ * would unify. Put another way, `can_simplify_params` should be
+ * true if type parameters appear free in `ty` and `false` if they
+ * are to be considered bound.
+ */
+
+ match ty::get(ty).sty {
+ ty::ty_bool => Some(BoolSimplifiedType),
+ ty::ty_char => Some(CharSimplifiedType),
+ ty::ty_int(int_type) => Some(IntSimplifiedType(int_type)),
+ ty::ty_uint(uint_type) => Some(UintSimplifiedType(uint_type)),
+ ty::ty_float(float_type) => Some(FloatSimplifiedType(float_type)),
+ ty::ty_enum(def_id, _) => Some(EnumSimplifiedType(def_id)),
+ ty::ty_str => Some(StrSimplifiedType),
+ ty::ty_vec(..) => Some(VecSimplifiedType),
+ ty::ty_ptr(_) => Some(PtrSimplifiedType),
+ ty::ty_trait(ref trait_info) => {
+ Some(TraitSimplifiedType(trait_info.principal.def_id))
+ }
+ ty::ty_struct(def_id, _) => {
+ Some(StructSimplifiedType(def_id))
+ }
+ ty::ty_rptr(_, mt) => {
+ // since we introduce auto-refs during method lookup, we
+ // just treat &T and T as equivalent from the point of
+ // view of possibly unifying
+ simplify_type(tcx, mt.ty, can_simplify_params)
+ }
+ ty::ty_uniq(_) => {
+ // treat like we would treat `Box`
+ let def_id = tcx.lang_items.owned_box().unwrap();
+ Some(StructSimplifiedType(def_id))
+ }
+ ty::ty_unboxed_closure(def_id, _, _) => {
+ Some(UnboxedClosureSimplifiedType(def_id))
+ }
+ ty::ty_tup(ref tys) => {
+ Some(TupleSimplifiedType(tys.len()))
+ }
+ ty::ty_closure(ref f) => {
+ Some(FunctionSimplifiedType(f.sig.inputs.len()))
+ }
+ ty::ty_bare_fn(ref f) => {
+ Some(FunctionSimplifiedType(f.sig.inputs.len()))
+ }
+ ty::ty_param(_) => {
+ if can_simplify_params {
+ Some(ParameterSimplifiedType)
+ } else {
+ None
+ }
+ }
+ ty::ty_open(_) | ty::ty_infer(_) | ty::ty_err => None,
+ }
+}
+
use super::NoMatch;
use super::TraitSource;
+use middle::fast_reject;
use middle::subst;
use middle::subst::Subst;
use middle::traits;
span: Span,
method_name: ast::Name,
steps: Rc<Vec<CandidateStep>>,
+ opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
inherent_candidates: Vec<Candidate>,
extension_candidates: Vec<Candidate>,
impl_dups: HashSet<ast::DefId>,
struct CandidateStep {
self_ty: ty::t,
- adjustment: PickAdjustment
+ adjustment: PickAdjustment,
}
struct Candidate {
// take place in the `fcx.infcx().probe` below.
let steps = create_steps(fcx, span, self_ty);
+ // Create a list of simplified self types, if we can.
+ let mut simplified_steps = Vec::new();
+ for step in steps.iter() {
+ match fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) {
+ None => { break; }
+ Some(simplified_type) => { simplified_steps.push(simplified_type); }
+ }
+ }
+ let opt_simplified_steps =
+ if simplified_steps.len() < steps.len() {
+ None // failed to convert at least one of the steps
+ } else {
+ Some(simplified_steps)
+ };
+
debug!("ProbeContext: steps for self_ty={} are {}",
self_ty.repr(fcx.tcx()),
steps.repr(fcx.tcx()));
// this creates one big transaction so that all type variables etc
// that we create during the probe process are removed later
- let mut steps = Some(steps); // FIXME(#18101) need once closures
+ let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures
fcx.infcx().probe(|| {
- let steps = steps.take().unwrap();
- let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps);
+ 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();
probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id);
probe_cx.pick()
fn new(fcx: &'a FnCtxt<'a,'tcx>,
span: Span,
method_name: ast::Name,
- steps: Vec<CandidateStep>)
+ steps: Vec<CandidateStep>,
+ opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
-> ProbeContext<'a,'tcx>
{
ProbeContext {
extension_candidates: Vec::new(),
impl_dups: HashSet::new(),
steps: Rc::new(steps),
+ opt_simplified_steps: opt_simplified_steps,
static_candidates: Vec::new(),
}
}
trait_def_id.repr(self.tcx()),
impl_def_id.repr(self.tcx()));
+ if !self.impl_can_possibly_match(impl_def_id) {
+ continue;
+ }
+
let impl_pty = check::impl_self_ty(self.fcx, self.span, impl_def_id);
let impl_substs = impl_pty.substs;
}
}
+ fn impl_can_possibly_match(&self, impl_def_id: ast::DefId) -> bool {
+ let simplified_steps = match self.opt_simplified_steps {
+ Some(ref simplified_steps) => simplified_steps,
+ None => { return true; }
+ };
+
+ let impl_type = ty::lookup_item_type(self.tcx(), impl_def_id);
+ let impl_simplified_type =
+ match fast_reject::simplify_type(self.tcx(), impl_type.ty, false) {
+ Some(simplified_type) => simplified_type,
+ None => { return true; }
+ };
+
+ simplified_steps.contains(&impl_simplified_type)
+ }
+
fn assemble_unboxed_closure_candidates(&mut self,
trait_def_id: ast::DefId,
method_ty: Rc<ty::Method>,