Skip to content

Commit 73cfef3

Browse files
committed
equire TAITs to appear in the signature of items that register a hidden type
1 parent 669e751 commit 73cfef3

Some content is hidden

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

42 files changed

+654
-242
lines changed

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ hir_analysis_trait_object_declared_with_no_traits =
6969
at least one trait is required for an object type
7070
.alias_span = this alias does not contain a trait
7171
72+
hir_analysis_opaque_type_constrained_bug_not_in_sig = opaque type constrained without being represented in the signature
73+
.item_label = this item must mention the opaque type in its signature or where bounds
74+
7275
hir_analysis_missing_type_params =
7376
the type {$parameterCount ->
7477
[one] parameter

compiler/rustc_hir_analysis/src/collect/type_of.rs

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use std::ops::ControlFlow;
2+
3+
use hir::def::DefKind;
4+
use rustc_data_structures::fx::FxHashSet;
15
use rustc_errors::{Applicability, StashKey};
26
use rustc_hir as hir;
37
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -9,15 +13,15 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
913
use rustc_middle::ty::subst::InternalSubsts;
1014
use rustc_middle::ty::util::IntTypeExt;
1115
use rustc_middle::ty::{
12-
self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
13-
TypeVisitableExt,
16+
self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
17+
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
1418
};
1519
use rustc_span::symbol::Ident;
1620
use rustc_span::{Span, DUMMY_SP};
1721

1822
use super::ItemCtxt;
1923
use super::{bad_placeholder, is_suggestable_infer_ty};
20-
use crate::errors::UnconstrainedOpaqueType;
24+
use crate::errors::{OpaqueTypeConstrainedButNotInSig, UnconstrainedOpaqueType};
2125

2226
/// Computes the relevant generic parameter for a potential generic const argument.
2327
///
@@ -635,6 +639,12 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
635639
let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
636640
debug!(?concrete_opaque_types);
637641
if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
642+
if !may_define_opaque_type(self.tcx, item_def_id, self.def_id) {
643+
self.tcx.sess.emit_err(OpaqueTypeConstrainedButNotInSig {
644+
span: concrete_type.span,
645+
item_span: self.tcx.def_span(item_def_id),
646+
});
647+
}
638648
debug!(?concrete_type, "found constraint");
639649
if let Some(prev) = &mut self.found {
640650
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
@@ -743,6 +753,117 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
743753
hidden.ty
744754
}
745755

756+
#[instrument(skip(tcx), level = "trace", ret)]
757+
fn may_define_opaque_type<'tcx>(
758+
tcx: TyCtxt<'tcx>,
759+
def_id: LocalDefId,
760+
opaque_def_id: LocalDefId,
761+
) -> bool {
762+
if tcx.is_descendant_of(opaque_def_id.to_def_id(), def_id.to_def_id()) {
763+
// If the opaque type is defined in the body of a function, that function
764+
// may constrain the opaque type since it can't mention it in bounds.
765+
return true;
766+
}
767+
768+
if tcx.is_closure(def_id.to_def_id()) {
769+
return may_define_opaque_type(tcx, tcx.local_parent(def_id), opaque_def_id);
770+
}
771+
772+
let param_env = tcx.param_env(def_id);
773+
774+
trace!(parent = ?tcx.parent(opaque_def_id.to_def_id()));
775+
fn has_tait<'tcx>(
776+
val: impl TypeVisitable<TyCtxt<'tcx>>,
777+
opaque_def_id: LocalDefId,
778+
tcx: TyCtxt<'tcx>,
779+
param_env: ty::ParamEnv<'tcx>,
780+
) -> bool {
781+
struct Visitor<'tcx> {
782+
opaque_def_id: DefId,
783+
tcx: TyCtxt<'tcx>,
784+
seen: FxHashSet<Ty<'tcx>>,
785+
param_env: ty::ParamEnv<'tcx>,
786+
}
787+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
788+
type BreakTy = ();
789+
790+
#[instrument(skip(self), level = "trace", ret)]
791+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
792+
// Erase all lifetimes, they can't affect anything, but recursion
793+
// may cause late bound regions to differ, because the type visitor
794+
// can't erase them in `visit_binder`.
795+
let t = t.fold_with(&mut ty::fold::BottomUpFolder {
796+
tcx: self.tcx,
797+
ct_op: |c| c,
798+
ty_op: |t| t,
799+
lt_op: |_| self.tcx.lifetimes.re_erased,
800+
});
801+
if !self.seen.insert(t) {
802+
return ControlFlow::Continue(());
803+
}
804+
match t.kind() {
805+
ty::Alias(ty::Opaque, alias) => {
806+
if alias.def_id == self.opaque_def_id {
807+
return ControlFlow::Break(());
808+
}
809+
for (pred, _span) in self
810+
.tcx
811+
.bound_explicit_item_bounds(alias.def_id)
812+
.subst_iter_copied(self.tcx, alias.substs)
813+
{
814+
pred.visit_with(self)?;
815+
}
816+
}
817+
ty::Alias(ty::Projection, _) => {
818+
if let Ok(proj) = self.tcx.try_normalize_erasing_regions(self.param_env, t)
819+
{
820+
proj.visit_with(self)?;
821+
}
822+
}
823+
// Types that have opaque type fields must get walked manually, they
824+
// would not be seen by the type visitor otherwise.
825+
ty::Adt(adt_def, substs) => {
826+
for variant in adt_def.variants() {
827+
for field in &variant.fields {
828+
field.ty(self.tcx, substs).visit_with(self)?;
829+
}
830+
}
831+
}
832+
_ => (),
833+
}
834+
t.super_visit_with(self)
835+
}
836+
}
837+
val.visit_with(&mut Visitor {
838+
opaque_def_id: opaque_def_id.to_def_id(),
839+
tcx,
840+
seen: Default::default(),
841+
param_env,
842+
})
843+
.is_break()
844+
}
845+
let tait_in_fn_sig = match tcx.def_kind(def_id) {
846+
DefKind::AssocFn | DefKind::Fn => {
847+
has_tait(tcx.fn_sig(def_id.to_def_id()).skip_binder(), opaque_def_id, tcx, param_env)
848+
}
849+
// Opaque types in types of contsts
850+
DefKind::Static(_) | DefKind::Const | DefKind::AssocConst => {
851+
has_tait(tcx.type_of(def_id.to_def_id()).skip_binder(), opaque_def_id, tcx, param_env)
852+
}
853+
// Nested opaque types
854+
DefKind::OpaqueTy => has_tait(
855+
tcx.bound_explicit_item_bounds(def_id.to_def_id()).skip_binder(),
856+
opaque_def_id,
857+
tcx,
858+
param_env,
859+
),
860+
_ => false,
861+
};
862+
trace!(?tait_in_fn_sig);
863+
tait_in_fn_sig
864+
|| has_tait(tcx.predicates_of(def_id.to_def_id()).predicates, opaque_def_id, tcx, param_env)
865+
}
866+
746867
fn find_opaque_ty_constraints_for_rpit(
747868
tcx: TyCtxt<'_>,
748869
def_id: LocalDefId,

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,15 @@ pub struct UnconstrainedOpaqueType {
176176
pub what: &'static str,
177177
}
178178

179+
#[derive(Diagnostic)]
180+
#[diag(hir_analysis_opaque_type_constrained_bug_not_in_sig)]
181+
pub struct OpaqueTypeConstrainedButNotInSig {
182+
#[primary_span]
183+
pub span: Span,
184+
#[label(hir_analysis_item_label)]
185+
pub item_span: Span,
186+
}
187+
179188
pub struct MissingTypeParams {
180189
pub span: Span,
181190
pub def_span: Span,

compiler/rustc_hir_typeck/src/inherited.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,17 @@ impl<'tcx> Deref for Inherited<'tcx> {
7373
}
7474

7575
impl<'tcx> Inherited<'tcx> {
76-
pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
76+
pub fn new(
77+
tcx: TyCtxt<'tcx>,
78+
def_id: LocalDefId,
79+
mk_defining_use_anchor: impl FnOnce(LocalDefId) -> DefiningAnchor,
80+
) -> Self {
7781
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
7882

7983
let infcx = tcx
8084
.infer_ctxt()
8185
.ignoring_regions()
82-
.with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
86+
.with_opaque_type_inference(mk_defining_use_anchor(hir_owner.def_id))
8387
.build();
8488
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
8589

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ mod writeback;
4747

4848
pub use fn_ctxt::FnCtxt;
4949
pub use inherited::Inherited;
50+
use rustc_infer::infer::DefiningAnchor;
5051

5152
use crate::check::check_fn;
5253
use crate::coercion::DynamicCoerceMany;
@@ -212,11 +213,21 @@ fn typeck_with_fallback<'tcx>(
212213
} else {
213214
param_env
214215
};
215-
let inh = Inherited::new(tcx, def_id);
216+
let fn_sig_infer = fn_sig.map_or(false, |fn_sig| {
217+
rustc_hir_analysis::collect::get_infer_ret_ty(&fn_sig.decl.output).is_some()
218+
});
219+
220+
let mk_defining_use_anchor = |def_id| {
221+
// In case we are inferring the return signature (via `_` types), ignore defining use
222+
// rules, as we'll error out anyway. This helps improve diagnostics, which otherwise
223+
// may just see `ty::Error` instead of `ty::Alias(Opaque, _)` and not produce better errors.
224+
if fn_sig_infer { DefiningAnchor::Bubble } else { DefiningAnchor::Bind(def_id) }
225+
};
226+
let inh = Inherited::new(tcx, def_id, mk_defining_use_anchor);
216227
let mut fcx = FnCtxt::new(&inh, param_env, def_id);
217228

218229
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
219-
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
230+
let fn_sig = if fn_sig_infer {
220231
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
221232
} else {
222233
tcx.fn_sig(def_id).subst_identity()

compiler/rustc_infer/src/infer/opaque_types.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,6 @@ impl<'tcx> InferCtxt<'tcx> {
372372
/// in its defining scope.
373373
#[instrument(skip(self), level = "trace", ret)]
374374
pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
375-
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
376375
let parent_def_id = match self.defining_use_anchor {
377376
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
378377
DefiningAnchor::Bind(bind) => bind,
@@ -385,9 +384,7 @@ impl<'tcx> InferCtxt<'tcx> {
385384
// Anonymous `impl Trait`
386385
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
387386
// Named `type Foo = impl Bar;`
388-
hir::OpaqueTyOrigin::TyAlias => {
389-
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
390-
}
387+
hir::OpaqueTyOrigin::TyAlias => may_define_opaque_type(self.tcx, parent_def_id, def_id),
391388
};
392389
in_definition_scope.then_some(origin)
393390
}
@@ -634,7 +631,13 @@ impl<'tcx> InferCtxt<'tcx> {
634631
/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
635632
/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
636633
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
637-
fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
634+
#[instrument(skip(tcx), level = "trace", ret)]
635+
fn may_define_opaque_type<'tcx>(
636+
tcx: TyCtxt<'tcx>,
637+
def_id: LocalDefId,
638+
opaque_def_id: LocalDefId,
639+
) -> bool {
640+
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id);
638641
let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
639642

640643
// Named opaque types can be defined by any siblings or children of siblings.

compiler/rustc_middle/src/ty/normalize_erasing_regions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
223223
TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
224224
}
225225

226-
#[instrument(skip(self), level = "debug")]
226+
#[instrument(skip(self), level = "debug", ret)]
227227
fn try_normalize_generic_arg_after_erasing_regions(
228228
&self,
229229
arg: ty::GenericArg<'tcx>,

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

Lines changed: 2 additions & 1 deletion
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

@@ -369,7 +370,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
369370
Node::Item(item) => {
370371
if let ItemKind::Fn(_, _, body_id) = &item.kind
371372
&& let output_ty = return_ty(cx, item.owner_id)
372-
&& let inherited = Inherited::new(cx.tcx, item.owner_id.def_id)
373+
&& let inherited = Inherited::new(cx.tcx, item.owner_id.def_id, DefiningAnchor::Bind)
373374
&& let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id)
374375
&& fn_ctxt.can_coerce(ty, output_ty)
375376
{

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

Lines changed: 2 additions & 1 deletion
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
@@ -33,7 +34,7 @@ pub(super) fn check_cast<'tcx>(
3334
let hir_id = e.hir_id;
3435
let local_def_id = hir_id.owner.def_id;
3536

36-
let inherited = Inherited::new(cx.tcx, local_def_id);
37+
let inherited = Inherited::new(cx.tcx, local_def_id, DefiningAnchor::Bind);
3738
let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id);
3839

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

0 commit comments

Comments
 (0)