about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2018-11-28 21:15:06 -0500
committerAaron Hill <aa1ronham@gmail.com>2018-11-28 21:15:06 -0500
commit5045e12bd7001956b14a6dfd642637a471e4b378 (patch)
tree70ee68cccaf479faa8c14ce0311bcdd831113d6b
parent1a84d211a2dad78f1d3412c65f5a72053a82893d (diff)
downloadrust-5045e12bd7001956b14a6dfd642637a471e4b378.tar.gz
rust-5045e12bd7001956b14a6dfd642637a471e4b378.zip
Filter out self-referential projection predicates
If we end up with a projection predicate that equates a type with
itself (e.g. <T as MyType>::Value == <T as MyType>::Value), we can
run into issues if we try to add it to our ParamEnv.
-rw-r--r--src/librustc/traits/auto_trait.rs27
-rw-r--r--src/test/rustdoc/synthetic_auto/self-referential.rs40
2 files changed, 66 insertions, 1 deletions
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index f560772e6c7..a0237348ea6 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -649,6 +649,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
         };
     }
 
+    fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
+        match p.ty().skip_binder().sty {
+            ty::Projection(proj) if proj == p.skip_binder().projection_ty => {
+                true
+            },
+            _ => false
+        }
+    }
+
     pub fn evaluate_nested_obligations<
         'b,
         'c,
@@ -713,7 +722,23 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                             debug!("evaluate_nested_obligations: adding projection predicate\
                             to computed_preds: {:?}", predicate);
 
-                        self.add_user_pred(computed_preds, predicate);
+                            // Under unusual circumstances, we can end up with a self-refeential
+                            // projection predicate. For example:
+                            // <T as MyType>::Value == <T as MyType>::Value
+                            // Not only is displaying this to the user pointless,
+                            // having it in the ParamEnv will cause an issue if we try to call
+                            // poly_project_and_unify_type on the predicate, since this kind of
+                            // predicate will normally never end up in a ParamEnv.
+                            //
+                            // For these reasons, we ignore these weird predicates,
+                            // ensuring that we're able to properly synthesize an auto trait impl
+                            if self.is_self_referential_projection(p) {
+                                debug!("evaluate_nested_obligations: encountered a projection
+                                 predicate equating a type with itself! Skipping");
+
+                            } else {
+                                self.add_user_pred(computed_preds, predicate);
+                            }
                     }
 
                     // We can only call poly_project_and_unify_type when our predicate's
diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs
new file mode 100644
index 00000000000..077786b280f
--- /dev/null
+++ b/src/test/rustdoc/synthetic_auto/self-referential.rs
@@ -0,0 +1,40 @@
+// Copyright 2018 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.
+
+// Some unusual code minimized from
+// https://github.com/sile/handy_async/tree/7b619b762c06544fc67792c8ff8ebc24a88fdb98
+
+pub trait Pattern {
+    type Value;
+}
+
+pub struct Constrain<A, B = A, C = A>(A, B, C);
+
+impl<A, B, C> Pattern for Constrain<A, B, C>
+    where A: Pattern,
+          B: Pattern<Value = A::Value>,
+          C: Pattern<Value = A::Value>,
+{
+    type Value = A::Value;
+}
+
+pub struct Wrapper<T>(T);
+
+impl<T> Pattern for Wrapper<T> {
+    type Value = T;
+}
+
+
+// @has self_referential/struct.WriteAndThen.html
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<P1> Send for \
+// WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
+pub struct WriteAndThen<P1>(pub P1::Value, pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
+    where P1: Pattern;
+