Skip to content

Commit 31a532a

Browse files
committed
Auto merge of rust-lang#17961 - Veykril:autoderef-alloc, r=Veykril
internal: Don't allocate autoderef steps when not needed
2 parents bdee5c9 + 98e23d3 commit 31a532a

File tree

3 files changed

+60
-26
lines changed

3 files changed

+60
-26
lines changed

src/tools/rust-analyzer/.git-blame-ignore-revs

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
# prettier format
88
f247090558c9ba3c551566eae5882b7ca865225f
99

10-
# subtree syncs
11-
932d85b52946d917deab2c23ead552f7f713b828
10+
# pre-josh subtree syncs
1211
3e358a6827d83e8d6473913a5e304734aadfed04
12+
932d85b52946d917deab2c23ead552f7f713b828
1313
9d2cb42a413e51deb50b36794a2e1605381878fc
14-
f532576ac53ddcc666bc8d59e0b6437065e2f599
14+
b2f6fd4f961fc7e4fbfdb80cae2e6065f8436f15
1515
c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1
16+
f532576ac53ddcc666bc8d59e0b6437065e2f599

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

+53-20
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! reference to a type with the field `bar`. This is an approximation of the
44
//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
55
6+
use std::mem;
7+
68
use chalk_ir::cast::Cast;
79
use hir_def::lang_item::LangItem;
810
use hir_expand::name::Name;
@@ -37,7 +39,7 @@ pub fn autoderef(
3739
) -> impl Iterator<Item = Ty> {
3840
let mut table = InferenceTable::new(db, env);
3941
let ty = table.instantiate_canonical(ty);
40-
let mut autoderef = Autoderef::new(&mut table, ty, false);
42+
let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false);
4143
let mut v = Vec::new();
4244
while let Some((ty, _steps)) = autoderef.next() {
4345
// `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -58,41 +60,76 @@ pub fn autoderef(
5860
v.into_iter()
5961
}
6062

63+
trait TrackAutoderefSteps {
64+
fn len(&self) -> usize;
65+
fn push(&mut self, kind: AutoderefKind, ty: &Ty);
66+
}
67+
68+
impl TrackAutoderefSteps for usize {
69+
fn len(&self) -> usize {
70+
*self
71+
}
72+
fn push(&mut self, _: AutoderefKind, _: &Ty) {
73+
*self += 1;
74+
}
75+
}
76+
impl TrackAutoderefSteps for Vec<(AutoderefKind, Ty)> {
77+
fn len(&self) -> usize {
78+
self.len()
79+
}
80+
fn push(&mut self, kind: AutoderefKind, ty: &Ty) {
81+
self.push((kind, ty.clone()));
82+
}
83+
}
84+
6185
#[derive(Debug)]
62-
pub(crate) struct Autoderef<'a, 'db> {
63-
pub(crate) table: &'a mut InferenceTable<'db>,
86+
pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> {
87+
pub(crate) table: &'table mut InferenceTable<'db>,
6488
ty: Ty,
6589
at_start: bool,
66-
steps: Vec<(AutoderefKind, Ty)>,
90+
steps: T,
6791
explicit: bool,
6892
}
6993

70-
impl<'a, 'db> Autoderef<'a, 'db> {
71-
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
94+
impl<'table, 'db> Autoderef<'table, 'db> {
95+
pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
7296
let ty = table.resolve_ty_shallow(&ty);
7397
Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
7498
}
7599

76-
pub(crate) fn step_count(&self) -> usize {
77-
self.steps.len()
78-
}
79-
80100
pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
81101
&self.steps
82102
}
103+
}
104+
105+
impl<'table, 'db> Autoderef<'table, 'db, usize> {
106+
pub(crate) fn new_no_tracking(
107+
table: &'table mut InferenceTable<'db>,
108+
ty: Ty,
109+
explicit: bool,
110+
) -> Self {
111+
let ty = table.resolve_ty_shallow(&ty);
112+
Autoderef { table, ty, at_start: true, steps: 0, explicit }
113+
}
114+
}
115+
116+
#[allow(private_bounds)]
117+
impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> {
118+
pub(crate) fn step_count(&self) -> usize {
119+
self.steps.len()
120+
}
83121

84122
pub(crate) fn final_ty(&self) -> Ty {
85123
self.ty.clone()
86124
}
87125
}
88126

89-
impl Iterator for Autoderef<'_, '_> {
127+
impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
90128
type Item = (Ty, usize);
91129

92130
#[tracing::instrument(skip_all)]
93131
fn next(&mut self) -> Option<Self::Item> {
94-
if self.at_start {
95-
self.at_start = false;
132+
if mem::take(&mut self.at_start) {
96133
return Some((self.ty.clone(), 0));
97134
}
98135

@@ -102,7 +139,7 @@ impl Iterator for Autoderef<'_, '_> {
102139

103140
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
104141

105-
self.steps.push((kind, self.ty.clone()));
142+
self.steps.push(kind, &self.ty);
106143
self.ty = new_ty;
107144

108145
Some((self.ty.clone(), self.step_count()))
@@ -129,12 +166,8 @@ pub(crate) fn builtin_deref<'ty>(
129166
match ty.kind(Interner) {
130167
TyKind::Ref(.., ty) => Some(ty),
131168
TyKind::Raw(.., ty) if explicit => Some(ty),
132-
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
133-
if crate::lang_items::is_box(db, adt) {
134-
substs.at(Interner, 0).ty(Interner)
135-
} else {
136-
None
137-
}
169+
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) if crate::lang_items::is_box(db, adt) => {
170+
substs.at(Interner, 0).ty(Interner)
138171
}
139172
_ => None,
140173
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ fn iterate_method_candidates_by_receiver(
10671067
// be found in any of the derefs of receiver_ty, so we have to go through
10681068
// that, including raw derefs.
10691069
table.run_in_snapshot(|table| {
1070-
let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
1070+
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
10711071
while let Some((self_ty, _)) = autoderef.next() {
10721072
iterate_inherent_methods(
10731073
&self_ty,
@@ -1082,7 +1082,7 @@ fn iterate_method_candidates_by_receiver(
10821082
ControlFlow::Continue(())
10831083
})?;
10841084
table.run_in_snapshot(|table| {
1085-
let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
1085+
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
10861086
while let Some((self_ty, _)) = autoderef.next() {
10871087
if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
10881088
// don't try to resolve methods on unknown types
@@ -1657,7 +1657,7 @@ fn autoderef_method_receiver(
16571657
ty: Ty,
16581658
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
16591659
let mut deref_chain: Vec<_> = Vec::new();
1660-
let mut autoderef = autoderef::Autoderef::new(table, ty, false);
1660+
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false);
16611661
while let Some((ty, derefs)) = autoderef.next() {
16621662
deref_chain.push((
16631663
autoderef.table.canonicalize(ty),

0 commit comments

Comments
 (0)