Skip to content

Commit 5045e12

Browse files
committed
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.
1 parent 1a84d21 commit 5045e12

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

src/librustc/traits/auto_trait.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
649649
};
650650
}
651651

652+
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
653+
match p.ty().skip_binder().sty {
654+
ty::Projection(proj) if proj == p.skip_binder().projection_ty => {
655+
true
656+
},
657+
_ => false
658+
}
659+
}
660+
652661
pub fn evaluate_nested_obligations<
653662
'b,
654663
'c,
@@ -713,7 +722,23 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
713722
debug!("evaluate_nested_obligations: adding projection predicate\
714723
to computed_preds: {:?}", predicate);
715724

716-
self.add_user_pred(computed_preds, predicate);
725+
// Under unusual circumstances, we can end up with a self-refeential
726+
// projection predicate. For example:
727+
// <T as MyType>::Value == <T as MyType>::Value
728+
// Not only is displaying this to the user pointless,
729+
// having it in the ParamEnv will cause an issue if we try to call
730+
// poly_project_and_unify_type on the predicate, since this kind of
731+
// predicate will normally never end up in a ParamEnv.
732+
//
733+
// For these reasons, we ignore these weird predicates,
734+
// ensuring that we're able to properly synthesize an auto trait impl
735+
if self.is_self_referential_projection(p) {
736+
debug!("evaluate_nested_obligations: encountered a projection
737+
predicate equating a type with itself! Skipping");
738+
739+
} else {
740+
self.add_user_pred(computed_preds, predicate);
741+
}
717742
}
718743

719744
// We can only call poly_project_and_unify_type when our predicate's
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Some unusual code minimized from
12+
// https://github.com/sile/handy_async/tree/7b619b762c06544fc67792c8ff8ebc24a88fdb98
13+
14+
pub trait Pattern {
15+
type Value;
16+
}
17+
18+
pub struct Constrain<A, B = A, C = A>(A, B, C);
19+
20+
impl<A, B, C> Pattern for Constrain<A, B, C>
21+
where A: Pattern,
22+
B: Pattern<Value = A::Value>,
23+
C: Pattern<Value = A::Value>,
24+
{
25+
type Value = A::Value;
26+
}
27+
28+
pub struct Wrapper<T>(T);
29+
30+
impl<T> Pattern for Wrapper<T> {
31+
type Value = T;
32+
}
33+
34+
35+
// @has self_referential/struct.WriteAndThen.html
36+
// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<P1> Send for \
37+
// WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
38+
pub struct WriteAndThen<P1>(pub P1::Value, pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
39+
where P1: Pattern;
40+

0 commit comments

Comments
 (0)