Skip to content

Commit 695fcf5

Browse files
committed
Factor out resolve_type_relative_path
IMPORTANT: This leads to a tiny diagnostic regression that will be fixed in the next commit!
1 parent 9e486fd commit 695fcf5

File tree

3 files changed

+130
-152
lines changed

3 files changed

+130
-152
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

+37-104
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
44
use rustc_errors::codes::*;
55
use rustc_errors::struct_span_code_err;
66
use rustc_hir as hir;
7+
use rustc_hir::AmbigArg;
78
use rustc_hir::def::{DefKind, Res};
89
use rustc_hir::def_id::{DefId, LocalDefId};
9-
use rustc_hir::{AmbigArg, HirId};
1010
use rustc_middle::bug;
1111
use rustc_middle::ty::{
1212
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -713,118 +713,51 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
713713
Err(guar) => Ty::new_error(tcx, guar),
714714
}
715715
}
716-
hir::QPath::TypeRelative(qself, item_segment)
717-
if item_segment.args.is_some_and(|args| {
716+
hir::QPath::TypeRelative(hir_self_ty, segment)
717+
if segment.args.is_some_and(|args| {
718718
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
719719
}) =>
720720
{
721-
match self
722-
.resolve_type_relative_return_type_notation(
723-
qself,
724-
item_segment,
725-
hir_ty.hir_id,
726-
hir_ty.span,
727-
)
728-
.and_then(|(candidate, item_def_id)| {
729-
self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span)
730-
}) {
731-
Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
732-
Err(guar) => Ty::new_error(tcx, guar),
733-
}
734-
}
735-
_ => self.lower_ty(hir_ty),
736-
}
737-
}
738-
739-
/// Perform type-dependent lookup for a *method* for return type notation.
740-
/// This generally mirrors `<dyn HirTyLowerer>::lower_type_relative_path`.
741-
fn resolve_type_relative_return_type_notation(
742-
&self,
743-
qself: &'tcx hir::Ty<'tcx>,
744-
item_segment: &'tcx hir::PathSegment<'tcx>,
745-
qpath_hir_id: HirId,
746-
span: Span,
747-
) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> {
748-
let tcx = self.tcx();
749-
let qself_ty = self.lower_ty(qself);
750-
let assoc_ident = item_segment.ident;
751-
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
752-
path.res
753-
} else {
754-
Res::Err
755-
};
756-
757-
let bound = match (qself_ty.kind(), qself_res) {
758-
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
759-
// `Self` in an impl of a trait -- we have a concrete self type and a
760-
// trait reference.
761-
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
762-
// A cycle error occurred, most likely.
763-
self.dcx().span_bug(span, "expected cycle error");
764-
};
765-
766-
self.probe_single_bound_for_assoc_item(
767-
|| {
768-
traits::supertraits(
769-
tcx,
770-
ty::Binder::dummy(trait_ref.instantiate_identity()),
771-
)
772-
},
773-
AssocItemQSelf::SelfTyAlias,
721+
let self_ty = self.lower_ty(hir_self_ty);
722+
let (item_def_id, bound) = match self.resolve_type_relative_path(
723+
self_ty,
724+
hir_self_ty,
774725
ty::AssocTag::Fn,
775-
assoc_ident,
776-
span,
726+
segment,
727+
hir_ty.hir_id,
728+
hir_ty.span,
777729
None,
778-
)?
779-
}
780-
(
781-
&ty::Param(_),
782-
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
783-
) => self.probe_single_ty_param_bound_for_assoc_item(
784-
param_did.expect_local(),
785-
qself.span,
786-
ty::AssocTag::Fn,
787-
assoc_ident,
788-
span,
789-
)?,
790-
_ => {
791-
if let Err(reported) = qself_ty.error_reported() {
792-
return Err(reported);
793-
} else {
794-
// FIXME(return_type_notation): Provide some structured suggestion here.
795-
let err = struct_span_code_err!(
796-
self.dcx(),
797-
span,
798-
E0223,
799-
"ambiguous associated function"
730+
) {
731+
Ok(result) => result,
732+
Err(guar) => return Ty::new_error(tcx, guar),
733+
};
734+
735+
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
736+
// which may happen via a higher-ranked where clause or supertrait.
737+
// This is the same restrictions as associated types; even though we could
738+
// support it, it just makes things a lot more difficult to support in
739+
// `resolve_bound_vars`, since we'd need to introduce those as elided
740+
// bound vars on the where clause too.
741+
if bound.has_bound_vars() {
742+
return Ty::new_error(
743+
tcx,
744+
self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
745+
span: hir_ty.span,
746+
inferred_sugg: Some(hir_ty.span.with_hi(segment.ident.span.lo())),
747+
bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder()),
748+
mpart_sugg: None,
749+
what: tcx.def_descr(item_def_id),
750+
}),
800751
);
801-
return Err(err.emit());
802752
}
803-
}
804-
};
805-
806-
let trait_def_id = bound.def_id();
807-
let assoc_fn = self
808-
.probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
809-
.expect("failed to find associated fn");
810753

