Skip to content

Commit 2a52de1

Browse files
committed
Emit ProjectionEq obligations when relating projections
1 parent 1de00d1 commit 2a52de1

File tree

35 files changed

+529
-204
lines changed

35 files changed

+529
-204
lines changed

compiler/rustc_borrowck/src/type_check/relate_tys.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_infer::traits::ObligationCause;
44
use rustc_middle::mir::ConstraintCategory;
55
use rustc_middle::ty::error::TypeError;
66
use rustc_middle::ty::relate::TypeRelation;
7-
use rustc_middle::ty::{self, Const, Ty};
7+
use rustc_middle::ty::{self, Const, ToPredicate, Ty};
88
use rustc_span::Span;
99
use rustc_trait_selection::traits::query::Fallible;
1010

@@ -147,6 +147,14 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
147147
// 'static.
148148
fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}
149149

150+
fn projection_equate(&mut self, projection_ty: ty::ProjectionTy<'tcx>, ty: Ty<'tcx>) {
151+
unreachable!()
152+
}
153+
154+
fn defer_projection_equality(&self) -> bool {
155+
false
156+
}
157+
150158
fn normalization() -> NormalizationStrategy {
151159
NormalizationStrategy::Eager
152160
}

compiler/rustc_error_codes/src/error_codes/E0275.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ trait Foo {}
88
struct Bar<T>(T);
99
1010
impl<T> Foo for T where Bar<T>: Foo {}
11+
12+
fn takes_foo<T: Foo>() {}
13+
14+
fn calls_takes_foo() {
15+
takes_foo::<()>();
16+
}
1117
```
1218

1319
This error occurs when there was a recursive trait requirement that overflowed

compiler/rustc_infer/src/infer/at.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub struct At<'a, 'tcx> {
4040
/// matching from matching anything against opaque
4141
/// types.
4242
pub define_opaque_types: bool,
43+
pub defer_projection_equality: bool,
4344
}
4445

4546
pub struct Trace<'a, 'tcx> {
@@ -55,7 +56,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
5556
cause: &'a ObligationCause<'tcx>,
5657
param_env: ty::ParamEnv<'tcx>,
5758
) -> At<'a, 'tcx> {
58-
At { infcx: self, cause, param_env, define_opaque_types: true }
59+
At {
60+
infcx: self,
61+
cause,
62+
param_env,
63+
define_opaque_types: true,
64+
defer_projection_equality: true,
65+
}
5966
}
6067

6168
/// Forks the inference context, creating a new inference context with the same inference
@@ -101,6 +108,10 @@ impl<'a, 'tcx> At<'a, 'tcx> {
101108
Self { define_opaque_types, ..self }
102109
}
103110

111+
pub fn defer_projection_equality(self, defer_projection_equality: bool) -> Self {
112+
Self { defer_projection_equality, ..self }
113+
}
114+
104115
/// Hacky routine for equating two impl headers in coherence.
105116
pub fn eq_impl_headers(
106117
self,
@@ -252,7 +263,12 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
252263
{
253264
let Trace { at, trace, a_is_expected } = self;
254265
at.infcx.commit_if_ok(|_| {
255-
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
266+
let mut fields = at.infcx.combine_fields(
267+
trace,
268+
at.param_env,
269+
at.define_opaque_types,
270+
at.defer_projection_equality,
271+
);
256272
fields
257273
.sub(a_is_expected)
258274
.relate(a, b)
@@ -269,7 +285,12 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
269285
{
270286
let Trace { at, trace, a_is_expected } = self;
271287
at.infcx.commit_if_ok(|_| {
272-
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
288+
let mut fields = at.infcx.combine_fields(
289+
trace,
290+
at.param_env,
291+
at.define_opaque_types,
292+
at.defer_projection_equality,
293+
);
273294
fields
274295
.equate(a_is_expected)
275296
.relate(a, b)
@@ -284,7 +305,12 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
284305
{
285306
let Trace { at, trace, a_is_expected } = self;
286307
at.infcx.commit_if_ok(|_| {
287-
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
308+
let mut fields = at.infcx.combine_fields(
309+
trace,
310+
at.param_env,
311+
at.define_opaque_types,
312+
at.defer_projection_equality,
313+
);
288314
fields
289315
.lub(a_is_expected)
290316
.relate(a, b)
@@ -299,7 +325,12 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
299325
{
300326
let Trace { at, trace, a_is_expected } = self;
301327
at.infcx.commit_if_ok(|_| {
302-
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
328+
let mut fields = at.infcx.combine_fields(
329+
trace,
330+
at.param_env,
331+
at.define_opaque_types,
332+
at.defer_projection_equality,
333+
);
303334
fields
304335
.glb(a_is_expected)
305336
.relate(a, b)

compiler/rustc_infer/src/infer/canonical/query_response.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,23 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
733733
span_bug!(self.cause.span(), "generic_const_exprs: unreachable `const_equate`");
734734
}
735735

736+
fn projection_equate(&mut self, projection_ty: ty::ProjectionTy<'tcx>, ty: Ty<'tcx>) {
737+
self.obligations.push(Obligation {
738+
cause: self.cause.clone(),
739+
param_env: self.param_env,
740+
predicate: ty::Binder::dummy(ty::PredicateKind::Projection(ty::ProjectionPredicate {
741+
projection_ty,
742+
term: ty::Term::from(ty),
743+
}))
744+
.to_predicate(self.infcx.tcx),
745+
recursion_depth: 0,
746+
})
747+
}
748+
749+
fn defer_projection_equality(&self) -> bool {
750+
true
751+
}
752+
736753
fn normalization() -> NormalizationStrategy {
737754
NormalizationStrategy::Eager
738755
}

compiler/rustc_infer/src/infer/combine.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub struct CombineFields<'infcx, 'tcx> {
5454
/// matching from matching anything against opaque
5555
/// types.
5656
pub define_opaque_types: bool,
57+
pub defer_projection_equality: bool,
5758
}
5859

5960
#[derive(Copy, Clone, Debug)]
@@ -457,6 +458,19 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
457458
ty::Binder::dummy(predicate).to_predicate(self.tcx()),
458459
));
459460
}
461+
462+
pub fn add_projection_equate_obligation(
463+
&mut self,
464+
projection_ty: ty::ProjectionTy<'tcx>,
465+
ty: Ty<'tcx>,
466+
) {
467+
self.obligations.push(Obligation::new(
468+
self.trace.cause.clone(),
469+
self.param_env,
470+
ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty::Term::from(ty) })
471+
.to_predicate(self.tcx()),
472+
));
473+
}
460474
}
461475

462476
struct Generalizer<'cx, 'tcx> {
@@ -759,6 +773,18 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
759773
_ => relate::super_relate_consts(self, c, c),
760774
}
761775
}
776+
777+
fn projection_equate_obligation(
778+
&mut self,
779+
_projection_ty: ty::ProjectionTy<'tcx>,
780+
_ty: Ty<'tcx>,
781+
) {
782+
bug!("`TypeGeneralizer` shouldn't equate projections with other kinds of types");
783+
}
784+
785+
fn defer_projection_equality(&self) -> bool {
786+
bug!("`TypeGeneralizer` shouldn't equate projections with other kinds of types");
787+
}
762788
}
763789

764790
pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
@@ -982,4 +1008,16 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
9821008
_ => relate::super_relate_consts(self, c, c),
9831009
}
9841010
}
1011+
1012+
fn projection_equate_obligation(
1013+
&mut self,
1014+
_projection_ty: ty::ProjectionTy<'tcx>,
1015+
_ty: Ty<'tcx>,
1016+
) {
1017+
bug!("`ConstInferUnifier` shouldn't equate projections with other kinds of types");
1018+
}
1019+
1020+
fn defer_projection_equality(&self) -> bool {
1021+
bug!("`ConstInferUnifier` shouldn't equate projections with other kinds of types");
1022+
}
9851023
}

compiler/rustc_infer/src/infer/equate.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,18 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
160160
}
161161
Ok(a)
162162
}
163+
164+
fn projection_equate_obligation(
165+
&mut self,
166+
projection_ty: ty::ProjectionTy<'tcx>,
167+
ty: Ty<'tcx>,
168+
) {
169+
self.fields.add_projection_equate_obligation(projection_ty, ty);
170+
}
171+
172+
fn defer_projection_equality(&self) -> bool {
173+
self.fields.defer_projection_equality
174+
}
163175
}
164176

165177
impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,6 +2777,18 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
27772777
// relation
27782778
Ok(a)
27792779
}
2780+
2781+
fn projection_equate_obligation(
2782+
&mut self,
2783+
projection_ty: ty::ProjectionTy<'tcx>,
2784+
ty: Ty<'tcx>,
2785+
) {
2786+
unreachable!()
2787+
}
2788+
2789+
fn defer_projection_equality(&self) -> bool {
2790+
false
2791+
}
27802792
}
27812793

27822794
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

compiler/rustc_infer/src/infer/glb.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
110110
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
111111
}
112112
}
113+
114+
fn projection_equate_obligation(
115+
&mut self,
116+
projection_ty: ty::ProjectionTy<'tcx>,
117+
ty: Ty<'tcx>,
118+
) {
119+
self.fields.add_projection_equate_obligation(projection_ty, ty);
120+
}
121+
122+
fn defer_projection_equality(&self) -> bool {
123+
self.fields.defer_projection_equality
124+
}
113125
}
114126

115127
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> {

compiler/rustc_infer/src/infer/lub.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
110110
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
111111
}
112112
}
113+
114+
fn projection_equate_obligation(
115+
&mut self,
116+
projection_ty: ty::ProjectionTy<'tcx>,
117+
ty: Ty<'tcx>,
118+
) {
119+
self.fields.add_projection_equate_obligation(projection_ty, ty);
120+
}
121+
122+
fn defer_projection_equality(&self) -> bool {
123+
self.fields.defer_projection_equality
124+
}
113125
}
114126

115127
impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
784784
trace: TypeTrace<'tcx>,
785785
param_env: ty::ParamEnv<'tcx>,
786786
define_opaque_types: bool,
787+
defer_projection_equality: bool,
787788
) -> CombineFields<'a, 'tcx> {
788789
CombineFields {
789790
infcx: self,
@@ -792,6 +793,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
792793
param_env,
793794
obligations: PredicateObligations::new(),
794795
define_opaque_types,
796+
defer_projection_equality,
795797
}
796798
}
797799

0 commit comments

Comments
 (0)