Skip to content

Commit 60bd3f9

Browse files
committed
Auto merge of #102700 - oli-obk:0xDEAD_TAIT, r=compiler-errors
Check hidden types in dead code fixes #99490 r? `@compiler-errors` best reviewed commit by commit
2 parents 6b3ede3 + 3c8b46c commit 60bd3f9

File tree

14 files changed

+387
-319
lines changed

14 files changed

+387
-319
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+7-248
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ use rustc_data_structures::fx::FxHashMap;
22
use rustc_data_structures::vec_map::VecMap;
33
use rustc_hir::def_id::LocalDefId;
44
use rustc_hir::OpaqueTyOrigin;
5-
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
65
use rustc_infer::infer::TyCtxtInferExt as _;
76
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
87
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
9-
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
10-
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
8+
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
119
use rustc_middle::ty::visit::TypeVisitable;
1210
use rustc_middle::ty::{
1311
self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
@@ -16,8 +14,6 @@ use rustc_span::Span;
1614
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
1715
use rustc_trait_selection::traits::TraitEngineExt as _;
1816

19-
use crate::session_diagnostics::ConstNotUsedTraitAlias;
20-
2117
use super::RegionInferenceContext;
2218

2319
impl<'tcx> RegionInferenceContext<'tcx> {
@@ -229,31 +225,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
229225
return self.tcx.ty_error();
230226
}
231227

232-
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
233-
234-
// Use substs to build up a reverse map from regions to their
235-
// identity mappings. This is necessary because of `impl
236-
// Trait` lifetimes are computed by replacing existing
237-
// lifetimes with 'static and remapping only those used in the
238-
// `impl Trait` return type, resulting in the parameters
239-
// shifting.
240-
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
241-
debug!(?id_substs);
242-
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
243-
substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
244-
debug!("map = {:#?}", map);
245-
246-
// Convert the type from the function into a type valid outside
247-
// the function, by replacing invalid regions with 'static,
248-
// after producing an error for each of them.
249-
let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
250-
self.tcx,
251-
opaque_type_key,
252-
map,
253-
instantiated_ty.ty,
254-
instantiated_ty.span,
255-
));
256-
debug!(?definition_ty);
228+
let definition_ty = instantiated_ty
229+
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
230+
.ty;
257231

