Skip to content

Commit 6ff7a2c

Browse files
committed
Propagate the resolved type of assoc const bindings via query feeding
1 parent a7f4fdb commit 6ff7a2c

File tree

9 files changed

+85
-37
lines changed

9 files changed

+85
-37
lines changed

compiler/rustc_hir_analysis/src/astconv/bounds.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
415415
// Create the generic arguments for the associated type or constant by joining the
416416
// parent arguments (the arguments of the trait) and the own arguments (the ones of
417417
// the associated item itself) and construct an alias type using them.
418-
candidate.map_bound(|trait_ref| {
418+
let alias_ty = candidate.map_bound(|trait_ref| {
419419
let ident = Ident::new(assoc_item.name, binding.ident.span);
420420
let item_segment = hir::PathSegment {
421421
ident,
@@ -437,7 +437,18 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
437437
// *constants* to represent *const projections*. Alias *term* would be a more
438438
// appropriate name but alas.
439439
ty::AliasTy::new(tcx, assoc_item.def_id, alias_args)
440-
})
440+
});
441+
442+
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
443+
if !speculative && let ty::AssocKind::Const = assoc_kind {
444+
let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args));
445+
// Since the arguments passed to the alias type above may contain early-bound
446+
// generic parameters, the instantiated type may contain some as well.
447+
// Therefore wrap it in `EarlyBinder`.
448+
tcx.feed_type_of_assoc_const_binding(binding.hir_id, ty::EarlyBinder::bind(ty));
449+
}
450+
451+
alias_ty
441452
};
442453

443454
match binding.kind {

compiler/rustc_hir_analysis/src/collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub fn provide(providers: &mut Providers) {
6262
*providers = Providers {
6363
type_of: type_of::type_of,
6464
type_of_opaque: type_of::type_of_opaque,
65+
type_of_assoc_const_binding: type_of::type_of_assoc_const_binding,
6566
type_alias_is_lazy: type_of::type_alias_is_lazy,
6667
item_bounds: item_bounds::item_bounds,
6768
explicit_item_bounds: item_bounds::explicit_item_bounds,

compiler/rustc_hir_analysis/src/collect/type_of.rs

+16-29
Original file line numberDiff line numberDiff line change
@@ -66,35 +66,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
6666
.expect("const parameter types cannot be generic");
6767
}
6868

69-
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
70-
if let Node::TraitRef(trait_ref) = tcx.hir_node(tcx.hir().parent_id(binding_id)) =>
71-
{
72-
let Some(trait_def_id) = trait_ref.trait_def_id() else {
73-
return Ty::new_error_with_message(
74-
tcx,
75-
tcx.def_span(def_id),
76-
"Could not find trait",
77-
);
78-
};
79-
let assoc_items = tcx.associated_items(trait_def_id);
80-
let assoc_item = assoc_items.find_by_name_and_kind(
81-
tcx,
82-
binding.ident,
83-
ty::AssocKind::Const,
84-
def_id.to_def_id(),
85-
);
86-
return if let Some(assoc_item) = assoc_item {
87-
tcx.type_of(assoc_item.def_id)
88-
.no_bound_vars()
89-
.expect("const parameter types cannot be generic")
90-
} else {
91-
// FIXME(associated_const_equality): add a useful error message here.
92-
Ty::new_error_with_message(
93-
tcx,
94-
tcx.def_span(def_id),
95-
"Could not find associated const on trait",
96-
)
97-
};
69+
Node::TypeBinding(&TypeBinding { hir_id, .. }) => {
70+
// FIXME(fmease): Reject “escaping” early-bound generic parameters.
71+
// FIXME(fmease): Reject escaping late-bound vars.
72+
return tcx.type_of_assoc_const_binding(hir_id).skip_binder().skip_binder();
9873
}
9974

10075
// This match arm is for when the def_id appears in a GAT whose
@@ -303,6 +278,18 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
303278
}
304279
}
305280

281+
pub(super) fn type_of_assoc_const_binding<'tcx>(
282+
tcx: TyCtxt<'tcx>,
283+
hir_id: HirId,
284+
) -> ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>> {
285+
let reported = tcx.dcx().delayed_bug(format!(
286+
"attempt to obtain type of assoc const binding `{hir_id}` before \
287+
it was resolved by `add_predicates_for_ast_type_binding`"
288+
));
289+
290+
ty::EarlyBinder::bind(ty::Binder::dummy(Ty::new_error(tcx, reported)))
291+
}
292+
306293
fn get_path_containing_arg_in_pat<'hir>(
307294
pat: &'hir hir::Pat<'hir>,
308295
arg_id: HirId,

