2014-12-17 14:16:28 -05: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.
|
|
|
|
|
|
|
|
//! Code for projecting associated types out of trait references.
|
|
|
|
|
|
|
|
use super::elaborate_predicates;
|
2016-02-16 10:36:47 -08:00
|
|
|
use super::specialization_graph;
|
|
|
|
use super::translate_substs;
|
2014-12-17 14:16:28 -05:00
|
|
|
use super::Obligation;
|
2014-12-30 17:42:02 -05:00
|
|
|
use super::ObligationCause;
|
2014-12-17 14:16:28 -05:00
|
|
|
use super::PredicateObligation;
|
|
|
|
use super::SelectionContext;
|
|
|
|
use super::SelectionError;
|
2015-06-10 00:09:37 +03:00
|
|
|
use super::VtableClosureData;
|
2016-05-11 14:40:24 -07:00
|
|
|
use super::VtableFnPointerData;
|
2014-12-17 14:16:28 -05:00
|
|
|
use super::VtableImplData;
|
2015-01-10 11:54:15 -05:00
|
|
|
use super::util;
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2016-03-29 12:54:26 +03:00
|
|
|
use hir::def_id::DefId;
|
2016-11-07 13:25:06 -05:00
|
|
|
use infer::InferOk;
|
2016-11-28 10:08:08 -08:00
|
|
|
use infer::type_variable::TypeVariableOrigin;
|
2016-05-21 08:29:50 -04:00
|
|
|
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
|
2016-02-16 10:36:47 -08:00
|
|
|
use syntax::ast;
|
2016-11-16 08:21:52 +00:00
|
|
|
use syntax::symbol::Symbol;
|
2016-05-21 08:30:29 -04:00
|
|
|
use ty::subst::Subst;
|
|
|
|
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
|
|
|
|
use ty::fold::{TypeFoldable, TypeFolder};
|
2015-01-10 11:54:15 -05:00
|
|
|
use util::common::FN_OUTPUT_NAME;
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2016-02-23 12:47:09 -08:00
|
|
|
/// Depending on the stage of compilation, we want projection to be
|
|
|
|
/// more or less conservative.
|
2017-05-17 08:01:04 -04:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
2016-06-30 21:22:47 +03:00
|
|
|
pub enum Reveal {
|
2016-02-23 12:47:09 -08:00
|
|
|
/// At type-checking time, we refuse to project any associated
|
|
|
|
/// type that is marked `default`. Non-`default` ("final") types
|
|
|
|
/// are always projected. This is necessary in general for
|
|
|
|
/// soundness of specialization. However, we *could* allow
|
|
|
|
/// projections in fully-monomorphic cases. We choose not to,
|
|
|
|
/// because we prefer for `default type` to force the type
|
|
|
|
/// definition to be treated abstractly by any consumers of the
|
|
|
|
/// impl. Concretely, that means that the following example will
|
|
|
|
/// fail to compile:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// trait Assoc {
|
|
|
|
/// type Output;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl<T> Assoc for T {
|
|
|
|
/// default type Output = bool;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// let <() as Assoc>::Output = true;
|
|
|
|
/// }
|
2017-02-19 14:46:29 +02:00
|
|
|
UserFacing,
|
2016-02-23 12:47:09 -08:00
|
|
|
|
2016-07-01 19:32:53 +03:00
|
|
|
/// At trans time, all monomorphic projections will succeed.
|
2016-07-22 18:56:22 +03:00
|
|
|
/// Also, `impl Trait` is normalized to the concrete type,
|
|
|
|
/// which has to be already collected by type-checking.
|
|
|
|
///
|
|
|
|
/// NOTE: As `impl Trait`'s concrete type should *never*
|
|
|
|
/// be observable directly by the user, `Reveal::All`
|
|
|
|
/// should not be used by checks which may expose
|
|
|
|
/// type equality or type contents to the user.
|
|
|
|
/// There are some exceptions, e.g. around OIBITS and
|
|
|
|
/// transmute-checking, which expose some details, but
|
|
|
|
/// not the whole concrete type of the `impl Trait`.
|
2016-06-30 21:22:47 +03:00
|
|
|
All,
|
2016-02-23 12:47:09 -08:00
|
|
|
}
|
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
pub type PolyProjectionObligation<'tcx> =
|
|
|
|
Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
|
|
|
|
|
|
|
|
pub type ProjectionObligation<'tcx> =
|
|
|
|
Obligation<'tcx, ty::ProjectionPredicate<'tcx>>;
|
|
|
|
|
|
|
|
pub type ProjectionTyObligation<'tcx> =
|
|
|
|
Obligation<'tcx, ty::ProjectionTy<'tcx>>;
|
|
|
|
|
2014-12-30 17:42:02 -05:00
|
|
|
/// When attempting to resolve `<T as TraitRef>::Name` ...
|
2015-06-18 08:51:23 +03:00
|
|
|
#[derive(Debug)]
|
2014-12-30 17:42:02 -05:00
|
|
|
pub enum ProjectionTyError<'tcx> {
|
2014-12-30 08:59:33 -05:00
|
|
|
/// ...we found multiple sources of information and couldn't resolve the ambiguity.
|
2014-12-17 14:16:28 -05:00
|
|
|
TooManyCandidates,
|
|
|
|
|
|
|
|
/// ...an error occurred matching `T : TraitRef`
|
|
|
|
TraitSelectionError(SelectionError<'tcx>),
|
|
|
|
}
|
|
|
|
|
2015-01-03 22:54:18 -05:00
|
|
|
#[derive(Clone)]
|
2014-12-17 14:16:28 -05:00
|
|
|
pub struct MismatchedProjectionTypes<'tcx> {
|
2015-09-06 21:51:58 +03:00
|
|
|
pub err: ty::error::TypeError<'tcx>
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
2015-06-18 08:51:23 +03:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
2014-12-17 14:16:28 -05:00
|
|
|
enum ProjectionTyCandidate<'tcx> {
|
2015-10-22 12:28:47 -04:00
|
|
|
// from a where-clause in the env or object type
|
2014-12-17 14:16:28 -05:00
|
|
|
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
2015-10-22 12:28:47 -04:00
|
|
|
|
|
|
|
// from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
|
|
|
|
TraitDef(ty::PolyProjectionPredicate<'tcx>),
|
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
// from a "impl" (or a "pseudo-impl" returned by select)
|
|
|
|
Select,
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ProjectionTyCandidateSet<'tcx> {
|
|
|
|
vec: Vec<ProjectionTyCandidate<'tcx>>,
|
|
|
|
ambiguous: bool
|
|
|
|
}
|
|
|
|
|
2015-01-26 14:20:38 -05:00
|
|
|
/// Evaluates constraints of the form:
|
|
|
|
///
|
|
|
|
/// for<...> <T as Trait>::U == V
|
|
|
|
///
|
|
|
|
/// If successful, this may result in additional obligations.
|
2016-04-29 06:00:23 +03:00
|
|
|
pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2014-12-17 14:16:28 -05:00
|
|
|
obligation: &PolyProjectionObligation<'tcx>)
|
2014-12-30 17:42:02 -05:00
|
|
|
-> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
|
2014-12-17 14:16:28 -05:00
|
|
|
{
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("poly_project_and_unify_type(obligation={:?})",
|
|
|
|
obligation);
|
2014-12-17 14:16:28 -05:00
|
|
|
|
|
|
|
let infcx = selcx.infcx();
|
2015-03-10 07:02:27 -04:00
|
|
|
infcx.commit_if_ok(|snapshot| {
|
2014-12-17 14:16:28 -05:00
|
|
|
let (skol_predicate, skol_map) =
|
|
|
|
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
|
|
|
|
|
|
|
let skol_obligation = obligation.with(skol_predicate);
|
2016-10-18 21:32:31 -04:00
|
|
|
let r = match project_and_unify_type(selcx, &skol_obligation) {
|
2015-02-03 06:12:43 -05:00
|
|
|
Ok(result) => {
|
2016-04-20 19:51:56 -04:00
|
|
|
let span = obligation.cause.span;
|
|
|
|
match infcx.leak_check(false, span, &skol_map, snapshot) {
|
2016-09-30 17:44:48 +10:00
|
|
|
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, result)),
|
2015-02-03 06:12:43 -05:00
|
|
|
Err(e) => Err(MismatchedProjectionTypes { err: e }),
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
2015-02-03 06:12:43 -05:00
|
|
|
Err(e)
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
2016-10-18 21:32:31 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
r
|
2015-02-03 06:12:43 -05:00
|
|
|
})
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
2015-01-26 14:20:38 -05:00
|
|
|
/// Evaluates constraints of the form:
|
|
|
|
///
|
|
|
|
/// <T as Trait>::U == V
|
|
|
|
///
|
|
|
|
/// If successful, this may result in additional obligations.
|
2016-04-29 06:00:23 +03:00
|
|
|
fn project_and_unify_type<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2014-12-17 14:16:28 -05:00
|
|
|
obligation: &ProjectionObligation<'tcx>)
|
2014-12-30 17:42:02 -05:00
|
|
|
-> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
|
2014-12-17 14:16:28 -05:00
|
|
|
{
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("project_and_unify_type(obligation={:?})",
|
|
|
|
obligation);
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2016-05-12 18:01:23 -07:00
|
|
|
let Normalized { value: normalized_ty, mut obligations } =
|
2014-12-30 17:42:02 -05:00
|
|
|
match opt_normalize_projection_type(selcx,
|
2017-05-23 04:19:47 -04:00
|
|
|
obligation.param_env,
|
|
|
|
obligation.predicate.projection_ty,
|
2014-12-30 17:42:02 -05:00
|
|
|
obligation.cause.clone(),
|
|
|
|
obligation.recursion_depth) {
|
|
|
|
Some(n) => n,
|
2016-05-10 23:25:34 -07:00
|
|
|
None => return Ok(None),
|
2014-12-30 17:42:02 -05:00
|
|
|
};
|
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("project_and_unify_type: normalized_ty={:?} obligations={:?}",
|
|
|
|
normalized_ty,
|
|
|
|
obligations);
|
2014-12-30 17:42:02 -05:00
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
let infcx = selcx.infcx();
|
2017-05-24 09:43:20 -04:00
|
|
|
match infcx.at(&obligation.cause, obligation.param_env)
|
|
|
|
.eq(normalized_ty, obligation.predicate.ty) {
|
2016-08-24 18:09:46 -04:00
|
|
|
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
|
2016-05-12 18:01:23 -07:00
|
|
|
obligations.extend(inferred_obligations);
|
2016-03-29 20:06:42 -07:00
|
|
|
Ok(Some(obligations))
|
|
|
|
},
|
2014-12-30 17:42:02 -05:00
|
|
|
Err(err) => Err(MismatchedProjectionTypes { err: err }),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-26 14:20:38 -05:00
|
|
|
/// Normalizes any associated type projections in `value`, replacing
|
|
|
|
/// them with a fully resolved type where possible. The return value
|
|
|
|
/// combines the normalized result and any additional obligations that
|
|
|
|
/// were incurred as result.
|
2016-04-29 06:00:23 +03:00
|
|
|
pub fn normalize<'a, 'b, 'gcx, 'tcx, T>(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2016-04-29 06:00:23 +03:00
|
|
|
cause: ObligationCause<'tcx>,
|
|
|
|
value: &T)
|
|
|
|
-> Normalized<'tcx, T>
|
2015-11-18 09:38:57 +00:00
|
|
|
where T : TypeFoldable<'tcx>
|
2014-12-30 17:42:02 -05:00
|
|
|
{
|
2017-05-23 04:19:47 -04:00
|
|
|
normalize_with_depth(selcx, param_env, cause, 0, value)
|
2015-01-01 13:15:14 -05:00
|
|
|
}
|
|
|
|
|
2015-01-26 14:20:38 -05:00
|
|
|
/// As `normalize`, but with a custom depth.
|
2016-04-29 06:00:23 +03:00
|
|
|
pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>(
|
|
|
|
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2016-04-29 06:00:23 +03:00
|
|
|
cause: ObligationCause<'tcx>,
|
|
|
|
depth: usize,
|
|
|
|
value: &T)
|
|
|
|
-> Normalized<'tcx, T>
|
|
|
|
|
2015-11-18 09:38:57 +00:00
|
|
|
where T : TypeFoldable<'tcx>
|
2015-01-01 13:15:14 -05:00
|
|
|
{
|
2016-05-21 05:42:27 -04:00
|
|
|
debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
|
2017-05-23 04:19:47 -04:00
|
|
|
let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth);
|
2014-12-30 17:42:02 -05:00
|
|
|
let result = normalizer.fold(value);
|
2016-05-21 05:42:27 -04:00
|
|
|
debug!("normalize_with_depth: depth={} result={:?} with {} obligations",
|
|
|
|
depth, result, normalizer.obligations.len());
|
|
|
|
debug!("normalize_with_depth: depth={} obligations={:?}",
|
|
|
|
depth, normalizer.obligations);
|
2014-12-30 17:42:02 -05:00
|
|
|
Normalized {
|
|
|
|
value: result,
|
|
|
|
obligations: normalizer.obligations,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
|
|
|
|
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2014-12-30 17:42:02 -05:00
|
|
|
cause: ObligationCause<'tcx>,
|
|
|
|
obligations: Vec<PredicateObligation<'tcx>>,
|
2015-03-25 17:06:52 -07:00
|
|
|
depth: usize,
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
|
|
|
|
fn new(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2014-12-30 17:42:02 -05:00
|
|
|
cause: ObligationCause<'tcx>,
|
2015-03-25 17:06:52 -07:00
|
|
|
depth: usize)
|
2016-04-29 06:00:23 +03:00
|
|
|
-> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx>
|
2014-12-30 17:42:02 -05:00
|
|
|
{
|
|
|
|
AssociatedTypeNormalizer {
|
2017-07-03 11:19:51 -07:00
|
|
|
selcx,
|
|
|
|
param_env,
|
|
|
|
cause,
|
2016-10-29 22:54:04 +01:00
|
|
|
obligations: vec![],
|
2017-07-03 11:19:51 -07:00
|
|
|
depth,
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-18 09:38:57 +00:00
|
|
|
fn fold<T:TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
|
2014-12-30 17:42:02 -05:00
|
|
|
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
|
|
|
|
|
|
|
|
if !value.has_projection_types() {
|
|
|
|
value.clone()
|
|
|
|
} else {
|
|
|
|
value.fold_with(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
|
|
|
|
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'tcx> {
|
2014-12-30 17:42:02 -05:00
|
|
|
self.selcx.tcx()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|
|
|
// We don't want to normalize associated types that occur inside of region
|
|
|
|
// binders, because they may contain bound regions, and we can't cope with that.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// for<'a> fn(<T as Foo<&'a>>::A)
|
|
|
|
//
|
|
|
|
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
|
|
|
|
// normalize it when we instantiate those bound regions (which
|
|
|
|
// should occur eventually).
|
|
|
|
|
2016-01-06 02:01:28 +00:00
|
|
|
let ty = ty.super_fold_with(self);
|
2014-12-30 17:42:02 -05:00
|
|
|
match ty.sty {
|
2016-07-22 18:56:22 +03:00
|
|
|
ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*)
|
|
|
|
// Only normalize `impl Trait` after type-checking, usually in trans.
|
2017-05-17 08:01:04 -04:00
|
|
|
match self.param_env.reveal {
|
|
|
|
Reveal::UserFacing => ty,
|
|
|
|
|
|
|
|
Reveal::All => {
|
|
|
|
let generic_ty = self.tcx().type_of(def_id);
|
|
|
|
let concrete_ty = generic_ty.subst(self.tcx(), substs);
|
|
|
|
self.fold_ty(concrete_ty)
|
|
|
|
}
|
2016-07-22 18:56:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-11 16:21:46 -07:00
|
|
|
ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*)
|
2014-12-30 17:42:02 -05:00
|
|
|
|
|
|
|
// (*) This is kind of hacky -- we need to be able to
|
|
|
|
// handle normalization within binders because
|
|
|
|
// otherwise we wind up a need to normalize when doing
|
|
|
|
// trait matching (since you can have a trait
|
|
|
|
// obligation like `for<'a> T::B : Fn(&'a int)`), but
|
|
|
|
// we can't normalize with bound regions in scope. So
|
|
|
|
// far now we just ignore binders but only normalize
|
|
|
|
// if all bound regions are gone (and then we still
|
|
|
|
// have to renormalize whenever we instantiate a
|
|
|
|
// binder). It would be better to normalize in a
|
|
|
|
// binding-aware fashion.
|
|
|
|
|
2016-05-21 05:42:27 -04:00
|
|
|
let Normalized { value: normalized_ty, obligations } =
|
2014-12-30 17:42:02 -05:00
|
|
|
normalize_projection_type(self.selcx,
|
2017-05-23 04:19:47 -04:00
|
|
|
self.param_env,
|
2014-12-30 17:42:02 -05:00
|
|
|
data.clone(),
|
|
|
|
self.cause.clone(),
|
|
|
|
self.depth);
|
2016-05-21 08:18:52 -04:00
|
|
|
debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?} \
|
|
|
|
with {} add'l obligations",
|
2016-05-21 05:42:27 -04:00
|
|
|
self.depth, ty, normalized_ty, obligations.len());
|
2015-06-10 17:22:20 +01:00
|
|
|
self.obligations.extend(obligations);
|
2016-05-21 05:42:27 -04:00
|
|
|
normalized_ty
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
2015-01-08 12:02:15 -05:00
|
|
|
|
2014-12-30 17:42:02 -05:00
|
|
|
_ => {
|
2015-01-08 12:02:15 -05:00
|
|
|
ty
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-22 15:11:56 -04:00
|
|
|
#[derive(Clone)]
|
2014-12-30 17:42:02 -05:00
|
|
|
pub struct Normalized<'tcx,T> {
|
|
|
|
pub value: T,
|
|
|
|
pub obligations: Vec<PredicateObligation<'tcx>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
|
|
|
|
|
2015-01-08 06:58:41 -05:00
|
|
|
impl<'tcx,T> Normalized<'tcx,T> {
|
2015-01-08 10:45:56 -05:00
|
|
|
pub fn with<U>(self, value: U) -> Normalized<'tcx,U> {
|
2015-01-08 06:58:41 -05:00
|
|
|
Normalized { value: value, obligations: self.obligations }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-26 14:20:38 -05:00
|
|
|
/// The guts of `normalize`: normalize a specific projection like `<T
|
|
|
|
/// as Trait>::Item`. The result is always a type (and possibly
|
|
|
|
/// additional obligations). If ambiguity arises, which implies that
|
|
|
|
/// there are unresolved type variables in the projection, we will
|
|
|
|
/// substitute a fresh type variable `$X` and generate a new
|
|
|
|
/// obligation `<T as Trait>::Item == $X` for later.
|
2016-04-29 06:00:23 +03:00
|
|
|
pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
|
|
|
|
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2014-12-30 17:42:02 -05:00
|
|
|
projection_ty: ty::ProjectionTy<'tcx>,
|
|
|
|
cause: ObligationCause<'tcx>,
|
2015-03-25 17:06:52 -07:00
|
|
|
depth: usize)
|
2014-12-30 17:42:02 -05:00
|
|
|
-> NormalizedTy<'tcx>
|
|
|
|
{
|
2017-05-23 04:19:47 -04:00
|
|
|
opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth)
|
2014-12-30 17:42:02 -05:00
|
|
|
.unwrap_or_else(move || {
|
|
|
|
// if we bottom out in ambiguity, create a type variable
|
|
|
|
// and a deferred predicate to resolve this when more type
|
|
|
|
// information is available.
|
|
|
|
|
2016-11-28 10:08:08 -08:00
|
|
|
let tcx = selcx.infcx().tcx;
|
|
|
|
let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
|
2017-05-31 12:35:13 -04:00
|
|
|
i.name == projection_ty.item_name(tcx) && i.kind == ty::AssociatedKind::Type
|
2016-11-28 10:08:08 -08:00
|
|
|
).map(|i| i.def_id).unwrap();
|
|
|
|
let ty_var = selcx.infcx().next_ty_var(
|
|
|
|
TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
|
2014-12-30 17:42:02 -05:00
|
|
|
let projection = ty::Binder(ty::ProjectionPredicate {
|
2017-07-03 11:19:51 -07:00
|
|
|
projection_ty,
|
2014-12-30 17:42:02 -05:00
|
|
|
ty: ty_var
|
|
|
|
});
|
2015-10-24 18:37:28 +03:00
|
|
|
let obligation = Obligation::with_depth(
|
2017-05-23 04:19:47 -04:00
|
|
|
cause, depth + 1, param_env, projection.to_predicate());
|
2014-12-30 17:42:02 -05:00
|
|
|
Normalized {
|
|
|
|
value: ty_var,
|
2016-10-29 22:54:04 +01:00
|
|
|
obligations: vec![obligation]
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-01-26 14:20:38 -05:00
|
|
|
/// The guts of `normalize`: normalize a specific projection like `<T
|
|
|
|
/// as Trait>::Item`. The result is always a type (and possibly
|
|
|
|
/// additional obligations). Returns `None` in the case of ambiguity,
|
|
|
|
/// which indicates that there are unbound type variables.
|
2016-04-29 06:00:23 +03:00
|
|
|
fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
|
|
|
|
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2014-12-30 17:42:02 -05:00
|
|
|
projection_ty: ty::ProjectionTy<'tcx>,
|
|
|
|
cause: ObligationCause<'tcx>,
|
2015-03-25 17:06:52 -07:00
|
|
|
depth: usize)
|
2014-12-30 17:42:02 -05:00
|
|
|
-> Option<NormalizedTy<'tcx>>
|
|
|
|
{
|
2016-04-20 19:51:56 -04:00
|
|
|
let infcx = selcx.infcx();
|
|
|
|
|
|
|
|
let projection_ty = infcx.resolve_type_vars_if_possible(&projection_ty);
|
|
|
|
|
|
|
|
debug!("opt_normalize_projection_type(\
|
2015-06-18 20:25:05 +03:00
|
|
|
projection_ty={:?}, \
|
2014-12-30 17:42:02 -05:00
|
|
|
depth={})",
|
2015-06-18 20:25:05 +03:00
|
|
|
projection_ty,
|
2014-12-30 17:42:02 -05:00
|
|
|
depth);
|
|
|
|
|
2016-05-21 08:30:52 -04:00
|
|
|
// FIXME(#20304) For now, I am caching here, which is good, but it
|
|
|
|
// means we don't capture the type variables that are created in
|
|
|
|
// the case of ambiguity. Which means we may create a large stream
|
|
|
|
// of such variables. OTOH, if we move the caching up a level, we
|
|
|
|
// would not benefit from caching when proving `T: Trait<U=Foo>`
|
|
|
|
// bounds. It might be the case that we want two distinct caches,
|
|
|
|
// or else another kind of cache entry.
|
|
|
|
|
|
|
|
match infcx.projection_cache.borrow_mut().try_start(projection_ty) {
|
|
|
|
Ok(()) => { }
|
|
|
|
Err(ProjectionCacheEntry::Ambiguous) => {
|
|
|
|
// If we found ambiguity the last time, that generally
|
|
|
|
// means we will continue to do so until some type in the
|
|
|
|
// key changes (and we know it hasn't, because we just
|
|
|
|
// fully resolved it). One exception though is closure
|
|
|
|
// types, which can transition from having a fixed kind to
|
|
|
|
// no kind with no visible change in the key.
|
|
|
|
//
|
|
|
|
// FIXME(#32286) refactor this so that closure type
|
|
|
|
// changes
|
|
|
|
debug!("opt_normalize_projection_type: \
|
|
|
|
found cache entry: ambiguous");
|
|
|
|
if !projection_ty.has_closure_types() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(ProjectionCacheEntry::InProgress) => {
|
|
|
|
// If while normalized A::B, we are asked to normalize
|
|
|
|
// A::B, just return A::B itself. This is a conservative
|
|
|
|
// answer, in the sense that A::B *is* clearly equivalent
|
|
|
|
// to A::B, though there may be a better value we can
|
|
|
|
// find.
|
|
|
|
|
|
|
|
// Under lazy normalization, this can arise when
|
|
|
|
// bootstrapping. That is, imagine an environment with a
|
|
|
|
// where-clause like `A::B == u32`. Now, if we are asked
|
|
|
|
// to normalize `A::B`, we will want to check the
|
|
|
|
// where-clauses in scope. So we will try to unify `A::B`
|
|
|
|
// with `A::B`, which can trigger a recursive
|
|
|
|
// normalization. In that case, I think we will want this code:
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// let ty = selcx.tcx().mk_projection(projection_ty.trait_ref,
|
2017-05-31 12:35:13 -04:00
|
|
|
// projection_ty.item_name(tcx);
|
2016-05-21 08:30:52 -04:00
|
|
|
// return Some(NormalizedTy { value: v, obligations: vec![] });
|
|
|
|
// ```
|
|
|
|
|
|
|
|
debug!("opt_normalize_projection_type: \
|
|
|
|
found cache entry: in-progress");
|
|
|
|
|
|
|
|
// But for now, let's classify this as an overflow:
|
|
|
|
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
|
|
|
|
let obligation = Obligation::with_depth(cause.clone(),
|
|
|
|
recursion_limit,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env,
|
2016-05-21 08:30:52 -04:00
|
|
|
projection_ty);
|
|
|
|
selcx.infcx().report_overflow_error(&obligation, false);
|
|
|
|
}
|
|
|
|
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
|
|
|
|
// If we find the value in the cache, then the obligations
|
|
|
|
// have already been returned from the previous entry (and
|
|
|
|
// should therefore have been honored).
|
|
|
|
debug!("opt_normalize_projection_type: \
|
|
|
|
found normalized ty `{:?}`",
|
|
|
|
ty);
|
|
|
|
return Some(NormalizedTy { value: ty, obligations: vec![] });
|
|
|
|
}
|
|
|
|
Err(ProjectionCacheEntry::Error) => {
|
|
|
|
debug!("opt_normalize_projection_type: \
|
|
|
|
found error");
|
2017-05-23 04:19:47 -04:00
|
|
|
return Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth));
|
2016-05-21 08:30:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-23 04:19:47 -04:00
|
|
|
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
|
2014-12-30 17:42:02 -05:00
|
|
|
match project_type(selcx, &obligation) {
|
2016-05-21 08:29:50 -04:00
|
|
|
Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
|
|
|
|
mut obligations,
|
|
|
|
cacheable })) => {
|
2014-12-30 17:42:02 -05:00
|
|
|
// if projection succeeded, then what we get out of this
|
|
|
|
// is also non-normalized (consider: it was derived from
|
|
|
|
// an impl, where-clause etc) and hence we must
|
|
|
|
// re-normalize it
|
|
|
|
|
2016-04-20 19:51:56 -04:00
|
|
|
debug!("opt_normalize_projection_type: \
|
2016-05-21 08:29:50 -04:00
|
|
|
projected_ty={:?} \
|
|
|
|
depth={} \
|
|
|
|
obligations={:?} \
|
|
|
|
cacheable={:?}",
|
2015-06-18 20:25:05 +03:00
|
|
|
projected_ty,
|
2015-01-01 13:15:14 -05:00
|
|
|
depth,
|
2016-05-21 08:29:50 -04:00
|
|
|
obligations,
|
|
|
|
cacheable);
|
2014-12-30 17:42:02 -05:00
|
|
|
|
2016-05-21 08:29:50 -04:00
|
|
|
let result = if projected_ty.has_projection_types() {
|
2017-05-24 12:01:53 -04:00
|
|
|
let mut normalizer = AssociatedTypeNormalizer::new(selcx,
|
|
|
|
param_env,
|
|
|
|
cause,
|
|
|
|
depth+1);
|
2014-12-30 17:42:02 -05:00
|
|
|
let normalized_ty = normalizer.fold(&projected_ty);
|
|
|
|
|
2016-04-20 19:51:56 -04:00
|
|
|
debug!("opt_normalize_projection_type: \
|
|
|
|
normalized_ty={:?} depth={}",
|
2015-06-18 20:25:05 +03:00
|
|
|
normalized_ty,
|
2014-12-30 17:42:02 -05:00
|
|
|
depth);
|
|
|
|
|
2015-06-10 17:22:20 +01:00
|
|
|
obligations.extend(normalizer.obligations);
|
2016-05-21 08:30:52 -04:00
|
|
|
Normalized {
|
2014-12-30 17:42:02 -05:00
|
|
|
value: normalized_ty,
|
2017-07-03 11:19:51 -07:00
|
|
|
obligations,
|
2016-05-21 08:30:52 -04:00
|
|
|
}
|
2014-12-30 17:42:02 -05:00
|
|
|
} else {
|
2016-05-21 08:30:52 -04:00
|
|
|
Normalized {
|
2014-12-30 17:42:02 -05:00
|
|
|
value: projected_ty,
|
2017-07-03 11:19:51 -07:00
|
|
|
obligations,
|
2016-05-21 08:30:52 -04:00
|
|
|
}
|
2016-05-21 08:29:50 -04:00
|
|
|
};
|
2016-05-21 08:30:52 -04:00
|
|
|
infcx.projection_cache.borrow_mut()
|
|
|
|
.complete(projection_ty, &result, cacheable);
|
|
|
|
Some(result)
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
Ok(ProjectedTy::NoProgress(projected_ty)) => {
|
2016-04-20 19:51:56 -04:00
|
|
|
debug!("opt_normalize_projection_type: \
|
|
|
|
projected_ty={:?} no progress",
|
2015-06-18 20:25:05 +03:00
|
|
|
projected_ty);
|
2016-05-21 08:30:52 -04:00
|
|
|
let result = Normalized {
|
2014-12-30 17:42:02 -05:00
|
|
|
value: projected_ty,
|
2016-10-29 22:54:04 +01:00
|
|
|
obligations: vec![]
|
2016-05-21 08:30:52 -04:00
|
|
|
};
|
|
|
|
infcx.projection_cache.borrow_mut()
|
|
|
|
.complete(projection_ty, &result, true);
|
|
|
|
Some(result)
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
Err(ProjectionTyError::TooManyCandidates) => {
|
2016-04-20 19:51:56 -04:00
|
|
|
debug!("opt_normalize_projection_type: \
|
|
|
|
too many candidates");
|
2016-05-21 08:30:52 -04:00
|
|
|
infcx.projection_cache.borrow_mut()
|
|
|
|
.ambiguous(projection_ty);
|
2014-12-30 17:42:02 -05:00
|
|
|
None
|
|
|
|
}
|
|
|
|
Err(ProjectionTyError::TraitSelectionError(_)) => {
|
2016-04-20 19:51:56 -04:00
|
|
|
debug!("opt_normalize_projection_type: ERROR");
|
2014-12-30 17:42:02 -05:00
|
|
|
// if we got an error processing the `T as Trait` part,
|
|
|
|
// just return `ty::err` but add the obligation `T :
|
|
|
|
// Trait`, which when processed will cause the error to be
|
|
|
|
// reported later
|
|
|
|
|
2016-05-21 08:30:52 -04:00
|
|
|
infcx.projection_cache.borrow_mut()
|
|
|
|
.error(projection_ty);
|
2017-05-23 04:19:47 -04:00
|
|
|
Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth))
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-07 13:51:16 -05:00
|
|
|
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
|
|
|
|
/// hold. In various error cases, we cannot generate a valid
|
|
|
|
/// normalized projection. Therefore, we create an inference variable
|
|
|
|
/// return an associated obligation that, when fulfilled, will lead to
|
|
|
|
/// an error.
|
2015-05-05 22:09:17 +03:00
|
|
|
///
|
2016-01-07 13:51:16 -05:00
|
|
|
/// Note that we used to return `TyError` here, but that was quite
|
|
|
|
/// dubious -- the premise was that an error would *eventually* be
|
|
|
|
/// reported, when the obligation was processed. But in general once
|
|
|
|
/// you see a `TyError` you are supposed to be able to assume that an
|
|
|
|
/// error *has been* reported, so that you can take whatever heuristic
|
|
|
|
/// paths you want to take. To make things worse, it was possible for
|
|
|
|
/// cycles to arise, where you basically had a setup like `<MyType<$0>
|
|
|
|
/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as
|
|
|
|
/// Trait>::Foo> to `[type error]` would lead to an obligation of
|
|
|
|
/// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report
|
|
|
|
/// an error for this obligation, but we legitimately should not,
|
|
|
|
/// because it contains `[type error]`. Yuck! (See issue #29857 for
|
|
|
|
/// one case where this arose.)
|
2016-04-29 06:00:23 +03:00
|
|
|
fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2016-04-29 06:00:23 +03:00
|
|
|
projection_ty: ty::ProjectionTy<'tcx>,
|
|
|
|
cause: ObligationCause<'tcx>,
|
|
|
|
depth: usize)
|
|
|
|
-> NormalizedTy<'tcx>
|
2014-12-30 17:42:02 -05:00
|
|
|
{
|
|
|
|
let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
|
2017-07-03 11:19:51 -07:00
|
|
|
let trait_obligation = Obligation { cause,
|
2014-12-30 17:42:02 -05:00
|
|
|
recursion_depth: depth,
|
2017-05-23 04:19:47 -04:00
|
|
|
param_env,
|
2015-06-23 11:50:50 -07:00
|
|
|
predicate: trait_ref.to_predicate() };
|
2016-11-28 10:08:08 -08:00
|
|
|
let tcx = selcx.infcx().tcx;
|
|
|
|
let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
|
2017-05-31 12:35:13 -04:00
|
|
|
i.name == projection_ty.item_name(tcx) && i.kind == ty::AssociatedKind::Type
|
2016-11-28 10:08:08 -08:00
|
|
|
).map(|i| i.def_id).unwrap();
|
|
|
|
let new_value = selcx.infcx().next_ty_var(
|
|
|
|
TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
|
2014-12-30 17:42:02 -05:00
|
|
|
Normalized {
|
2016-01-07 13:51:16 -05:00
|
|
|
value: new_value,
|
2016-10-29 22:54:04 +01:00
|
|
|
obligations: vec![trait_obligation]
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-30 17:42:02 -05:00
|
|
|
enum ProjectedTy<'tcx> {
|
2016-05-21 08:29:50 -04:00
|
|
|
Progress(Progress<'tcx>),
|
2014-12-30 17:42:02 -05:00
|
|
|
NoProgress(Ty<'tcx>),
|
|
|
|
}
|
|
|
|
|
2016-05-21 08:29:50 -04:00
|
|
|
struct Progress<'tcx> {
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
obligations: Vec<PredicateObligation<'tcx>>,
|
|
|
|
cacheable: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> Progress<'tcx> {
|
|
|
|
fn error<'a,'gcx>(tcx: TyCtxt<'a,'gcx,'tcx>) -> Self {
|
|
|
|
Progress {
|
|
|
|
ty: tcx.types.err,
|
|
|
|
obligations: vec![],
|
|
|
|
cacheable: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn with_addl_obligations(mut self,
|
|
|
|
mut obligations: Vec<PredicateObligation<'tcx>>)
|
|
|
|
-> Self {
|
2016-05-23 19:52:44 -04:00
|
|
|
debug!("with_addl_obligations: self.obligations.len={} obligations.len={}",
|
|
|
|
self.obligations.len(), obligations.len());
|
|
|
|
|
|
|
|
debug!("with_addl_obligations: self.obligations={:?} obligations={:?}",
|
|
|
|
self.obligations, obligations);
|
|
|
|
|
2016-05-21 08:29:50 -04:00
|
|
|
self.obligations.append(&mut obligations);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
/// Compute the result of a projection type (if we can).
|
2016-05-21 08:29:50 -04:00
|
|
|
///
|
|
|
|
/// IMPORTANT:
|
|
|
|
/// - `obligation` must be fully normalized
|
2016-04-29 06:00:23 +03:00
|
|
|
fn project_type<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2014-12-17 14:16:28 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>)
|
2014-12-30 17:42:02 -05:00
|
|
|
-> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>>
|
2014-12-17 14:16:28 -05:00
|
|
|
{
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("project(obligation={:?})",
|
|
|
|
obligation);
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2014-12-30 17:42:02 -05:00
|
|
|
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
|
|
|
|
if obligation.recursion_depth >= recursion_limit {
|
|
|
|
debug!("project: overflow!");
|
2016-03-17 00:15:31 +02:00
|
|
|
selcx.infcx().report_overflow_error(&obligation, true);
|
2014-12-30 17:42:02 -05:00
|
|
|
}
|
|
|
|
|
2016-05-21 08:29:50 -04:00
|
|
|
let obligation_trait_ref = &obligation.predicate.trait_ref;
|
2015-01-02 04:20:34 -05:00
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("project: obligation_trait_ref={:?}", obligation_trait_ref);
|
2015-01-02 04:20:34 -05:00
|
|
|
|
|
|
|
if obligation_trait_ref.references_error() {
|
2016-05-21 08:29:50 -04:00
|
|
|
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
|
2015-01-02 04:20:34 -05:00
|
|
|
}
|
|
|
|
|
2014-12-17 14:16:28 -05:00
|
|
|
let mut candidates = ProjectionTyCandidateSet {
|
|
|
|
vec: Vec::new(),
|
|
|
|
ambiguous: false,
|
|
|
|
};
|
|
|
|
|
2014-12-23 05:26:34 -05:00
|
|
|
assemble_candidates_from_param_env(selcx,
|
|
|
|
obligation,
|
2015-01-02 12:16:41 -08:00
|
|
|
&obligation_trait_ref,
|
2014-12-23 05:26:34 -05:00
|
|
|
&mut candidates);
|
|
|
|
|
2015-01-27 14:52:54 -05:00
|
|
|
assemble_candidates_from_trait_def(selcx,
|
|
|
|
obligation,
|
|
|
|
&obligation_trait_ref,
|
|
|
|
&mut candidates);
|
|
|
|
|
2014-12-23 05:26:34 -05:00
|
|
|
if let Err(e) = assemble_candidates_from_impls(selcx,
|
|
|
|
obligation,
|
2015-01-02 12:16:41 -08:00
|
|
|
&obligation_trait_ref,
|
2014-12-23 05:26:34 -05:00
|
|
|
&mut candidates) {
|
|
|
|
return Err(ProjectionTyError::TraitSelectionError(e));
|
2014-12-26 07:07:55 -05:00
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
|
|
|
|
debug!("{} candidates, ambiguous={}",
|
|
|
|
candidates.vec.len(),
|
|
|
|
candidates.ambiguous);
|
|
|
|
|
2015-10-22 12:28:47 -04:00
|
|
|
// Inherent ambiguity that prevents us from even enumerating the
|
|
|
|
// candidates.
|
|
|
|
if candidates.ambiguous {
|
|
|
|
return Err(ProjectionTyError::TooManyCandidates);
|
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2015-02-12 01:12:57 +08:00
|
|
|
// Drop duplicates.
|
|
|
|
//
|
|
|
|
// Note: `candidates.vec` seems to be on the critical path of the
|
|
|
|
// compiler. Replacing it with an hash set was also tried, which would
|
|
|
|
// render the following dedup unnecessary. It led to cleaner code but
|
|
|
|
// prolonged compiling time of `librustc` from 5m30s to 6m in one test, or
|
|
|
|
// ~9% performance lost.
|
|
|
|
if candidates.vec.len() > 1 {
|
|
|
|
let mut i = 0;
|
|
|
|
while i < candidates.vec.len() {
|
|
|
|
let has_dup = (0..i).any(|j| candidates.vec[i] == candidates.vec[j]);
|
|
|
|
if has_dup {
|
|
|
|
candidates.vec.swap_remove(i);
|
|
|
|
} else {
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-22 12:28:47 -04:00
|
|
|
// Prefer where-clauses. As in select, if there are multiple
|
|
|
|
// candidates, we prefer where-clause candidates over impls. This
|
|
|
|
// may seem a bit surprising, since impls are the source of
|
|
|
|
// "truth" in some sense, but in fact some of the impls that SEEM
|
|
|
|
// applicable are not, because of nested obligations. Where
|
|
|
|
// clauses are the safer choice. See the comment on
|
|
|
|
// `select::SelectionCandidate` and #21974 for more details.
|
|
|
|
if candidates.vec.len() > 1 {
|
|
|
|
debug!("retaining param-env candidates only from {:?}", candidates.vec);
|
|
|
|
candidates.vec.retain(|c| match *c {
|
|
|
|
ProjectionTyCandidate::ParamEnv(..) => true,
|
|
|
|
ProjectionTyCandidate::TraitDef(..) |
|
2016-03-15 06:10:01 -04:00
|
|
|
ProjectionTyCandidate::Select => false,
|
2015-10-22 12:28:47 -04:00
|
|
|
});
|
|
|
|
debug!("resulting candidate set: {:?}", candidates.vec);
|
|
|
|
if candidates.vec.len() != 1 {
|
|
|
|
return Err(ProjectionTyError::TooManyCandidates);
|
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
2015-10-22 12:28:47 -04:00
|
|
|
assert!(candidates.vec.len() <= 1);
|
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
match candidates.vec.pop() {
|
2014-12-17 14:16:28 -05:00
|
|
|
Some(candidate) => {
|
2016-05-21 08:29:50 -04:00
|
|
|
Ok(ProjectedTy::Progress(
|
|
|
|
confirm_candidate(selcx,
|
|
|
|
obligation,
|
|
|
|
&obligation_trait_ref,
|
|
|
|
candidate)))
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
None => {
|
2016-05-21 08:29:50 -04:00
|
|
|
Ok(ProjectedTy::NoProgress(
|
|
|
|
selcx.tcx().mk_projection(
|
|
|
|
obligation.predicate.trait_ref.clone(),
|
2017-05-31 12:35:13 -04:00
|
|
|
obligation.predicate.item_name(selcx.tcx()))))
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The first thing we have to do is scan through the parameter
|
|
|
|
/// environment to see whether there are any projection predicates
|
|
|
|
/// there that can answer this question.
|
2016-04-29 06:00:23 +03:00
|
|
|
fn assemble_candidates_from_param_env<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-02 04:20:34 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2015-04-21 18:59:58 +03:00
|
|
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
2014-12-17 14:16:28 -05:00
|
|
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
|
|
|
{
|
2015-10-22 12:28:47 -04:00
|
|
|
debug!("assemble_candidates_from_param_env(..)");
|
|
|
|
assemble_candidates_from_predicates(selcx,
|
|
|
|
obligation,
|
|
|
|
obligation_trait_ref,
|
|
|
|
candidate_set,
|
|
|
|
ProjectionTyCandidate::ParamEnv,
|
2017-05-23 04:19:47 -04:00
|
|
|
obligation.param_env.caller_bounds.iter().cloned());
|
2014-12-26 07:07:55 -05:00
|
|
|
}
|
|
|
|
|
2015-01-27 14:52:54 -05:00
|
|
|
/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
|
|
|
|
/// that the definition of `Foo` has some clues:
|
|
|
|
///
|
2015-03-12 22:42:38 -04:00
|
|
|
/// ```
|
2015-01-27 14:52:54 -05:00
|
|
|
/// trait Foo {
|
|
|
|
/// type FooT : Bar<BarT=i32>
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Here, for example, we could conclude that the result is `i32`.
|
2016-04-29 06:00:23 +03:00
|
|
|
fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-27 14:52:54 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2015-04-21 18:59:58 +03:00
|
|
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
2015-01-27 14:52:54 -05:00
|
|
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
|
|
|
{
|
2015-10-22 12:28:47 -04:00
|
|
|
debug!("assemble_candidates_from_trait_def(..)");
|
|
|
|
|
2015-01-27 14:52:54 -05:00
|
|
|
// Check whether the self-type is itself a projection.
|
2016-07-22 18:56:22 +03:00
|
|
|
let (def_id, substs) = match obligation_trait_ref.self_ty().sty {
|
|
|
|
ty::TyProjection(ref data) => {
|
|
|
|
(data.trait_ref.def_id, data.trait_ref.substs)
|
|
|
|
}
|
|
|
|
ty::TyAnon(def_id, substs) => (def_id, substs),
|
2015-06-11 16:21:46 -07:00
|
|
|
ty::TyInfer(ty::TyVar(_)) => {
|
2015-01-27 14:52:54 -05:00
|
|
|
// If the self-type is an inference variable, then it MAY wind up
|
|
|
|
// being a projected type, so induce an ambiguity.
|
|
|
|
candidate_set.ambiguous = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_ => { return; }
|
|
|
|
};
|
|
|
|
|
|
|
|
// If so, extract what we know from the trait and try to come up with a good answer.
|
2017-04-24 15:20:46 +03:00
|
|
|
let trait_predicates = selcx.tcx().predicates_of(def_id);
|
2016-07-22 18:56:22 +03:00
|
|
|
let bounds = trait_predicates.instantiate(selcx.tcx(), substs);
|
2016-06-13 20:10:32 +03:00
|
|
|
let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates);
|
2015-10-22 12:28:47 -04:00
|
|
|
assemble_candidates_from_predicates(selcx,
|
|
|
|
obligation,
|
|
|
|
obligation_trait_ref,
|
|
|
|
candidate_set,
|
|
|
|
ProjectionTyCandidate::TraitDef,
|
|
|
|
bounds)
|
2015-01-27 14:52:54 -05:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-02 04:20:34 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2015-04-21 18:59:58 +03:00
|
|
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
2014-12-26 07:07:55 -05:00
|
|
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
2015-10-22 12:28:47 -04:00
|
|
|
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
|
2015-05-11 17:02:56 -04:00
|
|
|
env_predicates: I)
|
2017-05-23 04:19:47 -04:00
|
|
|
where I: IntoIterator<Item=ty::Predicate<'tcx>>
|
2014-12-26 07:07:55 -05:00
|
|
|
{
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("assemble_candidates_from_predicates(obligation={:?})",
|
|
|
|
obligation);
|
2014-12-26 07:07:55 -05:00
|
|
|
let infcx = selcx.infcx();
|
2015-05-11 17:02:56 -04:00
|
|
|
for predicate in env_predicates {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("assemble_candidates_from_predicates: predicate={:?}",
|
|
|
|
predicate);
|
2014-12-17 14:16:28 -05:00
|
|
|
match predicate {
|
|
|
|
ty::Predicate::Projection(ref data) => {
|
2017-05-31 12:35:13 -04:00
|
|
|
let tcx = selcx.tcx();
|
|
|
|
let same_name = data.item_name(tcx) == obligation.predicate.item_name(tcx);
|
2015-01-06 13:41:14 -05:00
|
|
|
|
|
|
|
let is_match = same_name && infcx.probe(|_| {
|
2014-12-17 14:16:28 -05:00
|
|
|
let data_poly_trait_ref =
|
|
|
|
data.to_poly_trait_ref();
|
2015-01-10 11:54:15 -05:00
|
|
|
let obligation_poly_trait_ref =
|
|
|
|
obligation_trait_ref.to_poly_trait_ref();
|
2017-05-24 09:43:20 -04:00
|
|
|
infcx.at(&obligation.cause, obligation.param_env)
|
|
|
|
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
|
|
|
.map(|InferOk { obligations: _, value: () }| {
|
|
|
|
// FIXME(#32730) -- do we need to take obligations
|
|
|
|
// into account in any way? At the moment, no.
|
|
|
|
})
|
|
|
|
.is_ok()
|
2014-12-17 14:16:28 -05:00
|
|
|
});
|
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("assemble_candidates_from_predicates: candidate={:?} \
|
|
|
|
is_match={} same_name={}",
|
|
|
|
data, is_match, same_name);
|
2015-01-06 13:41:14 -05:00
|
|
|
|
2015-01-10 11:54:15 -05:00
|
|
|
if is_match {
|
2015-10-22 12:28:47 -04:00
|
|
|
candidate_set.vec.push(ctor(data.clone()));
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2014-12-30 17:42:02 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2015-04-21 18:59:58 +03:00
|
|
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
2014-12-17 14:16:28 -05:00
|
|
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
2014-12-30 17:42:02 -05:00
|
|
|
-> Result<(), SelectionError<'tcx>>
|
2014-12-17 14:16:28 -05:00
|
|
|
{
|
|
|
|
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
|
|
|
// start out by selecting the predicate `T as TraitRef<...>`:
|
2015-01-02 04:20:34 -05:00
|
|
|
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
|
|
|
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
2016-03-15 06:10:01 -04:00
|
|
|
selcx.infcx().probe(|_| {
|
|
|
|
let vtable = match selcx.select(&trait_obligation) {
|
|
|
|
Ok(Some(vtable)) => vtable,
|
|
|
|
Ok(None) => {
|
|
|
|
candidate_set.ambiguous = true;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
debug!("assemble_candidates_from_impls: selection error {:?}",
|
|
|
|
e);
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
};
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
match vtable {
|
|
|
|
super::VtableClosure(_) |
|
|
|
|
super::VtableFnPointer(_) |
|
|
|
|
super::VtableObject(_) => {
|
|
|
|
debug!("assemble_candidates_from_impls: vtable={:?}",
|
|
|
|
vtable);
|
2015-01-06 13:41:14 -05:00
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
candidate_set.vec.push(ProjectionTyCandidate::Select);
|
|
|
|
}
|
2016-07-01 19:32:53 +03:00
|
|
|
super::VtableImpl(ref impl_data) => {
|
2016-03-15 06:10:01 -04:00
|
|
|
// We have to be careful when projecting out of an
|
|
|
|
// impl because of specialization. If we are not in
|
|
|
|
// trans (i.e., projection mode is not "any"), and the
|
|
|
|
// impl's type is declared as default, then we disable
|
|
|
|
// projection (even if the trait ref is fully
|
|
|
|
// monomorphic). In the case where trait ref is not
|
|
|
|
// fully monomorphic (i.e., includes type parameters),
|
|
|
|
// this is because those type parameters may
|
|
|
|
// ultimately be bound to types from other crates that
|
|
|
|
// may have specialized impls we can't see. In the
|
|
|
|
// case where the trait ref IS fully monomorphic, this
|
|
|
|
// is a policy decision that we made in the RFC in
|
|
|
|
// order to preserve flexibility for the crate that
|
|
|
|
// defined the specializable impl to specialize later
|
|
|
|
// for existing types.
|
|
|
|
//
|
|
|
|
// In either case, we handle this by not adding a
|
|
|
|
// candidate for an impl if it contains a `default`
|
|
|
|
// type.
|
2017-05-16 17:31:18 +02:00
|
|
|
let node_item = assoc_ty_def(selcx,
|
|
|
|
impl_data.impl_def_id,
|
2017-05-31 12:35:13 -04:00
|
|
|
obligation.predicate.item_name(selcx.tcx()));
|
2017-05-16 17:31:18 +02:00
|
|
|
|
|
|
|
let is_default = if node_item.node.is_from_trait() {
|
|
|
|
// If true, the impl inherited a `type Foo = Bar`
|
|
|
|
// given in the trait, which is implicitly default.
|
|
|
|
// Otherwise, the impl did not specify `type` and
|
|
|
|
// neither did the trait:
|
|
|
|
//
|
|
|
|
// ```rust
|
|
|
|
// trait Foo { type T; }
|
|
|
|
// impl Foo for Bar { }
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// This is an error, but it will be
|
|
|
|
// reported in `check_impl_items_against_trait`.
|
|
|
|
// We accept it here but will flag it as
|
|
|
|
// an error when we confirm the candidate
|
|
|
|
// (which will ultimately lead to `normalize_to_error`
|
|
|
|
// being invoked).
|
|
|
|
node_item.item.defaultness.has_value()
|
|
|
|
} else {
|
|
|
|
node_item.item.defaultness.is_default() ||
|
|
|
|
selcx.tcx().impl_is_default(node_item.node.def_id())
|
|
|
|
};
|
|
|
|
|
|
|
|
// Only reveal a specializable default if we're past type-checking
|
|
|
|
// and the obligations is monomorphic, otherwise passes such as
|
|
|
|
// transmute checking and polymorphic MIR optimizations could
|
|
|
|
// get a result which isn't correct for all monomorphizations.
|
|
|
|
let new_candidate = if !is_default {
|
|
|
|
Some(ProjectionTyCandidate::Select)
|
2017-05-23 04:19:47 -04:00
|
|
|
} else if obligation.param_env.reveal == Reveal::All {
|
2017-05-16 17:31:18 +02:00
|
|
|
assert!(!poly_trait_ref.needs_infer());
|
|
|
|
if !poly_trait_ref.needs_subst() {
|
2016-07-01 19:32:53 +03:00
|
|
|
Some(ProjectionTyCandidate::Select)
|
2016-03-15 06:10:01 -04:00
|
|
|
} else {
|
2016-07-01 19:32:53 +03:00
|
|
|
None
|
2016-03-15 06:10:01 -04:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-16 17:31:18 +02:00
|
|
|
None
|
2016-03-15 06:10:01 -04:00
|
|
|
};
|
2017-05-16 17:31:18 +02:00
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
candidate_set.vec.extend(new_candidate);
|
|
|
|
}
|
|
|
|
super::VtableParam(..) => {
|
|
|
|
// This case tell us nothing about the value of an
|
|
|
|
// associated type. Consider:
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// trait SomeTrait { type Foo; }
|
|
|
|
// fn foo<T:SomeTrait>(...) { }
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// If the user writes `<T as SomeTrait>::Foo`, then the `T
|
|
|
|
// : SomeTrait` binding does not help us decide what the
|
|
|
|
// type `Foo` is (at least, not more specifically than
|
|
|
|
// what we already knew).
|
|
|
|
//
|
|
|
|
// But wait, you say! What about an example like this:
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// Doesn't the `T : Sometrait<Foo=usize>` predicate help
|
|
|
|
// resolve `T::Foo`? And of course it does, but in fact
|
|
|
|
// that single predicate is desugared into two predicates
|
|
|
|
// in the compiler: a trait predicate (`T : SomeTrait`) and a
|
|
|
|
// projection. And the projection where clause is handled
|
|
|
|
// in `assemble_candidates_from_param_env`.
|
|
|
|
}
|
|
|
|
super::VtableDefaultImpl(..) |
|
|
|
|
super::VtableBuiltin(..) => {
|
|
|
|
// These traits have no associated types.
|
|
|
|
span_bug!(
|
|
|
|
obligation.cause.span,
|
|
|
|
"Cannot project an associated type from `{:?}`",
|
|
|
|
vtable);
|
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
Ok(())
|
|
|
|
})
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn confirm_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2014-12-30 17:42:02 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2016-03-15 06:10:01 -04:00
|
|
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
2014-12-17 14:16:28 -05:00
|
|
|
candidate: ProjectionTyCandidate<'tcx>)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2014-12-17 14:16:28 -05:00
|
|
|
{
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("confirm_candidate(candidate={:?}, obligation={:?})",
|
|
|
|
candidate,
|
|
|
|
obligation);
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2014-12-30 17:42:02 -05:00
|
|
|
match candidate {
|
2015-10-22 12:28:47 -04:00
|
|
|
ProjectionTyCandidate::ParamEnv(poly_projection) |
|
|
|
|
ProjectionTyCandidate::TraitDef(poly_projection) => {
|
2015-01-10 11:54:15 -05:00
|
|
|
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
ProjectionTyCandidate::Select => {
|
|
|
|
confirm_select_candidate(selcx, obligation, obligation_trait_ref)
|
2015-01-10 11:54:15 -05:00
|
|
|
}
|
2016-03-15 06:10:01 -04:00
|
|
|
}
|
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
|
|
|
obligation_trait_ref: &ty::TraitRef<'tcx>)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2016-03-15 06:10:01 -04:00
|
|
|
{
|
|
|
|
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
|
|
|
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
|
|
|
let vtable = match selcx.select(&trait_obligation) {
|
|
|
|
Ok(Some(vtable)) => vtable,
|
|
|
|
_ => {
|
|
|
|
span_bug!(
|
|
|
|
obligation.cause.span,
|
|
|
|
"Failed to select `{:?}`",
|
|
|
|
trait_obligation);
|
2015-01-10 11:54:15 -05:00
|
|
|
}
|
2016-03-15 06:10:01 -04:00
|
|
|
};
|
2014-12-17 14:16:28 -05:00
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
match vtable {
|
|
|
|
super::VtableImpl(data) =>
|
|
|
|
confirm_impl_candidate(selcx, obligation, data),
|
|
|
|
super::VtableClosure(data) =>
|
|
|
|
confirm_closure_candidate(selcx, obligation, data),
|
|
|
|
super::VtableFnPointer(data) =>
|
|
|
|
confirm_fn_pointer_candidate(selcx, obligation, data),
|
|
|
|
super::VtableObject(_) =>
|
|
|
|
confirm_object_candidate(selcx, obligation, obligation_trait_ref),
|
|
|
|
super::VtableDefaultImpl(..) |
|
|
|
|
super::VtableParam(..) |
|
|
|
|
super::VtableBuiltin(..) =>
|
|
|
|
// we don't create Select candidates with this kind of resolution
|
|
|
|
span_bug!(
|
|
|
|
obligation.cause.span,
|
|
|
|
"Cannot project an associated type from `{:?}`",
|
|
|
|
vtable),
|
2015-01-10 11:54:15 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 06:10:01 -04:00
|
|
|
fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
|
|
|
obligation_trait_ref: &ty::TraitRef<'tcx>)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2016-03-15 06:10:01 -04:00
|
|
|
{
|
|
|
|
let self_ty = obligation_trait_ref.self_ty();
|
|
|
|
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
2016-04-04 15:28:52 -04:00
|
|
|
debug!("confirm_object_candidate(object_ty={:?})",
|
2016-03-15 06:10:01 -04:00
|
|
|
object_ty);
|
|
|
|
let data = match object_ty.sty {
|
2016-11-16 09:21:49 -07:00
|
|
|
ty::TyDynamic(ref data, ..) => data,
|
2016-03-15 06:10:01 -04:00
|
|
|
_ => {
|
|
|
|
span_bug!(
|
|
|
|
obligation.cause.span,
|
2016-04-04 15:28:52 -04:00
|
|
|
"confirm_object_candidate called with non-object: {:?}",
|
2016-05-21 08:29:50 -04:00
|
|
|
object_ty)
|
2016-03-15 06:10:01 -04:00
|
|
|
}
|
|
|
|
};
|
2016-11-16 09:21:49 -07:00
|
|
|
let env_predicates = data.projection_bounds().map(|p| {
|
2016-08-04 15:52:57 +03:00
|
|
|
p.with_self_ty(selcx.tcx(), object_ty).to_predicate()
|
|
|
|
}).collect();
|
2016-03-15 06:10:01 -04:00
|
|
|
let env_predicate = {
|
|
|
|
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
|
|
|
|
|
|
|
|
// select only those projections that are actually projecting an
|
|
|
|
// item with the correct name
|
2017-05-31 12:35:13 -04:00
|
|
|
let tcx = selcx.tcx();
|
2016-03-15 06:10:01 -04:00
|
|
|
let env_predicates = env_predicates.filter_map(|p| match p {
|
|
|
|
ty::Predicate::Projection(data) =>
|
2017-05-31 12:35:13 -04:00
|
|
|
if data.item_name(tcx) == obligation.predicate.item_name(tcx) {
|
2016-03-15 06:10:01 -04:00
|
|
|
Some(data)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
});
|
|
|
|
|
|
|
|
// select those with a relevant trait-ref
|
|
|
|
let mut env_predicates = env_predicates.filter(|data| {
|
|
|
|
let data_poly_trait_ref = data.to_poly_trait_ref();
|
|
|
|
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
|
|
|
selcx.infcx().probe(|_| {
|
2017-05-24 09:43:20 -04:00
|
|
|
selcx.infcx().at(&obligation.cause, obligation.param_env)
|
|
|
|
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
|
|
|
.is_ok()
|
2016-03-15 06:10:01 -04:00
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
// select the first matching one; there really ought to be one or
|
|
|
|
// else the object type is not WF, since an object type should
|
|
|
|
// include all of its projections explicitly
|
|
|
|
match env_predicates.next() {
|
|
|
|
Some(env_predicate) => env_predicate,
|
|
|
|
None => {
|
|
|
|
debug!("confirm_object_candidate: no env-predicate \
|
|
|
|
found in object type `{:?}`; ill-formed",
|
|
|
|
object_ty);
|
2016-05-21 08:29:50 -04:00
|
|
|
return Progress::error(selcx.tcx());
|
2016-03-15 06:10:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
confirm_param_env_candidate(selcx, obligation, env_predicate)
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-10 11:54:15 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2016-05-11 14:40:24 -07:00
|
|
|
fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2015-01-10 11:54:15 -05:00
|
|
|
{
|
2016-05-11 14:40:24 -07:00
|
|
|
let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty);
|
2017-05-13 17:11:52 +03:00
|
|
|
let sig = fn_type.fn_sig(selcx.tcx());
|
|
|
|
let Normalized {
|
|
|
|
value: sig,
|
|
|
|
obligations
|
|
|
|
} = normalize_with_depth(selcx,
|
|
|
|
obligation.param_env,
|
|
|
|
obligation.cause.clone(),
|
|
|
|
obligation.recursion_depth+1,
|
|
|
|
&sig);
|
|
|
|
|
2015-01-10 11:54:15 -05:00
|
|
|
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
|
2016-08-24 18:09:46 -04:00
|
|
|
.with_addl_obligations(fn_pointer_vtable.nested)
|
2017-05-13 17:11:52 +03:00
|
|
|
.with_addl_obligations(obligations)
|
2015-01-10 11:54:15 -05:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-10 11:54:15 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2015-06-10 00:09:37 +03:00
|
|
|
vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2015-01-10 11:54:15 -05:00
|
|
|
{
|
|
|
|
let closure_typer = selcx.closure_typer();
|
2017-05-13 13:12:29 +03:00
|
|
|
let closure_type = closure_typer.fn_sig(vtable.closure_def_id)
|
2017-02-13 23:26:32 +02:00
|
|
|
.subst(selcx.tcx(), vtable.substs.substs);
|
2015-06-10 00:09:37 +03:00
|
|
|
let Normalized {
|
|
|
|
value: closure_type,
|
2016-05-21 08:29:50 -04:00
|
|
|
obligations
|
2015-06-10 00:09:37 +03:00
|
|
|
} = normalize_with_depth(selcx,
|
2017-05-23 04:19:47 -04:00
|
|
|
obligation.param_env,
|
2015-06-10 00:09:37 +03:00
|
|
|
obligation.cause.clone(),
|
|
|
|
obligation.recursion_depth+1,
|
|
|
|
&closure_type);
|
2016-05-23 19:52:44 -04:00
|
|
|
|
|
|
|
debug!("confirm_closure_candidate: obligation={:?},closure_type={:?},obligations={:?}",
|
|
|
|
obligation,
|
|
|
|
closure_type,
|
|
|
|
obligations);
|
|
|
|
|
2016-05-21 08:29:50 -04:00
|
|
|
confirm_callable_candidate(selcx,
|
|
|
|
obligation,
|
2017-02-13 10:51:06 +02:00
|
|
|
closure_type,
|
2016-05-21 08:29:50 -04:00
|
|
|
util::TupleArgumentsFlag::No)
|
2016-05-23 19:52:44 -04:00
|
|
|
.with_addl_obligations(vtable.nested)
|
2016-11-29 00:12:07 +02:00
|
|
|
.with_addl_obligations(obligations)
|
2015-01-10 11:54:15 -05:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-10 11:54:15 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
2017-02-13 10:51:06 +02:00
|
|
|
fn_sig: ty::PolyFnSig<'tcx>,
|
2015-01-10 11:54:15 -05:00
|
|
|
flag: util::TupleArgumentsFlag)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2015-01-10 11:54:15 -05:00
|
|
|
{
|
|
|
|
let tcx = selcx.tcx();
|
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("confirm_callable_candidate({:?},{:?})",
|
|
|
|
obligation,
|
|
|
|
fn_sig);
|
2015-01-10 11:54:15 -05:00
|
|
|
|
2015-02-15 15:09:26 -05:00
|
|
|
// the `Output` associated type is declared on `FnOnce`
|
|
|
|
let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap();
|
|
|
|
|
2015-01-10 11:54:15 -05:00
|
|
|
// Note: we unwrap the binder here but re-create it below (1)
|
|
|
|
let ty::Binder((trait_ref, ret_type)) =
|
2016-03-17 00:15:31 +02:00
|
|
|
tcx.closure_trait_ref_and_return_type(fn_once_def_id,
|
|
|
|
obligation.predicate.trait_ref.self_ty(),
|
|
|
|
fn_sig,
|
|
|
|
flag);
|
2015-01-10 11:54:15 -05:00
|
|
|
|
|
|
|
let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here
|
2017-05-31 12:35:13 -04:00
|
|
|
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
|
|
|
tcx,
|
|
|
|
trait_ref,
|
|
|
|
Symbol::intern(FN_OUTPUT_NAME),
|
|
|
|
),
|
2015-01-10 11:54:15 -05:00
|
|
|
ty: ret_type
|
|
|
|
});
|
|
|
|
|
|
|
|
confirm_param_env_candidate(selcx, obligation, predicate)
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-10 11:54:15 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
|
|
|
poly_projection: ty::PolyProjectionPredicate<'tcx>)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2015-01-10 11:54:15 -05:00
|
|
|
{
|
|
|
|
let infcx = selcx.infcx();
|
2016-11-07 13:25:06 -05:00
|
|
|
let cause = obligation.cause.clone();
|
2017-05-23 04:19:47 -04:00
|
|
|
let param_env = obligation.param_env;
|
2016-05-21 08:29:50 -04:00
|
|
|
let trait_ref = obligation.predicate.trait_ref;
|
2017-05-23 04:19:47 -04:00
|
|
|
match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) {
|
2016-05-21 08:29:50 -04:00
|
|
|
Ok(InferOk { value: ty_match, obligations }) => {
|
|
|
|
Progress {
|
|
|
|
ty: ty_match.value,
|
2017-07-03 11:19:51 -07:00
|
|
|
obligations,
|
2016-05-21 08:29:50 -04:00
|
|
|
cacheable: ty_match.unconstrained_regions.is_empty(),
|
|
|
|
}
|
2016-03-29 20:06:42 -07:00
|
|
|
}
|
2015-01-10 11:54:15 -05:00
|
|
|
Err(e) => {
|
2016-03-25 18:31:27 +01:00
|
|
|
span_bug!(
|
2015-01-10 11:54:15 -05:00
|
|
|
obligation.cause.span,
|
2016-05-21 08:29:50 -04:00
|
|
|
"Failed to unify obligation `{:?}` \
|
|
|
|
with poly_projection `{:?}`: {:?}",
|
2016-03-25 18:31:27 +01:00
|
|
|
obligation,
|
2016-05-21 08:29:50 -04:00
|
|
|
poly_projection,
|
2016-03-25 18:31:27 +01:00
|
|
|
e);
|
2015-01-10 11:54:15 -05:00
|
|
|
}
|
2016-05-21 08:29:50 -04:00
|
|
|
}
|
2015-01-10 11:54:15 -05:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
2015-01-10 11:54:15 -05:00
|
|
|
obligation: &ProjectionTyObligation<'tcx>,
|
|
|
|
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
|
2016-05-21 08:29:50 -04:00
|
|
|
-> Progress<'tcx>
|
2015-01-10 11:54:15 -05:00
|
|
|
{
|
2015-12-29 13:37:34 -08:00
|
|
|
let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
|
2015-01-10 11:54:15 -05:00
|
|
|
|
2016-02-16 10:36:47 -08:00
|
|
|
let tcx = selcx.tcx();
|
2017-05-23 04:19:47 -04:00
|
|
|
let param_env = obligation.param_env;
|
2017-05-31 12:35:13 -04:00
|
|
|
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name(tcx));
|
2016-02-16 10:36:47 -08:00
|
|
|
|
2017-05-16 17:31:18 +02:00
|
|
|
let ty = if !assoc_ty.item.defaultness.has_value() {
|
|
|
|
// This means that the impl is missing a definition for the
|
|
|
|
// associated type. This error will be reported by the type
|
|
|
|
// checker method `check_impl_items_against_trait`, so here we
|
|
|
|
// just return TyError.
|
|
|
|
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
|
|
|
|
assoc_ty.item.name,
|
|
|
|
obligation.predicate.trait_ref);
|
|
|
|
tcx.types.err
|
|
|
|
} else {
|
|
|
|
tcx.type_of(assoc_ty.item.def_id)
|
|
|
|
};
|
2017-05-23 04:19:47 -04:00
|
|
|
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
|
2017-05-16 17:31:18 +02:00
|
|
|
Progress {
|
|
|
|
ty: ty.subst(tcx, substs),
|
|
|
|
obligations: nested,
|
|
|
|
cacheable: true
|
2016-02-16 10:36:47 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Locate the definition of an associated type in the specialization hierarchy,
|
|
|
|
/// starting from the given impl.
|
|
|
|
///
|
|
|
|
/// Based on the "projection mode", this lookup may in fact only examine the
|
2016-06-30 21:22:47 +03:00
|
|
|
/// topmost impl. See the comments for `Reveal` for more details.
|
2016-04-29 06:00:23 +03:00
|
|
|
fn assoc_ty_def<'cx, 'gcx, 'tcx>(
|
|
|
|
selcx: &SelectionContext<'cx, 'gcx, 'tcx>,
|
|
|
|
impl_def_id: DefId,
|
|
|
|
assoc_ty_name: ast::Name)
|
2017-05-16 17:31:18 +02:00
|
|
|
-> specialization_graph::NodeItem<ty::AssociatedItem>
|
2016-02-16 10:36:47 -08:00
|
|
|
{
|
2017-05-15 12:21:28 +02:00
|
|
|
let tcx = selcx.tcx();
|
|
|
|
let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
|
|
|
|
let trait_def = tcx.trait_def(trait_def_id);
|
|
|
|
|
|
|
|
// This function may be called while we are still building the
|
|
|
|
// specialization graph that is queried below (via TraidDef::ancestors()),
|
2017-05-16 15:03:20 +02:00
|
|
|
// so, in order to avoid unnecessary infinite recursion, we manually look
|
|
|
|
// for the associated item at the given impl.
|
|
|
|
// If there is no such item in that impl, this function will fail with a
|
|
|
|
// cycle error if the specialization graph is currently being built.
|
|
|
|
let impl_node = specialization_graph::Node::Impl(impl_def_id);
|
|
|
|
for item in impl_node.items(tcx) {
|
|
|
|
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
|
2017-05-16 17:31:18 +02:00
|
|
|
return specialization_graph::NodeItem {
|
2017-05-16 15:03:20 +02:00
|
|
|
node: specialization_graph::Node::Impl(impl_def_id),
|
2017-07-03 11:19:51 -07:00
|
|
|
item,
|
2017-05-16 17:31:18 +02:00
|
|
|
};
|
2017-05-15 12:21:28 +02:00
|
|
|
}
|
|
|
|
}
|
2017-05-16 15:03:20 +02:00
|
|
|
|
2017-05-16 17:31:18 +02:00
|
|
|
if let Some(assoc_item) = trait_def
|
2017-05-16 15:03:20 +02:00
|
|
|
.ancestors(tcx, impl_def_id)
|
|
|
|
.defs(tcx, assoc_ty_name, ty::AssociatedKind::Type)
|
2017-05-16 17:31:18 +02:00
|
|
|
.next() {
|
|
|
|
assoc_item
|
|
|
|
} else {
|
|
|
|
// This is saying that neither the trait nor
|
|
|
|
// the impl contain a definition for this
|
|
|
|
// associated type. Normally this situation
|
|
|
|
// could only arise through a compiler bug --
|
|
|
|
// if the user wrote a bad item name, it
|
|
|
|
// should have failed in astconv.
|
|
|
|
bug!("No associated type `{}` for {}",
|
|
|
|
assoc_ty_name,
|
|
|
|
tcx.item_path_str(impl_def_id))
|
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
2016-05-21 08:18:52 -04:00
|
|
|
|
|
|
|
// # Cache
|
|
|
|
|
|
|
|
pub struct ProjectionCache<'tcx> {
|
|
|
|
map: SnapshotMap<ty::ProjectionTy<'tcx>, ProjectionCacheEntry<'tcx>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
enum ProjectionCacheEntry<'tcx> {
|
|
|
|
InProgress,
|
|
|
|
Ambiguous,
|
|
|
|
Error,
|
|
|
|
NormalizedTy(Ty<'tcx>),
|
|
|
|
}
|
|
|
|
|
|
|
|
// NB: intentionally not Clone
|
|
|
|
pub struct ProjectionCacheSnapshot {
|
|
|
|
snapshot: Snapshot
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> ProjectionCache<'tcx> {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
ProjectionCache {
|
|
|
|
map: SnapshotMap::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn snapshot(&mut self) -> ProjectionCacheSnapshot {
|
|
|
|
ProjectionCacheSnapshot { snapshot: self.map.snapshot() }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) {
|
|
|
|
self.map.rollback_to(snapshot.snapshot);
|
|
|
|
}
|
|
|
|
|
2016-10-19 18:39:49 -04:00
|
|
|
pub fn rollback_skolemized(&mut self, snapshot: &ProjectionCacheSnapshot) {
|
|
|
|
self.map.partial_rollback(&snapshot.snapshot, &|k| k.has_re_skol());
|
2016-10-18 21:32:31 -04:00
|
|
|
}
|
|
|
|
|
2016-05-21 08:18:52 -04:00
|
|
|
pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) {
|
|
|
|
self.map.commit(snapshot.snapshot);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to start normalize `key`; returns an error if
|
|
|
|
/// normalization already occured (this error corresponds to a
|
|
|
|
/// cache hit, so it's actually a good thing).
|
|
|
|
fn try_start(&mut self, key: ty::ProjectionTy<'tcx>)
|
|
|
|
-> Result<(), ProjectionCacheEntry<'tcx>> {
|
2016-10-17 19:00:20 -07:00
|
|
|
if let Some(entry) = self.map.get(&key) {
|
|
|
|
return Err(entry.clone());
|
2016-05-21 08:18:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
self.map.insert(key, ProjectionCacheEntry::InProgress);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Indicates that `key` was normalized to `value`. If `cacheable` is false,
|
|
|
|
/// then this result is sadly not cacheable.
|
|
|
|
fn complete(&mut self,
|
|
|
|
key: ty::ProjectionTy<'tcx>,
|
|
|
|
value: &NormalizedTy<'tcx>,
|
|
|
|
cacheable: bool) {
|
|
|
|
let fresh_key = if cacheable {
|
|
|
|
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
|
|
|
|
key, value);
|
|
|
|
self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value))
|
|
|
|
} else {
|
|
|
|
debug!("ProjectionCacheEntry::complete: cannot cache: key={:?}, value={:?}",
|
|
|
|
key, value);
|
|
|
|
!self.map.remove(key)
|
|
|
|
};
|
|
|
|
|
|
|
|
assert!(!fresh_key, "never started projecting `{:?}`", key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Indicates that trying to normalize `key` resulted in
|
|
|
|
/// ambiguity. No point in trying it again then until we gain more
|
|
|
|
/// type information (in which case, the "fully resolved" key will
|
|
|
|
/// be different).
|
|
|
|
fn ambiguous(&mut self, key: ty::ProjectionTy<'tcx>) {
|
|
|
|
let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous);
|
|
|
|
assert!(!fresh, "never started projecting `{:?}`", key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Indicates that trying to normalize `key` resulted in
|
|
|
|
/// error.
|
|
|
|
fn error(&mut self, key: ty::ProjectionTy<'tcx>) {
|
|
|
|
let fresh = self.map.insert(key, ProjectionCacheEntry::Error);
|
|
|
|
assert!(!fresh, "never started projecting `{:?}`", key);
|
|
|
|
}
|
|
|
|
}
|