258232
if !check_opaque_type_parameter_valid(
259233
self.tcx,
@@ -269,6 +243,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
269243
let OpaqueTyOrigin::TyAlias = origin else {
270244
return definition_ty;
271245
};
246+
let def_id = opaque_type_key.def_id;
272247
// This logic duplicates most of `check_opaque_meets_bounds`.
273248
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
274249
let param_env = self.tcx.param_env(def_id);
@@ -284,6 +259,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
284259
.to_predicate(infcx.tcx);
285260
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
286261

262+
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
263+
287264
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
288265
// the bounds that the function supplies.
289266
match infcx.register_hidden_type(
@@ -424,221 +401,3 @@ fn check_opaque_type_parameter_valid(
424401
}
425402
true
426403
}
427-
428-
struct ReverseMapper<'tcx> {
429-
tcx: TyCtxt<'tcx>,
430-
431-
key: ty::OpaqueTypeKey<'tcx>,
432-
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
433-
do_not_error: bool,
434-
435-
/// initially `Some`, set to `None` once error has been reported
436-
hidden_ty: Option<Ty<'tcx>>,
437-
438-
/// Span of function being checked.
439-
span: Span,
440-
}
441-
442-
impl<'tcx> ReverseMapper<'tcx> {
443-
fn new(
444-
tcx: TyCtxt<'tcx>,
445-
key: ty::OpaqueTypeKey<'tcx>,
446-
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
447-
hidden_ty: Ty<'tcx>,
448-
span: Span,
449-
) -> Self {
450-
Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span }
451-
}
452-
453-
fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
454-
assert!(!self.do_not_error);
455-
self.do_not_error = true;
456-
let kind = kind.fold_with(self);
457-
self.do_not_error = false;
458-
kind
459-
}
460-
461-
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
462-
assert!(!self.do_not_error);
463-
kind.fold_with(self)
464-
}
465-
}
466-
467-
impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
468-
fn tcx(&self) -> TyCtxt<'tcx> {
469-
self.tcx
470-
}
471-
472-
#[instrument(skip(self), level = "debug")]
473-
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
474-
match *r {
475-
// Ignore bound regions and `'static` regions that appear in the
476-
// type, we only need to remap regions that reference lifetimes
477-
// from the function declaration.
478-
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
479-
ty::ReLateBound(..) | ty::ReStatic => return r,
480-
481-
// If regions have been erased (by writeback), don't try to unerase
482-
// them.
483-
ty::ReErased => return r,
484-
485-
// The regions that we expect from borrow checking.
486-
ty::ReEarlyBound(_) | ty::ReFree(_) => {}
487-
488-
ty::RePlaceholder(_) | ty::ReVar(_) => {
489-
// All of the regions in the type should either have been
490-
// erased by writeback, or mapped back to named regions by
491-
// borrow checking.
492-
bug!("unexpected region kind in opaque type: {:?}", r);
493-
}
494-
}
495-
496-
let generics = self.tcx().generics_of(self.key.def_id);
497-
match self.map.get(&r.into()).map(|k| k.unpack()) {
498-
Some(GenericArgKind::Lifetime(r1)) => r1,
499-
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
500-
None if self.do_not_error => self.tcx.lifetimes.re_static,
501-
None if generics.parent.is_some() => {
502-
if let Some(hidden_ty) = self.hidden_ty.take() {
503-
unexpected_hidden_region_diagnostic(
504-
self.tcx,
505-
self.tcx.def_span(self.key.def_id),
506-
hidden_ty,
507-
r,
508-
self.key,
509-
)
510-
.emit();
511-
}
512-
self.tcx.lifetimes.re_static
513-
}
514-
None => {
515-
self.tcx
516-
.sess
517-
.struct_span_err(self.span, "non-defining opaque type use in defining scope")
518-
.span_label(
519-
self.span,
520-
format!(
521-
"lifetime `{}` is part of concrete type but not used in \
522-
parameter list of the `impl Trait` type alias",
523-
r
524-
),
525-
)
526-
.emit();
527-
528-
self.tcx().lifetimes.re_static
529-
}
530-
}
531-
}
532-
533-
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
534-
match *ty.kind() {
535-
ty::Closure(def_id, substs) => {
536-
// I am a horrible monster and I pray for death. When
537-
// we encounter a closure here, it is always a closure
538-
// from within the function that we are currently
539-
// type-checking -- one that is now being encapsulated
540-
// in an opaque type. Ideally, we would
541-
// go through the types/lifetimes that it references
542-
// and treat them just like we would any other type,
543-
// which means we would error out if we find any
544-
// reference to a type/region that is not in the
545-
// "reverse map".
546-
//
547-
// **However,** in the case of closures, there is a
548-
// somewhat subtle (read: hacky) consideration. The
549-
// problem is that our closure types currently include
550-
// all the lifetime parameters declared on the
551-
// enclosing function, even if they are unused by the
552-
// closure itself. We can't readily filter them out,
553-
// so here we replace those values with `'empty`. This
554-
// can't really make a difference to the rest of the
555-
// compiler; those regions are ignored for the
556-
// outlives relation, and hence don't affect trait
557-
// selection or auto traits, and they are erased
558-
// during codegen.
559-
560-
let generics = self.tcx.generics_of(def_id);
561-
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
562-
if index < generics.parent_count {
563-
// Accommodate missing regions in the parent kinds...
564-
self.fold_kind_no_missing_regions_error(kind)
565-
} else {
566-
// ...but not elsewhere.
567-
self.fold_kind_normally(kind)
568-
}
569-
}));
570-
571-
self.tcx.mk_closure(def_id, substs)
572-
}
573-
574-
ty::Generator(def_id, substs, movability) => {
575-
let generics = self.tcx.generics_of(def_id);
576-
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
577-
if index < generics.parent_count {
578-
// Accommodate missing regions in the parent kinds...
579-
self.fold_kind_no_missing_regions_error(kind)
580-
} else {
581-
// ...but not elsewhere.
582-
self.fold_kind_normally(kind)
583-
}
584-
}));
585-
586-
self.tcx.mk_generator(def_id, substs, movability)
587-
}
588-
589-
ty::Param(param) => {
590-
// Look it up in the substitution list.
591-
match self.map.get(&ty.into()).map(|k| k.unpack()) {
592-
// Found it in the substitution list; replace with the parameter from the
593-
// opaque type.
594-
Some(GenericArgKind::Type(t1)) => t1,
595-
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
596-
None => {
597-
debug!(?param, ?self.map);
598-
self.tcx
599-
.sess
600-
.struct_span_err(
601-
self.span,
602-
&format!(
603-
"type parameter `{}` is part of concrete type but not \
604-
used in parameter list for the `impl Trait` type alias",
605-
ty
606-
),
607-
)
608-
.emit();
609-
610-
self.tcx().ty_error()
611-
}
612-
}
613-
}
614-
615-
_ => ty.super_fold_with(self),
616-
}
617-
}
618-
619-
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
620-
trace!("checking const {:?}", ct);
621-
// Find a const parameter
622-
match ct.kind() {
623-
ty::ConstKind::Param(..) => {
624-
// Look it up in the substitution list.
625-
match self.map.get(&ct.into()).map(|k| k.unpack()) {
626-
// Found it in the substitution list, replace with the parameter from the
627-
// opaque type.
628-
Some(GenericArgKind::Const(c1)) => c1,
629-
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
630-
None => {
631-
self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
632-
ct: ct.to_string(),
633-
span: self.span,
634-
});
635-
636-
self.tcx().const_error(ct.ty())
637-
}
638-
}
639-
}
640-
641-
_ => ct,
642-
}
643-
}
644-
}

