Skip to content

Commit 2071778

Browse files
committed
Auto merge of rust-lang#17595 - dfireBird:infer-lt, r=flodiebold
Implement lifetime inferring
2 parents fdd5294 + 4ca597a commit 2071778

File tree

14 files changed

+109
-85
lines changed

14 files changed

+109
-85
lines changed

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use triomphe::Arc;
5555

5656
use crate::{
5757
db::HirDatabase,
58-
error_lifetime, fold_tys,
58+
fold_tys,
5959
generics::Generics,
6060
infer::{coerce::CoerceMany, unify::InferenceTable},
6161
lower::ImplTraitLoweringMode,
@@ -327,13 +327,13 @@ pub struct Adjustment {
327327
}
328328

329329
impl Adjustment {
330-
pub fn borrow(m: Mutability, ty: Ty) -> Self {
331-
let ty = TyKind::Ref(m, error_lifetime(), ty).intern(Interner);
332-
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty }
330+
pub fn borrow(m: Mutability, ty: Ty, lt: Lifetime) -> Self {
331+
let ty = TyKind::Ref(m, lt.clone(), ty).intern(Interner);
332+
Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(lt, m)), target: ty }
333333
}
334334
}
335335

336-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
336+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
337337
pub enum Adjust {
338338
/// Go from ! to any type.
339339
NeverToAny,
@@ -353,18 +353,18 @@ pub enum Adjust {
353353
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
354354
pub struct OverloadedDeref(pub Option<Mutability>);
355355

356-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
356+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
357357
pub enum AutoBorrow {
358358
/// Converts from T to &T.
359-
Ref(Mutability),
359+
Ref(Lifetime, Mutability),
360360
/// Converts from T to *T.
361361
RawPtr(Mutability),
362362
}
363363

364364
impl AutoBorrow {
365-
fn mutability(self) -> Mutability {
366-
let (AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) = self;
367-
m
365+
fn mutability(&self) -> Mutability {
366+
let (AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) = self;
367+
*m
368368
}
369369
}
370370

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ impl InferenceContext<'_> {
474474

475475
fn walk_expr_with_adjust(&mut self, tgt_expr: ExprId, adjustment: &[Adjustment]) {
476476
if let Some((last, rest)) = adjustment.split_last() {
477-
match last.kind {
477+
match &last.kind {
478478
Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => {
479479
self.walk_expr_with_adjust(tgt_expr, rest)
480480
}

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

+22-15
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ use triomphe::Arc;
1818
use crate::{
1919
autoderef::{Autoderef, AutoderefKind},
2020
db::HirDatabase,
21-
error_lifetime,
2221
infer::{
2322
Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast,
2423
TypeError, TypeMismatch,
2524
},
2625
utils::ClosureSubst,
27-
Canonical, DomainGoal, FnAbi, FnPointer, FnSig, Guidance, InEnvironment, Interner, Solution,
28-
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
26+
Canonical, DomainGoal, FnAbi, FnPointer, FnSig, Guidance, InEnvironment, Interner, Lifetime,
27+
Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
2928
};
3029

3130
use super::unify::InferenceTable;
@@ -301,7 +300,7 @@ impl InferenceTable<'_> {
301300
// Examine the supertype and consider auto-borrowing.
302301
match to_ty.kind(Interner) {
303302
TyKind::Raw(mt, _) => return self.coerce_ptr(from_ty, to_ty, *mt),
304-
TyKind::Ref(mt, _, _) => return self.coerce_ref(from_ty, to_ty, *mt),
303+
TyKind::Ref(mt, lt, _) => return self.coerce_ref(from_ty, to_ty, *mt, lt),
305304
_ => {}
306305
}
307306

@@ -377,11 +376,17 @@ impl InferenceTable<'_> {
377376
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
378377
/// To match `A` with `B`, autoderef will be performed,
379378
/// calling `deref`/`deref_mut` where necessary.
380-
fn coerce_ref(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceResult {
381-
let from_mt = match from_ty.kind(Interner) {
382-
&TyKind::Ref(mt, _, _) => {
383-
coerce_mutabilities(mt, to_mt)?;
384-
mt
379+
fn coerce_ref(
380+
&mut self,
381+
from_ty: Ty,
382+
to_ty: &Ty,
383+
to_mt: Mutability,
384+
to_lt: &Lifetime,
385+
) -> CoerceResult {
386+
let (_from_lt, from_mt) = match from_ty.kind(Interner) {
387+
TyKind::Ref(mt, lt, _) => {
388+
coerce_mutabilities(*mt, to_mt)?;
389+
(lt.clone(), *mt) // clone is probably not good?
385390
}
386391
_ => return self.unify_and(&from_ty, to_ty, identity),
387392
};
@@ -427,8 +432,8 @@ impl InferenceTable<'_> {
427432
// compare those. Note that this means we use the target
428433
// mutability [1], since it may be that we are coercing
429434
// from `&mut T` to `&U`.
430-
let lt = error_lifetime(); // FIXME: handle lifetimes correctly, see rustc
431-
let derefd_from_ty = TyKind::Ref(to_mt, lt, referent_ty).intern(Interner);
435+
let lt = to_lt; // FIXME: Involve rustc LUB and SUB flag checks
436+
let derefd_from_ty = TyKind::Ref(to_mt, lt.clone(), referent_ty).intern(Interner);
432437
match autoderef.table.try_unify(&derefd_from_ty, to_ty) {
433438
Ok(result) => {
434439
found = Some(result.map(|()| derefd_from_ty));
@@ -472,8 +477,10 @@ impl InferenceTable<'_> {
472477
}
473478

474479
let mut adjustments = auto_deref_adjust_steps(&autoderef);
475-
adjustments
476-
.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(to_mt)), target: ty.clone() });
480+
adjustments.push(Adjustment {
481+
kind: Adjust::Borrow(AutoBorrow::Ref(to_lt.clone(), to_mt)),
482+
target: ty.clone(),
483+
});
477484

478485
success(adjustments, ty, goals)
479486
}
@@ -621,11 +628,11 @@ impl InferenceTable<'_> {
621628
(TyKind::Ref(from_mt, _, from_inner), &TyKind::Ref(to_mt, _, _)) => {
622629
coerce_mutabilities(*from_mt, to_mt)?;
623630

624-
let lt = error_lifetime();
631+
let lt = self.new_lifetime_var();
625632
Some((
626633
Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() },
627634
Adjustment {
628-
kind: Adjust::Borrow(AutoBorrow::Ref(to_mt)),
635+
kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), to_mt)),
629636
target: TyKind::Ref(to_mt, lt, from_inner.clone()).intern(Interner),
630637
},
631638
))

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

+29-10
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,10 @@ impl InferenceContext<'_> {
635635
let inner_ty = self.infer_expr_inner(*expr, &expectation);
636636
match rawness {
637637
Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
638-
Rawness::Ref => TyKind::Ref(mutability, error_lifetime(), inner_ty),
638+
Rawness::Ref => {
639+
let lt = self.table.new_lifetime_var();
640+
TyKind::Ref(mutability, lt, inner_ty)
641+
}
639642
}
640643
.intern(Interner)
641644
}
@@ -786,7 +789,11 @@ impl InferenceContext<'_> {
786789
adj.apply(&mut self.table, base_ty)
787790
});
788791
// mutability will be fixed up in `InferenceContext::infer_mut`;
789-
adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone()));
792+
adj.push(Adjustment::borrow(
793+
Mutability::Not,
794+
self_ty.clone(),
795+
self.table.new_lifetime_var(),
796+
));
790797
self.write_expr_adj(*base, adj);
791798
if let Some(func) = self
792799
.db
@@ -991,7 +998,7 @@ impl InferenceContext<'_> {
991998
match fn_x {
992999
FnTrait::FnOnce => (),
9931000
FnTrait::FnMut => {
994-
if let TyKind::Ref(Mutability::Mut, _, inner) = derefed_callee.kind(Interner) {
1001+
if let TyKind::Ref(Mutability::Mut, lt, inner) = derefed_callee.kind(Interner) {
9951002
if adjustments
9961003
.last()
9971004
.map(|it| matches!(it.kind, Adjust::Borrow(_)))
@@ -1000,15 +1007,27 @@ impl InferenceContext<'_> {
10001007
// prefer reborrow to move
10011008
adjustments
10021009
.push(Adjustment { kind: Adjust::Deref(None), target: inner.clone() });
1003-
adjustments.push(Adjustment::borrow(Mutability::Mut, inner.clone()))
1010+
adjustments.push(Adjustment::borrow(
1011+
Mutability::Mut,
1012+
inner.clone(),
1013+
lt.clone(),
1014+
))
10041015
}
10051016
} else {
1006-
adjustments.push(Adjustment::borrow(Mutability::Mut, derefed_callee.clone()));
1017+
adjustments.push(Adjustment::borrow(
1018+
Mutability::Mut,
1019+
derefed_callee.clone(),
1020+
self.table.new_lifetime_var(),
1021+
));
10071022
}
10081023
}
10091024
FnTrait::Fn => {
10101025
if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) {
1011-
adjustments.push(Adjustment::borrow(Mutability::Not, derefed_callee.clone()));
1026+
adjustments.push(Adjustment::borrow(
1027+
Mutability::Not,
1028+
derefed_callee.clone(),
1029+
self.table.new_lifetime_var(),
1030+
));
10121031
}
10131032
}
10141033
}
@@ -1313,23 +1332,23 @@ impl InferenceContext<'_> {
13131332
Some(sig) => {
13141333
let p_left = &sig.params()[0];
13151334
if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. }) {
1316-
if let &TyKind::Ref(mtbl, _, _) = p_left.kind(Interner) {
1335+
if let TyKind::Ref(mtbl, lt, _) = p_left.kind(Interner) {
13171336
self.write_expr_adj(
13181337
lhs,
13191338
vec![Adjustment {
1320-
kind: Adjust::Borrow(AutoBorrow::Ref(mtbl)),
1339+
kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
13211340
target: p_left.clone(),
13221341
}],
13231342
);
13241343
}
13251344
}
13261345
let p_right = &sig.params()[1];
13271346
if matches!(op, BinaryOp::CmpOp(..)) {
1328-
if let &TyKind::Ref(mtbl, _, _) = p_right.kind(Interner) {
1347+
if let TyKind::Ref(mtbl, lt, _) = p_right.kind(Interner) {
13291348
self.write_expr_adj(
13301349
rhs,
13311350
vec![Adjustment {
1332-
kind: Adjust::Borrow(AutoBorrow::Ref(mtbl)),
1351+
kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)),
13331352
target: p_right.clone(),
13341353
}],
13351354
);

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl InferenceContext<'_> {
2828
Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (),
2929
Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)),
3030
Adjust::Borrow(b) => match b {
31-
AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m,
31+
AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m) => mutability = *m,
3232
},
3333
}
3434
}
@@ -125,7 +125,7 @@ impl InferenceContext<'_> {
125125
.get_mut(&base)
126126
.and_then(|it| it.last_mut());
127127
if let Some(Adjustment {
128-
kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
128+
kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
129129
target,
130130
}) = base_adjustments
131131
{

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

+9-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use stdx::TupleExt;
1212

1313
use crate::{
1414
consteval::{try_const_usize, usize_const},
15-
error_lifetime,
1615
infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
1716
lower::lower_to_chalk_mutability,
1817
primitive::UintTy,
@@ -394,19 +393,20 @@ impl InferenceContext<'_> {
394393
expected: &Ty,
395394
default_bm: BindingMode,
396395
) -> Ty {
397-
let expectation = match expected.as_reference() {
398-
Some((inner_ty, _lifetime, _exp_mut)) => inner_ty.clone(),
396+
let (expectation_type, expectation_lt) = match expected.as_reference() {
397+
Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime.clone()),
399398
None => {
400399
let inner_ty = self.table.new_type_var();
400+
let inner_lt = self.table.new_lifetime_var();
401401
let ref_ty =
402-
TyKind::Ref(mutability, error_lifetime(), inner_ty.clone()).intern(Interner);
402+
TyKind::Ref(mutability, inner_lt.clone(), inner_ty.clone()).intern(Interner);
403403
// Unification failure will be reported by the caller.
404404
self.unify(&ref_ty, expected);
405-
inner_ty
405+
(inner_ty, inner_lt)
406406
}
407407
};
408-
let subty = self.infer_pat(inner_pat, &expectation, default_bm);
409-
TyKind::Ref(mutability, error_lifetime(), subty).intern(Interner)
408+
let subty = self.infer_pat(inner_pat, &expectation_type, default_bm);
409+
TyKind::Ref(mutability, expectation_lt, subty).intern(Interner)
410410
}
411411

412412
fn infer_bind_pat(
@@ -433,7 +433,8 @@ impl InferenceContext<'_> {
433433

434434
let bound_ty = match mode {
435435
BindingMode::Ref(mutability) => {
436-
TyKind::Ref(mutability, error_lifetime(), inner_ty.clone()).intern(Interner)
436+
let inner_lt = self.table.new_lifetime_var();
437+
TyKind::Ref(mutability, inner_lt, inner_ty.clone()).intern(Interner)
437438
}
438439
BindingMode::Move => inner_ty.clone(),
439440
};

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ use triomphe::Arc;
1717

1818
use super::{InferOk, InferResult, InferenceContext, TypeError};
1919
use crate::{
20-
consteval::unknown_const, db::HirDatabase, error_lifetime, fold_generic_args,
21-
fold_tys_and_consts, to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical,
22-
Const, ConstValue, DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData,
23-
Guidance, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy,
24-
ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
25-
TyKind, VariableKind, WhereClause,
20+
consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts,
21+
to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
22+
DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment,
23+
InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar,
24+
Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
25+
WhereClause,
2626
};
2727

2828
impl InferenceContext<'_> {
@@ -105,7 +105,7 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
105105
VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner),
106106
// Chalk can sometimes return new lifetime variables. We just replace them by errors
107107
// for now.
108-
VariableKind::Lifetime => error_lifetime().cast(Interner),
108+
VariableKind::Lifetime => ctx.new_lifetime_var().cast(Interner),
109109
VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner),
110110
}),
111111
);

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,8 @@ impl ReceiverAdjustments {
542542
}
543543
}
544544
if let Some(m) = self.autoref {
545-
let a = Adjustment::borrow(m, ty);
545+
let lt = table.new_lifetime_var();
546+
let a = Adjustment::borrow(m, ty, lt);
546547
ty = a.target.clone();
547548
adjust.push(a);
548549
}

