diff options
Diffstat (limited to 'crates')
30 files changed, 631 insertions, 491 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index db4ebada4..8d00f7401 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -59,7 +59,7 @@ use hir_ty::{ | |||
59 | traits::FnTrait, | 59 | traits::FnTrait, |
60 | AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, | 60 | AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, |
61 | DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, | 61 | DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, |
62 | SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind, | 62 | SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind, |
63 | TyVariableKind, WhereClause, | 63 | TyVariableKind, WhereClause, |
64 | }; | 64 | }; |
65 | use itertools::Itertools; | 65 | use 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; | |||
13 | use crate::{ | 13 | use 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 | ||
3 | use hir_def::{AssocContainerId, Lookup, TraitId}; | 3 | use chalk_ir::Mutability; |
4 | use hir_def::{ | ||
5 | type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId, | ||
6 | }; | ||
4 | 7 | ||
5 | use crate::{ | 8 | use 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 | ||
10 | pub trait TyExt { | 15 | pub 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 | ||
14 | impl TyExt for Ty { | 39 | impl 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, ¶meters)) | ||
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 | ||
20 | pub trait ProjectionTyExt { | 243 | pub 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); | |||
162 | impl_intern_key!(InternedLifetimeParamId); | 164 | impl_intern_key!(InternedLifetimeParamId); |
163 | 165 | ||
164 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 166 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
167 | pub struct InternedConstParamId(salsa::InternId); | ||
168 | impl_intern_key!(InternedConstParamId); | ||
169 | |||
170 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
165 | pub struct InternedOpaqueTyId(salsa::InternId); | 171 | pub struct InternedOpaqueTyId(salsa::InternId); |
166 | impl_intern_key!(InternedOpaqueTyId); | 172 | impl_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::{ | |||
227 | use la_arena::Idx; | 227 | use la_arena::Idx; |
228 | use smallvec::{smallvec, SmallVec}; | 228 | use smallvec::{smallvec, SmallVec}; |
229 | 229 | ||
230 | use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyKind}; | 230 | use 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 | }; |
12 | use hir_expand::diagnostics::DiagnosticSink; | 12 | use hir_expand::diagnostics::DiagnosticSink; |
13 | 13 | ||
14 | use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyKind}; | 14 | use crate::{ |
15 | db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyExt, TyKind, | ||
16 | }; | ||
15 | 17 | ||
16 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | 18 | pub(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 | ||
8 | use chalk_ir::BoundVar; | ||
8 | use hir_def::{ | 9 | use hir_def::{ |
9 | db::DefDatabase, | 10 | db::DefDatabase, |
10 | find_path, | 11 | find_path, |
@@ -18,12 +19,12 @@ use hir_def::{ | |||
18 | use hir_expand::name::Name; | 19 | use hir_expand::name::Name; |
19 | 20 | ||
20 | use crate::{ | 21 | use 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 | ||
29 | pub struct HirFormatter<'a> { | 30 | pub struct HirFormatter<'a> { |
@@ -290,6 +291,29 @@ impl HirDisplay for GenericArg { | |||
290 | } | 291 | } |
291 | } | 292 | } |
292 | 293 | ||
294 | impl 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 | |||
311 | impl HirDisplay for BoundVar { | ||
312 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
313 | write!(f, "?{}.{}", self.debruijn.depth(), self.index) | ||
314 | } | ||
315 | } | ||
316 | |||
293 | impl HirDisplay for Ty { | 317 | impl 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 { | |||
850 | impl HirDisplay for LifetimeData { | 876 | impl 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 | }; |
43 | use crate::{ | 43 | use 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 @@ | |||
7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; | 7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; |
8 | use hir_def::lang_item::LangItemTarget; | 8 | use hir_def::lang_item::LangItemTarget; |
9 | 9 | ||
10 | use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyKind}; | 10 | use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyExt, TyKind}; |
11 | 11 | ||
12 | use super::{InEnvironment, InferenceContext}; | 12 | use 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; | |||
15 | use syntax::ast::RangeOp; | 15 | use syntax::ast::RangeOp; |
16 | 16 | ||
17 | use crate::{ | 17 | use 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 | ||
29 | use super::{ | 30 | use 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 | ||
14 | use super::{BindingMode, Expectation, InferenceContext}; | 14 | use super::{BindingMode, Expectation, InferenceContext}; |
15 | use crate::{ | 15 | use 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 | ||
20 | impl<'a> InferenceContext<'a> { | 20 | impl<'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 | }; |
11 | use hir_expand::name::Name; | 11 | use hir_expand::name::Name; |
12 | 12 | ||
13 | use crate::{method_resolution, Interner, Substitution, Ty, TyBuilder, TyKind, ValueTyDefId}; | 13 | use crate::{ |
14 | method_resolution, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId, | ||
15 | }; | ||
14 | 16 | ||
15 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | 17 | use 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 | ||
31 | use std::sync::Arc; | 31 | use std::sync::Arc; |
32 | 32 | ||
33 | use itertools::Itertools; | ||
34 | |||
35 | use base_db::salsa; | 33 | use base_db::salsa; |
34 | use chalk_ir::UintTy; | ||
36 | use hir_def::{ | 35 | use 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 | ||
41 | use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; | 40 | use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; |
@@ -71,6 +70,11 @@ pub type Lifetime = chalk_ir::Lifetime<Interner>; | |||
71 | pub type LifetimeData = chalk_ir::LifetimeData<Interner>; | 70 | pub type LifetimeData = chalk_ir::LifetimeData<Interner>; |
72 | pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>; | 71 | pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>; |
73 | 72 | ||
73 | pub type Const = chalk_ir::Const<Interner>; | ||
74 | pub type ConstData = chalk_ir::ConstData<Interner>; | ||
75 | pub type ConstValue = chalk_ir::ConstValue<Interner>; | ||
76 | pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>; | ||
77 | |||
74 | pub type ChalkTraitId = chalk_ir::TraitId<Interner>; | 78 | pub type ChalkTraitId = chalk_ir::TraitId<Interner>; |
75 | 79 | ||
76 | pub type FnSig = chalk_ir::FnSig<Interner>; | 80 | pub type FnSig = chalk_ir::FnSig<Interner>; |
@@ -165,69 +169,12 @@ impl CallableSig { | |||
165 | } | 169 | } |
166 | 170 | ||
167 | impl Ty { | 171 | impl 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, ¶meters)) | ||
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 | ||
291 | pub 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 | |||
491 | pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId { | 297 | pub 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 { | |||
495 | pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId { | 301 | pub 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 | |||
305 | pub fn static_lifetime() -> Lifetime { | ||
306 | LifetimeData::Static.intern(&Interner) | ||
307 | } | ||
308 | |||
309 | pub 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 | ||
28 | use crate::{ | 28 | use 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 | }; |
27 | use mapping::{ | 27 | use 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 | ||
6 | use chalk_ir::{cast::Cast, interner::HasInterner, LifetimeData}; | 6 | use chalk_ir::{cast::Cast, interner::HasInterner}; |
7 | use chalk_solve::rust_ir; | 7 | use chalk_solve::rust_ir; |
8 | 8 | ||
9 | use base_db::salsa::InternKey; | 9 | use base_db::salsa::InternKey; |
10 | use hir_def::{GenericDefId, TypeAliasId}; | 10 | use hir_def::{GenericDefId, TypeAliasId}; |
11 | 11 | ||
12 | use crate::{ | 12 | use 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 | ||
18 | use super::interner::*; | 19 | use 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 { | |||
192 | fn ref_to_chalk( | 194 | fn 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. |
204 | fn array_to_chalk(db: &dyn HirDatabase, ty: Ty) -> chalk_ir::Ty<Interner> { | 207 | fn 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 | ||
215 | impl ToChalk for GenericArg { | 212 | impl 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::{ | |||
10 | use smallvec::SmallVec; | 10 | use smallvec::SmallVec; |
11 | 11 | ||
12 | use crate::{ | 12 | use 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 { | |||
39 | pub struct DynTy { | 40 | pub 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)] |
56 | pub struct BuildDataResult { | 56 | pub 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 | }; |
14 | use hir_def::FunctionId; | 14 | use hir_def::FunctionId; |
15 | use hir_ty::TypeWalk; | 15 | use hir_ty::{TyExt, TypeWalk}; |
16 | use ide::{AnalysisHost, RootDatabase}; | 16 | use ide::{AnalysisHost, RootDatabase}; |
17 | use ide_db::base_db::{ | 17 | use 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)] | ||
36 | pub(crate) enum Status { | ||
37 | Loading, | ||
38 | Ready { partial: bool }, | ||
39 | Invalid, | ||
40 | NeedsReload, | ||
41 | } | ||
42 | |||
43 | impl Default for Status { | ||
44 | fn default() -> Self { | ||
45 | Status::Loading | ||
46 | } | ||
47 | } | ||
48 | |||
49 | // Enforces drop order | 36 | // Enforces drop order |
50 | pub(crate) struct Handle<H, C> { | 37 | pub(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 | ||
244 | pub enum StatusNotification {} | 244 | pub enum ServerStatusNotification {} |
245 | 245 | ||
246 | #[derive(Serialize, Deserialize)] | 246 | impl Notification for ServerStatusNotification { |
247 | #[serde(rename_all = "camelCase")] | 247 | type Params = ServerStatusParams; |
248 | pub 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)] |
257 | pub struct StatusParams { | 252 | pub struct ServerStatusParams { |
258 | pub status: Status, | 253 | pub health: Health, |
254 | pub quiescent: bool, | ||
255 | pub message: Option<String>, | ||
259 | } | 256 | } |
260 | 257 | ||
261 | impl 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"; | 260 | pub enum Health { |
261 | Ok, | ||
262 | Warning, | ||
263 | Error, | ||
264 | } | 264 | } |
265 | 265 | ||
266 | pub enum CodeActionRequest {} | 266 | pub 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. |
3 | use std::{ | 3 | use 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}; | |||
12 | use ide_db::base_db::VfsPath; | 13 | use ide_db::base_db::VfsPath; |
13 | use lsp_server::{Connection, Notification, Request, Response}; | 14 | use lsp_server::{Connection, Notification, Request, Response}; |
14 | use lsp_types::notification::Notification as _; | 15 | use lsp_types::notification::Notification as _; |
16 | use project_model::BuildDataCollector; | ||
15 | use vfs::ChangeKind; | 17 | use vfs::ChangeKind; |
16 | 18 | ||
17 | use crate::{ | 19 | use 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 | ||
4 | pub(crate) struct OpQueue<Args, Output> { | 4 | pub(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 | ||
10 | impl<Args, Output: Default> Default for OpQueue<Args, Output> { | 10 | impl<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 | ||
16 | impl<Args, Output> OpQueue<Args, Output> { | 16 | impl<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 | ||
10 | use crate::{ | 10 | use 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 | }; |
16 | use lsp_ext::StatusParams; | ||
17 | 16 | ||
18 | #[derive(Debug)] | 17 | #[derive(Debug)] |
19 | pub(crate) enum ProjectWorkspaceProgress { | 18 | pub(crate) enum ProjectWorkspaceProgress { |
@@ -30,6 +29,13 @@ pub(crate) enum BuildDataProgress { | |||
30 | } | 29 | } |
31 | 30 | ||
32 | impl GlobalState { | 31 | impl 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 | }) |