Skip to content

Commit d80189d

Browse files
committed
Test fixes, added README for tests
1 parent 3262016 commit d80189d

19 files changed

+230
-27
lines changed

src/librustc/middle/traits/specialize/mod.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use middle::def_id::DefId;
2525
use middle::infer::{self, InferCtxt, TypeOrigin};
2626
use middle::region;
2727
use middle::subst::{Subst, Substs};
28-
use middle::traits::ProjectionMode;
28+
use middle::traits::{self, ProjectionMode, ObligationCause, Normalized};
2929
use middle::ty::{self, TyCtxt};
3030
use syntax::codemap::DUMMY_SP;
3131

@@ -149,14 +149,21 @@ pub fn specializes(tcx: &TyCtxt, impl1_def_id: DefId, impl2_def_id: DefId) -> bo
149149
// create a parameter environment corresponding to a (skolemized) instantiation of impl1
150150
let scheme = tcx.lookup_item_type(impl1_def_id);
151151
let predicates = tcx.lookup_predicates(impl1_def_id);
152-
let penv = tcx.construct_parameter_environment(DUMMY_SP,
153-
&scheme.generics,
154-
&predicates,
155-
region::DUMMY_CODE_EXTENT);
152+
let mut penv = tcx.construct_parameter_environment(DUMMY_SP,
153+
&scheme.generics,
154+
&predicates,
155+
region::DUMMY_CODE_EXTENT);
156156
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
157157
.unwrap()
158158
.subst(tcx, &penv.free_substs);
159159

160+
// Normalize the trait reference, adding any obligations that arise into the impl1 assumptions
161+
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
162+
let selcx = &mut SelectionContext::new(&infcx);
163+
traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
164+
};
165+
penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
166+
160167
// Install the parameter environment, which means we take the predicates of impl1 as assumptions:
161168
infcx.parameter_environment = penv;
162169

src/test/auxiliary/xcrate_associated_type_defaults.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010

1111
#![feature(associated_type_defaults)]
1212

