Skip to content

Commit 214fd98

Browse files
committed
Properly lower assoc consts from traits
1 parent 968cfaf commit 214fd98

File tree

3 files changed

+136
-24
lines changed

3 files changed

+136
-24
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,95 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
549549
}
550550
}
551551

552+
fn lower_assoc_const(
553+
&self,
554+
span: Span,
555+
item_def_id: DefId,
556+
item_segment: &hir::PathSegment<'tcx>,
557+
poly_trait_ref: ty::PolyTraitRef<'tcx>,
558+
) -> Const<'tcx> {
559+
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
560+
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
561+
span,
562+
item_def_id,
563+
item_segment,
564+
trait_ref.args,
565+
);
566+
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
567+
Const::new_unevaluated(self.tcx(), uv)
568+
} else {
569+
// There are no late-bound regions; we can just ignore the binder.
570+
let (mut mpart_sugg, mut inferred_sugg) = (None, None);
571+
let mut bound = String::new();
572+
573+
match self.node() {
574+
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
575+
let item = self
576+
.tcx
577+
.hir()
578+
.expect_item(self.tcx.hir().get_parent_item(self.hir_id()).def_id);
579+
match &item.kind {
580+
hir::ItemKind::Enum(_, generics)
581+
| hir::ItemKind::Struct(_, generics)
582+
| hir::ItemKind::Union(_, generics) => {
583+
let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
584+
let (lt_sp, sugg) = match generics.params {
585+
[] => (generics.span, format!("<{lt_name}>")),
586+
[bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")),
587+
};
588+
mpart_sugg = Some(errors::AssociatedItemTraitUninferredGenericParamsMultipartSuggestion {
589+
fspan: lt_sp,
590+
first: sugg,
591+
sspan: span.with_hi(item_segment.ident.span.lo()),
592+
second: format!(
593+
"{}::",
594+
// Replace the existing lifetimes with a new named lifetime.
595+
self.tcx.instantiate_bound_regions_uncached(
596+
poly_trait_ref,
597+
|_| {
598+
ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion {
599+
index: 0,
600+
name: Symbol::intern(&lt_name),
601+
})
602+
}
603+
),
604+
),
605+
});
606+
}
607+
_ => {}
608+
}
609+
}
610+
hir::Node::Item(hir::Item {
611+
kind:
612+
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..),
613+
..
614+
}) => {}
615+
hir::Node::Item(_)
616+
| hir::Node::ForeignItem(_)
617+
| hir::Node::TraitItem(_)
618+
| hir::Node::ImplItem(_) => {
619+
inferred_sugg = Some(span.with_hi(item_segment.ident.span.lo()));
620+
bound = format!(
621+
"{}::",
622+
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
623+
self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
624+
);
625+
}
626+
_ => {}
627+
}
628+
Const::new_error(
629+
self.tcx(),
630+
self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
631+
span,
632+
inferred_sugg,
633+
bound,
634+
mpart_sugg,
635+
what: "const",
636+
}),
637+
)
638+
}
639+
}
640+
552641
fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
553642
// FIXME(#103640): Should we handle the case where `ty` is a projection?
554643
ty.ty_adt_def()

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ pub trait HirTyLowerer<'tcx> {
150150
assoc_name: Ident,
151151
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
152152

153-
/// Lower an associated type to a projection.
153+
/// Lower an associated type (from a trait) to a projection.
154154
///
155155
/// This method has to be defined by the concrete lowering context because
156156
/// dealing with higher-ranked trait references depends on its capabilities:
@@ -170,6 +170,15 @@ pub trait HirTyLowerer<'tcx> {
170170
poly_trait_ref: ty::PolyTraitRef<'tcx>,
171171
) -> Ty<'tcx>;
172172

173+
/// Lower an associated constant (from a trait) to a [`ty::Const`].
174+
fn lower_assoc_const(
175+
&self,
176+
span: Span,
177+
item_def_id: DefId,
178+
item_segment: &hir::PathSegment<'tcx>,
179+
poly_trait_ref: ty::PolyTraitRef<'tcx>,
180+
) -> Const<'tcx>;
181+
173182
fn lower_fn_sig(
174183
&self,
175184
decl: &hir::FnDecl<'tcx>,
@@ -2253,16 +2262,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22532262
span,
22542263
impl_,
22552264
)
2265+
.map(|assoc| (impl_, assoc))
22562266
})
22572267
.collect::<Vec<_>>();
22582268
match &candidates[..] {
22592269
[] => {}
2260-
[assoc] => {
2261-
// FIXME: this is not necessarily correct.
2262-
// adapted from other code that also had a fixme about it being temporary.
2263-
let parent_args =
2264-
ty::GenericArgs::identity_for_item(tcx, tcx.parent(assoc.def_id));
2265-
return self.lower_assoc_const(span, assoc.def_id, assoc_segment, parent_args);
2270+
&[(impl_, assoc)] => {
2271+
// FIXME(min_generic_const_args): adapted from temporary inherent assoc ty code that may be incorrect
2272+
let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
2273+
let args = self.lower_generic_args_of_assoc_item(
2274+
span,
2275+
assoc.def_id,
2276+
assoc_segment,
2277+
parent_args,
2278+
);
2279+
let uv = ty::UnevaluatedConst::new(assoc.def_id, args);
2280+
return Const::new_unevaluated(tcx, uv);
22662281
}
22672282
[..] => {
22682283
return Const::new_error_with_message(tcx, span, "ambiguous assoc const path");
@@ -2322,23 +2337,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23222337
let assoc_const = self
23232338
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
23242339
.expect("failed to find associated const");
2325-
// FIXME: don't use no_bound_vars probably
2326-
let trait_ref_args = bound.no_bound_vars().unwrap().args;
2327-
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, trait_ref_args)
2328-
}
2329-
2330-
fn lower_assoc_const(
2331-
&self,
2332-
span: Span,
2333-
item_def_id: DefId,
2334-
item_segment: &hir::PathSegment<'tcx>,
2335-
parent_args: GenericArgsRef<'tcx>,
2336-
) -> Const<'tcx> {
2337-
let tcx = self.tcx();
2338-
let args =
2339-
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, parent_args);
2340-
let uv = ty::UnevaluatedConst::new(item_def_id, args);
2341-
Const::new_unevaluated(tcx, uv)
2340+
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound)
23422341
}
23432342

23442343
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,30 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
331331
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
332332
}
333333

334+
fn lower_assoc_const(
335+
&self,
336+
span: Span,
337+
item_def_id: DefId,
338+
item_segment: &hir::PathSegment<'tcx>,
339+
poly_trait_ref: ty::PolyTraitRef<'tcx>,
340+
) -> Const<'tcx> {
341+
let trait_ref = self.instantiate_binder_with_fresh_vars(
342+
span,
343+
// FIXME(min_generic_const_args): this should be assoc const not assoc type
344+
infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
345+
poly_trait_ref,
346+
);
347+
348+
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
349+
span,
350+
item_def_id,
351+
item_segment,
352+
trait_ref.args,
353+
);
354+
355+
Const::new_unevaluated(self.tcx(), ty::UnevaluatedConst::new(item_def_id, item_args))
356+
}
357+
334358
fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
335359
match ty.kind() {
336360
ty::Adt(adt_def, _) => Some(*adt_def),

0 commit comments

Comments
 (0)