let deref_ty = match *ty.kind() {
ty::Ref(_, deref_ty, _) => deref_ty,
- _ => {
- trace!("non_scalar_compare called on non-reference type: {}", ty);
- // Backcompat hack: due to non-structural matches not being a hard error, we can
- // reach this for types that have manual `Eq` or `PartialEq` impls.
- assert!(!ty.is_structural_eq_shallow(self.hir.tcx()));
- let ref_ty = self.hir.tcx().mk_imm_ref(self.hir.tcx().lifetimes.re_erased, ty);
- // let y = &place;
- let y = self.temp(ref_ty, source_info.span);
- self.cfg.push_assign(
- block,
- source_info,
- y,
- Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, place),
- );
- val = Operand::Move(y);
- // let temp = expect;
- let temp = self.temp(ty, source_info.span);
- self.cfg.push_assign(
- block,
- source_info,
- temp,
- Rvalue::Use(expect),
- );
- // reftemp = &temp;
- let reftemp = self.temp(ref_ty, source_info.span);
- self.cfg.push_assign(
- block,
- source_info,
- reftemp,
- Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, temp),
- );
- expect = Operand::Move(reftemp);
- ty
- },
+ _ => bug!("non_scalar_compare called on non-reference type: {}", ty),
};
let eq_def_id = self.hir.tcx().require_lang_item(LangItem::PartialEq, None);
include_lint_checks: bool,
}
+#[derive(Debug)]
+struct FallbackToConstRef;
+
impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
fn new(
pat_ctxt: &PatCtxt<'_, 'tcx>,
// once indirect_structural_match is a full fledged error, this
// level of indirection can be eliminated
- let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation);
+ let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap();
if self.include_lint_checks && !self.saw_const_match_error.get() {
// If we were able to successfully convert the const to some pat,
}
// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
- fn recur(&self, cv: &'tcx ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> {
+ fn recur(
+ &self,
+ cv: &'tcx ty::Const<'tcx>,
+ mir_structural_match_violation: bool,
+ ) -> Result<Pat<'tcx>, FallbackToConstRef> {
let id = self.id;
let span = self.span;
let tcx = self.tcx();
let param_env = self.param_env;
- let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| {
+ let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| -> Result<_, _> {
vals.iter()
.enumerate()
.map(|(idx, val)| {
let field = Field::new(idx);
- FieldPat { field, pattern: self.recur(val, false) }
+ Ok(FieldPat { field, pattern: self.recur(val, false)? })
})
.collect()
};
|lint| lint.build(&msg).emit(),
);
}
- PatKind::Constant { value: cv }
+ // Since we are behind a reference, we can just bubble the error up so we get a
+ // constant at reference type, making it easy to let the fallback call
+ // `PartialEq::eq` on it.
+ return Err(FallbackToConstRef);
}
ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => {
debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty);
variant_index: destructured
.variant
.expect("destructed const of adt without variant id"),
- subpatterns: field_pats(destructured.fields),
+ subpatterns: field_pats(destructured.fields)?,
}
}
ty::Tuple(_) | ty::Adt(_, _) => {
let destructured = tcx.destructure_const(param_env.and(cv));
- PatKind::Leaf { subpatterns: field_pats(destructured.fields) }
+ PatKind::Leaf { subpatterns: field_pats(destructured.fields)? }
}
ty::Array(..) => PatKind::Array {
prefix: tcx
.fields
.iter()
.map(|val| self.recur(val, false))
- .collect(),
+ .collect::<Result<_, _>>()?,
slice: None,
suffix: Vec::new(),
},
.fields
.iter()
.map(|val| self.recur(val, false))
- .collect(),
+ .collect::<Result<_, _>>()?,
slice: None,
suffix: vec![],
}),
// deref pattern.
_ => {
let old = self.behind_reference.replace(true);
- let val = PatKind::Deref {
- subpattern: self.recur(tcx.deref_const(self.param_env.and(cv)), false),
+ // In case there are structural-match violations somewhere in this subpattern,
+ // we fall back to a const pattern. If we do not do this, we may end up with
+ // a !structural-match constant that is not of reference type, which makes it
+ // very hard to invoke `PartialEq::eq` on it as a fallback.
+ let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
+ Ok(subpattern) => PatKind::Deref { subpattern },
+ Err(FallbackToConstRef) => PatKind::Constant { value: cv },
};
self.behind_reference.set(old);
val
);
}
- Pat { span, ty: cv.ty, kind: Box::new(kind) }
+ Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) })
}
}