Skip to content

Commit 13e91d5

Browse files
committed
hir: drop support for assoc type aliases, simplifying resolution of assoc items in docs
1 parent af7dbfe commit 13e91d5

File tree

7 files changed

+74
-159
lines changed

7 files changed

+74
-159
lines changed

crates/hir-ty/src/method_resolution.rs

+9-84
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use hir_def::{
1010
data::{adt::StructFlags, ImplData},
1111
item_scope::ItemScope,
1212
nameres::DefMap,
13-
resolver::HasResolver,
1413
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
1514
ModuleDefId, ModuleId, TraitId,
1615
};
@@ -1003,20 +1002,6 @@ pub fn iterate_method_candidates_dyn(
10031002
}
10041003
}
10051004

1006-
pub fn iterate_trait_item_candidates(
1007-
ty: &Canonical<Ty>,
1008-
db: &dyn HirDatabase,
1009-
env: Arc<TraitEnvironment>,
1010-
traits_in_scope: &FxHashSet<TraitId>,
1011-
name: Option<&Name>,
1012-
callback: &mut dyn FnMut(AssocItemId, bool) -> ControlFlow<()>,
1013-
) {
1014-
let mut table = InferenceTable::new(db, env);
1015-
let self_ty = table.instantiate_canonical(ty.clone());
1016-
1017-
iterate_trait_item_candidates_(&self_ty, &mut table, traits_in_scope, name, None, callback);
1018-
}
1019-
10201005
fn iterate_method_candidates_with_autoref(
10211006
receiver_ty: &Canonical<Ty>,
10221007
first_adjustment: ReceiverAdjustments,
@@ -1160,26 +1145,6 @@ fn iterate_trait_method_candidates(
11601145
receiver_ty: Option<&Ty>,
11611146
receiver_adjustments: Option<ReceiverAdjustments>,
11621147
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1163-
) -> ControlFlow<()> {
1164-
iterate_trait_item_candidates_(
1165-
self_ty,
1166-
table,
1167-
traits_in_scope,
1168-
name,
1169-
receiver_ty,
1170-
&mut move |assoc_item_id, visible| {
1171-
callback(receiver_adjustments.clone().unwrap_or_default(), assoc_item_id, visible)
1172-
},
1173-
)
1174-
}
1175-
1176-
fn iterate_trait_item_candidates_(
1177-
self_ty: &Ty,
1178-
table: &mut InferenceTable<'_>,
1179-
traits_in_scope: &FxHashSet<TraitId>,
1180-
name: Option<&Name>,
1181-
receiver_ty: Option<&Ty>,
1182-
callback: &mut dyn FnMut(AssocItemId, bool) -> ControlFlow<()>,
11831148
) -> ControlFlow<()> {
11841149
let db = table.db;
11851150
let env = table.trait_env.clone();
@@ -1222,7 +1187,7 @@ fn iterate_trait_item_candidates_(
12221187
}
12231188
}
12241189
known_implemented = true;
1225-
callback(item, visible)?;
1190+
callback(receiver_adjustments.clone().unwrap_or_default(), item, visible)?;
12261191
}
12271192
}
12281193
ControlFlow::Continue(())
@@ -1417,8 +1382,6 @@ fn is_valid_candidate(
14171382
visible_from_module: Option<ModuleId>,
14181383
) -> IsValidCandidate {
14191384
let db = table.db;
1420-
let def_db = db.upcast();
1421-
14221385
match item {
14231386
AssocItemId::FunctionId(f) => {
14241387
is_valid_fn_candidate(table, f, name, receiver_ty, self_ty, visible_from_module)
@@ -1434,61 +1397,23 @@ fn is_valid_candidate(
14341397
}
14351398
}
14361399
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
1437-
if !self_ty_matches(table, db, impl_id, self_ty) {
1400+
let self_ty_matches = table.run_in_snapshot(|table| {
1401+
let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
1402+
.fill_with_inference_vars(table)
1403+
.build();
1404+
table.unify(&expected_self_ty, self_ty)
1405+
});
1406+
if !self_ty_matches {
14381407
cov_mark::hit!(const_candidate_self_type_mismatch);
14391408
return IsValidCandidate::No;
14401409
}
14411410
}
14421411
IsValidCandidate::Yes
14431412
}
1444-
AssocItemId::TypeAliasId(t) => {
1445-
// Q: should this branch be restricted to `iterate_trait_item_candidates()`?
1446-
//
1447-
// the code below does not seem to be called when adding tests to
1448-
// `method_resolution.rs`, so resolution of type aliases is likely performed at some
1449-
// other point. due to the marks below, however, the test which ensures that marks have
1450-
// corresponding checks will fail
1451-
let data = db.type_alias_data(t);
1452-
1453-
check_that!(receiver_ty.is_none());
1454-
check_that!(name.map_or(true, |n| data.name == *n));
1455-
1456-
if let Some(from_module) = visible_from_module {
1457-
// Q: should the resolved visibility be added to the database?
1458-
let visibility = data.visibility.resolve(def_db, &t.resolver(def_db));
1459-
1460-
if !visibility.is_visible_from(def_db, from_module) {
1461-
// cov_mark::hit!(type_alias_candidate_not_visible);
1462-
return IsValidCandidate::NotVisible;
1463-
}
1464-
}
1465-
1466-
// Q: is it correct to use the same check as `ConstId`?
1467-
if let ItemContainerId::ImplId(impl_id) = t.lookup(def_db).container {
1468-
if !self_ty_matches(table, db, impl_id, self_ty) {
1469-
// cov_mark::hit!(type_alias_candidate_self_type_mismatch);
1470-
return IsValidCandidate::No;
1471-
}
1472-
}
1473-
1474-
IsValidCandidate::Yes
1475-
}
1413+
_ => IsValidCandidate::No,
14761414
}
14771415
}
14781416

