Skip to content

Commit 07254c2

Browse files
committed
Factor out shared code for lowering assoc item paths
1 parent cf5e01e commit 07254c2

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,
@@ -263,6 +264,42 @@ pub enum FeedConstTy {
263264
No,
264265
}
265266

267+
#[derive(Debug, Clone, Copy)]
268+
enum LowerAssocMode {
269+
Type { permit_variants: bool },
270+
Const,
271+
}
272+
273+
impl LowerAssocMode {
274+
fn kind(self) -> ty::AssocKind {
275+
match self {
276+
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
277+
LowerAssocMode::Const => ty::AssocKind::Const,
278+
}
279+
}
280+
281+
fn def_kind(self) -> DefKind {
282+
match self {
283+
LowerAssocMode::Type { .. } => DefKind::AssocTy,
284+
LowerAssocMode::Const => DefKind::AssocConst,
285+
}
286+
}
287+
288+
fn permit_variants(self) -> bool {
289+
match self {
290+
LowerAssocMode::Type { permit_variants } => permit_variants,
291+
LowerAssocMode::Const => true,
292+
}
293+
}
294+
}
295+
296+
#[derive(Debug, Clone, Copy)]
297+
enum LoweredAssoc<'tcx> {
298+
Type(Ty<'tcx>, DefId),
299+
Variant { adt: Ty<'tcx>, variant_did: DefId },
300+
Const(Const<'tcx>),
301+
}
302+
266303
/// New-typed boolean indicating whether explicit late-bound lifetimes
267304
/// are present in a set of generic arguments.
268305
///
@@ -1131,7 +1168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11311168
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
11321169
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
11331170
#[instrument(level = "debug", skip_all, ret)]
1134-
pub fn lower_assoc_path(
1171+
pub fn lower_assoc_path_ty(
11351172
&self,
11361173
hir_ref_id: HirId,
11371174
span: Span,
@@ -1140,6 +1177,56 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11401177
assoc_segment: &'tcx hir::PathSegment<'tcx>,
11411178
permit_variants: bool,
11421179
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
1180+
match self.lower_assoc_path_shared(
1181+
hir_ref_id,
1182+
span,
1183+
qself_ty,
1184+
qself,
1185+
assoc_segment,
1186+
LowerAssocMode::Type { permit_variants },
1187+
)? {
1188+
LoweredAssoc::Type(ty, def_id) => Ok((ty, DefKind::AssocTy, def_id)),
1189+
LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
1190+
LoweredAssoc::Const(_) => unreachable!("lowered assoc type to const somehow"),
1191+
}
1192+
}
1193+
1194+
#[instrument(level = "debug", skip_all, ret)]
1195+
fn lower_assoc_path_const(
1196+
&self,
1197+
hir_ref_id: HirId,
1198+
span: Span,
1199+
qself_ty: Ty<'tcx>,
1200+
qself: &'tcx hir::Ty<'tcx>,
1201+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1202+
) -> Result<Const<'tcx>, ErrorGuaranteed> {
1203+
match self.lower_assoc_path_shared(
1204+
hir_ref_id,
1205+
span,
1206+
qself_ty,
1207+
qself,
1208+
assoc_segment,
1209+
LowerAssocMode::Const,
1210+
)? {
1211+
LoweredAssoc::Type(..) => unreachable!("lowered assoc const to type somehow"),
1212+
LoweredAssoc::Variant { adt: _, variant_did } => {
1213+
let uv = ty::UnevaluatedConst::new(variant_did, ty::List::empty());
1214+
Ok(Const::new_unevaluated(self.tcx(), uv))
1215+
}
1216+
LoweredAssoc::Const(ct) => Ok(ct),
1217+
}
1218+
}
1219+
1220+
#[instrument(level = "debug", skip_all, ret)]
1221+
fn lower_assoc_path_shared(
1222+
&self,
1223+
hir_ref_id: HirId,
1224+
span: Span,
1225+
qself_ty: Ty<'tcx>,
1226+
qself: &'tcx hir::Ty<'tcx>,
1227+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1228+
mode: LowerAssocMode,
1229+
) -> Result<LoweredAssoc<'tcx>, ErrorGuaranteed> {
11431230
debug!(%qself_ty, ?assoc_segment.ident);
11441231
let tcx = self.tcx();
11451232

@@ -1154,28 +1241,47 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11541241
.iter()
11551242
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
11561243
if let Some(variant_def) = variant_def {
1157-
if permit_variants {
1244+
if mode.permit_variants() {
11581245
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
11591246
let _ = self.prohibit_generic_args(
11601247
slice::from_ref(assoc_segment).iter(),
11611248
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
11621249
);
1163-
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
1250+
return Ok(LoweredAssoc::Variant {
1251+
adt: qself_ty,
1252+
variant_did: variant_def.def_id,
1253+
});
11641254
} else {
11651255
variant_resolution = Some(variant_def.def_id);
11661256
}
11671257
}
11681258
}
11691259

1170-
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1171-
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1172-
assoc_segment,
1173-
adt_def.did(),
1174-
qself_ty,
1175-
hir_ref_id,
1176-
span,
1177-
)? {
1178-
return Ok((ty, DefKind::AssocTy, did));
1260+
match mode {
1261+
LowerAssocMode::Type { .. } => {
1262+
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1263+
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1264+
assoc_segment,
1265+
adt_def.did(),
1266+
qself_ty,
1267+
hir_ref_id,
1268+
span,
1269+
)? {
1270+
return Ok(LoweredAssoc::Type(ty, did));
1271+
}
1272+
}
1273+
LowerAssocMode::Const => {
1274+
// FIXME(mgca): Support self types other than ADTs.
1275+
if let Some((ct, _)) = self.probe_inherent_assoc_const(
1276+
assoc_segment,
1277+
adt_def.did(),
1278+
qself_ty,
1279+
hir_ref_id,
1280+
span,
1281+
)? {
1282+
return Ok(LoweredAssoc::Const(ct));
1283+
}
1284+
}
11791285
}
11801286
}
11811287

