Skip to content

Commit

Permalink
change to use higher_ranked_match
Browse files Browse the repository at this point in the history
also, consolidate the return type into from a tuple into a struct
`Progress`
  • Loading branch information
nikomatsakis committed May 31, 2016
1 parent 21eb366 commit 24d4f10
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 60 deletions.
7 changes: 4 additions & 3 deletions src/librustc/infer/mod.rs
Expand Up @@ -1619,7 +1619,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
origin: TypeOrigin,
match_a: ty::PolyProjectionPredicate<'tcx>,
match_b: ty::TraitRef<'tcx>)
-> RelateResult<HrMatchResult<Ty<'tcx>>>
-> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
{
let span = origin.span();
let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref;
Expand All @@ -1629,8 +1629,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
};

let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
self.combine_fields(true, trace)
.higher_ranked_match(span, &match_pair, &match_b)
let combine = self.combine_fields(true, trace);
let result = combine.higher_ranked_match(span, &match_pair, &match_b)?;
Ok(InferOk { value: result, obligations: combine.obligations })
}

/// See `verify_generic_bound` method in `region_inference`
Expand Down
143 changes: 86 additions & 57 deletions src/librustc/traits/project.rs
Expand Up @@ -28,6 +28,7 @@ use infer::{self, InferOk, TypeOrigin};
use ty::subst::Subst;
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder};
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use syntax::parse::token;
use syntax::ast;
use util::common::FN_OUTPUT_NAME;
Expand Down Expand Up @@ -424,19 +425,25 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(

let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
match project_type(selcx, &obligation) {
Ok(ProjectedTy::Progress(projected_ty, mut obligations)) => {
Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
mut obligations,
cacheable })) => {
// 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

debug!("opt_normalize_projection_type: \
projected_ty={:?} depth={} obligations={:?}",
projected_ty={:?} \
depth={} \
obligations={:?} \
cacheable={:?}",
projected_ty,
depth,
obligations);
obligations,
cacheable);

if projected_ty.has_projection_types() {
let result = if projected_ty.has_projection_types() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth+1);
let normalized_ty = normalizer.fold(&projected_ty);

Expand All @@ -455,7 +462,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
value: projected_ty,
obligations: obligations,
})
}
};

result
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
debug!("opt_normalize_projection_type: \
Expand Down Expand Up @@ -520,11 +529,37 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
}

enum ProjectedTy<'tcx> {
Progress(Ty<'tcx>, Vec<PredicateObligation<'tcx>>),
Progress(Progress<'tcx>),
NoProgress(Ty<'tcx>),
}

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 {
self.obligations.append(&mut obligations);
self
}
}

/// Compute the result of a projection type (if we can).
///
/// IMPORTANT:
/// - `obligation` must be fully normalized
fn project_type<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>)
Expand All @@ -539,13 +574,12 @@ fn project_type<'cx, 'gcx, 'tcx>(
selcx.infcx().report_overflow_error(&obligation, true);
}

let obligation_trait_ref =
selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate.trait_ref);
let obligation_trait_ref = &obligation.predicate.trait_ref;

debug!("project: obligation_trait_ref={:?}", obligation_trait_ref);

if obligation_trait_ref.references_error() {
return Ok(ProjectedTy::Progress(selcx.tcx().types.err, vec!()));
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
}