1479-
fn self_ty_matches(
1480-
table: &mut InferenceTable<'_>,
1481-
db: &dyn HirDatabase,
1482-
impl_id: ImplId,
1483-
self_ty: &Ty,
1484-
) -> bool {
1485-
table.run_in_snapshot(|table| {
1486-
let expected_self_ty =
1487-
TyBuilder::impl_self_ty(db, impl_id).fill_with_inference_vars(table).build();
1488-
table.unify(&expected_self_ty, self_ty)
1489-
})
1490-
}
1491-
14921417
enum IsValidCandidate {
14931418
Yes,
14941419
No,

crates/hir/src/attrs.rs

+36-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Attributes & documentation for hir types.
22
3+
use std::ops::ControlFlow;
4+
35
use base_db::FileId;
46
use hir_def::{
57
attr::AttrsWithOwner,
@@ -13,7 +15,7 @@ use hir_expand::{
1315
name::Name,
1416
span_map::{RealSpanMap, SpanMapRef},
1517
};
16-
use hir_ty::db::HirDatabase;
18+
use hir_ty::{db::HirDatabase, method_resolution};
1719
use syntax::{ast, AstNode};
1820

1921
use crate::{
@@ -243,23 +245,46 @@ fn resolve_impl_trait_item(
243245
name: &Name,
244246
ns: Option<Namespace>,
245247
) -> Option<DocLinkDef> {
248+
let canonical = ty.canonical();
249+
let krate = ty.krate(db);
250+
let environment = resolver.generic_def().map_or_else(
251+
|| crate::TraitEnvironment::empty(krate.id).into(),
252+
|d| db.trait_environment(d),
253+
);
246254
let traits_in_scope = resolver.traits_in_scope(db.upcast());
247255

248-
// If two traits in scope define the same item, Rustdoc links to no specific trait (for
249-
// instance, given two methods `a`, Rustdoc simply links to `method.a` with no
250-
// disambiguation) so we just pick the first one we find as well.
251-
ty.iterate_trait_item_candidates(
256+
let mut result = None;
257+
258+
// `ty.iterate_path_candidates()` require a scope, which is not available when resolving
259+
// attributes here. Use path resolution directly instead.
260+
//
261+
// FIXME: resolve type aliases (which are not yielded by iterate_path_candidates)
262+
method_resolution::iterate_path_candidates(
263+
&canonical,
252264
db,
253-
ty.krate(db),
254-
&resolver,
265+
environment,
255266
&traits_in_scope,
267+
method_resolution::VisibleFromModule::None,
256268
Some(name),
257-
move |assoc_item| {
269+
&mut |assoc_item_id| {
270+
let assoc_item: AssocItem = assoc_item_id.into();
271+
258272
debug_assert_eq!(assoc_item.name(db).as_ref(), Some(name));
259273

260-
as_module_def_if_namespace_matches(assoc_item, ns)
274+
// If two traits in scope define the same item, Rustdoc links to no specific trait (for
275+
// instance, given two methods `a`, Rustdoc simply links to `method.a` with no
276+
// disambiguation) so we just pick the first one we find as well.
277+
result = as_module_def_if_namespace_matches(assoc_item, ns);
278+
279+
if result.is_some() {
280+
ControlFlow::Break(())
281+
} else {
282+
ControlFlow::Continue(())
283+
}
261284
},
262-
)
285+
);
286+
287+
result
263288
}
264289

265290
fn resolve_field(
@@ -281,11 +306,7 @@ fn as_module_def_if_namespace_matches(
281306
let (def, expected_ns) = match assoc_item {
282307
AssocItem::Function(it) => (ModuleDef::Function(it), Namespace::Values),
283308
AssocItem::Const(it) => (ModuleDef::Const(it), Namespace::Values),
284-
AssocItem::TypeAlias(it) => {
285-
// Inherent associated types are supported in nightly:
286-
// https://github.com/rust-lang/rust/issues/8995
287-
(ModuleDef::TypeAlias(it), Namespace::Types)
288-
}
309+
AssocItem::TypeAlias(it) => (ModuleDef::TypeAlias(it), Namespace::Types),
289310
};
290311

291312
(ns.unwrap_or(expected_ns) == expected_ns).then(|| DocLinkDef::ModuleDef(def))

crates/hir/src/lib.rs

+4-57
Original file line numberDiff line numberDiff line change
@@ -4121,6 +4121,10 @@ impl Type {
41214121
}
41224122
}
41234123

4124+
pub(crate) fn canonical(&self) -> Canonical<Ty> {
4125+
hir_ty::replace_errors_with_variables(&self.ty)
4126+
}
4127+
41244128
/// Returns types that this type dereferences to (including this type itself). The returned
41254129
/// iterator won't yield the same type more than once even if the deref chain contains a cycle.
41264130
pub fn autoderef(&self, db: &dyn HirDatabase) -> impl Iterator<Item = Type> + '_ {
@@ -4387,63 +4391,6 @@ impl Type {
43874391
);
43884392
}
43894393

4390-
// Q: this method takes `krate + resolver` instead of `scope` because the
4391-
// caller doesn't have a scope available. is there a way to make this more
4392-
// consistent with other `iterate_` methods?
4393-
pub fn iterate_trait_item_candidates<T>(
4394-
&self,
4395-
db: &dyn HirDatabase,
4396-
krate: Crate,
4397-
resolver: &Resolver,
4398-
traits_in_scope: &FxHashSet<TraitId>,
4399-
name: Option<&Name>,
4400-
mut callback: impl FnMut(AssocItem) -> Option<T>,
4401-
) -> Option<T> {
4402-
let _p = profile::span("iterate_trait_item_candidates");
4403-
let mut slot = None;
4404-
self.iterate_trait_item_candidates_dyn(
4405-
db,
4406-
krate,
4407-
resolver,
4408-
traits_in_scope,
4409-
name,
4410-
&mut |assoc_item_id| {
4411-
if let Some(res) = callback(assoc_item_id.into()) {
4412-
slot = Some(res);
4413-
return ControlFlow::Break(());
4414-
}
4415-
ControlFlow::Continue(())
4416-
},
4417-
);
4418-
slot
4419-
}
4420-
4421-
fn iterate_trait_item_candidates_dyn(
4422-
&self,
4423-
db: &dyn HirDatabase,
4424-
krate: Crate,
4425-
resolver: &Resolver,
4426-
traits_in_scope: &FxHashSet<TraitId>,
4427-
name: Option<&Name>,
4428-
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
4429-
) {
4430-
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
4431-
4432-
let environment = resolver.generic_def().map_or_else(
4433-
|| Arc::new(TraitEnvironment::empty(krate.id)),
4434-
|d| db.trait_environment(d),
4435-
);
4436-
4437-
method_resolution::iterate_trait_item_candidates(
4438-
&canonical,
4439-
db,
4440-
environment,
4441-
traits_in_scope,
4442-
name,
4443-
&mut |id, _| callback(id),
4444-
);
4445-
}
4446-
44474394
pub fn as_adt(&self) -> Option<Adt> {
44484395
let (adt, _subst) = self.ty.as_adt()?;
44494396
Some(adt.into())

crates/ide-completion/src/completions/expr.rs

+21
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,22 @@ pub(crate) fn complete_expr_path(
6767
ctx.iterate_path_candidates(ty, |item| {
6868
add_assoc_item(acc, item);
6969
});
70+
71+
// Iterate assoc types separately
72+
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
73+
if let hir::AssocItem::TypeAlias(ty) = item {
74+
acc.add_type_alias(ctx, ty)
75+
}
76+
None::<()>
77+
});
7078
}
7179
Qualified::With { resolution: None, .. } => {}
7280
Qualified::With { resolution: Some(resolution), .. } => {
81+
// Add associated types on type parameters and `Self`.
82+
ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
83+
acc.add_type_alias(ctx, alias);
84+
None::<()>
85+
});
7386
match resolution {
7487
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
7588
let module_scope = module.scope(ctx.db, Some(ctx.module));
@@ -111,6 +124,14 @@ pub(crate) fn complete_expr_path(
111124
ctx.iterate_path_candidates(&ty, |item| {
112125
add_assoc_item(acc, item);
113126
});
127+
128+
// Iterate assoc types separately
129+
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
130+
if let hir::AssocItem::TypeAlias(ty) = item {
131+
acc.add_type_alias(ctx, ty)
132+
}
133+
None::<()>
134+
});
114135
}
115136
hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
116137
// Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.

crates/ide-completion/src/completions/pattern.rs

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ pub(crate) fn complete_pattern_path(
154154
}
155155

156156
ctx.iterate_path_candidates(&ty, |item| match item {
157+
AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta),
157158
AssocItem::Const(c) => acc.add_const(ctx, c),
158159
_ => {}
159160
});

crates/ide-completion/src/completions/type.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ pub(crate) fn complete_type_path(
4545
hir::AssocItem::Const(ct) if matches!(location, TypeLocation::GenericArg { .. }) => {
4646
acc.add_const(ctx, ct)
4747
}
48-
hir::AssocItem::Function(_) | hir::AssocItem::Const(_) | hir::AssocItem::TypeAlias(_) => (),
48+
hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => (),
49+
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
4950
};
5051

5152
match qualified {

crates/ide/src/doc_links/tests.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -482,13 +482,12 @@ fn doc_links_trait_impl_items() {
482482
r#"
483483
trait Trait {
484484
type Type;
485-
// ^^^^ Struct::Type
486485
const CONST: usize;
487486
// ^^^^^ Struct::CONST
488487
fn function();
489488
// ^^^^^^^^ Struct::function
490489
}
491-
/// [`Struct::Type`]
490+
// FIXME #9694: [`Struct::Type`]
492491
/// [`Struct::CONST`]
493492
/// [`Struct::function`]
494493
struct Struct$0;

0 commit comments

Comments
 (0)