Skip to content

Commit db4826d

Browse files
committed
Move bounds on associated types to the type
Given `trait X { type U; }` the bound `<Self as X>::U` now lives on the type, rather than the trait. This is feature gated on `feature(generic_associated_types)` for now until more testing can be done. The also enabled type-generic associated types since we no longer need "implies bounds".
1 parent 9818bc0 commit db4826d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+342
-495
lines changed

src/librustc_infer/infer/outlives/verify.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use crate::infer::outlives::env::RegionBoundPairs;
22
use crate::infer::{GenericKind, VerifyBound};
3-
use crate::traits;
43
use rustc_data_structures::captures::Captures;
54
use rustc_hir::def_id::DefId;
6-
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
5+
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
76
use rustc_middle::ty::{self, Ty, TyCtxt};
87

98
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
@@ -311,18 +310,14 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
311310
fn region_bounds_declared_on_associated_item(
312311
&self,
313312
assoc_item_def_id: DefId,
314-
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
313+
) -> impl Iterator<Item = ty::Region<'tcx>> {
315314
let tcx = self.tcx;
316-
let assoc_item = tcx.associated_item(assoc_item_def_id);
317-
let trait_def_id = assoc_item.container.assert_trait();
318-
let trait_predicates = tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p);
319-
let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id);
320-
let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
321-
self.collect_outlives_from_predicate_list(
322-
move |ty| ty == identity_proj,
323-
traits::elaborate_predicates(tcx, trait_predicates).map(|o| o.predicate),
324-
)
325-
.map(|b| b.1)
315+
let predicates = tcx.projection_predicates(assoc_item_def_id);
316+
predicates
317+
.into_iter()
318+
.filter_map(|p| p.to_opt_type_outlives())
319+
.filter_map(|p| p.no_bound_vars())
320+
.map(|b| b.1)
326321
}
327322

328323
/// Searches through a predicate list for a predicate `T: 'a`.

src/librustc_infer/traits/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ pub use self::project::{
2525
Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
2626
ProjectionCacheStorage, Reveal,
2727
};
28-
crate use self::util::elaborate_predicates;
29-
3028
pub use rustc_middle::traits::*;
3129

3230
/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for

src/librustc_middle/query/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ rustc_queries! {
136136
/// Returns the list of predicates that can be used for
137137
/// `SelectionCandidate::ProjectionCandidate` and
138138
/// `ProjectionTyCandidate::TraitDef`.
139+
/// Specifically this is the bounds (equivalent to) those
140+
/// written on the trait's type definition, or those
141+
/// after the `impl` keyword
142+
///
143+
/// type X: Bound + 'lt
144+
/// ^^^^^^^^^^^
145+
/// impl Debug + Display
146+
/// ^^^^^^^^^^^^^^^
147+
///
148+
/// `key` is the `DefId` of the associated type or opaque type.
139149
query projection_predicates(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
140150
desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) }
141151
}

src/librustc_ty/ty.rs

+42-15
Original file line numberDiff line numberDiff line change
@@ -371,34 +371,45 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
371371
/// (`type X: Trait`) to be used as candidates. We also allow the same bounds
372372
/// when desugared as bounds on the trait `where Self::X: Trait`.
373373
///
374-
/// Note that this filtering is done with the trait's identity substs to
374+
/// Note that this filtering is done with the items identity substs to
375375
/// simplify checking that these bounds are met in impls. This means that
376376
/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
377377
/// `hr-associated-type-bound-1.rs`.
378378
fn associated_type_projection_predicates(
379379
tcx: TyCtxt<'_>,
380-
def_id: DefId,
380+
assoc_item_def_id: DefId,
381381
) -> &'_ ty::List<ty::Predicate<'_>> {
382-
let trait_id = tcx.associated_item(def_id).container.id();
383-
let trait_substs = InternalSubsts::identity_for_item(tcx, trait_id);
384-
385-
let generic_trait_bounds = tcx.predicates_of(trait_id);
386-
let trait_bounds = generic_trait_bounds.instantiate_identity(tcx);
387-
let trait_predicates = util::elaborate_predicates(tcx, trait_bounds.predicates.into_iter());
382+
let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id);
383+
// We include predicates from the trait as well to handle
384+
// `where Self::X: Trait`.
385+
let item_bounds = generic_trait_bounds.instantiate_identity(tcx);
386+
let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter());
387+
388+
let assoc_item_ty = ty::ProjectionTy {
389+
item_def_id: assoc_item_def_id,
390+
substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
391+
};
388392

