Skip to content

Commit 123f17c

Browse files
authored
Merge pull request rust-lang#19127 from ChayimFriedman2/different-generic-args
feat: Refactor path lowering and serve a new path diagnostic
2 parents 6b46937 + 2e7158b commit 123f17c

File tree

19 files changed

+1222
-1144
lines changed

19 files changed

+1222
-1144
lines changed

src/tools/rust-analyzer/crates/hir-def/src/data.rs

+4
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ bitflags::bitflags! {
250250
const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 3;
251251
const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 4;
252252
const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 5;
253+
const RUSTC_PAREN_SUGAR = 1 << 6;
253254
}
254255
}
255256

@@ -294,6 +295,9 @@ impl TraitData {
294295
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
295296
flags |= TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
296297
}
298+
if attrs.by_key(&sym::rustc_paren_sugar).exists() {
299+
flags |= TraitFlags::RUSTC_PAREN_SUGAR;
300+
}
297301

298302
let mut skip_array_during_method_dispatch =
299303
attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();

src/tools/rust-analyzer/crates/hir-def/src/path.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,7 @@ impl Path {
173173
segments: path.mod_path().segments(),
174174
generic_args: Some(path.generic_args()),
175175
},
176-
Path::LangItem(_, seg) => PathSegments {
177-
segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
178-
generic_args: None,
179-
},
176+
Path::LangItem(_, seg) => PathSegments { segments: seg.as_slice(), generic_args: None },
180177
}
181178
}
182179

@@ -240,6 +237,11 @@ pub struct PathSegment<'a> {
240237
pub args_and_bindings: Option<&'a GenericArgs>,
241238
}
242239

240+
impl PathSegment<'_> {
241+
pub const MISSING: PathSegment<'static> =
242+
PathSegment { name: &Name::missing(), args_and_bindings: None };
243+
}
244+
243245
#[derive(Debug, Clone, Copy)]
244246
pub struct PathSegments<'a> {
245247
segments: &'a [Name],

src/tools/rust-analyzer/crates/hir-def/src/resolver.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,9 @@ impl Resolver {
327327
| LangItemTarget::ImplDef(_)
328328
| LangItemTarget::Static(_) => return None,
329329
};
330+
// Remaining segments start from 0 because lang paths have no segments other than the remaining.
330331
return Some((
331-
ResolveValueResult::Partial(type_ns, 1, None),
332+
ResolveValueResult::Partial(type_ns, 0, None),
332333
ResolvePathResultPrefixInfo::default(),
333334
));
334335
}

