mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 14:57:14 +00:00
Normalize bounds that we extract from where clauses. Fixes #20765.
This commit is contained in:
parent
b21a6da340
commit
47424cda1e
@ -218,8 +218,10 @@ pub enum Vtable<'tcx, N> {
|
||||
VtableImpl(VtableImplData<'tcx, N>),
|
||||
|
||||
/// Successful resolution to an obligation provided by the caller
|
||||
/// for some type parameter.
|
||||
VtableParam,
|
||||
/// for some type parameter. The `Vec<N>` represents the
|
||||
/// obligations incurred from normalizing the where-clause (if
|
||||
/// any).
|
||||
VtableParam(Vec<N>),
|
||||
|
||||
/// Virtual calls through an object
|
||||
VtableObject(VtableObjectData<'tcx>),
|
||||
@ -443,7 +445,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
VtableImpl(ref i) => i.iter_nested(),
|
||||
VtableFnPointer(..) => (&[]).iter(),
|
||||
VtableUnboxedClosure(..) => (&[]).iter(),
|
||||
VtableParam => (&[]).iter(),
|
||||
VtableParam(ref n) => n.iter(),
|
||||
VtableObject(_) => (&[]).iter(),
|
||||
VtableBuiltin(ref i) => i.iter_nested(),
|
||||
}
|
||||
@ -454,7 +456,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
|
||||
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
|
||||
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
|
||||
VtableParam => VtableParam,
|
||||
VtableParam(ref n) => VtableParam(n.iter().map(op).collect()),
|
||||
VtableObject(ref p) => VtableObject(p.clone()),
|
||||
VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)),
|
||||
}
|
||||
@ -467,7 +469,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
|
||||
VtableFnPointer(sig) => VtableFnPointer(sig),
|
||||
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
|
||||
VtableParam => VtableParam,
|
||||
VtableParam(n) => VtableParam(n.into_iter().map(op).collect()),
|
||||
VtableObject(p) => VtableObject(p),
|
||||
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
|
||||
}
|
||||
|
@ -747,7 +747,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
|
||||
try!(self.assemble_candidates_from_caller_bounds(obligation, &mut candidates));
|
||||
try!(self.assemble_candidates_from_caller_bounds(stack, &mut candidates));
|
||||
debug!("candidate list size: {}", candidates.vec.len());
|
||||
Ok(candidates)
|
||||
}
|
||||
@ -884,13 +884,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// supplied to find out whether it is listed among them.
|
||||
///
|
||||
/// Never affects inference environment.
|
||||
fn assemble_candidates_from_caller_bounds(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
fn assemble_candidates_from_caller_bounds<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
debug!("assemble_candidates_from_caller_bounds({})",
|
||||
obligation.repr(self.tcx()));
|
||||
stack.obligation.repr(self.tcx()));
|
||||
|
||||
let caller_trait_refs: Vec<_> =
|
||||
self.param_env().caller_bounds.predicates.iter()
|
||||
@ -903,8 +903,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
let matching_bounds =
|
||||
all_bounds.filter(
|
||||
|bound| self.infcx.probe(
|
||||
|_| self.match_poly_trait_ref(obligation, bound.clone())).is_ok());
|
||||
|bound| self.evaluate_where_clause(stack, bound.clone()).may_apply());
|
||||
|
||||
let param_candidates =
|
||||
matching_bounds.map(|bound| ParamCandidate(bound));
|
||||
@ -914,6 +913,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn evaluate_where_clause<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> EvaluationResult<'tcx>
|
||||
{
|
||||
self.infcx().probe(move |_| {
|
||||
match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
|
||||
Ok(obligations) => {
|
||||
self.evaluate_predicates_recursively(Some(stack), obligations.iter())
|
||||
}
|
||||
Err(()) => {
|
||||
EvaluatedToErr(Unimplemented)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Check for the artificial impl that the compiler will create for an obligation like `X :
|
||||
/// FnMut<..>` where `X` is an unboxed closure type.
|
||||
///
|
||||
@ -1140,6 +1156,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
candidate_j: &SelectionCandidate<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
if candidate_i == candidate_j {
|
||||
return true;
|
||||
}
|
||||
|
||||
match (candidate_i, candidate_j) {
|
||||
(&ImplCandidate(impl_def_id), &ParamCandidate(ref bound)) => {
|
||||
debug!("Considering whether to drop param {} in favor of impl {}",
|
||||
@ -1179,8 +1199,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// the where clauses are in scope.
|
||||
true
|
||||
}
|
||||
(&ParamCandidate(ref bound1), &ParamCandidate(ref bound2)) => {
|
||||
self.infcx.probe(|_| {
|
||||
let bound1 =
|
||||
project::normalize_with_depth(self,
|
||||
stack.obligation.cause.clone(),
|
||||
stack.obligation.recursion_depth+1,
|
||||
bound1);
|
||||
let bound2 =
|
||||
project::normalize_with_depth(self,
|
||||
stack.obligation.cause.clone(),
|
||||
stack.obligation.recursion_depth+1,
|
||||
bound2);
|
||||
let origin =
|
||||
infer::RelateOutputImplTypes(stack.obligation.cause.span);
|
||||
self.infcx
|
||||
.sub_poly_trait_refs(false, origin, bound1.value, bound2.value)
|
||||
.is_ok()
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
*candidate_i == *candidate_j
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1548,8 +1587,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
ParamCandidate(param) => {
|
||||
self.confirm_param_candidate(obligation, param);
|
||||
Ok(VtableParam)
|
||||
let obligations = self.confirm_param_candidate(obligation, param);
|
||||
Ok(VtableParam(obligations))
|
||||
}
|
||||
|
||||
ImplCandidate(impl_def_id) => {
|
||||
@ -1576,7 +1615,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
ProjectionCandidate => {
|
||||
self.confirm_projection_candidate(obligation);
|
||||
Ok(VtableParam)
|
||||
Ok(VtableParam(Vec::new()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1597,6 +1636,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
fn confirm_param_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
param: ty::PolyTraitRef<'tcx>)
|
||||
-> Vec<PredicateObligation<'tcx>>
|
||||
{
|
||||
debug!("confirm_param_candidate({},{})",
|
||||
obligation.repr(self.tcx()),
|
||||
@ -1606,11 +1646,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// where-clause trait-ref could be unified with the obligation
|
||||
// trait-ref. Repeat that unification now without any
|
||||
// transactional boundary; it should not fail.
|
||||
match self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
param.clone()) {
|
||||
Ok(()) => { }
|
||||
Err(_) => {
|
||||
match self.match_where_clause_trait_ref(obligation, param.clone()) {
|
||||
Ok(obligations) => obligations,
|
||||
Err(()) => {
|
||||
self.tcx().sess.bug(
|
||||
format!("Where clause `{}` was applicable to `{}` but now is not",
|
||||
param.repr(self.tcx()),
|
||||
@ -2037,19 +2075,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Normalize `where_clause_trait_ref` and try to match it against
|
||||
/// `obligation`. If successful, return any predicates that
|
||||
/// result from the normalization. Normalization is necessary
|
||||
/// because where-clauses are stored in the parameter environment
|
||||
/// unnormalized.
|
||||
fn match_where_clause_trait_ref(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Result<Vec<PredicateObligation<'tcx>>,()>
|
||||
{
|
||||
let where_clause_trait_ref =
|
||||
project::normalize_with_depth(self,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth+1,
|
||||
&where_clause_trait_ref);
|
||||
|
||||
let () =
|
||||
try!(self.match_poly_trait_ref(obligation, where_clause_trait_ref.value.clone()));
|
||||
|
||||
Ok(where_clause_trait_ref.obligations)
|
||||
}
|
||||
|
||||
/// Returns `Ok` if `poly_trait_ref` being true implies that the
|
||||
/// obligation is satisfied.
|
||||
fn match_poly_trait_ref(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Result<(),()>
|
||||
{
|
||||
debug!("match_poly_trait_ref: obligation={} where_clause_trait_ref={}",
|
||||
debug!("match_poly_trait_ref: obligation={} poly_trait_ref={}",
|
||||
obligation.repr(self.tcx()),
|
||||
where_clause_trait_ref.repr(self.tcx()));
|
||||
poly_trait_ref.repr(self.tcx()));
|
||||
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
match self.infcx.sub_poly_trait_refs(false,
|
||||
origin,
|
||||
where_clause_trait_ref,
|
||||
poly_trait_ref,
|
||||
obligation.predicate.to_poly_trait_ref()) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(_) => Err(()),
|
||||
|
@ -380,8 +380,9 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
|
||||
format!("VtableObject({})",
|
||||
d.repr(tcx)),
|
||||
|
||||
super::VtableParam =>
|
||||
format!("VtableParam"),
|
||||
super::VtableParam(ref n) =>
|
||||
format!("VtableParam({})",
|
||||
n.repr(tcx)),
|
||||
|
||||
super::VtableBuiltin(ref d) =>
|
||||
d.repr(tcx)
|
||||
|
@ -514,7 +514,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
|
||||
traits::VtableFnPointer(ref d) => {
|
||||
traits::VtableFnPointer(d.fold_with(folder))
|
||||
}
|
||||
traits::VtableParam => traits::VtableParam,
|
||||
traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
|
||||
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
|
||||
traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
|
||||
}
|
||||
|
@ -736,7 +736,7 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
format!("cannot get vtable for an object type: {}",
|
||||
data.repr(bcx.tcx())).as_slice());
|
||||
}
|
||||
traits::VtableParam => {
|
||||
traits::VtableParam(..) => {
|
||||
bcx.sess().bug(
|
||||
&format!("resolved vtable for {} to bad vtable {} in trans",
|
||||
trait_ref.repr(bcx.tcx()),
|
||||
|
@ -0,0 +1,34 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Test a where clause that uses a non-normalized projection type.
|
||||
|
||||
trait Int
|
||||
{
|
||||
type T;
|
||||
}
|
||||
|
||||
trait NonZero
|
||||
{
|
||||
fn non_zero(self) -> bool;
|
||||
}
|
||||
|
||||
fn foo<I:Int<T=J>,J>(t: I) -> bool
|
||||
where <I as Int>::T : NonZero
|
||||
// ^~~~~~~~~~~~~ canonical form is just J
|
||||
{
|
||||
bar::<J>()
|
||||
}
|
||||
|
||||
fn bar<NZ:NonZero>() -> bool { true }
|
||||
|
||||
fn main ()
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue
Block a user