Skip to content

Commit 37928f5

Browse files
committed
Neither require nor imply lifetime bounds on opaque type for well formedness
1 parent c8ecf09 commit 37928f5

30 files changed

+497
-42
lines changed

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
362362
self.region_bound_pairs
363363
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
364364
}
365+
366+
OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
367+
self.region_bound_pairs
368+
.insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
369+
}
365370
}
366371
}
367372
}

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
23742374
let labeled_user_string = match bound_kind {
23752375
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
23762376
GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
2377+
GenericKind::Opaque(def_id, substs) => {
2378+
format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
2379+
}
23772380
};
23782381

23792382
if let Some(SubregionOrigin::CompareImplItemObligation {

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
// RFC for reference.
44

55
use rustc_data_structures::sso::SsoHashSet;
6+
use rustc_hir::def_id::DefId;
67
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
7-
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
8+
use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
89
use smallvec::{smallvec, SmallVec};
910

1011
#[derive(Debug)]
@@ -45,6 +46,8 @@ pub enum Component<'tcx> {
4546
// them. This gives us room to improve the regionck reasoning in
4647
// the future without breaking backwards compat.
4748
EscapingProjection(Vec<Component<'tcx>>),
49+
50+
Opaque(DefId, SubstsRef<'tcx>),
4851
}
4952

5053
/// Push onto `out` all the things that must outlive `'a` for the condition
@@ -120,6 +123,17 @@ fn compute_components<'tcx>(
120123
out.push(Component::Param(p));
121124
}
122125

126+
// Ignore lifetimes found in opaque types. Opaque types can
127+
// have lifetimes in their substs which their hidden type doesn't
128+
// actually use. If we inferred that an opaque type is outlived by
129+
// its parameter lifetimes, then we could prove that any lifetime
130+
// outlives any other lifetime, which is unsound.
131+
// See https://github.com/rust-lang/rust/issues/84305 for
132+
// more details.
133+
ty::Opaque(def_id, substs) => {
134+
out.push(Component::Opaque(def_id, substs));
135+
},
136+
123137
// For projections, we prefer to generate an obligation like
124138
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
125139
// regionck more ways to prove that it holds. However,
@@ -168,7 +182,6 @@ fn compute_components<'tcx>(
168182
ty::Float(..) | // OutlivesScalar
169183
ty::Never | // ...
170184
ty::Adt(..) | // OutlivesNominalType
171-
ty::Opaque(..) | // OutlivesNominalType (ish)
172185
ty::Foreign(..) | // OutlivesNominalType
173186
ty::Str | // OutlivesScalar (ish)
174187
ty::Slice(..) | // ...

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
140140
self.region_bound_pairs
141141
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
142142
}
143+
OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
144+
self.region_bound_pairs
145+
.insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
146+
}
143147
OutlivesBound::RegionSubRegion(r_a, r_b) => {
144148
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
145149
infcx

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ where
284284
Component::Param(param_ty) => {
285285
self.param_ty_must_outlive(origin, region, *param_ty);
286286
}
287+
Component::Opaque(def_id, substs) => {
288+
self.opaque_must_outlive(*def_id, substs, origin, region)
289+
}
287290
Component::Projection(projection_ty) => {
288291
self.projection_must_outlive(origin, region, *projection_ty);
289292
}
@@ -319,6 +322,27 @@ where
319322
self.delegate.push_verify(origin, generic, region, verify_bound);
320323
}
321324

325+
#[instrument(level = "debug", skip(self))]
326+
fn opaque_must_outlive(
327+
&mut self,
328+
def_id: DefId,
329+
substs: SubstsRef<'tcx>,
330+
origin: infer::SubregionOrigin<'tcx>,
331+
region: ty::Region<'tcx>,
332+
) {
333+
self.generic_must_outlive(
334+
origin,
335+
region,
336+
GenericKind::Opaque(def_id, substs),
337+
def_id,
338+
substs,
339+
|ty| match *ty.kind() {
340+
ty::Opaque(def_id, substs) => (def_id, substs),
341+
_ => bug!("expected only projection types from env, not {:?}", ty),
342+
},
343+
);
344+
}
345+
322346
#[instrument(level = "debug", skip(self))]
323347
fn projection_must_outlive(
324348
&mut self,

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
4747
GenericKind::Projection(projection_ty) => {
4848
self.projection_bound(projection_ty, &mut visited)
4949
}
50+
GenericKind::Opaque(def_id, substs) => self.opaque_bound(def_id, substs),
5051
}
5152
}
5253

@@ -155,6 +156,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
155156
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
156157
}
157158

