Normalize types in impls, add test for coherence failure.

Fixes #20624.
This commit is contained in:
Niko Matsakis 2015-01-08 06:58:41 -05:00
parent 2f99a41fe1
commit bb0c8ef373
6 changed files with 122 additions and 31 deletions

View File

@ -28,7 +28,6 @@
#![feature(slicing_syntax, unsafe_destructor)]
#![feature(box_syntax)]
#![feature(rustc_diagnostic_macros)]
#![feature(old_impl_check)]
extern crate arena;
extern crate flate;

View File

@ -313,6 +313,17 @@ impl<T> VecPerParamSpace<T> {
self.content.insert(limit, value);
}
/// Appends `values` to the vector associated with `space`.
///
/// Unlike the `extend` method in `Vec`, this should not be assumed
/// to be a cheap operation (even when amortized over many calls).
pub fn extend<I:Iterator<Item=T>>(&mut self, space: ParamSpace, mut values: I) {
// This could be made more efficient, obviously.
for item in values {
self.push(space, item);
}
}
pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
let (start, limit) = self.limits(space);
if start == limit {

View File

@ -12,6 +12,7 @@
use super::SelectionContext;
use super::{Obligation, ObligationCause};
use super::project;
use super::util;
use middle::subst::{Subst};
@ -34,22 +35,28 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
impl1_def_id.repr(infcx.tcx),
impl2_def_id.repr(infcx.tcx));
let param_env = ty::empty_parameter_environment(infcx.tcx);
let mut selcx = SelectionContext::intercrate(infcx, &param_env);
let cause = ObligationCause::dummy();
// `impl1` provides an implementation of `Foo<X,Y> for Z`.
let impl1_substs =
util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id);
let impl1_trait_ref =
(*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs);
let impl1_trait_ref =
project::normalize(&mut selcx, cause.clone(), &impl1_trait_ref);
// Determine whether `impl2` can provide an implementation for those
// same types.
let param_env = ty::empty_parameter_environment(infcx.tcx);
let mut selcx = SelectionContext::intercrate(infcx, &param_env);
let obligation = Obligation::new(ObligationCause::dummy(),
let obligation = Obligation::new(cause,
ty::Binder(ty::TraitPredicate {
trait_ref: Rc::new(impl1_trait_ref),
trait_ref: Rc::new(impl1_trait_ref.value),
}));
debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx));
selcx.evaluate_impl(impl2_def_id, &obligation)
selcx.evaluate_impl(impl2_def_id, &obligation) &&
impl1_trait_ref.obligations.iter().all(
|o| selcx.evaluate_obligation(o))
}
#[allow(missing_copy_implementations)]

View File

@ -243,6 +243,13 @@ pub struct Normalized<'tcx,T> {
pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
impl<'tcx,T> Normalized<'tcx,T> {
fn with<U>(self, value: U) -> Normalized<'tcx,U> {
Normalized { value: value, obligations: self.obligations }
}
}
pub fn normalize_projection_type<'a,'b,'tcx>(
selcx: &'a mut SelectionContext<'b,'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,

View File

