aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs14
-rw-r--r--crates/hir_ty/src/builder.rs2
-rw-r--r--crates/hir_ty/src/chalk_ext.rs229
-rw-r--r--crates/hir_ty/src/db.rs6
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs4
-rw-r--r--crates/hir_ty/src/display.rs48
-rw-r--r--crates/hir_ty/src/infer.rs2
-rw-r--r--crates/hir_ty/src/infer/coerce.rs8
-rw-r--r--crates/hir_ty/src/infer/expr.rs25
-rw-r--r--crates/hir_ty/src/infer/pat.rs26
-rw-r--r--crates/hir_ty/src/infer/path.rs4
-rw-r--r--crates/hir_ty/src/infer/unify.rs6
-rw-r--r--crates/hir_ty/src/lib.rs241
-rw-r--r--crates/hir_ty/src/lower.rs11
-rw-r--r--crates/hir_ty/src/method_resolution.rs13
-rw-r--r--crates/hir_ty/src/traits/chalk.rs2
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs35
-rw-r--r--crates/hir_ty/src/types.rs10
-rw-r--r--crates/hir_ty/src/walk.rs10
-rw-r--r--crates/project_model/src/build_data.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs62
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs30
-rw-r--r--crates/rust-analyzer/src/main_loop.rs101
-rw-r--r--crates/rust-analyzer/src/op_queue.rs16
-rw-r--r--crates/rust-analyzer/src/reload.rs194
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/support.rs11
30 files changed, 631 insertions, 491 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index db4ebada4..8d00f7401 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -59,7 +59,7 @@ use hir_ty::{
59 traits::FnTrait, 59 traits::FnTrait,
60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, 60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, 61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution,
62 SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind, 62 SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind,
63 TyVariableKind, WhereClause, 63 TyVariableKind, WhereClause,
64}; 64};
65use itertools::Itertools; 65use itertools::Itertools;
@@ -1888,9 +1888,10 @@ impl Type {
1888 substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go) 1888 substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go)
1889 } 1889 }
1890 1890
1891 TyKind::Array(ty) | TyKind::Slice(ty) | TyKind::Raw(_, ty) | TyKind::Ref(_, ty) => { 1891 TyKind::Array(ty, _)
1892 go(ty) 1892 | TyKind::Slice(ty)
1893 } 1893 | TyKind::Raw(_, ty)
1894 | TyKind::Ref(_, _, ty) => go(ty),
1894 1895
1895 TyKind::Scalar(_) 1896 TyKind::Scalar(_)
1896 | TyKind::Str 1897 | TyKind::Str
@@ -2148,7 +2149,10 @@ impl Type {
2148 ); 2149 );
2149 } 2150 }
2150 2151
2151 TyKind::Ref(_, ty) | TyKind::Raw(_, ty) | TyKind::Array(ty) | TyKind::Slice(ty) => { 2152 TyKind::Ref(_, _, ty)
2153 | TyKind::Raw(_, ty)
2154 | TyKind::Array(ty, _)
2155 | TyKind::Slice(ty) => {
2152 walk_type(db, &type_.derived(ty.clone()), cb); 2156 walk_type(db, &type_.derived(ty.clone()), cb);
2153 } 2157 }
2154 2158
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 791915fe0..09512d1ce 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -13,7 +13,7 @@ use smallvec::SmallVec;
13use crate::{ 13use crate::{
14 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, 14 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
15 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, 15 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution,
16 TraitRef, Ty, TyDefId, TyKind, TypeWalk, ValueTyDefId, 16 TraitRef, Ty, TyDefId, TyExt, TyKind, TypeWalk, ValueTyDefId,
17}; 17};
18 18
19/// This is a builder for `Ty` or anything that needs a `Substitution`. 19/// This is a builder for `Ty` or anything that needs a `Substitution`.
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 0f4cb43e9..8e8a1aa48 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -1,20 +1,243 @@
1//! Various extensions traits for Chalk types. 1//! Various extensions traits for Chalk types.
2 2
3use hir_def::{AssocContainerId, Lookup, TraitId}; 3use chalk_ir::Mutability;
4use hir_def::{
5 type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId,
6};
4 7
5use crate::{ 8use crate::{
6 db::HirDatabase, from_assoc_type_id, to_chalk_trait_id, Interner, ProjectionTy, TraitRef, Ty, 9 db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
7 TyKind, 10 from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
11 CallableSig, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
12 Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
8}; 13};
9 14
10pub trait TyExt { 15pub trait TyExt {
11 fn is_unit(&self) -> bool; 16 fn is_unit(&self) -> bool;
17 fn is_never(&self) -> bool;
18 fn is_unknown(&self) -> bool;
19
20 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
21 fn as_tuple(&self) -> Option<&Substitution>;
22 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
23 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
24 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>;
25 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>;
26
27 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
28 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
29
30 fn strip_references(&self) -> &Ty;
31
32 /// If this is a `dyn Trait`, returns that trait.
33 fn dyn_trait(&self) -> Option<TraitId>;
34
35 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
36 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
12} 37}
13 38
14impl TyExt for Ty { 39impl TyExt for Ty {
15 fn is_unit(&self) -> bool { 40 fn is_unit(&self) -> bool {
16 matches!(self.kind(&Interner), TyKind::Tuple(0, _)) 41 matches!(self.kind(&Interner), TyKind::Tuple(0, _))
17 } 42 }
43
44 fn is_never(&self) -> bool {
45 matches!(self.kind(&Interner), TyKind::Never)
46 }
47
48 fn is_unknown(&self) -> bool {
49 matches!(self.kind(&Interner), TyKind::Error)
50 }
51
52 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
53 match self.kind(&Interner) {
54 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
55 _ => None,
56 }
57 }
58
59 fn as_tuple(&self) -> Option<&Substitution> {
60 match self.kind(&Interner) {
61 TyKind::Tuple(_, substs) => Some(substs),
62 _ => None,
63 }
64 }
65
66 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
67 if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) {
68 Some(func)
69 } else {
70 None
71 }
72 }
73 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
74 match self.kind(&Interner) {
75 TyKind::Ref(mutability, lifetime, ty) => Some((ty, *lifetime, *mutability)),
76 _ => None,
77 }
78 }
79
80 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
81 match self.kind(&Interner) {
82 TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)),
83 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
84 _ => None,
85 }
86 }
87
88 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
89 match *self.kind(&Interner) {
90 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
91 TyKind::FnDef(callable, ..) => {
92 Some(db.lookup_intern_callable_def(callable.into()).into())
93 }
94 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
95 TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
96 _ => None,
97 }
98 }
99
100 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
101 match self.kind(&Interner) {
102 &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
103 _ => None,
104 }
105 }
106
107 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
108 match self.kind(&Interner) {
109 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
110 TyKind::FnDef(def, parameters) => {
111 let callable_def = db.lookup_intern_callable_def((*def).into());
112 let sig = db.callable_item_signature(callable_def);
113 Some(sig.substitute(&Interner, &parameters))
114 }
115 TyKind::Closure(.., substs) => {
116 let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner);
117 sig_param.callable_sig(db)
118 }
119 _ => None,
120 }
121 }
122
123 fn dyn_trait(&self) -> Option<TraitId> {
124 let trait_ref = match self.kind(&Interner) {
125 TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
126 match b.skip_binders() {
127 WhereClause::Implemented(trait_ref) => Some(trait_ref),
128 _ => None,
129 }
130 }),
131 _ => None,
132 }?;
133 Some(from_chalk_trait_id(trait_ref.trait_id))
134 }
135
136 fn strip_references(&self) -> &Ty {
137 let mut t: &Ty = self;
138 while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(&Interner) {
139 t = ty;
140 }
141 t
142 }
143
144 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
145 match self.kind(&Interner) {
146 TyKind::OpaqueType(opaque_ty_id, ..) => {
147 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
148 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
149 let krate = def.module(db.upcast()).krate();
150 if let Some(future_trait) = db
151 .lang_item(krate, "future_trait".into())
152 .and_then(|item| item.as_trait())
153 {
154 // This is only used by type walking.
155 // Parameters will be walked outside, and projection predicate is not used.
156 // So just provide the Future trait.
157 let impl_bound = Binders::empty(
158 &Interner,
159 WhereClause::Implemented(TraitRef {
160 trait_id: to_chalk_trait_id(future_trait),
161 substitution: Substitution::empty(&Interner),
162 }),
163 );
164 Some(vec![impl_bound])
165 } else {
166 None
167 }
168 }
169 ImplTraitId::ReturnTypeImplTrait(..) => None,
170 }
171 }
172 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
173 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
174 {
175 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
176 db.return_type_impl_traits(func).map(|it| {
177 let data = (*it)
178 .as_ref()
179 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
180 data.substitute(&Interner, &opaque_ty.substitution)
181 })
182 }
183 // It always has an parameter for Future::Output type.
184 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
185 };
186
187 predicates.map(|it| it.into_value_and_skipped_binders().0)
188 }
189 TyKind::Placeholder(idx) => {
190 let id = from_placeholder_idx(db, *idx);
191 let generic_params = db.generic_params(id.parent);
192 let param_data = &generic_params.types[id.local_id];
193 match param_data.provenance {
194 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
195 let substs = TyBuilder::type_params_subst(db, id.parent);
196 let predicates = db
197 .generic_predicates(id.parent)
198 .into_iter()
199 .map(|pred| pred.clone().substitute(&Interner, &substs))
200 .filter(|wc| match &wc.skip_binders() {
201 WhereClause::Implemented(tr) => {
202 tr.self_type_parameter(&Interner) == self
203 }
204 WhereClause::AliasEq(AliasEq {
205 alias: AliasTy::Projection(proj),
206 ty: _,
207 }) => proj.self_type_parameter(&Interner) == self,
208 _ => false,
209 })
210 .collect::<Vec<_>>();
211
212 Some(predicates)
213 }
214 _ => None,
215 }
216 }
217 _ => None,
218 }
219 }
220
221 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
222 match self.kind(&Interner) {
223 TyKind::AssociatedType(id, ..) => {
224 match from_assoc_type_id(*id).lookup(db.upcast()).container {
225 AssocContainerId::TraitId(trait_id) => Some(trait_id),
226 _ => None,
227 }
228 }
229 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
230 match from_assoc_type_id(projection_ty.associated_ty_id)
231 .lookup(db.upcast())
232 .container
233 {
234 AssocContainerId::TraitId(trait_id) => Some(trait_id),
235 _ => None,
236 }
237 }
238 _ => None,
239 }
240 }
18} 241}
19 242
20pub trait ProjectionTyExt { 243pub trait ProjectionTyExt {
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 07510ae02..326c20240 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -88,6 +88,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
88 #[salsa::interned] 88 #[salsa::interned]
89 fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId; 89 fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId;
90 #[salsa::interned] 90 #[salsa::interned]
91 fn intern_const_param_id(&self, param_id: ConstParamId) -> InternedConstParamId;
92 #[salsa::interned]
91 fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId; 93 fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
92 #[salsa::interned] 94 #[salsa::interned]
93 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId; 95 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
@@ -162,6 +164,10 @@ pub struct InternedLifetimeParamId(salsa::InternId);
162impl_intern_key!(InternedLifetimeParamId); 164impl_intern_key!(InternedLifetimeParamId);
163 165
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
167pub struct InternedConstParamId(salsa::InternId);
168impl_intern_key!(InternedConstParamId);
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
165pub struct InternedOpaqueTyId(salsa::InternId); 171pub struct InternedOpaqueTyId(salsa::InternId);
166impl_intern_key!(InternedOpaqueTyId); 172impl_intern_key!(InternedOpaqueTyId);
167 173
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index db278d0db..d7bf9fdf7 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -315,7 +315,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
315 if pat_ty == match_expr_ty 315 if pat_ty == match_expr_ty
316 || match_expr_ty 316 || match_expr_ty
317 .as_reference() 317 .as_reference()
318 .map(|(match_expr_ty, _)| match_expr_ty == pat_ty) 318 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
319 .unwrap_or(false) 319 .unwrap_or(false)
320 { 320 {
321 // If we had a NotUsefulMatchArm diagnostic, we could 321 // If we had a NotUsefulMatchArm diagnostic, we could
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index 34291578a..e9762622f 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -227,7 +227,7 @@ use hir_def::{
227use la_arena::Idx; 227use la_arena::Idx;
228use smallvec::{smallvec, SmallVec}; 228use smallvec::{smallvec, SmallVec};
229 229
230use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyKind}; 230use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyExt, TyKind};
231 231
232#[derive(Debug, Clone, Copy)] 232#[derive(Debug, Clone, Copy)]
233/// Either a pattern from the source code being analyzed, represented as 233/// Either a pattern from the source code being analyzed, represented as
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index b5efe9df5..ed97dc0e3 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -11,7 +11,9 @@ use hir_def::{
11}; 11};
12use hir_expand::diagnostics::DiagnosticSink; 12use hir_expand::diagnostics::DiagnosticSink;
13 13
14use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyKind}; 14use crate::{
15 db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyExt, TyKind,
16};
15 17
16pub(super) struct UnsafeValidator<'a, 'b: 'a> { 18pub(super) struct UnsafeValidator<'a, 'b: 'a> {
17 owner: DefWithBodyId, 19 owner: DefWithBodyId,
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 4ef8024d0..8fe4ed3fa 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -5,6 +5,7 @@ use std::{
5 fmt::{self, Debug}, 5 fmt::{self, Debug},
6}; 6};
7 7
8use chalk_ir::BoundVar;
8use hir_def::{ 9use hir_def::{
9 db::DefDatabase, 10 db::DefDatabase,
10 find_path, 11 find_path,
@@ -18,12 +19,12 @@ use hir_def::{
18use hir_expand::name::Name; 19use hir_expand::name::Name;
19 20
20use crate::{ 21use crate::{
21 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, 22 const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
22 lt_from_placeholder_idx, primitive, subst_prefix, to_assoc_type_id, traits::chalk::from_chalk, 23 from_placeholder_idx, lt_from_placeholder_idx, primitive, subst_prefix, to_assoc_type_id,
23 utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, DomainGoal, GenericArg, 24 traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId,
24 ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, 25 CallableSig, Const, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime,
25 ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, 26 LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt,
26 WhereClause, 27 QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause,
27}; 28};
28 29
29pub struct HirFormatter<'a> { 30pub struct HirFormatter<'a> {
@@ -290,6 +291,29 @@ impl HirDisplay for GenericArg {
290 } 291 }
291} 292}
292 293
294impl HirDisplay for Const {
295 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
296 let data = self.interned();
297 match data.value {
298 ConstValue::BoundVar(idx) => idx.hir_fmt(f),
299 ConstValue::InferenceVar(..) => write!(f, "_"),
300 ConstValue::Placeholder(idx) => {
301 let id = const_from_placeholder_idx(f.db, idx);
302 let generics = generics(f.db.upcast(), id.parent);
303 let param_data = &generics.params.consts[id.local_id];
304 write!(f, "{}", param_data.name)
305 }
306 ConstValue::Concrete(_) => write!(f, "_"),
307 }
308 }
309}
310
311impl HirDisplay for BoundVar {
312 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
313 write!(f, "?{}.{}", self.debruijn.depth(), self.index)
314 }
315}
316
293impl HirDisplay for Ty { 317impl HirDisplay for Ty {
294 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 318 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
295 if f.should_truncate() { 319 if f.should_truncate() {
@@ -309,12 +333,14 @@ impl HirDisplay for Ty {
309 t.hir_fmt(f)?; 333 t.hir_fmt(f)?;
310 write!(f, "]")?; 334 write!(f, "]")?;
311 } 335 }
312 TyKind::Array(t) => { 336 TyKind::Array(t, c) => {
313 write!(f, "[")?; 337 write!(f, "[")?;
314 t.hir_fmt(f)?; 338 t.hir_fmt(f)?;
315 write!(f, "; _]")?; 339 write!(f, "; ")?;
340 c.hir_fmt(f)?;
341 write!(f, "]")?;
316 } 342 }
317 TyKind::Raw(m, t) | TyKind::Ref(m, t) => { 343 TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
318 let ty_display = 344 let ty_display =
319 t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); 345 t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
320 346
@@ -617,7 +643,7 @@ impl HirDisplay for Ty {
617 } 643 }
618 } 644 }
619 } 645 }
620 TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, 646 TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
621 TyKind::Dyn(dyn_ty) => { 647 TyKind::Dyn(dyn_ty) => {
622 write_bounds_like_dyn_trait_with_prefix( 648 write_bounds_like_dyn_trait_with_prefix(
623 "dyn", 649 "dyn",
@@ -850,7 +876,7 @@ impl HirDisplay for Lifetime {
850impl HirDisplay for LifetimeData { 876impl HirDisplay for LifetimeData {
851 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 877 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
852 match self { 878 match self {
853 LifetimeData::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index), 879 LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
854 LifetimeData::InferenceVar(_) => write!(f, "_"), 880 LifetimeData::InferenceVar(_) => write!(f, "_"),
855 LifetimeData::Placeholder(idx) => { 881 LifetimeData::Placeholder(idx) => {
856 let id = lt_from_placeholder_idx(f.db, *idx); 882 let id = lt_from_placeholder_idx(f.db, *idx);
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 1c3faf5cb..5146d873b 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -42,7 +42,7 @@ use super::{
42}; 42};
43use crate::{ 43use crate::{
44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
45 to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyKind, 45 to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyExt, TyKind,
46}; 46};
47 47
48// This lint has a false positive here. See the link below for details. 48// This lint has a false positive here. See the link below for details.
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 32c273afc..159a53a63 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -7,7 +7,7 @@
7use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 7use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9 9
10use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyKind}; 10use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyExt, TyKind};
11 11
12use super::{InEnvironment, InferenceContext}; 12use super::{InEnvironment, InferenceContext};
13 13
@@ -81,7 +81,7 @@ impl<'a> InferenceContext<'a> {
81 // `&T` -> `*const T` 81 // `&T` -> `*const T`
82 // `&mut T` -> `*mut T`/`*const T` 82 // `&mut T` -> `*mut T`/`*const T`
83 (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..)) 83 (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..))
84 | (TyKind::Ref(Mutability::Mut, substs), &TyKind::Raw(m2, ..)) => { 84 | (TyKind::Ref(Mutability::Mut, _, substs), &TyKind::Raw(m2, ..)) => {
85 from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner); 85 from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner);
86 } 86 }
87 87
@@ -111,7 +111,9 @@ impl<'a> InferenceContext<'a> {
111 // Auto Deref if cannot coerce 111 // Auto Deref if cannot coerce
112 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { 112 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
113 // FIXME: DerefMut 113 // FIXME: DerefMut
114 (TyKind::Ref(_, st1), TyKind::Ref(_, st2)) => self.unify_autoderef_behind_ref(st1, st2), 114 (TyKind::Ref(.., st1), TyKind::Ref(.., st2)) => {
115 self.unify_autoderef_behind_ref(st1, st2)
116 }
115 117
116 // Otherwise, normal unify 118 // Otherwise, normal unify
117 _ => self.unify(&from_ty, to_ty), 119 _ => self.unify(&from_ty, to_ty),
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 2fcc7c549..5b3cdab4e 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -15,15 +15,16 @@ use stdx::always;
15use syntax::ast::RangeOp; 15use syntax::ast::RangeOp;
16 16
17use crate::{ 17use crate::{
18 autoderef, 18 autoderef, dummy_usize_const,
19 lower::lower_to_chalk_mutability, 19 lower::lower_to_chalk_mutability,
20 method_resolution, op, 20 method_resolution, op,
21 primitive::{self, UintTy}, 21 primitive::{self, UintTy},
22 to_chalk_trait_id, 22 static_lifetime, to_chalk_trait_id,
23 traits::{chalk::from_chalk, FnTrait}, 23 traits::{chalk::from_chalk, FnTrait},
24 utils::{generics, variant_data, Generics}, 24 utils::{generics, variant_data, Generics},
25 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner, 25 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
26 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeWalk, 26 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
27 TypeWalk,
27}; 28};
28 29
29use super::{ 30use super::{
@@ -533,7 +534,7 @@ impl<'a> InferenceContext<'a> {
533 let inner_ty = self.infer_expr_inner(*expr, &expectation); 534 let inner_ty = self.infer_expr_inner(*expr, &expectation);
534 match rawness { 535 match rawness {
535 Rawness::RawPtr => TyKind::Raw(mutability, inner_ty), 536 Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
536 Rawness::Ref => TyKind::Ref(mutability, inner_ty), 537 Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty),
537 } 538 }
538 .intern(&Interner) 539 .intern(&Interner)
539 } 540 }
@@ -708,7 +709,7 @@ impl<'a> InferenceContext<'a> {
708 } 709 }
709 Expr::Array(array) => { 710 Expr::Array(array) => {
710 let elem_ty = match expected.ty.kind(&Interner) { 711 let elem_ty = match expected.ty.kind(&Interner) {
711 TyKind::Array(st) | TyKind::Slice(st) => st.clone(), 712 TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
712 _ => self.table.new_type_var(), 713 _ => self.table.new_type_var(),
713 }; 714 };
714 715
@@ -732,17 +733,19 @@ impl<'a> InferenceContext<'a> {
732 } 733 }
733 } 734 }
734 735
735 TyKind::Array(elem_ty).intern(&Interner) 736 TyKind::Array(elem_ty, dummy_usize_const()).intern(&Interner)
736 } 737 }
737 Expr::Literal(lit) => match lit { 738 Expr::Literal(lit) => match lit {
738 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 739 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
739 Literal::String(..) => { 740 Literal::String(..) => {
740 TyKind::Ref(Mutability::Not, TyKind::Str.intern(&Interner)).intern(&Interner) 741 TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
742 .intern(&Interner)
741 } 743 }
742 Literal::ByteString(..) => { 744 Literal::ByteString(..) => {
743 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner); 745 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
744 let array_type = TyKind::Array(byte_type).intern(&Interner); 746 let array_type =
745 TyKind::Ref(Mutability::Not, array_type).intern(&Interner) 747 TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
748 TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
746 } 749 }
747 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner), 750 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
748 Literal::Int(_v, ty) => match ty { 751 Literal::Int(_v, ty) => match ty {
@@ -878,7 +881,9 @@ impl<'a> InferenceContext<'a> {
878 // Apply autoref so the below unification works correctly 881 // Apply autoref so the below unification works correctly
879 // FIXME: return correct autorefs from lookup_method 882 // FIXME: return correct autorefs from lookup_method
880 let actual_receiver_ty = match expected_receiver_ty.as_reference() { 883 let actual_receiver_ty = match expected_receiver_ty.as_reference() {
881 Some((_, mutability)) => TyKind::Ref(mutability, derefed_receiver_ty).intern(&Interner), 884 Some((_, lifetime, mutability)) => {
885 TyKind::Ref(mutability, lifetime, derefed_receiver_ty).intern(&Interner)
886 }
882 _ => derefed_receiver_ty, 887 _ => derefed_receiver_ty,
883 }; 888 };
884 self.unify(&expected_receiver_ty, &actual_receiver_ty); 889 self.unify(&expected_receiver_ty, &actual_receiver_ty);
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index afaf6b28b..12431ae07 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -13,8 +13,8 @@ use hir_expand::name::Name;
13 13
14use super::{BindingMode, Expectation, InferenceContext}; 14use super::{BindingMode, Expectation, InferenceContext};
15use crate::{ 15use crate::{
16 lower::lower_to_chalk_mutability, utils::variant_data, Interner, Substitution, Ty, TyBuilder, 16 lower::lower_to_chalk_mutability, static_lifetime, utils::variant_data, Interner, Substitution,
17 TyKind, 17 Ty, TyBuilder, TyExt, TyKind,
18}; 18};
19 19
20impl<'a> InferenceContext<'a> { 20impl<'a> InferenceContext<'a> {
@@ -104,7 +104,7 @@ impl<'a> InferenceContext<'a> {
104 let body = Arc::clone(&self.body); // avoid borrow checker problem 104 let body = Arc::clone(&self.body); // avoid borrow checker problem
105 105
106 if is_non_ref_pat(&body, pat) { 106 if is_non_ref_pat(&body, pat) {
107 while let Some((inner, mutability)) = expected.as_reference() { 107 while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
108 expected = inner; 108 expected = inner;
109 default_bm = match default_bm { 109 default_bm = match default_bm {
110 BindingMode::Move => BindingMode::Ref(mutability), 110 BindingMode::Move => BindingMode::Ref(mutability),
@@ -162,7 +162,7 @@ impl<'a> InferenceContext<'a> {
162 Pat::Ref { pat, mutability } => { 162 Pat::Ref { pat, mutability } => {
163 let mutability = lower_to_chalk_mutability(*mutability); 163 let mutability = lower_to_chalk_mutability(*mutability);
164 let expectation = match expected.as_reference() { 164 let expectation = match expected.as_reference() {
165 Some((inner_ty, exp_mut)) => { 165 Some((inner_ty, _lifetime, exp_mut)) => {
166 if mutability != exp_mut { 166 if mutability != exp_mut {
167 // FIXME: emit type error? 167 // FIXME: emit type error?
168 } 168 }
@@ -171,7 +171,7 @@ impl<'a> InferenceContext<'a> {
171 _ => self.result.standard_types.unknown.clone(), 171 _ => self.result.standard_types.unknown.clone(),
172 }; 172 };
173 let subty = self.infer_pat(*pat, &expectation, default_bm); 173 let subty = self.infer_pat(*pat, &expectation, default_bm);
174 TyKind::Ref(mutability, subty).intern(&Interner) 174 TyKind::Ref(mutability, static_lifetime(), subty).intern(&Interner)
175 } 175 }
176 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( 176 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
177 p.as_deref(), 177 p.as_deref(),
@@ -204,7 +204,8 @@ impl<'a> InferenceContext<'a> {
204 204
205 let bound_ty = match mode { 205 let bound_ty = match mode {
206 BindingMode::Ref(mutability) => { 206 BindingMode::Ref(mutability) => {
207 TyKind::Ref(mutability, inner_ty.clone()).intern(&Interner) 207 TyKind::Ref(mutability, static_lifetime(), inner_ty.clone())
208 .intern(&Interner)
208 } 209 }
209 BindingMode::Move => inner_ty.clone(), 210 BindingMode::Move => inner_ty.clone(),
210 }; 211 };
@@ -213,17 +214,20 @@ impl<'a> InferenceContext<'a> {
213 return inner_ty; 214 return inner_ty;
214 } 215 }
215 Pat::Slice { prefix, slice, suffix } => { 216 Pat::Slice { prefix, slice, suffix } => {
216 let (container_ty, elem_ty): (fn(_) -> _, _) = match expected.kind(&Interner) { 217 let elem_ty = match expected.kind(&Interner) {
217 TyKind::Array(st) => (TyKind::Array, st.clone()), 218 TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
218 TyKind::Slice(st) => (TyKind::Slice, st.clone()), 219 _ => self.err_ty(),
219 _ => (TyKind::Slice, self.err_ty()),
220 }; 220 };
221 221
222 for pat_id in prefix.iter().chain(suffix) { 222 for pat_id in prefix.iter().chain(suffix) {
223 self.infer_pat(*pat_id, &elem_ty, default_bm); 223 self.infer_pat(*pat_id, &elem_ty, default_bm);
224 } 224 }
225 225
226 let pat_ty = container_ty(elem_ty).intern(&Interner); 226 let pat_ty = match expected.kind(&Interner) {
227 TyKind::Array(_, const_) => TyKind::Array(elem_ty, const_.clone()),
228 _ => TyKind::Slice(elem_ty),
229 }
230 .intern(&Interner);
227 if let Some(slice_pat_id) = slice { 231 if let Some(slice_pat_id) = slice {
228 self.infer_pat(*slice_pat_id, &pat_ty, default_bm); 232 self.infer_pat(*slice_pat_id, &pat_ty, default_bm);
229 } 233 }
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 14f705173..b19d67bb1 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -10,7 +10,9 @@ use hir_def::{
10}; 10};
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use crate::{method_resolution, Interner, Substitution, Ty, TyBuilder, TyKind, ValueTyDefId}; 13use crate::{
14 method_resolution, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
15};
14 16
15use super::{ExprOrPatId, InferenceContext, TraitRef}; 17use super::{ExprOrPatId, InferenceContext, TraitRef};
16 18
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 2f9523325..7d76cda68 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -317,9 +317,11 @@ impl InferenceTable {
317 | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => { 317 | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => {
318 self.unify_substs(substs1, substs2, depth + 1) 318 self.unify_substs(substs1, substs2, depth + 1)
319 } 319 }
320 (TyKind::Ref(_, ty1), TyKind::Ref(_, ty2)) 320 (TyKind::Array(ty1, c1), TyKind::Array(ty2, c2)) if c1 == c2 => {
321 self.unify_inner(ty1, ty2, depth + 1)
322 }
323 (TyKind::Ref(_, _, ty1), TyKind::Ref(_, _, ty2))
321 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2)) 324 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2))
322 | (TyKind::Array(ty1), TyKind::Array(ty2))
323 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1), 325 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1),
324 _ => true, /* we checked equals_ctor already */ 326 _ => true, /* we checked equals_ctor already */
325 } 327 }
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index c3ec12352..f5b658cba 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -30,12 +30,11 @@ mod test_db;
30 30
31use std::sync::Arc; 31use std::sync::Arc;
32 32
33use itertools::Itertools;
34
35use base_db::salsa; 33use base_db::salsa;
34use chalk_ir::UintTy;
36use hir_def::{ 35use hir_def::{
37 expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, 36 expr::ExprId, type_ref::Rawness, ConstParamId, LifetimeParamId, TraitId, TypeAliasId,
38 LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, 37 TypeParamId,
39}; 38};
40 39
41use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; 40use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
@@ -71,6 +70,11 @@ pub type Lifetime = chalk_ir::Lifetime<Interner>;
71pub type LifetimeData = chalk_ir::LifetimeData<Interner>; 70pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
72pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>; 71pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
73 72
73pub type Const = chalk_ir::Const<Interner>;
74pub type ConstData = chalk_ir::ConstData<Interner>;
75pub type ConstValue = chalk_ir::ConstValue<Interner>;
76pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
77
74pub type ChalkTraitId = chalk_ir::TraitId<Interner>; 78pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
75 79
76pub type FnSig = chalk_ir::FnSig<Interner>; 80pub type FnSig = chalk_ir::FnSig<Interner>;
@@ -165,69 +169,12 @@ impl CallableSig {
165} 169}
166 170
167impl Ty { 171impl Ty {
168 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
169 match self.kind(&Interner) {
170 TyKind::Ref(mutability, ty) => Some((ty, *mutability)),
171 _ => None,
172 }
173 }
174
175 pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
176 match self.kind(&Interner) {
177 TyKind::Ref(mutability, ty) => Some((ty, Rawness::Ref, *mutability)),
178 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
179 _ => None,
180 }
181 }
182
183 pub fn strip_references(&self) -> &Ty {
184 let mut t: &Ty = self;
185
186 while let TyKind::Ref(_mutability, ty) = t.kind(&Interner) {
187 t = ty;
188 }
189
190 t
191 }
192
193 pub fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
194 match self.kind(&Interner) {
195 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
196 _ => None,
197 }
198 }
199
200 pub fn as_tuple(&self) -> Option<&Substitution> {
201 match self.kind(&Interner) {
202 TyKind::Tuple(_, substs) => Some(substs),
203 _ => None,
204 }
205 }
206
207 pub fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
208 match *self.kind(&Interner) {
209 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
210 TyKind::FnDef(callable, ..) => {
211 Some(db.lookup_intern_callable_def(callable.into()).into())
212 }
213 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
214 TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
215 _ => None,
216 }
217 }
218
219 pub fn is_never(&self) -> bool {
220 matches!(self.kind(&Interner), TyKind::Never)
221 }
222
223 pub fn is_unknown(&self) -> bool {
224 matches!(self.kind(&Interner), TyKind::Error)
225 }
226
227 pub fn equals_ctor(&self, other: &Ty) -> bool { 172 pub fn equals_ctor(&self, other: &Ty) -> bool {
228 match (self.kind(&Interner), other.kind(&Interner)) { 173 match (self.kind(&Interner), other.kind(&Interner)) {
229 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2, 174 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
230 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_), TyKind::Array(_)) => true, 175 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
176 true
177 }
231 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2, 178 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
232 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2, 179 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
233 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => { 180 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
@@ -252,24 +199,6 @@ impl Ty {
252 } 199 }
253 } 200 }
254 201
255 /// If this is a `dyn Trait` type, this returns the `Trait` part.
256 fn dyn_trait_ref(&self) -> Option<&TraitRef> {
257 match self.kind(&Interner) {
258 TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
259 match b.skip_binders() {
260 WhereClause::Implemented(trait_ref) => Some(trait_ref),
261 _ => None,
262 }
263 }),
264 _ => None,
265 }
266 }
267
268 /// If this is a `dyn Trait`, returns that trait.
269 pub fn dyn_trait(&self) -> Option<TraitId> {
270 self.dyn_trait_ref().map(|it| it.trait_id).map(from_chalk_trait_id)
271 }
272
273 fn builtin_deref(&self) -> Option<Ty> { 202 fn builtin_deref(&self) -> Option<Ty> {
274 match self.kind(&Interner) { 203 match self.kind(&Interner) {
275 TyKind::Ref(.., ty) => Some(ty.clone()), 204 TyKind::Ref(.., ty) => Some(ty.clone()),
@@ -278,37 +207,6 @@ impl Ty {
278 } 207 }
279 } 208 }
280 209
281 pub fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
282 match self.kind(&Interner) {
283 &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
284 _ => None,
285 }
286 }
287
288 pub fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
289 if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) {
290 Some(func)
291 } else {
292 None
293 }
294 }
295
296 pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
297 match self.kind(&Interner) {
298 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
299 TyKind::FnDef(def, parameters) => {
300 let callable_def = db.lookup_intern_callable_def((*def).into());
301 let sig = db.callable_item_signature(callable_def);
302 Some(sig.substitute(&Interner, &parameters))
303 }
304 TyKind::Closure(.., substs) => {
305 let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner);
306 sig_param.callable_sig(db)
307 }
308 _ => None,
309 }
310 }
311
312 /// Returns the type parameters of this type if it has some (i.e. is an ADT 210 /// Returns the type parameters of this type if it has some (i.e. is an ADT
313 /// or function); so if `self` is `Option<u32>`, this returns the `u32`. 211 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
314 pub fn substs(&self) -> Option<&Substitution> { 212 pub fn substs(&self) -> Option<&Substitution> {
@@ -336,104 +234,6 @@ impl Ty {
336 _ => None, 234 _ => None,
337 } 235 }
338 } 236 }
339
340 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
341 match self.kind(&Interner) {
342 TyKind::OpaqueType(opaque_ty_id, ..) => {
343 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
344 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
345 let krate = def.module(db.upcast()).krate();
346 if let Some(future_trait) = db
347 .lang_item(krate, "future_trait".into())
348 .and_then(|item| item.as_trait())
349 {
350 // This is only used by type walking.
351 // Parameters will be walked outside, and projection predicate is not used.
352 // So just provide the Future trait.
353 let impl_bound = Binders::empty(
354 &Interner,
355 WhereClause::Implemented(TraitRef {
356 trait_id: to_chalk_trait_id(future_trait),
357 substitution: Substitution::empty(&Interner),
358 }),
359 );
360 Some(vec![impl_bound])
361 } else {
362 None
363 }
364 }
365 ImplTraitId::ReturnTypeImplTrait(..) => None,
366 }
367 }
368 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
369 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
370 {
371 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
372 db.return_type_impl_traits(func).map(|it| {
373 let data = (*it)
374 .as_ref()
375 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
376 data.substitute(&Interner, &opaque_ty.substitution)
377 })
378 }
379 // It always has an parameter for Future::Output type.
380 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
381 };
382
383 predicates.map(|it| it.into_value_and_skipped_binders().0)
384 }
385 TyKind::Placeholder(idx) => {
386 let id = from_placeholder_idx(db, *idx);
387 let generic_params = db.generic_params(id.parent);
388 let param_data = &generic_params.types[id.local_id];
389 match param_data.provenance {
390 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
391 let substs = TyBuilder::type_params_subst(db, id.parent);
392 let predicates = db
393 .generic_predicates(id.parent)
394 .into_iter()
395 .map(|pred| pred.clone().substitute(&Interner, &substs))
396 .filter(|wc| match &wc.skip_binders() {
397 WhereClause::Implemented(tr) => {
398 tr.self_type_parameter(&Interner) == self
399 }
400 WhereClause::AliasEq(AliasEq {
401 alias: AliasTy::Projection(proj),
402 ty: _,
403 }) => proj.self_type_parameter(&Interner) == self,
404 _ => false,
405 })
406 .collect_vec();
407
408 Some(predicates)
409 }
410 _ => None,
411 }
412 }
413 _ => None,
414 }
415 }
416
417 pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
418 match self.kind(&Interner) {
419 TyKind::AssociatedType(id, ..) => {
420 match from_assoc_type_id(*id).lookup(db.upcast()).container {
421 AssocContainerId::TraitId(trait_id) => Some(trait_id),
422 _ => None,
423 }
424 }
425 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
426 match from_assoc_type_id(projection_ty.associated_ty_id)
427 .lookup(db.upcast())
428 .container
429 {
430 AssocContainerId::TraitId(trait_id) => Some(trait_id),
431 _ => None,
432 }
433 }
434 _ => None,
435 }
436 }
437} 237}
438 238
439#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 239#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
@@ -488,6 +288,12 @@ pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> L
488 db.lookup_intern_lifetime_param_id(interned_id) 288 db.lookup_intern_lifetime_param_id(interned_id)
489} 289}
490 290
291pub fn const_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> ConstParamId {
292 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
293 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
294 db.lookup_intern_const_param_id(interned_id)
295}
296
491pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId { 297pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
492 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id)) 298 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
493} 299}
@@ -495,3 +301,16 @@ pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
495pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId { 301pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
496 salsa::InternKey::from_intern_id(id.0) 302 salsa::InternKey::from_intern_id(id.0)
497} 303}
304
305pub fn static_lifetime() -> Lifetime {
306 LifetimeData::Static.intern(&Interner)
307}
308
309pub fn dummy_usize_const() -> Const {
310 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
311 chalk_ir::ConstData {
312 ty: usize_ty,
313 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
314 }
315 .intern(&Interner)
316}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 3cbb6ad54..8be1bcddb 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -27,7 +27,7 @@ use stdx::impl_from;
27 27
28use crate::{ 28use crate::{
29 db::HirDatabase, 29 db::HirDatabase,
30 to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, 30 dummy_usize_const, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
31 traits::chalk::{Interner, ToChalk}, 31 traits::chalk::{Interner, ToChalk},
32 utils::{ 32 utils::{
33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, 33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
@@ -166,7 +166,7 @@ impl<'a> TyLoweringContext<'a> {
166 } 166 }
167 TypeRef::Array(inner) => { 167 TypeRef::Array(inner) => {
168 let inner_ty = self.lower_ty(inner); 168 let inner_ty = self.lower_ty(inner);
169 TyKind::Array(inner_ty).intern(&Interner) 169 TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner)
170 } 170 }
171 TypeRef::Slice(inner) => { 171 TypeRef::Slice(inner) => {
172 let inner_ty = self.lower_ty(inner); 172 let inner_ty = self.lower_ty(inner);
@@ -174,7 +174,9 @@ impl<'a> TyLoweringContext<'a> {
174 } 174 }
175 TypeRef::Reference(inner, _, mutability) => { 175 TypeRef::Reference(inner, _, mutability) => {
176 let inner_ty = self.lower_ty(inner); 176 let inner_ty = self.lower_ty(inner);
177 TyKind::Ref(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner) 177 let lifetime = static_lifetime();
178 TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
179 .intern(&Interner)
178 } 180 }
179 TypeRef::Placeholder => TyKind::Error.intern(&Interner), 181 TypeRef::Placeholder => TyKind::Error.intern(&Interner),
180 TypeRef::Fn(params, is_varargs) => { 182 TypeRef::Fn(params, is_varargs) => {
@@ -198,7 +200,7 @@ impl<'a> TyLoweringContext<'a> {
198 ) 200 )
199 }); 201 });
200 let bounds = crate::make_only_type_binders(1, bounds); 202 let bounds = crate::make_only_type_binders(1, bounds);
201 TyKind::Dyn(DynTy { bounds }).intern(&Interner) 203 TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(&Interner)
202 } 204 }
203 TypeRef::ImplTrait(bounds) => { 205 TypeRef::ImplTrait(bounds) => {
204 match self.impl_trait_mode { 206 match self.impl_trait_mode {
@@ -390,6 +392,7 @@ impl<'a> TyLoweringContext<'a> {
390 ))), 392 ))),
391 ), 393 ),
392 ), 394 ),
395 lifetime: static_lifetime(),
393 }; 396 };
394 TyKind::Dyn(dyn_ty).intern(&Interner) 397 TyKind::Dyn(dyn_ty).intern(&Interner)
395 }; 398 };
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 6d65d3eb9..ee725fd46 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -19,9 +19,10 @@ use crate::{
19 db::HirDatabase, 19 db::HirDatabase,
20 from_foreign_def_id, 20 from_foreign_def_id,
21 primitive::{self, FloatTy, IntTy, UintTy}, 21 primitive::{self, FloatTy, IntTy, UintTy},
22 static_lifetime,
22 utils::all_super_traits, 23 utils::all_super_traits,
23 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, 24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
24 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyKind, 25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
25 TypeWalk, 26 TypeWalk,
26}; 27};
27 28
@@ -453,7 +454,8 @@ fn iterate_method_candidates_with_autoref(
453 } 454 }
454 let refed = Canonical { 455 let refed = Canonical {
455 binders: deref_chain[0].binders.clone(), 456 binders: deref_chain[0].binders.clone(),
456 value: TyKind::Ref(Mutability::Not, deref_chain[0].value.clone()).intern(&Interner), 457 value: TyKind::Ref(Mutability::Not, static_lifetime(), deref_chain[0].value.clone())
458 .intern(&Interner),
457 }; 459 };
458 if iterate_method_candidates_by_receiver( 460 if iterate_method_candidates_by_receiver(
459 &refed, 461 &refed,
@@ -470,7 +472,8 @@ fn iterate_method_candidates_with_autoref(
470 } 472 }
471 let ref_muted = Canonical { 473 let ref_muted = Canonical {
472 binders: deref_chain[0].binders.clone(), 474 binders: deref_chain[0].binders.clone(),
473 value: TyKind::Ref(Mutability::Mut, deref_chain[0].value.clone()).intern(&Interner), 475 value: TyKind::Ref(Mutability::Mut, static_lifetime(), deref_chain[0].value.clone())
476 .intern(&Interner),
474 }; 477 };
475 if iterate_method_candidates_by_receiver( 478 if iterate_method_candidates_by_receiver(
476 &ref_muted, 479 &ref_muted,
@@ -839,7 +842,9 @@ fn autoderef_method_receiver(
839) -> Vec<Canonical<Ty>> { 842) -> Vec<Canonical<Ty>> {
840 let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); 843 let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
841 // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) 844 // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
842 if let Some(TyKind::Array(parameters)) = deref_chain.last().map(|ty| ty.value.kind(&Interner)) { 845 if let Some(TyKind::Array(parameters, _)) =
846 deref_chain.last().map(|ty| ty.value.kind(&Interner))
847 {
843 let kinds = deref_chain.last().unwrap().binders.clone(); 848 let kinds = deref_chain.last().unwrap().binders.clone();
844 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner); 849 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner);
845 deref_chain.push(Canonical { value: unsized_ty, binders: kinds }) 850 deref_chain.push(Canonical { value: unsized_ty, binders: kinds })
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 5a8b5cd86..f03b92422 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -22,7 +22,7 @@ use crate::{
22 to_assoc_type_id, to_chalk_trait_id, 22 to_assoc_type_id, to_chalk_trait_id,
23 utils::generics, 23 utils::generics,
24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, 24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution,
25 TraitRef, Ty, TyBuilder, TyKind, WhereClause, 25 TraitRef, Ty, TyBuilder, TyExt, TyKind, WhereClause,
26}; 26};
27use mapping::{ 27use mapping::{
28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, 28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 3047fbacb..cf73cb078 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -3,16 +3,17 @@
3//! Chalk (in both directions); plus some helper functions for more specialized 3//! Chalk (in both directions); plus some helper functions for more specialized
4//! conversions. 4//! conversions.
5 5
6use chalk_ir::{cast::Cast, interner::HasInterner, LifetimeData}; 6use chalk_ir::{cast::Cast, interner::HasInterner};
7use chalk_solve::rust_ir; 7use chalk_solve::rust_ir;
8 8
9use base_db::salsa::InternKey; 9use base_db::salsa::InternKey;
10use hir_def::{GenericDefId, TypeAliasId}; 10use hir_def::{GenericDefId, TypeAliasId};
11 11
12use crate::{ 12use crate::{
13 chalk_ext::ProjectionTyExt, db::HirDatabase, primitive::UintTy, AliasTy, CallableDefId, 13 chalk_ext::ProjectionTyExt, db::HirDatabase, dummy_usize_const, static_lifetime, AliasTy,
14 Canonical, DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy, 14 CallableDefId, Canonical, Const, DomainGoal, FnPointer, GenericArg, InEnvironment, Lifetime,
15 QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TypeWalk, WhereClause, 15 OpaqueTy, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk,
16 WhereClause,
16}; 17};
17 18
18use super::interner::*; 19use super::interner::*;
@@ -22,8 +23,8 @@ impl ToChalk for Ty {
22 type Chalk = chalk_ir::Ty<Interner>; 23 type Chalk = chalk_ir::Ty<Interner>;
23 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { 24 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
24 match self.into_inner() { 25 match self.into_inner() {
25 TyKind::Ref(m, ty) => ref_to_chalk(db, m, ty), 26 TyKind::Ref(m, lt, ty) => ref_to_chalk(db, m, lt, ty),
26 TyKind::Array(ty) => array_to_chalk(db, ty), 27 TyKind::Array(ty, size) => array_to_chalk(db, ty, size),
27 TyKind::Function(FnPointer { sig, substitution: substs, .. }) => { 28 TyKind::Function(FnPointer { sig, substitution: substs, .. }) => {
28 let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db)); 29 let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db));
29 chalk_ir::TyKind::Function(chalk_ir::FnPointer { 30 chalk_ir::TyKind::Function(chalk_ir::FnPointer {
@@ -100,7 +101,7 @@ impl ToChalk for Ty {
100 ); 101 );
101 let bounded_ty = chalk_ir::DynTy { 102 let bounded_ty = chalk_ir::DynTy {
102 bounds: chalk_ir::Binders::new(binders, where_clauses), 103 bounds: chalk_ir::Binders::new(binders, where_clauses),
103 lifetime: LifetimeData::Static.intern(&Interner), 104 lifetime: static_lifetime(),
104 }; 105 };
105 chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner) 106 chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner)
106 } 107 }
@@ -110,7 +111,7 @@ impl ToChalk for Ty {
110 fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self { 111 fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
111 match chalk.data(&Interner).kind.clone() { 112 match chalk.data(&Interner).kind.clone() {
112 chalk_ir::TyKind::Error => TyKind::Error, 113 chalk_ir::TyKind::Error => TyKind::Error,
113 chalk_ir::TyKind::Array(ty, _size) => TyKind::Array(from_chalk(db, ty)), 114 chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size),
114 chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx), 115 chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx),
115 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => { 116 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => {
116 let associated_ty = proj.associated_ty_id; 117 let associated_ty = proj.associated_ty_id;
@@ -149,6 +150,7 @@ impl ToChalk for Ty {
149 where_clauses.bounds.binders.clone(), 150 where_clauses.bounds.binders.clone(),
150 crate::QuantifiedWhereClauses::from_iter(&Interner, bounds), 151 crate::QuantifiedWhereClauses::from_iter(&Interner, bounds),
151 ), 152 ),
153 lifetime: static_lifetime(),
152 }) 154 })
153 } 155 }
154 156
@@ -167,8 +169,8 @@ impl ToChalk for Ty {
167 } 169 }
168 chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)), 170 chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)),
169 chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)), 171 chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)),
170 chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => { 172 chalk_ir::TyKind::Ref(mutability, lifetime, ty) => {
171 TyKind::Ref(mutability, from_chalk(db, ty)) 173 TyKind::Ref(mutability, lifetime, from_chalk(db, ty))
172 } 174 }
173 chalk_ir::TyKind::Str => TyKind::Str, 175 chalk_ir::TyKind::Str => TyKind::Str,
174 chalk_ir::TyKind::Never => TyKind::Never, 176 chalk_ir::TyKind::Never => TyKind::Never,
@@ -192,24 +194,19 @@ impl ToChalk for Ty {
192fn ref_to_chalk( 194fn ref_to_chalk(
193 db: &dyn HirDatabase, 195 db: &dyn HirDatabase,
194 mutability: chalk_ir::Mutability, 196 mutability: chalk_ir::Mutability,
197 _lifetime: Lifetime,
195 ty: Ty, 198 ty: Ty,
196) -> chalk_ir::Ty<Interner> { 199) -> chalk_ir::Ty<Interner> {
197 let arg = ty.to_chalk(db); 200 let arg = ty.to_chalk(db);
198 let lifetime = LifetimeData::Static.intern(&Interner); 201 let lifetime = static_lifetime();
199 chalk_ir::TyKind::Ref(mutability, lifetime, arg).intern(&Interner) 202 chalk_ir::TyKind::Ref(mutability, lifetime, arg).intern(&Interner)
200} 203}
201 204
202/// We currently don't model constants, but Chalk does. So, we have to insert a 205/// We currently don't model constants, but Chalk does. So, we have to insert a
203/// fake constant here, because Chalks built-in logic may expect it to be there. 206/// fake constant here, because Chalks built-in logic may expect it to be there.
204fn array_to_chalk(db: &dyn HirDatabase, ty: Ty) -> chalk_ir::Ty<Interner> { 207fn array_to_chalk(db: &dyn HirDatabase, ty: Ty, _: Const) -> chalk_ir::Ty<Interner> {
205 let arg = ty.to_chalk(db); 208 let arg = ty.to_chalk(db);
206 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner); 209 chalk_ir::TyKind::Array(arg, dummy_usize_const()).intern(&Interner)
207 let const_ = chalk_ir::ConstData {
208 ty: usize_ty,
209 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
210 }
211 .intern(&Interner);
212 chalk_ir::TyKind::Array(arg, const_).intern(&Interner)
213} 210}
214 211
215impl ToChalk for GenericArg { 212impl ToChalk for GenericArg {
diff --git a/crates/hir_ty/src/types.rs b/crates/hir_ty/src/types.rs
index d4e07a6b8..89c0ddd1a 100644
--- a/crates/hir_ty/src/types.rs
+++ b/crates/hir_ty/src/types.rs
@@ -10,8 +10,9 @@ use chalk_ir::{
10use smallvec::SmallVec; 10use smallvec::SmallVec;
11 11
12use crate::{ 12use crate::{
13 AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, FnDefId, FnSig, ForeignDefId, 13 AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId,
14 InferenceVar, Interner, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, VariableKinds, 14 InferenceVar, Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind,
15 VariableKinds,
15}; 16};
16 17
17#[derive(Clone, PartialEq, Eq, Debug, Hash)] 18#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -39,6 +40,7 @@ impl ProjectionTy {
39pub struct DynTy { 40pub struct DynTy {
40 /// The unknown self type. 41 /// The unknown self type.
41 pub bounds: Binders<QuantifiedWhereClauses>, 42 pub bounds: Binders<QuantifiedWhereClauses>,
43 pub lifetime: Lifetime,
42} 44}
43 45
44#[derive(Clone, PartialEq, Eq, Debug, Hash)] 46#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -112,7 +114,7 @@ pub enum TyKind {
112 Tuple(usize, Substitution), 114 Tuple(usize, Substitution),
113 115
114 /// An array with the given length. Written as `[T; n]`. 116 /// An array with the given length. Written as `[T; n]`.
115 Array(Ty), 117 Array(Ty, Const),
116 118
117 /// The pointee of an array slice. Written as `[T]`. 119 /// The pointee of an array slice. Written as `[T]`.
118 Slice(Ty), 120 Slice(Ty),
@@ -122,7 +124,7 @@ pub enum TyKind {
122 124
123 /// A reference; a pointer with an associated lifetime. Written as 125 /// A reference; a pointer with an associated lifetime. Written as
124 /// `&'a mut T` or `&'a T`. 126 /// `&'a mut T` or `&'a T`.
125 Ref(Mutability, Ty), 127 Ref(Mutability, Lifetime, Ty),
126 128
127 /// This represents a placeholder for an opaque type in situations where we 129 /// This represents a placeholder for an opaque type in situations where we
128 /// don't know the hidden type (i.e. currently almost always). This is 130 /// don't know the hidden type (i.e. currently almost always). This is
diff --git a/crates/hir_ty/src/walk.rs b/crates/hir_ty/src/walk.rs
index e1e77ba37..41ebf6137 100644
--- a/crates/hir_ty/src/walk.rs
+++ b/crates/hir_ty/src/walk.rs
@@ -153,7 +153,10 @@ impl TypeWalk for Ty {
153 p.walk(f); 153 p.walk(f);
154 } 154 }
155 } 155 }
156 TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => { 156 TyKind::Slice(ty)
157 | TyKind::Array(ty, _)
158 | TyKind::Ref(_, _, ty)
159 | TyKind::Raw(_, ty) => {
157 ty.walk(f); 160 ty.walk(f);
158 } 161 }
159 TyKind::Function(fn_pointer) => { 162 TyKind::Function(fn_pointer) => {
@@ -187,7 +190,10 @@ impl TypeWalk for Ty {
187 TyKind::Alias(AliasTy::Opaque(o_ty)) => { 190 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
188 o_ty.substitution.walk_mut_binders(f, binders); 191 o_ty.substitution.walk_mut_binders(f, binders);
189 } 192 }
190 TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => { 193 TyKind::Slice(ty)
194 | TyKind::Array(ty, _)
195 | TyKind::Ref(_, _, ty)
196 | TyKind::Raw(_, ty) => {
191 ty.walk_mut_binders(f, binders); 197 ty.walk_mut_binders(f, binders);
192 } 198 }
193 TyKind::Function(fn_pointer) => { 199 TyKind::Function(fn_pointer) => {
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
index f7050be4e..c2c87b207 100644
--- a/crates/project_model/src/build_data.rs
+++ b/crates/project_model/src/build_data.rs
@@ -52,7 +52,7 @@ pub struct BuildDataCollector {
52 configs: FxHashMap<AbsPathBuf, BuildDataConfig>, 52 configs: FxHashMap<AbsPathBuf, BuildDataConfig>,
53} 53}
54 54
55#[derive(Debug, Default, PartialEq, Eq)] 55#[derive(Debug, Default, PartialEq, Eq, Clone)]
56pub struct BuildDataResult { 56pub struct BuildDataResult {
57 data: FxHashMap<AbsPathBuf, BuildDataMap>, 57 data: FxHashMap<AbsPathBuf, BuildDataMap>,
58} 58}
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 18fd7ea74..fe9f273b0 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -12,7 +12,7 @@ use hir::{
12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef, 12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
13}; 13};
14use hir_def::FunctionId; 14use hir_def::FunctionId;
15use hir_ty::TypeWalk; 15use hir_ty::{TyExt, TypeWalk};
16use ide::{AnalysisHost, RootDatabase}; 16use ide::{AnalysisHost, RootDatabase};
17use ide_db::base_db::{ 17use ide_db::base_db::{
18 salsa::{self, ParallelDatabase}, 18 salsa::{self, ParallelDatabase},
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index cda272fd4..e012b4452 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -445,8 +445,8 @@ impl Config {
445 pub fn hover_actions(&self) -> bool { 445 pub fn hover_actions(&self) -> bool {
446 self.experimental("hoverActions") 446 self.experimental("hoverActions")
447 } 447 }
448 pub fn status_notification(&self) -> bool { 448 pub fn server_status_notification(&self) -> bool {
449 self.experimental("statusNotification") 449 self.experimental("serverStatusNotification")
450 } 450 }
451 451
452 pub fn publish_diagnostics(&self) -> bool { 452 pub fn publish_diagnostics(&self) -> bool {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 8679c8599..adeb7a97e 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -23,6 +23,7 @@ use crate::{
23 document::DocumentData, 23 document::DocumentData,
24 from_proto, 24 from_proto,
25 line_index::{LineEndings, LineIndex}, 25 line_index::{LineEndings, LineIndex},
26 lsp_ext,
26 main_loop::Task, 27 main_loop::Task,
27 op_queue::OpQueue, 28 op_queue::OpQueue,
28 reload::SourceRootConfig, 29 reload::SourceRootConfig,
@@ -32,20 +33,6 @@ use crate::{
32 Result, 33 Result,
33}; 34};
34 35
35#[derive(Eq, PartialEq, Copy, Clone)]
36pub(crate) enum Status {
37 Loading,
38 Ready { partial: bool },
39 Invalid,
40 NeedsReload,
41}
42
43impl Default for Status {
44 fn default() -> Self {
45 Status::Loading
46 }
47}
48
49// Enforces drop order 36// Enforces drop order
50pub(crate) struct Handle<H, C> { 37pub(crate) struct Handle<H, C> {
51 pub(crate) handle: H, 38 pub(crate) handle: H,
@@ -67,26 +54,36 @@ pub(crate) struct GlobalState {
67 req_queue: ReqQueue, 54 req_queue: ReqQueue,
68 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, 55 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
69 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>, 56 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
70 pub(crate) vfs_config_version: u32,
71 pub(crate) flycheck: Vec<FlycheckHandle>,
72 pub(crate) flycheck_sender: Sender<flycheck::Message>,
73 pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
74 pub(crate) config: Arc<Config>, 57 pub(crate) config: Arc<Config>,
75 pub(crate) analysis_host: AnalysisHost, 58 pub(crate) analysis_host: AnalysisHost,
76 pub(crate) diagnostics: DiagnosticCollection, 59 pub(crate) diagnostics: DiagnosticCollection,
77 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, 60 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
78 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, 61 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
79 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
80 pub(crate) shutdown_requested: bool, 62 pub(crate) shutdown_requested: bool,
81 pub(crate) status: Status, 63 pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
82 pub(crate) source_root_config: SourceRootConfig, 64 pub(crate) source_root_config: SourceRootConfig,
83 pub(crate) proc_macro_client: Option<ProcMacroClient>, 65 pub(crate) proc_macro_client: Option<ProcMacroClient>,
84 66
85 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, 67 pub(crate) flycheck: Vec<FlycheckHandle>,
86 pub(crate) fetch_workspaces_queue: OpQueue<(), ()>, 68 pub(crate) flycheck_sender: Sender<flycheck::Message>,
69 pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
87 70
71 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
72 pub(crate) vfs_config_version: u32,
73 pub(crate) vfs_progress_config_version: u32,
74 pub(crate) vfs_progress_n_total: usize,
75 pub(crate) vfs_progress_n_done: usize,
76
77 /// For both `workspaces` and `workspace_build_data`, the field stores the
78 /// data we actually use, while the `OpQueue` stores the result of the last
79 /// fetch.
80 ///
81 /// If the fetch (partially) fails, we do not update the values.
82 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
83 pub(crate) fetch_workspaces_queue: OpQueue<(), Vec<anyhow::Result<ProjectWorkspace>>>,
88 pub(crate) workspace_build_data: Option<BuildDataResult>, 84 pub(crate) workspace_build_data: Option<BuildDataResult>,
89 pub(crate) fetch_build_data_queue: OpQueue<BuildDataCollector, ()>, 85 pub(crate) fetch_build_data_queue:
86 OpQueue<BuildDataCollector, Option<anyhow::Result<BuildDataResult>>>,
90 87
91 latest_requests: Arc<RwLock<LatestRequests>>, 88 latest_requests: Arc<RwLock<LatestRequests>>,
92} 89}
@@ -124,25 +121,32 @@ impl GlobalState {
124 GlobalState { 121 GlobalState {
125 sender, 122 sender,
126 req_queue: ReqQueue::default(), 123 req_queue: ReqQueue::default(),
127 vfs_config_version: 0,
128 task_pool, 124 task_pool,
129 loader, 125 loader,
130 flycheck: Vec::new(),
131 flycheck_sender,
132 flycheck_receiver,
133 config: Arc::new(config), 126 config: Arc::new(config),
134 analysis_host, 127 analysis_host,
135 diagnostics: Default::default(), 128 diagnostics: Default::default(),
136 mem_docs: FxHashMap::default(), 129 mem_docs: FxHashMap::default(),
137 semantic_tokens_cache: Arc::new(Default::default()), 130 semantic_tokens_cache: Arc::new(Default::default()),
138 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
139 shutdown_requested: false, 131 shutdown_requested: false,
140 status: Status::default(), 132 last_reported_status: None,
141 source_root_config: SourceRootConfig::default(), 133 source_root_config: SourceRootConfig::default(),
142 proc_macro_client: None, 134 proc_macro_client: None,
135
136 flycheck: Vec::new(),
137 flycheck_sender,
138 flycheck_receiver,
139
140 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
141 vfs_config_version: 0,
142 vfs_progress_config_version: 0,
143 vfs_progress_n_total: 0,
144 vfs_progress_n_done: 0,
145
143 workspaces: Arc::new(Vec::new()), 146 workspaces: Arc::new(Vec::new()),
144 fetch_workspaces_queue: OpQueue::default(), 147 fetch_workspaces_queue: OpQueue::default(),
145 workspace_build_data: None, 148 workspace_build_data: None,
149
146 fetch_build_data_queue: OpQueue::default(), 150 fetch_build_data_queue: OpQueue::default(),
147 latest_requests: Default::default(), 151 latest_requests: Default::default(),
148 } 152 }
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 0e1fec209..81a6f22f1 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -241,26 +241,26 @@ pub struct SsrParams {
241 pub selections: Vec<lsp_types::Range>, 241 pub selections: Vec<lsp_types::Range>,
242} 242}
243 243
244pub enum StatusNotification {} 244pub enum ServerStatusNotification {}
245 245
246#[derive(Serialize, Deserialize)] 246impl Notification for ServerStatusNotification {
247#[serde(rename_all = "camelCase")] 247 type Params = ServerStatusParams;
248pub enum Status { 248 const METHOD: &'static str = "experimental/serverStatus";
249 Loading,
250 ReadyPartial,
251 Ready,
252 NeedsReload,
253 Invalid,
254} 249}
255 250
256#[derive(Deserialize, Serialize)] 251#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
257pub struct StatusParams { 252pub struct ServerStatusParams {
258 pub status: Status, 253 pub health: Health,
254 pub quiescent: bool,
255 pub message: Option<String>,
259} 256}
260 257
261impl Notification for StatusNotification { 258#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
262 type Params = StatusParams; 259#[serde(rename_all = "camelCase")]
263 const METHOD: &'static str = "rust-analyzer/status"; 260pub enum Health {
261 Ok,
262 Warning,
263 Error,
264} 264}
265 265
266pub enum CodeActionRequest {} 266pub enum CodeActionRequest {}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index e88f16cc1..a5655116b 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -2,6 +2,7 @@
2//! requests/replies and notifications back to the client. 2//! requests/replies and notifications back to the client.
3use std::{ 3use std::{
4 env, fmt, 4 env, fmt,
5 sync::Arc,
5 time::{Duration, Instant}, 6 time::{Duration, Instant},
6}; 7};
7 8
@@ -12,6 +13,7 @@ use ide::{Canceled, FileId};
12use ide_db::base_db::VfsPath; 13use ide_db::base_db::VfsPath;
13use lsp_server::{Connection, Notification, Request, Response}; 14use lsp_server::{Connection, Notification, Request, Response};
14use lsp_types::notification::Notification as _; 15use lsp_types::notification::Notification as _;
16use project_model::BuildDataCollector;
15use vfs::ChangeKind; 17use vfs::ChangeKind;
16 18
17use crate::{ 19use crate::{
@@ -19,7 +21,7 @@ use crate::{
19 dispatch::{NotificationDispatcher, RequestDispatcher}, 21 dispatch::{NotificationDispatcher, RequestDispatcher},
20 document::DocumentData, 22 document::DocumentData,
21 from_proto, 23 from_proto,
22 global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, 24 global_state::{file_id_to_url, url_to_file_id, GlobalState},
23 handlers, lsp_ext, 25 handlers, lsp_ext,
24 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, 26 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
25 reload::{BuildDataProgress, ProjectWorkspaceProgress}, 27 reload::{BuildDataProgress, ProjectWorkspaceProgress},
@@ -187,7 +189,7 @@ impl GlobalState {
187 log::info!("task queue len: {}", task_queue_len); 189 log::info!("task queue len: {}", task_queue_len);
188 } 190 }
189 191
190 let mut new_status = self.status; 192 let was_quiescent = self.is_quiescent();
191 match event { 193 match event {
192 Event::Lsp(msg) => match msg { 194 Event::Lsp(msg) => match msg {
193 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, 195 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
@@ -227,11 +229,24 @@ impl GlobalState {
227 (Progress::Report, Some(msg)) 229 (Progress::Report, Some(msg))
228 } 230 }
229 ProjectWorkspaceProgress::End(workspaces) => { 231 ProjectWorkspaceProgress::End(workspaces) => {
230 self.fetch_workspaces_completed(); 232 self.fetch_workspaces_completed(workspaces);
231 self.switch_workspaces(workspaces, None); 233
234 let old = Arc::clone(&self.workspaces);
235 self.switch_workspaces();
236 let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
237
238 if self.config.run_build_scripts() && workspaces_updated {
239 let mut collector = BuildDataCollector::default();
240 for ws in self.workspaces.iter() {
241 ws.collect_build_data_configs(&mut collector);
242 }
243 self.fetch_build_data_request(collector)
244 }
245
232 (Progress::End, None) 246 (Progress::End, None)
233 } 247 }
234 }; 248 };
249
235 self.report_progress("fetching", state, msg, None); 250 self.report_progress("fetching", state, msg, None);
236 } 251 }
237 Task::FetchBuildData(progress) => { 252 Task::FetchBuildData(progress) => {
@@ -240,19 +255,21 @@ impl GlobalState {
240 BuildDataProgress::Report(msg) => { 255 BuildDataProgress::Report(msg) => {
241 (Some(Progress::Report), Some(msg)) 256 (Some(Progress::Report), Some(msg))
242 } 257 }
243 BuildDataProgress::End(collector) => { 258 BuildDataProgress::End(build_data_result) => {
244 self.fetch_build_data_completed(); 259 self.fetch_build_data_completed(build_data_result);
245 let workspaces = 260
246 (*self.workspaces).clone().into_iter().map(Ok).collect(); 261 self.switch_workspaces();
247 self.switch_workspaces(workspaces, Some(collector)); 262
248 (Some(Progress::End), None) 263 (Some(Progress::End), None)
249 } 264 }
250 }; 265 };
266
251 if let Some(state) = state { 267 if let Some(state) = state {
252 self.report_progress("loading", state, msg, None); 268 self.report_progress("loading", state, msg, None);
253 } 269 }
254 } 270 }
255 } 271 }
272
256 // Coalesce multiple task events into one loop turn 273 // Coalesce multiple task events into one loop turn
257 task = match self.task_pool.receiver.try_recv() { 274 task = match self.task_pool.receiver.try_recv() {
258 Ok(task) => task, 275 Ok(task) => task,
@@ -298,30 +315,25 @@ impl GlobalState {
298 } 315 }
299 vfs::loader::Message::Progress { n_total, n_done, config_version } => { 316 vfs::loader::Message::Progress { n_total, n_done, config_version } => {
300 always!(config_version <= self.vfs_config_version); 317 always!(config_version <= self.vfs_config_version);
301 if n_total == 0 { 318
302 new_status = Status::Invalid; 319 self.vfs_progress_config_version = config_version;
320 self.vfs_progress_n_total = n_total;
321 self.vfs_progress_n_done = n_done;
322
323 let state = if n_done == 0 {
324 Progress::Begin
325 } else if n_done < n_total {
326 Progress::Report
303 } else { 327 } else {
304 let state = if n_done == 0 { 328 assert_eq!(n_done, n_total);
305 new_status = Status::Loading; 329 Progress::End
306 Progress::Begin 330 };
307 } else if n_done < n_total { 331 self.report_progress(
308 Progress::Report 332 "roots scanned",
309 } else { 333 state,
310 assert_eq!(n_done, n_total); 334 Some(format!("{}/{}", n_done, n_total)),
311 new_status = Status::Ready { 335 Some(Progress::fraction(n_done, n_total)),
312 partial: self.config.run_build_scripts() 336 )
313 && self.workspace_build_data.is_none()
314 || config_version < self.vfs_config_version,
315 };
316 Progress::End
317 };
318 self.report_progress(
319 "roots scanned",
320 state,
321 Some(format!("{}/{}", n_done, n_total)),
322 Some(Progress::fraction(n_done, n_total)),
323 )
324 }
325 } 337 }
326 } 338 }
327 // Coalesce many VFS event into a single loop turn 339 // Coalesce many VFS event into a single loop turn
@@ -397,18 +409,14 @@ impl GlobalState {
397 } 409 }
398 410
399 let state_changed = self.process_changes(); 411 let state_changed = self.process_changes();
400 let prev_status = self.status; 412
401 if prev_status != new_status { 413 if self.is_quiescent() && !was_quiescent {
402 self.transition(new_status);
403 }
404 let is_ready = matches!(self.status, Status::Ready { .. });
405 if prev_status == Status::Loading && is_ready {
406 for flycheck in &self.flycheck { 414 for flycheck in &self.flycheck {
407 flycheck.update(); 415 flycheck.update();
408 } 416 }
409 } 417 }
410 418
411 if is_ready && (state_changed || prev_status == Status::Loading) { 419 if self.is_quiescent() && (!was_quiescent || state_changed) {
412 self.update_file_notifications_on_threadpool(); 420 self.update_file_notifications_on_threadpool();
413 421
414 // Refresh semantic tokens if the client supports it. 422 // Refresh semantic tokens if the client supports it.
@@ -437,9 +445,13 @@ impl GlobalState {
437 } 445 }
438 } 446 }
439 447
440 self.fetch_workspaces_if_needed(); 448 if self.config.cargo_autoreload() {
449 self.fetch_workspaces_if_needed();
450 }
441 self.fetch_build_data_if_needed(); 451 self.fetch_build_data_if_needed();
442 452
453 self.report_new_status_if_needed();
454
443 let loop_duration = loop_start.elapsed(); 455 let loop_duration = loop_start.elapsed();
444 if loop_duration > Duration::from_millis(100) { 456 if loop_duration > Duration::from_millis(100) {
445 log::warn!("overly long loop turn: {:?}", loop_duration); 457 log::warn!("overly long loop turn: {:?}", loop_duration);
@@ -466,7 +478,8 @@ impl GlobalState {
466 return Ok(()); 478 return Ok(());
467 } 479 }
468 480
469 if self.status == Status::Loading && req.method != "shutdown" { 481 // Avoid flashing a bunch of unresolved references during initial load.
482 if self.workspaces.is_empty() && !self.is_quiescent() {
470 self.respond(lsp_server::Response::new_err( 483 self.respond(lsp_server::Response::new_err(
471 req.id, 484 req.id,
472 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) 485 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
@@ -477,7 +490,11 @@ impl GlobalState {
477 } 490 }
478 491
479 RequestDispatcher { req: Some(req), global_state: self } 492 RequestDispatcher { req: Some(req), global_state: self }
480 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))? 493 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| {
494 s.fetch_workspaces_request();
495 s.fetch_workspaces_if_needed();
496 Ok(())
497 })?
481 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 498 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
482 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? 499 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
483 .on_sync::<lsp_types::request::Shutdown>(|s, ()| { 500 .on_sync::<lsp_types::request::Shutdown>(|s, ()| {
diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs
index f71b718bc..1d612a933 100644
--- a/crates/rust-analyzer/src/op_queue.rs
+++ b/crates/rust-analyzer/src/op_queue.rs
@@ -2,27 +2,27 @@
2//! at a time. 2//! at a time.
3 3
4pub(crate) struct OpQueue<Args, Output> { 4pub(crate) struct OpQueue<Args, Output> {
5 op_scheduled: Option<Args>, 5 op_requested: Option<Args>,
6 op_in_progress: bool, 6 op_in_progress: bool,
7 last_op_result: Output, 7 last_op_result: Output,
8} 8}
9 9
10impl<Args, Output: Default> Default for OpQueue<Args, Output> { 10impl<Args, Output: Default> Default for OpQueue<Args, Output> {
11 fn default() -> Self { 11 fn default() -> Self {
12 Self { op_scheduled: None, op_in_progress: false, last_op_result: Default::default() } 12 Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() }
13 } 13 }
14} 14}
15 15
16impl<Args, Output> OpQueue<Args, Output> { 16impl<Args, Output> OpQueue<Args, Output> {
17 pub(crate) fn request_op(&mut self, data: Args) { 17 pub(crate) fn request_op(&mut self, data: Args) {
18 self.op_scheduled = Some(data); 18 self.op_requested = Some(data);
19 } 19 }
20 pub(crate) fn should_start_op(&mut self) -> Option<Args> { 20 pub(crate) fn should_start_op(&mut self) -> Option<Args> {
21 if self.op_in_progress { 21 if self.op_in_progress {
22 return None; 22 return None;
23 } 23 }
24 self.op_in_progress = self.op_scheduled.is_some(); 24 self.op_in_progress = self.op_requested.is_some();
25 self.op_scheduled.take() 25 self.op_requested.take()
26 } 26 }
27 pub(crate) fn op_completed(&mut self, result: Output) { 27 pub(crate) fn op_completed(&mut self, result: Output) {
28 assert!(self.op_in_progress); 28 assert!(self.op_in_progress);
@@ -34,4 +34,10 @@ impl<Args, Output> OpQueue<Args, Output> {
34 pub(crate) fn last_op_result(&self) -> &Output { 34 pub(crate) fn last_op_result(&self) -> &Output {
35 &self.last_op_result 35 &self.last_op_result
36 } 36 }
37 pub(crate) fn op_in_progress(&self) -> bool {
38 self.op_in_progress
39 }
40 pub(crate) fn op_requested(&self) -> bool {
41 self.op_requested.is_some()
42 }
37} 43}
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index d12f891bb..301c7003b 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -9,11 +9,10 @@ use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
9 9
10use crate::{ 10use crate::{
11 config::{Config, FilesWatcher, LinkedProject}, 11 config::{Config, FilesWatcher, LinkedProject},
12 global_state::{GlobalState, Status}, 12 global_state::GlobalState,
13 lsp_ext, 13 lsp_ext,
14 main_loop::Task, 14 main_loop::Task,
15}; 15};
16use lsp_ext::StatusParams;
17 16
18#[derive(Debug)] 17#[derive(Debug)]
19pub(crate) enum ProjectWorkspaceProgress { 18pub(crate) enum ProjectWorkspaceProgress {
@@ -30,6 +29,13 @@ pub(crate) enum BuildDataProgress {
30} 29}
31 30
32impl GlobalState { 31impl GlobalState {
32 pub(crate) fn is_quiescent(&self) -> bool {
33 !(self.fetch_workspaces_queue.op_in_progress()
34 || self.fetch_build_data_queue.op_in_progress()
35 || self.vfs_progress_config_version < self.vfs_config_version
36 || self.vfs_progress_n_done < self.vfs_progress_n_total)
37 }
38
33 pub(crate) fn update_configuration(&mut self, config: Config) { 39 pub(crate) fn update_configuration(&mut self, config: Config) {
34 let _p = profile::span("GlobalState::update_configuration"); 40 let _p = profile::span("GlobalState::update_configuration");
35 let old_config = mem::replace(&mut self.config, Arc::new(config)); 41 let old_config = mem::replace(&mut self.config, Arc::new(config));
@@ -46,25 +52,17 @@ impl GlobalState {
46 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { 52 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) {
47 return; 53 return;
48 } 54 }
49 match self.status {
50 Status::Loading | Status::NeedsReload => return,
51 Status::Ready { .. } | Status::Invalid => (),
52 }
53 log::info!( 55 log::info!(
54 "Reloading workspace because of the following changes: {}", 56 "Requesting workspace reload because of the following changes: {}",
55 itertools::join( 57 itertools::join(
56 changes 58 changes
57 .iter() 59 .iter()
58 .filter(|(path, kind)| is_interesting(path, *kind)) 60 .filter(|(path, kind)| is_interesting(path, *kind))
59 .map(|(path, kind)| format!("{}/{:?}", path.display(), kind)), 61 .map(|(path, kind)| format!("{}: {:?}", path.display(), kind)),
60 ", " 62 ", "
61 ) 63 )
62 ); 64 );
63 if self.config.cargo_autoreload() { 65 self.fetch_workspaces_request();
64 self.fetch_workspaces_request();
65 } else {
66 self.transition(Status::NeedsReload);
67 }
68 66
69 fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool { 67 fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool {
70 const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; 68 const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
@@ -101,46 +99,32 @@ impl GlobalState {
101 false 99 false
102 } 100 }
103 } 101 }
104 pub(crate) fn transition(&mut self, new_status: Status) { 102 pub(crate) fn report_new_status_if_needed(&mut self) {
105 self.status = new_status; 103 if !self.config.server_status_notification() {
106 if self.config.status_notification() { 104 return;
107 let lsp_status = match new_status {
108 Status::Loading => lsp_ext::Status::Loading,
109 Status::Ready { partial: true } => lsp_ext::Status::ReadyPartial,
110 Status::Ready { partial: false } => lsp_ext::Status::Ready,
111 Status::Invalid => lsp_ext::Status::Invalid,
112 Status::NeedsReload => lsp_ext::Status::NeedsReload,
113 };
114 self.send_notification::<lsp_ext::StatusNotification>(StatusParams {
115 status: lsp_status,
116 });
117 } 105 }
118 }
119
120 pub(crate) fn fetch_build_data_request(&mut self, build_data_collector: BuildDataCollector) {
121 self.fetch_build_data_queue.request_op(build_data_collector);
122 }
123 106
124 pub(crate) fn fetch_build_data_if_needed(&mut self) { 107 let mut status = lsp_ext::ServerStatusParams {
125 let mut build_data_collector = match self.fetch_build_data_queue.should_start_op() { 108 health: lsp_ext::Health::Ok,
126 Some(it) => it, 109 quiescent: self.is_quiescent(),
127 None => return, 110 message: None,
128 }; 111 };
129 self.task_pool.handle.spawn_with_sender(move |sender| { 112 if !self.config.cargo_autoreload()
130 sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap(); 113 && self.is_quiescent()
114 && self.fetch_workspaces_queue.op_requested()
115 {
116 status.health = lsp_ext::Health::Warning;
117 status.message = Some("Workspace reload required".to_string())
118 }
119 if let Some(error) = self.loading_error() {
120 status.health = lsp_ext::Health::Error;
121 status.message = Some(format!("Workspace reload failed: {}", error))
122 }
131 123
132 let progress = { 124 if self.last_reported_status.as_ref() != Some(&status) {
133 let sender = sender.clone(); 125 self.last_reported_status = Some(status.clone());
134 move |msg| { 126 self.send_notification::<lsp_ext::ServerStatusNotification>(status);
135 sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap() 127 }
136 }
137 };
138 let res = build_data_collector.collect(&progress);
139 sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap();
140 });
141 }
142 pub(crate) fn fetch_build_data_completed(&mut self) {
143 self.fetch_build_data_queue.op_completed(())
144 } 128 }
145 129
146 pub(crate) fn fetch_workspaces_request(&mut self) { 130 pub(crate) fn fetch_workspaces_request(&mut self) {
@@ -194,57 +178,69 @@ impl GlobalState {
194 } 178 }
195 }); 179 });
196 } 180 }
197 pub(crate) fn fetch_workspaces_completed(&mut self) { 181 pub(crate) fn fetch_workspaces_completed(
198 self.fetch_workspaces_queue.op_completed(()) 182 &mut self,
183 workspaces: Vec<anyhow::Result<ProjectWorkspace>>,
184 ) {
185 self.fetch_workspaces_queue.op_completed(workspaces)
199 } 186 }
200 187
201 pub(crate) fn switch_workspaces( 188 pub(crate) fn fetch_build_data_request(&mut self, build_data_collector: BuildDataCollector) {
189 self.fetch_build_data_queue.request_op(build_data_collector);
190 }
191 pub(crate) fn fetch_build_data_if_needed(&mut self) {
192 let mut build_data_collector = match self.fetch_build_data_queue.should_start_op() {
193 Some(it) => it,
194 None => return,
195 };
196 self.task_pool.handle.spawn_with_sender(move |sender| {
197 sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
198
199 let progress = {
200 let sender = sender.clone();
201 move |msg| {
202 sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
203 }
204 };
205 let res = build_data_collector.collect(&progress);
206 sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap();
207 });
208 }
209 pub(crate) fn fetch_build_data_completed(
202 &mut self, 210 &mut self,
203 workspaces: Vec<anyhow::Result<ProjectWorkspace>>, 211 build_data: anyhow::Result<BuildDataResult>,
204 workspace_build_data: Option<anyhow::Result<BuildDataResult>>,
205 ) { 212 ) {
206 let _p = profile::span("GlobalState::switch_workspaces"); 213 self.fetch_build_data_queue.op_completed(Some(build_data))
207 log::info!("will switch workspaces: {:?}", workspaces); 214 }
208 215
209 let mut has_errors = false; 216 pub(crate) fn switch_workspaces(&mut self) {
210 let workspaces = workspaces 217 let _p = profile::span("GlobalState::switch_workspaces");
211 .into_iter() 218 log::info!("will switch workspaces");
212 .filter_map(|res| {
213 res.map_err(|err| {
214 has_errors = true;
215 log::error!("failed to load workspace: {:#}", err);
216 if self.workspaces.is_empty() {
217 self.show_message(
218 lsp_types::MessageType::Error,
219 format!("rust-analyzer failed to load workspace: {:#}", err),
220 );
221 }
222 })
223 .ok()
224 })
225 .collect::<Vec<_>>();
226 219
227 let workspace_build_data = match workspace_build_data { 220 if let Some(error_message) = self.loading_error() {
228 Some(Ok(it)) => Some(it), 221 log::error!("failed to switch workspaces: {}", error_message);
229 Some(Err(err)) => { 222 self.show_message(lsp_types::MessageType::Error, error_message);
230 log::error!("failed to fetch build data: {:#}", err); 223 if !self.workspaces.is_empty() {
231 self.show_message(
232 lsp_types::MessageType::Error,
233 format!("rust-analyzer failed to fetch build data: {:#}", err),
234 );
235 return; 224 return;
236 } 225 }
237 None => None, 226 }
227
228 let workspaces = self
229 .fetch_workspaces_queue
230 .last_op_result()
231 .iter()
232 .filter_map(|res| res.as_ref().ok().cloned())
233 .collect::<Vec<_>>();
234
235 let workspace_build_data = match self.fetch_build_data_queue.last_op_result() {
236 Some(Ok(it)) => Some(it.clone()),
237 None | Some(Err(_)) => None,
238 }; 238 };
239 239
240 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data { 240 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data {
241 return; 241 return;
242 } 242 }
243 243
244 if !self.workspaces.is_empty() && has_errors {
245 return;
246 }
247
248 if let FilesWatcher::Client = self.config.files().watcher { 244 if let FilesWatcher::Client = self.config.files().watcher {
249 if self.config.did_change_watched_files_dynamic_registration() { 245 if self.config.did_change_watched_files_dynamic_registration() {
250 let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { 246 let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
@@ -337,14 +333,6 @@ impl GlobalState {
337 }; 333 };
338 change.set_crate_graph(crate_graph); 334 change.set_crate_graph(crate_graph);
339 335
340 if self.config.run_build_scripts() && workspace_build_data.is_none() {
341 let mut collector = BuildDataCollector::default();
342 for ws in &workspaces {
343 ws.collect_build_data_configs(&mut collector);
344 }
345 self.fetch_build_data_request(collector)
346 }
347
348 self.source_root_config = project_folders.source_root_config; 336 self.source_root_config = project_folders.source_root_config;
349 self.workspaces = Arc::new(workspaces); 337 self.workspaces = Arc::new(workspaces);
350 self.workspace_build_data = workspace_build_data; 338 self.workspace_build_data = workspace_build_data;
@@ -355,6 +343,24 @@ impl GlobalState {
355 log::info!("did switch workspaces"); 343 log::info!("did switch workspaces");
356 } 344 }
357 345
346 fn loading_error(&self) -> Option<String> {
347 let mut message = None;
348
349 for ws in self.fetch_workspaces_queue.last_op_result() {
350 if let Err(err) = ws {
351 let message = message.get_or_insert_with(String::new);
352 stdx::format_to!(message, "rust-analyzer failed to load workspace: {:#}\n", err);
353 }
354 }
355
356 if let Some(Err(err)) = self.fetch_build_data_queue.last_op_result() {
357 let message = message.get_or_insert_with(String::new);
358 stdx::format_to!(message, "rust-analyzer failed to fetch build data: {:#}\n", err);
359 }
360
361 message
362 }
363
358 fn reload_flycheck(&mut self) { 364 fn reload_flycheck(&mut self) {
359 let _p = profile::span("GlobalState::reload_flycheck"); 365 let _p = profile::span("GlobalState::reload_flycheck");
360 let config = match self.config.flycheck() { 366 let config = match self.config.flycheck() {
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs
index 95bf26f01..8d68f1b7d 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/support.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs
@@ -103,7 +103,7 @@ impl<'a> Project<'a> {
103 ..Default::default() 103 ..Default::default()
104 }), 104 }),
105 experimental: Some(json!({ 105 experimental: Some(json!({
106 "statusNotification": true, 106 "serverStatusNotification": true,
107 })), 107 })),
108 ..Default::default() 108 ..Default::default()
109 }, 109 },
@@ -213,13 +213,12 @@ impl Server {
213 } 213 }
214 pub(crate) fn wait_until_workspace_is_loaded(self) -> Server { 214 pub(crate) fn wait_until_workspace_is_loaded(self) -> Server {
215 self.wait_for_message_cond(1, &|msg: &Message| match msg { 215 self.wait_for_message_cond(1, &|msg: &Message| match msg {
216 Message::Notification(n) if n.method == "rust-analyzer/status" => { 216 Message::Notification(n) if n.method == "experimental/serverStatus" => {
217 let status = n 217 let status = n
218 .clone() 218 .clone()
219 .extract::<lsp_ext::StatusParams>("rust-analyzer/status") 219 .extract::<lsp_ext::ServerStatusParams>("experimental/serverStatus")
220 .unwrap() 220 .unwrap();
221 .status; 221 status.quiescent
222 matches!(status, lsp_ext::Status::Ready)
223 } 222 }
224 _ => false, 223 _ => false,
225 }) 224 })