159+
fn opaque_bound(&self, def_id: DefId, substs: SubstsRef<'tcx>) -> VerifyBound<'tcx> {
160+
let bounds: Vec<_> =
161+
self.bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r)).collect();
162+
trace!("{:#?}", bounds);
163+
if bounds.is_empty() {
164+
// No bounds means the value must not have any lifetimes.
165+
// FIXME: should we implicitly add 'static to `tcx.item_bounds` for opaque types, just
166+
// like we add `Sized`?
167+
VerifyBound::OutlivedBy(self.tcx.lifetimes.re_static)
168+
} else {
169+
VerifyBound::AnyBound(bounds)
170+
}
171+
}
172+
158173
fn bound_from_components(
159174
&self,
160175
components: &[Component<'tcx>],
@@ -184,6 +199,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
184199
match *component {
185200
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
186201
Component::Param(param_ty) => self.param_bound(param_ty),
202+
Component::Opaque(did, substs) => self.opaque_bound(did, substs),
187203
Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
188204
Component::EscapingProjection(ref components) => {
189205
self.bound_from_components(components, visited)

compiler/rustc_infer/src/infer/region_constraints/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ use rustc_data_structures::intern::Interned;
1212
use rustc_data_structures::sync::Lrc;
1313
use rustc_data_structures::undo_log::UndoLogs;
1414
use rustc_data_structures::unify as ut;
15+
use rustc_hir::def_id::DefId;
1516
use rustc_index::vec::IndexVec;
1617
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
18+
use rustc_middle::ty::subst::SubstsRef;
1719
use rustc_middle::ty::ReStatic;
1820
use rustc_middle::ty::{self, Ty, TyCtxt};
1921
use rustc_middle::ty::{ReLateBound, ReVar};
@@ -168,6 +170,7 @@ pub struct Verify<'tcx> {
168170
pub enum GenericKind<'tcx> {
169171
Param(ty::ParamTy),
170172
Projection(ty::ProjectionTy<'tcx>),
173+
Opaque(DefId, SubstsRef<'tcx>),
171174
}
172175

173176
/// Describes the things that some `GenericKind` value `G` is known to
@@ -747,6 +750,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
747750
match *self {
748751
GenericKind::Param(ref p) => write!(f, "{:?}", p),
749752
GenericKind::Projection(ref p) => write!(f, "{:?}", p),
753+
GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
754+
write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
755+
}),
750756
}
751757
}
752758
}
@@ -756,6 +762,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
756762
match *self {
757763
GenericKind::Param(ref p) => write!(f, "{}", p),
758764
GenericKind::Projection(ref p) => write!(f, "{}", p),
765+
GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
766+
write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
767+
}),
759768
}
760769
}
761770
}
@@ -765,6 +774,7 @@ impl<'tcx> GenericKind<'tcx> {
765774
match *self {
766775
GenericKind::Param(ref p) => p.to_ty(tcx),
767776
GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
777+
GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
768778
}
769779
}
770780
}

compiler/rustc_infer/src/traits/util.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,13 @@ impl<'tcx> Elaborator<'tcx> {
246246

247247
Component::UnresolvedInferenceVariable(_) => None,
248248

249+
Component::Opaque(def_id, substs) => {
250+
let ty = tcx.mk_opaque(def_id, substs);
251+
Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
252+
ty, r_min,
253+
)))
254+
}
255+
249256
Component::Projection(projection) => {
250257
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
251258
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
@@ -262,8 +269,9 @@ impl<'tcx> Elaborator<'tcx> {
262269
None
263270
}
264271
})
265-
.map(ty::Binder::dummy)
266-
.map(|predicate_kind| predicate_kind.to_predicate(tcx))
272+
.map(|predicate_kind| {
273+
bound_predicate.rebind(predicate_kind).to_predicate(tcx)
274+
})
267275
.filter(|&predicate| visited.insert(predicate))
268276
.map(|predicate| {
269277
predicate_obligation(

compiler/rustc_middle/src/traits/query.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
use crate::error::DropCheckOverflow;
99
use crate::infer::canonical::{Canonical, QueryResponse};
1010
use crate::ty::error::TypeError;
11-
use crate::ty::subst::GenericArg;
11+
use crate::ty::subst::{GenericArg, SubstsRef};
1212
use crate::ty::{self, Ty, TyCtxt};
13+
use rustc_hir::def_id::DefId;
1314
use rustc_span::source_map::Span;
1415
use std::iter::FromIterator;
1516

@@ -219,4 +220,5 @@ pub enum OutlivesBound<'tcx> {
219220
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
220221
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
221222
RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
223+
RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>),
222224
}

compiler/rustc_traits/src/implied_outlives_bounds.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ fn implied_bounds_from_components<'tcx>(
153153
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
154154
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
155155
Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
156+
Component::Opaque(def_id, substs) => {
157+
Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs))
158+
}
156159
Component::EscapingProjection(_) =>
157160
// If the projection has escaping regions, don't
158161
// try to infer any implied bounds even for its

