Skip to content

Commit 31bfd26

Browse files
authored
Unrolled build for rust-lang#136554
Rollup merge of rust-lang#136554 - compiler-errors:opt-alias-variances, r=lcnr Add `opt_alias_variances` and use it in outlives code ...so to fix some subtle outlives bugs with precise capturing in traits, and eventually make it easier to compute variances for "forced unconstrained" trait lifetimes. r? lcnr
2 parents e060723 + d17a4a7 commit 31bfd26

File tree

12 files changed

+117
-50
lines changed

12 files changed

+117
-50
lines changed

compiler/rustc_borrowck/src/type_check/opaque_types.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ where
284284
return;
285285
}
286286

287-
match ty.kind() {
287+
match *ty.kind() {
288288
ty::Closure(_, args) => {
289289
// Skip lifetime parameters of the enclosing item(s)
290290

@@ -316,10 +316,12 @@ where
316316
args.as_coroutine().resume_ty().visit_with(self);
317317
}
318318

319-
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
320-
// Skip lifetime parameters that are not captures.
321-
let variances = self.tcx.variances_of(*def_id);
322-
319+
ty::Alias(kind, ty::AliasTy { def_id, args, .. })
320+
if let Some(variances) = self.tcx.opt_alias_variances(kind, def_id) =>
321+
{
322+
// Skip lifetime parameters that are not captured, since they do
323+
// not need member constraints registered for them; we'll erase
324+
// them (and hopefully in the future replace them with placeholders).
323325
for (v, s) in std::iter::zip(variances, args.iter()) {
324326
if *v != ty::Bivariant {
325327
s.visit_with(self);

compiler/rustc_infer/src/infer/outlives/for_liveness.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ where
4848
return ty.super_visit_with(self);
4949
}
5050

51-
match ty.kind() {
51+
match *ty.kind() {
5252
// We can prove that an alias is live two ways:
5353
// 1. All the components are live.
5454
//
@@ -95,11 +95,9 @@ where
9595
assert!(r.type_flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS));
9696
r.visit_with(self);
9797
} else {
98-
// Skip lifetime parameters that are not captures.
99-
let variances = match kind {
100-
ty::Opaque => Some(self.tcx.variances_of(*def_id)),
101-
_ => None,
102-
};
98+
// Skip lifetime parameters that are not captured, since they do
99+
// not need to be live.
100+
let variances = tcx.opt_alias_variances(kind, def_id);
103101

104102
for (idx, s) in args.iter().enumerate() {
105103
if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) {

compiler/rustc_infer/src/infer/outlives/obligations.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -392,13 +392,13 @@ where
392392
// the problem is to add `T: 'r`, which isn't true. So, if there are no
393393
// inference variables, we use a verify constraint instead of adding
394394
// edges, which winds up enforcing the same condition.
395-
let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque;
395+
let kind = alias_ty.kind(self.tcx);
396396
if approx_env_bounds.is_empty()
397397
&& trait_bounds.is_empty()
398-
&& (alias_ty.has_infer_regions() || is_opaque)
398+
&& (alias_ty.has_infer_regions() || kind == ty::Opaque)
399399
{
400400
debug!("no declared bounds");
401-
let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id));
401+
let opt_variances = self.tcx.opt_alias_variances(kind, alias_ty.def_id);
402402
self.args_must_outlive(alias_ty.args, origin, region, opt_variances);
403403
return;
404404
}

compiler/rustc_infer/src/infer/outlives/verify.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
102102

103103
#[instrument(level = "debug", skip(self))]
104104
pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> {
105-
let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
106-
107105
// Search the env for where clauses like `P: 'a`.
108106
let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| {
109107
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars()
110-
&& ty == alias_ty_as_ty
108+
&& let ty::Alias(_, alias_ty_from_bound) = *ty.kind()
109+
&& alias_ty_from_bound == alias_ty
111110
{
112111
// Micro-optimize if this is an exact match (this
113112
// occurs often when there are no region variables
@@ -127,7 +126,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
127126
// see the extensive comment in projection_must_outlive
128127
let recursive_bound = {
129128
let mut components = smallvec![];
130-
compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components);
129+
let kind = alias_ty.kind(self.tcx);
130+
compute_alias_components_recursive(self.tcx, kind, alias_ty, &mut components);
131131
self.bound_from_components(&components)
132132
};
133133

compiler/rustc_middle/src/ty/context.rs

+8
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
194194
self.variances_of(def_id)
195195
}
196196

197+
fn opt_alias_variances(
198+
self,
199+
kind: impl Into<ty::AliasTermKind>,
200+
def_id: DefId,
201+
) -> Option<&'tcx [ty::Variance]> {
202+
self.opt_alias_variances(kind, def_id)
203+
}
204+
197205
fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
198206
self.type_of(def_id)
199207
}

compiler/rustc_middle/src/ty/util.rs

+23
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,29 @@ impl<'tcx> TyCtxt<'tcx> {
948948

949949
ty
950950
}
951+
952+
// Computes the variances for an alias (opaque or RPITIT) that represent
953+
// its (un)captured regions.
954+
pub fn opt_alias_variances(
955+
self,
956+
kind: impl Into<ty::AliasTermKind>,
957+
def_id: DefId,
958+
) -> Option<&'tcx [ty::Variance]> {
959+
match kind.into() {
960+
ty::AliasTermKind::ProjectionTy => {
961+
if self.is_impl_trait_in_trait(def_id) {
962+
Some(self.variances_of(def_id))
963+
} else {
964+
None
965+
}
966+
}
967+
ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)),
968+
ty::AliasTermKind::InherentTy
969+
| ty::AliasTermKind::WeakTy
970+
| ty::AliasTermKind::UnevaluatedConst
971+
| ty::AliasTermKind::ProjectionConst => None,
972+
}
973+
}
951974
}
952975

