Skip to content

Commit 71d3aed

Browse files
committed
Factor out shared code for lowering assoc item paths
1 parent 9cfc352 commit 71d3aed

File tree

2 files changed

+151
-133
lines changed
  • compiler
    • rustc_hir_analysis/src/hir_ty_lowering
    • rustc_hir_typeck/src/fn_ctxt

2 files changed

+151
-133
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 150 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
5252
use rustc_type_ir::Upcast;
5353
use tracing::{debug, instrument};
5454

55+
use self::errors::assoc_kind_str;
5556
use crate::check::check_abi_fn_ptr;
5657
use crate::errors::{
5758
AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, NoVariantNamed,
@@ -266,6 +267,42 @@ pub enum FeedConstTy<'a, 'tcx> {
266267
No,
267268
}
268269

270+
#[derive(Debug, Clone, Copy)]
271+
enum LowerAssocMode {
272+
Type { permit_variants: bool },
273+
Const,
274+
}
275+
276+
impl LowerAssocMode {
277+
fn kind(self) -> ty::AssocKind {
278+
match self {
279+
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
280+
LowerAssocMode::Const => ty::AssocKind::Const,
281+
}
282+
}
283+
284+
fn def_kind(self) -> DefKind {
285+
match self {
286+
LowerAssocMode::Type { .. } => DefKind::AssocTy,
287+
LowerAssocMode::Const => DefKind::AssocConst,
288+
}
289+
}
290+
291+
fn permit_variants(self) -> bool {
292+
match self {
293+
LowerAssocMode::Type { permit_variants } => permit_variants,
294+
LowerAssocMode::Const => true,
295+
}
296+
}
297+
}
298+
299+
#[derive(Debug, Clone, Copy)]
300+
enum LoweredAssoc<'tcx> {
301+
Type(Ty<'tcx>, DefId),
302+
Variant { adt: Ty<'tcx>, variant_did: DefId },
303+
Const(Const<'tcx>),
304+
}
305+
269306
/// New-typed boolean indicating whether explicit late-bound lifetimes
270307
/// are present in a set of generic arguments.
271308
///
@@ -1138,7 +1175,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11381175
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
11391176
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
11401177
#[instrument(level = "debug", skip_all, ret)]
1141-
pub fn lower_assoc_path(
1178+
pub fn lower_assoc_path_ty(
11421179
&self,
11431180
hir_ref_id: HirId,
11441181
span: Span,
@@ -1147,6 +1184,56 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11471184
assoc_segment: &'tcx hir::PathSegment<'tcx>,
11481185
permit_variants: bool,
11491186
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
1187+
match self.lower_assoc_path_shared(
1188+
hir_ref_id,
1189+
span,
1190+
qself_ty,
1191+
qself,
1192+
assoc_segment,
1193+
LowerAssocMode::Type { permit_variants },
1194+
)? {
1195+
LoweredAssoc::Type(ty, def_id) => Ok((ty, DefKind::AssocTy, def_id)),
1196+
LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
1197+
LoweredAssoc::Const(_) => unreachable!("lowered assoc type to const somehow"),
1198+
}
1199+
}
1200+
1201+
#[instrument(level = "debug", skip_all, ret)]
1202+
fn lower_assoc_path_const(
1203+
&self,
1204+
hir_ref_id: HirId,
1205+
span: Span,
1206+
qself_ty: Ty<'tcx>,
1207+
qself: &'tcx hir::Ty<'tcx>,
1208+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1209+
) -> Result<Const<'tcx>, ErrorGuaranteed> {
1210+
match self.lower_assoc_path_shared(
1211+
hir_ref_id,
1212+
span,
1213+
qself_ty,
1214+
qself,
1215+
assoc_segment,
1216+
LowerAssocMode::Const,
1217+
)? {
1218+
LoweredAssoc::Type(..) => unreachable!("lowered assoc const to type somehow"),
1219+
LoweredAssoc::Variant { adt: _, variant_did } => {
1220+
let uv = ty::UnevaluatedConst::new(variant_did, ty::List::empty());
1221+
Ok(Const::new_unevaluated(self.tcx(), uv))
1222+
}
1223+
LoweredAssoc::Const(ct) => Ok(ct),
1224+
}
1225+
}
1226+
1227+
#[instrument(level = "debug", skip_all, ret)]
1228+
fn lower_assoc_path_shared(
1229+
&self,
1230+
hir_ref_id: HirId,
1231+
span: Span,
1232+
qself_ty: Ty<'tcx>,
1233+
qself: &'tcx hir::Ty<'tcx>,
1234+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1235+
mode: LowerAssocMode,
1236+
) -> Result<LoweredAssoc<'tcx>, ErrorGuaranteed> {
11501237
debug!(%qself_ty, ?assoc_segment.ident);
11511238
let tcx = self.tcx();
11521239

@@ -1161,28 +1248,47 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11611248
.iter()
11621249
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
11631250
if let Some(variant_def) = variant_def {
1164-
if permit_variants {
1251+
if mode.permit_variants() {
11651252
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
11661253
let _ = self.prohibit_generic_args(
11671254
slice::from_ref(assoc_segment).iter(),
11681255
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
11691256
);
1170-
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
1257+
return Ok(LoweredAssoc::Variant {
1258+
adt: qself_ty,
1259+
variant_did: variant_def.def_id,
1260+
});
11711261
} else {
11721262
variant_resolution = Some(variant_def.def_id);
11731263
}
11741264
}
11751265
}
11761266

1177-
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1178-
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1179-
assoc_segment,
1180-
adt_def.did(),
1181-
qself_ty,
1182-
hir_ref_id,
1183-
span,
1184-
)? {
1185-
return Ok((ty, DefKind::AssocTy, did));
1267+
match mode {
1268+
LowerAssocMode::Type { .. } => {
1269+
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1270+
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1271+
assoc_segment,
1272+
adt_def.did(),
1273+
qself_ty,
1274+
hir_ref_id,
1275+
span,
1276+
)? {
1277+
return Ok(LoweredAssoc::Type(ty, did));
1278+
}
1279+
}
1280+
LowerAssocMode::Const => {
1281+
// FIXME(mgca): Support self types other than ADTs.
1282+
if let Some((ct, _)) = self.probe_inherent_assoc_const(
1283+
assoc_segment,
1284+
adt_def.did(),
1285+
qself_ty,
1286+
hir_ref_id,
1287+
span,
1288+
)? {
1289+
return Ok(LoweredAssoc::Const(ct));
1290+
}
1291+
}
11861292
}
11871293
}
11881294

@@ -1211,7 +1317,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12111317
)
12121318
},
12131319
AssocItemQSelf::SelfTyAlias,
1214-
ty::AssocKind::Type,
1320+
mode.kind(),
12151321
assoc_ident,
12161322
span,
12171323
None,
@@ -1223,14 +1329,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12231329
) => self.probe_single_ty_param_bound_for_assoc_item(
12241330
param_did.expect_local(),
12251331
qself.span,
1226-
ty::AssocKind::Type,
1332+
mode.kind(),
12271333
assoc_ident,
12281334
span,
12291335
)?,
12301336
_ => {
1337+
let kind_str = assoc_kind_str(mode.kind());
12311338
let reported = if variant_resolution.is_some() {
12321339
// Variant in type position
1233-
let msg = format!("expected type, found variant `{assoc_ident}`");
1340+
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
12341341
self.dcx().span_err(span, msg)
12351342
} else if qself_ty.is_enum() {
12361343
let mut err = self.dcx().create_err(NoVariantNamed {
@@ -1334,18 +1441,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13341441
&[qself_ty.to_string()],
13351442
&traits,
13361443
assoc_ident.name,
1337-
ty::AssocKind::Type,
1444+
mode.kind(),
13381445
)
13391446
};
13401447
return Err(reported);
13411448
}
13421449
};
13431450

