Skip to content

Commit 1a171d0

Browse files
authored
Rollup merge of #72788 - matthewjasper:projection-bound-validation, r=nikomatsakis
Projection bound validation During selection we use bounds declared on associated types (e.g. `type X: Copy`) to satisfy trait/projection bounds. This would be fine so long as those bounds are checked on any impls/trait objects. For simple cases they are because the bound `Self::X: Copy` gets normalized when we check the impl. However, for default values with specialization and higher-ranked bounds from GATs or otherwise, we can't normalize when checking the impl, and so we use the bound from the trait to prove that the bound applies to the impl, which is clearly unsound. This PR makes 2 fixes for this: 1. Requiring that the bounds on the trait apply to a projection type with the corresponding substs, so a bound `for<'a> <Self as X<'a>>::U: Copy` on the trait cannot be used to prove `<T as X<'_>>::U: Copy`. 2. Actually checking that the bounds that we still allow apply to generic/default associated types. Opening for a crater run. Closes #68641 Closes #68642 Closes #68643 Closes #68644 Closes #68645 Closes #68656 r? @ghost
2 parents a1404a9 + 5e8c9f4 commit 1a171d0

File tree

86 files changed

+1584
-490
lines changed

Some content is hidden

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

86 files changed

+1584
-490
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

+17
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,23 @@ rustc_queries! {
133133
cache_on_disk_if { key.is_local() }
134134
}
135135

136+
/// Returns the list of predicates that can be used for
137+
/// `SelectionCandidate::ProjectionCandidate` and
138+
/// `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.
149+
query projection_predicates(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
150+
desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) }
151+
}
152+
136153
query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
137154
desc { "looking up the native libraries of a linked crate" }
138155
}

src/librustc_middle/ty/flags.rs

