Stop exporting TypeckRootCtxt
and FnCtxt
.
While they have many convenient APIs, it is better to expose dedicated functions for them
This commit is contained in:
parent
7a495cc13d
commit
a9edbfda32
@ -40,17 +40,19 @@
|
|||||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||||
use rustc_middle::ty::cast::{CastKind, CastTy};
|
use rustc_middle::ty::cast::{CastKind, CastTy};
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
|
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
use rustc_span::DUMMY_SP;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
|
||||||
/// Reifies a cast check to be checked once we have full type information for
|
/// Reifies a cast check to be checked once we have full type information for
|
||||||
/// a function context.
|
/// a function context.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CastCheck<'tcx> {
|
pub(crate) struct CastCheck<'tcx> {
|
||||||
/// The expression whose value is being casted
|
/// The expression whose value is being casted
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
/// The source type for the cast expression
|
/// The source type for the cast expression
|
||||||
@ -60,8 +62,6 @@ pub struct CastCheck<'tcx> {
|
|||||||
cast_ty: Ty<'tcx>,
|
cast_ty: Ty<'tcx>,
|
||||||
cast_span: Span,
|
cast_span: Span,
|
||||||
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
|
/// The kind of pointer and associated metadata (thin, length or vtable) - we
|
||||||
@ -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> {
|
impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
pub fn new(
|
pub(crate) fn new(
|
||||||
fcx: &FnCtxt<'a, 'tcx>,
|
fcx: &FnCtxt<'a, 'tcx>,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
expr_ty: Ty<'tcx>,
|
expr_ty: Ty<'tcx>,
|
||||||
cast_ty: Ty<'tcx>,
|
cast_ty: Ty<'tcx>,
|
||||||
cast_span: Span,
|
cast_span: Span,
|
||||||
span: Span,
|
span: Span,
|
||||||
constness: hir::Constness,
|
|
||||||
) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
|
) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
|
||||||
let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
|
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
|
// For better error messages, check for some obviously unsized
|
||||||
// cases now. We do a more thorough check at the end, once
|
// cases now. We do a more thorough check at the end, once
|
||||||
@ -644,7 +671,7 @@ pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
|
|||||||
/// Checks a cast, and report an error if one exists. In some cases, this
|
/// 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
|
/// can return Ok and create type errors in the fcx rather than returning
|
||||||
/// directly. coercion-cast is handled in check instead of here.
|
/// 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::CastTy::*;
|
||||||
use rustc_middle::ty::cast::IntTy::*;
|
use rustc_middle::ty::cast::IntTy::*;
|
||||||
|
|
||||||
|
@ -1318,6 +1318,20 @@ fn try_find_coercion_lub<E>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
/// CoerceMany encapsulates the pattern you should use when you have
|
||||||
/// many expressions that are all getting coerced to a common
|
/// many expressions that are all getting coerced to a common
|
||||||
/// type. This arises, for example, when you have a match (the result
|
/// type. This arises, for example, when you have a match (the result
|
||||||
|
@ -1390,15 +1390,7 @@ fn check_expr_cast(
|
|||||||
} else {
|
} else {
|
||||||
// Defer other checks until we're done type checking.
|
// Defer other checks until we're done type checking.
|
||||||
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
||||||
match cast::CastCheck::new(
|
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
|
||||||
self,
|
|
||||||
e,
|
|
||||||
t_expr,
|
|
||||||
t_cast,
|
|
||||||
t.span,
|
|
||||||
expr.span,
|
|
||||||
hir::Constness::NotConst,
|
|
||||||
) {
|
|
||||||
Ok(cast_check) => {
|
Ok(cast_check) => {
|
||||||
debug!(
|
debug!(
|
||||||
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
|
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
///
|
///
|
||||||
/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
|
/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
|
||||||
/// [`InferCtxt`]: infer::InferCtxt
|
/// [`InferCtxt`]: infer::InferCtxt
|
||||||
pub struct FnCtxt<'a, 'tcx> {
|
pub(crate) struct FnCtxt<'a, 'tcx> {
|
||||||
pub(super) body_id: LocalDefId,
|
pub(super) body_id: LocalDefId,
|
||||||
|
|
||||||
/// The parameter environment used for proving trait obligations
|
/// The parameter environment used for proving trait obligations
|
||||||
|
@ -42,8 +42,9 @@
|
|||||||
mod upvar;
|
mod upvar;
|
||||||
mod writeback;
|
mod writeback;
|
||||||
|
|
||||||
pub use fn_ctxt::FnCtxt;
|
pub use coercion::can_coerce;
|
||||||
pub use typeck_root_ctxt::TypeckRootCtxt;
|
use fn_ctxt::FnCtxt;
|
||||||
|
use typeck_root_ctxt::TypeckRootCtxt;
|
||||||
|
|
||||||
use crate::check::check_fn;
|
use crate::check::check_fn;
|
||||||
use crate::coercion::DynamicCoerceMany;
|
use crate::coercion::DynamicCoerceMany;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
/// `bar()` will each have their own `FnCtxt`, but they will
|
/// `bar()` will each have their own `FnCtxt`, but they will
|
||||||
/// share the inference context, will process obligations together,
|
/// share the inference context, will process obligations together,
|
||||||
/// can access each other's local types (scoping permitted), etc.
|
/// 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) infcx: InferCtxt<'tcx>,
|
||||||
|
|
||||||
pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
|
pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
|
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
|
||||||
use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt};
|
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::mir::Mutability;
|
use rustc_middle::mir::Mutability;
|
||||||
@ -437,9 +436,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
|
|||||||
Node::Item(item) => {
|
Node::Item(item) => {
|
||||||
if let ItemKind::Fn(_, _, body_id) = &item.kind
|
if let ItemKind::Fn(_, _, body_id) = &item.kind
|
||||||
&& let output_ty = return_ty(cx, item.owner_id)
|
&& let output_ty = return_ty(cx, item.owner_id)
|
||||||
&& let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id)
|
&& rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty)
|
||||||
&& let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id)
|
|
||||||
&& fn_ctxt.can_coerce(ty, output_ty)
|
|
||||||
{
|
{
|
||||||
if has_lifetime(output_ty) && has_lifetime(ty) {
|
if has_lifetime(output_ty) && has_lifetime(ty) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::utils::check_cast;
|
use rustc_hir_typeck::cast::check_cast;
|
||||||
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
|
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::Sugg;
|
||||||
@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
|
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
|
||||||
let mut app = Applicability::MachineApplicable;
|
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(FnPtrAddrCast | PtrAddrCast) if const_context => return false,
|
||||||
Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
|
Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
|
||||||
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
|
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
|
||||||
|
@ -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_lint::LateContext;
|
||||||
use rustc_middle::ty::cast::CastKind;
|
|
||||||
use rustc_middle::ty::Ty;
|
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,
|
// check if the component types of the transmuted collection and the result have different ABI,
|
||||||
// size or alignment
|
// size or alignment
|
||||||
@ -20,35 +15,3 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
|
|||||||
false
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user