aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--docs/dev/lsp-extensions.md30
-rw-r--r--editors/code/src/client.ts2
-rw-r--r--editors/code/src/ctx.ts47
-rw-r--r--editors/code/src/lsp_ext.ts9
34 files changed, 677 insertions, 533 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 })
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 73be59a82..989771ac6 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
1<!--- 1<!---
2lsp_ext.rs hash: e8a7502bd2b2c2f5 2lsp_ext.rs hash: faae991334a151d0
3 3
4If you need to change the above hash to make the test pass, please check if you 4If you need to change the above hash to make the test pass, please check if you
5need to adjust this doc as well and ping this issue: 5need to adjust this doc as well and ping this issue:
@@ -419,23 +419,37 @@ Returns internal status message, mostly for debugging purposes.
419 419
420Reloads project information (that is, re-executes `cargo metadata`). 420Reloads project information (that is, re-executes `cargo metadata`).
421 421
422## Status Notification 422## Server Status
423 423
424**Experimental Client Capability:** `{ "statusNotification": boolean }` 424**Experimental Client Capability:** `{ "serverStatus": boolean }`
425 425
426**Method:** `rust-analyzer/status` 426**Method:** `experimental/serverStatus`
427 427
428**Notification:** 428**Notification:**
429 429
430```typescript 430```typescript
431interface StatusParams { 431interface ServerStatusParams {
432 status: "loading" | "readyPartial" | "ready" | "invalid" | "needsReload", 432 /// `ok` means that the server is completely functional.
433 ///
434 /// `warning` means that the server is partially functional.
435 /// It can server requests, but some results might be wrong due to,
436 /// for example, some missing dependencies.
437 ///
438 /// `error` means that the server is not functional. For example,
439 /// there's a fatal build configuration problem.
440 health: "ok" | "warning" | "error",
441 /// Is there any pending background work which might change the status?
442 /// For example, are dependencies being downloaded?
443 quiescent: bool,
444 /// Explanatory message to show on hover.
445 message?: string,
433} 446}
434``` 447```
435 448
436This notification is sent from server to client. 449This notification is sent from server to client.
437The client can use it to display persistent status to the user (in modline). 450The client can use it to display *persistent* status to the user (in modline).
438For `needsReload` state, the client can provide a context-menu action to run `rust-analyzer/reloadWorkspace` request. 451It is similar to the `showMessage`, but is intended for stares rather than point-in-time events.
452
439 453
440## Syntax Tree 454## Syntax Tree
441 455
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 0771ca3b6..116f41df6 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -159,7 +159,7 @@ class ExperimentalFeatures implements lc.StaticFeature {
159 caps.snippetTextEdit = true; 159 caps.snippetTextEdit = true;
160 caps.codeActionGroup = true; 160 caps.codeActionGroup = true;
161 caps.hoverActions = true; 161 caps.hoverActions = true;
162 caps.statusNotification = true; 162 caps.serverStatusNotification = true;
163 capabilities.experimental = caps; 163 capabilities.experimental = caps;
164 } 164 }
165 initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { 165 initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index c07583cfa..bd023f803 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -5,7 +5,7 @@ import * as ra from './lsp_ext';
5import { Config } from './config'; 5import { Config } from './config';
6import { createClient } from './client'; 6import { createClient } from './client';
7import { isRustEditor, RustEditor } from './util'; 7import { isRustEditor, RustEditor } from './util';
8import { Status } from './lsp_ext'; 8import { ServerStatusParams } from './lsp_ext';
9 9
10export class Ctx { 10export class Ctx {
11 private constructor( 11 private constructor(
@@ -36,7 +36,7 @@ export class Ctx {
36 36
37 res.pushCleanup(client.start()); 37 res.pushCleanup(client.start());
38 await client.onReady(); 38 await client.onReady();
39 client.onNotification(ra.status, (params) => res.setStatus(params.status)); 39 client.onNotification(ra.serverStatus, (params) => res.setServerStatus(params));
40 return res; 40 return res;
41 } 41 }
42 42
@@ -66,39 +66,28 @@ export class Ctx {
66 return this.extCtx.subscriptions; 66 return this.extCtx.subscriptions;
67 } 67 }
68 68
69 setStatus(status: Status) { 69 setServerStatus(status: ServerStatusParams) {
70 switch (status) { 70 this.statusBar.tooltip = status.message ?? "Ready";
71 case "loading": 71 let icon = "";
72 this.statusBar.text = "$(sync~spin) rust-analyzer"; 72 switch (status.health) {
73 this.statusBar.tooltip = "Loading the project"; 73 case "ok":
74 this.statusBar.command = undefined;
75 this.statusBar.color = undefined; 74 this.statusBar.color = undefined;
76 break; 75 break;
77 case "readyPartial": 76 case "warning":
78 this.statusBar.text = "rust-analyzer"; 77 this.statusBar.tooltip += "\nClick to reload.";
79 this.statusBar.tooltip = "Ready (Partial)";
80 this.statusBar.command = undefined;
81 this.statusBar.color = undefined;
82 break;
83 case "ready":
84 this.statusBar.text = "rust-analyzer";
85 this.statusBar.tooltip = "Ready";
86 this.statusBar.command = undefined;
87 this.statusBar.color = undefined;
88 break;
89 case "invalid":
90 this.statusBar.text = "$(error) rust-analyzer";
91 this.statusBar.tooltip = "Failed to load the project";
92 this.statusBar.command = undefined;
93 this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground");
94 break;
95 case "needsReload":
96 this.statusBar.text = "$(warning) rust-analyzer";
97 this.statusBar.tooltip = "Click to reload";
98 this.statusBar.command = "rust-analyzer.reloadWorkspace"; 78 this.statusBar.command = "rust-analyzer.reloadWorkspace";
99 this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground"); 79 this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground");
80 icon = "$(warning) ";
81 break;
82 case "error":
83 this.statusBar.tooltip += "\nClick to reload.";
84 this.statusBar.command = "rust-analyzer.reloadWorkspace";
85 this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground");
86 icon = "$(error) ";
100 break; 87 break;
101 } 88 }
89 if (!status.quiescent) icon = "$(sync~spin) ";
90 this.statusBar.text = `${icon} rust-analyzer`;
102 } 91 }
103 92
104 pushCleanup(d: Disposable) { 93 pushCleanup(d: Disposable) {
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 00e128b8c..e453bb9e0 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -10,11 +10,12 @@ export interface AnalyzerStatusParams {
10export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>("rust-analyzer/analyzerStatus"); 10export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>("rust-analyzer/analyzerStatus");
11export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage"); 11export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage");
12 12
13export type Status = "loading" | "ready" | "readyPartial" | "invalid" | "needsReload"; 13export interface ServerStatusParams {
14export interface StatusParams { 14 health: "ok" | "warning" | "error";
15 status: Status; 15 quiescent: boolean;
16 message?: string;
16} 17}
17export const status = new lc.NotificationType<StatusParams>("rust-analyzer/status"); 18export const serverStatus = new lc.NotificationType<ServerStatusParams>("experimental/serverStatus");
18 19
19export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace"); 20export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace");
20 21