1
Fork 0

Make hir::TyKind::TraitObject use tagged ptr

This commit is contained in:
Boxy 2025-01-10 23:20:31 +00:00
parent 3cd8fcbf87
commit 0f10ba60ff
20 changed files with 84 additions and 48 deletions

View file

@ -28,6 +28,7 @@ use rustc_data_structures::packed::Pu128;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_data_structures::tagged_ptr::Tag;
use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_macros::{Decodable, Encodable, HashStable_Generic};
pub use rustc_span::AttrId; pub use rustc_span::AttrId;
use rustc_span::source_map::{Spanned, respan}; use rustc_span::source_map::{Spanned, respan};
@ -2269,10 +2270,32 @@ impl TyKind {
/// Syntax used to declare a trait object. /// Syntax used to declare a trait object.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[repr(u8)]
pub enum TraitObjectSyntax { pub enum TraitObjectSyntax {
Dyn, // SAFETY: When adding new variants make sure to update the `Tag` impl.
DynStar, Dyn = 0,
None, DynStar = 1,
None = 2,
}
/// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means
/// it can be represented with a `u2`. We use `repr(u8)` to guarantee the
/// discriminants of the variants are no greater than `3`.
unsafe impl Tag for TraitObjectSyntax {
const BITS: u32 = 2;
fn into_usize(self) -> usize {
self as u8 as usize
}
unsafe fn from_usize(tag: usize) -> Self {
match tag {
0 => TraitObjectSyntax::Dyn,
1 => TraitObjectSyntax::DynStar,
2 => TraitObjectSyntax::None,
_ => unreachable!(),
}
}
} }
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]

View file

@ -48,6 +48,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
@ -1158,7 +1159,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetime_bound = this.elided_dyn_bound(t.span); let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound) (bounds, lifetime_bound)
}); });
let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None); let kind = hir::TyKind::TraitObject(
bounds,
TaggedRef::new(lifetime_bound, TraitObjectSyntax::None),
);
return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() }; return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
} }
@ -1309,7 +1313,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span)); lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
(bounds, lifetime_bound) (bounds, lifetime_bound)
}); });
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind) hir::TyKind::TraitObject(bounds, TaggedRef::new(lifetime_bound, *kind))
} }
TyKind::ImplTrait(def_node_id, bounds) => { TyKind::ImplTrait(def_node_id, bounds) => {
let span = t.span; let span = t.span;
@ -2365,8 +2369,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir_id = self.next_id(); hir_id = self.next_id();
hir::TyKind::TraitObject( hir::TyKind::TraitObject(
arena_vec![self; principal], arena_vec![self; principal],
self.elided_dyn_bound(span), TaggedRef::new(self.elided_dyn_bound(span), TraitObjectSyntax::None),
TraitObjectSyntax::None,
) )
} }
_ => hir::TyKind::Path(hir::QPath::Resolved(None, path)), _ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),

View file

