2014-09-12 10:53:35 -04:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
/*! 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};
|
2014-09-11 17:07:49 +12:00
|
|
|
use super::{VtableImplData, VtableParamData};
|
2014-09-12 10:53:35 -04:00
|
|
|
use super::{util};
|
|
|
|
|
|
|
|
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
|
|
|
use middle::ty;
|
|
|
|
use middle::typeck::check::regionmanip;
|
|
|
|
use middle::typeck::infer;
|
|
|
|
use middle::typeck::infer::InferCtxt;
|
|
|
|
use std::rc::Rc;
|
|
|
|
use syntax::ast;
|
|
|
|
use util::nodemap::DefIdMap;
|
|
|
|
use util::ppaux::Repr;
|
|
|
|
|
|
|
|
pub struct SelectionContext<'cx, 'tcx:'cx> {
|
|
|
|
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
|
|
|
param_env: &'cx ty::ParameterEnvironment,
|
|
|
|
unboxed_closures: &'cx DefIdMap<ty::UnboxedClosure>,
|
|
|
|
}
|
|
|
|
|
|
|
|
// pub struct SelectionCache {
|
|
|
|
// hashmap: RefCell<HashMap<CacheKey, Candidate>>,
|
|
|
|
// }
|
|
|
|
|
|
|
|
// #[deriving(Hash,Eq,PartialEq)]
|
|
|
|
// struct CacheKey {
|
|
|
|
// trait_def_id: ast::DefId,
|
|
|
|
// skol_obligation_self_ty: ty::t,
|
|
|
|
// }
|
|
|
|
|
|
|
|
enum MatchResult<T> {
|
|
|
|
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,
|
2014-09-11 17:07:49 +12:00
|
|
|
MatchedParamCandidate(VtableParamData),
|
2014-09-12 10:53:35 -04:00
|
|
|
AmbiguousParamCandidate,
|
|
|
|
Impl(ImplCandidate),
|
|
|
|
MatchedUnboxedClosureCandidate(/* closure */ ast::DefId)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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,
|
|
|
|
unboxed_closures: &'cx DefIdMap<ty::UnboxedClosure>)
|
|
|
|
-> SelectionContext<'cx, 'tcx> {
|
|
|
|
SelectionContext { infcx: infcx, param_env: param_env,
|
|
|
|
unboxed_closures: unboxed_closures }
|
|
|
|
}
|
|
|
|
|
|
|
|
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<Foo>:Iterable<Bar>`, but the impl specifies
|
|
|
|
// `impl<T> Iterable<T> for Vec<T>`, than an error would result.
|
|
|
|
|
|
|
|
pub fn select(&self, obligation: &Obligation) -> SelectionResult<Selection> {
|
|
|
|
/*!
|
|
|
|
* 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()));
|
|
|
|
|
|
|
|
match try!(self.candidate_from_obligation(obligation)) {
|
|
|
|
None => Ok(None),
|
|
|
|
Some(candidate) => self.confirm_candidate(obligation, candidate),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn select_inherent_impl(&self,
|
|
|
|
impl_def_id: ast::DefId,
|
|
|
|
obligation_cause: ObligationCause,
|
|
|
|
obligation_self_ty: ty::t)
|
2014-09-11 17:07:49 +12:00
|
|
|
-> SelectionResult<VtableImplData<Obligation>>
|
2014-09-12 10:53:35 -04:00
|
|
|
{
|
|
|
|
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(&self,
|
|
|
|
obligation: &Obligation)
|
|
|
|
-> EvaluationResult
|
|
|
|
{
|
|
|
|
/*!
|
|
|
|
* Evaluates whether the obligation `obligation` can be
|
|
|
|
* satisfied (by any means).
|
|
|
|
*/
|
|
|
|
|
|
|
|
debug!("evaluate_obligation({})",
|
|
|
|
obligation.repr(self.tcx()));
|
|
|
|
|
|
|
|
match self.candidate_from_obligation(obligation) {
|
|
|
|
Ok(Some(c)) => c.to_evaluation_result(),
|
|
|
|
Ok(None) => EvaluatedToAmbiguity,
|
|
|
|
Err(_) => EvaluatedToUnmatch,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn evaluate_impl(&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(&self, obligation: &Obligation)
|
|
|
|
-> SelectionResult<Candidate>
|
|
|
|
{
|
|
|
|
debug!("candidate_from_obligation({}, self_ty={})",
|
|
|
|
obligation.repr(self.tcx()),
|
|
|
|
self.infcx.ty_to_string(obligation.self_ty()));
|
|
|
|
|
|
|
|
let skol_obligation_self_ty =
|
|
|
|
infer::skolemize(self.infcx, obligation.self_ty());
|
|
|
|
|
|
|
|
// First, check the cache.
|
|
|
|
match self.check_candidate_cache(obligation, skol_obligation_self_ty) {
|
|
|
|
Some(c) => {
|
|
|
|
return Ok(Some(c));
|
|
|
|
}
|
|
|
|
None => { }
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut candidates =
|
|
|
|
try!(self.assemble_candidates(obligation,
|
|
|
|
skol_obligation_self_ty));
|
|
|
|
|
|
|
|
debug!("candidate_from_obligation: {} candidates for {}",
|
|
|
|
candidates.len(), obligation.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.
|
|
|
|
let trait_ref = &*obligation.trait_ref;
|
|
|
|
return if !self.trait_ref_unconstrained(trait_ref) {
|
|
|
|
debug!("candidate_from_obligation({}) -> 0 matches, unimpl",
|
|
|
|
obligation.repr(self.tcx()));
|
|
|
|
Err(Unimplemented)
|
|
|
|
} else {
|
|
|
|
debug!("candidate_from_obligation({}) -> 0 matches, ambig",
|
|
|
|
obligation.repr(self.tcx()));
|
|
|
|
Ok(None)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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!("candidate_from_obligation({}) -> multiple matches, ambig",
|
|
|
|
obligation.repr(self.tcx()));
|
|
|
|
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
let candidate = candidates.pop().unwrap();
|
|
|
|
self.insert_candidate_cache(obligation, skol_obligation_self_ty,
|
|
|
|
candidate.clone());
|
|
|
|
Ok(Some(candidate))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_candidate_cache(&self,
|
|
|
|
_obligation: &Obligation,
|
|
|
|
_skol_obligation_self_ty: ty::t)
|
|
|
|
-> Option<Candidate>
|
|
|
|
{
|
|
|
|
// let cache_key = CacheKey::new(obligation.trait_ref.def_id,
|
|
|
|
// skol_obligation_self_ty);
|
|
|
|
// let hashmap = self.tcx().selection_cache.hashmap.borrow();
|
|
|
|
// hashmap.find(&cache_key).map(|c| (*c).clone())
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn insert_candidate_cache(&self,
|
|
|
|
_obligation: &Obligation,
|
|
|
|
_skol_obligation_self_ty: ty::t,
|
|
|
|
_candidate: Candidate)
|
|
|
|
{
|
|
|
|
// FIXME -- Enable caching. I think the right place to put the cache
|
|
|
|
// is in the ParameterEnvironment, not the tcx, because otherwise
|
|
|
|
// when there are distinct where clauses in scope the cache can get
|
|
|
|
// confused.
|
|
|
|
//
|
|
|
|
//let cache_key = CacheKey::new(obligation.trait_ref.def_id,
|
|
|
|
// skol_obligation_self_ty);
|
|
|
|
//let mut hashmap = self.tcx().selection_cache.hashmap.borrow_mut();
|
|
|
|
//hashmap.insert(cache_key, candidate);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assemble_candidates(&self,
|
|
|
|
obligation: &Obligation,
|
|
|
|
skol_obligation_self_ty: ty::t)
|
|
|
|
-> Result<Vec<Candidate>, SelectionError>
|
|
|
|
{
|
|
|
|
// Check for overflow.
|
|
|
|
|
|
|
|
let recursion_limit = self.infcx.tcx.sess.recursion_limit.get();
|
|
|
|
if obligation.recursion_depth >= recursion_limit {
|
|
|
|
debug!("{} --> overflow", obligation.repr(self.tcx()));
|
|
|
|
return Err(Overflow);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut candidates = Vec::new();
|
|
|
|
|
|
|
|
match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id) {
|
|
|
|
Some(_) => {
|
|
|
|
// FIXME -- The treatment of builtin bounds is a bit
|
|
|
|
// hacky right now. Eventually, the idea is to move
|
|
|
|
// the logic for selection out of type_contents and
|
|
|
|
// into this module (And make it based on the generic
|
|
|
|
// mechanisms of OIBTT2). However, I want to land
|
|
|
|
// some code today, so we're going to cut a few
|
|
|
|
// corners. What we do now is that the trait selection
|
|
|
|
// code always considers builtin obligations to
|
|
|
|
// match. The fulfillment code (which also has the job
|
|
|
|
// of tracking all the traits that must hold) will
|
|
|
|
// then just accumulate the various
|
|
|
|
// builtin-bound-related obligations that must be met.
|
|
|
|
// Later, at the end of typeck, after writeback etc,
|
|
|
|
// we will rewalk this list and extract all the
|
|
|
|
// builtin-bound-related obligations and test them
|
|
|
|
// again using type contents. Part of the motivation
|
|
|
|
// for this is that the type contents code requires
|
|
|
|
// that writeback has been completed in some cases.
|
|
|
|
|
|
|
|
candidates.push(AmbiguousBuiltinCandidate);
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
|
|
|
// Other bounds. Consider both in-scope bounds from fn decl
|
|
|
|
// and applicable impls.
|
|
|
|
|
|
|
|
try!(self.assemble_candidates_from_caller_bounds(
|
|
|
|
obligation,
|
|
|
|
skol_obligation_self_ty,
|
|
|
|
&mut candidates));
|
|
|
|
|
|
|
|
try!(self.assemble_unboxed_candidates(
|
|
|
|
obligation,
|
|
|
|
skol_obligation_self_ty,
|
|
|
|
&mut candidates));
|
|
|
|
|
|
|
|
// If there is a fn bound that applies, forego the
|
|
|
|
// impl search. It can only generate conflicts.
|
|
|
|
|
|
|
|
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(&self,
|
|
|
|
obligation: &Obligation,
|
|
|
|
skol_obligation_self_ty: ty::t,
|
|
|
|
candidates: &mut Vec<Candidate>)
|
|
|
|
-> Result<(),SelectionError>
|
|
|
|
{
|
|
|
|
/*!
|
|
|
|
* Given an obligation like `<SomeTrait for T>`, search the obligations
|
|
|
|
* that the caller supplied to find out whether it is listed among
|
|
|
|
* them.
|
|
|
|
*
|
|
|
|
* Never affects inference environment.
|
|
|
|
v */
|
|
|
|
|
|
|
|
debug!("assemble_candidates_from_caller_bounds({})",
|
|
|
|
obligation.repr(self.tcx()));
|
|
|
|
|
|
|
|
for caller_obligation in self.param_env.caller_obligations.iter() {
|
|
|
|
debug!("caller_obligation={}",
|
|
|
|
caller_obligation.repr(self.tcx()));
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
match self.match_self_types(obligation.cause,
|
|
|
|
caller_self_ty,
|
|
|
|
skol_obligation_self_ty) {
|
|
|
|
AmbiguousMatch => {
|
|
|
|
debug!("-> AmbiguousParamCandidate");
|
|
|
|
candidates.push(AmbiguousParamCandidate);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
match util::search_trait_and_supertraits_from_bound(
|
|
|
|
self.infcx.tcx, caller_bound,
|
|
|
|
|d| d == obligation.trait_ref.def_id)
|
|
|
|
{
|
|
|
|
Some(vtable_param) => {
|
|
|
|
// If so, we're done!
|
|
|
|
debug!("-> MatchedParamCandidate({})", vtable_param);
|
|
|
|
candidates.push(MatchedParamCandidate(vtable_param));
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assemble_unboxed_candidates(&self,
|
|
|
|
obligation: &Obligation,
|
|
|
|
skol_obligation_self_ty: ty::t,
|
|
|
|
candidates: &mut Vec<Candidate>)
|
|
|
|
-> 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.unboxed_closures.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(&self,
|
|
|
|
obligation: &Obligation,
|
|
|
|
skol_obligation_self_ty: ty::t,
|
|
|
|
candidates: &mut Vec<Candidate>)
|
|
|
|
-> 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(&self,
|
|
|
|
impl_def_id: ast::DefId,
|
|
|
|
obligation_cause: ObligationCause,
|
|
|
|
skol_obligation_self_ty: ty::t)
|
|
|
|
-> Option<ImplCandidate>
|
|
|
|
{
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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(&self,
|
|
|
|
obligation: &Obligation,
|
|
|
|
candidate: Candidate)
|
|
|
|
-> SelectionResult<Selection>
|
|
|
|
{
|
|
|
|
debug!("confirm_candidate({}, {})",
|
|
|
|
obligation.repr(self.tcx()),
|
|
|
|
candidate.repr(self.tcx()));
|
|
|
|
|
|
|
|
match candidate {
|
|
|
|
AmbiguousBuiltinCandidate |
|
|
|
|
AmbiguousParamCandidate |
|
|
|
|
Impl(AmbiguousImplCandidate(_)) => {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
|
|
|
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(&self,
|
|
|
|
obligation: &Obligation,
|
2014-09-11 17:07:49 +12:00
|
|
|
param: VtableParamData)
|
|
|
|
-> Result<VtableParamData,SelectionError>
|
2014-09-12 10:53:35 -04:00
|
|
|
{
|
|
|
|
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(&self,
|
|
|
|
obligation: &Obligation,
|
|
|
|
impl_def_id: ast::DefId)
|
2014-09-11 17:07:49 +12:00
|
|
|
-> Result<VtableImplData<Obligation>,SelectionError>
|
2014-09-12 10:53:35 -04:00
|
|
|
{
|
|
|
|
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(&self,
|
|
|
|
impl_def_id: ast::DefId,
|
|
|
|
obligation_cause: ObligationCause,
|
|
|
|
obligation_self_ty: ty::t,
|
|
|
|
obligation_recursion_depth: uint)
|
2014-09-11 17:07:49 +12:00
|
|
|
-> Result<VtableImplData<Obligation>,
|
2014-09-12 10:53:35 -04:00
|
|
|
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);
|
2014-09-11 17:07:49 +12:00
|
|
|
let vtable_impl = VtableImplData { impl_def_id: impl_def_id,
|
2014-09-12 10:53:35 -04:00
|
|
|
substs: substs,
|
|
|
|
nested: impl_obligations };
|
|
|
|
|
|
|
|
Ok(vtable_impl)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn confirm_unboxed_closure_candidate(&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.unboxed_closures.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(&self,
|
|
|
|
impl_def_id: ast::DefId,
|
|
|
|
obligation_cause: ObligationCause,
|
|
|
|
obligation_self_ty: ty::t)
|
|
|
|
-> MatchResult<Substs>
|
|
|
|
{
|
|
|
|
/*!
|
|
|
|
* 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<T:Copy> 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(&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(&self,
|
|
|
|
impl_def_id: ast::DefId,
|
|
|
|
obligation_cause: ObligationCause,
|
|
|
|
obligation_trait_ref: Rc<ty::TraitRef>,
|
|
|
|
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<char> for Elems<int>` using the following impl:
|
|
|
|
*
|
|
|
|
* impl<T> Iterator<T> for Elems<T> { ... }
|
|
|
|
*
|
|
|
|
* 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(&self,
|
|
|
|
obligation_cause: ObligationCause,
|
|
|
|
obligation_trait_ref: Rc<ty::TraitRef>,
|
|
|
|
expected_trait_ref: Rc<ty::TraitRef>)
|
|
|
|
-> 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<T> Iterator<T> for Vec<T> { ... }
|
|
|
|
*
|
|
|
|
* and our obligation is `Iterator<Foo> for Vec<int>` (note
|
|
|
|
* the mismatch in the obligation types). Up until this step,
|
|
|
|
* no error would be reported: the self type is `Vec<int>`,
|
|
|
|
* and that matches `Vec<T>` 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<int> for Vec<int>`, and the
|
|
|
|
* `obligation_trait_ref` would be `Iterator<Foo> for Vec<int>`.
|
|
|
|
*
|
|
|
|
* 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 all_impls(&self, trait_def_id: ast::DefId) -> Vec<ast::DefId> {
|
|
|
|
/*!
|
|
|
|
* 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<Obligation>
|
|
|
|
{
|
|
|
|
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 trait_ref_unconstrained(&self,
|
|
|
|
trait_ref: &ty::TraitRef)
|
|
|
|
-> bool
|
|
|
|
{
|
|
|
|
/*!
|
|
|
|
* True if the self type of the trait-ref contains
|
|
|
|
* unconstrained type variables.
|
|
|
|
*/
|
|
|
|
|
|
|
|
let mut found_skol = false;
|
|
|
|
|
|
|
|
// Skolemization replaces all unconstrained type vars with
|
|
|
|
// a SkolemizedTy instance. Then we search to see if we
|
|
|
|
// found any.
|
|
|
|
let skol_ty = infer::skolemize(self.infcx, trait_ref.self_ty());
|
|
|
|
ty::walk_ty(skol_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(),
|
|
|
|
|
|
|
|
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 {
|
|
|
|
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 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
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|