Skip to content

Commit bb0c8ef

Browse files
committed
Normalize types in impls, add test for coherence failure.
Fixes #20624.
1 parent 2f99a41 commit bb0c8ef

File tree

6 files changed

+122
-31
lines changed

6 files changed

+122
-31
lines changed

src/librustc/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#![feature(slicing_syntax, unsafe_destructor)]
2929
#![feature(box_syntax)]
3030
#![feature(rustc_diagnostic_macros)]
31-
#![feature(old_impl_check)]
3231

3332
extern crate arena;
3433
extern crate flate;

src/librustc/middle/subst.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,17 @@ impl<T> VecPerParamSpace<T> {
313313
self.content.insert(limit, value);
314314
}
315315

316+
/// Appends `values` to the vector associated with `space`.
317+
///
318+
/// Unlike the `extend` method in `Vec`, this should not be assumed
319+
/// to be a cheap operation (even when amortized over many calls).
320+
pub fn extend<I:Iterator<Item=T>>(&mut self, space: ParamSpace, mut values: I) {
321+
// This could be made more efficient, obviously.
322+
for item in values {
323+
self.push(space, item);
324+
}
325+
}
326+
316327
pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
317328
let (start, limit) = self.limits(space);
318329
if start == limit {

src/librustc/middle/traits/coherence.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
1313
use super::SelectionContext;
1414
use super::{Obligation, ObligationCause};
15+
use super::project;
1516
use super::util;
1617

1718
use middle::subst::{Subst};
@@ -34,22 +35,28 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
3435
impl1_def_id.repr(infcx.tcx),
3536
impl2_def_id.repr(infcx.tcx));
3637

38+
let param_env = ty::empty_parameter_environment(infcx.tcx);
39+
let mut selcx = SelectionContext::intercrate(infcx, &param_env);
40+
let cause = ObligationCause::dummy();
41+
3742
// `impl1` provides an implementation of `Foo<X,Y> for Z`.
3843
let impl1_substs =
3944
util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id);
4045
let impl1_trait_ref =
4146
(*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs);
47+
let impl1_trait_ref =
48+
project::normalize(&mut selcx, cause.clone(), &impl1_trait_ref);
4249

4350
// Determine whether `impl2` can provide an implementation for those
4451
// same types.
45-
let param_env = ty::empty_parameter_environment(infcx.tcx);
46-
let mut selcx = SelectionContext::intercrate(infcx, &param_env);
47-
let obligation = Obligation::new(ObligationCause::dummy(),
52+
let obligation = Obligation::new(cause,
4853
ty::Binder(ty::TraitPredicate {
49-
trait_ref: Rc::new(impl1_trait_ref),
54+
trait_ref: Rc::new(impl1_trait_ref.value),
5055
}));
5156
debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx));
52-
selcx.evaluate_impl(impl2_def_id, &obligation)
57+
selcx.evaluate_impl(impl2_def_id, &obligation) &&
58+
impl1_trait_ref.obligations.iter().all(
59+
|o| selcx.evaluate_obligation(o))
5360
}
5461

5562
#[allow(missing_copy_implementations)]

src/librustc/middle/traits/project.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ pub struct Normalized<'tcx,T> {
243243

244244
pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
245245

246+
impl<'tcx,T> Normalized<'tcx,T> {
247+
fn with<U>(self, value: U) -> Normalized<'tcx,U> {
248+
Normalized { value: value, obligations: self.obligations }
249+
}
250+
}
251+
252+
246253
pub fn normalize_projection_type<'a,'b,'tcx>(
247254
selcx: &'a mut SelectionContext<'b,'tcx>,
248255
projection_ty: ty::ProjectionTy<'tcx>,

src/librustc/middle/traits/select.rs

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use self::EvaluationResult::*;
1919

2020
use super::{DerivedObligationCause};
2121
use super::{project};
22+
use super::project::Normalized;
2223
use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
2324
use super::{ObligationCauseCode, BuiltinDerivedObligation};
2425
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
@@ -1160,7 +1161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11601161
let impl_trait_ref =
11611162
ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
11621163
let impl_trait_ref =
1163-
impl_trait_ref.subst(self.tcx(), &impl_substs);
1164+
impl_trait_ref.subst(self.tcx(), &impl_substs.value);
11641165
let poly_impl_trait_ref =
11651166
ty::Binder(impl_trait_ref);
11661167
let origin =
@@ -1731,15 +1732,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17311732
let substs =
17321733
self.rematch_impl(impl_def_id, obligation,
17331734
snapshot, &skol_map, skol_obligation_trait_ref.trait_ref);
1734-
debug!("confirm_impl_candidate substs={:?}", substs);
1735+
debug!("confirm_impl_candidate substs={}", substs.repr(self.tcx()));
17351736
Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
17361737
obligation.recursion_depth + 1, skol_map, snapshot))
17371738
})
17381739
}
17391740

17401741
fn vtable_impl(&mut self,
17411742
impl_def_id: ast::DefId,
1742-
substs: Substs<'tcx>,
1743+
substs: Normalized<'tcx, Substs<'tcx>>,
17431744
cause: ObligationCause<'tcx>,
17441745
recursion_depth: uint,
17451746
skol_map: infer::SkolemizationMap,
@@ -1752,21 +1753,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17521753
recursion_depth,
17531754
skol_map.repr(self.tcx()));
17541755