@@ -1204,7 +1310,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12041310
)
12051311
},
12061312
AssocItemQSelf::SelfTyAlias,
1207-
ty::AssocKind::Type,
1313+
mode.kind(),
12081314
assoc_ident,
12091315
span,
12101316
None,
@@ -1216,14 +1322,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12161322
) => self.probe_single_ty_param_bound_for_assoc_item(
12171323
param_did.expect_local(),
12181324
qself.span,
1219-
ty::AssocKind::Type,
1325+
mode.kind(),
12201326
assoc_ident,
12211327
span,
12221328
)?,
12231329
_ => {
1330+
let kind_str = assoc_kind_str(mode.kind());
12241331
let reported = if variant_resolution.is_some() {
12251332
// Variant in type position
1226-
let msg = format!("expected type, found variant `{assoc_ident}`");
1333+
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
12271334
self.dcx().span_err(span, msg)
12281335
} else if qself_ty.is_enum() {
12291336
let mut err = self.dcx().create_err(NoVariantNamed {
@@ -1328,18 +1435,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13281435
&[qself_ty.to_string()],
13291436
&traits,
13301437
assoc_ident.name,
1331-
ty::AssocKind::Type,
1438+
mode.kind(),
13321439
)
13331440
};
13341441
return Err(reported);
13351442
}
13361443
};
13371444

13381445
let trait_did = bound.def_id();
1339-
let assoc_ty = self
1340-
.probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did)
1341-
.expect("failed to find associated type");
1342-
let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound);
1446+
let assoc_item = self
1447+
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
1448+
.expect("failed to find associated item");
1449+
let result = match mode {
1450+
LowerAssocMode::Type { .. } => {
1451+
let assoc_ty = self.lower_assoc_ty(span, assoc_item.def_id, assoc_segment, bound);
1452+
LoweredAssoc::Type(assoc_ty, assoc_item.def_id)
1453+
}
1454+
LowerAssocMode::Const => {
1455+
if assoc_item.has_type_const_attr(tcx) {
1456+
let assoc_ct =
1457+
self.lower_assoc_const(span, assoc_item.def_id, assoc_segment, bound);
1458+
LoweredAssoc::Const(assoc_ct)
1459+
} else {
1460+
let mut err = tcx.dcx().struct_span_err(
1461+
span,
1462+
"use of trait associated const without `#[type_const]`",
1463+
);
1464+
err.note("the declaration in the trait must be marked with `#[type_const]`");
1465+
return Err(err.emit());
1466+
}
1467+
}
1468+
};
13431469

13441470
if let Some(variant_def_id) = variant_resolution {
13451471
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
@@ -1355,7 +1481,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13551481
};
13561482

13571483
could_refer_to(DefKind::Variant, variant_def_id, "");
1358-
could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
1484+
could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
13591485

13601486
lint.span_suggestion(
13611487
span,
@@ -1365,7 +1491,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13651491
);
13661492
});
13671493
}
1368-
Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
1494+
Ok(result)
13691495
}
13701496