src/tools/rust-analyzer/crates/hir-expand/src/name.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ impl Name {
142142
/// Ideally, we want a `gensym` semantics for missing names -- each missing
143143
/// name is equal only to itself. It's not clear how to implement this in
144144
/// salsa though, so we punt on that bit for a moment.
145-
pub fn missing() -> Name {
146-
Name { symbol: sym::MISSING_NAME.clone(), ctx: () }
145+
pub const fn missing() -> Name {
146+
Name { symbol: sym::consts::MISSING_NAME, ctx: () }
147147
}
148148

149149
/// Returns true if this is a fake name for things missing in the source code. See

src/tools/rust-analyzer/crates/hir-ty/src/infer.rs

+19-34
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
pub(crate) mod cast;
1717
pub(crate) mod closure;
1818
mod coerce;
19-
mod diagnostics;
19+
pub(crate) mod diagnostics;
2020
mod expr;
2121
mod mutability;
2222
mod pat;
@@ -1502,21 +1502,22 @@ impl<'a> InferenceContext<'a> {
15021502
&self.diagnostics,
15031503
InferenceTyDiagnosticSource::Body,
15041504
);
1505+
let mut path_ctx = ctx.at_path(path, node);
15051506
let (resolution, unresolved) = if value_ns {
1506-
let Some(res) = ctx.resolve_path_in_value_ns(path, node, HygieneId::ROOT) else {
1507+
let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
15071508
return (self.err_ty(), None);
15081509
};
15091510
match res {
15101511
ResolveValueResult::ValueNs(value, _) => match value {
15111512
ValueNs::EnumVariantId(var) => {
1512-
let substs = ctx.substs_from_path(path, var.into(), true);
1513+
let substs = path_ctx.substs_from_path(var.into(), true);
15131514
drop(ctx);
15141515
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
15151516
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
15161517
return (ty, Some(var.into()));
15171518
}
15181519
ValueNs::StructId(strukt) => {
1519-
let substs = ctx.substs_from_path(path, strukt.into(), true);
1520+
let substs = path_ctx.substs_from_path(strukt.into(), true);
15201521
drop(ctx);
15211522
let ty = self.db.ty(strukt.into());
15221523
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
@@ -1531,7 +1532,7 @@ impl<'a> InferenceContext<'a> {
15311532
ResolveValueResult::Partial(typens, unresolved, _) => (typens, Some(unresolved)),
15321533
}
15331534
} else {
1534-
match ctx.resolve_path_in_type_ns(path, node) {
1535+
match path_ctx.resolve_path_in_type_ns() {
15351536
Some((it, idx)) => (it, idx),
15361537
None => return (self.err_ty(), None),
15371538
}
@@ -1542,21 +1543,21 @@ impl<'a> InferenceContext<'a> {
15421543
};
15431544
return match resolution {
15441545
TypeNs::AdtId(AdtId::StructId(strukt)) => {
1545-
let substs = ctx.substs_from_path(path, strukt.into(), true);
1546+
let substs = path_ctx.substs_from_path(strukt.into(), true);
15461547
drop(ctx);
15471548
let ty = self.db.ty(strukt.into());
15481549
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
15491550
forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
15501551
}
15511552
TypeNs::AdtId(AdtId::UnionId(u)) => {
1552-
let substs = ctx.substs_from_path(path, u.into(), true);
1553+
let substs = path_ctx.substs_from_path(u.into(), true);
15531554
drop(ctx);
15541555
let ty = self.db.ty(u.into());
15551556
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
15561557
forbid_unresolved_segments((ty, Some(u.into())), unresolved)
15571558
}
15581559
TypeNs::EnumVariantId(var) => {
1559-
let substs = ctx.substs_from_path(path, var.into(), true);
1560+
let substs = path_ctx.substs_from_path(var.into(), true);
15601561
drop(ctx);
15611562
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
15621563
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
@@ -1567,31 +1568,32 @@ impl<'a> InferenceContext<'a> {
15671568
let substs = generics.placeholder_subst(self.db);
15681569
let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
15691570

1570-
let Some(mut remaining_idx) = unresolved else {
1571+
let Some(remaining_idx) = unresolved else {
15711572
drop(ctx);
15721573
return self.resolve_variant_on_alias(ty, None, mod_path);
15731574
};
15741575

15751576
let mut remaining_segments = path.segments().skip(remaining_idx);
15761577

1578+
if remaining_segments.len() >= 2 {
1579+
path_ctx.ignore_last_segment();
1580+
}
1581+
15771582
// We need to try resolving unresolved segments one by one because each may resolve
15781583
// to a projection, which `TyLoweringContext` cannot handle on its own.
15791584
let mut tried_resolving_once = false;
1580-
while !remaining_segments.is_empty() {
1581-
let resolved_segment = path.segments().get(remaining_idx - 1).unwrap();
1582-
let current_segment = remaining_segments.take(1);
1583-
1585+
while let Some(current_segment) = remaining_segments.first() {
15841586
// If we can resolve to an enum variant, it takes priority over associated type
15851587
// of the same name.
15861588
if let Some((AdtId::EnumId(id), _)) = ty.as_adt() {
15871589
let enum_data = self.db.enum_data(id);
1588-
let name = current_segment.first().unwrap().name;
1589-
if let Some(variant) = enum_data.variant(name) {
1590+
if let Some(variant) = enum_data.variant(current_segment.name) {
15901591
return if remaining_segments.len() == 1 {
15911592
(ty, Some(variant.into()))
15921593
} else {
15931594
// We still have unresolved paths, but enum variants never have
15941595
// associated types!
1596+
// FIXME: Report an error.
15951597
(self.err_ty(), None)
15961598
};
15971599
}
@@ -1600,23 +1602,13 @@ impl<'a> InferenceContext<'a> {
16001602
if tried_resolving_once {
16011603
// FIXME: with `inherent_associated_types` this is allowed, but our `lower_partly_resolved_path()`
16021604
// will need to be updated to err at the correct segment.
1603-
//
1604-
// We need to stop here because otherwise the segment index passed to `lower_partly_resolved_path()`
1605-
// will be incorrect, and that can mess up error reporting.
16061605
break;
16071606
}
16081607

16091608
// `lower_partly_resolved_path()` returns `None` as type namespace unless
16101609
// `remaining_segments` is empty, which is never the case here. We don't know
16111610
// which namespace the new `ty` is in until normalized anyway.
1612-
(ty, _) = ctx.lower_partly_resolved_path(
1613-
node,
1614-
resolution,
1615-
resolved_segment,
1616-
current_segment,
1617-
(remaining_idx - 1) as u32,
1618-
false,
1619-
);
1611+
(ty, _) = path_ctx.lower_partly_resolved_path(resolution, false);
16201612
tried_resolving_once = true;
16211613

16221614
ty = self.table.insert_type_vars(ty);
@@ -1626,8 +1618,6 @@ impl<'a> InferenceContext<'a> {
16261618
return (self.err_ty(), None);
16271619
}
16281620

1629-
// FIXME(inherent_associated_types): update `resolution` based on `ty` here.
1630-
remaining_idx += 1;
16311621
remaining_segments = remaining_segments.skip(1);
16321622
}
16331623
drop(ctx);
@@ -1643,12 +1633,7 @@ impl<'a> InferenceContext<'a> {
16431633
(ty, variant)
16441634
}
16451635
TypeNs::TypeAliasId(it) => {
1646-
let resolved_seg = match unresolved {
1647-
None => path.segments().last().unwrap(),
1648-
Some(n) => path.segments().get(path.segments().len() - n - 1).unwrap(),
1649-
};
1650-
let substs =
1651-
ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None);
1636+
let substs = path_ctx.substs_from_path_segment(it.into(), true, None);
16521637
drop(ctx);
16531638
let ty = self.db.ty(it.into());
16541639
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));

src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs

+28-48
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@
55
use std::cell::RefCell;
66
use std::ops::{Deref, DerefMut};
77

8-
use hir_def::expr_store::HygieneId;
9-
use hir_def::hir::ExprOrPatId;
10-
use hir_def::path::{Path, PathSegment, PathSegments};
11-
use hir_def::resolver::{ResolveValueResult, Resolver, TypeNs};
12-
use hir_def::type_ref::TypesMap;
13-
use hir_def::TypeOwnerId;
8+
use either::Either;
9+
use hir_def::{hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap, TypeOwnerId};
1410

15-
use crate::db::HirDatabase;
1611
use crate::{
17-
InferenceDiagnostic, InferenceTyDiagnosticSource, Ty, TyLoweringContext, TyLoweringDiagnostic,
12+
db::HirDatabase,
13+
lower::path::{PathDiagnosticCallback, PathLoweringContext},
14+
InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringContext, TyLoweringDiagnostic,
1815
};
1916

2017
// Unfortunately, this struct needs to use interior mutability (but we encapsulate it)
@@ -44,13 +41,19 @@ impl Diagnostics {
4441
}
4542
}
4643

44+
pub(crate) struct PathDiagnosticCallbackData<'a> {
45+
node: ExprOrPatId,
46+
diagnostics: &'a Diagnostics,
47+
}
48+
4749
pub(super) struct InferenceTyLoweringContext<'a> {
4850
ctx: TyLoweringContext<'a>,
4951
diagnostics: &'a Diagnostics,
5052
source: InferenceTyDiagnosticSource,
5153
}
5254

5355
impl<'a> InferenceTyLoweringContext<'a> {
56+
#[inline]
5457
pub(super) fn new(
5558
db: &'a dyn HirDatabase,
5659
resolver: &'a Resolver,
@@ -62,65 +65,42 @@ impl<'a> InferenceTyLoweringContext<'a> {
6265
Self { ctx: TyLoweringContext::new(db, resolver, types_map, owner), diagnostics, source }
6366
}
6467

65-
pub(super) fn resolve_path_in_type_ns(
66-
&mut self,
67-
path: &Path,
68-
node: ExprOrPatId,
69-
) -> Option<(TypeNs, Option<usize>)> {
70-
let diagnostics = self.diagnostics;
71-
self.ctx.resolve_path_in_type_ns(path, &mut |_, diag| {
72-
diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
73-
})
74-
}
75-
76-
pub(super) fn resolve_path_in_value_ns(
77-
&mut self,
78-
path: &Path,
79-
node: ExprOrPatId,
80-
hygiene_id: HygieneId,
81-
) -> Option<ResolveValueResult> {
82-
let diagnostics = self.diagnostics;
83-
self.ctx.resolve_path_in_value_ns(path, hygiene_id, &mut |_, diag| {
84-
diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag })
85-
})
86-
}
87-
88-
pub(super) fn lower_partly_resolved_path(
89-
&mut self,
68+
#[inline]
69+
pub(super) fn at_path<'b>(
70+
&'b mut self,
71+
path: &'b Path,
9072
node: ExprOrPatId,
91-
resolution: TypeNs,
92-
resolved_segment: PathSegment<'_>,
93-
remaining_segments: PathSegments<'_>,
94-
resolved_segment_idx: u32,
95-
infer_args: bool,
96-
) -> (Ty, Option<TypeNs>) {
97-
let diagnostics = self.diagnostics;
98-
self.ctx.lower_partly_resolved_path(
99-
resolution,
100-
resolved_segment,
101-
remaining_segments,
102-
resolved_segment_idx,
103-
infer_args,
104-
&mut |_, diag| diagnostics.push(InferenceDiagnostic::PathDiagnostic { node, diag }),
105-
)
73+
) -> PathLoweringContext<'b, 'a> {
74+
let on_diagnostic = PathDiagnosticCallback {
75+
data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }),
76+
callback: |data, _, diag| {
77+
let data = data.as_ref().right().unwrap();
78+
data.diagnostics
79+
.push(InferenceDiagnostic::PathDiagnostic { node: data.node, diag });
80+
},
81+
};
82+
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
10683
}
10784
}
10885

10986
impl<'a> Deref for InferenceTyLoweringContext<'a> {
11087
type Target = TyLoweringContext<'a>;
11188

89+
#[inline]
11290
fn deref(&self) -> &Self::Target {
11391
&self.ctx
11492
}
11593
}
11694

11795
impl DerefMut for InferenceTyLoweringContext<'_> {
96+
#[inline]
11897
fn deref_mut(&mut self) -> &mut Self::Target {
11998
&mut self.ctx
12099
}
121100
}
122101

123102
impl Drop for InferenceTyLoweringContext<'_> {
103+
#[inline]
124104
fn drop(&mut self) {
125105
self.diagnostics
126106
.push_ty_diagnostics(self.source, std::mem::take(&mut self.ctx.diagnostics));

src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2201,8 +2201,8 @@ impl InferenceContext<'_> {
22012201
for kind_id in def_generics.iter_self_id().take(self_params) {
22022202
let arg = args.peek();
22032203
let arg = match (kind_id, arg) {
2204-
// Lifetimes can be elided.
2205-
// Once we have implemented lifetime elision correctly,
2204+
// Lifetimes can be inferred.
2205+
// Once we have implemented lifetime inference correctly,
22062206
// this should be handled in a proper way.
22072207
(
22082208
GenericParamId::LifetimeParamId(_),

src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -564,9 +564,17 @@ impl InferenceContext<'_> {
564564
| Pat::Range { .. }
565565
| Pat::Slice { .. } => true,
566566
Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
567-
Pat::Path(p) => {
568-
let v = self.resolve_value_path_inner(p, pat.into());
569-
v.is_some_and(|x| !matches!(x.0, hir_def::resolver::ValueNs::ConstId(_)))
567+
Pat::Path(path) => {
568+
// A const is a reference pattern, but other value ns things aren't (see #16131). We don't need more than
569+
// the hir-def resolver for this, because if there are segments left, this can only be an (associated) const.
570+
//
571+
// Do not use `TyLoweringContext`'s resolution, we want to ignore errors here (they'll be reported elsewhere).
572+
let resolution = self.resolver.resolve_path_in_value_ns_fully(
573+
self.db.upcast(),
574+
path,
575+
body.pat_path_hygiene(pat),
576+
);
577+
resolution.is_some_and(|it| !matches!(it, hir_def::resolver::ValueNs::ConstId(_)))
570578
}
571579
Pat::ConstBlock(..) => false,
572580
Pat::Lit(expr) => !matches!(

0 commit comments

Comments
 (0)