summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/traits/coherence.rs56
-rw-r--r--src/librustc_typeck/coherence/orphan.rs6
-rw-r--r--src/test/compile-fail/coherence-all-remote.rs2
-rw-r--r--src/test/compile-fail/coherence-cow-no-cover.rs23
-rw-r--r--src/test/compile-fail/coherence-orphan.rs2
-rw-r--r--src/test/compile-fail/coherence-pair-covered-uncovered-1.rs24
-rw-r--r--src/test/run-pass/coherence-bigint-int.rs (renamed from src/test/compile-fail/coherence-bigint-int.rs)2
-rw-r--r--src/test/run-pass/coherence-bigint-vecint.rs (renamed from src/test/compile-fail/coherence-bigint-vecint.rs)2
-rw-r--r--src/test/run-pass/coherence-cow-1.rs23
-rw-r--r--src/test/run-pass/coherence-cow-2.rs23
10 files changed, 135 insertions, 28 deletions
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index e3363aa8fb7..44cd17caaec 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -15,7 +15,7 @@ use super::{Obligation, ObligationCause};
 use super::project;
 use super::util;
 
-use middle::subst::{Subst};
+use middle::subst::{Subst, TypeSpace};
 use middle::ty::{self, Ty};
 use middle::infer::InferCtxt;
 use std::collections::HashSet;
@@ -89,16 +89,28 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
         return Ok(());
     }
 
-    // Otherwise, check that (1) all type parameters are covered.
-    let covered_params = type_parameters_covered_by_ty(tcx, trait_ref.self_ty());
-    let all_params = type_parameters_reachable_from_ty(trait_ref.self_ty());
-    for &param in all_params.difference(&covered_params) {
-        return Err(OrphanCheckErr::UncoveredTy(param));
-    }
-
-    // And (2) some local type appears.
-    if !trait_ref.self_ty().walk().any(|t| ty_is_local_constructor(tcx, t)) {
-        return Err(OrphanCheckErr::NoLocalInputType);
+    // First, create an ordered iterator over all the type parameters to the trait, with the self
+    // type appearing first.
+    let input_tys = Some(trait_ref.self_ty());
+    let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter());
+    let mut input_tys = input_tys;
+
+    // Find the first input type that either references a type parameter OR
+    // some local type.
+    match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) {
+        Some(&input_ty) => {
+            // Within this first type, check that all type parameters are covered by a local
+            // type constructor. Note that if there is no local type constructor, then any
+            // type parameter at all will be an error.
+            let covered_params = type_parameters_covered_by_ty(tcx, input_ty);
+            let all_params = type_parameters_reachable_from_ty(input_ty);
+            for &param in all_params.difference(&covered_params) {
+                return Err(OrphanCheckErr::UncoveredTy(param));
+            }
+        }
+        None => {
+            return Err(OrphanCheckErr::NoLocalInputType);
+        }
     }
 
     return Ok(());
@@ -162,13 +174,17 @@ fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
 
 /// All type parameters reachable from `ty`
 fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet<Ty<'tcx>> {
-    ty.walk()
-        .filter(|&t| {
-            match t.sty {
-                // FIXME(#20590) straighten story about projection types
-                ty::ty_projection(..) | ty::ty_param(..) => true,
-                _ => false,
-            }
-        })
-        .collect()
+    ty.walk().filter(|&t| is_type_parameter(t)).collect()
+}
+
+fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty))
+}
+
+fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
+    match ty.sty {
+        // FIXME(#20590) straighten story about projection types
+        ty::ty_projection(..) | ty::ty_param(..) => true,
+        _ => false,
+    }
 }
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 60b1fa5f4cf..5b97175ab22 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -77,14 +77,12 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
                     Ok(()) => { }
                     Err(traits::OrphanCheckErr::NoLocalInputType) => {
                         if !ty::has_attr(self.tcx, trait_def_id, "old_orphan_check") {
-                            let self_ty = ty::lookup_item_type(self.tcx, def_id).ty;
                             span_err!(
                                 self.tcx.sess, item.span, E0117,
-                                "the type `{}` does not reference any \
+                                "the impl does not reference any \
                                  types defined in this crate; \
                                  only traits defined in the current crate can be \
-                                 implemented for arbitrary types",
-                                self_ty.user_string(self.tcx));
+                                 implemented for arbitrary types");
                         }
                     }
                     Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
diff --git a/src/test/compile-fail/coherence-all-remote.rs b/src/test/compile-fail/coherence-all-remote.rs
index f8ddf83c9c6..1e3b7f6dbd2 100644
--- a/src/test/compile-fail/coherence-all-remote.rs
+++ b/src/test/compile-fail/coherence-all-remote.rs
@@ -14,6 +14,6 @@ extern crate "coherence-lib" as lib;
 use lib::Remote1;
 
 impl<T> Remote1<T> for isize { }