811-
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
812-
// which may happen via a higher-ranked where clause or supertrait.
813-
// This is the same restrictions as associated types; even though we could
814-
// support it, it just makes things a lot more difficult to support in
815-
// `resolve_bound_vars`, since we'd need to introduce those as elided
816-
// bound vars on the where clause too.
817-
if bound.has_bound_vars() {
818-
return Err(self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
819-
span,
820-
inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
821-
bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
822-
mpart_sugg: None,
823-
what: assoc_fn.descr(),
824-
}));
754+
match self.lower_return_type_notation_ty(bound, item_def_id, hir_ty.span) {
755+
Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
756+
Err(guar) => Ty::new_error(tcx, guar),
757+
}
758+
}
759+
_ => self.lower_ty(hir_ty),
825760
}
826-
827-
Ok((bound, assoc_fn.def_id))
828761
}
829762

830763
/// Do the common parts of lowering an RTN type. This involves extending the

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+75-48
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
3838
use rustc_middle::mir::interpret::LitToConstInput;
3939
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
4040
use rustc_middle::ty::{
41-
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
42-
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
41+
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
42+
TypeVisitableExt, TypingMode, Upcast, fold_regions,
4343
};
4444
use rustc_middle::{bug, span_bug};
4545
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -937,7 +937,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
937937
fn probe_trait_that_defines_assoc_item(
938938
&self,
939939
trait_def_id: DefId,
940-
assoc_tag: AssocTag,
940+
assoc_tag: ty::AssocTag,
941941
assoc_ident: Ident,
942942
) -> bool {
943943
self.tcx()
@@ -980,7 +980,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
980980
&self,
981981
ty_param_def_id: LocalDefId,
982982
ty_param_span: Span,
983-
assoc_tag: AssocTag,
983+
assoc_tag: ty::AssocTag,
984984
assoc_ident: Ident,
985985
span: Span,
986986
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
@@ -1015,7 +1015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10151015
&self,
10161016
all_candidates: impl Fn() -> I,
10171017
qself: AssocItemQSelf,
1018-
assoc_tag: AssocTag,
1018+
assoc_tag: ty::AssocTag,
10191019
assoc_ident: Ident,
10201020
span: Span,
10211021
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@@ -1238,7 +1238,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12381238
) -> Result<TypeRelativePath<'tcx>, ErrorGuaranteed> {
12391239
debug!(%self_ty, ?segment.ident);
12401240
let tcx = self.tcx();
1241-
let ident = segment.ident;
12421241

12431242
// Check if we have an enum variant or an inherent associated type.
12441243
let mut variant_def_id = None;
@@ -1247,7 +1246,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12471246
let variant_def = adt_def
12481247
.variants()
12491248
.iter()
1250-
.find(|vd| tcx.hygienic_eq(ident, vd.ident(tcx), adt_def.did()));
1249+
.find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
12511250
if let Some(variant_def) = variant_def {
12521251
if let PermitVariants::Yes = mode.permit_variants() {
12531252
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
@@ -1282,13 +1281,70 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12821281
}
12831282
}
12841283