compiler/rustc_typeck/src/mem_categorization.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
265265
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
266266
}
267267

268+
#[instrument(level = "debug", skip(self, previous))]
268269
fn cat_expr_adjusted_with<F>(
269270
&self,
270271
expr: &hir::Expr<'_>,
@@ -274,7 +275,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
274275
where
275276
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
276277
{
277-
debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
278278
let target = self.resolve_vars_if_possible(adjustment.target);
279279
match adjustment.kind {
280280
adjustment::Adjust::Deref(overloaded) => {
@@ -299,6 +299,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
299299
}
300300
}
301301

302+
#[instrument(level = "debug", skip(self))]
302303
pub(crate) fn cat_expr_unadjusted(
303304
&self,
304305
expr: &hir::Expr<'_>,
@@ -387,15 +388,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
387388
}
388389
}
389390

391+
#[instrument(level = "debug", skip(self, span))]
390392
pub(crate) fn cat_res(
391393
&self,
392394
hir_id: hir::HirId,
393395
span: Span,
394396
expr_ty: Ty<'tcx>,
395397
res: Res,
396398
) -> McResult<PlaceWithHirId<'tcx>> {
397-
debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
398-
399399
match res {
400400
Res::Def(
401401
DefKind::Ctor(..)
@@ -475,13 +475,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
475475
ret
476476
}
477477

478+
#[instrument(level = "debug", skip(self))]
478479
fn cat_overloaded_place(
479480
&self,
480481
expr: &hir::Expr<'_>,
481482
base: &hir::Expr<'_>,
482483
) -> McResult<PlaceWithHirId<'tcx>> {
483-
debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
484-
485484
// Reconstruct the output assuming it's a reference with the
486485
// same region and mutability as the receiver. This holds for
487486
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
@@ -497,13 +496,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
497496
self.cat_deref(expr, base)
498497
}
499498

499+
#[instrument(level = "debug", skip(self, node))]
500500
fn cat_deref(
501501
&self,
502502
node: &impl HirNode,
503503
base_place: PlaceWithHirId<'tcx>,
504504
) -> McResult<PlaceWithHirId<'tcx>> {
505-
debug!("cat_deref: base_place={:?}", base_place);
506-
507505
let base_curr_ty = base_place.place.ty();
508506
let deref_ty = match base_curr_ty.builtin_deref(true) {
509507
Some(mt) => mt.ty,

compiler/rustc_typeck/src/outlives/utils.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
22
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
3-
use rustc_middle::ty::{self, Region, Ty, TyCtxt};
3+
use rustc_middle::ty::{self, EarlyBinder, Region, Ty, TyCtxt};
44
use rustc_span::Span;
55
use smallvec::smallvec;
66
use std::collections::BTreeMap;
@@ -96,6 +96,39 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
9696
.or_insert(span);
9797
}
9898

99+
Component::Opaque(def_id, substs) => {
100+
for predicate in tcx.item_bounds(def_id) {
101+
let predicate = EarlyBinder(predicate).subst(tcx, substs);
102+
// FIXME(oli-obk): fishy skip-binder
103+
match predicate.kind().skip_binder() {
104+
ty::PredicateKind::Trait(tp) => {
105+
for subst in tp.trait_ref.substs {
106+
insert_outlives_predicate(
107+
tcx,
108+
subst,
109+
outlived_region,
110+
span,
111+
required_predicates,
112+
)
113+
}
114+
}
115+
ty::PredicateKind::RegionOutlives(_)
116+
| ty::PredicateKind::TypeOutlives(_)
117+
| ty::PredicateKind::Projection(_)
118+
| ty::PredicateKind::WellFormed(_)
119+
| ty::PredicateKind::ObjectSafe(_)
120+
| ty::PredicateKind::ClosureKind(_, _, _)
121+
| ty::PredicateKind::Subtype(_)
122+
| ty::PredicateKind::Coerce(_)
123+
| ty::PredicateKind::ConstEvaluatable(_)
124+
| ty::PredicateKind::ConstEquate(_, _)
125+
| ty::PredicateKind::TypeWellFormedFromEnv(_) => {
126+
todo!("{:#?}", predicate)
127+
}
128+
}
129+
}
130+
}
131+
99132
Component::EscapingProjection(_) => {
100133
// As above, but the projection involves
101134
// late-bound regions. Therefore, the WF

src/test/ui/generic-associated-types/bugs/issue-86218.stderr

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

0 commit comments

Comments
 (0)