Skip to content

Commit f8d3f40

Browse files
committed
walk hir to get const evaluatable predicates
1 parent ac1d0d8 commit f8d3f40

File tree

3 files changed

+96
-73
lines changed

3 files changed

+96
-73
lines changed

compiler/rustc_typeck/src/collect.rs

Lines changed: 84 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,11 @@ use rustc_middle::hir::map::Map;
3737
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
3838
use rustc_middle::mir::mono::Linkage;
3939
use rustc_middle::ty::query::Providers;
40-
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
40+
use rustc_middle::ty::subst::InternalSubsts;
4141
use rustc_middle::ty::util::Discr;
4242
use rustc_middle::ty::util::IntTypeExt;
4343
use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
4444
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
45-
use rustc_middle::ty::{TypeFoldable, TypeVisitor};
4645
use rustc_session::config::SanitizerSet;
4746
use rustc_session::lint;
4847
use rustc_session::parse::feature_err;
@@ -51,8 +50,6 @@ use rustc_span::{Span, DUMMY_SP};
5150
use rustc_target::spec::abi;
5251
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
5352

54-
use smallvec::SmallVec;
55-
5653
mod type_of;
5754

5855
struct OnlySelfBounds(bool);
@@ -1676,65 +1673,10 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
16761673
}
16771674
}
16781675

1679-
if tcx.features().const_evaluatable_checked {
1680-
let const_evaluatable = const_evaluatable_predicates_of(tcx, def_id, &result);
1681-
if !const_evaluatable.is_empty() {
1682-
result.predicates = tcx
1683-
.arena
1684-
.alloc_from_iter(result.predicates.iter().copied().chain(const_evaluatable));
1685-
}
1686-
}
1687-
16881676
debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
16891677
result
16901678
}
16911679

1692-
pub fn const_evaluatable_predicates_of<'tcx>(
1693-
tcx: TyCtxt<'tcx>,
1694-
def_id: DefId,
1695-
predicates: &ty::GenericPredicates<'tcx>,
1696-
) -> Vec<(ty::Predicate<'tcx>, Span)> {
1697-
#[derive(Default)]
1698-
struct ConstCollector<'tcx> {
1699-
ct: SmallVec<[(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>, Span); 4]>,
1700-
curr_span: Span,
1701-
}
1702-
1703-
impl<'tcx> TypeVisitor<'tcx> for ConstCollector<'tcx> {
1704-
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool {
1705-
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
1706-
self.ct.push((def, substs, self.curr_span));
1707-
}
1708-
false
1709-
}
1710-
}
1711-
1712-
let mut collector = ConstCollector::default();
1713-
for &(pred, span) in predicates.predicates.iter() {
1714-
collector.curr_span = span;
1715-
pred.visit_with(&mut collector);
1716-
}
1717-
1718-
match tcx.def_kind(def_id) {
1719-
DefKind::Fn | DefKind::AssocFn => {
1720-
tcx.fn_sig(def_id).visit_with(&mut collector);
1721-
}
1722-
_ => (),
1723-
}
1724-
debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.ct);
1725-
1726-
// We only want unique const evaluatable predicates.
1727-
collector.ct.sort();
1728-
collector.ct.dedup();
1729-
collector
1730-
.ct
1731-
.into_iter()
1732-
.map(move |(def_id, subst, span)| {
1733-
(ty::PredicateAtom::ConstEvaluatable(def_id, subst).to_predicate(tcx), span)
1734-
})
1735-
.collect()
1736-
}
1737-
17381680
/// Returns a list of all type predicates (explicit and implicit) for the definition with
17391681
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
17401682
/// `Self: Trait` predicates for traits.
@@ -2061,6 +2003,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
20612003
}))
20622004
}
20632005

2006+
if tcx.features().const_evaluatable_checked {
2007+
predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
2008+
}
2009+
20642010
let mut predicates: Vec<_> = predicates.into_iter().collect();
20652011

20662012
// 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
20872033
result
20882034
}
20892035

