Skip to content

Commit

Permalink
Rollup merge of rust-lang#123625 - oli-obk:private_fnctxt, r=fee1-dead
Browse files Browse the repository at this point in the history
Stop exporting `TypeckRootCtxt` and `FnCtxt`.

While they have many convenient APIs, it is better to expose dedicated functions for them

noticed in rust-lang#122213
  • Loading branch information
matthiaskrgr committed Apr 8, 2024
2 parents 5c3559d + a9edbfd commit f825271
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 63 deletions.
41 changes: 34 additions & 7 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,19 @@ use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
use rustc_session::lint;
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_span::DUMMY_SP;
use rustc_trait_selection::infer::InferCtxtExt;

/// Reifies a cast check to be checked once we have full type information for
/// a function context.
#[derive(Debug)]
pub struct CastCheck<'tcx> {
pub(crate) struct CastCheck<'tcx> {
/// The expression whose value is being casted
expr: &'tcx hir::Expr<'tcx>,
/// The source type for the cast expression
Expand All @@ -60,8 +62,6 @@ pub struct CastCheck<'tcx> {
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
/// whether the cast is made in a const context or not.
pub constness: hir::Constness,
}

/// The kind of pointer and associated metadata (thin, length or vtable) - we
Expand Down Expand Up @@ -194,18 +194,45 @@ fn make_invalid_casting_error<'a, 'tcx>(
)
}

/// If a cast from `from_ty` to `to_ty` is valid, returns a `Some` containing the kind
/// of the cast.
///
/// This is a helper used from clippy.
pub fn check_cast<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
e: &'tcx hir::Expr<'tcx>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
) -> Option<CastKind> {
let hir_id = e.hir_id;
let local_def_id = hir_id.owner.def_id;

let root_ctxt = crate::TypeckRootCtxt::new(tcx, local_def_id);
let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, local_def_id);

if let Ok(check) = CastCheck::new(
&fn_ctxt, e, from_ty, to_ty,
// We won't show any errors to the user, so the span is irrelevant here.
DUMMY_SP, DUMMY_SP,
) {
check.do_check(&fn_ctxt).ok()
} else {
None
}
}

impl<'a, 'tcx> CastCheck<'tcx> {
pub fn new(
pub(crate) fn new(
fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr<'tcx>,
expr_ty: Ty<'tcx>,
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
constness: hir::Constness,
) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness };
let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };

// For better error messages, check for some obviously unsized
// cases now. We do a more thorough check at the end, once
Expand Down Expand Up @@ -644,7 +671,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
/// Checks a cast, and report an error if one exists. In some cases, this
/// can return Ok and create type errors in the fcx rather than returning
/// directly. coercion-cast is handled in check instead of here.
pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
use rustc_middle::ty::cast::CastTy::*;
use rustc_middle::ty::cast::IntTy::*;

Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

/// Check whether `ty` can be coerced to `output_ty`.
/// Used from clippy.
pub fn can_coerce<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: LocalDefId,
ty: Ty<'tcx>,
output_ty: Ty<'tcx>,
) -> bool {
let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id);
let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id);
fn_ctxt.can_coerce(ty, output_ty)
}

/// CoerceMany encapsulates the pattern you should use when you have
/// many expressions that are all getting coerced to a common
/// type. This arises, for example, when you have a match (the result
Expand Down
10 changes: 1 addition & 9 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1390,15 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
match cast::CastCheck::new(
self,
e,
t_expr,
t_cast,
t.span,
expr.span,
hir::Constness::NotConst,
) {
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
Ok(cast_check) => {
debug!(
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use std::ops::Deref;
///
/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
/// [`InferCtxt`]: infer::InferCtxt
pub struct FnCtxt<'a, 'tcx> {
pub(crate) struct FnCtxt<'a, 'tcx> {
pub(super) body_id: LocalDefId,

/// The parameter environment used for proving trait obligations
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ mod typeck_root_ctxt;
mod upvar;
mod writeback;

pub use fn_ctxt::FnCtxt;
pub use typeck_root_ctxt::TypeckRootCtxt;
pub use coercion::can_coerce;
use fn_ctxt::FnCtxt;
use typeck_root_ctxt::TypeckRootCtxt;

use crate::check::check_fn;
use crate::coercion::DynamicCoerceMany;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::ops::Deref;
/// `bar()` will each have their own `FnCtxt`, but they will
/// share the inference context, will process obligations together,
/// can access each other's local types (scoping permitted), etc.
pub struct TypeckRootCtxt<'tcx> {
pub(crate) struct TypeckRootCtxt<'tcx> {
pub(super) infcx: InferCtxt<'tcx>,

pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::Mutability;
Expand Down Expand Up @@ -437,9 +436,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
Node::Item(item) => {
if let ItemKind::Fn(_, _, body_id) = &item.kind
&& let output_ty = return_ty(cx, item.owner_id)
&& let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id)
&& let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id)
&& fn_ctxt.can_coerce(ty, output_ty)
&& rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty)
{
if has_lifetime(output_ty) && has_lifetime(ty) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::utils::check_cast;
use rustc_hir_typeck::cast::check_cast;
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
Expand All @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
) -> bool {
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
let mut app = Applicability::MachineApplicable;
let mut sugg = match check_cast(cx, e, from_ty, to_ty) {
let mut sugg = match check_cast(cx.tcx, cx.param_env, e, from_ty, to_ty) {
Some(FnPtrAddrCast | PtrAddrCast) if const_context => return false,
Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
Expand Down
37 changes: 0 additions & 37 deletions src/tools/clippy/clippy_lints/src/transmute/utils.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
use rustc_hir as hir;
use rustc_hir::Expr;
use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt};
use rustc_lint::LateContext;
use rustc_middle::ty::cast::CastKind;
use rustc_middle::ty::Ty;
use rustc_span::DUMMY_SP;

// check if the component types of the transmuted collection and the result have different ABI,
// size or alignment
Expand All @@ -20,35 +15,3 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
false
}
}

/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
/// the cast. In certain cases, including some invalid casts from array references
/// to pointers, this may cause additional errors to be emitted and/or ICE error
/// messages. This function will panic if that occurs.
pub(super) fn check_cast<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
) -> Option<CastKind> {
let hir_id = e.hir_id;
let local_def_id = hir_id.owner.def_id;

let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id);
let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id);

if let Ok(check) = cast::CastCheck::new(
&fn_ctxt,
e,
from_ty,
to_ty,
// We won't show any error to the user, so we don't care what the span is here.
DUMMY_SP,
DUMMY_SP,
hir::Constness::NotConst,
) {
check.do_check(&fn_ctxt).ok()
} else {
None
}
}

0 comments on commit f825271

Please sign in to comment.