Skip to content

Commit 83c5028

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 373c735 commit 83c5028

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

+343
-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

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

391-
let predicates = trait_predicates.filter_map(|obligation| {
395+
let predicates = item_predicates.filter_map(|obligation| {
392396
let pred = obligation.predicate;
393397
match pred.kind() {
394398
ty::PredicateKind::Trait(tr, _) => {
395399
if let ty::Projection(p) = tr.skip_binder().self_ty().kind {
396-
if p.item_def_id == def_id && p.substs.starts_with(trait_substs) {
400+
if p == assoc_item_ty {
397401
return Some(pred);
398402
}
399403
}
400404
}
401405
ty::PredicateKind::Projection(proj) => {
402406
if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind {
403-
if p.item_def_id == def_id && p.substs.starts_with(trait_substs) {
407+
if p == assoc_item_ty {
408+
return Some(pred);
409+
}
410+
}
411+
}
412+
ty::PredicateKind::TypeOutlives(outlives) => {
413+
if let ty::Projection(p) = outlives.skip_binder().0.kind {
414+
if p == assoc_item_ty {
404415
return Some(pred);
405416
}
406417
}
@@ -411,21 +422,25 @@ fn associated_type_projection_predicates(
411422
});
412423

413424
let result = tcx.mk_predicates(predicates);
414-
debug!("associated_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result);
425+
debug!(
426+
"associated_type_projection_predicates({}) = {:?}",
427+
tcx.def_path_str(assoc_item_def_id),
428+
result
429+
);
415430
result
416431
}
417432

418-
/// Opaque types might not have the same issues as associated types, but we use a
433+
/// Opaque types don't have the same issues as associated types, but we use a
419434
/// similar filtering for consistency.
420435
fn opaque_type_projection_predicates(
421436
tcx: TyCtxt<'_>,
422437
def_id: DefId,
423438
) -> &'_ ty::List<ty::Predicate<'_>> {
424439
let substs = InternalSubsts::identity_for_item(tcx, def_id);
425440

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

430445
let filtered_predicates = predicates.filter_map(|obligation| {
431446
let pred = obligation.predicate;
@@ -446,8 +461,22 @@ fn opaque_type_projection_predicates(
446461
}
447462
}
448463
}
464+
ty::PredicateKind::TypeOutlives(outlives) => {
465+
if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind {
466+
if opaque_def_id == def_id && opaque_substs == substs {
467+
return Some(pred);
468+
}
469+
} else {
470+
// These can come from elaborating other predicates
471+
return None;
472+
}
473+
}
474+
// These can come from elaborating other predicates
475+
ty::PredicateKind::RegionOutlives(_) => return None,
449476
_ => {}
450477
}
478+
// Other predicates are currently only possible for type alias impl
479+
// trait. After #72080 is merged this can be a (delayed?) bug.
451480
None
452481
});
453482

src/librustc_typeck/check/compare_method.rs

+14-30
Original file line numberDiff line numberDiff line change
@@ -1185,16 +1185,18 @@ fn compare_projection_bounds<'tcx>(
11851185
impl_ty_span: Span,
11861186
impl_trait_ref: ty::TraitRef<'tcx>,
11871187
) -> Result<(), ErrorReported> {
1188-
let is_gat = !tcx.generics_of(impl_ty.def_id).params.is_empty();
1189-
if impl_ty.defaultness.is_final() && !is_gat {
1188+
let have_gats = tcx.features().generic_associated_types;
1189+
if impl_ty.defaultness.is_final() && !have_gats {
11901190
// For "final", non-generic associate type implementations, we
11911191
// don't need this as described above.
11921192
return Ok(());
11931193
}
11941194

11951195
let param_env = tcx.param_env(impl_ty.def_id);
11961196

1197-
let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.container.id());
1197+
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
1198+
let rebased_substs =
1199+
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
11981200
let impl_ty_value = tcx.type_of(impl_ty.def_id);
11991201

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

@@ -1246,7 +1225,7 @@ fn compare_projection_bounds<'tcx>(
12461225
let cause = ObligationCause {
12471226
span: impl_ty_span,
12481227
body_id: impl_ty_hir_id,
1249-
code: ObligationCauseCode::ItemObligation(impl_trait_ref.def_id),
1228+
code: ObligationCauseCode::ItemObligation(trait_ty.def_id),
12501229
};
12511230

12521231
let predicates = tcx.projection_predicates(trait_ty.def_id);
@@ -1271,10 +1250,15 @@ fn compare_projection_bounds<'tcx>(
12711250
substs: projection_substs,
12721251
item_def_id: projection.projection_ty.item_def_id,
12731252
},
1274-
ty: projection.ty.subst(tcx, impl_trait_ref.substs),
1253+
ty: projection.ty.subst(tcx, rebased_substs),
12751254
}
12761255
})
12771256
.to_predicate(tcx),
1257+
ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives
1258+
.map_bound(|outlives| {
1259+
ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs))
1260+
})
1261+
.to_predicate(tcx),
12781262
_ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
12791263
};
12801264

0 commit comments

Comments
 (0)