Skip to content

Commit b232bb8

Browse files
committed
Require TAITs to appear in the signature of items that register a hidden type
1 parent 65d2f2a commit b232bb8

32 files changed

+520
-266
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
680680
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
681681
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
682682
&& let Some(def_id) = def_id.as_local()
683-
&& self.opaque_type_origin(def_id, DUMMY_SP).is_some() {
683+
&& self.opaque_type_origin(def_id, DUMMY_SP, self.param_env).is_some() {
684684
return None;
685685
}
686686
}

compiler/rustc_hir_typeck/src/inherited.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,18 @@ pub struct InheritedBuilder<'tcx> {
8282
}
8383

8484
impl<'tcx> Inherited<'tcx> {
85-
pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
85+
pub fn build(
86+
tcx: TyCtxt<'tcx>,
87+
def_id: LocalDefId,
88+
mk_defining_use_anchor: impl FnOnce(LocalDefId) -> DefiningAnchor,
89+
) -> InheritedBuilder<'tcx> {
8690
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
8791

8892
InheritedBuilder {
8993
infcx: tcx
9094
.infer_ctxt()
9195
.ignoring_regions()
92-
.with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)),
96+
.with_opaque_type_inference(mk_defining_use_anchor(hir_owner.def_id)),
9397
def_id,
9498
typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
9599
}

compiler/rustc_hir_typeck/src/lib.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub use diverges::Diverges;
4848
pub use expectation::Expectation;
4949
pub use fn_ctxt::*;
5050
pub use inherited::{Inherited, InheritedBuilder};
51+
use rustc_infer::infer::DefiningAnchor;
5152

5253
use crate::check::check_fn;
5354
use crate::coercion::DynamicCoerceMany;
@@ -199,12 +200,23 @@ fn typeck_with_fallback<'tcx>(
199200
});
200201
let body = tcx.hir().body(body_id);
201202