2036+
fn const_evaluatable_predicates_of<'tcx>(
2037+
tcx: TyCtxt<'tcx>,
2038+
def_id: LocalDefId,
2039+
) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
2040+
struct ConstCollector<'tcx> {
2041+
tcx: TyCtxt<'tcx>,
2042+
preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
2043+
}
2044+
2045+
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
2046+
type Map = Map<'tcx>;
2047+
2048+
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
2049+
intravisit::NestedVisitorMap::None
2050+
}
2051+
2052+
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
2053+
let def_id = self.tcx.hir().local_def_id(c.hir_id);
2054+
let ct = ty::Const::from_anon_const(self.tcx, def_id);
2055+
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
2056+
let span = self.tcx.hir().span(c.hir_id);
2057+
self.preds.insert((
2058+
ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
2059+
span,
2060+
));
2061+
}
2062+
}
2063+
2064+
// Look into `TyAlias`.
2065+
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
2066+
use ty::fold::{TypeFoldable, TypeVisitor};
2067+
struct TyAliasVisitor<'a, 'tcx> {
2068+
tcx: TyCtxt<'tcx>,
2069+
preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>,
2070+
span: Span,
2071+
}
2072+
2073+
impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> {
2074+
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool {
2075+
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
2076+
self.preds.insert((
2077+
ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
2078+
self.span,
2079+
));
2080+
}
2081+
false
2082+
}
2083+
}
2084+
2085+
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind {
2086+
if let Res::Def(DefKind::TyAlias, def_id) = path.res {
2087+
let mut visitor =
2088+
TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span };
2089+
self.tcx.type_of(def_id).visit_with(&mut visitor);
2090+
}
2091+
}
2092+
2093+
intravisit::walk_ty(self, ty)
2094+
}
2095+
}
2096+
2097+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
2098+
let node = tcx.hir().get(hir_id);
2099+
2100+
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
2101+
if let Some(generics) = node.generics() {
2102+
warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
2103+
collector.visit_generics(generics);
2104+
}
2105+
2106+
if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
2107+
warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
2108+
collector.visit_fn_decl(fn_sig.decl);
2109+
}
2110+
warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
2111+
2112+
collector.preds
2113+
}
2114+
20902115
fn projection_ty_from_predicates(
20912116
tcx: TyCtxt<'tcx>,
20922117
key: (

src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ error: constant expression depends on a generic parameter
44
LL | let _ = const_evaluatable_lib::test1::<T>();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
7+
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
88
|
99
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
10-
| ----- required by this bound in `test1`
10+
| ---------------------------- required by this bound in `test1`
1111
|
1212
= note: this may fail depending on what value the parameter takes
1313

@@ -17,10 +17,10 @@ error: constant expression depends on a generic parameter
1717
LL | let _ = const_evaluatable_lib::test1::<T>();
1818
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1919
|
20-
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
20+
::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
2121
|
22-
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
23-
| ----- required by this bound in `test1`
22+
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
23+
| ---------------------------- required by this bound in `test1`
2424
|
2525
= note: this may fail depending on what value the parameter takes
2626

@@ -30,10 +30,10 @@ error: constant expression depends on a generic parameter
3030
LL | let _ = const_evaluatable_lib::test1::<T>();
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3232
|
33-
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
33+
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
3434
|
3535
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
36-
| ----- required by this bound in `test1::{{constant}}#1`
36+
| ---------------------------- required by this bound in `test1::{{constant}}#1`
3737
|
3838
= note: this may fail depending on what value the parameter takes
3939

@@ -43,10 +43,10 @@ error: constant expression depends on a generic parameter
4343
LL | let _ = const_evaluatable_lib::test1::<T>();
4444
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4545
|
46-
::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
46+
::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
4747
|
48-
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
49-
| ----- required by this bound in `test1::{{constant}}#1`
48+
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
49+
| ---------------------------- required by this bound in `test1::{{constant}}#1`
5050
|
5151
= note: this may fail depending on what value the parameter takes
5252

src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
error: overly complex generic constant
1+
error: constant expression depends on a generic parameter
22
--> $DIR/let-bindings.rs:6:68
33
|
44
LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
5-
| ^^^^^^-^^^^^^^^^^^^^
6-
| |
7-
| unsupported statement
5+
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `test::{{constant}}#0`
86
|
97
= help: consider moving this anonymous constant into a `const` function
108

0 commit comments

Comments
 (0)