// 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. /*! See `doc.rs` for high-level documentation */ use super::{Obligation, ObligationCause}; use super::{EvaluationResult, EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; use super::{SelectionResult}; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure}; use super::{VtableImplData, VtableParamData}; use super::{util}; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::ty; use middle::ty_fold::TypeFoldable; use middle::typeck::check::regionmanip; use middle::typeck::infer; use middle::typeck::infer::{InferCtxt, TypeSkolemizer}; use std::cell::RefCell; use std::collections::hashmap::HashMap; use std::rc::Rc; use syntax::ast; use util::ppaux::Repr; pub struct SelectionContext<'cx, 'tcx:'cx> { infcx: &'cx InferCtxt<'cx, 'tcx>, param_env: &'cx ty::ParameterEnvironment, typer: &'cx Typer<'tcx>+'cx, skolemizer: TypeSkolemizer<'cx, 'tcx>, } // A stack that walks back up the stack frame. struct ObligationStack<'prev> { obligation: &'prev Obligation, skol_obligation_self_ty: ty::t, previous: Option<&'prev ObligationStack<'prev>> } pub struct SelectionCache { hashmap: RefCell>>, } #[deriving(Hash,Eq,PartialEq)] struct CacheKey { trait_def_id: ast::DefId, skol_obligation_self_ty: ty::t, } #[deriving(PartialEq,Eq)] enum MatchResult { Matched(T), AmbiguousMatch, NoMatch } /** * The selection process begins by considering all impls, where * clauses, and so forth that might resolve an obligation. Sometimes * we'll be able to say definitively that (e.g.) an impl does not * apply to the obligation: perhaps it is defined for `uint` but the * obligation is for `int`. In that case, we drop the impl out of the * list. But the other cases are considered *candidates*. * * Candidates can either be definitive or ambiguous. An ambiguous * candidate is one that might match or might not, depending on how * type variables wind up being resolved. This only occurs during inference. * * For selection to suceed, there must be exactly one non-ambiguous * candidate. Usually, it is not possible to have more than one * definitive candidate, due to the coherence rules. However, there is * one case where it could occur: if there is a blanket impl for a * trait (that is, an impl applied to all T), and a type parameter * with a where clause. In that case, we can have a candidate from the * where clause and a second candidate from the impl. This is not a * problem because coherence guarantees us that the impl which would * be used to satisfy the where clause is the same one that we see * now. To resolve this issue, therefore, we ignore impls if we find a * matching where clause. Part of the reason for this is that where * clauses can give additional information (like, the types of output * parameters) that would have to be inferred from the impl. */ #[deriving(Clone)] enum Candidate { MatchedBuiltinCandidate, AmbiguousBuiltinCandidate, MatchedParamCandidate(VtableParamData), AmbiguousParamCandidate, Impl(ImplCandidate), MatchedUnboxedClosureCandidate(/* closure */ ast::DefId), ErrorCandidate, } #[deriving(Clone)] enum ImplCandidate { MatchedImplCandidate(ast::DefId), AmbiguousImplCandidate(ast::DefId), } impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, param_env: &'cx ty::ParameterEnvironment, typer: &'cx Typer<'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { infcx: infcx, param_env: param_env, typer: typer, skolemizer: infcx.skolemizer(), } } pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> { self.infcx.tcx } /////////////////////////////////////////////////////////////////////////// // Selection // // The selection phase tries to identify *how* an obligation will // be resolved. For example, it will identify which impl or // parameter bound is to be used. The process can be inconclusive // if the self type in the obligation is not fully inferred. Selection // can result in an error in one of two ways: // // 1. If no applicable impl or parameter bound can be found. // 2. If the output type parameters in the obligation do not match // those specified by the impl/bound. For example, if the obligation // is `Vec:Iterable`, but the impl specifies // `impl Iterable for Vec`, than an error would result. pub fn select(&mut self, obligation: &Obligation) -> SelectionResult { /*! * Evaluates whether the obligation can be satisfied. Returns * an indication of whether the obligation can be satisfied * and, if so, by what means. Never affects surrounding typing * environment. */ debug!("select({})", obligation.repr(self.tcx())); let stack = self.new_stack(obligation); match try!(self.candidate_from_obligation(&stack)) { None => Ok(None), Some(candidate) => self.confirm_candidate(obligation, candidate), } } pub fn select_inherent_impl(&mut self, impl_def_id: ast::DefId, obligation_cause: ObligationCause, obligation_self_ty: ty::t) -> SelectionResult> { debug!("select_inherent_impl(impl_def_id={}, obligation_self_ty={})", impl_def_id.repr(self.tcx()), obligation_self_ty.repr(self.tcx())); match self.candidate_from_impl(impl_def_id, obligation_cause, obligation_self_ty) { Some(MatchedImplCandidate(impl_def_id)) => { let vtable_impl = try!(self.confirm_inherent_impl_candidate( impl_def_id, obligation_cause, obligation_self_ty, 0)); Ok(Some(vtable_impl)) } Some(AmbiguousImplCandidate(_)) => { Ok(None) } None => { Err(Unimplemented) } } } /////////////////////////////////////////////////////////////////////////// // EVALUATION // // Tests whether an obligation can be selected or whether an impl can be // applied to particular types. It skips the "confirmation" step and // hence completely ignores output type parameters. pub fn evaluate_obligation(&mut self, obligation: &Obligation) -> EvaluationResult { /*! * Evaluates whether the obligation `obligation` can be * satisfied (by any means). */ debug!("evaluate_obligation({})", obligation.repr(self.tcx())); let stack = self.new_stack(obligation); match self.candidate_from_obligation(&stack) { Ok(Some(c)) => c.to_evaluation_result(), Ok(None) => EvaluatedToAmbiguity, Err(_) => EvaluatedToUnmatch, } } fn evaluate_builtin_bound_recursively(&mut self, bound: ty::BuiltinBound, previous_stack: &ObligationStack, ty: ty::t) -> EvaluationResult { let obligation = util::obligation_for_builtin_bound( self.tcx(), previous_stack.obligation.cause, bound, previous_stack.obligation.recursion_depth + 1, ty); let obligation = match obligation { Ok(ob) => ob, _ => return EvaluatedToMatch }; self.evaluate_obligation_recursively(previous_stack, &obligation) } fn evaluate_obligation_recursively(&mut self, previous_stack: &ObligationStack, obligation: &Obligation) -> EvaluationResult { debug!("evaluate_obligation_recursively({})", obligation.repr(self.tcx())); // If there is any previous entry on the stack that precisely // matches this obligation, then we can assume that the // obligation is satisfied for now (still all other conditions // must be met of course). One obvious case this comes up is // marker traits like `Send`. Think of a a linked list: // // struct List { data: T, next: Option>> { // // `Box>` will be `Send` if `T` is `Send` and // `Option>>` is `Send`, and in turn // `Option>>` is `Send` if `Box>` is // `Send`. if previous_stack.iter() .filter(|e| e.obligation.trait_ref.def_id == obligation.trait_ref.def_id) .find(|e| self.match_self_types(obligation.cause, e.skol_obligation_self_ty, obligation.self_ty()) == Matched(())) .is_some() { return EvaluatedToMatch; } let stack = self.push_stack(previous_stack, obligation); match self.candidate_from_obligation(&stack) { Ok(Some(c)) => c.to_evaluation_result(), Ok(None) => EvaluatedToAmbiguity, Err(_) => EvaluatedToUnmatch, } } pub fn evaluate_impl(&mut self, impl_def_id: ast::DefId, obligation_cause: ObligationCause, obligation_self_ty: ty::t) -> EvaluationResult { /*! * Evaluates whether the impl with id `impl_def_id` could be * applied to the self type `obligation_self_ty`. This can be * used either for trait or inherent impls. */ debug!("evaluate_impl(impl_def_id={}, obligation_self_ty={})", impl_def_id.repr(self.tcx()), obligation_self_ty.repr(self.tcx())); match self.candidate_from_impl(impl_def_id, obligation_cause, obligation_self_ty) { Some(c) => c.to_evaluation_result(), None => EvaluatedToUnmatch, } } /////////////////////////////////////////////////////////////////////////// // CANDIDATE ASSEMBLY // // The selection process begins by examining all in-scope impls, // caller obligations, and so forth and assembling a list of // candidates. See `doc.rs` and the `Candidate` type for more details. fn candidate_from_obligation(&mut self, stack: &ObligationStack) -> SelectionResult { debug!("candidate_from_obligation({})", stack.repr(self.tcx())); // First, check the cache. match self.check_candidate_cache(stack.obligation, stack.skol_obligation_self_ty) { Some(c) => { debug!("check_candidate_cache(obligation={}, skol_obligation_self_ty={}, \ candidate={})", stack.obligation.trait_ref.def_id, stack.skol_obligation_self_ty.repr(self.tcx()), c.repr(self.tcx())); return c; } None => { } } // If no match, compute result and insert into cache. let result = self.pick_candidate(stack); self.insert_candidate_cache(stack.obligation, stack.skol_obligation_self_ty, result.clone()); result } fn pick_candidate(&mut self, stack: &ObligationStack) -> SelectionResult { if ty::type_is_error(stack.skol_obligation_self_ty) { return Ok(Some(ErrorCandidate)); } let mut candidates = try!(self.assemble_candidates(stack)); debug!("assembled {} candidates for {}", candidates.len(), stack.repr(self.tcx())); // Examine candidates to determine outcome. Ideally we will // have exactly one candidate that is definitively applicable. if candidates.len() == 0 { // Annoying edge case: if there are no impls, then there // is no way that this trait reference is implemented, // *unless* it contains unbound variables. In that case, // it is possible that one of those unbound variables will // be bound to a new type from some other crate which will // also contain impls. return if !self.contains_skolemized_types(stack.skol_obligation_self_ty) { debug!("0 matches, unimpl"); Err(Unimplemented) } else { debug!("0 matches, ambig"); Ok(None) } } else if candidates.len() > 1 { // Ambiguity. Possibly we should report back more // information on the potential candidates so we can give // a better error message. debug!("multiple matches, ambig"); Ok(None) } else { let candidate = candidates.pop().unwrap(); Ok(Some(candidate)) } } fn pick_candidate_cache(&self, _obligation: &Obligation, skol_obligation_self_ty: ty::t) -> &SelectionCache { if ty::type_has_self(skol_obligation_self_ty) || ty::type_has_params(skol_obligation_self_ty) { &self.param_env.selection_cache } else { &self.tcx().selection_cache } } fn check_candidate_cache(&mut self, obligation: &Obligation, skol_obligation_self_ty: ty::t) -> Option> { let cache = self.pick_candidate_cache(obligation, skol_obligation_self_ty); let cache_key = CacheKey::new(obligation.trait_ref.def_id, skol_obligation_self_ty); let hashmap = cache.hashmap.borrow(); hashmap.find(&cache_key).map(|c| (*c).clone()) } fn insert_candidate_cache(&mut self, obligation: &Obligation, skol_obligation_self_ty: ty::t, candidate: SelectionResult) { debug!("insert_candidate_cache(obligation={}, skol_obligation_self_ty={}, candidate={})", obligation.trait_ref.def_id, skol_obligation_self_ty.repr(self.tcx()), candidate.repr(self.tcx())); let cache = self.pick_candidate_cache(obligation, skol_obligation_self_ty); let cache_key = CacheKey::new(obligation.trait_ref.def_id, skol_obligation_self_ty); let mut hashmap = cache.hashmap.borrow_mut(); hashmap.insert(cache_key, candidate); } fn assemble_candidates(&mut self, stack: &ObligationStack) -> Result, SelectionError> { // Check for overflow. let ObligationStack { obligation, skol_obligation_self_ty, .. } = *stack; let recursion_limit = self.infcx.tcx.sess.recursion_limit.get(); if obligation.recursion_depth >= recursion_limit { debug!("{} --> overflow", stack.obligation.repr(self.tcx())); return Err(Overflow); } let mut candidates = Vec::new(); // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. // Where clauses have highest precedence. try!(self.assemble_candidates_from_caller_bounds( obligation, skol_obligation_self_ty, &mut candidates)); // In the special case of builtin bounds, consider the "compiler-supplied" impls. if candidates.len() == 0 { match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id) { Some(bound) => { try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); } None => { } } } // In the special case of fn traits and synthesized unboxed // closure types, consider the compiler-supplied impls. Note // that this is exclusive with the builtin bound case above. if candidates.len() == 0 { try!(self.assemble_unboxed_candidates( obligation, skol_obligation_self_ty, &mut candidates)); } // Finally, consider the actual impls found in the program. if candidates.len() == 0 { try!(self.assemble_candidates_from_impls( obligation, skol_obligation_self_ty, &mut candidates)); } Ok(candidates) } fn assemble_candidates_from_caller_bounds(&mut self, obligation: &Obligation, skol_obligation_self_ty: ty::t, candidates: &mut Vec) -> Result<(),SelectionError> { /*! * Given an obligation like ``, search the obligations * that the caller supplied to find out whether it is listed among * them. * * Never affects inference environment. */ debug!("assemble_candidates_from_caller_bounds({}, {})", obligation.repr(self.tcx()), skol_obligation_self_ty.repr(self.tcx())); for caller_obligation in self.param_env.caller_obligations.iter() { // Skip over obligations that don't apply to // `self_ty`. let caller_bound = &caller_obligation.trait_ref; let caller_self_ty = caller_bound.substs.self_ty().unwrap(); debug!("caller_obligation={}, caller_self_ty={}", caller_obligation.repr(self.tcx()), self.infcx.ty_to_string(caller_self_ty)); match self.match_self_types(obligation.cause, caller_self_ty, skol_obligation_self_ty) { AmbiguousMatch => { debug!("-> AmbiguousMatch"); candidates.push(AmbiguousParamCandidate); return Ok(()); } NoMatch => { debug!("-> NoMatch"); continue; } Matched(()) => { } } // Search through the trait (and its supertraits) to // see if it matches the def-id we are looking for. let caller_bound = (*caller_bound).clone(); for bound in util::transitive_bounds(self.tcx(), &[caller_bound]) { debug!("-> check bound={}", bound.repr(self.tcx())); if bound.def_id == obligation.trait_ref.def_id { // If so, we're done! debug!("-> MatchedParamCandidate({})", bound.repr(self.tcx())); let vtable_param = VtableParamData { bound: bound }; candidates.push(MatchedParamCandidate(vtable_param)); return Ok(()); } } } Ok(()) } fn assemble_unboxed_candidates(&mut self, obligation: &Obligation, skol_obligation_self_ty: ty::t, candidates: &mut Vec) -> Result<(),SelectionError> { /*! * Check for the artificial impl that the compiler will create * for an obligation like `X : FnMut<..>` where `X` is an * unboxed closure type. */ let closure_def_id = match ty::get(skol_obligation_self_ty).sty { ty::ty_unboxed_closure(id, _) => id, _ => { return Ok(()); } }; let tcx = self.tcx(); let fn_traits = [ (ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()), (ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()), (ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()), ]; for tuple in fn_traits.iter() { let kind = match tuple { &(kind, Some(ref fn_trait)) if *fn_trait == obligation.trait_ref.def_id => { kind } _ => continue, }; // Check to see whether the argument and return types match. let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) { Some(closure) => closure.kind, None => { self.tcx().sess.span_bug( obligation.cause.span, format!("No entry for unboxed closure: {}", closure_def_id.repr(self.tcx())).as_slice()); } }; if closure_kind != kind { continue; } candidates.push(MatchedUnboxedClosureCandidate(closure_def_id)); } Ok(()) } fn assemble_candidates_from_impls(&mut self, obligation: &Obligation, skol_obligation_self_ty: ty::t, candidates: &mut Vec) -> Result<(), SelectionError> { /*! * Search for impls that might apply to `obligation`. */ let all_impls = self.all_impls(obligation.trait_ref.def_id); for &impl_def_id in all_impls.iter() { self.infcx.probe(|| { match self.candidate_from_impl(impl_def_id, obligation.cause, skol_obligation_self_ty) { Some(c) => { candidates.push(Impl(c)); } None => { } } }); } Ok(()) } fn candidate_from_impl(&mut self, impl_def_id: ast::DefId, obligation_cause: ObligationCause, skol_obligation_self_ty: ty::t) -> Option { match self.match_impl_self_types(impl_def_id, obligation_cause, skol_obligation_self_ty) { Matched(_) => { Some(MatchedImplCandidate(impl_def_id)) } AmbiguousMatch => { Some(AmbiguousImplCandidate(impl_def_id)) } NoMatch => { None } } } /////////////////////////////////////////////////////////////////////////// // BUILTIN BOUNDS // // These cover the traits that are built-in to the language // itself. This includes `Copy` and `Sized` for sure. For the // moment, it also includes `Send` / `Sync` and a few others, but // those will hopefully change to library-defined traits in the // future. fn assemble_builtin_bound_candidates(&mut self, bound: ty::BuiltinBound, stack: &ObligationStack, candidates: &mut Vec) -> Result<(),SelectionError> { // Copy -- owned, dtor, managed, marker, &mut -- only INTERIOR? // Sized -- str, [T], Trait -- but only INTERIOR // Send -- managed data, nonsend annot, borrowed data -- REACHABILITY // Sync -- non-sync marker trait -- REACHABILITY // Ideally, we'd only have to examine the immediate fields. // But think this through carefully I guess. enum WhenOk<'a> { Always, Unknown, Never, If(ty::t), IfAll(&'a [ty::t]), IfTrue(bool) } let ok = |this: &mut SelectionContext, w: WhenOk| { let r = match w { Always => EvaluatedToMatch, Unknown => EvaluatedToAmbiguity, Never => EvaluatedToUnmatch, IfTrue(true) => EvaluatedToMatch, IfTrue(false) => EvaluatedToUnmatch, If(ty) => this.evaluate_builtin_bound_recursively(bound, stack, ty), IfAll(tys) => { let mut result = EvaluatedToMatch; for &ty in tys.iter() { match this.evaluate_builtin_bound_recursively(bound, stack, ty) { EvaluatedToMatch => { } EvaluatedToAmbiguity => { result = EvaluatedToAmbiguity; } EvaluatedToUnmatch => { result = EvaluatedToUnmatch; break; } } } result } }; match r { EvaluatedToMatch => Ok(candidates.push(MatchedBuiltinCandidate)), EvaluatedToAmbiguity => Ok(candidates.push(AmbiguousBuiltinCandidate)), EvaluatedToUnmatch => Err(Unimplemented) } }; return match ty::get(stack.skol_obligation_self_ty).sty { ty::ty_uint(_) | ty::ty_int(_) | ty::ty_infer(ty::SkolemizedIntTy(_)) | ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_float(_) | ty::ty_bare_fn(_) | ty::ty_char => { // safe for everything ok(self, Always) } ty::ty_uniq(referent_ty) => { // Box match bound { ty::BoundCopy => { ok(self, Never) } ty::BoundSized => { ok(self, Always) } ty::BoundSync | ty::BoundSend => { ok(self, If(referent_ty)) } } } ty::ty_ptr(ty::mt { ty: referent_ty, .. }) => { // *const T, *mut T match bound { ty::BoundCopy | ty::BoundSized => { ok(self, Always) } ty::BoundSync | ty::BoundSend => { ok(self, If(referent_ty)) } } } ty::ty_closure(ref c) => { match c.store { ty::UniqTraitStore => { // proc: Equivalent to `Box` match bound { ty::BoundCopy => { ok(self, Never) } ty::BoundSized => { ok(self, Always) } ty::BoundSync | ty::BoundSend => { ok(self, IfTrue(c.bounds.builtin_bounds.contains_elem(bound))) } } } ty::RegionTraitStore(_, mutbl) => { // ||: Equivalent to `&FnMut` or `&mut FnMut` or something like that. match bound { ty::BoundCopy => { ok(self, match mutbl { ast::MutMutable => Never, // &mut T is affine ast::MutImmutable => Always, // &T is copyable }) } ty::BoundSized => { ok(self, Always) } ty::BoundSync | ty::BoundSend => { ok(self, IfTrue(c.bounds.builtin_bounds.contains_elem(bound))) } } } } } ty::ty_trait(box ty::TyTrait { bounds, .. }) => { match bound { ty::BoundSized => { ok(self, Never) } ty::BoundCopy | ty::BoundSync | ty::BoundSend => { ok(self, IfTrue(bounds.builtin_bounds.contains_elem(bound))) } } } ty::ty_rptr(_, ty::mt { ty: referent_ty, mutbl: mutbl }) => { // &mut T or &T match bound { ty::BoundCopy => { ok(self, match mutbl { ast::MutMutable => Never, // &mut T is affine and hence never `Copy` ast::MutImmutable => Always, // &T is copyable }) } ty::BoundSized => { ok(self, Always) } ty::BoundSync | ty::BoundSend => { // Note: technically, a region pointer is only // sendable if it has lifetime // `'static`. However, we don't take regions // into account when doing trait matching: // instead, when we decide that `T : Send`, we // will register a separate constraint with // the region inferencer that `T : 'static` // holds as well (because the trait `Send` // requires it). This will ensure that there // is no borrowed data in `T` (or else report // an inference error). The reason we do it // this way is that we do not yet *know* what // lifetime the borrowed reference has, since // we haven't finished running inference -- in // other words, there's a kind of // chicken-and-egg problem. ok(self, If(referent_ty)) } } } ty::ty_vec(element_ty, ref len) => { // [T, ..n] and [T] match bound { ty::BoundCopy => { match *len { Some(_) => ok(self, If(element_ty)), // [T, ..n] is copy iff T is copy None => ok(self, Never), // [T] is unsized and hence affine } } ty::BoundSized => { ok(self, IfTrue(len.is_some())) } ty::BoundSync | ty::BoundSend => { ok(self, If(element_ty)) } } } ty::ty_str => { // Equivalent to [u8] match bound { ty::BoundSync | ty::BoundSend => { ok(self, Always) } ty::BoundCopy | ty::BoundSized => { ok(self, Never) } } } ty::ty_tup(ref tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet ok(self, IfAll(tys.as_slice())) } ty::ty_unboxed_closure(def_id, _) => { // FIXME -- This case is tricky. In the case of by-ref // closures particularly, we need the results of // inference to decide how to reflect the type of each // upvar (the upvar may have type `T`, but the runtime // type could be `&mut`, `&`, or just `T`). For now, // though, we'll do this unsoundly and assume that all // captures are by value. Really what we ought to do // is reserve judgement and then intertwine this // analysis with closure inference. // // FIXME -- this is wrong with respect to // skolemization. We want to skolemize the types of // the variables, but to do THAT we need the ability // to "start" the skolemization numbering from a // higher point. Perhaps this just means creating a // single skolemizer and then using it again here? assert_eq!(def_id.krate, ast::LOCAL_CRATE); match self.tcx().freevars.borrow().find(&def_id.node) { None => { // No upvars. ok(self, Always) } Some(freevars) => { let tys: Vec = freevars .iter() .map(|freevar| { let freevar_def_id = freevar.def.def_id(); let freevar_ty = self.typer.node_ty(freevar_def_id.node) .unwrap_or(ty::mk_err()); freevar_ty.fold_with(&mut self.skolemizer) }) .collect(); ok(self, IfAll(tys.as_slice())) } } } ty::ty_struct(def_id, ref substs) => { let types: Vec = ty::struct_fields(self.tcx(), def_id, substs) .iter() .map(|f| f.mt.ty) .collect(); nominal(self, bound, def_id, types, ok) } ty::ty_enum(def_id, ref substs) => { let types: Vec = ty::substd_enum_variants(self.tcx(), def_id, substs) .iter() .flat_map(|variant| variant.args.iter()) .map(|&ty| ty) .collect(); nominal(self, bound, def_id, types, ok) } ty::ty_param(_) => { // Note: A type parameter is only considered to meet a // particular bound if there is a where clause telling // us that it does, and that case is handled by // `assemble_candidates_from_caller_bounds()`. ok(self, Never) } ty::ty_infer(ty::SkolemizedTy(_)) => { // Skolemized types represent unbound type // variables. They might or might not have applicable // impls and so forth, depending on what those type // variables wind up being bound to. ok(self, Unknown) } ty::ty_open(_) | ty::ty_infer(ty::TyVar(_)) | ty::ty_infer(ty::IntVar(_)) | ty::ty_infer(ty::FloatVar(_)) | ty::ty_err => { self.tcx().sess.span_bug( stack.obligation.cause.span, format!( "asked to compute contents of unexpected type: {}", stack.skol_obligation_self_ty.repr(self.tcx())).as_slice()); } }; fn nominal(this: &mut SelectionContext, bound: ty::BuiltinBound, def_id: ast::DefId, types: Vec, ok: |&mut SelectionContext, WhenOk| -> Result<(),SelectionError>) -> Result<(),SelectionError> { // First check for markers and other nonsense. let tcx = this.tcx(); match bound { ty::BoundSend => { if Some(def_id) == tcx.lang_items.no_send_bound() || Some(def_id) == tcx.lang_items.managed_bound() { return ok(this, Never); } } ty::BoundCopy => { if Some(def_id) == tcx.lang_items.no_copy_bound() || Some(def_id) == tcx.lang_items.managed_bound() || ty::has_dtor(tcx, def_id) { return ok(this, Never); } } ty::BoundSync => { if Some(def_id) == tcx.lang_items.no_sync_bound() || Some(def_id) == tcx.lang_items.managed_bound() { return ok(this, Never); } else if Some(def_id) == tcx.lang_items.unsafe_type() { // FIXME(#13231) -- we currently consider `UnsafeCell` // to always be sync. This is allow for types like `Queue` // and `Mutex`, where `Queue : Sync` is `T : Send`. return ok(this, Always); } } ty::BoundSized => { } } ok(this, IfAll(types.as_slice())) } } /////////////////////////////////////////////////////////////////////////// // CONFIRMATION // // Confirmation unifies the output type parameters of the trait // with the values found in the obligation, possibly yielding a // type error. See `doc.rs` for more details. fn confirm_candidate(&mut self, obligation: &Obligation, candidate: Candidate) -> SelectionResult { debug!("confirm_candidate({}, {})", obligation.repr(self.tcx()), candidate.repr(self.tcx())); match candidate { AmbiguousBuiltinCandidate | AmbiguousParamCandidate | Impl(AmbiguousImplCandidate(_)) => { Ok(None) } ErrorCandidate | MatchedBuiltinCandidate => { Ok(Some(VtableBuiltin)) } MatchedParamCandidate(param) => { Ok(Some(VtableParam( try!(self.confirm_param_candidate(obligation, param))))) } Impl(MatchedImplCandidate(impl_def_id)) => { let vtable_impl = try!(self.confirm_impl_candidate(obligation, impl_def_id)); Ok(Some(VtableImpl(vtable_impl))) } MatchedUnboxedClosureCandidate(closure_def_id) => { try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id)); Ok(Some(VtableUnboxedClosure(closure_def_id))) } } } fn confirm_param_candidate(&mut self, obligation: &Obligation, param: VtableParamData) -> Result { debug!("confirm_param_candidate({},{})", obligation.repr(self.tcx()), param.repr(self.tcx())); let () = try!(self.confirm(obligation.cause, obligation.trait_ref.clone(), param.bound.clone())); Ok(param) } fn confirm_impl_candidate(&mut self, obligation: &Obligation, impl_def_id: ast::DefId) -> Result,SelectionError> { debug!("confirm_impl_candidate({},{})", obligation.repr(self.tcx()), impl_def_id.repr(self.tcx())); // For a non-inhernet impl, we begin the same way as an // inherent impl, by matching the self-type and assembling // list of nested obligations. let vtable_impl = try!(self.confirm_inherent_impl_candidate( impl_def_id, obligation.cause, obligation.trait_ref.self_ty(), obligation.recursion_depth)); // But then we must also match the output types. let () = try!(self.confirm_impl_vtable(impl_def_id, obligation.cause, obligation.trait_ref.clone(), &vtable_impl.substs)); Ok(vtable_impl) } fn confirm_inherent_impl_candidate(&mut self, impl_def_id: ast::DefId, obligation_cause: ObligationCause, obligation_self_ty: ty::t, obligation_recursion_depth: uint) -> Result, SelectionError> { let substs = match self.match_impl_self_types(impl_def_id, obligation_cause, obligation_self_ty) { Matched(substs) => substs, AmbiguousMatch | NoMatch => { self.tcx().sess.bug( format!("Impl {} was matchable against {} but now is not", impl_def_id.repr(self.tcx()), obligation_self_ty.repr(self.tcx())) .as_slice()); } }; let impl_obligations = self.impl_obligations(obligation_cause, obligation_recursion_depth, impl_def_id, &substs); let vtable_impl = VtableImplData { impl_def_id: impl_def_id, substs: substs, nested: impl_obligations }; Ok(vtable_impl) } fn confirm_unboxed_closure_candidate(&mut self, obligation: &Obligation, closure_def_id: ast::DefId) -> Result<(),SelectionError> { debug!("confirm_unboxed_closure_candidate({},{})", obligation.repr(self.tcx()), closure_def_id.repr(self.tcx())); let closure_type = match self.typer.unboxed_closures().borrow().find(&closure_def_id) { Some(closure) => closure.closure_type.clone(), None => { self.tcx().sess.span_bug( obligation.cause.span, format!("No entry for unboxed closure: {}", closure_def_id.repr(self.tcx())).as_slice()); } }; // FIXME(pcwalton): This is a bogus thing to do, but // it'll do for now until we get the new trait-bound // region skolemization working. let (_, new_signature) = regionmanip::replace_late_bound_regions_in_fn_sig( self.tcx(), &closure_type.sig, |br| self.infcx.next_region_var( infer::LateBoundRegion(obligation.cause.span, br))); let arguments_tuple = *new_signature.inputs.get(0); let trait_ref = Rc::new(ty::TraitRef { def_id: obligation.trait_ref.def_id, substs: Substs::new_trait( vec![arguments_tuple, new_signature.output], vec![], obligation.self_ty()) }); self.confirm(obligation.cause, obligation.trait_ref.clone(), trait_ref) } /////////////////////////////////////////////////////////////////////////// // Matching // // Matching is a common path used for both evaluation and // confirmation. It basically unifies types that appear in impls // and traits. This does affect the surrounding environment; // therefore, when used during evaluation, match routines must be // run inside of a `probe()` so that their side-effects are // contained. fn match_impl_self_types(&mut self, impl_def_id: ast::DefId, obligation_cause: ObligationCause, obligation_self_ty: ty::t) -> MatchResult { /*! * Determines whether the self type declared against * `impl_def_id` matches `obligation_self_ty`. If successful, * returns the substitutions used to make them match. See * `match_impl()`. For example, if `impl_def_id` is declared * as: * * impl Foo for ~T { ... } * * and `obligation_self_ty` is `int`, we'd back an `Err(_)` * result. But if `obligation_self_ty` were `~int`, we'd get * back `Ok(T=int)`. */ // Create fresh type variables for each type parameter declared // on the impl etc. let impl_substs = util::fresh_substs_for_impl(self.infcx, obligation_cause.span, impl_def_id); // Find the self type for the impl. let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty; let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs); debug!("match_impl_self_types(obligation_self_ty={}, impl_self_ty={})", obligation_self_ty.repr(self.tcx()), impl_self_ty.repr(self.tcx())); match self.match_self_types(obligation_cause, impl_self_ty, obligation_self_ty) { Matched(()) => { debug!("Matched impl_substs={}", impl_substs.repr(self.tcx())); Matched(impl_substs) } AmbiguousMatch => { debug!("AmbiguousMatch"); AmbiguousMatch } NoMatch => { debug!("NoMatch"); NoMatch } } } fn match_self_types(&mut self, cause: ObligationCause, // The self type provided by the impl/caller-obligation: provided_self_ty: ty::t, // The self type the obligation is for: required_self_ty: ty::t) -> MatchResult<()> { // FIXME(#5781) -- equating the types is stronger than // necessary. Should consider variance of trait w/r/t Self. let origin = infer::RelateSelfType(cause.span); match self.infcx.eq_types(false, origin, provided_self_ty, required_self_ty) { Ok(()) => Matched(()), Err(ty::terr_sorts(ty::expected_found{expected: t1, found: t2})) => { // This error occurs when there is an unresolved type // variable in the `required_self_ty` that was forced // to unify with a non-type-variable. That basically // means we don't know enough to say with certainty // whether there is a match or not -- it depends on // how that type variable is ultimately resolved. if ty::type_is_skolemized(t1) || ty::type_is_skolemized(t2) { AmbiguousMatch } else { NoMatch } } Err(_) => NoMatch, } } /////////////////////////////////////////////////////////////////////////// // 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. fn confirm_impl_vtable(&mut self, impl_def_id: ast::DefId, obligation_cause: ObligationCause, obligation_trait_ref: Rc, substs: &Substs) -> Result<(), SelectionError> { /*! * 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. */ 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) } fn confirm(&mut self, obligation_cause: ObligationCause, obligation_trait_ref: Rc, expected_trait_ref: Rc) -> Result<(), SelectionError> { /*! * 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. */ let origin = infer::RelateOutputImplTypes(obligation_cause.span); let obligation_trait_ref = obligation_trait_ref.clone(); match self.infcx.sub_trait_refs(false, origin, expected_trait_ref.clone(), obligation_trait_ref) { Ok(()) => Ok(()), Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, e)) } } /////////////////////////////////////////////////////////////////////////// // Miscellany fn new_stack<'o>(&mut self, obligation: &'o Obligation) -> ObligationStack<'o> { let skol_obligation_self_ty = obligation.self_ty().fold_with(&mut self.skolemizer); ObligationStack { obligation: obligation, skol_obligation_self_ty: skol_obligation_self_ty, previous: None } } fn push_stack<'o>(&self, previous_stack: &'o ObligationStack<'o>, obligation: &'o Obligation) -> ObligationStack<'o> { // No need to skolemize obligation.self_ty, because we // guarantee the self-type for all recursive obligations are // already skolemized. ObligationStack { obligation: obligation, skol_obligation_self_ty: obligation.self_ty(), previous: Some(previous_stack) } } fn all_impls(&self, trait_def_id: ast::DefId) -> Vec { /*! * Returns se tof all impls for a given trait. */ ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_def_id); match self.tcx().trait_impls.borrow().find(&trait_def_id) { None => Vec::new(), Some(impls) => impls.borrow().clone() } } fn impl_obligations(&self, cause: ObligationCause, recursion_depth: uint, impl_def_id: ast::DefId, impl_substs: &Substs) -> VecPerParamSpace { let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; util::obligations_for_generics(self.tcx(), cause, recursion_depth, &impl_generics, impl_substs) } fn contains_skolemized_types(&self, ty: ty::t) -> bool { /*! * True if the type contains skolemized variables. */ let mut found_skol = false; ty::walk_ty(ty, |t| { match ty::get(t).sty { ty::ty_infer(ty::SkolemizedTy(_)) => { found_skol = true; } _ => { } } }); found_skol } } impl Candidate { fn to_evaluation_result(&self) -> EvaluationResult { match *self { Impl(ref i) => i.to_evaluation_result(), ErrorCandidate | MatchedUnboxedClosureCandidate(..) | MatchedBuiltinCandidate | MatchedParamCandidate(..) => { EvaluatedToMatch } AmbiguousBuiltinCandidate | AmbiguousParamCandidate => { EvaluatedToAmbiguity } } } } impl ImplCandidate { fn to_evaluation_result(&self) -> EvaluationResult { match *self { MatchedImplCandidate(..) => EvaluatedToMatch, AmbiguousImplCandidate(..) => EvaluatedToAmbiguity } } } impl Repr for Candidate { fn repr(&self, tcx: &ty::ctxt) -> String { match *self { ErrorCandidate => format!("ErrorCandidate"), MatchedBuiltinCandidate => format!("MatchedBuiltinCandidate"), AmbiguousBuiltinCandidate => format!("AmbiguousBuiltinCandidate"), MatchedUnboxedClosureCandidate(c) => format!("MatchedUnboxedClosureCandidate({})", c), MatchedParamCandidate(ref r) => format!("MatchedParamCandidate({})", r.repr(tcx)), AmbiguousParamCandidate => format!("AmbiguousParamCandidate"), Impl(ref i) => i.repr(tcx) } } } impl Repr for ImplCandidate { fn repr(&self, tcx: &ty::ctxt) -> String { match *self { MatchedImplCandidate(ref d) => format!("MatchedImplCandidate({})", d.repr(tcx)), AmbiguousImplCandidate(ref d) => format!("AmbiguousImplCandidate({})", d.repr(tcx)), } } } impl SelectionCache { pub fn new() -> SelectionCache { SelectionCache { hashmap: RefCell::new(HashMap::new()) } } } impl<'o> ObligationStack<'o> { fn iter(&self) -> Option<&ObligationStack> { Some(self) } } impl<'o> Iterator<&'o ObligationStack<'o>> for Option<&'o ObligationStack<'o>> { fn next(&mut self) -> Option<&'o ObligationStack<'o>> { match *self { Some(o) => { *self = o.previous; Some(o) } None => { None } } } } impl<'o> Repr for ObligationStack<'o> { fn repr(&self, tcx: &ty::ctxt) -> String { format!("ObligationStack({}, {})", self.obligation.repr(tcx), self.skol_obligation_self_ty.repr(tcx)) } } impl CacheKey { pub fn new(trait_def_id: ast::DefId, skol_obligation_self_ty: ty::t) -> CacheKey { CacheKey { trait_def_id: trait_def_id, skol_obligation_self_ty: skol_obligation_self_ty } } }