compiler/rustc_borrowck/src/session_diagnostics.rs

-9
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@ pub(crate) struct VarNeedNotMut {
5252
#[suggestion_short(applicability = "machine-applicable", code = "")]
5353
pub span: Span,
5454
}
55-
56-
#[derive(Diagnostic)]
57-
#[diag(borrowck::const_not_used_in_type_alias)]
58-
pub(crate) struct ConstNotUsedTraitAlias {
59-
pub ct: String,
60-
#[primary_span]
61-
pub span: Span,
62-
}
63-
6455
#[derive(Diagnostic)]
6556
#[diag(borrowck::var_cannot_escape_closure)]
6657
#[note]

compiler/rustc_hir_analysis/src/check/writeback.rs

+27-24
Original file line numberDiff line numberDiff line change
@@ -536,33 +536,36 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
536536
let opaque_types =
537537
self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
538538
for (opaque_type_key, decl) in opaque_types {
539-
let hidden_type = match decl.origin {
540-
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
541-
let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span);
542-
struct RecursionChecker {
543-
def_id: LocalDefId,
544-
}
545-
impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
546-
type BreakTy = ();
547-
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
548-
if let ty::Opaque(def_id, _) = *t.kind() {
549-
if def_id == self.def_id.to_def_id() {
550-
return ControlFlow::Break(());
551-
}
552-
}
553-
t.super_visit_with(self)
539+
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
540+
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
541+
542+
struct RecursionChecker {
543+
def_id: LocalDefId,
544+
}
545+
impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
546+
type BreakTy = ();
547+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
548+
if let ty::Opaque(def_id, _) = *t.kind() {
549+
if def_id == self.def_id.to_def_id() {
550+
return ControlFlow::Break(());
554551
}
555552
}
556-
if ty
557-
.visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
558-
.is_break()
559-
{
560-
return;
561-
}
562-
Some(ty)
553+
t.super_visit_with(self)
563554
}
564-
hir::OpaqueTyOrigin::TyAlias => None,
565-
};
555+
}
556+
if hidden_type
557+
.visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
558+
.is_break()
559+
{
560+
continue;
561+
}
562+
563+
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
564+
opaque_type_key,
565+
self.fcx.infcx.tcx,
566+
true,
567+
);
568+
566569
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
567570
}
568571
}

0 commit comments

Comments
 (0)