Skip to content

Commit 41f18e3

Browse files
committed
Properly lower assoc consts from traits
1 parent 04787ce commit 41f18e3

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

534+
fn lower_assoc_const(
535+
&self,
536+
span: Span,
537+
item_def_id: DefId,
538+
item_segment: &hir::PathSegment<'tcx>,
539+
poly_trait_ref: ty::PolyTraitRef<'tcx>,
540+
) -> Const<'tcx> {
541+
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
542+
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
543+
span,
544+
item_def_id,
545+
item_segment,
546+
trait_ref.args,
547+
);
548+
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
549+
Const::new_unevaluated(self.tcx(), uv)
550+
} else {
551+
// There are no late-bound regions; we can just ignore the binder.
552+
let (mut mpart_sugg, mut inferred_sugg) = (None, None);
553+
let mut bound = String::new();
554+
555+
match self.node() {
556+
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
557+
let item = self
558+
.tcx
559+
.hir()
560+
.expect_item(self.tcx.hir().get_parent_item(self.hir_id()).def_id);
561+
match &item.kind {
562+
hir::ItemKind::Enum(_, generics)
563+
| hir::ItemKind::Struct(_, generics)
564+
| hir::ItemKind::Union(_, generics) => {
565+
let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
566+
let (lt_sp, sugg) = match generics.params {
567+
[] => (generics.span, format!("<{lt_name}>")),
568+
[bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")),
569+
};
570+
mpart_sugg = Some(errors::AssociatedItemTraitUninferredGenericParamsMultipartSuggestion {
571+
fspan: lt_sp,
572+
first: sugg,
573+
sspan: span.with_hi(item_segment.ident.span.lo()),
574+
second: format!(
575+
"{}::",
576+
// Replace the existing lifetimes with a new named lifetime.
577+
self.tcx.instantiate_bound_regions_uncached(
578+
poly_trait_ref,
579+
|_| {
580+
ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion {
581+
index: 0,
582+
name: Symbol::intern(&lt_name),
583+
})
584+
}
585+
),
586+
),
587+
});
588+
}
589+
_ => {}
590+
}
591+
}
592+
hir::Node::Item(hir::Item {
593+
kind:
594+
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..),
595+
..
596+
}) => {}
597+
hir::Node::Item(_)
598+
| hir::Node::ForeignItem(_)
599+
| hir::Node::TraitItem(_)
600+
| hir::Node::ImplItem(_) => {
601+
inferred_sugg = Some(span.with_hi(item_segment.ident.span.lo()));
602+
bound = format!(
603+
"{}::",
604+
// Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
605+
self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(),
606+
);
607+
}
608+
_ => {}
609+
}
610+
Const::new_error(
611+
self.tcx(),
612+
self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
613+
span,
614+
inferred_sugg,
615+
bound,
616+
mpart_sugg,
617+
what: "const",
618+
}),
619+
)
620+
}
621+
}
622+
534623
fn probe_adt(&self, _span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
535624
// FIXME(#103640): Should we handle the case where `ty` is a projection?
536625
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
@@ -152,7 +152,7 @@ pub trait HirTyLowerer<'tcx> {
152152
assoc_name: Ident,
153153
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
154154

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

175+
/// Lower an associated constant (from a trait) to a [`ty::Const`].
176+
fn lower_assoc_const(
177+
&self,
178+
span: Span,
179+
item_def_id: DefId,
180+
item_segment: &hir::PathSegment<'tcx>,
181+
poly_trait_ref: ty::PolyTraitRef<'tcx>,
182+
) -> Const<'tcx>;
183+
175184
fn lower_fn_sig(
176185
&self,
177186
decl: &hir::FnDecl<'tcx>,
@@ -2315,16 +2324,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23152324
span,
23162325
impl_,
23172326
)
2327+
.map(|assoc| (impl_, assoc))
23182328
})
23192329
.collect::<Vec<_>>();
23202330
match &candidates[..] {
23212331
[] => {}
2322-
[assoc] => {
2323-
// FIXME: this is not necessarily correct.
2324-
// adapted from other code that also had a fixme about it being temporary.
2325-
let parent_args =
2326-
ty::GenericArgs::identity_for_item(tcx, tcx.parent(assoc.def_id));
2327-
return self.lower_assoc_const(span, assoc.def_id, assoc_segment, parent_args);
2332+
&[(impl_, assoc)] => {
2333+
// FIXME(min_generic_const_args): adapted from temporary inherent assoc ty code that may be incorrect
2334+
let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
2335+
let args = self.lower_generic_args_of_assoc_item(
2336+
span,
2337+
assoc.def_id,
2338+
assoc_segment,
2339+
parent_args,
2340+
);
2341+
let uv = ty::UnevaluatedConst::new(assoc.def_id, args);
2342+
return Const::new_unevaluated(tcx, uv);
23282343
}
23292344
[..] => {
23302345
return Const::new_error_with_message(tcx, span, "ambiguous assoc const path");
@@ -2384,23 +2399,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23842399
let assoc_const = self
23852400
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
23862401
.expect("failed to find associated const");
2387-
// FIXME: don't use no_bound_vars probably
2388-
let trait_ref_args = bound.no_bound_vars().unwrap().args;
2389-
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, trait_ref_args)
2390-
}
2391-
2392-
fn lower_assoc_const(
2393-
&self,
2394-
span: Span,
2395-
item_def_id: DefId,
2396-
item_segment: &hir::PathSegment<'tcx>,
2397-
parent_args: GenericArgsRef<'tcx>,
2398-
) -> Const<'tcx> {
2399-
let tcx = self.tcx();
2400-
let args =
2401-
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, parent_args);
2402-
let uv = ty::UnevaluatedConst::new(item_def_id, args);
2403-
Const::new_unevaluated(tcx, uv)
2402+
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound)
24042403
}
24052404

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