Skip to content

Commit 0dfa6ff

Browse files
committed
Avoid cycles from projection bounds
Only check the own predicates of associated types when confirming projection candidates. Also consider implied bounds when comparing trait and impl methods.
1 parent 596d6c4 commit 0dfa6ff

File tree

11 files changed

+118
-81
lines changed

11 files changed

+118
-81
lines changed

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
2828
use rustc_middle::ty::subst::Subst;
2929
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
3030
use rustc_span::symbol::sym;
31-
use rustc_span::DUMMY_SP;
3231

3332
pub use rustc_middle::traits::Reveal;
3433

@@ -1409,6 +1408,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
14091408
match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
14101409
Ok(InferOk { value: _, obligations }) => {
14111410
nested_obligations.extend(obligations);
1411+
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
14121412
Progress { ty: cache_entry.ty, obligations: nested_obligations }
14131413
}
14141414
Err(e) => {
@@ -1430,7 +1430,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
14301430
) -> Progress<'tcx> {
14311431
let tcx = selcx.tcx();
14321432

1433-
let ImplSourceUserDefinedData { impl_def_id, substs, nested } = impl_impl_source;
1433+
let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source;
14341434
let assoc_item_id = obligation.predicate.item_def_id;
14351435
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
14361436

@@ -1463,15 +1463,48 @@ fn confirm_impl_candidate<'cx, 'tcx>(
14631463
let ty = tcx.type_of(assoc_ty.item.def_id);
14641464
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
14651465
let err = tcx.ty_error_with_message(
1466-
DUMMY_SP,
1466+
obligation.cause.span,
14671467
"impl item and trait item have different parameter counts",
14681468
);
14691469
Progress { ty: err, obligations: nested }
14701470
} else {
1471+
assoc_ty_own_obligations(selcx, obligation, &mut nested);
14711472
Progress { ty: ty.subst(tcx, substs), obligations: nested }
14721473
}
14731474
}
14741475

1476+
// Get obligations corresponding to the predicates from the where-clause of the
1477+
// associated type itself.
1478+
// Note: `feature(generic_associated_types)` is required to write such
1479+
// predicates, even for non-generic associcated types.
1480+
fn assoc_ty_own_obligations<'cx, 'tcx>(
1481+
selcx: &mut SelectionContext<'cx, 'tcx>,
1482+
obligation: &ProjectionTyObligation<'tcx>,
1483+
nested: &mut Vec<PredicateObligation<'tcx>>,
1484+
) {
1485+
let tcx = selcx.tcx();
1486+
for predicate in tcx
1487+
.predicates_of(obligation.predicate.item_def_id)
1488+
.instantiate_own(tcx, obligation.predicate.substs)
1489+
.predicates
1490+
{
1491+
let normalized = normalize_with_depth_to(
1492+
selcx,
1493+
obligation.param_env,
1494+
obligation.cause.clone(),
1495+
obligation.recursion_depth + 1,
1496+
&predicate,
1497+
nested,
1498+
);
1499+
nested.push(Obligation::with_depth(
1500+
obligation.cause.clone(),
1501+
obligation.recursion_depth + 1,
1502+
obligation.param_env,
1503+
normalized,
1504+
));
1505+
}
1506+
}
1507+
14751508
/// Locate the definition of an associated type in the specialization hierarchy,
14761509
/// starting from the given impl.
14771510
///

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
157157
);
158158
}),
159159
);
160-
// Require that the projection is well-formed.
161-
let self_ty = self.infcx.replace_bound_vars_with_placeholders(&bound_self_ty);
162-
let self_ty = normalize_with_depth_to(
163-
self,
164-
obligation.param_env,
165-
obligation.cause.clone(),
166-
obligation.recursion_depth + 1,
167-
&self_ty,
168-
&mut obligations,
169-
);
170-
obligations.push(Obligation::with_depth(
171-
obligation.cause.clone(),
172-
obligation.recursion_depth + 1,
173-
obligation.param_env,
174-
ty::PredicateKind::WellFormed(self_ty.into()).to_predicate(tcx),
175-
));
160+
161+
if let ty::Projection(..) = bound_self_ty.skip_binder().kind {
162+
for predicate in tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates {
163+
let normalized = normalize_with_depth_to(
164+
self,
165+
obligation.param_env,
166+
obligation.cause.clone(),
167+
obligation.recursion_depth + 1,
168+
&predicate,
169+
&mut obligations,
170+
);
171+
obligations.push(Obligation::with_depth(
172+
obligation.cause.clone(),
173+
obligation.recursion_depth + 1,
174+
obligation.param_env,
175+
normalized,
176+
));
177+
}
178+
}
179+
176180
obligations
177181
})
178182
}

compiler/rustc_typeck/src/check/compare_method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ fn compare_predicate_entailment<'tcx>(
328328
// Finally, resolve all regions. This catches wily misuses of
329329
// lifetime parameters.
330330
let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
331-
fcx.regionck_item(impl_m_hir_id, impl_m_span, &[]);
331+
fcx.regionck_item(impl_m_hir_id, impl_m_span, trait_sig.inputs_and_output);
332332

333333
Ok(())
334334
})
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// check-pass
2+
3+
trait IntoIt {
4+
type Item;
5+
}
6+
7+
impl<I> IntoIt for I {
8+
type Item = ();
9+
}
10+
11+
trait BaseGraph
12+
where
13+
<Self::VertexIter as IntoIt>::Item: Sized,
14+
{
15+
type VertexIter: IntoIt;
16+
}
17+
18+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// check-pass
2+
3+
trait A {
4+
type U: Copy;
5+
}
6+
7+
trait B where
8+
<Self::V as A>::U: Copy,
9+
{
10+
type V: A;
11+
}
12+
13+
fn main() {}
Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
1-
#![feature(box_syntax)]
1+
// check-pass
22