let mut candidates = ProjectionTyCandidateSet {
Expand Down Expand Up @@ -623,16 +657,17 @@ fn project_type<'cx, 'gcx, 'tcx>(

match candidates.vec.pop() {
Some(candidate) => {
let (ty, obligations) = confirm_candidate(selcx,
obligation,
&obligation_trait_ref,
candidate);
Ok(ProjectedTy::Progress(ty, obligations))
Ok(ProjectedTy::Progress(
confirm_candidate(selcx,
obligation,
&obligation_trait_ref,
candidate)))
}
None => {
Ok(ProjectedTy::NoProgress(selcx.tcx().mk_projection(
obligation.predicate.trait_ref.clone(),
obligation.predicate.item_name)))
Ok(ProjectedTy::NoProgress(
selcx.tcx().mk_projection(
obligation.predicate.trait_ref.clone(),
obligation.predicate.item_name)))
}
}
}
Expand Down Expand Up @@ -935,7 +970,7 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate: ProjectionTyCandidate<'tcx>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
debug!("confirm_candidate(candidate={:?}, obligation={:?})",
candidate,
Expand All @@ -957,7 +992,7 @@ fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
obligation_trait_ref: &ty::TraitRef<'tcx>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
Expand Down Expand Up @@ -995,7 +1030,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
obligation_trait_ref: &ty::TraitRef<'tcx>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
let self_ty = obligation_trait_ref.self_ty();
let object_ty = selcx.infcx().shallow_resolve(self_ty);
Expand All @@ -1007,7 +1042,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
span_bug!(
obligation.cause.span,
"confirm_object_candidate called with non-object: {:?}",
object_ty);
object_ty)
}
};
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
Expand Down Expand Up @@ -1051,7 +1086,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
debug!("confirm_object_candidate: no env-predicate \
found in object type `{:?}`; ill-formed",
object_ty);
return (selcx.tcx().types.err, vec!());
return Progress::error(selcx.tcx());
}
}
};
Expand All @@ -1063,7 +1098,7 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
// FIXME(#32730) drop this assertion once obligations are propagated from inference (fn pointer
// vtable nested obligations ONLY come from unification in inference)
Expand All @@ -1077,31 +1112,30 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
let closure_typer = selcx.closure_typer();
let closure_type = closure_typer.closure_type(vtable.closure_def_id, vtable.substs);
let Normalized {
value: closure_type,
mut obligations
obligations
} = normalize_with_depth(selcx,
obligation.cause.clone(),
obligation.recursion_depth+1,
&closure_type);
let (ty, mut cc_obligations) = confirm_callable_candidate(selcx,
obligation,
&closure_type.sig,
util::TupleArgumentsFlag::No);
obligations.append(&mut cc_obligations);
(ty, obligations)
confirm_callable_candidate(selcx,
obligation,
&closure_type.sig,
util::TupleArgumentsFlag::No)
.with_addl_obligations(obligations)
}

fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
fn_sig: &ty::PolyFnSig<'tcx>,
flag: util::TupleArgumentsFlag)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
let tcx = selcx.tcx();

Expand Down Expand Up @@ -1134,47 +1168,38 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
poly_projection: ty::PolyProjectionPredicate<'tcx>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
let infcx = selcx.infcx();

let projection =
infcx.replace_late_bound_regions_with_fresh_var(
obligation.cause.span,
infer::LateBoundRegionConversionTime::HigherRankedType,
&poly_projection).0;

assert_eq!(projection.projection_ty.item_name,
obligation.predicate.item_name);

let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
let obligations = match infcx.eq_trait_refs(false,
origin,
obligation.predicate.trait_ref.clone(),
projection.projection_ty.trait_ref.clone()) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) once obligations are generated in inference, remove this assertion
let trait_ref = obligation.predicate.trait_ref;
match infcx.match_poly_projection_predicate(origin, poly_projection, trait_ref) {
Ok(InferOk { value: ty_match, obligations }) => {
// FIXME(#32730) once obligations are generated in inference, drop this assertion
assert!(obligations.is_empty());
obligations
Progress {
ty: ty_match.value,
obligations: obligations,
cacheable: ty_match.unconstrained_regions.is_empty(),
}
}
Err(e) => {
span_bug!(
obligation.cause.span,
"Failed to unify `{:?}` and `{:?}` in projection: {}",
"Failed to unify obligation `{:?}` \
with poly_projection `{:?}`: {:?}",
obligation,
projection,
poly_projection,
e);
}
};

(projection.ty, obligations)
}
}

fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
let VtableImplData { substs, nested, impl_def_id } = impl_vtable;

Expand All @@ -1195,7 +1220,11 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
tcx.types.err
});
let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node);
(ty.subst(tcx, substs), nested)
Progress {
ty: ty.subst(tcx, substs),
obligations: nested,
cacheable: true
}
}
None => {
span_bug!(obligation.cause.span,
Expand Down

0 comments on commit 24d4f10

Please sign in to comment.