Add CustomEq
qualif
This commit is contained in:
parent
0850c3bbb8
commit
6b54829b78
3 changed files with 64 additions and 1 deletions
|
@ -80,6 +80,7 @@ pub struct BorrowCheckResult<'tcx> {
|
||||||
pub struct ConstQualifs {
|
pub struct ConstQualifs {
|
||||||
pub has_mut_interior: bool,
|
pub has_mut_interior: bool,
|
||||||
pub needs_drop: bool,
|
pub needs_drop: bool,
|
||||||
|
pub custom_eq: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// After we borrow check a closure, we are left with various
|
/// After we borrow check a closure, we are left with various
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
//!
|
//!
|
||||||
//! See the `Qualif` trait for more info.
|
//! See the `Qualif` trait for more info.
|
||||||
|
|
||||||
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
|
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
use super::ConstCx;
|
use super::ConstCx;
|
||||||
|
|
||||||
|
@ -12,6 +14,7 @@ pub fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> ConstQualifs
|
||||||
ConstQualifs {
|
ConstQualifs {
|
||||||
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
|
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
|
||||||
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
|
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
|
||||||
|
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +111,39 @@ impl Qualif for NeedsDrop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A constant that cannot be used as part of a pattern in a `match` expression.
|
||||||
|
pub struct CustomEq;
|
||||||
|
|
||||||
|
impl Qualif for CustomEq {
|
||||||
|
const ANALYSIS_NAME: &'static str = "flow_custom_eq";
|
||||||
|
|
||||||
|
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
|
||||||
|
qualifs.custom_eq
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
|
// If *any* component of a composite data type does not implement `Structural{Partial,}Eq`,
|
||||||
|
// we know that at least some values of that type are not structural-match. I say "some"
|
||||||
|
// because that component may be part of an enum variant (e.g.,
|
||||||
|
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
|
||||||
|
// structural-match (`Option::None`).
|
||||||
|
let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
|
||||||
|
traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_adt_inherently(
|
||||||
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
|
adt: &'tcx AdtDef,
|
||||||
|
substs: SubstsRef<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let ty = cx.tcx.mk_ty(ty::Adt(adt, substs));
|
||||||
|
let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
|
||||||
|
cx.tcx
|
||||||
|
.infer_ctxt()
|
||||||
|
.enter(|infcx| !traits::type_marked_structural(id, cx.body.span, &infcx, ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
|
// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
|
||||||
|
|
||||||
/// Returns `true` if this `Rvalue` contains qualif `Q`.
|
/// Returns `true` if this `Rvalue` contains qualif `Q`.
|
||||||
|
|
|
@ -17,7 +17,7 @@ use std::borrow::Cow;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use super::ops::{self, NonConstOp};
|
use super::ops::{self, NonConstOp};
|
||||||
use super::qualifs::{self, HasMutInterior, NeedsDrop};
|
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
|
||||||
use super::resolver::FlowSensitiveAnalysis;
|
use super::resolver::FlowSensitiveAnalysis;
|
||||||
use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif};
|
use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif};
|
||||||
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
|
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
|
||||||
|
@ -142,9 +142,35 @@ impl Qualifs<'mir, 'tcx> {
|
||||||
|
|
||||||
let return_loc = ccx.body.terminator_loc(return_block);
|
let return_loc = ccx.body.terminator_loc(return_block);
|
||||||
|
|
||||||
|
let custom_eq = match ccx.const_kind() {
|
||||||
|
// We don't care whether a `const fn` returns a value that is not structurally
|
||||||
|
// matchable. Functions calls are opaque and always use type-based qualification, so
|
||||||
|
// this value should never be used.
|
||||||
|
ConstKind::ConstFn => true,
|
||||||
|
|
||||||
|
// If we know that all values of the return type are structurally matchable, there's no
|
||||||
|
// need to run dataflow.
|
||||||
|
ConstKind::Const | ConstKind::Static | ConstKind::StaticMut
|
||||||
|
if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstKind::Const | ConstKind::Static | ConstKind::StaticMut => {
|
||||||
|
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
|
||||||
|
.into_engine(ccx.tcx, &ccx.body, ccx.def_id)
|
||||||
|
.iterate_to_fixpoint()
|
||||||
|
.into_results_cursor(&ccx.body);
|
||||||
|
|
||||||
|
cursor.seek_after(return_loc);
|
||||||
|
cursor.contains(RETURN_PLACE)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ConstQualifs {
|
ConstQualifs {
|
||||||
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
|
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
|
||||||
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
|
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
|
||||||
|
custom_eq,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue