Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
&& let Some(def_id) = def_id.as_local()
&& self.opaque_type_origin(def_id, DUMMY_SP).is_some() {
&& self.opaque_type_origin(def_id, DUMMY_SP, self.param_env).is_some() {
return None;
}
}
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_hir_typeck/src/inherited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,18 @@ pub struct InheritedBuilder<'tcx> {
}

impl<'tcx> Inherited<'tcx> {
pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
pub fn build(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
mk_defining_use_anchor: impl FnOnce(LocalDefId) -> DefiningAnchor,
) -> InheritedBuilder<'tcx> {
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;

InheritedBuilder {
infcx: tcx
.infer_ctxt()
.ignoring_regions()
.with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)),
.with_opaque_type_inference(mk_defining_use_anchor(hir_owner.def_id)),
def_id,
typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
}
Expand Down
16 changes: 14 additions & 2 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub use diverges::Diverges;
pub use expectation::Expectation;
pub use fn_ctxt::*;
pub use inherited::{Inherited, InheritedBuilder};
use rustc_infer::infer::DefiningAnchor;

use crate::check::check_fn;
use crate::coercion::DynamicCoerceMany;
Expand Down Expand Up @@ -199,12 +200,23 @@ fn typeck_with_fallback<'tcx>(
});
let body = tcx.hir().body(body_id);

let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
let fn_sig_infer = fn_sig.map_or(false, |fn_sig| {
rustc_hir_analysis::collect::get_infer_ret_ty(&fn_sig.decl.output).is_some()
});

let mk_defining_use_anchor = |def_id| {
// In case we are inferring the return signature (via `_` types), ignore defining use
// rules, as we'll error out anyway. This helps improve diagnostics, which otherwise
// may just see `ty::Error` instead of `ty::Alias(Opaque, _)` and not produce better errors.
if fn_sig_infer { DefiningAnchor::Bubble } else { DefiningAnchor::Bind(def_id) }
};

