From b95b285ef4831ea1342e4aead7aa245156b24cb7 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 30 Aug 2022 12:39:28 -0700 Subject: [PATCH] Make x.py check work --- clippy_lints/src/transmute/utils.rs | 29 ++-- clippy_utils/src/qualify_min_const_fn.rs | 141 +++++++++++-------- clippy_utils/src/ty.rs | 165 ++++++++++++++--------- 3 files changed, 204 insertions(+), 131 deletions(-) diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index 74927570b..78cc589cc 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -2,11 +2,18 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; -use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited}; +use rustc_typeck::check::{ + cast::{self, CastCheckResult}, + FnCtxt, Inherited, +}; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment -pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { +pub(super) fn is_layout_incompatible<'tcx>( + cx: &LateContext<'tcx>, + from: Ty<'tcx>, + to: Ty<'tcx>, +) -> bool { if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) @@ -29,7 +36,9 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) -> bool { - use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; + use CastKind::{ + AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast, + }; matches!( check_cast(cx, e, from_ty, to_ty), Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) @@ -40,7 +49,12 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// 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. -fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { +fn check_cast<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option { let hir_id = e.hir_id; let local_def_id = hir_id.owner; @@ -48,12 +62,9 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> 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. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "Newly created FnCtxt contained errors" - ); + assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors"); - if let Ok(check) = CastCheck::new( + if let CastCheckResult::Deferred(check) = cast::check_cast( &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, diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index d5f64e511..781744870 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,11 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option) -> McfResult { +pub fn is_min_const_fn<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + msrv: Option, +) -> McfResult { let def_id = body.source.def_id(); let mut current = def_id; loop { @@ -33,10 +37,18 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), - ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), - ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), - ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate), + ty::PredicateKind::ObjectSafe(_) => { + panic!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateKind::ClosureKind(..) => { + panic!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Subtype(_) => { + panic!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Coerce(_) => { + panic!("coerce predicate on function: {:#?}", predicate) + } } } match predicates.parent { @@ -77,22 +89,23 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { return Err((span, "mutable references in const fn are unstable".into())); - }, + } ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); - }, - ty::Dynamic(preds, _) => { + } + ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { return Err(( span, "trait bounds other than `Sized` \ on const fn parameters are unstable" .into(), )); - }, + } ty::ExistentialPredicate::Trait(trait_ref) => { if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { return Err(( @@ -102,11 +115,11 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { .into(), )); } - }, + } } } - }, - _ => {}, + } + _ => {} } } Ok(()) @@ -120,10 +133,13 @@ fn check_rvalue<'tcx>( span: Span, ) -> McfResult { match rvalue { - Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), - Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - check_place(tcx, *place, span, body) - }, + Rvalue::ThreadLocalRef(_) => { + Err((span, "cannot access thread local storage in const fn".into())) + } + Rvalue::Len(place) + | Rvalue::Discriminant(place) + | Rvalue::Ref(_, _, place) + | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) @@ -136,7 +152,9 @@ fn check_rvalue<'tcx>( ) => check_operand(tcx, operand, span, body), Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, ), _, _, @@ -146,7 +164,10 @@ fn check_rvalue<'tcx>( deref_ty.ty } else { // We cannot allow this for now. - return Err((span, "unsizing casts are only allowed for references right now".into())); + return Err(( + span, + "unsizing casts are only allowed for references right now".into(), + )); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { @@ -157,10 +178,14 @@ fn check_rvalue<'tcx>( // We just can't allow trait objects until we have figured out trait method calls. Err((span, "unsizing casts are not allowed in const fn".into())) } - }, + } Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) - }, + } + Rvalue::Cast(CastKind::DynStar, _, _) => { + // FIXME(dyn-star) + unimplemented!() + } // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; @@ -169,13 +194,12 @@ fn check_rvalue<'tcx>( if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { - Err(( - span, - "only int, `bool` and `char` operations are stable in const fn".into(), - )) + Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) } - }, - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), + } + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => { + Ok(()) + } Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { @@ -183,13 +207,13 @@ fn check_rvalue<'tcx>( } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } - }, + } Rvalue::Aggregate(_, operands) => { for operand in operands { check_operand(tcx, operand, span, body)?; } Ok(()) - }, + } } } @@ -204,7 +228,7 @@ fn check_statement<'tcx>( StatementKind::Assign(box (place, rval)) => { check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) - }, + } StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), // just an assignment @@ -214,14 +238,15 @@ fn check_statement<'tcx>( StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body), - StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( - rustc_middle::mir::CopyNonOverlapping { dst, src, count }, - )) => { + StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + dst, + src, + count, + }) => { check_operand(tcx, dst, span, body)?; check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) - }, - + } // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) @@ -232,7 +257,12 @@ fn check_statement<'tcx>( } } -fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_operand<'tcx>( + tcx: TyCtxt<'tcx>, + operand: &Operand<'tcx>, + span: Span, + body: &Body<'tcx>, +) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -242,7 +272,12 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b } } -fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_place<'tcx>( + tcx: TyCtxt<'tcx>, + place: Place<'tcx>, + span: Span, + body: &Body<'tcx>, +) -> McfResult { let mut cursor = place.projection.as_ref(); while let [ref proj_base @ .., elem] = *cursor { cursor = proj_base; @@ -255,12 +290,12 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B return Err((span, "accessing union fields is unstable".into())); } } - }, + } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref - | ProjectionElem::Index(_) => {}, + | ProjectionElem::Index(_) => {} } } @@ -286,18 +321,16 @@ fn check_terminator<'a, 'tcx>( TerminatorKind::DropAndReplace { place, value, .. } => { check_place(tcx, *place, span, body)?; check_operand(tcx, value, span, body) - }, + } - TerminatorKind::SwitchInt { - discr, - switch_ty: _, - targets: _, - } => check_operand(tcx, discr, span, body), + TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => { + check_operand(tcx, discr, span, body) + } TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) - }, + } TerminatorKind::Call { func, @@ -342,17 +375,15 @@ fn check_terminator<'a, 'tcx>( } else { Err((span, "can only call other const fns within const fn".into())) } - }, + } - TerminatorKind::Assert { - cond, - expected: _, - msg: _, - target: _, - cleanup: _, - } => check_operand(tcx, cond, span, body), + TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { + check_operand(tcx, cond, span, body) + } - TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), + TerminatorKind::InlineAsm { .. } => { + Err((span, "cannot use inline assembly in const fn".into())) + } } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 5a7f95684..99803ae93 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -14,8 +14,9 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, - Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, + self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, + ProjectionTy, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, + UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -166,9 +167,7 @@ pub fn implements_trait_with_env<'tcx>( } let ty_params = tcx.mk_substs(ty_params.iter()); tcx.infer_ctxt().enter(|infcx| { - infcx - .type_implements_trait(trait_id, ty, ty_params, param_env) - .must_apply_modulo_regions() + infcx.type_implements_trait(trait_id, ty, ty_params, param_env).must_apply_modulo_regions() }) } @@ -185,11 +184,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), - ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { + ty::Slice(ty) + | ty::Array(ty, _) + | ty::RawPtr(ty::TypeAndMut { ty, .. }) + | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) - }, + } ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { @@ -200,8 +202,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - }, - ty::Dynamic(binder, _) => { + } + ty::Dynamic(binder, _, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) { @@ -210,7 +212,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - }, + } _ => false, } } @@ -220,7 +222,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { +pub fn is_normalizable<'tcx>( + cx: &LateContext<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } @@ -240,15 +246,14 @@ fn is_normalizable_helper<'tcx>( if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, substs) => def.variants().iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) + variant.fields.iter().all(|field| { + is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache) + }) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) - }, + } _ => true, // if inner_ty == ty, we've already checked it }), } @@ -273,7 +278,9 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), + ty::Array(inner_type, _) | ty::Slice(inner_type) => { + is_recursively_primitive_type(inner_type) + } ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type), _ => false, } @@ -313,11 +320,9 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Returns `false` if the `LangItem` is not defined. pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { match ty.kind() { - ty::Adt(adt, _) => cx - .tcx - .lang_items() - .require(lang_item) - .map_or(false, |li| li == adt.did()), + ty::Adt(adt, _) => { + cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did()) + } _ => false, } } @@ -342,7 +347,11 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// deallocate memory. For these types, and composites containing them, changing the drop order /// won't result in any observable side effects. pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet>) -> bool { + fn needs_ordered_drop_inner<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + seen: &mut FxHashSet>, + ) -> bool { if !seen.insert(ty) { return false; } @@ -393,11 +402,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// removed. pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(*ty, count + 1) - } else { - (ty, count) - } + if let ty::Ref(_, ty, _) = ty.kind() { peel(*ty, count + 1) } else { (ty, count) } } peel(ty, 0) } @@ -452,17 +457,18 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { return false; } - substs_a - .iter() - .zip(substs_b.iter()) - .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { - (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, + substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| { + match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => { + inner_a == inner_b + } (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { same_type_and_consts(type_a, type_b) - }, + } _ => true, - }) - }, + } + }) + } _ => a == b, } } @@ -478,7 +484,10 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { } /// Gets an iterator over all predicates which apply to the given item. -pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator, Span)> { +pub fn all_predicates_of( + tcx: TyCtxt<'_>, + id: DefId, +) -> impl Iterator, Span)> { let mut next_id = Some(id); iter::from_fn(move || { next_id.take().map(|id| { @@ -508,7 +517,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some(sig.input(i)) } - }, + } Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } @@ -517,7 +526,10 @@ impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. For closures this will also get the type as /// written. This will return `None` when the index is out of bounds only for variadic /// functions, otherwise this will panic. - pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { + pub fn input_with_hir( + self, + i: usize, + ) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { match self { Self::Sig(sig, _) => { if sig.c_variadic() { @@ -528,7 +540,7 @@ impl<'tcx> ExprFnSig<'tcx> { } else { Some((None, sig.input(i))) } - }, + } Self::Closure(decl, sig) => Some(( decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), @@ -547,17 +559,15 @@ impl<'tcx> ExprFnSig<'tcx> { } pub fn predicates_id(&self) -> Option { - if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { - id - } else { - None - } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { id } else { None } } } /// If the expression is function like, get the signature for it. pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option> { - if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = + path_res(cx, expr) + { Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id))) } else { ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs()) @@ -571,15 +581,17 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { - let decl = id - .as_local() - .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); + let decl = id.as_local().and_then(|id| { + cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)) + }); Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) - }, - ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), + } + ty::FnDef(id, subs) => { + Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))) + } ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), - ty::Dynamic(bounds, _) => { + ty::Dynamic(bounds, _, _) => { let lang_items = cx.tcx.lang_items(); match bounds.principal() { Some(bound) @@ -589,16 +601,19 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option None, } - }, + } ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), + _ => sig_for_projection(cx, proj) + .or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, @@ -629,7 +644,7 @@ fn sig_from_bounds<'tcx>( return None; } inputs = Some(i); - }, + } PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty => @@ -639,7 +654,7 @@ fn sig_from_bounds<'tcx>( return None; } output = Some(pred.kind().rebind(p.term.ty().unwrap())); - }, + } _ => (), } } @@ -647,7 +662,10 @@ fn sig_from_bounds<'tcx>( inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } -fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { +fn sig_for_projection<'tcx>( + cx: &LateContext<'tcx>, + ty: ProjectionTy<'tcx>, +) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); @@ -673,8 +691,10 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O return None; } inputs = Some(i); - }, - PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { + } + PredicateKind::Projection(p) + if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => + { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? return None; @@ -683,7 +703,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap())) .subst(cx.tcx, ty.substs), ); - }, + } _ => (), } } @@ -777,7 +797,10 @@ pub fn for_each_top_level_late_bound_region( ControlFlow::Continue(()) } } - fn visit_binder>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow { + fn visit_binder>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow { self.index += 1; let res = t.super_visit_with(self); self.index -= 1; @@ -791,19 +814,27 @@ pub fn for_each_top_level_late_bound_region( pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> { match res { Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()), - Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)), - Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()), + Res::Def(DefKind::Variant, id) => { + Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)) + } + Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => { + Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()) + } Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => { let var_id = cx.tcx.parent(id); Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) - }, + } Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), _ => None, } } /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`. -pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool { +pub fn ty_is_fn_once_param<'tcx>( + tcx: TyCtxt<'_>, + ty: Ty<'tcx>, + predicates: &'tcx [Predicate<'_>], +) -> bool { let ty::Param(ty) = *ty.kind() else { return false; };