Skip to content

Commit e8489d3

Browse files
committed
Auto merge of #21792 - nikomatsakis:orphan-ordered-first, r=aturon
Update the coherence rules to "covered first" -- the first type parameter to contain either a local type or a type parameter must contain only covered type parameters. cc #19470. Fixes #20974. Fixes #20749. r? @aturon
2 parents f1398d2 + 2c2879b commit e8489d3

10 files changed

+135
-28
lines changed

src/librustc/middle/traits/coherence.rs

+36-20
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use super::{Obligation, ObligationCause};
1515
use super::project;
1616
use super::util;
1717

18-
use middle::subst::{Subst};
18+
use middle::subst::{Subst, TypeSpace};
1919
use middle::ty::{self, Ty};
2020
use middle::infer::InferCtxt;
2121
use std::collections::HashSet;
@@ -89,16 +89,28 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
8989
return Ok(());
9090
}
9191

92-
// Otherwise, check that (1) all type parameters are covered.
93-
let covered_params = type_parameters_covered_by_ty(tcx, trait_ref.self_ty());
94-
let all_params = type_parameters_reachable_from_ty(trait_ref.self_ty());
95-
for &param in all_params.difference(&covered_params) {
96-
return Err(OrphanCheckErr::UncoveredTy(param));
97-
}
98-
99-
// And (2) some local type appears.
100-
if !trait_ref.self_ty().walk().any(|t| ty_is_local_constructor(tcx, t)) {
101-
return Err(OrphanCheckErr::NoLocalInputType);
92+
// First, create an ordered iterator over all the type parameters to the trait, with the self
93+
// type appearing first.
94+
let input_tys = Some(trait_ref.self_ty());
95+
let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter());
96+
let mut input_tys = input_tys;
97+
98+
// Find the first input type that either references a type parameter OR
99+
// some local type.
100+
match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) {
101+
Some(&input_ty) => {
102+
// Within this first type, check that all type parameters are covered by a local
103+
// type constructor. Note that if there is no local type constructor, then any
104+
// type parameter at all will be an error.
105+
let covered_params = type_parameters_covered_by_ty(tcx, input_ty);
106+
let all_params = type_parameters_reachable_from_ty(input_ty);
107+
for &param in all_params.difference(&covered_params) {
108+
return Err(OrphanCheckErr::UncoveredTy(param));
109+
}
110+
}
111+
None => {
112+
return Err(OrphanCheckErr::NoLocalInputType);
113+
}
102114
}
103115

104116
return Ok(());
@@ -162,13 +174,17 @@ fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
162174

163175
/// All type parameters reachable from `ty`
164176
fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet<Ty<'tcx>> {
165-
ty.walk()
166-
.filter(|&t| {
167-
match t.sty {
168-
// FIXME(#20590) straighten story about projection types
169-
ty::ty_projection(..) | ty::ty_param(..) => true,
170-
_ => false,
171-
}
172-
})
173-
.collect()
177+
ty.walk().filter(|&t| is_type_parameter(t)).collect()
178+
}
179+
180+
fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
181+
ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty))
182+
}
183+
184+
fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
185+
match ty.sty {
186+
// FIXME(#20590) straighten story about projection types
187+
ty::ty_projection(..) | ty::ty_param(..) => true,
188+
_ => false,
189+
}
174190
}

src/librustc_typeck/coherence/orphan.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,12 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
7777
Ok(()) => { }
7878
Err(traits::OrphanCheckErr::NoLocalInputType) => {
7979
if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") {
80-
let self_ty = ty::lookup_item_type(self.tcx, def_id).ty;
8180
span_err!(
8281
self.tcx.sess, item.span, E0117,
83-
"the type `{}` does not reference any \
82+
"the impl does not reference any \
8483
types defined in this crate; \
8584
only traits defined in the current crate can be \
86-
implemented for arbitrary types",
87-
self_ty.user_string(self.tcx));
85+
implemented for arbitrary types");
8886
}
8987
}
9088
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {

src/test/compile-fail/coherence-all-remote.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ extern crate "coherence-lib" as lib;
1414
use lib::Remote1;
1515

1616
impl<T> Remote1<T> for isize { }
17-
//~^ ERROR E0117
17+
//~^ ERROR E0210
1818

1919
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
// aux-build:coherence-lib.rs
12+
13+
// Test that it's not ok for U to appear uncovered
14+
15+
extern crate "coherence-lib" as lib;
16+
use lib::{Remote,Pair};
17+
18+
pub struct Cover<T>(T);
19+
20+
impl<T,U> Remote for Pair<Cover<T>,U> { }
21+
//~^ ERROR type parameter `U` is not constrained by any local type
22+
23+
fn main() { }

src/test/compile-fail/coherence-orphan.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct TheType;
2121

2222
impl TheTrait<usize> for isize { } //~ ERROR E0117
2323

24-
impl TheTrait<TheType> for isize { } //~ ERROR E0117
24+
impl TheTrait<TheType> for isize { }
2525

2626
impl TheTrait<isize> for TheType { }
2727

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 the same coverage rules apply even if the local type appears in the
12+
// list of type parameters, not the self type.
13+
14+
// aux-build:coherence-lib.rs
15+
16+
extern crate "coherence-lib" as lib;
17+
use lib::{Remote1, Pair};
18+
19+
pub struct Local<T>(T);
20+
21+
impl<T,U> Remote1<Pair<T,Local<U>>> for i32 { }
22+
//~^ ERROR type parameter `T` is not constrained
23+
24+
fn main() { }

src/test/compile-fail/coherence-bigint-int.rs src/test/run-pass/coherence-bigint-int.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ use lib::Remote1;
1515

1616
pub struct BigInt;
1717

18-
impl Remote1<BigInt> for isize { } //~ ERROR E0117
18+
impl Remote1<BigInt> for isize { }
1919

2020
fn main() { }

src/test/compile-fail/coherence-bigint-vecint.rs src/test/run-pass/coherence-bigint-vecint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ use lib::Remote1;
1515

1616
pub struct BigInt;
1717

18-
impl Remote1<BigInt> for Vec<isize> { } //~ ERROR E0117
18+
impl Remote1<BigInt> for Vec<isize> { }
1919

2020
fn main() { }

src/test/run-pass/coherence-cow-1.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
// aux-build:coherence-lib.rs
12+
13+
// Test that it's ok for T to appear first in the self-type, as long
14+
// as it's covered somewhere.
15+
16+
extern crate "coherence-lib" as lib;
17+
use lib::{Remote,Pair};
18+
19+
pub struct Cover<T>(T);
20+
21+
impl<T> Remote for Pair<T,Cover<T>> { }
22+
23+
fn main() { }

src/test/run-pass/coherence-cow-2.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
// aux-build:coherence-lib.rs
12+
13+
// Test that it's ok for T to appear second in the self-type, as long
14+
// as it's covered somewhere.
15+
16+
extern crate "coherence-lib" as lib;
17+
use lib::{Remote,Pair};
18+
19+
pub struct Cover<T>(T);
20+
21+
impl<T> Remote for Pair<Cover<T>,T> { }
22+
23+
fn main() { }

0 commit comments

Comments
 (0)