389-
let predicates = trait_predicates.filter_map(|obligation| {
393+
let predicates = item_predicates.filter_map(|obligation| {
390394
let pred = obligation.predicate;
391395
match pred.kind() {
392396
ty::PredicateKind::Trait(tr, _) => {
393397
if let ty::Projection(p) = tr.skip_binder().self_ty().kind {
394-
if p.item_def_id == def_id && p.substs.starts_with(trait_substs) {
398+
if p == assoc_item_ty {
395399
return Some(pred);
396400
}
397401
}
398402
}
399403
ty::PredicateKind::Projection(proj) => {
400404
if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind {
401-
if p.item_def_id == def_id && p.substs.starts_with(trait_substs) {
405+
if p == assoc_item_ty {
406+
return Some(pred);
407+
}
408+
}
409+
}
410+
ty::PredicateKind::TypeOutlives(outlives) => {
411+
if let ty::Projection(p) = outlives.skip_binder().0.kind {
412+
if p == assoc_item_ty {
402413
return Some(pred);
403414
}
404415
}
@@ -409,7 +420,11 @@ fn associated_type_projection_predicates(
409420
});
410421

411422
let result = tcx.mk_predicates(predicates);
412-
debug!("associated_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result);
423+
debug!(
424+
"associated_type_projection_predicates({}) = {:?}",
425+
tcx.def_path_str(assoc_item_def_id),
426+
result
427+
);
413428
result
414429
}
415430

@@ -422,9 +437,9 @@ fn opaque_type_projection_predicates(
422437
) -> &'_ ty::List<ty::Predicate<'_>> {
423438
let substs = InternalSubsts::identity_for_item(tcx, def_id);
424439

425-
let generics_bounds = tcx.predicates_of(def_id);
426-
let bounds = generics_bounds.instantiate_identity(tcx);
427-
let predicates = util::elaborate_predicates(tcx, bounds.predicates.into_iter());
440+
let bounds = tcx.predicates_of(def_id);
441+
let predicates =
442+
util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred));
428443

429444
let filtered_predicates = predicates.filter_map(|obligation| {
430445
let pred = obligation.predicate;
@@ -445,6 +460,18 @@ fn opaque_type_projection_predicates(
445460
}
446461
}
447462
}
463+
ty::PredicateKind::TypeOutlives(outlives) => {
464+
if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind {
465+
if opaque_def_id == def_id && opaque_substs == substs {
466+
return Some(pred);
467+
}
468+
} else {
469+
// These can come from elaborating other predicates
470+
return None;
471+
}
472+
}
473+
// These can come from elaborating other predicates
474+
ty::PredicateKind::RegionOutlives(_) => return None,
448475
_ => {}
449476
}
450477
tcx.sess.delay_span_bug(

src/librustc_typeck/check/compare_method.rs

+13-29
Original file line numberDiff line numberDiff line change
@@ -1189,16 +1189,18 @@ fn compare_projection_bounds<'tcx>(
11891189
impl_ty_span: Span,
11901190
impl_trait_ref: ty::TraitRef<'tcx>,
11911191
) -> Result<(), ErrorReported> {
1192-
let is_gat = !tcx.generics_of(impl_ty.def_id).params.is_empty();
1193-
if impl_ty.defaultness.is_final() && !is_gat {
1192+
let have_gats = tcx.features().generic_associated_types;
1193+
if impl_ty.defaultness.is_final() && !have_gats {
11941194
// For "final", non-generic associate type implementations, we
11951195
// don't need this as described above.
11961196
return Ok(());
11971197
}
11981198

11991199
let param_env = tcx.param_env(impl_ty.def_id);
12001200

1201-
let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.container.id());
1201+
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
1202+
let rebased_substs =
1203+
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
12021204
let impl_ty_value = tcx.type_of(impl_ty.def_id);
12031205

12041206
// Map the predicate from the trait to the corresponding one for the impl.
@@ -1211,32 +1213,9 @@ fn compare_projection_bounds<'tcx>(
12111213
// function would translate and partially normalize
12121214
// `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`.
12131215
let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| {
1214-
let normalized_self = if !is_gat {
1215-
// projection_predicates only includes projections where the
1216-
// substs of the trait ref are exactly the trait's identity
1217-
// substs, so we can simply return the value from the impl.
1218-
impl_ty_value
1219-
} else {
1220-
let predicate_self_ty = predicate_substs.type_at(0);
1221-
let impl_ty_substs = if let ty::Projection(p) = predicate_self_ty.kind {
1222-
assert!(
1223-
p.item_def_id == trait_ty.def_id,
1224-
"projection_predicates returned predicate for the wrong type: {}",
1225-
predicate_self_ty,
1226-
);
1227-
p.substs.rebase_onto(tcx, impl_trait_ref.def_id, impl_substs)
1228-
} else {
1229-
bug!(
1230-
"projection_predicates returned predicate for the wrong type `{}`",
1231-
predicate_self_ty,
1232-
);
1233-
};
1234-
impl_ty_value.subst(tcx, impl_ty_substs)
1235-
};
1236-
12371216
tcx.mk_substs(
1238-
iter::once(normalized_self.into())
1239-
.chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, impl_trait_ref.substs))),
1217+
iter::once(impl_ty_value.into())
1218+
.chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))),
12401219
)
12411220
};
12421221

@@ -1275,10 +1254,15 @@ fn compare_projection_bounds<'tcx>(
12751254
substs: projection_substs,
12761255
item_def_id: projection.projection_ty.item_def_id,
12771256
},
1278-
ty: projection.ty.subst(tcx, impl_trait_ref.substs),
1257+
ty: projection.ty.subst(tcx, rebased_substs),
12791258
}
12801259
})
12811260
.to_predicate(tcx),
1261+
ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives
1262+
.map_bound(|outlives| {
1263+
ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs))
1264+
})
1265+
.to_predicate(tcx),
12821266
_ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
12831267
};
12841268

0 commit comments

Comments
 (0)