@ -19,6 +19,7 @@ use self::EvaluationResult::*;
use super::{DerivedObligationCause};
use super::{project};
use super::project::Normalized;
use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
use super::{ObligationCauseCode, BuiltinDerivedObligation};
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
@ -1160,7 +1161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let impl_trait_ref =
ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
let impl_trait_ref =
impl_trait_ref.subst(self.tcx(), &impl_substs);
impl_trait_ref.subst(self.tcx(), &impl_substs.value);
let poly_impl_trait_ref =
ty::Binder(impl_trait_ref);
let origin =
@ -1731,7 +1732,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let substs =
self.rematch_impl(impl_def_id, obligation,
snapshot, &skol_map, skol_obligation_trait_ref.trait_ref);
debug!("confirm_impl_candidate substs={:?}", substs);
debug!("confirm_impl_candidate substs={}", substs.repr(self.tcx()));
Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
obligation.recursion_depth + 1, skol_map, snapshot))
})
@ -1739,7 +1740,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn vtable_impl(&mut self,
impl_def_id: ast::DefId,
substs: Substs<'tcx>,
substs: Normalized<'tcx, Substs<'tcx>>,
cause: ObligationCause<'tcx>,
recursion_depth: uint,
skol_map: infer::SkolemizationMap,
@ -1752,21 +1753,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
recursion_depth,
skol_map.repr(self.tcx()));
let impl_predicates =
self.impl_predicates(cause,
let mut impl_obligations =
self.impl_obligations(cause,
recursion_depth,
impl_def_id,
&substs,
&substs.value,
skol_map,
snapshot);
debug!("vtable_impl: impl_def_id={} impl_predicates={}",
debug!("vtable_impl: impl_def_id={} impl_obligations={}",
impl_def_id.repr(self.tcx()),
impl_predicates.repr(self.tcx()));
impl_obligations.repr(self.tcx()));
impl_obligations.extend(TypeSpace, substs.obligations.into_iter());
VtableImplData { impl_def_id: impl_def_id,
substs: substs,
nested: impl_predicates }
substs: substs.value,
nested: impl_obligations }
}
fn confirm_object_candidate(&mut self,
@ -1950,7 +1953,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
snapshot: &infer::CombinedSnapshot,
skol_map: &infer::SkolemizationMap,
skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
-> Substs<'tcx>
-> Normalized<'tcx, Substs<'tcx>>
{
match self.match_impl(impl_def_id, obligation, snapshot,
skol_map, skol_obligation_trait_ref) {
@ -1972,7 +1975,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
snapshot: &infer::CombinedSnapshot,
skol_map: &infer::SkolemizationMap,
skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
-> Result<Substs<'tcx>, ()>
-> Result<Normalized<'tcx, Substs<'tcx>>, ()>
{
let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
@ -1990,6 +1993,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
&impl_substs);
let impl_trait_ref =
project::normalize_with_depth(self,
obligation.cause.clone(),
obligation.recursion_depth + 1,
&impl_trait_ref);
debug!("match_impl(impl_def_id={}, obligation={}, \
impl_trait_ref={}, skol_obligation_trait_ref={})",
impl_def_id.repr(self.tcx()),
@ -2000,7 +2009,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
match self.infcx.sub_trait_refs(false,
origin,
impl_trait_ref,
impl_trait_ref.value.clone(),
skol_obligation_trait_ref) {
Ok(()) => { }
Err(e) => {
@ -2020,7 +2029,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx()));
Ok(impl_substs)
Ok(Normalized { value: impl_substs,
obligations: impl_trait_ref.obligations })
}
fn fast_reject_trait_refs(&mut self,
@ -2161,7 +2171,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
fn impl_predicates(&mut self,
fn impl_obligations(&mut self,
cause: ObligationCause<'tcx>,
recursion_depth: uint,
impl_def_id: ast::DefId,
@ -2181,9 +2191,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
cause,
recursion_depth,
&normalized_bounds.value);
for obligation in normalized_bounds.obligations.into_iter() {
impl_obligations.push(TypeSpace, obligation);
}
impl_obligations.extend(TypeSpace, normalized_bounds.obligations.into_iter());
impl_obligations
}

View File

@ -0,0 +1,59 @@
// 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.
// Test that coherence detects overlap when some of the types in the
// impls are projections of associated type. Issue #20624.
use std::ops::Deref;
pub struct Cow<'a, B: ?Sized>;
/// Trait for moving into a `Cow`
pub trait IntoCow<'a, B: ?Sized> {
/// Moves `self` into `Cow`
fn into_cow(self) -> Cow<'a, B>;
}
impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
//~^ ERROR E0119
fn into_cow(self) -> Cow<'a, B> {
self
}
}
impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
//~^ ERROR E0119
fn into_cow(self) -> Cow<'a, B> {
Cow
}
}
impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned {
fn into_cow(self) -> Cow<'a, B> {
Cow
}
}
impl ToOwned for u8 {
type Owned = &'static u8;
fn to_owned(&self) -> &'static u8 { panic!() }
}
/// A generalization of Clone to borrowed data.
pub trait ToOwned {
type Owned;
/// Create owned data from borrowed data, usually by copying.
fn to_owned(&self) -> Self::Owned;
}
fn main() {}