compiler/rustc_middle/src/query/erase.rs

+4
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ impl<T: EraseType> EraseType for ty::EarlyBinder<T> {
184184
type Result = T::Result;
185185
}
186186

187+
impl EraseType for ty::Binder<'_, Ty<'_>> {
188+
type Result = [u8; size_of::<ty::Binder<'static, Ty<'static>>>()];
189+
}
190+
187191
impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
188192
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
189193
}

compiler/rustc_middle/src/query/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ rustc_queries! {
255255
cycle_stash
256256
}
257257

258+
query type_of_assoc_const_binding(key: hir::HirId) -> ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>> {
259+
desc { |tcx| "getting type of associated constant binding `{key:?}`" }
260+
feedable
261+
}
262+
258263
query type_alias_is_lazy(key: DefId) -> bool {
259264
desc { |tcx|
260265
"computing whether `{path}` is a lazy type alias",

compiler/rustc_middle/src/ty/context.rs

+17
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ use rustc_type_ir::TyKind::*;
7171
use rustc_type_ir::WithCachedTypeInfo;
7272
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
7373

74+
use std::assert_matches::debug_assert_matches;
7475
use std::borrow::Borrow;
7576
use std::cmp::Ordering;
7677
use std::fmt;
@@ -533,6 +534,22 @@ impl<'tcx> TyCtxt<'tcx> {
533534
debug_assert_eq!(self.def_kind(key), DefKind::AnonConst);
534535
TyCtxtFeed { tcx: self, key }.type_of(value)
535536
}
537+
538+
pub fn feed_type_of_assoc_const_binding(
539+
self,
540+
key: hir::HirId,
541+
value: ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>>,
542+
) {
543+
debug_assert_matches!(
544+
self.hir_node(key),
545+
hir::Node::TypeBinding(hir::TypeBinding {
546+
kind: hir::TypeBindingKind::Equality { term: hir::Term::Const(_) },
547+
..
548+
})
549+
);
550+
551+
TyCtxtFeed { tcx: self, key }.type_of_assoc_const_binding(value)
552+
}
536553
}
537554

538555
impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Regression test for issue #118040.
2+
// Ensure that we support assoc const eq bounds where the assoc const comes from a supertrait.
3+
4+
// check-pass
5+
6+
#![feature(associated_const_equality)]
7+
8+
trait Trait: SuperTrait {}
9+
trait SuperTrait: SuperSuperTrait<i32> {}
10+
trait SuperSuperTrait<T> {
11+
const K: T;
12+
}
13+
14+
fn take(_: impl Trait<K = 0>) {}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
// Regression test for issue #112560.
22
// Respect the fact that (associated) types and constants live in different namespaces and
33
// therefore equality bounds involving identically named associated items don't conflict if
4-
// their kind (type vs. const) differs.
5-
6-
// FIXME(fmease): Extend this test to cover supertraits again
7-
// once #118040 is fixed. See initial version of PR #118360.
4+
// their kind (type vs. const) differs. This obviously extends to supertraits.
85

96
// check-pass
107

118
#![feature(associated_const_equality)]
129

13-
trait Trait {
10+
trait Trait: SuperTrait {
1411
type N;
12+
type Q;
1513

1614
const N: usize;
1715
}
1816

19-
fn take(_: impl Trait<N = 0, N = ()>) {}
17+
trait SuperTrait {
18+
const Q: &'static str;
19+
}
20+
21+
fn take0(_: impl Trait<N = 0, N = ()>) {}
22+
23+
fn take1(_: impl Trait<Q = "...", Q = [()]>) {}
2024

2125
fn main() {}

tests/ui/generic-const-items/associated-const-equality.rs

+3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
trait Owner {
77
const C<const N: u32>: u32;
88
const K<const N: u32>: u32;
9+
const Q<T>: Option<T>;
910
}
1011

1112
impl Owner for () {
1213
const C<const N: u32>: u32 = N;
1314
const K<const N: u32>: u32 = N + 1;
15+
const Q<T>: Option<T> = None;
1416
}
1517

1618
fn take0<const N: u32>(_: impl Owner<C<N> = { N }>) {}
1719
fn take1(_: impl Owner<K<99> = 100>) {}
20+
fn take2(_: impl Owner<Q<()> = { Some(()) }>) {}
1821

1922
fn main() {
2023
take0::<128>(());

0 commit comments

Comments
 (0)