From 5045e12bd7001956b14a6dfd642637a471e4b378 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 28 Nov 2018 21:15:06 -0500 Subject: [PATCH] Filter out self-referential projection predicates If we end up with a projection predicate that equates a type with itself (e.g. ::Value == ::Value), we can run into issues if we try to add it to our ParamEnv. --- src/librustc/traits/auto_trait.rs | 27 ++++++++++++- .../synthetic_auto/self-referential.rs | 40 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/synthetic_auto/self-referential.rs diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index f560772e6c73..a0237348ea69 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: + // ::Value == ::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 000000000000..077786b280fc --- /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 or the MIT license +// , 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, C); + +impl Pattern for Constrain + where A: Pattern, + B: Pattern, + C: Pattern, +{ + type Value = A::Value; +} + +pub struct Wrapper(T); + +impl Pattern for Wrapper { + type Value = T; +} + + +// @has self_referential/struct.WriteAndThen.html +// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl Send for \ +// WriteAndThen where ::Value: Send" +pub struct WriteAndThen(pub P1::Value, pub > as Pattern>::Value) + where P1: Pattern; +