make compare_const_impl
a query and use it in instance.rs
This commit is contained in:
parent
f914b82a75
commit
86a8a3beb4
9 changed files with 120 additions and 86 deletions
|
@ -2,7 +2,7 @@ use crate::check::intrinsicck::InlineAsmCtxt;
|
||||||
|
|
||||||
use super::coercion::CoerceMany;
|
use super::coercion::CoerceMany;
|
||||||
use super::compare_method::check_type_bounds;
|
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 super::*;
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
|
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
|
||||||
|
@ -1045,13 +1045,11 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
match impl_item_full.kind {
|
match impl_item_full.kind {
|
||||||
hir::ImplItemKind::Const(..) => {
|
hir::ImplItemKind::Const(..) => {
|
||||||
// Find associated const definition.
|
// Find associated const definition.
|
||||||
compare_const_impl(
|
let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
|
||||||
tcx,
|
|
||||||
&ty_impl_item,
|
&ty_impl_item,
|
||||||
impl_item.span,
|
|
||||||
&ty_trait_item,
|
&ty_trait_item,
|
||||||
impl_trait_ref,
|
impl_trait_ref,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
hir::ImplItemKind::Fn(..) => {
|
hir::ImplItemKind::Fn(..) => {
|
||||||
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
|
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
|
||||||
|
|
|
@ -1300,15 +1300,15 @@ fn compare_generic_param_kinds<'tcx>(
|
||||||
Ok(())
|
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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_c: &ty::AssocItem,
|
(impl_c, trait_c, impl_trait_ref): (&ty::AssocItem, &ty::AssocItem, ty::TraitRef<'tcx>),
|
||||||
impl_c_span: Span,
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
trait_c: &ty::AssocItem,
|
|
||||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
|
||||||
) {
|
|
||||||
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
|
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| {
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
let param_env = tcx.param_env(impl_c.def_id);
|
let param_env = tcx.param_env(impl_c.def_id);
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
@ -1346,68 +1346,68 @@ pub(crate) fn compare_const_impl<'tcx>(
|
||||||
|
|
||||||
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
|
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
|
||||||
|
|
||||||
let err = infcx
|
let maybe_error_reported = infcx
|
||||||
.at(&cause, param_env)
|
.at(&cause, param_env)
|
||||||
.sup(trait_ty, impl_ty)
|
.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 {
|
// Locate the Span containing just the type of the offending impl
|
||||||
debug!(
|
match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
|
||||||
"checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
|
ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
|
||||||
impl_ty, trait_ty
|
_ => 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 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(
|
let mut diag = struct_span_err!(
|
||||||
&mut diag,
|
tcx.sess,
|
||||||
&cause,
|
cause.span,
|
||||||
trait_c_span.map(|span| (span, "type in trait".to_owned())),
|
E0326,
|
||||||
Some(infer::ValuePairs::Terms(ExpectedFound {
|
"implemented const `{}` has an incompatible type for trait",
|
||||||
expected: trait_ty.into(),
|
trait_c.name
|
||||||
found: impl_ty.into(),
|
);
|
||||||
})),
|
|
||||||
terr,
|
let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
|
||||||
false,
|
// Add a label to the Span containing just the type of the const
|
||||||
false,
|
match tcx.hir().expect_trait_item(trait_c_def_id).kind {
|
||||||
);
|
TraitItemKind::Const(ref ty, _) => ty.span,
|
||||||
diag.emit();
|
_ => 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()
|
||||||
|
});
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
// version.
|
// version.
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.report_fulfillment_errors(&errors, None, false);
|
return Err(infcx.report_fulfillment_errors(&errors, None, false));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME return `ErrorReported` if region obligations error?
|
||||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||||
infcx.check_region_obligations_and_report_errors(
|
infcx.check_region_obligations_and_report_errors(
|
||||||
impl_c.def_id.expect_local(),
|
impl_c.def_id.expect_local(),
|
||||||
&outlives_environment,
|
&outlives_environment,
|
||||||
);
|
);
|
||||||
});
|
maybe_error_reported
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compare_ty_impl<'tcx>(
|
pub(crate) fn compare_ty_impl<'tcx>(
|
||||||
|
|
|
@ -251,6 +251,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
check_mod_item_types,
|
check_mod_item_types,
|
||||||
region_scope_tree,
|
region_scope_tree,
|
||||||
collect_trait_impl_trait_tys,
|
collect_trait_impl_trait_tys,
|
||||||
|
compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2100,4 +2100,10 @@ rustc_queries! {
|
||||||
query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
|
query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
|
||||||
desc { "checking to see if {:?} permits being left zeroed", key.ty }
|
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) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -557,3 +557,14 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
|
||||||
DUMMY_SP
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -182,40 +182,18 @@ fn resolve_associated_item<'tcx>(
|
||||||
// a `trait` to an associated `const` definition in an `impl`, where
|
// a `trait` to an associated `const` definition in an `impl`, where
|
||||||
// the definition in the `impl` has the wrong type (for which an
|
// the definition in the `impl` has the wrong type (for which an
|
||||||
// error has already been/will be emitted elsewhere).
|
// 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
|
if leaf_def.item.kind == ty::AssocKind::Const
|
||||||
&& trait_item_id != leaf_def.item.def_id
|
&& trait_item_id != leaf_def.item.def_id
|
||||||
&& leaf_def.item.def_id.is_local()
|
&& leaf_def.item.def_id.is_local()
|
||||||
{
|
{
|
||||||
let normalized_type_of = |def_id, substs| {
|
let impl_item = tcx.associated_item(leaf_def.item.def_id);
|
||||||
tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(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((
|
||||||
let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
|
impl_item,
|
||||||
let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
|
trait_item,
|
||||||
|
impl_trait_ref,
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ty::Instance::new(leaf_def.item.def_id, substs))
|
Some(ty::Instance::new(leaf_def.item.def_id, substs))
|
||||||
|
|
18
src/test/ui/associated-consts/mismatched_impl_ty_1.rs
Normal file
18
src/test/ui/associated-consts/mismatched_impl_ty_1.rs
Normal file
|
@ -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;
|
||||||
|
}
|
11
src/test/ui/associated-consts/mismatched_impl_ty_2.rs
Normal file
11
src/test/ui/associated-consts/mismatched_impl_ty_2.rs
Normal file
|
@ -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;
|
||||||
|
}
|
11
src/test/ui/associated-consts/mismatched_impl_ty_3.rs
Normal file
11
src/test/ui/associated-consts/mismatched_impl_ty_3.rs
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue