Skip to content

Commit 86a8a3b

Browse files
committed
make compare_const_impl a query and use it in instance.rs
1 parent f914b82 commit 86a8a3b

File tree

9 files changed

+118
-84
lines changed

9 files changed

+118
-84
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::check::intrinsicck::InlineAsmCtxt;
22

33
use super::coercion::CoerceMany;
44
use super::compare_method::check_type_bounds;
5-
use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
5+
use super::compare_method::{compare_impl_method, compare_ty_impl};
66
use super::*;
77
use rustc_attr as attr;
88
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
@@ -1045,13 +1045,11 @@ fn check_impl_items_against_trait<'tcx>(
10451045
match impl_item_full.kind {
10461046
hir::ImplItemKind::Const(..) => {
10471047
// Find associated const definition.
1048-
compare_const_impl(
1049-
tcx,
1048+
let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
10501049
&ty_impl_item,
1051-
impl_item.span,
10521050
&ty_trait_item,
10531051
impl_trait_ref,
1054-
);
1052+
));
10551053
}
10561054
hir::ImplItemKind::Fn(..) => {
10571055
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);

compiler/rustc_hir_analysis/src/check/compare_method.rs

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,15 +1300,15 @@ fn compare_generic_param_kinds<'tcx>(
13001300
Ok(())
13011301
}
13021302

1303-
pub(crate) fn compare_const_impl<'tcx>(
1303+
/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
1304+
pub(crate) fn raw_compare_const_impl<'tcx>(
13041305
tcx: TyCtxt<'tcx>,
1305-
impl_c: &ty::AssocItem,
1306-
impl_c_span: Span,
1307-
trait_c: &ty::AssocItem,
1308-
impl_trait_ref: ty::TraitRef<'tcx>,
1309-
) {
1306+
(impl_c, trait_c, impl_trait_ref): (&ty::AssocItem, &ty::AssocItem, ty::TraitRef<'tcx>),
1307+
) -> Result<(), ErrorGuaranteed> {
13101308
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
13111309

1310+
let impl_c_span = tcx.def_span(impl_c.def_id);
1311+
13121312
tcx.infer_ctxt().enter(|infcx| {
13131313
let param_env = tcx.param_env(impl_c.def_id);
13141314
let ocx = ObligationCtxt::new(&infcx);
@@ -1346,68 +1346,68 @@ pub(crate) fn compare_const_impl<'tcx>(
13461346

13471347
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
13481348

1349-
let err = infcx
1349+
let maybe_error_reported = infcx
13501350
.at(&cause, param_env)
13511351
.sup(trait_ty, impl_ty)
1352-
.map(|ok| ocx.register_infer_ok_obligations(ok));
1352+
.map(|ok| ocx.register_infer_ok_obligations(ok))
1353+
.map_err(|terr| {
1354+
debug!(
1355+
"checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
1356+
impl_ty, trait_ty
1357+
);
13531358

1354-
if let Err(terr) = err {
1355-
debug!(
1356-
"checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
1357-
impl_ty, trait_ty
1358-
);
1359+
// Locate the Span containing just the type of the offending impl
1360+
match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
1361+
ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
1362+
_ => bug!("{:?} is not a impl const", impl_c),
1363+
}
13591364

1360-
// Locate the Span containing just the type of the offending impl
1361-
match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
1362-
ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
1363-
_ => bug!("{:?} is not a impl const", impl_c),
1364-
}
1365+
let mut diag = struct_span_err!(
1366+
tcx.sess,
1367+
cause.span,
1368+
E0326,
1369+
"implemented const `{}` has an incompatible type for trait",
1370+
trait_c.name
1371+
);
13651372

1366-
let mut diag = struct_span_err!(
1367-
tcx.sess,
1368-
cause.span,
1369-
E0326,
1370-
"implemented const `{}` has an incompatible type for trait",
1371-
trait_c.name
1372-
);
1373+
let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
1374+
// Add a label to the Span containing just the type of the const
1375+
match tcx.hir().expect_trait_item(trait_c_def_id).kind {
1376+
TraitItemKind::Const(ref ty, _) => ty.span,
1377+
_ => bug!("{:?} is not a trait const", trait_c),
1378+
}
1379+
});
13731380

1374-
let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
1375-
// Add a label to the Span containing just the type of the const
1376-
match tcx.hir().expect_trait_item(trait_c_def_id).kind {
1377-
TraitItemKind::Const(ref ty, _) => ty.span,
1378-
_ => bug!("{:?} is not a trait const", trait_c),
1379-
}
1381+
infcx.note_type_err(
1382+
&mut diag,
1383+
&cause,
1384+
trait_c_span.map(|span| (span, "type in trait".to_owned())),
1385+
Some(infer::ValuePairs::Terms(ExpectedFound {
1386+
expected: trait_ty.into(),
1387+
found: impl_ty.into(),
1388+
})),
1389+
terr,
1390+
false,
1391+
false,
1392+
);
1393+
diag.emit()
13801394
});
13811395

1382-
infcx.note_type_err(
1383-
&mut diag,
1384-
&cause,
1385-
trait_c_span.map(|span| (span, "type in trait".to_owned())),
1386-
Some(infer::ValuePairs::Terms(ExpectedFound {
1387-
expected: trait_ty.into(),
1388-
found: impl_ty.into(),
1389-
})),
1390-
terr,
1391-
false,
1392-
false,
1393-
);
1394-
diag.emit();
1395-
}
1396-
13971396
// Check that all obligations are satisfied by the implementation's
13981397
// version.
13991398
let errors = ocx.select_all_or_error();
14001399
if !errors.is_empty() {
1401-
infcx.report_fulfillment_errors(&errors, None, false);
1402-
return;
1400+
return Err(infcx.report_fulfillment_errors(&errors, None, false));
14031401
}
14041402