13711497
fn probe_inherent_assoc_ty(
@@ -2263,7 +2389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22632389
hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
22642390
debug!(?qself, ?segment);
22652391
let ty = self.lower_ty(qself);
2266-
self.lower_const_assoc_path(hir_id, const_arg.span(), ty, qself, segment)
2392+
self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
22672393
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
22682394
}
22692395
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
@@ -2382,114 +2508,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23822508
}
23832509
}
23842510

2385-
#[instrument(level = "debug", skip(self), ret)]
2386-
pub fn lower_const_assoc_path(
2387-
&self,
2388-
hir_ref_id: HirId,
2389-
span: Span,
2390-
qself_ty: Ty<'tcx>,
2391-
qself: &'tcx hir::Ty<'tcx>,
2392-
assoc_segment: &'tcx hir::PathSegment<'tcx>,
2393-
) -> Result<Const<'tcx>, ErrorGuaranteed> {
2394-
debug!(%qself_ty, ?assoc_segment.ident);
2395-
let tcx = self.tcx();
2396-
2397-
let assoc_ident = assoc_segment.ident;
2398-
2399-
// Check if we have an enum variant or an inherent associated const.
2400-
// FIXME(mgca): handle assoc fns once we support those
2401-
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
2402-
if adt_def.is_enum() {
2403-
let variant_def = adt_def
2404-
.variants()
2405-
.iter()
2406-
.find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
2407-
if let Some(variant_def) = variant_def {
2408-
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
2409-
let _ = self.prohibit_generic_args(
2410-
slice::from_ref(assoc_segment).iter(),
2411-
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
2412-
);
2413-
let uv = ty::UnevaluatedConst::new(variant_def.def_id, ty::List::empty());
2414-
return Ok(Const::new_unevaluated(tcx, uv));
2415-
}
2416-
}
2417-
2418-
// FIXME(mgca): Support self types other than ADTs.
2419-
if let Some((ct, _)) = self.probe_inherent_assoc_const(
2420-
assoc_segment,
2421-
adt_def.did(),
2422-
qself_ty,
2423-
hir_ref_id,
2424-
span,
2425-
)? {
2426-
return Ok(ct);
2427-
}
2428-
}
2429-
2430-
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
2431-
path.res
2432-
} else {
2433-
Res::Err
2434-
};
2435-
2436-
// Find the type of the associated item, and the trait where the associated
2437-
// item is declared.
2438-
let bound_result = match (qself_ty.kind(), qself_res) {
2439-
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
2440-
// `Self` in an impl of a trait -- we have a concrete self type and a
2441-
// trait reference.
2442-
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
2443-
// A cycle error occurred, most likely.
2444-
self.dcx().span_bug(span, "expected cycle error");
2445-
};
2446-
2447-
self.probe_single_bound_for_assoc_item(
2448-
|| {
2449-
traits::supertraits(
2450-
tcx,
2451-
ty::Binder::dummy(trait_ref.instantiate_identity()),
2452-
)
2453-
},
2454-
AssocItemQSelf::SelfTyAlias,
2455-
ty::AssocKind::Const,
2456-
assoc_ident,
2457-
span,
2458-
None,
2459-
)
2460-
}
2461-
(
2462-
&ty::Param(_),
2463-
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
2464-
) => self.probe_single_ty_param_bound_for_assoc_item(
2465-
param_did.expect_local(),
2466-
qself.span,
2467-
ty::AssocKind::Const,
2468-
assoc_ident,
2469-
span,
2470-
),
2471-
_ => panic!("handle errors here"), // FIXME: do this
2472-
};
2473-
let bound = match bound_result {
2474-
Ok(b) => b,
2475-
Err(reported) => return Err(reported),
2476-
};
2477-
2478-
let trait_did = bound.def_id();
2479-
let assoc_const = self
2480-
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
2481-
.expect("failed to find associated const");
2482-
if assoc_const.has_type_const_attr(tcx) {
2483-
Ok(self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound))
2484-
} else {
2485-
let mut err = tcx
2486-
.dcx()
2487-
.struct_span_err(span, "use of trait associated const without `#[type_const]`");
2488-
err.note("the declaration in the trait must be marked with `#[type_const]`");
2489-
Err(err.emit())
2490-
}
2491-
}
2492-
24932511
/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
24942512
#[instrument(skip(self), level = "debug")]
24952513
fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> {
@@ -2689,7 +2707,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
26892707
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
26902708
debug!(?qself, ?segment);
26912709
let ty = self.lower_ty(qself);
2692-
self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
2710+
self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
26932711
.map(|(ty, _, _)| ty)
26942712
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
26952713
}

0 commit comments

Comments
 (0)