1755-
let impl_predicates =
1756-
self.impl_predicates(cause,
1756+
let mut impl_obligations =
1757+
self.impl_obligations(cause,
17571758
recursion_depth,
17581759
impl_def_id,
1759-
&substs,
1760+
&substs.value,
17601761
skol_map,
17611762
snapshot);
17621763

1763-
debug!("vtable_impl: impl_def_id={} impl_predicates={}",
1764+
debug!("vtable_impl: impl_def_id={} impl_obligations={}",
17641765
impl_def_id.repr(self.tcx()),
1765-
impl_predicates.repr(self.tcx()));
1766+
impl_obligations.repr(self.tcx()));
1767+
1768+
impl_obligations.extend(TypeSpace, substs.obligations.into_iter());
17661769

17671770
VtableImplData { impl_def_id: impl_def_id,
1768-
substs: substs,
1769-
nested: impl_predicates }
1771+
substs: substs.value,
1772+
nested: impl_obligations }
17701773
}
17711774

17721775
fn confirm_object_candidate(&mut self,
@@ -1950,7 +1953,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19501953
snapshot: &infer::CombinedSnapshot,
19511954
skol_map: &infer::SkolemizationMap,
19521955
skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
1953-
-> Substs<'tcx>
1956+
-> Normalized<'tcx, Substs<'tcx>>
19541957
{
19551958
match self.match_impl(impl_def_id, obligation, snapshot,
19561959
skol_map, skol_obligation_trait_ref) {
@@ -1972,7 +1975,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19721975
snapshot: &infer::CombinedSnapshot,
19731976
skol_map: &infer::SkolemizationMap,
19741977
skol_obligation_trait_ref: Rc<ty::TraitRef<'tcx>>)
1975-
-> Result<Substs<'tcx>, ()>
1978+
-> Result<Normalized<'tcx, Substs<'tcx>>, ()>
19761979
{
19771980
let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
19781981

@@ -1990,6 +1993,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19901993
let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
19911994
&impl_substs);
19921995

1996+
let impl_trait_ref =
1997+
project::normalize_with_depth(self,
1998+
obligation.cause.clone(),
1999+
obligation.recursion_depth + 1,
2000+
&impl_trait_ref);
2001+
19932002
debug!("match_impl(impl_def_id={}, obligation={}, \
19942003
impl_trait_ref={}, skol_obligation_trait_ref={})",
19952004
impl_def_id.repr(self.tcx()),
@@ -2000,7 +2009,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20002009
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
20012010
match self.infcx.sub_trait_refs(false,
20022011
origin,
2003-
impl_trait_ref,
2012+
impl_trait_ref.value.clone(),
20042013
skol_obligation_trait_ref) {
20052014
Ok(()) => { }
20062015
Err(e) => {
@@ -2020,7 +2029,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20202029
}
20212030

20222031
debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx()));
2023-
Ok(impl_substs)
2032+
Ok(Normalized { value: impl_substs,
2033+
obligations: impl_trait_ref.obligations })
20242034
}
20252035

20262036
fn fast_reject_trait_refs(&mut self,
@@ -2161,14 +2171,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
21612171
}
21622172
}
21632173

2164-
fn impl_predicates(&mut self,
2165-
cause: ObligationCause<'tcx>,
2166-
recursion_depth: uint,
2167-
impl_def_id: ast::DefId,
2168-
impl_substs: &Substs<'tcx>,
2169-
skol_map: infer::SkolemizationMap,
2170-
snapshot: &infer::CombinedSnapshot)
2171-
-> VecPerParamSpace<PredicateObligation<'tcx>>
2174+
fn impl_obligations(&mut self,
2175+
cause: ObligationCause<'tcx>,
2176+
recursion_depth: uint,
2177+
impl_def_id: ast::DefId,
2178+
impl_substs: &Substs<'tcx>,
2179+
skol_map: infer::SkolemizationMap,
2180+
snapshot: &infer::CombinedSnapshot)
2181+
-> VecPerParamSpace<PredicateObligation<'tcx>>
21722182
{
21732183
let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
21742184
let bounds = impl_generics.to_bounds(self.tcx(), impl_substs);
@@ -2181,9 +2191,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
21812191
cause,
21822192
recursion_depth,
21832193
&normalized_bounds.value);
2184-
for obligation in normalized_bounds.obligations.into_iter() {
2185-
impl_obligations.push(TypeSpace, obligation);
2186-
}
2194+
impl_obligations.extend(TypeSpace, normalized_bounds.obligations.into_iter());
21872195
impl_obligations
21882196
}
21892197

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that coherence detects overlap when some of the types in the
12+
// impls are projections of associated type. Issue #20624.
13+
14+
use std::ops::Deref;
15+
16+
pub struct Cow<'a, B: ?Sized>;
17+
18+
/// Trait for moving into a `Cow`
19+
pub trait IntoCow<'a, B: ?Sized> {
20+
/// Moves `self` into `Cow`
21+
fn into_cow(self) -> Cow<'a, B>;
22+
}
23+
24+
impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
25+
//~^ ERROR E0119
26+
fn into_cow(self) -> Cow<'a, B> {
27+
self
28+
}
29+
}
30+
31+
impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
32+
//~^ ERROR E0119
33+
fn into_cow(self) -> Cow<'a, B> {
34+
Cow
35+
}
36+
}
37+
38+
impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned {
39+
fn into_cow(self) -> Cow<'a, B> {
40+
Cow
41+
}
42+
}
43+
44+
impl ToOwned for u8 {
45+
type Owned = &'static u8;
46+
fn to_owned(&self) -> &'static u8 { panic!() }
47+
}
48+
49+
/// A generalization of Clone to borrowed data.
50+
pub trait ToOwned {
51+
type Owned;
52+
53+
/// Create owned data from borrowed data, usually by copying.
54+
fn to_owned(&self) -> Self::Owned;
55+
}
56+
57+
58+
fn main() {}
59+

0 commit comments

Comments
 (0)