]> git.lizzy.rs Git - rust.git/commitdiff
walk hir to get const evaluatable predicates
authorBastian Kauschke <bastian_kauschke@hotmail.de>
Tue, 22 Sep 2020 08:54:09 +0000 (10:54 +0200)
committerBastian Kauschke <bastian_kauschke@hotmail.de>
Thu, 24 Sep 2020 07:03:50 +0000 (09:03 +0200)
compiler/rustc_typeck/src/collect.rs
src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr

index fd2cd03a9c1808f6aa6b745067ca8c32f97a0601..d341e7eec41a34466144c7cdcb802168a21a2950 100644 (file)
 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_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: (
index e8afb495e602b0a7477e83f5db0538d333424e2c..e7da191e670ec5646c56ccb1bd8b8268ef5df490 100644 (file)
@@ -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
 
index 5749defb3e12c679227424fb7eef06d8bf66ad61..b76e300663d762e5f715bf90ce5203b63b06f138 100644 (file)
@@ -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