1284+
let (item_def_id, bound) = self.resolve_type_relative_path(
1285+
self_ty,
1286+
hir_self_ty,
1287+
mode.assoc_tag(),
1288+
segment,
1289+
qpath_hir_id,
1290+
span,
1291+
variant_def_id,
1292+
)?;
1293+
1294+
let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?;
1295+
1296+
if let Some(variant_def_id) = variant_def_id {
1297+
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| {
1298+
lint.primary_message("ambiguous associated item");
1299+
let mut could_refer_to = |kind: DefKind, def_id, also| {
1300+
let note_msg = format!(
1301+
"`{}` could{} refer to the {} defined here",
1302+
segment.ident,
1303+
also,
1304+
tcx.def_kind_descr(kind, def_id)
1305+
);
1306+
lint.span_note(tcx.def_span(def_id), note_msg);
1307+
};
1308+
1309+
could_refer_to(DefKind::Variant, variant_def_id, "");
1310+
could_refer_to(mode.def_kind(), item_def_id, " also");
1311+
1312+
lint.span_suggestion(
1313+
span,
1314+
"use fully-qualified syntax",
1315+
format!(
1316+
"<{} as {}>::{}",
1317+
self_ty,
1318+
tcx.item_name(bound.def_id()),
1319+
segment.ident
1320+
),
1321+
Applicability::MachineApplicable,
1322+
);
1323+
});
1324+
}
1325+
1326+
Ok(TypeRelativePath::AssocItem(item_def_id, args))
1327+
}
1328+
1329+
/// Resolve a [type-relative](hir::QPath::TypeRelative) (and type-level) path.
1330+
fn resolve_type_relative_path(
1331+
&self,
1332+
self_ty: Ty<'tcx>,
1333+
hir_self_ty: &'tcx hir::Ty<'tcx>,
1334+
assoc_tag: ty::AssocTag,
1335+
segment: &'tcx hir::PathSegment<'tcx>,
1336+
qpath_hir_id: HirId,
1337+
span: Span,
1338+
variant_def_id: Option<DefId>,
1339+
) -> Result<(DefId, ty::PolyTraitRef<'tcx>), ErrorGuaranteed> {
1340+
let tcx = self.tcx();
1341+
12851342
let self_ty_res = match hir_self_ty.kind {
12861343
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
12871344
_ => Res::Err,
12881345
};
12891346

1290-
// Find the type of the associated item, and the trait where the associated
1291-
// item is declared.
1347+
// Find the type of the assoc item, and the trait where the associated item is declared.
12921348
let bound = match (self_ty.kind(), self_ty_res) {
12931349
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
12941350
// `Self` in an impl of a trait -- we have a concrete self type and a
@@ -1300,14 +1356,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13001356

13011357
self.probe_single_bound_for_assoc_item(
13021358
|| {
1303-
traits::supertraits(
1304-
tcx,
1305-
ty::Binder::dummy(trait_ref.instantiate_identity()),
1306-
)
1359+
let trait_ref = ty::Binder::dummy(trait_ref.instantiate_identity());
1360+
traits::supertraits(tcx, trait_ref)
13071361
},
13081362
AssocItemQSelf::SelfTyAlias,
1309-
mode.assoc_tag(),
1310-
ident,
1363+
assoc_tag,
1364+
segment.ident,
13111365
span,
13121366
None,
13131367
)?
@@ -1318,55 +1372,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13181372
) => self.probe_single_ty_param_bound_for_assoc_item(
13191373
param_did.expect_local(),
13201374
hir_self_ty.span,
1321-
mode.assoc_tag(),
1322-
ident,
1375+
assoc_tag,
1376+
segment.ident,
13231377
span,
13241378
)?,
13251379
_ => {
13261380
return Err(self.report_unresolved_type_relative_path(
13271381
self_ty,
13281382
hir_self_ty,
1329-
mode.assoc_tag(),
1330-
ident,
1383+
assoc_tag,
1384+
segment.ident,
13311385
qpath_hir_id,
13321386
span,
13331387
variant_def_id,
13341388
));
13351389
}
13361390
};
13371391

1338-
let trait_def_id = bound.def_id();
13391392
let assoc_item = self
1340-
.probe_assoc_item(ident, mode.assoc_tag(), qpath_hir_id, span, trait_def_id)
1393+
.probe_assoc_item(segment.ident, assoc_tag, qpath_hir_id, span, bound.def_id())
13411394
.expect("failed to find associated item");
1342-
let (def_id, args) = self.lower_assoc_item_path(span, assoc_item.def_id, segment, bound)?;
1343-
let result = TypeRelativePath::AssocItem(def_id, args);
1344-
1345-
if let Some(variant_def_id) = variant_def_id {
1346-
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| {
1347-
lint.primary_message("ambiguous associated item");
1348-
let mut could_refer_to = |kind: DefKind, def_id, also| {
1349-
let note_msg = format!(
1350-
"`{}` could{} refer to the {} defined here",
1351-
ident,
1352-
also,
1353-
tcx.def_kind_descr(kind, def_id)
1354-
);
1355-
lint.span_note(tcx.def_span(def_id), note_msg);
1356-
};
13571395

1358-
could_refer_to(DefKind::Variant, variant_def_id, "");
1359-
could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
1360-
1361-
lint.span_suggestion(
1362-
span,
1363-
"use fully-qualified syntax",
1364-
format!("<{} as {}>::{}", self_ty, tcx.item_name(trait_def_id), ident),
1365-
Applicability::MachineApplicable,
1366-
);
1367-
});
1368-
}
1369-
Ok(result)
1396+
Ok((assoc_item.def_id, bound))
13701397
}
13711398

13721399
/// Search for inherent associated items for use at the type level.

0 commit comments

Comments
 (0)