953976
struct OpaqueTypeExpander<'tcx> {

compiler/rustc_type_ir/src/interner.rs

+6
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ pub trait Interner:
141141
type VariancesOf: Copy + Debug + SliceLike<Item = ty::Variance>;
142142
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
143143

144+
fn opt_alias_variances(
145+
self,
146+
kind: impl Into<ty::AliasTermKind>,
147+
def_id: Self::DefId,
148+
) -> Option<Self::VariancesOf>;
149+
144150
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
145151

146152
type AdtDef: AdtDef<Self>;

compiler/rustc_type_ir/src/outlives.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
148148
// trait-ref. Therefore, if we see any higher-ranked regions,
149149
// we simply fallback to the most restrictive rule, which
150150
// requires that `Pi: 'a` for all `i`.
151-
ty::Alias(_, alias_ty) => {
151+
ty::Alias(kind, alias_ty) => {
152152
if !alias_ty.has_escaping_bound_vars() {
153153
// best case: no escaping regions, so push the
154154
// projection and skip the subtree (thus generating no
@@ -162,7 +162,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
162162
// OutlivesProjectionComponents. Continue walking
163163
// through and constrain Pi.
164164
let mut subcomponents = smallvec![];
165-
compute_alias_components_recursive(self.cx, ty, &mut subcomponents);
165+
compute_alias_components_recursive(self.cx, kind, alias_ty, &mut subcomponents);
166166
self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
167167
}
168168
}
@@ -217,21 +217,17 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
217217
}
218218
}
219219

