Skip to content

Commit 0f7174a

Browse files
committed
Re-use the deref-pattern recursion instead of duplicating the logic
1 parent 2304917 commit 0f7174a

File tree

1 file changed

+26
-59
lines changed

1 file changed

+26
-59
lines changed

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

+26-59
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,15 @@ impl<'tcx> ConstToPat<'tcx> {
359359
def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx(), substs)),
360360
))?,
361361
},
362+
ty::Slice(elem_ty) => PatKind::Slice {
363+
prefix: cv
364+
.unwrap_branch()
365+
.iter()
366+
.map(|val| self.recur(*val, *elem_ty, false))
367+
.collect::<Result<_, _>>()?,
368+
slice: None,
369+
suffix: Box::new([]),
370+
},
362371
ty::Array(elem_ty, _) => PatKind::Array {
363372
prefix: cv
364373
.unwrap_branch()
@@ -372,70 +381,16 @@ impl<'tcx> ConstToPat<'tcx> {
372381
// `&str` is represented as a valtree, let's keep using this
373382
// optimization for now.
374383
ty::Str => PatKind::Constant { value: mir::ConstantKind::Ty(tcx.mk_const(cv, ty)) },
375-
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
376-
// matching against references, you can only use byte string literals.
377-
// The typechecker has a special case for byte string literals, by treating them
378-
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
379-
// has no negative effects on pattern matching, even if we're actually matching on
380-
// arrays.
381-
ty::Array(elem_ty, _) if !self.treat_byte_string_as_slice => {
382-
let old = self.behind_reference.replace(true);
383-
// References have the same valtree representation as their pointee.
384-
let array = cv;
385-
let val = PatKind::Deref {
386-
subpattern: Box::new(Pat {
387-
kind: PatKind::Array {
388-
prefix: array.unwrap_branch()
389-
.iter()
390-
.map(|val| self.recur(*val, elem_ty, false))
391-
.collect::<Result<_, _>>()?,
392-
slice: None,
393-
suffix: Box::new([]),
394-
},
395-
span,
396-
ty: tcx.mk_slice(elem_ty),
397-
}),
398-
};
399-
self.behind_reference.set(old);
400-
val
401-
}
402-
ty::Array(elem_ty, _) |
403-
// Cannot merge this with the catch all branch below, because the `const_deref`
404-
// changes the type from slice to array, we need to keep the original type in the
405-
// pattern.
406-
ty::Slice(elem_ty) => {
407-
let old = self.behind_reference.replace(true);
408-
// References have the same valtree representation as their pointee.
409-
let array = cv;
410-
let val = PatKind::Deref {
411-
subpattern: Box::new(Pat {
412-
kind: PatKind::Slice {
413-
prefix: array.unwrap_branch()
414-
.iter()
415-
.map(|val| self.recur(*val, elem_ty, false))
416-
.collect::<Result<_, _>>()?,
417-
slice: None,
418-
suffix: Box::new([]),
419-
},
420-
span,
421-
ty: tcx.mk_slice(elem_ty),
422-
}),
423-
};
424-
self.behind_reference.set(old);
425-
val
426-
}
427384
// Backwards compatibility hack: support references to non-structural types,
428385
// but hard error if we aren't behind a double reference. We could just use
429386
// the fallback code path below, but that would allow *more* of this fishy
430387
// code to compile, as then it only goes through the future incompat lint
431388
// instead of a hard error.
432389
ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
433390
if self.behind_reference.get() {
434-
if !self.saw_const_match_error.get()
435-
&& !self.saw_const_match_lint.get()
436-
{
437-
self.saw_const_match_lint.set(true);
438-
tcx.emit_spanned_lint(
391+
if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() {
392+
self.saw_const_match_lint.set(true);
393+
tcx.emit_spanned_lint(
439394
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
440395
self.id,
441396
span,
@@ -456,16 +411,28 @@ impl<'tcx> ConstToPat<'tcx> {
456411
// convert the dereferenced constant to a pattern that is the sub-pattern of the
457412
// deref pattern.
458413
_ => {
459-
if !pointee_ty.is_sized(tcx, param_env) {
414+
if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() {
460415
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
461416
tcx.sess.emit_err(err);
462417

463418
// FIXME: introduce PatKind::Error to silence follow up diagnostics due to unreachable patterns.
464419
PatKind::Wild
465420
} else {
466421
let old = self.behind_reference.replace(true);
422+
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
423+
// matching against references, you can only use byte string literals.
424+
// The typechecker has a special case for byte string literals, by treating them
425+
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
426+
// has no negative effects on pattern matching, even if we're actually matching on
427+
// arrays.
428+
let pointee_ty = match *pointee_ty.kind() {
429+
ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => {
430+
tcx.mk_slice(elem_ty)
431+
}
432+
_ => *pointee_ty,
433+
};
467434
// References have the same valtree representation as their pointee.
468-
let subpattern = self.recur(cv, *pointee_ty, false)?;
435+
let subpattern = self.recur(cv, pointee_ty, false)?;
469436
self.behind_reference.set(old);
470437
PatKind::Deref { subpattern }
471438
}

0 commit comments

Comments
 (0)