Skip to content

Commit e3ed159

Browse files
committed
Properly lower assoc consts from traits
1 parent 9647496 commit e3ed159

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
@@ -532,6 +532,95 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
532532
}
533533
}
534534

535+
fn lower_assoc_const(
536+
&self,
537+
span: Span,
538+
item_def_id: DefId,
539+
item_segment: &hir::PathSegment<'tcx>,
540+
poly_trait_ref: ty::PolyTraitRef<'tcx>,
541+
) -> Const<'tcx> {
542+
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
543+
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
544+
span,
545+
item_def_id,
546+
item_segment,
547+
trait_ref.args,
548+
);
549+
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
550+
Const::new_unevaluated(self.tcx(), uv)
551+
} else {
552+
// There are no late-bound regions; we can just ignore the binder.
553+
let (mut mpart_sugg, mut inferred_sugg) = (None, None);
554+
let mut bound = String::new();
555+
556+
match self.node() {
557+
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
558+
let item = self
559+
.tcx
560+
.hir()
561+
.expect_item(self.tcx.hir().get_parent_item(self.hir_id()).def_id);
562+
match &item.kind {
563+
hir::ItemKind::Enum(_, generics)
564+
| hir::ItemKind::Struct(_, generics)
565+
| hir::ItemKind::Union(_, generics) => {
566+
let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
567+
let (lt_sp, sugg) = match generics.params {
568+
[] => (generics.span, format!("<{lt_name}>")),
569+
[bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")),
570+
};
571+
mpart_sugg = Some(errors::AssociatedItemTraitUninferredGenericParamsMultipartSuggestion {
572+
fspan: lt_sp,
573+
first: sugg,
574+
sspan: span.with_hi(item_segment.ident.span.lo()),
575+
second: format!(
576+
"{}::",
577+
// Replace the existing lifetimes with a new named lifetime.
578+
self.tcx.instantiate_bound_regions_uncached(
579+
poly_trait_ref,
580+
|_| {
581+
ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion {
582+
index: 0,
583+
name: Symbol::intern(&lt_name),
584+
})
585+
}
586+
),
587+
),
588+
});
589+
}
590+
_ => {}
591+
}
592+
}
593+
hir::Node::Item(hir::Item {
594+
kind:
595+
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..),
596+
..
597+
}) => {}
598+
hir::Node::Item(_)
599+
| hir::Node::ForeignItem(_)
600+
| hir::Node::TraitItem(_)
601+
| hir::Node::ImplItem(_) => {
602+
inferred_sugg = Some(span.with_hi(item_segment.ident.span.lo()));
603+
bound = format!(
604+
"{}::",
605+
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
606+
self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
607+
);
608+
}
609+
_ => {}
610+
}
611+
Const::new_error(
612+
self.tcx(),
613+
self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
614+
span,
615+
inferred_sugg,
616+
bound,
617+
mpart_sugg,
618+
what: "const",
619+
}),
620+
)
621+
}
622+
}
623+
535624
fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
536625
// FIXME(#103640): Should we handle the case where `ty` is a projection?
537626
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>,
@@ -2254,16 +2263,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22542263
span,
22552264
impl_,
22562265
)
2266+
.map(|assoc| (impl_, assoc))
22572267
})
22582268
.collect::<Vec<_>>();
22592269
match &candidates[..] {
22602270
[] => {}
2261-
[assoc] => {
2262-
// FIXME: this is not necessarily correct.
2263-
// adapted from other code that also had a fixme about it being temporary.
2264-
let parent_args =
2265-
ty::GenericArgs::identity_for_item(tcx, tcx.parent(assoc.def_id));
2266-
return self.lower_assoc_const(span, assoc.def_id, assoc_segment, parent_args);
2271+
&[(impl_, assoc)] => {
2272+
// FIXME(min_generic_const_args): adapted from temporary inherent assoc ty code that may be incorrect
2273+
let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
2274+
let args = self.lower_generic_args_of_assoc_item(
2275+
span,
2276+
assoc.def_id,
2277+
assoc_segment,
2278+
parent_args,
2279+
);
2280+
let uv = ty::UnevaluatedConst::new(assoc.def_id, args);
2281+
return Const::new_unevaluated(tcx, uv);
22672282
}
22682283
[..] => {
22692284
return Const::new_error_with_message(tcx, span, "ambiguous assoc const path");
@@ -2323,23 +2338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23232338
let assoc_const = self
23242339
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
23252340
.expect("failed to find associated const");
2326-
// FIXME: don't use no_bound_vars probably
2327-
let trait_ref_args = bound.no_bound_vars().unwrap().args;
2328-
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, trait_ref_args)
2329-
}
2330-
2331-
fn lower_assoc_const(
2332-
&self,
2333-
span: Span,
2334-
item_def_id: DefId,
2335-
item_segment: &hir::PathSegment<'tcx>,
2336-
parent_args: GenericArgsRef<'tcx>,
2337-
) -> Const<'tcx> {
2338-
let tcx = self.tcx();
2339-
let args =
2340-
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, parent_args);
2341-
let uv = ty::UnevaluatedConst::new(item_def_id, args);
2342-
Const::new_unevaluated(tcx, uv)
2341+
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound)
23432342
}
23442343

23452344
/// 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)