13-
pub trait Foo {
14-
type Input = usize;
15-
fn bar(&self, _: Self::Input) {}
13+
pub trait Foo<T: Default + ToString> {
14+
type Out: Default + ToString = T;
1615
}
1716

18-
impl Foo for () {}
17+
impl Foo<u32> for () {
18+
}
19+
20+
impl Foo<u64> for () {
21+
type Out = bool;
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
This directory contains the test for incorrect usage of specialization that
2+
should lead to compile failure. Those tests break down into a few categories:
3+
4+
- Feature gating
5+
- [On use of the `default` keyword](specialization-feature-gate-default.rs)
6+
- [On overlapping impls](specialization-feature-gate-overlap.rs)
7+
8+
- Overlap checking with specialization enabled
9+
- [Basic overlap scenarios](specialization-overlap.rs)
10+
- Includes purely structural overlap
11+
- Includes purely trait-based overlap
12+
- Includes mix
13+
- [Overlap with differing polarity](specialization-overlap-negative.rs)
14+
15+
- [Attempt to specialize without using `default`](specialization-no-default.rs)
16+
17+
- [Attempt to change impl polarity in a specialization](specialization-polarity.rs)
18+
19+
- Attempt to rely on projection of a `default` type
20+
- [Rely on it externally in both generic and monomorphic contexts](specialization-default-projection.rs)
21+
- [Rely on it both within an impl and outside it](specialization-default-types.rs)

src/test/compile-fail/specialization/specialization-default-projection.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ fn generic<T>() -> <T as Foo>::Assoc {
2828
// `T` could be some downstream crate type that specializes (or,
2929
// for that matter, `u8`).
3030

31-
() //~ ERROR E0308
31+
() //~ ERROR mismatched types
3232
}
3333

3434
fn monomorphic() -> () {
3535
// Even though we know that `()` is not specialized in a
3636
// downstream crate, typeck refuses to project here.
3737

38-
generic::<()>() //~ ERROR E0308
38+
generic::<()>() //~ ERROR mismatched types
3939
}
4040

4141
fn main() {

src/test/compile-fail/specialization/specialization-default-types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ trait Example {
2222
impl<T> Example for T {
2323
default type Output = Box<T>;
2424
default fn generate(self) -> Self::Output {
25-
Box::new(self) //~ ERROR E0308
25+
Box::new(self) //~ ERROR mismatched types
2626
}
2727
}
2828

@@ -32,7 +32,7 @@ impl Example for bool {
3232
}
3333

3434
fn trouble<T>(t: T) -> Box<T> {
35-
Example::generate(t) //~ ERROR E0308
35+
Example::generate(t) //~ ERROR mismatched types
3636
}
3737

3838
fn weaponize() -> bool {

src/test/compile-fail/specialization/specialization-overlap.rs

+4
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ trait Baz<U> {}
2222
impl<T> Baz<T> for u8 {}
2323
impl<T> Baz<u8> for T {} //~ ERROR E0119
2424

25+
trait Qux {}
26+
impl<T: Clone> Qux for T {}
27+
impl<T: Eq> Qux for T {} //~ ERROR E0119
28+
2529
fn main() {}

src/test/run-pass/default-associated-types.rs

+10-11
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,22 @@
1010

1111
#![feature(associated_type_defaults)]
1212

13-
trait Foo<T> {
14-
type Out = T;
15-
fn foo(&self) -> Self::Out;
13+
trait Foo<T: Default + ToString> {
14+
type Out: Default + ToString = T;
1615
}
1716

1817
impl Foo<u32> for () {
19-
fn foo(&self) -> u32 {
20-
4u32
21-
}
2218
}
2319

24-
impl Foo<u64> for bool {
25-
type Out = ();
26-
fn foo(&self) {}
20+
impl Foo<u64> for () {
21+
type Out = bool;
2722
}
2823

2924
fn main() {
30-
assert_eq!(<() as Foo<u32>>::foo(&()), 4u32);
31-
assert_eq!(<bool as Foo<u64>>::foo(&true), ());
25+
assert_eq!(
26+
<() as Foo<u32>>::Out::default().to_string(),
27+
"0");
28+
assert_eq!(
29+
<() as Foo<u64>>::Out::default().to_string(),
30+
"false");
3231
}
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Tests that specialization is working correctly:
2+
3+
- Dispatch
4+
- [On methods](specialization-basics.rs), includes:
5+
- Specialization via adding a trait bound
6+
- Including both remote and local traits
7+
- Specialization via pure structure (e.g. `(T, U)` vs `(T, T)`)
8+
- Specialization via concrete types vs unknown types
9+
- In top level of the trait reference
10+
- Embedded within another type (`Vec<T>` vs `Vec<i32>`)
11+
- [Specialization based on super trait relationships](specialization-super-traits.rs)
12+
- [On assoc fns](specialization-assoc-fns.rs)
13+
- [Ensure that impl order doesn't matter](specialization-out-of-order.rs)
14+
15+
- Item inheritance
16+
- [Correct default cascading for methods](specialization-default-methods.rs)
17+
- Inheritance works across impls with varying generics
18+
- [With projections](specialization-translate-projections.rs)
19+
- [With projections that involve input types](specialization-translate-projections-with-params.rs)
20+
21+
- Normalization issues
22+
- [Non-default assoc types can be projected](specialization-projection.rs)
23+
- Including non-specialized cases
24+
- Including specialized cases
25+
- [Specialized Impls can happen on projections](specialization-on-projection.rs)
26+
- [Projections and aliases play well together](specialization-projection-alias.rs)
27+
- [Projections involving specialization allowed in the trait ref for impls, and overlap can still be determined](specialization-overlap-projection.rs)
28+
- Only works for the simple case where the most specialized impl directly
29+
provides a non-`default` associated type
30+
31+
- Across crates
32+
- [For traits defined in upstream crate](specialization-allowed-cross-crate.rs)
33+
- [Full method dispatch tests, drawing from upstream crate](specialization-cross-crate.rs)
34+
- Including *additional* local specializations
35+
- [Full method dispatch tests, *without* turning on specialization in local crate](specialization-cross-crate-no-gate.rs)
36+
- [Test that defaults cascade correctly from upstream crates](specialization-cross-crate-defaults.rs)
37+
- Including *additional* local use of defaults

src/test/run-pass/specialization/specialization-assoc-fns.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// Test that non-method associated functions can be specialized
12+
1113
#![feature(specialization)]
1214

1315
trait Foo {

src/test/run-pass/specialization/specialization-cross-crate-defaults.rs

+12
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,22 @@ extern crate specialization_cross_crate_defaults;
1616

1717
use specialization_cross_crate_defaults::*;
1818

19+
struct LocalDefault;
20+
struct LocalOverride;
21+
22+
impl Foo for LocalDefault {}
23+
24+
impl Foo for LocalOverride {
25+
fn foo(&self) -> bool { true }
26+
}
27+
1928
fn test_foo() {
2029
assert!(0i8.foo() == false);
2130
assert!(0i32.foo() == false);
2231
assert!(0i64.foo() == true);
32+
33+
assert!(LocalDefault.foo() == false);
34+
assert!(LocalOverride.foo() == true);
2335
}
2436

2537
fn test_bar() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2015 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 specialization works even if only the upstream crate enables it
12+
13+
// aux-build:specialization_cross_crate.rs
14+
15+
extern crate specialization_cross_crate;
16+
17+
use specialization_cross_crate::*;
18+
19+
fn main() {
20+
assert!(0u8.foo() == "generic Clone");
21+
assert!(vec![0u8].foo() == "generic Vec");
22+
assert!(vec![0i32].foo() == "Vec<i32>");
23+
assert!(0i32.foo() == "i32");
24+
assert!(String::new().foo() == "String");
25+
assert!(((), 0).foo() == "generic pair");
26+
assert!(((), ()).foo() == "generic uniform pair");
27+
assert!((0u8, 0u32).foo() == "(u8, u32)");
28+
assert!((0u8, 0u8).foo() == "(u8, u8)");
29+
}

src/test/run-pass/specialization/specialization-default-methods.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#![feature(specialization)]
1212

13+
// Test that default methods are cascaded correctly
14+
1315
// First, test only use of explicit `default` items:
1416

1517
trait Foo {

src/test/run-pass/specialization/specialization-on-projection.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#![feature(specialization)]
1212

13+
// Ensure that specialization works for impls defined directly on a projection
14+
1315
trait Foo<T> {}
1416

1517
trait Assoc {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2016 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 impls on projected self types can resolve overlap, even when the
12+
// projections involve specialization, so long as the associated type is
13+
// provided by the most specialized impl.
14+
15+
#![feature(specialization)]
16+
17+
trait Assoc {
18+
type Output;
19+
}
20+
21+
impl<T> Assoc for T {
22+
default type Output = bool;
23+
}
24+
25+
impl Assoc for u8 { type Output = u8; }
26+
impl Assoc for u16 { type Output = u16; }
27+
28+
trait Foo {}
29+
impl Foo for u32 {}
30+
impl Foo for <u8 as Assoc>::Output {}
31+
impl Foo for <u16 as Assoc>::Output {}
32+
33+
fn main() {}

src/test/run-pass/specialization/specialization-projection-alias.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ impl<T> Id_ for T {
2323
default type Out = T;
2424
}
2525

26-
fn main() {
26+
fn test_proection() {
2727
let x: Id<bool> = panic!();
2828
}
29+
30+
fn main() {
31+
32+
}

src/test/run-pass/specialization/specialization-projection.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// Make sure we *can* project non-defaulted associated types
1414
// cf compile-fail/specialization-default-projection.rs
1515

16+
// First, do so without any use of specialization
17+
1618
trait Foo {
1719
type Assoc;
1820
}
@@ -21,9 +23,27 @@ impl<T> Foo for T {
2123
type Assoc = ();
2224
}
2325

24-
fn generic<T>() -> <T as Foo>::Assoc {
26+
fn generic_foo<T>() -> <T as Foo>::Assoc {
2527
()
2628
}
2729

30+
// Next, allow for one layer of specialization
31+
32+
trait Bar {
33+
type Assoc;
34+
}
35+
36+
impl<T> Bar for T {
37+
default type Assoc = ();
38+
}
39+
40+
impl<T: Clone> Bar for T {
41+
type Assoc = u8;
42+
}
43+
44+
fn generic_bar_clone<T: Clone>() -> <T as Bar>::Assoc {
45+
0u8
46+
}
47+
2848
fn main() {
2949
}

src/test/run-pass/specialization/specialization-translate-projections-with-params.rs

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// Ensure that provided items are inherited properly even when impls vary in
12+
// type parameters *and* rely on projections, and the type parameters are input
13+
// types on the trait.
14+
1115
#![feature(specialization)]
1216

1317
trait Trait<T> {

src/test/run-pass/specialization/specialization-translate-projections.rs

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// Ensure that provided items are inherited properly even when impls vary in
12+
// type parameters *and* rely on projections.
13+
1114
#![feature(specialization)]
1215

1316
use std::convert::Into;

0 commit comments

Comments
 (0)