13441451
let trait_did = bound.def_id();
1345-
let assoc_ty = self
1346-
.probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did)
1347-
.expect("failed to find associated type");
1348-
let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound);
1452+
let assoc_item = self
1453+
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
1454+
.expect("failed to find associated item");
1455+
let result = match mode {
1456+
LowerAssocMode::Type { .. } => {
1457+
let assoc_ty = self.lower_assoc_ty(span, assoc_item.def_id, assoc_segment, bound);
1458+
LoweredAssoc::Type(assoc_ty, assoc_item.def_id)
1459+
}
1460+
LowerAssocMode::Const => {
1461+
if assoc_item.has_type_const_attr(tcx) {
1462+
let assoc_ct =
1463+
self.lower_assoc_const(span, assoc_item.def_id, assoc_segment, bound);
1464+
LoweredAssoc::Const(assoc_ct)
1465+
} else {
1466+
let mut err = tcx.dcx().struct_span_err(
1467+
span,
1468+
"use of trait associated const without `#[type_const]`",
1469+
);
1470+
err.note("the declaration in the trait must be marked with `#[type_const]`");
1471+
return Err(err.emit());
1472+
}
1473+
}
1474+
};
13491475

13501476
if let Some(variant_def_id) = variant_resolution {
13511477
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
@@ -1361,7 +1487,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13611487
};
13621488

13631489
could_refer_to(DefKind::Variant, variant_def_id, "");
1364-
could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
1490+
could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
13651491

13661492
lint.span_suggestion(
13671493
span,
@@ -1371,7 +1497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13711497
);
13721498
});
13731499
}
1374-
Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
1500+
Ok(result)
13751501
}
13761502

