From 70f9d520793318617949e660458bd717548ec8d6 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 20 Jan 2023 15:59:56 +0000 Subject: [PATCH 1/4] Add and use expect methods to hir. --- compiler/rustc_hir/src/hir.rs | 343 +++++++++++++++++- .../rustc_hir_analysis/src/astconv/mod.rs | 3 +- .../src/check/compare_impl_item.rs | 16 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 8 +- .../src/coherence/builtin.rs | 2 +- .../src/coherence/unsafety.rs | 4 +- compiler/rustc_hir_analysis/src/collect.rs | 3 +- 7 files changed, 356 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d6566860f81..4640317ac73 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2263,7 +2263,7 @@ pub struct TraitItem<'hir> { pub defaultness: Defaultness, } -impl TraitItem<'_> { +impl<'hir> TraitItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2273,6 +2273,27 @@ pub fn hir_id(&self) -> HirId { pub fn trait_item_id(&self) -> TraitItemId { TraitItemId { owner_id: self.owner_id } } + + /// Expect an [`TraitItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option) { + let TraitItemKind::Const(ty, body) = self.kind else { unreachable!() }; + (ty, body) + } + + /// Expect an [`TraitItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { + let TraitItemKind::Fn(ty, trfn) = &self.kind else { unreachable!() }; + (ty, trfn) + } + + /// Expect an [`TraitItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { + let TraitItemKind::Type(bounds, ty) = self.kind else { unreachable!() }; + (bounds, ty) + } } /// Represents a trait method's body (or just argument names). @@ -2325,7 +2346,7 @@ pub struct ImplItem<'hir> { pub vis_span: Span, } -impl ImplItem<'_> { +impl<'hir> ImplItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2335,6 +2356,27 @@ pub fn hir_id(&self) -> HirId { pub fn impl_item_id(&self) -> ImplItemId { ImplItemId { owner_id: self.owner_id } } + + /// Expect an [`ImplItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ImplItemKind::Const(ty, body) = self.kind else { unreachable!() }; + (ty, body) + } + + /// Expect an [`ImplItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) { + let ImplItemKind::Fn(ty, body) = &self.kind else { unreachable!() }; + (ty, *body) + } + + /// Expect an [`ImplItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_type(&self) -> &'hir Ty<'hir> { + let ImplItemKind::Type(ty) = self.kind else { unreachable!() }; + ty + } } /// Represents various kinds of content within an `impl`. @@ -2995,7 +3037,7 @@ pub struct Item<'hir> { pub vis_span: Span, } -impl Item<'_> { +impl<'hir> Item<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -3005,6 +3047,127 @@ pub fn hir_id(&self) -> HirId { pub fn item_id(&self) -> ItemId { ItemId { owner_id: self.owner_id } } + + /// Expect an [`ItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_extern_crate(&self) -> Option { + let ItemKind::ExternCrate(s) = self.kind else { unreachable!() }; + s + } + + /// Expect an [`ItemKind::Use`] or panic. + #[track_caller] + pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) { + let ItemKind::Use(p, uk) = self.kind else { unreachable!() }; + (p, uk) + } + + /// Expect an [`ItemKind::Static`] or panic. + #[track_caller] + pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) { + let ItemKind::Static(ty, mutbl, body) = self.kind else { unreachable!() }; + (ty, mutbl, body) + } + /// Expect an [`ItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ItemKind::Const(ty, body) = self.kind else { unreachable!() }; + (ty, body) + } + /// Expect an [`ItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) { + let ItemKind::Fn(sig, gen, body) = &self.kind else { unreachable!() }; + (sig, gen, *body) + } + + /// Expect an [`ItemKind::Macro`] or panic. + #[track_caller] + pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) { + let ItemKind::Macro(def, mk) = &self.kind else { unreachable!() }; + (def, *mk) + } + + /// Expect an [`ItemKind::Mod`] or panic. + #[track_caller] + pub fn expect_mod(&self) -> &'hir Mod<'hir> { + let ItemKind::Mod(m) = self.kind else { unreachable!() }; + m + } + + /// Expect an [`ItemKind::ForeignMod`] or panic. + #[track_caller] + pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) { + let ItemKind::ForeignMod { abi, items } = self.kind else { unreachable!() }; + (abi, items) + } + + /// Expect an [`ItemKind::GlobalAsm`] or panic. + #[track_caller] + pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> { + let ItemKind::GlobalAsm(asm) = self.kind else { unreachable!() }; + asm + } + + /// Expect an [`ItemKind::TyAlias`] or panic. + #[track_caller] + pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { + let ItemKind::TyAlias(ty, gen) = self.kind else { unreachable!() }; + (ty, gen) + } + + /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. + /// Expect an [`ItemKind::OpaqueTy`] or panic. + #[track_caller] + pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { + let ItemKind::OpaqueTy(ty) = &self.kind else { unreachable!() }; + ty + } + + /// Expect an [`ItemKind::Enum`] or panic. + #[track_caller] + pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) { + let ItemKind::Enum(def, gen) = &self.kind else { unreachable!() }; + (def, gen) + } + + /// Expect an [`ItemKind::Struct`] or panic. + #[track_caller] + pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Struct(data, gen) = &self.kind else { unreachable!() }; + (data, gen) + } + + /// A union definition, e.g., `union Foo {x: A, y: B}`. + /// Expect an [`ItemKind::Union`] or panic. + #[track_caller] + pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Union(data, gen) = &self.kind else { unreachable!() }; + (data, gen) + } + + /// Expect an [`ItemKind::Trait`] or panic. + #[track_caller] + pub fn expect_trait( + self, + ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) { + let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { unreachable!() }; + (is_auto, unsafety, gen, bounds, items) + } + + /// Expect an [`ItemKind::TraitAlias`] or panic. + #[track_caller] + pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) { + let ItemKind::TraitAlias(gen, bounds) = self.kind else { unreachable!() }; + (gen, bounds) + } + + /// Expect an [`ItemKind::Impl`] or panic. + #[track_caller] + pub fn expect_impl(&self) -> &'hir Impl<'hir> { + let ItemKind::Impl(imp) = self.kind else { unreachable!() }; + imp + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -3590,6 +3753,180 @@ pub fn fn_kind(self) -> Option> { pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> { if let Node::Ctor(&VariantData::Tuple(fields, _, _)) = self { Some(fields) } else { None } } + + /// Expect a [`Node::Param`] or panic. + #[track_caller] + pub fn expect_param(self) -> &'hir Param<'hir> { + let Node::Param(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Item`] or panic. + #[track_caller] + pub fn expect_item(self) -> &'hir Item<'hir> { + let Node::Item(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::ForeignItem`] or panic. + #[track_caller] + pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> { + let Node::ForeignItem(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::TraitItem`] or panic. + #[track_caller] + pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> { + let Node::TraitItem(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::ImplItem`] or panic. + #[track_caller] + pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> { + let Node::ImplItem(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Variant`] or panic. + #[track_caller] + pub fn expect_variant(self) -> &'hir Variant<'hir> { + let Node::Variant(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Field`] or panic. + #[track_caller] + pub fn expect_field(self) -> &'hir FieldDef<'hir> { + let Node::Field(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::AnonConst`] or panic. + #[track_caller] + pub fn expect_anon_const(self) -> &'hir AnonConst { + let Node::AnonConst(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Expr`] or panic. + #[track_caller] + pub fn expect_expr(self) -> &'hir Expr<'hir> { + let Node::Expr(this) = self else { unreachable!() }; + this + } + /// Expect a [`Node::ExprField`] or panic. + #[track_caller] + pub fn expect_expr_field(self) -> &'hir ExprField<'hir> { + let Node::ExprField(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Stmt`] or panic. + #[track_caller] + pub fn expect_stmt(self) -> &'hir Stmt<'hir> { + let Node::Stmt(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::PathSegment`] or panic. + #[track_caller] + pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> { + let Node::PathSegment(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Ty`] or panic. + #[track_caller] + pub fn expect_ty(self) -> &'hir Ty<'hir> { + let Node::Ty(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::TypeBinding`] or panic. + #[track_caller] + pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> { + let Node::TypeBinding(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::TraitRef`] or panic. + #[track_caller] + pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> { + let Node::TraitRef(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Pat`] or panic. + #[track_caller] + pub fn expect_pat(self) -> &'hir Pat<'hir> { + let Node::Pat(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::PatField`] or panic. + #[track_caller] + pub fn expect_pat_field(self) -> &'hir PatField<'hir> { + let Node::PatField(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Arm`] or panic. + #[track_caller] + pub fn expect_arm(self) -> &'hir Arm<'hir> { + let Node::Arm(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Block`] or panic. + #[track_caller] + pub fn expect_block(self) -> &'hir Block<'hir> { + let Node::Block(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Local`] or panic. + #[track_caller] + pub fn expect_local(self) -> &'hir Local<'hir> { + let Node::Local(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Ctor`] or panic. + #[track_caller] + pub fn expect_ctor(self) -> &'hir VariantData<'hir> { + let Node::Ctor(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Lifetime`] or panic. + #[track_caller] + pub fn expect_lifetime(self) -> &'hir Lifetime { + let Node::Lifetime(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::GenericParam`] or panic. + #[track_caller] + pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> { + let Node::GenericParam(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Crate`] or panic. + #[track_caller] + pub fn expect_crate(self) -> &'hir Mod<'hir> { + let Node::Crate(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Infer`] or panic. + #[track_caller] + pub fn expect_infer(self) -> &'hir InferArg { + let Node::Infer(this) = self else { unreachable!() }; + this + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6435b05cef8..1b7509d6d42 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -3124,8 +3124,7 @@ fn suggest_trait_fn_ty_for_impl_fn_infer( let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) = hir.get(fn_hir_id) else { return None }; - let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) = - hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") }; + let i = hir.get_parent(fn_hir_id).expect_item().expect_impl(); let trait_ref = self.instantiate_mono_trait_ref( i.of_trait.as_ref()?, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index cfebcceef3c..53f5cb2cc9a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; -use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; +use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -916,7 +916,7 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box`, the // span points only at the type `Box, but we want to cover the whole // argument pattern and type. - let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") }; + let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx .hir() .body_param_names(body) @@ -1078,12 +1078,12 @@ fn extract_spans_for_error_reporting<'tcx>( ) -> (Span, Option) { let tcx = infcx.tcx; let mut impl_args = { - let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }; let trait_args = trait_m.def_id.as_local().map(|def_id| { - let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) }; + let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }); @@ -1356,7 +1356,7 @@ fn compare_number_of_method_arguments<'tcx>( .def_id .as_local() .and_then(|def_id| { - let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) }; + let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn(); let pos = trait_number_args.saturating_sub(1); trait_m_sig.decl.inputs.get(pos).map(|arg| { if pos == 0 { @@ -1368,7 +1368,7 @@ fn compare_number_of_method_arguments<'tcx>( }) .or(trait_item_span); - let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let pos = impl_number_args.saturating_sub(1); let impl_span = impl_m_sig .decl @@ -1704,7 +1704,7 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") }; + let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); cause.span = ty.span; let mut diag = struct_span_err!( @@ -1717,7 +1717,7 @@ pub(super) fn compare_impl_const_raw( let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { // Add a label to the Span containing just the type of the const - let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") }; + let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); ty.span }); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 11237afe8a0..dd8ecd670cb 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1053,8 +1053,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // All field types must be well-formed. for field in &variant.fields { let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_wf_obligation( hir_ty.span, @@ -1087,8 +1087,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_bound( traits::ObligationCause::new( diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 55de68f83f2..cd63235857b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -54,7 +54,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => {} } - let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") }; + let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span }); } diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index fe6119dce87..c6b16171311 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -3,15 +3,13 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = item.expect_impl(); if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let trait_ref = trait_ref.subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c17778ce8bc..1cbface0742 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1342,8 +1342,7 @@ fn suggest_impl_trait<'tcx>( fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option>> { let icx = ItemCtxt::new(tcx, def_id); - let item = tcx.hir().expect_item(def_id.expect_local()); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl(); impl_ .of_trait .as_ref() From a4aebf030e32d67e72db8b52be74fb6223a3006f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 05:50:06 +0000 Subject: [PATCH 2/4] Improve ICE messages for `*::expect_*` --- compiler/rustc_hir/src/hir.rs | 118 ++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4640317ac73..ef4a8754ac2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2277,23 +2277,28 @@ pub fn trait_item_id(&self) -> TraitItemId { /// Expect an [`TraitItemKind::Const`] or panic. #[track_caller] pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option) { - let TraitItemKind::Const(ty, body) = self.kind else { unreachable!() }; + let TraitItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; (ty, body) } /// Expect an [`TraitItemKind::Fn`] or panic. #[track_caller] pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { - let TraitItemKind::Fn(ty, trfn) = &self.kind else { unreachable!() }; + let TraitItemKind::Fn(ty, trfn) = &self.kind else { self.expect_failed("a function") }; (ty, trfn) } /// Expect an [`TraitItemKind::ExternCrate`] or panic. #[track_caller] pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { - let TraitItemKind::Type(bounds, ty) = self.kind else { unreachable!() }; + let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") }; (bounds, ty) } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents a trait method's body (or just argument names). @@ -2360,23 +2365,28 @@ pub fn impl_item_id(&self) -> ImplItemId { /// Expect an [`ImplItemKind::Const`] or panic. #[track_caller] pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { - let ImplItemKind::Const(ty, body) = self.kind else { unreachable!() }; + let ImplItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; (ty, body) } /// Expect an [`ImplItemKind::Fn`] or panic. #[track_caller] pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) { - let ImplItemKind::Fn(ty, body) = &self.kind else { unreachable!() }; + let ImplItemKind::Fn(ty, body) = &self.kind else { self.expect_failed("a function") }; (ty, *body) } - /// Expect an [`ImplItemKind::ExternCrate`] or panic. + /// Expect an [`ImplItemKind::Type`] or panic. #[track_caller] pub fn expect_type(&self) -> &'hir Ty<'hir> { - let ImplItemKind::Type(ty) = self.kind else { unreachable!() }; + let ImplItemKind::Type(ty) = self.kind else { self.expect_failed("a type") }; ty } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents various kinds of content within an `impl`. @@ -3051,68 +3061,68 @@ pub fn item_id(&self) -> ItemId { /// Expect an [`ItemKind::ExternCrate`] or panic. #[track_caller] pub fn expect_extern_crate(&self) -> Option { - let ItemKind::ExternCrate(s) = self.kind else { unreachable!() }; + let ItemKind::ExternCrate(s) = self.kind else { self.expect_failed("an extern crate") }; s } /// Expect an [`ItemKind::Use`] or panic. #[track_caller] pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) { - let ItemKind::Use(p, uk) = self.kind else { unreachable!() }; + let ItemKind::Use(p, uk) = self.kind else { self.expect_failed("a use") }; (p, uk) } /// Expect an [`ItemKind::Static`] or panic. #[track_caller] pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) { - let ItemKind::Static(ty, mutbl, body) = self.kind else { unreachable!() }; + let ItemKind::Static(ty, mutbl, body) = self.kind else { self.expect_failed("a static") }; (ty, mutbl, body) } /// Expect an [`ItemKind::Const`] or panic. #[track_caller] pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { - let ItemKind::Const(ty, body) = self.kind else { unreachable!() }; + let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; (ty, body) } /// Expect an [`ItemKind::Fn`] or panic. #[track_caller] pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) { - let ItemKind::Fn(sig, gen, body) = &self.kind else { unreachable!() }; + let ItemKind::Fn(sig, gen, body) = &self.kind else { self.expect_failed("a function") }; (sig, gen, *body) } /// Expect an [`ItemKind::Macro`] or panic. #[track_caller] pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) { - let ItemKind::Macro(def, mk) = &self.kind else { unreachable!() }; + let ItemKind::Macro(def, mk) = &self.kind else { self.expect_failed("a macro") }; (def, *mk) } /// Expect an [`ItemKind::Mod`] or panic. #[track_caller] pub fn expect_mod(&self) -> &'hir Mod<'hir> { - let ItemKind::Mod(m) = self.kind else { unreachable!() }; + let ItemKind::Mod(m) = self.kind else { self.expect_failed("a module") }; m } /// Expect an [`ItemKind::ForeignMod`] or panic. #[track_caller] pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) { - let ItemKind::ForeignMod { abi, items } = self.kind else { unreachable!() }; + let ItemKind::ForeignMod { abi, items } = self.kind else { self.expect_failed("a foreign module") }; (abi, items) } /// Expect an [`ItemKind::GlobalAsm`] or panic. #[track_caller] pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> { - let ItemKind::GlobalAsm(asm) = self.kind else { unreachable!() }; + let ItemKind::GlobalAsm(asm) = self.kind else { self.expect_failed("a global asm") }; asm } /// Expect an [`ItemKind::TyAlias`] or panic. #[track_caller] pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { - let ItemKind::TyAlias(ty, gen) = self.kind else { unreachable!() }; + let ItemKind::TyAlias(ty, gen) = self.kind else { self.expect_failed("a type alias") }; (ty, gen) } @@ -3120,21 +3130,21 @@ pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { /// Expect an [`ItemKind::OpaqueTy`] or panic. #[track_caller] pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { - let ItemKind::OpaqueTy(ty) = &self.kind else { unreachable!() }; + let ItemKind::OpaqueTy(ty) = &self.kind else { self.expect_failed("an opaque type") }; ty } /// Expect an [`ItemKind::Enum`] or panic. #[track_caller] pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) { - let ItemKind::Enum(def, gen) = &self.kind else { unreachable!() }; + let ItemKind::Enum(def, gen) = &self.kind else { self.expect_failed("an enum") }; (def, gen) } /// Expect an [`ItemKind::Struct`] or panic. #[track_caller] pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { - let ItemKind::Struct(data, gen) = &self.kind else { unreachable!() }; + let ItemKind::Struct(data, gen) = &self.kind else { self.expect_failed("a struct") }; (data, gen) } @@ -3142,7 +3152,7 @@ pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { /// Expect an [`ItemKind::Union`] or panic. #[track_caller] pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { - let ItemKind::Union(data, gen) = &self.kind else { unreachable!() }; + let ItemKind::Union(data, gen) = &self.kind else { self.expect_failed("a union") }; (data, gen) } @@ -3151,23 +3161,28 @@ pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { pub fn expect_trait( self, ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) { - let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { unreachable!() }; + let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { self.expect_failed("a trait") }; (is_auto, unsafety, gen, bounds, items) } /// Expect an [`ItemKind::TraitAlias`] or panic. #[track_caller] pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) { - let ItemKind::TraitAlias(gen, bounds) = self.kind else { unreachable!() }; + let ItemKind::TraitAlias(gen, bounds) = self.kind else { self.expect_failed("a trait alias") }; (gen, bounds) } /// Expect an [`ItemKind::Impl`] or panic. #[track_caller] pub fn expect_impl(&self) -> &'hir Impl<'hir> { - let ItemKind::Impl(imp) = self.kind else { unreachable!() }; + let ItemKind::Impl(imp) = self.kind else { self.expect_failed("an impl") }; imp } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -3757,176 +3772,181 @@ pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> { /// Expect a [`Node::Param`] or panic. #[track_caller] pub fn expect_param(self) -> &'hir Param<'hir> { - let Node::Param(this) = self else { unreachable!() }; + let Node::Param(this) = self else { self.expect_failed("a parameter") }; this } /// Expect a [`Node::Item`] or panic. #[track_caller] pub fn expect_item(self) -> &'hir Item<'hir> { - let Node::Item(this) = self else { unreachable!() }; + let Node::Item(this) = self else { self.expect_failed("a item") }; this } /// Expect a [`Node::ForeignItem`] or panic. #[track_caller] pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> { - let Node::ForeignItem(this) = self else { unreachable!() }; + let Node::ForeignItem(this) = self else { self.expect_failed("a foreign item") }; this } /// Expect a [`Node::TraitItem`] or panic. #[track_caller] pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> { - let Node::TraitItem(this) = self else { unreachable!() }; + let Node::TraitItem(this) = self else { self.expect_failed("a trait item") }; this } /// Expect a [`Node::ImplItem`] or panic. #[track_caller] pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> { - let Node::ImplItem(this) = self else { unreachable!() }; + let Node::ImplItem(this) = self else { self.expect_failed("an implementation item") }; this } /// Expect a [`Node::Variant`] or panic. #[track_caller] pub fn expect_variant(self) -> &'hir Variant<'hir> { - let Node::Variant(this) = self else { unreachable!() }; + let Node::Variant(this) = self else { self.expect_failed("a variant") }; this } /// Expect a [`Node::Field`] or panic. #[track_caller] pub fn expect_field(self) -> &'hir FieldDef<'hir> { - let Node::Field(this) = self else { unreachable!() }; + let Node::Field(this) = self else { self.expect_failed("a field definition") }; this } /// Expect a [`Node::AnonConst`] or panic. #[track_caller] pub fn expect_anon_const(self) -> &'hir AnonConst { - let Node::AnonConst(this) = self else { unreachable!() }; + let Node::AnonConst(this) = self else { self.expect_failed("an anonymous constant") }; this } /// Expect a [`Node::Expr`] or panic. #[track_caller] pub fn expect_expr(self) -> &'hir Expr<'hir> { - let Node::Expr(this) = self else { unreachable!() }; + let Node::Expr(this) = self else { self.expect_failed("an expression") }; this } /// Expect a [`Node::ExprField`] or panic. #[track_caller] pub fn expect_expr_field(self) -> &'hir ExprField<'hir> { - let Node::ExprField(this) = self else { unreachable!() }; + let Node::ExprField(this) = self else { self.expect_failed("an expression field") }; this } /// Expect a [`Node::Stmt`] or panic. #[track_caller] pub fn expect_stmt(self) -> &'hir Stmt<'hir> { - let Node::Stmt(this) = self else { unreachable!() }; + let Node::Stmt(this) = self else { self.expect_failed("a statement") }; this } /// Expect a [`Node::PathSegment`] or panic. #[track_caller] pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> { - let Node::PathSegment(this) = self else { unreachable!() }; + let Node::PathSegment(this) = self else { self.expect_failed("a path segment") }; this } /// Expect a [`Node::Ty`] or panic. #[track_caller] pub fn expect_ty(self) -> &'hir Ty<'hir> { - let Node::Ty(this) = self else { unreachable!() }; + let Node::Ty(this) = self else { self.expect_failed("a type") }; this } /// Expect a [`Node::TypeBinding`] or panic. #[track_caller] pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> { - let Node::TypeBinding(this) = self else { unreachable!() }; + let Node::TypeBinding(this) = self else { self.expect_failed("a type binding") }; this } /// Expect a [`Node::TraitRef`] or panic. #[track_caller] pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> { - let Node::TraitRef(this) = self else { unreachable!() }; + let Node::TraitRef(this) = self else { self.expect_failed("a trait reference") }; this } /// Expect a [`Node::Pat`] or panic. #[track_caller] pub fn expect_pat(self) -> &'hir Pat<'hir> { - let Node::Pat(this) = self else { unreachable!() }; + let Node::Pat(this) = self else { self.expect_failed("a pattern") }; this } /// Expect a [`Node::PatField`] or panic. #[track_caller] pub fn expect_pat_field(self) -> &'hir PatField<'hir> { - let Node::PatField(this) = self else { unreachable!() }; + let Node::PatField(this) = self else { self.expect_failed("a pattern field") }; this } /// Expect a [`Node::Arm`] or panic. #[track_caller] pub fn expect_arm(self) -> &'hir Arm<'hir> { - let Node::Arm(this) = self else { unreachable!() }; + let Node::Arm(this) = self else { self.expect_failed("an arm") }; this } /// Expect a [`Node::Block`] or panic. #[track_caller] pub fn expect_block(self) -> &'hir Block<'hir> { - let Node::Block(this) = self else { unreachable!() }; + let Node::Block(this) = self else { self.expect_failed("a block") }; this } /// Expect a [`Node::Local`] or panic. #[track_caller] pub fn expect_local(self) -> &'hir Local<'hir> { - let Node::Local(this) = self else { unreachable!() }; + let Node::Local(this) = self else { self.expect_failed("a local") }; this } /// Expect a [`Node::Ctor`] or panic. #[track_caller] pub fn expect_ctor(self) -> &'hir VariantData<'hir> { - let Node::Ctor(this) = self else { unreachable!() }; + let Node::Ctor(this) = self else { self.expect_failed("a constructor") }; this } /// Expect a [`Node::Lifetime`] or panic. #[track_caller] pub fn expect_lifetime(self) -> &'hir Lifetime { - let Node::Lifetime(this) = self else { unreachable!() }; + let Node::Lifetime(this) = self else { self.expect_failed("a lifetime") }; this } /// Expect a [`Node::GenericParam`] or panic. #[track_caller] pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> { - let Node::GenericParam(this) = self else { unreachable!() }; + let Node::GenericParam(this) = self else { self.expect_failed("a generic parameter") }; this } /// Expect a [`Node::Crate`] or panic. #[track_caller] pub fn expect_crate(self) -> &'hir Mod<'hir> { - let Node::Crate(this) = self else { unreachable!() }; + let Node::Crate(this) = self else { self.expect_failed("a crate") }; this } /// Expect a [`Node::Infer`] or panic. #[track_caller] pub fn expect_infer(self) -> &'hir InferArg { - let Node::Infer(this) = self else { unreachable!() }; + let Node::Infer(this) = self else { self.expect_failed("an infer") }; this } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} node, found {self:?}") + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. From b2ef837b6c52d1cb0977c7fc1e62af5ee546827e Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 05:50:37 +0000 Subject: [PATCH 3/4] Use `expect_{use,fn}` in a couple of places --- compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 2 +- compiler/rustc_hir_analysis/src/check_unused.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 53f5cb2cc9a..92a96d71358 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1504,7 +1504,7 @@ fn compare_synthetic_generics<'tcx>( let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; let impl_m = tcx.hir().expect_impl_item(impl_m); - let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() }; + let (sig, _) = impl_m.expect_fn(); let input_tys = sig.decl.inputs; struct Visitor(Option, hir::def_id::LocalDefId); diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index ebb78213a63..5716be4f1a9 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -29,7 +29,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if item.span.is_dummy() { continue; } - let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; + let (path, _) = item.expect_use(); let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet) } else { From 883145f75d105abc32911f536738f66d74d32f4f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 05:55:20 +0000 Subject: [PATCH 4/4] fix `TraitItemKind::expect_type` docs --- compiler/rustc_hir/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ef4a8754ac2..95422f74120 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2288,7 +2288,7 @@ pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { (ty, trfn) } - /// Expect an [`TraitItemKind::ExternCrate`] or panic. + /// Expect an [`TraitItemKind::Type`] or panic. #[track_caller] pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") };