let typeck_results = Inherited::build(tcx, def_id, mk_defining_use_anchor).enter(|inh| {
let param_env = tcx.param_env(def_id);
let mut fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);

if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
let fn_sig = if fn_sig_infer {
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
} else {
tcx.fn_sig(def_id)
Expand Down
137 changes: 128 additions & 9 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitor,
};
use rustc_middle::ty::{DefIdTree, GenericArgKind};
use rustc_span::Span;
use smallvec::SmallVec;

use std::ops::ControlFlow;

Expand Down Expand Up @@ -59,7 +60,7 @@ impl<'tcx> InferCtxt<'tcx> {
let replace_opaque_type = |def_id: DefId| {
def_id
.as_local()
.map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some())
.map_or(false, |def_id| self.opaque_type_origin(def_id, span, param_env).is_some())
};
let value = value.fold_with(&mut BottomUpFolder {
tcx: self.tcx,
Expand Down Expand Up @@ -144,7 +145,7 @@ impl<'tcx> InferCtxt<'tcx> {
// let x = || foo(); // returns the Opaque assoc with `foo`
// }
// ```
self.opaque_type_origin(def_id, cause.span)?
self.opaque_type_origin(def_id, cause.span, param_env)?
}
DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
DefiningAnchor::Error => return None,
Expand All @@ -155,9 +156,10 @@ impl<'tcx> InferCtxt<'tcx> {
// no one encounters it in practice.
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
// where it is of no concern, so we only check for TAITs.
if let Some(OpaqueTyOrigin::TyAlias) = b_def_id
.as_local()
.and_then(|b_def_id| self.opaque_type_origin(b_def_id, cause.span))
if let Some(OpaqueTyOrigin::TyAlias) =
b_def_id.as_local().and_then(|b_def_id| {
self.opaque_type_origin(b_def_id, cause.span, param_env)
})
{
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
span: cause.span,
Expand Down Expand Up @@ -372,7 +374,12 @@ impl<'tcx> InferCtxt<'tcx> {
}

#[instrument(skip(self), level = "trace", ret)]
pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
pub fn opaque_type_origin(
&self,
def_id: LocalDefId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
) -> Option<OpaqueTyOrigin> {
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = match self.defining_use_anchor {
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
Expand All @@ -395,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> {
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
// Named `type Foo = impl Bar;`
hir::OpaqueTyOrigin::TyAlias => {
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id, def_id, param_env)
}
};
trace!(?origin);
Expand Down Expand Up @@ -639,11 +646,123 @@ impl<'tcx> InferCtxt<'tcx> {
/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
#[instrument(skip(tcx), level = "trace", ret)]
fn may_define_opaque_type<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
opaque_hir_id: hir::HirId,
opaque_def_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);

// Named opaque types can be defined by any siblings or children of siblings.
let scope = tcx.hir().get_defining_scope(opaque_hir_id);

// When doing checks within the opaque type itself
if def_id != opaque_def_id
// When the opaque type is defined in the body of a function, the function may access it.
&& hir_id != scope
{
trace!(parent = ?tcx.parent(opaque_def_id.to_def_id()));
fn has_tait<'tcx>(
val: impl TypeVisitable<'tcx>,
opaque_def_id: LocalDefId,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
struct Visitor<'tcx> {
opaque_def_id: DefId,
tcx: TyCtxt<'tcx>,
ignore_nested: SmallVec<[DefId; 1]>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'tcx> TypeVisitor<'tcx> for Visitor<'tcx> {
type BreakTy = ();
#[instrument(skip(self), level = "trace", ret)]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
ty::Alias(ty::Opaque, alias) => {
if alias.def_id == self.opaque_def_id {
return ControlFlow::Break(());
}
if !self.ignore_nested.contains(&alias.def_id) {
// avoid infinite recursion since the opaque type shows
// up in its own bounds.
self.ignore_nested.push(alias.def_id);
for (pred, _span) in self
.tcx
.bound_explicit_item_bounds(alias.def_id)
.subst_iter_copied(self.tcx, alias.substs)
{
pred.visit_with(self)?;
}
}
}
ty::Alias(ty::Projection, _) => {
if let Ok(proj) =
self.tcx.try_normalize_erasing_regions(self.param_env, t)
{
proj.visit_with(self)?;
}
}
// Types that have opaque type fields must get walked manually, they
// would not be seen by the type visitor otherwise.
ty::Adt(adt_def, substs) => {
if !self.ignore_nested.contains(&adt_def.did()) {
// avoid infinite recursion since adts can recursively refer
// to themselves
self.ignore_nested.push(adt_def.did());
for variant in adt_def.variants() {
for field in &variant.fields {
field.ty(self.tcx, substs).visit_with(self)?;
}
}
}
}
_ => (),
}
t.super_visit_with(self)
}
}
val.visit_with(&mut Visitor {
opaque_def_id: opaque_def_id.to_def_id(),
tcx,
ignore_nested: SmallVec::new(),
param_env,
})
.is_break()
}
let tait_in_fn_sig = match tcx.def_kind(def_id) {
DefKind::AssocFn | DefKind::Fn => {
has_tait(tcx.fn_sig(def_id.to_def_id()), opaque_def_id, tcx, param_env)
}
// Opaque types in types of contsts
DefKind::Static(_) | DefKind::Const | DefKind::AssocConst => {
has_tait(tcx.type_of(def_id.to_def_id()), opaque_def_id, tcx, param_env)
}
// Nested opaque types
DefKind::OpaqueTy => has_tait(
tcx.bound_explicit_item_bounds(def_id.to_def_id()).skip_binder(),
opaque_def_id,
tcx,
param_env,
),
_ => false,
};
trace!(?tait_in_fn_sig);
if !tait_in_fn_sig
&& !has_tait(
tcx.predicates_of(def_id.to_def_id()).predicates,
opaque_def_id,
tcx,
param_env,
)
{
return false;
}
}

// We walk up the node tree until we hit the root or the scope of the opaque type.
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
hir_id = tcx.hir().get_parent_item(hir_id).into();
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
}

#[instrument(skip(self), level = "debug")]
#[instrument(skip(self), level = "debug", ret)]
fn try_normalize_generic_arg_after_erasing_regions(
&self,
arg: ty::GenericArg<'tcx>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, Clause, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
use rustc_span::{sym, Symbol};
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
use rustc_infer::infer::DefiningAnchor;

use super::UNNECESSARY_TO_OWNED;

Expand Down Expand Up @@ -370,7 +371,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
if let ItemKind::Fn(_, _, body_id) = &item.kind
&& let output_ty = return_ty(cx, item.hir_id())
&& let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
&& Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
&& Inherited::build(cx.tcx, local_def_id, DefiningAnchor::Bind).enter(|inherited| {
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
fn_ctxt.can_coerce(ty, output_ty)
}) {
Expand Down
3 changes: 2 additions & 1 deletion src/tools/clippy/clippy_lints/src/transmute/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use rustc_hir_typeck::{cast, FnCtxt, Inherited};
use rustc_lint::LateContext;
use rustc_middle::ty::{cast::CastKind, Ty};
use rustc_span::DUMMY_SP;
use rustc_infer::infer::DefiningAnchor;

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

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

// If we already have errors, we can't be sure we can pointer cast.
Expand Down
Loading