From 70dfe3fa746ac459747da30aca0bac11379088d5 Mon Sep 17 00:00:00 2001
From: Bastian Kauschke <bastian_kauschke@hotmail.de>
Date: Sun, 2 Aug 2020 21:28:18 +0200
Subject: [PATCH] move const param structural match checks to wfcheck

---
 src/librustc_typeck/check/mod.rs              |   4 +-
 src/librustc_typeck/check/wfcheck.rs          | 116 +++++++++++-
 src/librustc_typeck/collect/type_of.rs        |  85 +--------
 .../ui/const-generics/issues/issue-75047.rs   |  15 ++
 .../ui/const-generics/nested-type.full.stderr | 163 ++---------------
 .../ui/const-generics/nested-type.min.stderr  | 167 ++----------------
 src/test/ui/const-generics/nested-type.rs     |   6 +-
 7 files changed, 155 insertions(+), 401 deletions(-)
 create mode 100644 src/test/ui/const-generics/issues/issue-75047.rs

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 824e81a974c..dc4f181ec93 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -729,8 +729,8 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
 }
 
 pub fn check_wf_new(tcx: TyCtxt<'_>) {
-    let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
-    tcx.hir().krate().par_visit_all_item_likes(&visit);
+    let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
+    tcx.hir().krate().visit_all_item_likes(&mut visit.as_deep_visitor());
 }
 
 fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index d47a8273d07..740f30f5224 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -6,9 +6,11 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::itemlikevisit::ParItemLikeVisitor;
+use rustc_hir::intravisit as hir_visit;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items;
 use rustc_hir::ItemKind;
+use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
@@ -275,6 +277,95 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
 }
 
+fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
+    match param.kind {
+        // We currently only check wf of const params here.
+        hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
+
+        // Const parameters are well formed if their
+        // type is structural match.
+        hir::GenericParamKind::Const { ty: hir_ty } => {
+            let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
+
+            let err_ty_str;
+            let err = if tcx.features().min_const_generics {
+                match ty.kind {
+                    ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => {
+                        err_ty_str = format!("`{}`", ty);
+                        Some(err_ty_str.as_str())
+                    }
+                }
+            } else {
+                match ty.peel_refs().kind {
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => None,
+                }
+            };
+            if let Some(unsupported_type) = err {
+                let mut err = tcx.sess.struct_span_err(
+                    hir_ty.span,
+                    &format!("using {} as const generic parameters is forbidden", unsupported_type),
+                );
+
+                if tcx.features().min_const_generics {
+                    err.note("the only supported types are integers, `bool` and `char`")
+                        .note("more complex types are supported with `#[feature(const_generics)]`")
+                        .emit()
+                } else {
+                    err.emit();
+                }
+            };
+            if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
+                .is_some()
+            {
+                // We use the same error code in both branches, because this is really the same
+                // issue: we just special-case the message for type parameters to make it
+                // clearer.
+                if let ty::Param(_) = ty.peel_refs().kind {
+                    // Const parameters may not have type parameters as their types,
+                    // because we cannot be sure that the type parameter derives `PartialEq`
+                    // and `Eq` (just implementing them is not enough for `structural_match`).
+                    struct_span_err!(
+                        tcx.sess,
+                        hir_ty.span,
+                        E0741,
+                        "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
+                            used as the type of a const parameter",
+                        ty,
+                    )
+                    .span_label(
+                        hir_ty.span,
+                        format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
+                    )
+                    .note(
+                        "it is not currently possible to use a type parameter as the type of a \
+                            const parameter",
+                    )
+                    .emit();
+                } else {
+                    struct_span_err!(
+                        tcx.sess,
+                        hir_ty.span,
+                        E0741,
+                        "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
+                            the type of a const parameter",
+                        ty,
+                    )
+                    .span_label(
+                        hir_ty.span,
+                        format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
+                    )
+                    .emit();
+                }
+            }
+        }
+    }
+}
+
 fn check_associated_item(
     tcx: TyCtxt<'_>,
     item_id: hir::HirId,
@@ -1292,23 +1383,38 @@ impl CheckTypeWellFormedVisitor<'tcx> {
     }
 }
 
-impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
-    fn visit_item(&self, i: &'tcx hir::Item<'tcx>) {
+impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
+    type Map = hir_map::Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
+        hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    }
+
+    fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
         debug!("visit_item: {:?}", i);
         let def_id = self.tcx.hir().local_def_id(i.hir_id);
         self.tcx.ensure().check_item_well_formed(def_id);
+        hir_visit::walk_item(self, i);
     }
 
-    fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) {
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         debug!("visit_trait_item: {:?}", trait_item);
         let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
         self.tcx.ensure().check_trait_item_well_formed(def_id);
+        hir_visit::walk_trait_item(self, trait_item);
     }
 
-    fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         debug!("visit_impl_item: {:?}", impl_item);
         let def_id = self.tcx.hir().local_def_id(impl_item.hir_id);
         self.tcx.ensure().check_impl_item_well_formed(def_id);
+        hir_visit::walk_impl_item(self, impl_item);
+    }
+
+    fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
+        check_param_wf(self.tcx, p);
+        // No need to walk further here, there is nothing interesting
+        // inside of generic params we don't already check in `check_param_wf`.
     }
 }
 
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index f1478c8c952..70ed92c5614 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -12,7 +12,6 @@ use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
-use rustc_trait_selection::traits;
 
 use super::ItemCtxt;
 use super::{bad_placeholder_type, is_suggestable_infer_ty};