220-
/// Collect [Component]s for *all* the args of `parent`.
220+
/// Collect [Component]s for *all* the args of `alias_ty`.
221221
///
222-
/// This should not be used to get the components of `parent` itself.
222+
/// This should not be used to get the components of `alias_ty` itself.
223223
/// Use [push_outlives_components] instead.
224224
pub fn compute_alias_components_recursive<I: Interner>(
225225
cx: I,
226-
alias_ty: I::Ty,
226+
kind: ty::AliasTyKind,
227+
alias_ty: ty::AliasTy<I>,
227228
out: &mut SmallVec<[Component<I>; 4]>,
228229
) {
229-
let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
230-
unreachable!("can only call `compute_alias_components_recursive` on an alias type")
231-
};
232-
233-
let opt_variances =
234-
if kind == ty::Opaque { Some(cx.variances_of(alias_ty.def_id)) } else { None };
230+
let opt_variances = cx.opt_alias_variances(kind, alias_ty.def_id);
235231

236232
let mut visitor = OutlivesCollector { cx, out, visited: Default::default() };
237233

compiler/rustc_type_ir/src/predicate.rs

+11
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,17 @@ impl AliasTermKind {
469469
}
470470
}
471471

472+
impl From<ty::AliasTyKind> for AliasTermKind {
473+
fn from(value: ty::AliasTyKind) -> Self {
474+
match value {
475+
ty::Projection => AliasTermKind::ProjectionTy,
476+
ty::Opaque => AliasTermKind::OpaqueTy,
477+
ty::Weak => AliasTermKind::WeakTy,
478+
ty::Inherent => AliasTermKind::InherentTy,
479+
}
480+
}
481+
}
482+
472483
/// Represents the unprojected term of a projection goal.
473484
///
474485
/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.

compiler/rustc_type_ir/src/relate.rs

+7-21
Original file line numberDiff line numberDiff line change
@@ -236,28 +236,14 @@ impl<I: Interner> Relate<I> for ty::AliasTy<I> {
236236
ExpectedFound::new(a, b)
237237
}))
238238
} else {
239-
let args = match a.kind(relation.cx()) {
240-
ty::Opaque => relate_args_with_variances(
241-
relation,
242-
a.def_id,
243-
relation.cx().variances_of(a.def_id),
244-
a.args,
245-
b.args,
239+
let cx = relation.cx();
240+
let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) {
241+
relate_args_with_variances(
242+
relation, a.def_id, variances, a.args, b.args,
246243
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
247-
)?,
248-
ty::Projection if relation.cx().is_impl_trait_in_trait(a.def_id) => {
249-
relate_args_with_variances(
250-
relation,
251-
a.def_id,
252-
relation.cx().variances_of(a.def_id),
253-
a.args,
254-
b.args,
255-
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
256-
)?
257-
}
258-
ty::Projection | ty::Weak | ty::Inherent => {
259-
relate_args_invariantly(relation, a.args, b.args)?
260-
}
244+
)?
245+
} else {
246+
relate_args_invariantly(relation, a.args, b.args)?
261247
};
262248
Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args))
263249
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ check-pass
2+
3+
// Ensure that we skip uncaptured args from RPITITs when comptuing outlives.
4+
5+
#![feature(precise_capturing_in_traits)]
6+
7+
struct Invariant<T>(*mut T);
8+
9+
trait Foo {
10+
fn hello<'s: 's>(&'s self) -> Invariant<impl Sized + use<Self>>;
11+
}
12+
13+
fn outlives_static(_: impl Sized + 'static) {}
14+
15+
fn hello<'s, T: Foo + 'static>(x: &'s T) {
16+
outlives_static(x.hello());
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ check-pass
2+
3+
// Ensure that we skip uncaptured args from RPITITs when collecting the regions
4+
// to enforce member constraints in opaque type inference.
5+
6+
#![feature(precise_capturing_in_traits)]
7+
8+
struct Invariant<T>(*mut T);
9+
10+
trait Foo {
11+
fn hello<'s: 's>(&'s self) -> Invariant<impl Sized + use<Self>>;
12+
}
13+
14+
fn hello<'s, T: Foo>(x: &'s T) -> Invariant<impl Sized> {
15+
x.hello()
16+
}
17+
18+
fn main() {}

0 commit comments

Comments
 (0)