src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
337337
self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into());
338338
Ok(Some(current))
339339
}
340-
Adjust::Borrow(AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) => {
340+
Adjust::Borrow(AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) => {
341341
let Some((p, current)) =
342342
self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)?
343343
else {

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

+4-9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use hir_def::{
2626
AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
2727
};
2828
use hir_expand::{db::ExpandDatabase, FileRange, InFile};
29+
use itertools::Itertools;
2930
use rustc_hash::FxHashMap;
3031
use stdx::format_to;
3132
use syntax::{
@@ -94,7 +95,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
9495
let mut had_annotations = false;
9596
let mut mismatches = FxHashMap::default();
9697
let mut types = FxHashMap::default();
97-
let mut adjustments = FxHashMap::<_, Vec<_>>::default();
98+
let mut adjustments = FxHashMap::default();
9899
for (file_id, annotations) in db.extract_annotations() {
99100
for (range, expected) in annotations {
100101
let file_range = FileRange { file_id, range };
@@ -107,13 +108,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
107108
} else if expected.starts_with("adjustments:") {
108109
adjustments.insert(
109110
file_range,
110-
expected
111-
.trim_start_matches("adjustments:")
112-
.trim()
113-
.split(',')
114-
.map(|it| it.trim().to_owned())
115-
.filter(|it| !it.is_empty())
116-
.collect(),
111+
expected.trim_start_matches("adjustments:").trim().to_owned(),
117112
);
118113
} else {
119114
panic!("unexpected annotation: {expected}");
@@ -200,7 +195,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
200195
adjustments
201196
.iter()
202197
.map(|Adjustment { kind, .. }| format!("{kind:?}"))
203-
.collect::<Vec<_>>()
198+
.join(", ")
204199
);
205200
}
206201
}

0 commit comments

Comments
 (0)