From 56d765d0eb2121e4a345656351a24cb0d9d68b22 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Tue, 9 Jun 2015 21:33:28 +0300
Subject: [PATCH] Simplify and type_known_to_meet_builtin_bound and make it
 more correct when associated types are involved.

---
 src/librustc/middle/traits/mod.rs    | 75 ++++++----------------------
 src/test/compile-fail/issue-25700.rs | 24 +++++++++
 src/test/run-pass/issue-25700-1.rs   | 22 ++++++++
 3 files changed, 62 insertions(+), 59 deletions(-)
 create mode 100644 src/test/compile-fail/issue-25700.rs
 create mode 100644 src/test/run-pass/issue-25700-1.rs

diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 50536f586e7..fb6bac9ea06 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -304,12 +304,12 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
 /// `bound` or is not known to meet bound (note that this is
 /// conservative towards *no impl*, which is the opposite of the
 /// `evaluate` methods).
-pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                       typer: &ty::ClosureTyper<'tcx>,
-                                       ty: Ty<'tcx>,
-                                       bound: ty::BuiltinBound,
-                                       span: Span)
-                                       -> SelectionResult<'tcx, ()>
+pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+                                                 typer: &ty::ClosureTyper<'tcx>,
+                                                 ty: Ty<'tcx>,
+                                                 bound: ty::BuiltinBound,
+                                                 span: Span)
+                                                 -> bool
 {
     debug!("type_known_to_meet_builtin_bound(ty={}, bound={:?})",
            ty.repr(infcx.tcx),
@@ -327,61 +327,18 @@ pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
     // Note: we only assume something is `Copy` if we can
     // *definitively* show that it implements `Copy`. Otherwise,
     // assume it is move; linear is always ok.
-    let result = match fulfill_cx.select_all_or_error(infcx, typer) {
-        Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
-        Err(errors) => {
-            // If there were any hard errors, propagate an arbitrary
-            // one of those. If no hard errors at all, report
-            // ambiguity.
-            let sel_error =
-                errors.iter()
-                      .filter_map(|err| {
-                          match err.code {
-                              CodeAmbiguity => None,
-                              CodeSelectionError(ref e) => Some(e.clone()),
-                              CodeProjectionError(_) => {
-                                  infcx.tcx.sess.span_bug(
-                                      span,
-                                      "projection error while selecting?")
-                              }
-                          }
-                      })
-                      .next();
-            match sel_error {
-                None => { Ok(None) }
-                Some(e) => { Err(e) }
-            }
-        }
-    };
-
-    debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} result={:?}",
-           ty.repr(infcx.tcx),
-           bound,
-           result);
-
-    result
-}
-
-pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                                 typer: &ty::ClosureTyper<'tcx>,
-                                                 ty: Ty<'tcx>,
-                                                 bound: ty::BuiltinBound,
-                                                 span: Span)
-                                                 -> bool
-{
-    match evaluate_builtin_bound(infcx, typer, ty, bound, span) {
-        Ok(Some(())) => {
-            // definitely impl'd
+    match fulfill_cx.select_all_or_error(infcx, typer) {
+        Ok(()) => {
+            debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} success",
+                   ty.repr(infcx.tcx),
+                   bound);
             true
         }
-        Ok(None) => {
-            // ambiguous: if coherence check was successful, shouldn't
-            // happen, but we might have reported an error and been
-            // soldering on, so just treat this like not implemented
-            false
-        }
-        Err(_) => {
-            // errors: not implemented.
+        Err(e) => {
+            debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} errors={}",
+                   ty.repr(infcx.tcx),
+                   bound,
+                   e.repr(infcx.tcx));
             false
         }
     }
diff --git a/src/test/compile-fail/issue-25700.rs b/src/test/compile-fail/issue-25700.rs
new file mode 100644
index 00000000000..477c3237f84
--- /dev/null
+++ b/src/test/compile-fail/issue-25700.rs
@@ -0,0 +1,24 @@
+// Copyright 2015 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.
+
+struct S<T: 'static>(Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+    fn clone(&self) -> Self { *self }
+}
+fn main() {
+    let t = S::<()>(None);
+    drop(t);
+    drop(t); //~ ERROR use of moved value
+}
diff --git a/src/test/run-pass/issue-25700-1.rs b/src/test/run-pass/issue-25700-1.rs
new file mode 100644
index 00000000000..57f5b84b285
--- /dev/null
+++ b/src/test/run-pass/issue-25700-1.rs
@@ -0,0 +1,22 @@
+// Copyright 2015 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.
+
+struct S<T: 'static>(Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+    fn clone(&self) -> Self { *self }
+}
+fn main() {
+    S::<()>(None);
+}