walk hir to get const evaluatable predicates
This commit is contained in:
parent
ac1d0d8b28
commit
f8d3f401df
@ -37,12 +37,11 @@ use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::util::Discr;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
|
||||
use rustc_middle::ty::{TypeFoldable, TypeVisitor};
|
||||
use rustc_session::config::SanitizerSet;
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
@ -51,8 +50,6 @@ use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
mod type_of;
|
||||
|
||||
struct OnlySelfBounds(bool);
|
||||
@ -1676,65 +1673,10 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
|
||||
}
|
||||
}
|
||||
|
||||
if tcx.features().const_evaluatable_checked {
|
||||
let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result);
|
||||
if !const_evaluatable.is_empty() {
|
||||
result.predicates = tcx
|
||||
.arena
|
||||
.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable));
|
||||
}
|
||||
}
|
||||
|
||||
debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn const_evaluatable_predicates_of<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
predicates: &ty::GenericPredicates<'tcx>,
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
#[derive(Default)]
|
||||
struct ConstCollector<'tcx> {
|
||||
ct: SmallVec<[(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>, Span); 4]>,
|
||||
curr_span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> {
|
||||
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool {
|
||||
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
|
||||
self.ct.push((def, substs, self.curr_span));
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
let mut collector = ConstCollector::default();
|
||||
for &(pred, span) in predicates.predicates.iter() {
|
||||
collector.curr_span = span;
|
||||
pred.visit_with(&mut collector);
|
||||
}
|
||||
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Fn | DefKind::AssocFn => {
|
||||
tcx.fn_sig(def_id).visit_with(&mut collector);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct);
|
||||
|
||||
// We only want unique const evaluatable predicates.
|
||||
collector.ct.sort();
|
||||
collector.ct.dedup();
|
||||
collector
|
||||
.ct
|
||||
.into_iter()
|
||||
.map(move |(def_id, subst, span)| {
|
||||
(ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns a list of all type predicates (explicit and implicit) for the definition with
|
||||
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
|
||||
/// `Self: Trait` predicates for traits.
|
||||
@ -2061,6 +2003,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
}))
|
||||
}
|
||||
|
||||
if tcx.features().const_evaluatable_checked {
|
||||
predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
|
||||
}
|
||||
|
||||
let mut predicates: Vec<_> = predicates.into_iter().collect();
|
||||
|
||||
// Subtle: before we store the predicates into the tcx, we
|
||||
@ -2087,6 +2033,85 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
result
|
||||
}
|
||||
|
||||
fn const_evaluatable_predicates_of<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
|
||||
struct ConstCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
|
||||
}
|
||||
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
|
||||
let def_id = self.tcx.hir().local_def_id(c.hir_id);
|
||||
let ct = ty::Const::from_anon_const(self.tcx, def_id);
|
||||
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
|
||||
let span = self.tcx.hir().span(c.hir_id);
|
||||
self.preds.insert((
|
||||
ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Look into `TyAlias`.
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
use ty::fold::{TypeFoldable, TypeVisitor};
|
||||
struct TyAliasVisitor<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> {
|
||||
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool {
|
||||
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
|
||||
self.preds.insert((
|
||||
ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
|
||||
self.span,
|
||||
));
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind {
|
||||
if let Res::Def(DefKind::TyAlias, def_id) = path.res {
|
||||
let mut visitor =
|
||||
TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span };
|
||||
self.tcx.type_of(def_id).visit_with(&mut visitor);
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_ty(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let node = tcx.hir().get(hir_id);
|
||||
|
||||
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
|
||||
if let Some(generics) = node.generics() {
|
||||
warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
|
||||
collector.visit_generics(generics);
|
||||
}
|
||||
|
||||
if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
|
||||
warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
|
||||
collector.visit_fn_decl(fn_sig.decl);
|
||||
}
|
||||
warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
|
||||
|
||||
collector.preds
|
||||
}
|
||||
|
||||
fn projection_ty_from_predicates(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: (
|
||||
|
@ -4,10 +4,10 @@ error: constant expression depends on a generic parameter
|
||||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
|
||||
|
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
| ----- required by this bound in `test1`
|
||||
| ---------------------------- required by this bound in `test1`
|
||||
|
|
||||
= note: this may fail depending on what value the parameter takes
|
||||
|
||||
@ -17,10 +17,10 @@ error: constant expression depends on a generic parameter
|
||||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
|
||||
|
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
| ----- required by this bound in `test1`
|
||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
||||
| ---------------------------- required by this bound in `test1`
|
||||
|
|
||||
= note: this may fail depending on what value the parameter takes
|
||||
|
||||
@ -30,10 +30,10 @@ error: constant expression depends on a generic parameter
|
||||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
|
||||
|
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
| ----- required by this bound in `test1::{{constant}}#1`
|
||||
| ---------------------------- required by this bound in `test1::{{constant}}#1`
|
||||
|
|
||||
= note: this may fail depending on what value the parameter takes
|
||||
|
||||
@ -43,10 +43,10 @@ error: constant expression depends on a generic parameter
|
||||
LL | let _ = const_evaluatable_lib::test1::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
|
||||
::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
|
||||
|
|
||||
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
|
||||
| ----- required by this bound in `test1::{{constant}}#1`
|
||||
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
|
||||
| ---------------------------- required by this bound in `test1::{{constant}}#1`
|
||||
|
|
||||
= note: this may fail depending on what value the parameter takes
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
error: overly complex generic constant
|
||||
error: constant expression depends on a generic parameter
|
||||
--> $DIR/let-bindings.rs:6:68
|
||||
|
|
||||
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
|
||||
| ^^^^^^-^^^^^^^^^^^^^
|
||||
| |
|
||||
| unsupported statement
|
||||
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test::{{constant}}#0`
|
||||
|
|
||||
= help: consider moving this anonymous constant into a `const` function
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user