mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-25 14:13:38 +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>),
|
VtableImpl(VtableImplData<'tcx, N>),
|
||||||
|
|
||||||
/// Successful resolution to an obligation provided by the caller
|
/// Successful resolution to an obligation provided by the caller
|
||||||
/// for some type parameter.
|
/// for some type parameter. The `Vec<N>` represents the
|
||||||
VtableParam,
|
/// obligations incurred from normalizing the where-clause (if
|
||||||
|
/// any).
|
||||||
|
VtableParam(Vec<N>),
|
||||||
|
|
||||||
/// Virtual calls through an object
|
/// Virtual calls through an object
|
||||||
VtableObject(VtableObjectData<'tcx>),
|
VtableObject(VtableObjectData<'tcx>),
|
||||||
@ -443,7 +445,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||||||
VtableImpl(ref i) => i.iter_nested(),
|
VtableImpl(ref i) => i.iter_nested(),
|
||||||
VtableFnPointer(..) => (&[]).iter(),
|
VtableFnPointer(..) => (&[]).iter(),
|
||||||
VtableUnboxedClosure(..) => (&[]).iter(),
|
VtableUnboxedClosure(..) => (&[]).iter(),
|
||||||
VtableParam => (&[]).iter(),
|
VtableParam(ref n) => n.iter(),
|
||||||
VtableObject(_) => (&[]).iter(),
|
VtableObject(_) => (&[]).iter(),
|
||||||
VtableBuiltin(ref i) => i.iter_nested(),
|
VtableBuiltin(ref i) => i.iter_nested(),
|
||||||
}
|
}
|
||||||
@ -454,7 +456,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||||||
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
|
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
|
||||||
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
|
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
|
||||||
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.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()),
|
VtableObject(ref p) => VtableObject(p.clone()),
|
||||||
VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)),
|
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)),
|
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
|
||||||
VtableFnPointer(sig) => VtableFnPointer(sig),
|
VtableFnPointer(sig) => VtableFnPointer(sig),
|
||||||
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
|
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
|
||||||
VtableParam => VtableParam,
|
VtableParam(n) => VtableParam(n.into_iter().map(op).collect()),
|
||||||
VtableObject(p) => VtableObject(p),
|
VtableObject(p) => VtableObject(p),
|
||||||
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
|
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);
|
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());
|
debug!("candidate list size: {}", candidates.vec.len());
|
||||||
Ok(candidates)
|
Ok(candidates)
|
||||||
}
|
}
|
||||||
@ -884,13 +884,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
/// supplied to find out whether it is listed among them.
|
/// supplied to find out whether it is listed among them.
|
||||||
///
|
///
|
||||||
/// Never affects inference environment.
|
/// Never affects inference environment.
|
||||||
fn assemble_candidates_from_caller_bounds(&mut self,
|
fn assemble_candidates_from_caller_bounds<'o>(&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
stack: &TraitObligationStack<'o, 'tcx>,
|
||||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||||
-> Result<(),SelectionError<'tcx>>
|
-> Result<(),SelectionError<'tcx>>
|
||||||
{
|
{
|
||||||
debug!("assemble_candidates_from_caller_bounds({})",
|
debug!("assemble_candidates_from_caller_bounds({})",
|
||||||
obligation.repr(self.tcx()));
|
stack.obligation.repr(self.tcx()));
|
||||||
|
|
||||||
let caller_trait_refs: Vec<_> =
|
let caller_trait_refs: Vec<_> =
|
||||||
self.param_env().caller_bounds.predicates.iter()
|
self.param_env().caller_bounds.predicates.iter()
|
||||||
@ -903,8 +903,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
let matching_bounds =
|
let matching_bounds =
|
||||||
all_bounds.filter(
|
all_bounds.filter(
|
||||||
|bound| self.infcx.probe(
|
|bound| self.evaluate_where_clause(stack, bound.clone()).may_apply());
|
||||||
|_| self.match_poly_trait_ref(obligation, bound.clone())).is_ok());
|
|
||||||
|
|
||||||
let param_candidates =
|
let param_candidates =
|
||||||
matching_bounds.map(|bound| ParamCandidate(bound));
|
matching_bounds.map(|bound| ParamCandidate(bound));
|
||||||
@ -914,6 +913,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
Ok(())
|
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 :
|
/// Check for the artificial impl that the compiler will create for an obligation like `X :
|
||||||
/// FnMut<..>` where `X` is an unboxed closure type.
|
/// FnMut<..>` where `X` is an unboxed closure type.
|
||||||
///
|
///
|
||||||
@ -1140,6 +1156,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
candidate_j: &SelectionCandidate<'tcx>)
|
candidate_j: &SelectionCandidate<'tcx>)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
|
if candidate_i == candidate_j {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
match (candidate_i, candidate_j) {
|
match (candidate_i, candidate_j) {
|
||||||
(&ImplCandidate(impl_def_id), &ParamCandidate(ref bound)) => {
|
(&ImplCandidate(impl_def_id), &ParamCandidate(ref bound)) => {
|
||||||
debug!("Considering whether to drop param {} in favor of impl {}",
|
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.
|
// the where clauses are in scope.
|
||||||
true
|
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) => {
|
ParamCandidate(param) => {
|
||||||
self.confirm_param_candidate(obligation, param);
|
let obligations = self.confirm_param_candidate(obligation, param);
|
||||||
Ok(VtableParam)
|
Ok(VtableParam(obligations))
|
||||||
}
|
}
|
||||||
|
|
||||||
ImplCandidate(impl_def_id) => {
|
ImplCandidate(impl_def_id) => {
|
||||||
@ -1576,7 +1615,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
ProjectionCandidate => {
|
ProjectionCandidate => {
|
||||||
self.confirm_projection_candidate(obligation);
|
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,
|
fn confirm_param_candidate(&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
param: ty::PolyTraitRef<'tcx>)
|
param: ty::PolyTraitRef<'tcx>)
|
||||||
|
-> Vec<PredicateObligation<'tcx>>
|
||||||
{
|
{
|
||||||
debug!("confirm_param_candidate({},{})",
|
debug!("confirm_param_candidate({},{})",
|
||||||
obligation.repr(self.tcx()),
|
obligation.repr(self.tcx()),
|
||||||
@ -1606,11 +1646,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// where-clause trait-ref could be unified with the obligation
|
// where-clause trait-ref could be unified with the obligation
|
||||||
// trait-ref. Repeat that unification now without any
|
// trait-ref. Repeat that unification now without any
|
||||||
// transactional boundary; it should not fail.
|
// transactional boundary; it should not fail.
|
||||||
match self.confirm_poly_trait_refs(obligation.cause.clone(),
|
match self.match_where_clause_trait_ref(obligation, param.clone()) {
|
||||||
obligation.predicate.to_poly_trait_ref(),
|
Ok(obligations) => obligations,
|
||||||
param.clone()) {
|
Err(()) => {
|
||||||
Ok(()) => { }
|
|
||||||
Err(_) => {
|
|
||||||
self.tcx().sess.bug(
|
self.tcx().sess.bug(
|
||||||
format!("Where clause `{}` was applicable to `{}` but now is not",
|
format!("Where clause `{}` was applicable to `{}` but now is not",
|
||||||
param.repr(self.tcx()),
|
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,
|
fn match_poly_trait_ref(&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
|
poly_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||||
-> Result<(),()>
|
-> Result<(),()>
|
||||||
{
|
{
|
||||||
debug!("match_poly_trait_ref: obligation={} where_clause_trait_ref={}",
|
debug!("match_poly_trait_ref: obligation={} poly_trait_ref={}",
|
||||||
obligation.repr(self.tcx()),
|
obligation.repr(self.tcx()),
|
||||||
where_clause_trait_ref.repr(self.tcx()));
|
poly_trait_ref.repr(self.tcx()));
|
||||||
|
|
||||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||||
match self.infcx.sub_poly_trait_refs(false,
|
match self.infcx.sub_poly_trait_refs(false,
|
||||||
origin,
|
origin,
|
||||||
where_clause_trait_ref,
|
poly_trait_ref,
|
||||||
obligation.predicate.to_poly_trait_ref()) {
|
obligation.predicate.to_poly_trait_ref()) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(()),
|
||||||
|
@ -380,8 +380,9 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
|
|||||||
format!("VtableObject({})",
|
format!("VtableObject({})",
|
||||||
d.repr(tcx)),
|
d.repr(tcx)),
|
||||||
|
|
||||||
super::VtableParam =>
|
super::VtableParam(ref n) =>
|
||||||
format!("VtableParam"),
|
format!("VtableParam({})",
|
||||||
|
n.repr(tcx)),
|
||||||
|
|
||||||
super::VtableBuiltin(ref d) =>
|
super::VtableBuiltin(ref d) =>
|
||||||
d.repr(tcx)
|
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(ref d) => {
|
||||||
traits::VtableFnPointer(d.fold_with(folder))
|
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::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
|
||||||
traits::VtableObject(ref d) => traits::VtableObject(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: {}",
|
format!("cannot get vtable for an object type: {}",
|
||||||
data.repr(bcx.tcx())).as_slice());
|
data.repr(bcx.tcx())).as_slice());
|
||||||
}
|
}
|
||||||
traits::VtableParam => {
|
traits::VtableParam(..) => {
|
||||||
bcx.sess().bug(
|
bcx.sess().bug(
|
||||||
&format!("resolved vtable for {} to bad vtable {} in trans",
|
&format!("resolved vtable for {} to bad vtable {} in trans",
|
||||||
trait_ref.repr(bcx.tcx()),
|
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