Rollup merge of #120318 - Nadrieril:share-debug-impl, r=compiler-errors
pattern_analysis: Reuse most of the `DeconstructedPat` `Debug` impl The `DeconstructedPat: Debug` is best-effort because we'd need `tcx` to get things like field names etc. Since rust-analyzer has a similar constraint, this PR moves most the impl to be shared between the two. While I was at it I also fixed a nit in the `IntRange: Debug` impl. r? `@compiler-errors`
This commit is contained in:
commit
a1ecced532
@ -391,12 +391,18 @@ impl IntRange {
|
|||||||
/// first.
|
/// first.
|
||||||
impl fmt::Debug for IntRange {
|
impl fmt::Debug for IntRange {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if let Finite(lo) = self.lo {
|
if self.is_singleton() {
|
||||||
|
// Only finite ranges can be singletons.
|
||||||
|
let Finite(lo) = self.lo else { unreachable!() };
|
||||||
write!(f, "{lo}")?;
|
write!(f, "{lo}")?;
|
||||||
}
|
} else {
|
||||||
write!(f, "{}", RangeEnd::Excluded)?;
|
if let Finite(lo) = self.lo {
|
||||||
if let Finite(hi) = self.hi {
|
write!(f, "{lo}")?;
|
||||||
write!(f, "{hi}")?;
|
}
|
||||||
|
write!(f, "{}", RangeEnd::Excluded)?;
|
||||||
|
if let Finite(hi) = self.hi {
|
||||||
|
write!(f, "{hi}")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -112,8 +112,12 @@ pub trait TypeCx: Sized + fmt::Debug {
|
|||||||
/// This must follow the invariants of `ConstructorSet`
|
/// This must follow the invariants of `ConstructorSet`
|
||||||
fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
|
fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
|
||||||
|
|
||||||
/// Best-effort `Debug` implementation.
|
/// Write the name of the variant represented by `pat`. Used for the best-effort `Debug` impl of
|
||||||
fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
|
/// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`.
|
||||||
|
fn write_variant_name(
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
||||||
|
) -> fmt::Result;
|
||||||
|
|
||||||
/// Raise a bug.
|
/// Raise a bug.
|
||||||
fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
|
fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
|
||||||
|
@ -142,7 +142,75 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
|
|||||||
/// This is best effort and not good enough for a `Display` impl.
|
/// This is best effort and not good enough for a `Display` impl.
|
||||||
impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
|
impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
Cx::debug_pat(f, self)
|
let pat = self;
|
||||||
|
let mut first = true;
|
||||||
|
let mut start_or_continue = |s| {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut start_or_comma = || start_or_continue(", ");
|
||||||
|
|
||||||
|
match pat.ctor() {
|
||||||
|
Struct | Variant(_) | UnionField => {
|
||||||
|
Cx::write_variant_name(f, pat)?;
|
||||||
|
// Without `cx`, we can't know which field corresponds to which, so we can't
|
||||||
|
// get the names of the fields. Instead we just display everything as a tuple
|
||||||
|
// struct, which should be good enough.
|
||||||
|
write!(f, "(")?;
|
||||||
|
for p in pat.iter_fields() {
|
||||||
|
write!(f, "{}", start_or_comma())?;
|
||||||
|
write!(f, "{p:?}")?;
|
||||||
|
}
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
||||||
|
// be careful to detect strings here. However a string literal pattern will never
|
||||||
|
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
||||||
|
Ref => {
|
||||||
|
let subpattern = pat.iter_fields().next().unwrap();
|
||||||
|
write!(f, "&{:?}", subpattern)
|
||||||
|
}
|
||||||
|
Slice(slice) => {
|
||||||
|
let mut subpatterns = pat.iter_fields();
|
||||||
|
write!(f, "[")?;
|
||||||
|
match slice.kind {
|
||||||
|
SliceKind::FixedLen(_) => {
|
||||||
|
for p in subpatterns {
|
||||||
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SliceKind::VarLen(prefix_len, _) => {
|
||||||
|
for p in subpatterns.by_ref().take(prefix_len) {
|
||||||
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
||||||
|
}
|
||||||
|
write!(f, "{}", start_or_comma())?;
|
||||||
|
write!(f, "..")?;
|
||||||
|
for p in subpatterns {
|
||||||
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
Bool(b) => write!(f, "{b}"),
|
||||||
|
// Best-effort, will render signed ranges incorrectly
|
||||||
|
IntRange(range) => write!(f, "{range:?}"),
|
||||||
|
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
||||||
|
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
||||||
|
Str(value) => write!(f, "{value:?}"),
|
||||||
|
Opaque(..) => write!(f, "<constant pattern>"),
|
||||||
|
Or => {
|
||||||
|
for pat in pat.iter_fields() {
|
||||||
|
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,103 +850,6 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
|||||||
|
|
||||||
Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind }
|
Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Best-effort `Debug` implementation.
|
|
||||||
pub(crate) fn debug_pat(
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
let mut first = true;
|
|
||||||
let mut start_or_continue = |s| {
|
|
||||||
if first {
|
|
||||||
first = false;
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
s
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut start_or_comma = || start_or_continue(", ");
|
|
||||||
|
|
||||||
match pat.ctor() {
|
|
||||||
Struct | Variant(_) | UnionField => match pat.ty().kind() {
|
|
||||||
ty::Adt(def, _) if def.is_box() => {
|
|
||||||
// Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
|
|
||||||
// of `std`). So this branch is only reachable when the feature is enabled and
|
|
||||||
// the pattern is a box pattern.
|
|
||||||
let subpattern = pat.iter_fields().next().unwrap();
|
|
||||||
write!(f, "box {subpattern:?}")
|
|
||||||
}
|
|
||||||
ty::Adt(..) | ty::Tuple(..) => {
|
|
||||||
let variant =
|
|
||||||
match pat.ty().kind() {
|
|
||||||
ty::Adt(adt, _) => Some(adt.variant(
|
|
||||||
RustcMatchCheckCtxt::variant_index_for_adt(pat.ctor(), *adt),
|
|
||||||
)),
|
|
||||||
ty::Tuple(_) => None,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(variant) = variant {
|
|
||||||
write!(f, "{}", variant.name)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Without `cx`, we can't know which field corresponds to which, so we can't
|
|
||||||
// get the names of the fields. Instead we just display everything as a tuple
|
|
||||||
// struct, which should be good enough.
|
|
||||||
write!(f, "(")?;
|
|
||||||
for p in pat.iter_fields() {
|
|
||||||
write!(f, "{}", start_or_comma())?;
|
|
||||||
write!(f, "{p:?}")?;
|
|
||||||
}
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
|
||||||
_ => write!(f, "_"),
|
|
||||||
},
|
|
||||||
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
|
||||||
// be careful to detect strings here. However a string literal pattern will never
|
|
||||||
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
|
||||||
Ref => {
|
|
||||||
let subpattern = pat.iter_fields().next().unwrap();
|
|
||||||
write!(f, "&{:?}", subpattern)
|
|
||||||
}
|
|
||||||
Slice(slice) => {
|
|
||||||
let mut subpatterns = pat.iter_fields();
|
|
||||||
write!(f, "[")?;
|
|
||||||
match slice.kind {
|
|
||||||
SliceKind::FixedLen(_) => {
|
|
||||||
for p in subpatterns {
|
|
||||||
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SliceKind::VarLen(prefix_len, _) => {
|
|
||||||
for p in subpatterns.by_ref().take(prefix_len) {
|
|
||||||
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
||||||
}
|
|
||||||
write!(f, "{}", start_or_comma())?;
|
|
||||||
write!(f, "..")?;
|
|
||||||
for p in subpatterns {
|
|
||||||
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
Bool(b) => write!(f, "{b}"),
|
|
||||||
// Best-effort, will render signed ranges incorrectly
|
|
||||||
IntRange(range) => write!(f, "{range:?}"),
|
|
||||||
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
|
||||||
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
|
||||||
Str(value) => write!(f, "{value}"),
|
|
||||||
Opaque(..) => write!(f, "<constant pattern>"),
|
|
||||||
Or => {
|
|
||||||
for pat in pat.iter_fields() {
|
|
||||||
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
@ -978,12 +881,21 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
|||||||
self.ctors_for_ty(*ty)
|
self.ctors_for_ty(*ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_pat(
|
fn write_variant_name(
|
||||||
f: &mut fmt::Formatter<'_>,
|
f: &mut fmt::Formatter<'_>,
|
||||||
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
Self::debug_pat(f, pat)
|
if let ty::Adt(adt, _) = pat.ty().kind() {
|
||||||
|
if adt.is_box() {
|
||||||
|
write!(f, "Box")?
|
||||||
|
} else {
|
||||||
|
let variant = adt.variant(Self::variant_index_for_adt(pat.ctor(), *adt));
|
||||||
|
write!(f, "{}", variant.name)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
|
fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
|
||||||
span_bug!(self.scrut_span, "{}", fmt)
|
span_bug!(self.scrut_span, "{}", fmt)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user