202-
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
203+
let fn_sig_infer = fn_sig.map_or(false, |fn_sig| {
204+
rustc_hir_analysis::collect::get_infer_ret_ty(&fn_sig.decl.output).is_some()
205+
});
206+
207+
let mk_defining_use_anchor = |def_id| {
208+
// In case we are inferring the return signature (via `_` types), ignore defining use
209+
// rules, as we'll error out anyway. This helps improve diagnostics, which otherwise
210+
// may just see `ty::Error` instead of `ty::Alias(Opaque, _)` and not produce better errors.
211+
if fn_sig_infer { DefiningAnchor::Bubble } else { DefiningAnchor::Bind(def_id) }
212+
};
213+
214+
let typeck_results = Inherited::build(tcx, def_id, mk_defining_use_anchor).enter(|inh| {
203215
let param_env = tcx.param_env(def_id);
204216
let mut fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
205217

206218
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
207-
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
219+
let fn_sig = if fn_sig_infer {
208220
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
209221
} else {
210222
tcx.fn_sig(def_id)

compiler/rustc_infer/src/infer/opaque_types.rs

+128-9
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ use rustc_hir as hir;
1010
use rustc_middle::traits::ObligationCause;
1111
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1212
use rustc_middle::ty::fold::BottomUpFolder;
13-
use rustc_middle::ty::GenericArgKind;
1413
use rustc_middle::ty::{
1514
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
1615
TypeVisitable, TypeVisitor,
1716
};
17+
use rustc_middle::ty::{DefIdTree, GenericArgKind};
1818
use rustc_span::Span;
19+
use smallvec::SmallVec;
1920

2021
use std::ops::ControlFlow;
2122

@@ -59,7 +60,7 @@ impl<'tcx> InferCtxt<'tcx> {
5960
let replace_opaque_type = |def_id: DefId| {
6061
def_id
6162
.as_local()
62-
.map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some())
63+
.map_or(false, |def_id| self.opaque_type_origin(def_id, span, param_env).is_some())
6364
};
6465
let value = value.fold_with(&mut BottomUpFolder {
6566
tcx: self.tcx,
@@ -144,7 +145,7 @@ impl<'tcx> InferCtxt<'tcx> {
144145
// let x = || foo(); // returns the Opaque assoc with `foo`
145146
// }
146147
// ```
147-
self.opaque_type_origin(def_id, cause.span)?
148+
self.opaque_type_origin(def_id, cause.span, param_env)?
148149
}
149150
DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
150151
DefiningAnchor::Error => return None,
@@ -155,9 +156,10 @@ impl<'tcx> InferCtxt<'tcx> {
155156
// no one encounters it in practice.
156157
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
157158
// where it is of no concern, so we only check for TAITs.
158-
if let Some(OpaqueTyOrigin::TyAlias) = b_def_id
159-
.as_local()
160-
.and_then(|b_def_id| self.opaque_type_origin(b_def_id, cause.span))
159+
if let Some(OpaqueTyOrigin::TyAlias) =
160+
b_def_id.as_local().and_then(|b_def_id| {
161+
self.opaque_type_origin(b_def_id, cause.span, param_env)
162+
})
161163
{
162164
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
163165
span: cause.span,
@@ -372,7 +374,12 @@ impl<'tcx> InferCtxt<'tcx> {
372374
}
373375

374376
#[instrument(skip(self), level = "trace", ret)]
375-
pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
377+
pub fn opaque_type_origin(
378+
&self,
379+
def_id: LocalDefId,
380+
span: Span,
381+
param_env: ty::ParamEnv<'tcx>,
382+
) -> Option<OpaqueTyOrigin> {
376383
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
377384
let parent_def_id = match self.defining_use_anchor {
378385
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
@@ -395,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> {
395402
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
396403
// Named `type Foo = impl Bar;`
397404
hir::OpaqueTyOrigin::TyAlias => {
398-
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
405+
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id, def_id, param_env)
399406
}
400407
};
401408
trace!(?origin);
@@ -639,11 +646,123 @@ impl<'tcx> InferCtxt<'tcx> {
639646
/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
640647
/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
641648
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
642-
fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
649+
#[instrument(skip(tcx), level = "trace", ret)]
650+
fn may_define_opaque_type<'tcx>(
651+
tcx: TyCtxt<'tcx>,
652+
def_id: LocalDefId,
653+
opaque_hir_id: hir::HirId,
654+
opaque_def_id: LocalDefId,
655+
param_env: ty::ParamEnv<'tcx>,
656+
) -> bool {
643657
let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
644658

645659
// Named opaque types can be defined by any siblings or children of siblings.
646660
let scope = tcx.hir().get_defining_scope(opaque_hir_id);
661+
662+
// When doing checks within the opaque type itself
663+
if def_id != opaque_def_id
664+
// When the opaque type is defined in the body of a function, the function may access it.
665+
&& hir_id != scope
666+
{
667+
trace!(parent = ?tcx.parent(opaque_def_id.to_def_id()));
668+
fn has_tait<'tcx>(
669+
val: impl TypeVisitable<'tcx>,
670+
opaque_def_id: LocalDefId,
671+
tcx: TyCtxt<'tcx>,
672+
param_env: ty::ParamEnv<'tcx>,
673+
) -> bool {
674+
struct Visitor<'tcx> {
675+
opaque_def_id: DefId,
676+
tcx: TyCtxt<'tcx>,
677+
ignore_nested: SmallVec<[DefId; 1]>,
678+
param_env: ty::ParamEnv<'tcx>,
679+
}
680+
impl<'tcx> TypeVisitor<'tcx> for Visitor<'tcx> {
681+
type BreakTy = ();
682+
#[instrument(skip(self), level = "trace", ret)]
683+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
684+
match t.kind() {
685+
ty::Alias(ty::Opaque, alias) => {
686+
if alias.def_id == self.opaque_def_id {
687+
return ControlFlow::Break(());
688+
}
689+
if !self.ignore_nested.contains(&alias.def_id) {
690+
// avoid infinite recursion since the opaque type shows
691+
// up in its own bounds.
692+
self.ignore_nested.push(alias.def_id);
693+
for (pred, _span) in self
694+
.tcx
695+
.bound_explicit_item_bounds(alias.def_id)
696+
.subst_iter_copied(self.tcx, alias.substs)
697+
{
698+
pred.visit_with(self)?;
699+
}
700+
}
701+
}
702+
ty::Alias(ty::Projection, _) => {
703+
if let Ok(proj) =
704+
self.tcx.try_normalize_erasing_regions(self.param_env, t)
705+
{
706+
proj.visit_with(self)?;
707+
}
708+
}
709+
// Types that have opaque type fields must get walked manually, they
710+
// would not be seen by the type visitor otherwise.
711+
ty::Adt(adt_def, substs) => {
712+
if !self.ignore_nested.contains(&adt_def.did()) {
713+
// avoid infinite recursion since adts can recursively refer
714+
// to themselves
715+
self.ignore_nested.push(adt_def.did());
716+
for variant in adt_def.variants() {
717+
for field in &variant.fields {
718+
field.ty(self.tcx, substs).visit_with(self)?;
719+
}
720+
}
721+
}
722+
}
723+
_ => (),
724+
}
725+
t.super_visit_with(self)
726+
}
727+
}
728+
val.visit_with(&mut Visitor {
729+
opaque_def_id: opaque_def_id.to_def_id(),
730+
tcx,
731+
ignore_nested: SmallVec::new(),
732+
param_env,
733+
})
734+
.is_break()
735+
}
736+
let tait_in_fn_sig = match tcx.def_kind(def_id) {
737+
DefKind::AssocFn | DefKind::Fn => {
738+
has_tait(tcx.fn_sig(def_id.to_def_id()), opaque_def_id, tcx, param_env)
739+
}
740+
// Opaque types in types of contsts
741+
DefKind::Static(_) | DefKind::Const | DefKind::AssocConst => {
742+
has_tait(tcx.type_of(def_id.to_def_id()), opaque_def_id, tcx, param_env)
743+
}
744+
// Nested opaque types
745+
DefKind::OpaqueTy => has_tait(
746+
tcx.bound_explicit_item_bounds(def_id.to_def_id()).skip_binder(),
747+
opaque_def_id,
748+
tcx,
749+
param_env,
750+
),
751+
_ => false,
752+
};
753+
trace!(?tait_in_fn_sig);
754+
if !tait_in_fn_sig
755+
&& !has_tait(
756+
tcx.predicates_of(def_id.to_def_id()).predicates,
757+
opaque_def_id,
758+
tcx,
759+
param_env,
760+
)
761+
{
762+
return false;
763+
}
764+
}
765+
647766
// We walk up the node tree until we hit the root or the scope of the opaque type.
648767
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
649768
hir_id = tcx.hir().get_parent_item(hir_id).into();

compiler/rustc_middle/src/ty/normalize_erasing_regions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
226226
TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
227227
}
228228

229-
#[instrument(skip(self), level = "debug")]
229+
#[instrument(skip(self), level = "debug", ret)]
230230
fn try_normalize_generic_arg_after_erasing_regions(
231231
&self,
232232
arg: ty::GenericArg<'tcx>,

src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
1717
use rustc_middle::ty::{self, Clause, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
1818
use rustc_span::{sym, Symbol};
1919
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
20+
use rustc_infer::infer::DefiningAnchor;
2021

2122
use super::UNNECESSARY_TO_OWNED;
2223

@@ -370,7 +371,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
370371
if let ItemKind::Fn(_, _, body_id) = &item.kind
371372
&& let output_ty = return_ty(cx, item.hir_id())
372373
&& let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
373-
&& Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
374+
&& Inherited::build(cx.tcx, local_def_id, DefiningAnchor::Bind).enter(|inherited| {
374375
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
375376
fn_ctxt.can_coerce(ty, output_ty)
376377
}) {

src/tools/clippy/clippy_lints/src/transmute/utils.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rustc_hir_typeck::{cast, FnCtxt, Inherited};
44
use rustc_lint::LateContext;
55
use rustc_middle::ty::{cast::CastKind, Ty};
66
use rustc_span::DUMMY_SP;
7+
use rustc_infer::infer::DefiningAnchor;
78

89
// check if the component types of the transmuted collection and the result have different ABI,
910
// size or alignment
@@ -45,7 +46,7 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>
4546
let hir_id = e.hir_id;
4647
let local_def_id = hir_id.owner.def_id;
4748

48-
Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
49+
Inherited::build(cx.tcx, local_def_id, DefiningAnchor::Bind).enter(|inherited| {
4950
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, hir_id);
5051

5152
// If we already have errors, we can't be sure we can pointer cast.

0 commit comments

Comments
 (0)