about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs98
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_query_impl/src/keys.rs11
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs38
-rw-r--r--src/test/ui/associated-consts/mismatched_impl_ty_1.rs18
-rw-r--r--src/test/ui/associated-consts/mismatched_impl_ty_2.rs11
-rw-r--r--src/test/ui/associated-consts/mismatched_impl_ty_3.rs11
9 files changed, 118 insertions, 84 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 4bbe9abaf98..5e65446e100 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -2,7 +2,7 @@ use crate::check::intrinsicck::InlineAsmCtxt;
 
 use super::coercion::CoerceMany;
 use super::compare_method::check_type_bounds;
-use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
+use super::compare_method::{compare_impl_method, compare_ty_impl};
 use super::*;
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
@@ -1045,13 +1045,11 @@ fn check_impl_items_against_trait<'tcx>(
         match impl_item_full.kind {
             hir::ImplItemKind::Const(..) => {
                 // Find associated const definition.
-                compare_const_impl(
-                    tcx,
+                let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
                     &ty_impl_item,
-                    impl_item.span,
                     &ty_trait_item,
                     impl_trait_ref,
-                );
+                ));
             }
             hir::ImplItemKind::Fn(..) => {
                 let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index ae98a8f6209..c859796d388 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -1300,15 +1300,15 @@ fn compare_generic_param_kinds<'tcx>(
     Ok(())
 }
 
-pub(crate) fn compare_const_impl<'tcx>(
+/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
+pub(crate) fn raw_compare_const_impl<'tcx>(
     tcx: TyCtxt<'tcx>,
-    impl_c: &ty::AssocItem,
-    impl_c_span: Span,
-    trait_c: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) {
+    (impl_c, trait_c, impl_trait_ref): (&ty::AssocItem, &ty::AssocItem, ty::TraitRef<'tcx>),
+) -> Result<(), ErrorGuaranteed> {
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
+    let impl_c_span = tcx.def_span(impl_c.def_id);
+
     tcx.infer_ctxt().enter(|infcx| {
         let param_env = tcx.param_env(impl_c.def_id);
         let ocx = ObligationCtxt::new(&infcx);
@@ -1346,68 +1346,68 @@ pub(crate) fn compare_const_impl<'tcx>(
 
         debug!("compare_const_impl: trait_ty={:?}", trait_ty);
 
-        let err = infcx
+        let maybe_error_reported = infcx
             .at(&cause, param_env)
             .sup(trait_ty, impl_ty)
-            .map(|ok| ocx.register_infer_ok_obligations(ok));
+            .map(|ok| ocx.register_infer_ok_obligations(ok))
+            .map_err(|terr| {
+                debug!(
+                    "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+                    impl_ty, trait_ty
+                );
 
-        if let Err(terr) = err {
-            debug!(
-                "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
-                impl_ty, trait_ty
-            );
+                // Locate the Span containing just the type of the offending impl
+                match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
+                    ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
+                    _ => bug!("{:?} is not a impl const", impl_c),
+                }
 
-            // Locate the Span containing just the type of the offending impl
-            match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
-                ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
-                _ => bug!("{:?} is not a impl const", impl_c),
-            }
+                let mut diag = struct_span_err!(
+                    tcx.sess,
+                    cause.span,
+                    E0326,
+                    "implemented const `{}` has an incompatible type for trait",
+                    trait_c.name
+                );
 
-            let mut diag = struct_span_err!(
-                tcx.sess,
-                cause.span,
-                E0326,
-                "implemented const `{}` has an incompatible type for trait",
-                trait_c.name
-            );
+                let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
+                    // Add a label to the Span containing just the type of the const
+                    match tcx.hir().expect_trait_item(trait_c_def_id).kind {
+                        TraitItemKind::Const(ref ty, _) => ty.span,
+                        _ => bug!("{:?} is not a trait const", trait_c),
+                    }
+                });
 
-            let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
-                // Add a label to the Span containing just the type of the const
-                match tcx.hir().expect_trait_item(trait_c_def_id).kind {
-                    TraitItemKind::Const(ref ty, _) => ty.span,
-                    _ => bug!("{:?} is not a trait const", trait_c),
-                }
+                infcx.note_type_err(
+                    &mut diag,
+                    &cause,
+                    trait_c_span.map(|span| (span, "type in trait".to_owned())),
+                    Some(infer::ValuePairs::Terms(ExpectedFound {
+                        expected: trait_ty.into(),
+                        found: impl_ty.into(),
+                    })),
+                    terr,
+                    false,
+                    false,
+                );
+                diag.emit()
             });
 
-            infcx.note_type_err(
-                &mut diag,
-                &cause,
-                trait_c_span.map(|span| (span, "type in trait".to_owned())),
-                Some(infer::ValuePairs::Terms(ExpectedFound {
-                    expected: trait_ty.into(),
-                    found: impl_ty.into(),
-                })),
-                terr,
-                false,
-                false,
-            );
-            diag.emit();
-        }
-
         // Check that all obligations are satisfied by the implementation's
         // version.
         let errors = ocx.select_all_or_error();
         if !errors.is_empty() {
-            infcx.report_fulfillment_errors(&errors, None, false);
-            return;
+            return Err(infcx.report_fulfillment_errors(&errors, None, false));
         }
 
+        // FIXME return `ErrorReported` if region obligations error?
         let outlives_environment = OutlivesEnvironment::new(param_env);
         infcx.check_region_obligations_and_report_errors(
             impl_c.def_id.expect_local(),
             &outlives_environment,
         );