@ -887,7 +887,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if alias_ty.span.desugaring_kind().is_some() { if alias_ty.span.desugaring_kind().is_some() {
// Skip `async` desugaring `impl Future`. // Skip `async` desugaring `impl Future`.
} }
if let TyKind::TraitObject(_, lt, _) = alias_ty.kind { if let TyKind::TraitObject(_, lt) = alias_ty.kind {
if lt.ident.name == kw::Empty { if lt.ident.name == kw::Empty {
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
} else { } else {

View file

@ -15,6 +15,7 @@ pub use rustc_ast::{
}; };
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
@ -764,11 +765,8 @@ impl<'hir> Generics<'hir> {
&& let [.., segment] = trait_ref.path.segments && let [.., segment] = trait_ref.path.segments
&& let Some(ret_ty) = segment.args().paren_sugar_output() && let Some(ret_ty) = segment.args().paren_sugar_output()
&& let ret_ty = ret_ty.peel_refs() && let ret_ty = ret_ty.peel_refs()
&& let TyKind::TraitObject( && let TyKind::TraitObject(_, tagged_ptr) = ret_ty.kind
_, && let TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar = tagged_ptr.tag()
_,
TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar,
) = ret_ty.kind
&& ret_ty.span.can_be_used_for_suggestions() && ret_ty.span.can_be_used_for_suggestions()
{ {
Some(ret_ty.span) Some(ret_ty.span)
@ -3230,7 +3228,10 @@ pub enum TyKind<'hir> {
TraitAscription(GenericBounds<'hir>), TraitAscription(GenericBounds<'hir>),
/// A trait object type `Bound1 + Bound2 + Bound3` /// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime. /// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), ///
/// We use pointer tagging to represent a `&'hir Lifetime` and `TraitObjectSyntax` pair
/// as otherwise this type being `repr(C)` would result in `TyKind` increasing in size.
TraitObject(&'hir [PolyTraitRef<'hir>], TaggedRef<'hir, Lifetime, TraitObjectSyntax>),
/// Unused for now. /// Unused for now.
Typeof(&'hir AnonConst), Typeof(&'hir AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been /// `TyKind::Infer` means the type should be inferred instead of it having been

View file

@ -922,7 +922,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_const_arg(length)); try_visit!(visitor.visit_const_arg(length));
} }
TyKind::TraitObject(bounds, ref lifetime, _syntax) => { TyKind::TraitObject(bounds, ref lifetime) => {
for bound in bounds { for bound in bounds {
try_visit!(visitor.visit_poly_trait_ref(bound)); try_visit!(visitor.visit_poly_trait_ref(bound));
} }

View file

@ -810,7 +810,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
intravisit::walk_ty(this, ty); intravisit::walk_ty(this, ty);
}); });
} }
hir::TyKind::TraitObject(bounds, lifetime, _) => { hir::TyKind::TraitObject(bounds, lifetime) => {
let lifetime = lifetime.pointer();
debug!(?bounds, ?lifetime, "TraitObject"); debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope }; let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| { self.with(scope, |this| {
@ -827,7 +829,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// use the object lifetime defaulting // use the object lifetime defaulting
// rules. So e.g., `Box<dyn Debug>` becomes // rules. So e.g., `Box<dyn Debug>` becomes
// `Box<dyn Debug + 'static>`. // `Box<dyn Debug + 'static>`.
self.resolve_object_lifetime_default(lifetime) self.resolve_object_lifetime_default(&*lifetime)
} }
LifetimeName::Infer => { LifetimeName::Infer => {
// If the user writes `'_`, we use the *ordinary* elision // If the user writes `'_`, we use the *ordinary* elision
@ -838,7 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
} }
LifetimeName::Param(..) | LifetimeName::Static => { LifetimeName::Param(..) | LifetimeName::Static => {
// If the user wrote an explicit name, use that. // If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime); self.visit_lifetime(&*lifetime);
} }
LifetimeName::Error => {} LifetimeName::Error => {}
} }

View file

