diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2018-11-28 21:15:06 -0500 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2018-11-28 21:15:06 -0500 |
| commit | 5045e12bd7001956b14a6dfd642637a471e4b378 (patch) | |
| tree | 70ee68cccaf479faa8c14ce0311bcdd831113d6b | |
| parent | 1a84d211a2dad78f1d3412c65f5a72053a82893d (diff) | |
| download | rust-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.rs | 27 | ||||
| -rw-r--r-- | src/test/rustdoc/synthetic_auto/self-referential.rs | 40 |
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; + |