@@ -323,88 +322,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
         }
 
         Node::GenericParam(param) => match &param.kind {
-            GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
-            GenericParamKind::Const { ty: ref hir_ty, .. } => {
-                let ty = icx.to_ty(hir_ty);
-                let err_ty_str;
-                let err = if tcx.features().min_const_generics {
-                    match ty.kind {
-                        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
-                        ty::FnPtr(_) => Some("function pointers"),
-                        ty::RawPtr(_) => Some("raw pointers"),
-                        _ => {
-                            err_ty_str = format!("`{}`", ty);
-                            Some(err_ty_str.as_str())
-                        }
-                    }
-                } else {
-                    match ty.peel_refs().kind {
-                        ty::FnPtr(_) => Some("function pointers"),
-                        ty::RawPtr(_) => Some("raw pointers"),
-                        _ => None,
-                    }
-                };
-                if let Some(unsupported_type) = err {
-                    let mut err = tcx.sess.struct_span_err(
-                        hir_ty.span,
-                        &format!(
-                            "using {} as const generic parameters is forbidden",
-                            unsupported_type
-                        ),
-                    );
-
-                    if tcx.features().min_const_generics {
-                        err.note("the only supported types are integers, `bool` and `char`")
-                        .note("more complex types are supported with `#[feature(const_generics)]`").emit()
-                    } else {
-                        err.emit();
-                    }
-                };
-                if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
-                    .is_some()
-                {
-                    // We use the same error code in both branches, because this is really the same
-                    // issue: we just special-case the message for type parameters to make it
-                    // clearer.
-                    if let ty::Param(_) = ty.peel_refs().kind {
-                        // Const parameters may not have type parameters as their types,
-                        // because we cannot be sure that the type parameter derives `PartialEq`
-                        // and `Eq` (just implementing them is not enough for `structural_match`).
-                        struct_span_err!(
-                            tcx.sess,
-                            hir_ty.span,
-                            E0741,
-                            "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
-                             used as the type of a const parameter",
-                            ty,
-                        )
-                        .span_label(
-                            hir_ty.span,
-                            format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
-                        )
-                        .note(
-                            "it is not currently possible to use a type parameter as the type of a \
-                             const parameter",
-                        )
-                        .emit();
-                    } else {
-                        struct_span_err!(
-                            tcx.sess,
-                            hir_ty.span,
-                            E0741,
-                            "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
-                             the type of a const parameter",
-                            ty,
-                        )
-                        .span_label(
-                            hir_ty.span,
-                            format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
-                        )
-                        .emit();
-                    }
-                }
-                ty
-            }
+            GenericParamKind::Type { default: Some(ty), .. }
+            | GenericParamKind::Const { ty, .. } => icx.to_ty(ty),
             x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
         },
 
diff --git a/src/test/ui/const-generics/issues/issue-75047.rs b/src/test/ui/const-generics/issues/issue-75047.rs
new file mode 100644
index 00000000000..5d068d851c1
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-75047.rs
@@ -0,0 +1,15 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Bar<T>(T);
+
+impl<T> Bar<T> {
+    const fn value() -> usize {
+        42
+    }
+}
+
+struct Foo<const N: [u8; Bar::<u32>::value()]>;
+
+fn main() {}
diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr
index 012b8fe587b..a55d43d395c 100644
--- a/src/test/ui/const-generics/nested-type.full.stderr
+++ b/src/test/ui/const-generics/nested-type.full.stderr
@@ -1,159 +1,16 @@
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/nested-type.rs:17:5
    |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
-   |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
-   |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^
 
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/nested-type.rs:17:5
    |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
-   |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
-   |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0015, E0080.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr
index ebe818785ac..17e2eef7278 100644
--- a/src/test/ui/const-generics/nested-type.min.stderr
+++ b/src/test/ui/const-generics/nested-type.min.stderr
@@ -4,172 +4,29 @@ error: using `[u8; _]` as const generic parameters is forbidden
 LL |   struct Foo<const N: [u8; {
    |  _____________________^
 LL | |
-LL | |
+LL | |     struct Foo<const N: usize>;
 LL | |
 ...  |
-LL | |     Foo::<17>::value()
+LL | |
 LL | | }]>;
    | |__^
    |
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/nested-type.rs:17:5
    |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
-   |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
-   |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^
 
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/nested-type.rs:17:5
    |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
-   |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
-   |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value`
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0015, E0080.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs
index 98a5a0dd3d8..70d6ac42e9f 100644
--- a/src/test/ui/const-generics/nested-type.rs
+++ b/src/test/ui/const-generics/nested-type.rs
@@ -5,9 +5,7 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 struct Foo<const N: [u8; {
-//~^ ERROR cycle detected
-//~| ERROR cycle detected
-//[min]~| ERROR using `[u8; _]` as const generic
+//[min]~^ ERROR using `[u8; _]` as const generic
     struct Foo<const N: usize>;
 
     impl<const N: usize> Foo<N> {
@@ -17,6 +15,8 @@ struct Foo<const N: [u8; {
     }
 
     Foo::<17>::value()
+    //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR evaluation of constant value failed
 }]>;
 
 fn main() {}