@ -23,9 +23,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Option<ErrorGuaranteed> { ) -> Option<ErrorGuaranteed> {
let tcx = self.tcx(); let tcx = self.tcx();
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = let poly_trait_ref = if let hir::TyKind::TraitObject([poly_trait_ref, ..], tagged_ptr) =
self_ty.kind self_ty.kind
else { && let TraitObjectSyntax::None = tagged_ptr.tag()
{
poly_trait_ref
} else {
return None; return None;
}; };
@ -294,7 +297,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let (dyn_str, paren_dyn_str) = let (dyn_str, paren_dyn_str) =
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") }; if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind { let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind {
// There are more than one trait bound, we need surrounding parentheses. // There are more than one trait bound, we need surrounding parentheses.
vec![ vec![
(self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()), (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),

View file

@ -2311,7 +2311,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.late_bound_vars(hir_ty.hir_id), tcx.late_bound_vars(hir_ty.hir_id),
), ),
), ),
hir::TyKind::TraitObject(bounds, lifetime, repr) => { hir::TyKind::TraitObject(bounds, tagged_ptr) => {
let lifetime = tagged_ptr.pointer();
let repr = tagged_ptr.tag();
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) { if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
// Don't continue with type analysis if the `dyn` keyword is missing // Don't continue with type analysis if the `dyn` keyword is missing
// It generates confusing errors, especially if the user meant to use another // It generates confusing errors, especially if the user meant to use another

View file

@ -402,7 +402,8 @@ impl<'a> State<'a> {
self.print_bounds("impl", bounds); self.print_bounds("impl", bounds);
} }
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false), hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
hir::TyKind::TraitObject(bounds, lifetime, syntax) => { hir::TyKind::TraitObject(bounds, lifetime) => {
let syntax = lifetime.tag();
match syntax { match syntax {
ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"), ast::TraitObjectSyntax::Dyn => self.word_nbsp("dyn"),
ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"), ast::TraitObjectSyntax::DynStar => self.word_nbsp("dyn*"),
@ -421,7 +422,7 @@ impl<'a> State<'a> {
if !lifetime.is_elided() { if !lifetime.is_elided() {
self.nbsp(); self.nbsp();
self.word_space("+"); self.word_space("+");
self.print_lifetime(lifetime); self.print_lifetime(lifetime.pointer());
} }
} }
hir::TyKind::Array(ty, ref length) => { hir::TyKind::Array(ty, ref length) => {

View file

@ -111,7 +111,9 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
} }
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; let hir::TyKind::TraitObject(bounds, _lifetime_and_syntax_pointer) = &ty.kind else {
return;
};
for bound in &bounds[..] { for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id(); let def_id = bound.trait_ref.trait_def_id();
if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) { if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) {

View file

@ -572,16 +572,16 @@ pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
match ty.kind { match ty.kind {
hir::TyKind::TraitObject( hir::TyKind::TraitObject(_, tagged_ptr)
_, if let hir::Lifetime {
hir::Lifetime {
res: res:
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
.. ..
}, } = tagged_ptr.pointer() =>
_, {
) self.0.push(ty)
| hir::TyKind::OpaqueDef(..) => self.0.push(ty), }
hir::TyKind::OpaqueDef(..) => self.0.push(ty),
_ => {} _ => {}
} }
hir::intravisit::walk_ty(self, ty); hir::intravisit::walk_ty(self, ty);

View file

@ -374,7 +374,7 @@ pub fn suggest_new_region_bound(
} }
} }
} }
TyKind::TraitObject(_, lt, _) => { TyKind::TraitObject(_, lt) => {
if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res { if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
err.span_suggestion_verbose( err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(), fn_return.span.shrink_to_hi(),
@ -592,11 +592,9 @@ pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec<Span>, pub DefId);
impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
if let TyKind::TraitObject( if let TyKind::TraitObject(poly_trait_refs, lifetime_ptr) = t.kind
poly_trait_refs, && let Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. } =
Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. }, lifetime_ptr.pointer()
_,
) = t.kind
{ {
for ptr in poly_trait_refs { for ptr in poly_trait_refs {
if Some(self.1) == ptr.trait_ref.trait_def_id() { if Some(self.1) == ptr.trait_ref.trait_def_id() {

View file

@ -580,8 +580,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.tcx.hir_node_by_def_id(obligation.cause.body_id) self.tcx.hir_node_by_def_id(obligation.cause.body_id)
&& let hir::ItemKind::Impl(impl_) = item.kind && let hir::ItemKind::Impl(impl_) = item.kind
&& let None = impl_.of_trait && let None = impl_.of_trait
&& let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind && let hir::TyKind::TraitObject(_, tagged_ptr) = impl_.self_ty.kind
&& let TraitObjectSyntax::None = syntax && let TraitObjectSyntax::None = tagged_ptr.tag()
&& impl_.self_ty.span.edition().at_least_rust_2021() && impl_.self_ty.span.edition().at_least_rust_2021()
{ {
// Silence the dyn-compatibility error in favor of the missing dyn on // Silence the dyn-compatibility error in favor of the missing dyn on

View file

@ -3074,7 +3074,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
} }
if let Some(ty) = ty { if let Some(ty) = ty {
match ty.kind { match ty.kind {
hir::TyKind::TraitObject(traits, _, _) => { hir::TyKind::TraitObject(traits, _) => {
let (span, kw) = match traits { let (span, kw) = match traits {
[first, ..] if first.span.lo() == ty.span.lo() => { [first, ..] if first.span.lo() == ty.span.lo() => {
// Missing `dyn` in front of trait object. // Missing `dyn` in front of trait object.

View file

@ -1843,10 +1843,10 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
} }
TyKind::Path(_) => clean_qpath(ty, cx), TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, lifetime, _) => { TyKind::TraitObject(bounds, lifetime) => {
let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect(); let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
let lifetime = let lifetime =
if !lifetime.is_elided() { Some(clean_lifetime(lifetime, cx)) } else { None }; if !lifetime.is_elided() { Some(clean_lifetime(lifetime.pointer(), cx)) } else { None };
DynTrait(bounds, lifetime) DynTrait(bounds, lifetime)
} }
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),

View file

@ -433,7 +433,7 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
sub_visitor.visit_fn_decl(decl); sub_visitor.visit_fn_decl(decl);
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts()); self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
}, },
TyKind::TraitObject(bounds, lt, _) => { TyKind::TraitObject(bounds, lt) => {
if !lt.is_elided() { if !lt.is_elided() {
self.unelided_trait_object_lifetime = true; self.unelided_trait_object_lifetime = true;
} }

View file

@ -47,7 +47,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
// Originally reported as the issue #3128. // Originally reported as the issue #3128.
let inner_snippet = snippet(cx, inner.span, ".."); let inner_snippet = snippet(cx, inner.span, "..");
let suggestion = match &inner.kind { let suggestion = match &inner.kind {
TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => { TyKind::TraitObject(bounds, lt_bound) if bounds.len() > 1 || !lt_bound.is_elided() => {
format!("&{ltopt}({inner_snippet})") format!("&{ltopt}({inner_snippet})")
}, },
TyKind::Path(qpath) TyKind::Path(qpath)

View file

@ -52,7 +52,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
// function types bring a lot of overhead // function types bring a lot of overhead
TyKind::BareFn(bare) if bare.abi == Abi::Rust => (50 * self.nest, 1), TyKind::BareFn(bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
TyKind::TraitObject(param_bounds, _, _) => { TyKind::TraitObject(param_bounds, _) => {
let has_lifetime_parameters = param_bounds.iter().any(|bound| { let has_lifetime_parameters = param_bounds.iter().any(|bound| {
bound bound
.bound_generic_params .bound_generic_params

View file

@ -400,7 +400,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")), TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
TyKind::Path(qpath) => qpath_search_pat(&qpath), TyKind::Path(qpath) => qpath_search_pat(&qpath),
TyKind::Infer => (Pat::Str("_"), Pat::Str("_")), TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
TyKind::TraitObject(_, _, TraitObjectSyntax::Dyn) => (Pat::Str("dyn"), Pat::Str("")), TyKind::TraitObject(_, tagged_ptr) if let TraitObjectSyntax::Dyn = tagged_ptr.tag() => (Pat::Str("dyn"), Pat::Str("")),
// NOTE: `TraitObject` is incomplete. It will always return true then. // NOTE: `TraitObject` is incomplete. It will always return true then.
_ => (Pat::Str(""), Pat::Str("")), _ => (Pat::Str(""), Pat::Str("")),
} }

View file

@ -1281,7 +1281,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
} }
}, },
TyKind::Path(qpath) => self.hash_qpath(qpath), TyKind::Path(qpath) => self.hash_qpath(qpath),
TyKind::TraitObject(_, lifetime, _) => { TyKind::TraitObject(_, lifetime) => {
self.hash_lifetime(lifetime); self.hash_lifetime(lifetime);
}, },
TyKind::Typeof(anon_const) => { TyKind::Typeof(anon_const) => {