mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
internal: Don't allocate autoderef steps when not needed
This commit is contained in:
parent
737d5088e5
commit
b6ed2f5a41
3 changed files with 60 additions and 26 deletions
|
@ -7,9 +7,10 @@
|
||||||
# prettier format
|
# prettier format
|
||||||
f247090558c9ba3c551566eae5882b7ca865225f
|
f247090558c9ba3c551566eae5882b7ca865225f
|
||||||
|
|
||||||
# subtree syncs
|
# pre-josh subtree syncs
|
||||||
932d85b52946d917deab2c23ead552f7f713b828
|
|
||||||
3e358a6827d83e8d6473913a5e304734aadfed04
|
3e358a6827d83e8d6473913a5e304734aadfed04
|
||||||
|
932d85b52946d917deab2c23ead552f7f713b828
|
||||||
9d2cb42a413e51deb50b36794a2e1605381878fc
|
9d2cb42a413e51deb50b36794a2e1605381878fc
|
||||||
f532576ac53ddcc666bc8d59e0b6437065e2f599
|
b2f6fd4f961fc7e4fbfdb80cae2e6065f8436f15
|
||||||
c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1
|
c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1
|
||||||
|
f532576ac53ddcc666bc8d59e0b6437065e2f599
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
//! reference to a type with the field `bar`. This is an approximation of the
|
//! reference to a type with the field `bar`. This is an approximation of the
|
||||||
//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
|
//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use chalk_ir::cast::Cast;
|
use chalk_ir::cast::Cast;
|
||||||
use hir_def::lang_item::LangItem;
|
use hir_def::lang_item::LangItem;
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
|
@ -37,7 +39,7 @@ pub fn autoderef(
|
||||||
) -> impl Iterator<Item = Ty> {
|
) -> impl Iterator<Item = Ty> {
|
||||||
let mut table = InferenceTable::new(db, env);
|
let mut table = InferenceTable::new(db, env);
|
||||||
let ty = table.instantiate_canonical(ty);
|
let ty = table.instantiate_canonical(ty);
|
||||||
let mut autoderef = Autoderef::new(&mut table, ty, false);
|
let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false);
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
while let Some((ty, _steps)) = autoderef.next() {
|
while let Some((ty, _steps)) = autoderef.next() {
|
||||||
// `ty` may contain unresolved inference variables. Since there's no chance they would be
|
// `ty` may contain unresolved inference variables. Since there's no chance they would be
|
||||||
|
@ -58,41 +60,76 @@ pub fn autoderef(
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait TrackAutoderefSteps {
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
fn push(&mut self, kind: AutoderefKind, ty: &Ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrackAutoderefSteps for usize {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
fn push(&mut self, _: AutoderefKind, _: &Ty) {
|
||||||
|
*self += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TrackAutoderefSteps for Vec<(AutoderefKind, Ty)> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
|
fn push(&mut self, kind: AutoderefKind, ty: &Ty) {
|
||||||
|
self.push((kind, ty.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Autoderef<'a, 'db> {
|
pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> {
|
||||||
pub(crate) table: &'a mut InferenceTable<'db>,
|
pub(crate) table: &'table mut InferenceTable<'db>,
|
||||||
ty: Ty,
|
ty: Ty,
|
||||||
at_start: bool,
|
at_start: bool,
|
||||||
steps: Vec<(AutoderefKind, Ty)>,
|
steps: T,
|
||||||
explicit: bool,
|
explicit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'db> Autoderef<'a, 'db> {
|
impl<'table, 'db> Autoderef<'table, 'db> {
|
||||||
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
|
pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
|
||||||
let ty = table.resolve_ty_shallow(&ty);
|
let ty = table.resolve_ty_shallow(&ty);
|
||||||
Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
|
Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn step_count(&self) -> usize {
|
|
||||||
self.steps.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
|
pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
|
||||||
&self.steps
|
&self.steps
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'table, 'db> Autoderef<'table, 'db, usize> {
|
||||||
|
pub(crate) fn new_no_tracking(
|
||||||
|
table: &'table mut InferenceTable<'db>,
|
||||||
|
ty: Ty,
|
||||||
|
explicit: bool,
|
||||||
|
) -> Self {
|
||||||
|
let ty = table.resolve_ty_shallow(&ty);
|
||||||
|
Autoderef { table, ty, at_start: true, steps: 0, explicit }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(private_bounds)]
|
||||||
|
impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> {
|
||||||
|
pub(crate) fn step_count(&self) -> usize {
|
||||||
|
self.steps.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn final_ty(&self) -> Ty {
|
pub(crate) fn final_ty(&self) -> Ty {
|
||||||
self.ty.clone()
|
self.ty.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for Autoderef<'_, '_> {
|
impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
|
||||||
type Item = (Ty, usize);
|
type Item = (Ty, usize);
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.at_start {
|
if mem::take(&mut self.at_start) {
|
||||||
self.at_start = false;
|
|
||||||
return Some((self.ty.clone(), 0));
|
return Some((self.ty.clone(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +139,7 @@ impl Iterator for Autoderef<'_, '_> {
|
||||||
|
|
||||||
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
|
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
|
||||||
|
|
||||||
self.steps.push((kind, self.ty.clone()));
|
self.steps.push(kind, &self.ty);
|
||||||
self.ty = new_ty;
|
self.ty = new_ty;
|
||||||
|
|
||||||
Some((self.ty.clone(), self.step_count()))
|
Some((self.ty.clone(), self.step_count()))
|
||||||
|
@ -129,12 +166,8 @@ pub(crate) fn builtin_deref<'ty>(
|
||||||
match ty.kind(Interner) {
|
match ty.kind(Interner) {
|
||||||
TyKind::Ref(.., ty) => Some(ty),
|
TyKind::Ref(.., ty) => Some(ty),
|
||||||
TyKind::Raw(.., ty) if explicit => Some(ty),
|
TyKind::Raw(.., ty) if explicit => Some(ty),
|
||||||
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
|
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) if crate::lang_items::is_box(db, adt) => {
|
||||||
if crate::lang_items::is_box(db, adt) {
|
substs.at(Interner, 0).ty(Interner)
|
||||||
substs.at(Interner, 0).ty(Interner)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1067,7 +1067,7 @@ fn iterate_method_candidates_by_receiver(
|
||||||
// be found in any of the derefs of receiver_ty, so we have to go through
|
// be found in any of the derefs of receiver_ty, so we have to go through
|
||||||
// that, including raw derefs.
|
// that, including raw derefs.
|
||||||
table.run_in_snapshot(|table| {
|
table.run_in_snapshot(|table| {
|
||||||
let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
|
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
|
||||||
while let Some((self_ty, _)) = autoderef.next() {
|
while let Some((self_ty, _)) = autoderef.next() {
|
||||||
iterate_inherent_methods(
|
iterate_inherent_methods(
|
||||||
&self_ty,
|
&self_ty,
|
||||||
|
@ -1082,7 +1082,7 @@ fn iterate_method_candidates_by_receiver(
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
})?;
|
})?;
|
||||||
table.run_in_snapshot(|table| {
|
table.run_in_snapshot(|table| {
|
||||||
let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
|
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
|
||||||
while let Some((self_ty, _)) = autoderef.next() {
|
while let Some((self_ty, _)) = autoderef.next() {
|
||||||
if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
|
if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
|
||||||
// don't try to resolve methods on unknown types
|
// don't try to resolve methods on unknown types
|
||||||
|
@ -1657,7 +1657,7 @@ fn autoderef_method_receiver(
|
||||||
ty: Ty,
|
ty: Ty,
|
||||||
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
|
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
|
||||||
let mut deref_chain: Vec<_> = Vec::new();
|
let mut deref_chain: Vec<_> = Vec::new();
|
||||||
let mut autoderef = autoderef::Autoderef::new(table, ty, false);
|
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false);
|
||||||
while let Some((ty, derefs)) = autoderef.next() {
|
while let Some((ty, derefs)) = autoderef.next() {
|
||||||
deref_chain.push((
|
deref_chain.push((
|
||||||
autoderef.table.canonicalize(ty),
|
autoderef.table.canonicalize(ty),
|
||||||
|
|
Loading…
Reference in a new issue