1403+
// FIXME return `ErrorReported` if region obligations error?
14051404
let outlives_environment = OutlivesEnvironment::new(param_env);
14061405
infcx.check_region_obligations_and_report_errors(
14071406
impl_c.def_id.expect_local(),
14081407
&outlives_environment,
14091408
);
1410-
});
1409+
maybe_error_reported
1410+
})
14111411
}
14121412

14131413
pub(crate) fn compare_ty_impl<'tcx>(

compiler/rustc_hir_analysis/src/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ pub fn provide(providers: &mut Providers) {
251251
check_mod_item_types,
252252
region_scope_tree,
253253
collect_trait_impl_trait_tys,
254+
compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
254255
..*providers
255256
};
256257
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,4 +2100,10 @@ rustc_queries! {
21002100
query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
21012101
desc { "checking to see if {:?} permits being left zeroed", key.ty }
21022102
}
2103+
2104+
query compare_assoc_const_impl_item_with_trait_item(
2105+
key: (&'tcx ty::AssocItem, &'tcx ty::AssocItem, ty::TraitRef<'tcx>)
2106+
) -> Result<(), ErrorGuaranteed> {
2107+
desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.def_id) }
2108+
}
21032109
}

compiler/rustc_query_impl/src/keys.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,3 +557,14 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
557557
DUMMY_SP
558558
}
559559
}
560+
561+
impl<'tcx> Key for (&'tcx ty::AssocItem, &'tcx ty::AssocItem, ty::TraitRef<'tcx>) {
562+
#[inline(always)]
563+
fn query_crate_is_local(&self) -> bool {
564+
self.0.def_id.krate == LOCAL_CRATE
565+
}
566+
567+
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
568+
tcx.def_span(self.0.def_id)
569+
}
570+
}

compiler/rustc_ty_utils/src/instance.rs

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -182,40 +182,18 @@ fn resolve_associated_item<'tcx>(
182182
// a `trait` to an associated `const` definition in an `impl`, where
183183
// the definition in the `impl` has the wrong type (for which an
184184
// error has already been/will be emitted elsewhere).
185-
//
186-
// NB: this may be expensive, we try to skip it in all the cases where
187-
// we know the error would've been caught (e.g. in an upstream crate).
188-
//
189-
// A better approach might be to just introduce a query (returning
190-
// `Result<(), ErrorGuaranteed>`) for the check that `rustc_hir_analysis`
191-
// performs (i.e. that the definition's type in the `impl` matches
192-
// the declaration in the `trait`), so that we can cheaply check
193-
// here if it failed, instead of approximating it.
194185
if leaf_def.item.kind == ty::AssocKind::Const
195186
&& trait_item_id != leaf_def.item.def_id
196187
&& leaf_def.item.def_id.is_local()
197188
{
198-
let normalized_type_of = |def_id, substs| {
199-
tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
200-
};
201-
202-
let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
203-
let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
204-
205-
if original_ty != resolved_ty {
206-
let msg = format!(
207-
"Instance::resolve: inconsistent associated `const` type: \
208-
was `{}: {}` but resolved to `{}: {}`",
209-
tcx.def_path_str_with_substs(trait_item_id, rcvr_substs),
210-
original_ty,
211-
tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
212-
resolved_ty,
213-
);
214-
let span = tcx.def_span(leaf_def.item.def_id);
215-
let reported = tcx.sess.delay_span_bug(span, &msg);
216-
217-
return Err(reported);
218-
}
189+
let impl_item = tcx.associated_item(leaf_def.item.def_id);
190+
let trait_item = tcx.associated_item(trait_item_id);
191+
let impl_trait_ref = tcx.impl_trait_ref(impl_item.container_id(tcx)).unwrap();
192+
tcx.compare_assoc_const_impl_item_with_trait_item((
193+
impl_item,
194+
trait_item,
195+
impl_trait_ref,
196+
))?;
219197
}
220198

221199
Some(ty::Instance::new(leaf_def.item.def_id, substs))
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-pass
2+
#![feature(generic_const_exprs)]
3+
#![allow(incomplete_features)]
4+
5+
trait MyTrait {
6+
type ArrayType;
7+
const SIZE: usize;
8+
const ARRAY: Self::ArrayType;
9+
}
10+
impl MyTrait for () {
11+
type ArrayType = [u8; Self::SIZE];
12+
const SIZE: usize = 4;
13+
const ARRAY: [u8; Self::SIZE] = [1, 2, 3, 4];
14+
}
15+
16+
fn main() {
17+
let _ = <() as MyTrait>::ARRAY;
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-pass
2+
trait Trait {
3+
const ASSOC: fn(&'static u32);
4+
}
5+
impl Trait for () {
6+
const ASSOC: for<'a> fn(&'a u32) = |_| ();
7+
}
8+
9+
fn main() {
10+
let _ = <() as Trait>::ASSOC;
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-pass
2+
trait Trait {
3+
const ASSOC: for<'a, 'b> fn(&'a u32, &'b u32);
4+
}
5+
impl Trait for () {
6+
const ASSOC: for<'a> fn(&'a u32, &'a u32) = |_, _| ();
7+
}
8+
9+
fn main() {
10+
let _ = <() as Trait>::ASSOC;
11+
}

0 commit comments

Comments
 (0)