diff options
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/check.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/compare_method.rs | 98 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/mod.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/keys.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/instance.rs | 38 | ||||
| -rw-r--r-- | src/test/ui/associated-consts/mismatched_impl_ty_1.rs | 18 | ||||
| -rw-r--r-- | src/test/ui/associated-consts/mismatched_impl_ty_2.rs | 11 | ||||
| -rw-r--r-- | src/test/ui/associated-consts/mismatched_impl_ty_3.rs | 11 |
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; +} |