13771503
fn probe_inherent_assoc_ty(
@@ -2304,7 +2430,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23042430
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
23052431
debug!(?qself, ?segment);
23062432
let ty = self.lower_ty(qself);
2307-
self.lower_const_assoc_path(hir_id, const_arg.span(), ty, qself, segment)
2433+
self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
23082434
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
23092435
}
23102436
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
@@ -2423,114 +2549,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24232549
}
24242550
}
24252551

2426-
#[instrument(level = "debug", skip(self), ret)]
2427-
pub fn lower_const_assoc_path(
2428-
&self,
2429-
hir_ref_id: HirId,
2430-
span: Span,
2431-
qself_ty: Ty<'tcx>,
2432-
qself: &'tcx hir::Ty<'tcx>,
2433-
assoc_segment: &'tcx hir::PathSegment<'tcx>,
2434-
) -> Result<Const<'tcx>, ErrorGuaranteed> {
2435-
debug!(%qself_ty, ?assoc_segment.ident);
2436-
let tcx = self.tcx();
2437-
2438-
let assoc_ident = assoc_segment.ident;
2439-
2440-
// Check if we have an enum variant or an inherent associated const.
2441-
// FIXME(mgca): handle assoc fns once we support those
2442-
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
2443-
if adt_def.is_enum() {
2444-
let variant_def = adt_def
2445-
.variants()
2446-
.iter()
2447-
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
2448-
if let Some(variant_def) = variant_def {
2449-
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
2450-
let _ = self.prohibit_generic_args(
2451-
slice::from_ref(assoc_segment).iter(),
2452-
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
2453-
);
2454-
let uv = ty::UnevaluatedConst::new(variant_def.def_id, ty::List::empty());
2455-
return Ok(Const::new_unevaluated(tcx, uv));
2456-
}
2457-
}
2458-
2459-
// FIXME(mgca): Support self types other than ADTs.
2460-
if let Some((ct, _)) = self.probe_inherent_assoc_const(
2461-
assoc_segment,
2462-
adt_def.did(),
2463-
qself_ty,
2464-
hir_ref_id,
2465-
span,
2466-
)? {
2467-
return Ok(ct);
2468-
}
2469-
}
2470-
2471-
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
2472-
path.res
2473-
} else {
2474-
Res::Err
2475-
};
2476-
2477-
// Find the type of the associated item, and the trait where the associated
2478-
// item is declared.
2479-
let bound_result = match (qself_ty.kind(), qself_res) {
2480-
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
2481-
// `Self` in an impl of a trait -- we have a concrete self type and a
2482-
// trait reference.
2483-
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
2484-
// A cycle error occurred, most likely.
2485-
self.dcx().span_bug(span, "expected cycle error");
2486-
};
2487-
2488-
self.probe_single_bound_for_assoc_item(
2489-
|| {
2490-
traits::supertraits(
2491-
tcx,
2492-
ty::Binder::dummy(trait_ref.instantiate_identity()),
2493-
)
2494-
},
2495-
AssocItemQSelf::SelfTyAlias,
2496-
ty::AssocKind::Const,
2497-
assoc_ident,
2498-
span,
2499-
None,
2500-
)
2501-
}
2502-
(
2503-
&ty::Param(_),
2504-
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
2505-
) => self.probe_single_ty_param_bound_for_assoc_item(
2506-
param_did.expect_local(),
2507-
qself.span,
2508-
ty::AssocKind::Const,
2509-
assoc_ident,
2510-
span,
2511-
),
2512-
_ => panic!("handle errors here"), // FIXME: do this
2513-
};
2514-
let bound = match bound_result {
2515-
Ok(b) => b,
2516-
Err(reported) => return Err(reported),
2517-
};
2518-
2519-
let trait_did = bound.def_id();
2520-
let assoc_const = self
2521-
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
2522-
.expect("failed to find associated const");
2523-
if assoc_const.has_type_const_attr(tcx) {
2524-
Ok(self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound))
2525-
} else {
2526-
let mut err = tcx
2527-
.dcx()
2528-
.struct_span_err(span, "use of trait associated const without `#[type_const]`");
2529-
err.note("the declaration in the trait must be marked with `#[type_const]`");
2530-
Err(err.emit())
2531-
}
2532-
}
2533-
25342552
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
25352553
#[instrument(skip(self), level = "debug")]
25362554
fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
@@ -2730,7 +2748,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
27302748
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
27312749
debug!(?qself, ?segment);
27322750
let ty = self.lower_ty(qself);
2733-
self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
2751+
self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
27342752
.map(|(ty, _, _)| ty)
27352753
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
27362754
}

0 commit comments

Comments
 (0)