3-
struct Ctxt { v: usize }
3+
struct Ctxt {
4+
v: usize,
5+
}
46

57
trait GetCtxt {
68
// Here the `&` is bound in the method definition:
79
fn get_ctxt(&self) -> &Ctxt;
810
}
911

10-
struct HasCtxt<'a> { c: &'a Ctxt }
12+
struct HasCtxt<'a> {
13+
c: &'a Ctxt,
14+
}
1115

1216
impl<'a> GetCtxt for HasCtxt<'a> {
13-
14-
// Here an error occurs because we used `&self` but
15-
// the definition used `&`:
16-
fn get_ctxt(&self) -> &'a Ctxt { //~ ERROR method not compatible with trait
17+
// Ok: Have implied bound of WF(&'b HasCtxt<'a>)
18+
// so know 'a: 'b
19+
// so know &'a Ctxt <: &'b Ctxt
20+
fn get_ctxt<'b>(&'b self) -> &'a Ctxt {
1721
self.c
1822
}
19-
2023
}
2124

22-
fn get_v(gc: Box<dyn GetCtxt>) -> usize {
25+
fn get_v(gc: Box<dyn GetCtxt + '_>) -> usize {
2326
gc.get_ctxt().v
2427
}
2528

2629
fn main() {
2730
let ctxt = Ctxt { v: 22 };
2831
let hc = HasCtxt { c: &ctxt };
29-
assert_eq!(get_v(box hc as Box<dyn GetCtxt>), 22);
32+
assert_eq!(get_v(Box::new(hc) as Box<dyn GetCtxt>), 22);
3033
}

src/test/ui/regions/regions-trait-1.stderr

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/test/ui/specialization/issue-38091-2.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
// build-fail
2+
//~^ ERROR overflow evaluating the requirement `i32: Check`
3+
14
#![feature(specialization)]
25
//~^ WARN the feature `specialization` is incomplete
36

47
trait Iterate<'a> {
58
type Ty: Valid;
69
fn iterate(self);
710
}
8-
impl<'a, T> Iterate<'a> for T where T: Check {
11+
impl<'a, T> Iterate<'a> for T
12+
where
13+
T: Check,
14+
{
915
default type Ty = ();
1016
default fn iterate(self) {}
1117
}
@@ -19,5 +25,4 @@ impl Valid for () {}
1925

2026
fn main() {
2127
Iterate::iterate(0);
22-
//~^ ERROR overflow evaluating the requirement `{integer}: Check`
2328
}

src/test/ui/specialization/issue-38091-2.stderr

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2-
--> $DIR/issue-38091-2.rs:1:12
2+
--> $DIR/issue-38091-2.rs:4:12
33
|
44
LL | #![feature(specialization)]
55
| ^^^^^^^^^^^^^^
66
|
77
= note: `#[warn(incomplete_features)]` on by default
88
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
99

10-
error[E0275]: overflow evaluating the requirement `{integer}: Check`
11-
--> $DIR/issue-38091-2.rs:21:5
10+
error[E0275]: overflow evaluating the requirement `i32: Check`
1211
|
13-
LL | fn iterate(self);
14-
| ----------------- required by `Iterate::iterate`
15-
...
16-
LL | Iterate::iterate(0);
17-
| ^^^^^^^^^^^^^^^^
18-
|
19-
= note: required because of the requirements on the impl of `Iterate<'_>` for `{integer}`
12+
= note: required because of the requirements on the impl of `Iterate` for `i32`
2013

2114
error: aborting due to previous error; 1 warning emitted
2215

src/test/ui/specialization/issue-38091.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ trait Iterate<'a> {
55
type Ty: Valid;
66
fn iterate(self);
77
}
8-
impl<'a, T> Iterate<'a> for T where T: Check {
8+
impl<'a, T> Iterate<'a> for T
9+
where
10+
T: Check,
11+
{
912
default type Ty = ();
1013
//~^ ERROR the trait bound `(): Valid` is not satisfied
1114
default fn iterate(self) {}
@@ -18,5 +21,4 @@ trait Valid {}
1821

1922
fn main() {
2023
Iterate::iterate(0);
21-
//~^ ERROR overflow evaluating the requirement `{integer}: Check`
2224
}

src/test/ui/specialization/issue-38091.stderr

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,14 @@ LL | #![feature(specialization)]
88
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
99

1010
error[E0277]: the trait bound `(): Valid` is not satisfied
11-
--> $DIR/issue-38091.rs:9:5
11+
--> $DIR/issue-38091.rs:12:5
1212
|
1313
LL | type Ty: Valid;
1414
| ----- required by this bound in `Iterate::Ty`
1515
...
1616
LL | default type Ty = ();
1717
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()`
1818

19-
error[E0275]: overflow evaluating the requirement `{integer}: Check`
20-
--> $DIR/issue-38091.rs:20:5
21-
|
22-
LL | fn iterate(self);
23-
| ----------------- required by `Iterate::iterate`
24-
...
25-
LL | Iterate::iterate(0);
26-
| ^^^^^^^^^^^^^^^^
27-
|
28-
= note: required because of the requirements on the impl of `Iterate<'_>` for `{integer}`
29-
30-
error: aborting due to 2 previous errors; 1 warning emitted
19+
error: aborting due to previous error; 1 warning emitted
3120

32-
Some errors have detailed explanations: E0275, E0277.
33-
For more information about an error, try `rustc --explain E0275`.
21+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)