-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ impl FlagComputation {
9393

9494
&ty::Bound(debruijn, _) => {
9595
self.add_binder(debruijn);
96-
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
9796
}
9897

9998
&ty::Placeholder(..) => {
@@ -216,7 +215,6 @@ impl FlagComputation {
216215
}
217216
ty::ConstKind::Bound(debruijn, _) => {
218217
self.add_binder(debruijn);
219-
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
220218
}
221219
ty::ConstKind::Param(_) => {
222220
self.add_flags(TypeFlags::HAS_CT_PARAM);

src/librustc_middle/ty/sty.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1589,19 +1589,16 @@ impl RegionKind {
15891589
flags = flags | TypeFlags::HAS_FREE_REGIONS;
15901590
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
15911591
flags = flags | TypeFlags::HAS_RE_INFER;
1592-
flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
15931592
}
15941593
ty::RePlaceholder(..) => {
15951594
flags = flags | TypeFlags::HAS_FREE_REGIONS;
15961595
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
15971596
flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
1598-
flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
15991597
}
16001598
ty::ReEarlyBound(..) => {
16011599
flags = flags | TypeFlags::HAS_FREE_REGIONS;
16021600
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
16031601
flags = flags | TypeFlags::HAS_RE_PARAM;
1604-
flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
16051602
}
16061603
ty::ReFree { .. } => {
16071604
flags = flags | TypeFlags::HAS_FREE_REGIONS;

src/librustc_middle/ty/subst.rs

+11
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,17 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
333333
/// in a different item, with `target_substs` as the base for
334334
/// the target impl/trait, with the source child-specific
335335
/// parameters (e.g., method parameters) on top of that base.
336+
///
337+
/// For example given:
338+
///
339+
/// trait X<S> { fn f<T>(); }
340+
/// impl<U> X<U> for U { fn f<V>() {} }
341+
///
342+
/// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait.
343+
/// * If `source_ancestor` is the def_id of the trait.
344+
/// * If `target_substs` is `[U]`, the substs for the impl.
345+
/// * Then we will return `[U, T]`, the subst for `f` in the impl that
346+
/// are needed for it to match the trait.
336347
pub fn rebase_onto(
337348
&self,
338349
tcx: TyCtxt<'tcx>,

src/librustc_resolve/late/lifetimes.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
883883
})
884884
.collect();
885885
if !lifetimes.is_empty() {
886-
self.trait_ref_hack = true;
887886
let next_early_index = self.next_early_index();
888887
let scope = Scope::Binder {
889888
lifetimes,
@@ -895,9 +894,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
895894
let result = self.with(scope, |old_scope, this| {
896895
this.check_lifetime_params(old_scope, &bound_generic_params);
897896
this.visit_ty(&bounded_ty);
897+
this.trait_ref_hack = true;
898898
walk_list!(this, visit_param_bound, bounds);
899+
this.trait_ref_hack = false;
899900
});
900-
self.trait_ref_hack = false;
901901
result
902902
} else {
903903
self.visit_ty(&bounded_ty);
@@ -932,13 +932,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
932932
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
933933

934934
let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
935-
if !self.trait_ref_hack
935+
936+
let trait_ref_hack = take(&mut self.trait_ref_hack);
937+
if !trait_ref_hack
936938
|| trait_ref.bound_generic_params.iter().any(|param| match param.kind {
937939
GenericParamKind::Lifetime { .. } => true,
938940
_ => false,
939941
})
940942
{
941-
if self.trait_ref_hack {
943+
if trait_ref_hack {
942944
struct_span_err!(
943945
self.tcx.sess,
944946
trait_ref.span,
@@ -968,10 +970,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
968970
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
969971
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
970972
this.visit_trait_ref(&trait_ref.trait_ref);
971-
})
973+
});
972974
} else {
973975
self.visit_trait_ref(&trait_ref.trait_ref);
974976
}
977+
self.trait_ref_hack = trait_ref_hack;
975978
if should_pop_missing_lt {
976979
self.missing_named_lifetime_spots.pop();
977980
}

src/librustc_trait_selection/traits/project.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -896,9 +896,12 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
896896

897897
let tcx = selcx.tcx();
898898
// Check whether the self-type is itself a projection.
899-
let (def_id, substs) = match obligation_trait_ref.self_ty().kind {
900-
ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs),
901-
ty::Opaque(def_id, substs) => (def_id, substs),
899+
// If so, extract what we know from the trait and try to come up with a good answer.
900+
let bounds = match obligation_trait_ref.self_ty().kind {
901+
ty::Projection(ref data) => {
902+
tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
903+
}
904+
ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
902905
ty::Infer(ty::TyVar(_)) => {
903906
// If the self-type is an inference variable, then it MAY wind up
904907
// being a projected type, so induce an ambiguity.
@@ -908,17 +911,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
908911
_ => return,
909912
};
910913

911-
// If so, extract what we know from the trait and try to come up with a good answer.
912-
let trait_predicates = tcx.predicates_of(def_id);
913-
let bounds = trait_predicates.instantiate(tcx, substs);
914-
let bounds = elaborate_predicates(tcx, bounds.predicates.into_iter()).map(|o| o.predicate);
915914
assemble_candidates_from_predicates(
916915
selcx,
917916
obligation,
918917
obligation_trait_ref,
919918
candidate_set,
920919
ProjectionTyCandidate::TraitDef,
921-
bounds,
920+
bounds.iter(),
922921
)
923922
}
924923

@@ -1484,6 +1483,12 @@ fn confirm_impl_candidate<'cx, 'tcx>(
14841483
);
14851484
return Progress { ty: tcx.ty_error(), obligations: nested };
14861485
}
1486+
// If we're trying to normalize `<Vec<u32> as X>::A<S>` using
1487+
//`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
1488+
//
1489+
// * `obligation.predicate.substs` is `[Vec<u32>, S]`
1490+
// * `substs` is `[u32]`
1491+
// * `substs` ends up as `[u32, S]`
14871492
let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
14881493
let substs =
14891494
translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);

src/librustc_trait_selection/traits/select/mod.rs

+22-28
Original file line numberDiff line numberDiff line change
@@ -1273,9 +1273,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12731273
placeholder_trait_predicate,
12741274
);
12751275

1276-
let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind {
1277-
ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
1278-
ty::Opaque(def_id, substs) => (def_id, substs),
1276+
let tcx = self.infcx.tcx;
1277+
let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind {
1278+
ty::Projection(ref data) => {
1279+
tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
1280+
}
1281+
ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
12791282
_ => {
12801283
span_bug!(
12811284
obligation.cause.span,
@@ -1285,32 +1288,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12851288
);
12861289
}
12871290
};
1288-
debug!(
1289-
"match_projection_obligation_against_definition_bounds: \
1290-
def_id={:?}, substs={:?}",
1291-
def_id, substs
1292-
);
12931291

1294-
let predicates_of = self.tcx().predicates_of(def_id);
1295-
let bounds = predicates_of.instantiate(self.tcx(), substs);
1296-
debug!(
1297-
"match_projection_obligation_against_definition_bounds: \
1298-
bounds={:?}",
1299-
bounds
1300-
);
1301-
1302-
let elaborated_predicates =
1303-
util::elaborate_predicates(self.tcx(), bounds.predicates.into_iter());
1304-
let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| {
1305-
self.infcx.probe(|_| {
1306-
self.match_projection(
1307-
obligation,
1308-
*bound,
1309-
placeholder_trait_predicate.trait_ref,
1310-
&placeholder_map,
1311-
snapshot,
1312-
)
1313-
})
1292+
let matching_bound = predicates.iter().find_map(|bound| {
1293+
if let ty::PredicateKind::Trait(bound, _) = bound.kind() {
1294+
let bound = bound.to_poly_trait_ref();
1295+
if self.infcx.probe(|_| {
1296+
self.match_projection(
1297+
obligation,
1298+
bound,
1299+
placeholder_trait_predicate.trait_ref,
1300+
&placeholder_map,
1301+
snapshot,
1302+
)
1303+
}) {
1304+
return Some(bound);
1305+
}
1306+
}
1307+
None
13141308
});
13151309

13161310
debug!(

0 commit comments

Comments
 (0)