-    });
+        maybe_error_reported
+    })
 }
 
 pub(crate) fn compare_ty_impl<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 593a9776bde..04e8c9c22d1 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -251,6 +251,7 @@ pub fn provide(providers: &mut Providers) {
         check_mod_item_types,
         region_scope_tree,
         collect_trait_impl_trait_tys,
+        compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
         ..*providers
     };
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index fb867f8b46b..3fdeb3dd8ba 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2100,4 +2100,10 @@ rustc_queries! {
     query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
         desc { "checking to see if {:?} permits being left zeroed", key.ty }
     }
+
+    query compare_assoc_const_impl_item_with_trait_item(
+        key: (&'tcx ty::AssocItem, &'tcx ty::AssocItem, ty::TraitRef<'tcx>)
+    ) -> Result<(), ErrorGuaranteed> {
+        desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.def_id) }
+    }
 }
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 47762440e29..68debcffc85 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -557,3 +557,14 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for (&'tcx ty::AssocItem, &'tcx ty::AssocItem, ty::TraitRef<'tcx>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.def_id.krate == LOCAL_CRATE
+    }
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.def_span(self.0.def_id)
+    }
+}
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index fa1dc90e4a2..97e2a146d28 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -182,40 +182,18 @@ fn resolve_associated_item<'tcx>(
             // a `trait` to an associated `const` definition in an `impl`, where
             // the definition in the `impl` has the wrong type (for which an
             // error has already been/will be emitted elsewhere).
-            //
-            // NB: this may be expensive, we try to skip it in all the cases where
-            // we know the error would've been caught (e.g. in an upstream crate).
-            //
-            // A better approach might be to just introduce a query (returning
-            // `Result<(), ErrorGuaranteed>`) for the check that `rustc_hir_analysis`
-            // performs (i.e. that the definition's type in the `impl` matches
-            // the declaration in the `trait`), so that we can cheaply check
-            // here if it failed, instead of approximating it.
             if leaf_def.item.kind == ty::AssocKind::Const
                 && trait_item_id != leaf_def.item.def_id
                 && leaf_def.item.def_id.is_local()
             {
-                let normalized_type_of = |def_id, substs| {
-                    tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
-                };
-
-                let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
-                let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
-
-                if original_ty != resolved_ty {
-                    let msg = format!(
-                        "Instance::resolve: inconsistent associated `const` type: \
-                         was `{}: {}` but resolved to `{}: {}`",
-                        tcx.def_path_str_with_substs(trait_item_id, rcvr_substs),
-                        original_ty,
-                        tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
-                        resolved_ty,
-                    );
-                    let span = tcx.def_span(leaf_def.item.def_id);
-                    let reported = tcx.sess.delay_span_bug(span, &msg);
-
-                    return Err(reported);
-                }
+                let impl_item = tcx.associated_item(leaf_def.item.def_id);
+                let trait_item = tcx.associated_item(trait_item_id);
+                let impl_trait_ref = tcx.impl_trait_ref(impl_item.container_id(tcx)).unwrap();
+                tcx.compare_assoc_const_impl_item_with_trait_item((
+                    impl_item,
+                    trait_item,
+                    impl_trait_ref,
+                ))?;
             }
 
             Some(ty::Instance::new(leaf_def.item.def_id, substs))
diff --git a/src/test/ui/associated-consts/mismatched_impl_ty_1.rs b/src/test/ui/associated-consts/mismatched_impl_ty_1.rs
new file mode 100644
index 00000000000..4dc6c2e47a9
--- /dev/null
+++ b/src/test/ui/associated-consts/mismatched_impl_ty_1.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait MyTrait {
+    type ArrayType;
+    const SIZE: usize;
+    const ARRAY: Self::ArrayType;
+}
+impl MyTrait for () {
+    type ArrayType = [u8; Self::SIZE];
+    const SIZE: usize = 4;
+    const ARRAY: [u8; Self::SIZE] = [1, 2, 3, 4];
+}
+
+fn main() {
+    let _ = <() as MyTrait>::ARRAY;
+}
diff --git a/src/test/ui/associated-consts/mismatched_impl_ty_2.rs b/src/test/ui/associated-consts/mismatched_impl_ty_2.rs
new file mode 100644
index 00000000000..539becfdc7c
--- /dev/null
+++ b/src/test/ui/associated-consts/mismatched_impl_ty_2.rs
@@ -0,0 +1,11 @@
+// run-pass
+trait Trait {
+    const ASSOC: fn(&'static u32);
+}
+impl Trait for () {
+    const ASSOC: for<'a> fn(&'a u32) = |_| ();
+}
+
+fn main() {
+    let _ = <() as Trait>::ASSOC;
+}
diff --git a/src/test/ui/associated-consts/mismatched_impl_ty_3.rs b/src/test/ui/associated-consts/mismatched_impl_ty_3.rs
new file mode 100644
index 00000000000..17bcc8fe576
--- /dev/null
+++ b/src/test/ui/associated-consts/mismatched_impl_ty_3.rs
@@ -0,0 +1,11 @@
+// run-pass
+trait Trait {
+    const ASSOC: for<'a, 'b> fn(&'a u32, &'b u32);
+}
+impl Trait for () {
+    const ASSOC: for<'a> fn(&'a u32, &'a u32) = |_, _| ();
+}
+
+fn main() {
+    let _ = <() as Trait>::ASSOC;
+}