Skip to content

Commit 4c0addc

Browse files
committed
Check supertraits and gen args when resolving anon consts in assoc const eq bounds
1 parent a191610 commit 4c0addc

File tree

4 files changed

+85
-23
lines changed

4 files changed

+85
-23
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
345345
/// type itself: `['a]`. The returned `GenericArgsRef` concatenates these two
346346
/// lists: `[Vec<u8>, u8, 'a]`.
347347
#[instrument(level = "debug", skip(self, span), ret)]
348-
fn create_args_for_ast_path<'a>(
348+
pub(crate) fn create_args_for_ast_path<'a>(
349349
&self,
350350
span: Span,
351351
def_id: DefId,

compiler/rustc_hir_analysis/src/collect/type_of.rs

+65-22
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ use rustc_middle::ty::util::IntTypeExt;
88
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
99
use rustc_span::symbol::Ident;
1010
use rustc_span::{Span, DUMMY_SP};
11+
use rustc_trait_selection::traits;
1112

12-
use super::ItemCtxt;
1313
use super::{bad_placeholder, is_suggestable_infer_ty};
14+
use super::{AstConv, ItemCtxt};
1415
pub use opaque::test_opaque_hidden_types;
1516

1617
mod opaque;
@@ -60,35 +61,78 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
6061
.expect("const parameter types cannot be generic");
6162
}
6263

63-
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
64-
if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(binding_id)) =>
65-
{
64+
Node::TypeBinding(
65+
binding @ &TypeBinding { hir_id: binding_id, ident, gen_args, span, .. },
66+
) if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(binding_id)) => {
6667
let Some(trait_def_id) = trait_ref.trait_def_id() else {
6768
return Ty::new_error_with_message(
6869
tcx,
6970
tcx.def_span(def_id),
70-
"Could not find trait",
71+
"could not find trait",
7172
);
7273
};
73-
let assoc_items = tcx.associated_items(trait_def_id);
74-
let assoc_item = assoc_items.find_by_name_and_kind(
75-
tcx,
76-
binding.ident,
77-
ty::AssocKind::Const,
78-
def_id.to_def_id(),
74+
75+
// FIXME(associated_const_equality): We're now performing a full but ad-hoc type-based
76+
// resolution of the associated constant. Doing all this work *here* isn't great.
77+
// Ideally, we would've computed this already somewhere else (in a query?).
78+
79+
let icx = ItemCtxt::new(tcx, def_id);
80+
let trait_segment = trait_ref.path.segments.last().unwrap();
81+
let (trait_args, _) = icx.astconv().create_args_for_ast_path(
82+
trait_ref.path.span,
83+
trait_def_id,
84+
&[],
85+
trait_segment,
86+
trait_segment.args(),
87+
trait_segment.infer_args,
88+
// FIXME(associated_const_equality): This isn't correct, it should be the concrete /
89+
// instantiated self type. Theoretically, we could search for it in the HIR of the
90+
// parent item but that's super fragile and hairy.
91+
Some(tcx.types.self_param),
92+
ty::BoundConstness::NotConst,
7993
);
80-
return if let Some(assoc_item) = assoc_item {
81-
tcx.type_of(assoc_item.def_id)
82-
.no_bound_vars()
83-
.expect("const parameter types cannot be generic")
84-
} else {
85-
// FIXME(associated_const_equality): add a useful error message here.
86-
Ty::new_error_with_message(
94+
let trait_ref = ty::Binder::bind_with_vars(
95+
ty::TraitRef::new(tcx, trait_def_id, trait_args),
96+
tcx.late_bound_vars(trait_ref.hir_ref_id),
97+
);
98+
99+
// We shouldn't need to deal with ambiguity since `add_predicates_for_ast_type_binding`
100+
// should've already bailed out early in such case.
101+
let Some((assoc_item, parent_args)) =
102+
traits::supertraits(tcx, trait_ref).find_map(|trait_ref| {
103+
tcx.associated_items(trait_ref.def_id())
104+
.find_by_name_and_kind(
105+
tcx,
106+
binding.ident,
107+
ty::AssocKind::Const,
108+
trait_ref.def_id(),
109+
)
110+
// FIXME(fmease): `skip_binder` is fishy!
111+
.map(|item| (item, trait_ref.skip_binder().args))
112+
})
113+
else {
114+
return Ty::new_error_with_message(
87115
tcx,
88116
tcx.def_span(def_id),
89-
"Could not find associated const on trait",
90-
)
117+
"could not find associated const on trait",
118+
);
91119
};
120+
121+
let args = icx.astconv().create_args_for_associated_item(
122+
span,
123+
assoc_item.def_id,
124+
// FIXME(fmease): This is gross as hell!
125+
&hir::PathSegment {
126+
ident,
127+
hir_id,
128+
res: def::Res::Def(def::DefKind::AssocConst, assoc_item.def_id),
129+
args: Some(gen_args),
130+
infer_args: false,
131+
},
132+
parent_args,
133+
);
134+
135+
return tcx.type_of(assoc_item.def_id).instantiate(tcx, args);
92136
}
93137

94138
// This match arm is for when the def_id appears in a GAT whose
@@ -120,8 +164,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
120164
.unwrap()
121165
.0
122166
.def_id;
123-
let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
124-
let ty = item_ctxt.ast_ty_to_ty(hir_ty);
167+
let ty = ItemCtxt::new(tcx, item_def_id).to_ty(hir_ty);
125168

126169
// Iterate through the generics of the projection to find the one that corresponds to
127170
// the def_id that this query was called with. We filter to only type and const args here
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() {}

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)