-//~^ ERROR E0117
+//~^ ERROR E0210
 
 fn main() { }
diff --git a/src/test/compile-fail/coherence-cow-no-cover.rs b/src/test/compile-fail/coherence-cow-no-cover.rs
new file mode 100644
index 00000000000..8d14eb96c61
--- /dev/null
+++ b/src/test/compile-fail/coherence-cow-no-cover.rs
@@ -0,0 +1,23 @@
+// 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.
+
+// aux-build:coherence-lib.rs
+
+// Test that it's not ok for U to appear uncovered
+
+extern crate "coherence-lib" as lib;
+use lib::{Remote,Pair};
+
+pub struct Cover<T>(T);
+
+impl<T,U> Remote for Pair<Cover<T>,U> { }
+//~^ ERROR type parameter `U` is not constrained by any local type
+
+fn main() { }
diff --git a/src/test/compile-fail/coherence-orphan.rs b/src/test/compile-fail/coherence-orphan.rs
index f9f965e1ae3..d7cd68e73c3 100644
--- a/src/test/compile-fail/coherence-orphan.rs
+++ b/src/test/compile-fail/coherence-orphan.rs
@@ -21,7 +21,7 @@ struct TheType;
 
 impl TheTrait<usize> for isize { } //~ ERROR E0117
 
-impl TheTrait<TheType> for isize { } //~ ERROR E0117
+impl TheTrait<TheType> for isize { }
 
 impl TheTrait<isize> for TheType { }
 
diff --git a/src/test/compile-fail/coherence-pair-covered-uncovered-1.rs b/src/test/compile-fail/coherence-pair-covered-uncovered-1.rs
new file mode 100644
index 00000000000..3655bca6f1d
--- /dev/null
+++ b/src/test/compile-fail/coherence-pair-covered-uncovered-1.rs
@@ -0,0 +1,24 @@
+// 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 the same coverage rules apply even if the local type appears in the
+// list of type parameters, not the self type.
+
+// aux-build:coherence-lib.rs
+
+extern crate "coherence-lib" as lib;
+use lib::{Remote1, Pair};
+
+pub struct Local<T>(T);
+
+impl<T,U> Remote1<Pair<T,Local<U>>> for i32 { }
+//~^ ERROR type parameter `T` is not constrained
+
+fn main() { }
diff --git a/src/test/compile-fail/coherence-bigint-int.rs b/src/test/run-pass/coherence-bigint-int.rs
index 684773098cd..baf2f57206d 100644
--- a/src/test/compile-fail/coherence-bigint-int.rs
+++ b/src/test/run-pass/coherence-bigint-int.rs
@@ -15,6 +15,6 @@ use lib::Remote1;
 
 pub struct BigInt;
 
-impl Remote1<BigInt> for isize { } //~ ERROR E0117
+impl Remote1<BigInt> for isize { }
 
 fn main() { }
diff --git a/src/test/compile-fail/coherence-bigint-vecint.rs b/src/test/run-pass/coherence-bigint-vecint.rs
index 28747674b8b..cdc5bc11716 100644
--- a/src/test/compile-fail/coherence-bigint-vecint.rs
+++ b/src/test/run-pass/coherence-bigint-vecint.rs
@@ -15,6 +15,6 @@ use lib::Remote1;
 
 pub struct BigInt;
 
-impl Remote1<BigInt> for Vec<isize> { } //~ ERROR E0117
+impl Remote1<BigInt> for Vec<isize> { }
 
 fn main() { }
diff --git a/src/test/run-pass/coherence-cow-1.rs b/src/test/run-pass/coherence-cow-1.rs
new file mode 100644
index 00000000000..b380372b401
--- /dev/null
+++ b/src/test/run-pass/coherence-cow-1.rs
@@ -0,0 +1,23 @@
+// 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.
+
+// aux-build:coherence-lib.rs
+
+// Test that it's ok for T to appear first in the self-type, as long
+// as it's covered somewhere.
+
+extern crate "coherence-lib" as lib;
+use lib::{Remote,Pair};
+
+pub struct Cover<T>(T);
+
+impl<T> Remote for Pair<T,Cover<T>> { }
+
+fn main() { }
diff --git a/src/test/run-pass/coherence-cow-2.rs b/src/test/run-pass/coherence-cow-2.rs
new file mode 100644
index 00000000000..93e507c0d63
--- /dev/null
+++ b/src/test/run-pass/coherence-cow-2.rs
@@ -0,0 +1,23 @@
+// 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.
+
+// aux-build:coherence-lib.rs
+
+// Test that it's ok for T to appear second in the self-type, as long
+// as it's covered somewhere.
+
+extern crate "coherence-lib" as lib;
+use lib::{Remote,Pair};
+
+pub struct Cover<T>(T);
+
+impl<T> Remote for Pair<Cover<T>,T> { }
+
+fn main() { }