aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/source_analyzer.rs15
-rw-r--r--crates/hir_def/src/body/lower.rs29
-rw-r--r--crates/hir_def/src/expr.rs19
-rw-r--r--crates/hir_def/src/lib.rs13
-rw-r--r--crates/hir_def/src/path.rs6
-rw-r--r--crates/hir_ty/src/builder.rs2
-rw-r--r--crates/hir_ty/src/chalk_ext.rs229
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs9
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs4
-rw-r--r--crates/hir_ty/src/infer.rs7
-rw-r--r--crates/hir_ty/src/infer/coerce.rs2
-rw-r--r--crates/hir_ty/src/infer/expr.rs20
-rw-r--r--crates/hir_ty/src/infer/pat.rs12
-rw-r--r--crates/hir_ty/src/infer/path.rs4
-rw-r--r--crates/hir_ty/src/lib.rs214
-rw-r--r--crates/hir_ty/src/lower.rs5
-rw-r--r--crates/hir_ty/src/method_resolution.rs2
-rw-r--r--crates/hir_ty/src/traits/chalk.rs2
-rw-r--r--crates/hir_ty/src/utils.rs13
-rw-r--r--crates/paths/src/lib.rs7
-rw-r--r--crates/project_model/src/build_data.rs86
-rw-r--r--crates/project_model/src/workspace.rs10
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs62
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs30
-rw-r--r--crates/rust-analyzer/src/main_loop.rs101
-rw-r--r--crates/rust-analyzer/src/op_queue.rs16
-rw-r--r--crates/rust-analyzer/src/reload.rs213
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/support.rs11
-rw-r--r--crates/stdx/src/lib.rs8
-rw-r--r--crates/vfs/Cargo.toml1
-rw-r--r--crates/vfs/src/path_interner.rs29
35 files changed, 665 insertions, 526 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index dfc1d8a0c..8d00f7401 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -59,7 +59,7 @@ use hir_ty::{
59 traits::FnTrait, 59 traits::FnTrait,
60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, 60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, 61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution,
62 SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind, 62 SolutionVariables, Substitution, TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind,
63 TyVariableKind, WhereClause, 63 TyVariableKind, WhereClause,
64}; 64};
65use itertools::Itertools; 65use itertools::Itertools;
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 4ce1c2080..c013e78d9 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -161,14 +161,15 @@ impl SourceAnalyzer {
161 db: &dyn HirDatabase, 161 db: &dyn HirDatabase,
162 field: &ast::RecordExprField, 162 field: &ast::RecordExprField,
163 ) -> Option<(Field, Option<Local>)> { 163 ) -> Option<(Field, Option<Local>)> {
164 let expr_id = 164 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
165 self.body_source_map.as_ref()?.node_field(InFile::new(self.file_id, field))?; 165 let expr = ast::Expr::from(record_expr);
166 let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?;
166 167
168 let local_name = field.field_name()?.as_name();
167 let local = if field.name_ref().is_some() { 169 let local = if field.name_ref().is_some() {
168 None 170 None
169 } else { 171 } else {
170 let local_name = field.field_name()?.as_name(); 172 let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
171 let path = ModPath::from_segments(PathKind::Plain, once(local_name));
172 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { 173 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
173 Some(ValueNs::LocalBinding(pat_id)) => { 174 Some(ValueNs::LocalBinding(pat_id)) => {
174 Some(Local { pat_id, parent: self.resolver.body_owner()? }) 175 Some(Local { pat_id, parent: self.resolver.body_owner()? })
@@ -176,8 +177,10 @@ impl SourceAnalyzer {
176 _ => None, 177 _ => None,
177 } 178 }
178 }; 179 };
179 let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; 180 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
180 Some((struct_field.into(), local)) 181 let variant_data = variant.variant_data(db.upcast());
182 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
183 Some((field.into(), local))
181 } 184 }
182 185
183 pub(crate) fn resolve_record_pat_field( 186 pub(crate) fn resolve_record_pat_field(
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 63e89a1f4..bfb75a8a5 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -30,6 +30,7 @@ use crate::{
30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
31 Statement, 31 Statement,
32 }, 32 },
33 intern::Interned,
33 item_scope::BuiltinShadowMode, 34 item_scope::BuiltinShadowMode,
34 path::{GenericArgs, Path}, 35 path::{GenericArgs, Path},
35 type_ref::{Mutability, Rawness, TypeRef}, 36 type_ref::{Mutability, Rawness, TypeRef},
@@ -322,8 +323,10 @@ impl ExprCollector<'_> {
322 Vec::new() 323 Vec::new()
323 }; 324 };
324 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 325 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
325 let generic_args = 326 let generic_args = e
326 e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); 327 .generic_arg_list()
328 .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
329 .map(Box::new);
327 self.alloc_expr( 330 self.alloc_expr(
328 Expr::MethodCall { receiver, method_name, args, generic_args }, 331 Expr::MethodCall { receiver, method_name, args, generic_args },
329 syntax_ptr, 332 syntax_ptr,
@@ -385,7 +388,7 @@ impl ExprCollector<'_> {
385 self.alloc_expr(Expr::Yield { expr }, syntax_ptr) 388 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
386 } 389 }
387 ast::Expr::RecordExpr(e) => { 390 ast::Expr::RecordExpr(e) => {
388 let path = e.path().and_then(|path| self.expander.parse_path(path)); 391 let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
389 let record_lit = if let Some(nfl) = e.record_expr_field_list() { 392 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
390 let fields = nfl 393 let fields = nfl
391 .fields() 394 .fields()
@@ -430,7 +433,7 @@ impl ExprCollector<'_> {
430 } 433 }
431 ast::Expr::CastExpr(e) => { 434 ast::Expr::CastExpr(e) => {
432 let expr = self.collect_expr_opt(e.expr()); 435 let expr = self.collect_expr_opt(e.expr());
433 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); 436 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
434 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 437 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
435 } 438 }
436 ast::Expr::RefExpr(e) => { 439 ast::Expr::RefExpr(e) => {
@@ -464,13 +467,16 @@ impl ExprCollector<'_> {
464 if let Some(pl) = e.param_list() { 467 if let Some(pl) = e.param_list() {
465 for param in pl.params() { 468 for param in pl.params() {
466 let pat = self.collect_pat_opt(param.pat()); 469 let pat = self.collect_pat_opt(param.pat());
467 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 470 let type_ref =
471 param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
468 args.push(pat); 472 args.push(pat);
469 arg_types.push(type_ref); 473 arg_types.push(type_ref);
470 } 474 }
471 } 475 }
472 let ret_type = 476 let ret_type = e
473 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); 477 .ret_type()
478 .and_then(|r| r.ty())
479 .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
474 let body = self.collect_expr_opt(e.body()); 480 let body = self.collect_expr_opt(e.body());
475 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 481 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
476 } 482 }
@@ -625,7 +631,8 @@ impl ExprCollector<'_> {
625 return; 631 return;
626 } 632 }
627 let pat = self.collect_pat_opt(stmt.pat()); 633 let pat = self.collect_pat_opt(stmt.pat());
628 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 634 let type_ref =
635 stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
629 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 636 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
630 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); 637 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
631 } 638 }
@@ -755,7 +762,7 @@ impl ExprCollector<'_> {
755 } 762 }
756 } 763 }
757 ast::Pat::TupleStructPat(p) => { 764 ast::Pat::TupleStructPat(p) => {
758 let path = p.path().and_then(|path| self.expander.parse_path(path)); 765 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
759 let (args, ellipsis) = self.collect_tuple_pat(p.fields()); 766 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
760 Pat::TupleStruct { path, args, ellipsis } 767 Pat::TupleStruct { path, args, ellipsis }
761 } 768 }
@@ -765,7 +772,7 @@ impl ExprCollector<'_> {
765 Pat::Ref { pat, mutability } 772 Pat::Ref { pat, mutability }
766 } 773 }
767 ast::Pat::PathPat(p) => { 774 ast::Pat::PathPat(p) => {
768 let path = p.path().and_then(|path| self.expander.parse_path(path)); 775 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
769 path.map(Pat::Path).unwrap_or(Pat::Missing) 776 path.map(Pat::Path).unwrap_or(Pat::Missing)
770 } 777 }
771 ast::Pat::OrPat(p) => { 778 ast::Pat::OrPat(p) => {
@@ -779,7 +786,7 @@ impl ExprCollector<'_> {
779 } 786 }
780 ast::Pat::WildcardPat(_) => Pat::Wild, 787 ast::Pat::WildcardPat(_) => Pat::Wild,
781 ast::Pat::RecordPat(p) => { 788 ast::Pat::RecordPat(p) => {
782 let path = p.path().and_then(|path| self.expander.parse_path(path)); 789 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
783 let args: Vec<_> = p 790 let args: Vec<_> = p
784 .record_pat_field_list() 791 .record_pat_field_list()
785 .expect("every struct should have a field list") 792 .expect("every struct should have a field list")
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index 6c7376fad..b4ad984bd 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -18,6 +18,7 @@ use syntax::ast::RangeOp;
18 18
19use crate::{ 19use crate::{
20 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, 20 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
21 intern::Interned,
21 path::{GenericArgs, Path}, 22 path::{GenericArgs, Path},
22 type_ref::{Mutability, Rawness, TypeRef}, 23 type_ref::{Mutability, Rawness, TypeRef},
23 BlockId, 24 BlockId,
@@ -86,7 +87,7 @@ pub enum Expr {
86 receiver: ExprId, 87 receiver: ExprId,
87 method_name: Name, 88 method_name: Name,
88 args: Vec<ExprId>, 89 args: Vec<ExprId>,
89 generic_args: Option<GenericArgs>, 90 generic_args: Option<Box<GenericArgs>>,
90 }, 91 },
91 Match { 92 Match {
92 expr: ExprId, 93 expr: ExprId,
@@ -106,7 +107,7 @@ pub enum Expr {
106 expr: Option<ExprId>, 107 expr: Option<ExprId>,
107 }, 108 },
108 RecordLit { 109 RecordLit {
109 path: Option<Path>, 110 path: Option<Box<Path>>,
110 fields: Vec<RecordLitField>, 111 fields: Vec<RecordLitField>,
111 spread: Option<ExprId>, 112 spread: Option<ExprId>,
112 }, 113 },
@@ -131,7 +132,7 @@ pub enum Expr {
131 }, 132 },
132 Cast { 133 Cast {
133 expr: ExprId, 134 expr: ExprId,
134 type_ref: TypeRef, 135 type_ref: Interned<TypeRef>,
135 }, 136 },
136 Ref { 137 Ref {
137 expr: ExprId, 138 expr: ExprId,
@@ -161,8 +162,8 @@ pub enum Expr {
161 }, 162 },
162 Lambda { 163 Lambda {
163 args: Vec<PatId>, 164 args: Vec<PatId>,
164 arg_types: Vec<Option<TypeRef>>, 165 arg_types: Vec<Option<Interned<TypeRef>>>,
165 ret_type: Option<TypeRef>, 166 ret_type: Option<Interned<TypeRef>>,
166 body: ExprId, 167 body: ExprId,
167 }, 168 },
168 Tuple { 169 Tuple {
@@ -240,7 +241,7 @@ pub struct RecordLitField {
240 241
241#[derive(Debug, Clone, Eq, PartialEq)] 242#[derive(Debug, Clone, Eq, PartialEq)]
242pub enum Statement { 243pub enum Statement {
243 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, 244 Let { pat: PatId, type_ref: Option<Interned<TypeRef>>, initializer: Option<ExprId> },
244 Expr(ExprId), 245 Expr(ExprId),
245} 246}
246 247
@@ -412,13 +413,13 @@ pub enum Pat {
412 Wild, 413 Wild,
413 Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, 414 Tuple { args: Vec<PatId>, ellipsis: Option<usize> },
414 Or(Vec<PatId>), 415 Or(Vec<PatId>),
415 Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, 416 Record { path: Option<Box<Path>>, args: Vec<RecordFieldPat>, ellipsis: bool },
416 Range { start: ExprId, end: ExprId }, 417 Range { start: ExprId, end: ExprId },
417 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, 418 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> },
418 Path(Path), 419 Path(Box<Path>),
419 Lit(ExprId), 420 Lit(ExprId),
420 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, 421 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
421 TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, 422 TupleStruct { path: Option<Box<Path>>, args: Vec<PatId>, ellipsis: Option<usize> },
422 Ref { pat: PatId, mutability: Mutability }, 423 Ref { pat: PatId, mutability: Mutability },
423 Box { inner: PatId }, 424 Box { inner: PatId },
424 ConstBlock(ExprId), 425 ConstBlock(ExprId),
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index be9a5e1a0..abd6c553f 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -56,6 +56,7 @@ use std::{
56 sync::Arc, 56 sync::Arc,
57}; 57};
58 58
59use adt::VariantData;
59use base_db::{impl_intern_key, salsa, CrateId}; 60use base_db::{impl_intern_key, salsa, CrateId};
60use hir_expand::{ 61use hir_expand::{
61 ast_id_map::FileAstId, 62 ast_id_map::FileAstId,
@@ -442,6 +443,18 @@ pub enum VariantId {
442} 443}
443impl_from!(EnumVariantId, StructId, UnionId for VariantId); 444impl_from!(EnumVariantId, StructId, UnionId for VariantId);
444 445
446impl VariantId {
447 pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
448 match self {
449 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
450 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
451 VariantId::EnumVariantId(it) => {
452 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
453 }
454 }
455 }
456}
457
445trait Intern { 458trait Intern {
446 type ID; 459 type ID;
447 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID; 460 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index f9c8328f0..b528ff8ba 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -289,6 +289,12 @@ impl From<Name> for Path {
289 } 289 }
290} 290}
291 291
292impl From<Name> for Box<Path> {
293 fn from(name: Name) -> Box<Path> {
294 Box::new(Path::from(name))
295 }
296}
297
292impl From<Name> for ModPath { 298impl From<Name> for ModPath {
293 fn from(name: Name) -> ModPath { 299 fn from(name: Name) -> ModPath {
294 ModPath::from_segments(PathKind::Plain, iter::once(name)) 300 ModPath::from_segments(PathKind::Plain, iter::once(name))
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 791915fe0..09512d1ce 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -13,7 +13,7 @@ use smallvec::SmallVec;
13use crate::{ 13use crate::{
14 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, 14 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
15 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, 15 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution,
16 TraitRef, Ty, TyDefId, TyKind, TypeWalk, ValueTyDefId, 16 TraitRef, Ty, TyDefId, TyExt, TyKind, TypeWalk, ValueTyDefId,
17}; 17};
18 18
19/// This is a builder for `Ty` or anything that needs a `Substitution`. 19/// This is a builder for `Ty` or anything that needs a `Substitution`.
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 0f4cb43e9..8e8a1aa48 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -1,20 +1,243 @@
1//! Various extensions traits for Chalk types. 1//! Various extensions traits for Chalk types.
2 2
3use hir_def::{AssocContainerId, Lookup, TraitId}; 3use chalk_ir::Mutability;
4use hir_def::{
5 type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId,
6};
4 7
5use crate::{ 8use crate::{
6 db::HirDatabase, from_assoc_type_id, to_chalk_trait_id, Interner, ProjectionTy, TraitRef, Ty, 9 db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
7 TyKind, 10 from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
11 CallableSig, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
12 Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
8}; 13};
9 14
10pub trait TyExt { 15pub trait TyExt {
11 fn is_unit(&self) -> bool; 16 fn is_unit(&self) -> bool;
17 fn is_never(&self) -> bool;
18 fn is_unknown(&self) -> bool;
19
20 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
21 fn as_tuple(&self) -> Option<&Substitution>;
22 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
23 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
24 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>;
25 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>;
26
27 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
28 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
29
30 fn strip_references(&self) -> &Ty;
31
32 /// If this is a `dyn Trait`, returns that trait.
33 fn dyn_trait(&self) -> Option<TraitId>;
34
35 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
36 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
12} 37}
13 38
14impl TyExt for Ty { 39impl TyExt for Ty {
15 fn is_unit(&self) -> bool { 40 fn is_unit(&self) -> bool {
16 matches!(self.kind(&Interner), TyKind::Tuple(0, _)) 41 matches!(self.kind(&Interner), TyKind::Tuple(0, _))
17 } 42 }
43
44 fn is_never(&self) -> bool {
45 matches!(self.kind(&Interner), TyKind::Never)
46 }
47
48 fn is_unknown(&self) -> bool {
49 matches!(self.kind(&Interner), TyKind::Error)
50 }
51
52 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
53 match self.kind(&Interner) {
54 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
55 _ => None,
56 }
57 }
58
59 fn as_tuple(&self) -> Option<&Substitution> {
60 match self.kind(&Interner) {
61 TyKind::Tuple(_, substs) => Some(substs),
62 _ => None,
63 }
64 }
65
66 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
67 if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) {
68 Some(func)
69 } else {
70 None
71 }
72 }
73 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
74 match self.kind(&Interner) {
75 TyKind::Ref(mutability, lifetime, ty) => Some((ty, *lifetime, *mutability)),
76 _ => None,
77 }
78 }
79
80 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
81 match self.kind(&Interner) {
82 TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)),
83 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
84 _ => None,
85 }
86 }
87
88 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
89 match *self.kind(&Interner) {
90 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
91 TyKind::FnDef(callable, ..) => {
92 Some(db.lookup_intern_callable_def(callable.into()).into())
93 }
94 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
95 TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
96 _ => None,
97 }
98 }
99
100 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
101 match self.kind(&Interner) {
102 &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
103 _ => None,
104 }
105 }
106
107 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
108 match self.kind(&Interner) {
109 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
110 TyKind::FnDef(def, parameters) => {
111 let callable_def = db.lookup_intern_callable_def((*def).into());
112 let sig = db.callable_item_signature(callable_def);
113 Some(sig.substitute(&Interner, &parameters))
114 }
115 TyKind::Closure(.., substs) => {
116 let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner);
117 sig_param.callable_sig(db)
118 }
119 _ => None,
120 }
121 }
122
123 fn dyn_trait(&self) -> Option<TraitId> {
124 let trait_ref = match self.kind(&Interner) {
125 TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
126 match b.skip_binders() {
127 WhereClause::Implemented(trait_ref) => Some(trait_ref),
128 _ => None,
129 }
130 }),
131 _ => None,
132 }?;
133 Some(from_chalk_trait_id(trait_ref.trait_id))
134 }
135
136 fn strip_references(&self) -> &Ty {
137 let mut t: &Ty = self;
138 while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(&Interner) {
139 t = ty;
140 }
141 t
142 }
143
144 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
145 match self.kind(&Interner) {
146 TyKind::OpaqueType(opaque_ty_id, ..) => {
147 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
148 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
149 let krate = def.module(db.upcast()).krate();
150 if let Some(future_trait) = db
151 .lang_item(krate, "future_trait".into())
152 .and_then(|item| item.as_trait())
153 {
154 // This is only used by type walking.
155 // Parameters will be walked outside, and projection predicate is not used.
156 // So just provide the Future trait.
157 let impl_bound = Binders::empty(
158 &Interner,
159 WhereClause::Implemented(TraitRef {
160 trait_id: to_chalk_trait_id(future_trait),
161 substitution: Substitution::empty(&Interner),
162 }),
163 );
164 Some(vec![impl_bound])
165 } else {
166 None
167 }
168 }
169 ImplTraitId::ReturnTypeImplTrait(..) => None,
170 }
171 }
172 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
173 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
174 {
175 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
176 db.return_type_impl_traits(func).map(|it| {
177 let data = (*it)
178 .as_ref()
179 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
180 data.substitute(&Interner, &opaque_ty.substitution)
181 })
182 }
183 // It always has an parameter for Future::Output type.
184 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
185 };
186
187 predicates.map(|it| it.into_value_and_skipped_binders().0)
188 }
189 TyKind::Placeholder(idx) => {
190 let id = from_placeholder_idx(db, *idx);
191 let generic_params = db.generic_params(id.parent);
192 let param_data = &generic_params.types[id.local_id];
193 match param_data.provenance {
194 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
195 let substs = TyBuilder::type_params_subst(db, id.parent);
196 let predicates = db
197 .generic_predicates(id.parent)
198 .into_iter()
199 .map(|pred| pred.clone().substitute(&Interner, &substs))
200 .filter(|wc| match &wc.skip_binders() {
201 WhereClause::Implemented(tr) => {
202 tr.self_type_parameter(&Interner) == self
203 }
204 WhereClause::AliasEq(AliasEq {
205 alias: AliasTy::Projection(proj),
206 ty: _,
207 }) => proj.self_type_parameter(&Interner) == self,
208 _ => false,
209 })
210 .collect::<Vec<_>>();
211
212 Some(predicates)
213 }
214 _ => None,
215 }
216 }
217 _ => None,
218 }
219 }
220
221 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
222 match self.kind(&Interner) {
223 TyKind::AssociatedType(id, ..) => {
224 match from_assoc_type_id(*id).lookup(db.upcast()).container {
225 AssocContainerId::TraitId(trait_id) => Some(trait_id),
226 _ => None,
227 }
228 }
229 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
230 match from_assoc_type_id(projection_ty.associated_ty_id)
231 .lookup(db.upcast())
232 .container
233 {
234 AssocContainerId::TraitId(trait_id) => Some(trait_id),
235 _ => None,
236 }
237 }
238 _ => None,
239 }
240 }
18} 241}
19 242
20pub trait ProjectionTyExt { 243pub trait ProjectionTyExt {
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index d7bf9fdf7..79602c3dd 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -14,7 +14,6 @@ use crate::{
14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, 14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
15 MissingPatFields, RemoveThisSemicolon, 15 MissingPatFields, RemoveThisSemicolon,
16 }, 16 },
17 utils::variant_data,
18 AdtId, InferenceResult, Interner, TyExt, TyKind, 17 AdtId, InferenceResult, Interner, TyExt, TyKind,
19}; 18};
20 19
@@ -104,7 +103,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
104 let root = source_ptr.file_syntax(db.upcast()); 103 let root = source_ptr.file_syntax(db.upcast());
105 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { 104 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) {
106 if let Some(_) = record_expr.record_expr_field_list() { 105 if let Some(_) = record_expr.record_expr_field_list() {
107 let variant_data = variant_data(db.upcast(), variant_def); 106 let variant_data = variant_def.variant_data(db.upcast());
108 let missed_fields = missed_fields 107 let missed_fields = missed_fields
109 .into_iter() 108 .into_iter()
110 .map(|idx| variant_data.fields()[idx].name.clone()) 109 .map(|idx| variant_data.fields()[idx].name.clone())
@@ -135,7 +134,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
135 let root = source_ptr.file_syntax(db.upcast()); 134 let root = source_ptr.file_syntax(db.upcast());
136 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { 135 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
137 if let Some(_) = record_pat.record_pat_field_list() { 136 if let Some(_) = record_pat.record_pat_field_list() {
138 let variant_data = variant_data(db.upcast(), variant_def); 137 let variant_data = variant_def.variant_data(db.upcast());
139 let missed_fields = missed_fields 138 let missed_fields = missed_fields
140 .into_iter() 139 .into_iter()
141 .map(|idx| variant_data.fields()[idx].name.clone()) 140 .map(|idx| variant_data.fields()[idx].name.clone())
@@ -453,7 +452,7 @@ pub fn record_literal_missing_fields(
453 return None; 452 return None;
454 } 453 }
455 454
456 let variant_data = variant_data(db.upcast(), variant_def); 455 let variant_data = variant_def.variant_data(db.upcast());
457 456
458 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); 457 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
459 let missed_fields: Vec<LocalFieldId> = variant_data 458 let missed_fields: Vec<LocalFieldId> = variant_data
@@ -483,7 +482,7 @@ pub fn record_pattern_missing_fields(
483 return None; 482 return None;
484 } 483 }
485 484
486 let variant_data = variant_data(db.upcast(), variant_def); 485 let variant_data = variant_def.variant_data(db.upcast());
487 486
488 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); 487 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
489 let missed_fields: Vec<LocalFieldId> = variant_data 488 let missed_fields: Vec<LocalFieldId> = variant_data
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index 34291578a..e9762622f 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -227,7 +227,7 @@ use hir_def::{
227use la_arena::Idx; 227use la_arena::Idx;
228use smallvec::{smallvec, SmallVec}; 228use smallvec::{smallvec, SmallVec};
229 229
230use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyKind}; 230use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyExt, TyKind};
231 231
232#[derive(Debug, Clone, Copy)] 232#[derive(Debug, Clone, Copy)]
233/// Either a pattern from the source code being analyzed, represented as 233/// Either a pattern from the source code being analyzed, represented as
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index b5efe9df5..ed97dc0e3 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -11,7 +11,9 @@ use hir_def::{
11}; 11};
12use hir_expand::diagnostics::DiagnosticSink; 12use hir_expand::diagnostics::DiagnosticSink;
13 13
14use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyKind}; 14use crate::{
15 db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyExt, TyKind,
16};
15 17
16pub(super) struct UnsafeValidator<'a, 'b: 'a> { 18pub(super) struct UnsafeValidator<'a, 'b: 'a> {
17 owner: DefWithBodyId, 19 owner: DefWithBodyId,
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 1c3faf5cb..c63878e7a 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -42,7 +42,7 @@ use super::{
42}; 42};
43use crate::{ 43use crate::{
44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
45 to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyKind, 45 to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyExt, TyKind,
46}; 46};
47 47
48// This lint has a false positive here. See the link below for details. 48// This lint has a false positive here. See the link below for details.
@@ -131,8 +131,6 @@ pub struct InferenceResult {
131 method_resolutions: FxHashMap<ExprId, FunctionId>, 131 method_resolutions: FxHashMap<ExprId, FunctionId>,
132 /// For each field access expr, records the field it resolves to. 132 /// For each field access expr, records the field it resolves to.
133 field_resolutions: FxHashMap<ExprId, FieldId>, 133 field_resolutions: FxHashMap<ExprId, FieldId>,
134 /// For each field in record literal, records the field it resolves to.
135 record_field_resolutions: FxHashMap<ExprId, FieldId>,
136 record_pat_field_resolutions: FxHashMap<PatId, FieldId>, 134 record_pat_field_resolutions: FxHashMap<PatId, FieldId>,
137 /// For each struct literal, records the variant it resolves to. 135 /// For each struct literal, records the variant it resolves to.
138 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, 136 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
@@ -153,9 +151,6 @@ impl InferenceResult {
153 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { 151 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
154 self.field_resolutions.get(&expr).copied() 152 self.field_resolutions.get(&expr).copied()
155 } 153 }
156 pub fn record_field_resolution(&self, expr: ExprId) -> Option<FieldId> {
157 self.record_field_resolutions.get(&expr).copied()
158 }
159 pub fn record_pat_field_resolution(&self, pat: PatId) -> Option<FieldId> { 154 pub fn record_pat_field_resolution(&self, pat: PatId) -> Option<FieldId> {
160 self.record_pat_field_resolutions.get(&pat).copied() 155 self.record_pat_field_resolutions.get(&pat).copied()
161 } 156 }
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index d6c48870a..159a53a63 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -7,7 +7,7 @@
7use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 7use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9 9
10use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyKind}; 10use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyExt, TyKind};
11 11
12use super::{InEnvironment, InferenceContext}; 12use super::{InEnvironment, InferenceContext};
13 13
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 53d94fd0d..9ab0fa212 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -21,9 +21,10 @@ use crate::{
21 primitive::{self, UintTy}, 21 primitive::{self, UintTy},
22 static_lifetime, 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, Generics},
25 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner, 25 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
26 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeWalk, 26 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
27 TypeWalk,
27}; 28};
28 29
29use super::{ 30use super::{
@@ -317,7 +318,13 @@ impl<'a> InferenceContext<'a> {
317 self.normalize_associated_types_in(ret_ty) 318 self.normalize_associated_types_in(ret_ty)
318 } 319 }
319 Expr::MethodCall { receiver, args, method_name, generic_args } => self 320 Expr::MethodCall { receiver, args, method_name, generic_args } => self
320 .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), 321 .infer_method_call(
322 tgt_expr,
323 *receiver,
324 &args,
325 &method_name,
326 generic_args.as_deref(),
327 ),
321 Expr::Match { expr, arms } => { 328 Expr::Match { expr, arms } => {
322 let input_ty = self.infer_expr(*expr, &Expectation::none()); 329 let input_ty = self.infer_expr(*expr, &Expectation::none());
323 330
@@ -398,7 +405,7 @@ impl<'a> InferenceContext<'a> {
398 TyKind::Never.intern(&Interner) 405 TyKind::Never.intern(&Interner)
399 } 406 }
400 Expr::RecordLit { path, fields, spread } => { 407 Expr::RecordLit { path, fields, spread } => {
401 let (ty, def_id) = self.resolve_variant(path.as_ref()); 408 let (ty, def_id) = self.resolve_variant(path.as_deref());
402 if let Some(variant) = def_id { 409 if let Some(variant) = def_id {
403 self.write_variant_resolution(tgt_expr.into(), variant); 410 self.write_variant_resolution(tgt_expr.into(), variant);
404 } 411 }
@@ -407,7 +414,7 @@ impl<'a> InferenceContext<'a> {
407 414
408 let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner)); 415 let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner));
409 let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); 416 let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
410 let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it)); 417 let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
411 for field in fields.iter() { 418 for field in fields.iter() {
412 let field_def = 419 let field_def =
413 variant_data.as_ref().and_then(|it| match it.field(&field.name) { 420 variant_data.as_ref().and_then(|it| match it.field(&field.name) {
@@ -419,9 +426,6 @@ impl<'a> InferenceContext<'a> {
419 None 426 None
420 } 427 }
421 }); 428 });
422 if let Some(field_def) = field_def {
423 self.result.record_field_resolutions.insert(field.expr, field_def);
424 }
425 let field_ty = field_def.map_or(self.err_ty(), |it| { 429 let field_ty = field_def.map_or(self.err_ty(), |it| {
426 field_types[it.local_id].clone().substitute(&Interner, &substs) 430 field_types[it.local_id].clone().substitute(&Interner, &substs)
427 }); 431 });
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index c1d7a6b76..942f70edf 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -13,8 +13,8 @@ use hir_expand::name::Name;
13 13
14use super::{BindingMode, Expectation, InferenceContext}; 14use super::{BindingMode, Expectation, InferenceContext};
15use crate::{ 15use crate::{
16 lower::lower_to_chalk_mutability, static_lifetime, utils::variant_data, Interner, Substitution, 16 lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder,
17 Ty, TyBuilder, TyKind, 17 TyExt, TyKind,
18}; 18};
19 19
20impl<'a> InferenceContext<'a> { 20impl<'a> InferenceContext<'a> {
@@ -28,7 +28,7 @@ impl<'a> InferenceContext<'a> {
28 ellipsis: Option<usize>, 28 ellipsis: Option<usize>,
29 ) -> Ty { 29 ) -> Ty {
30 let (ty, def) = self.resolve_variant(path); 30 let (ty, def) = self.resolve_variant(path);
31 let var_data = def.map(|it| variant_data(self.db.upcast(), it)); 31 let var_data = def.map(|it| it.variant_data(self.db.upcast()));
32 if let Some(variant) = def { 32 if let Some(variant) = def {
33 self.write_variant_resolution(id.into(), variant); 33 self.write_variant_resolution(id.into(), variant);
34 } 34 }
@@ -68,7 +68,7 @@ impl<'a> InferenceContext<'a> {
68 id: PatId, 68 id: PatId,
69 ) -> Ty { 69 ) -> Ty {
70 let (ty, def) = self.resolve_variant(path); 70 let (ty, def) = self.resolve_variant(path);
71 let var_data = def.map(|it| variant_data(self.db.upcast(), it)); 71 let var_data = def.map(|it| it.variant_data(self.db.upcast()));
72 if let Some(variant) = def { 72 if let Some(variant) = def {
73 self.write_variant_resolution(id.into(), variant); 73 self.write_variant_resolution(id.into(), variant);
74 } 74 }
@@ -174,7 +174,7 @@ impl<'a> InferenceContext<'a> {
174 TyKind::Ref(mutability, static_lifetime(), 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_ref(), 177 p.as_deref(),
178 subpats, 178 subpats,
179 expected, 179 expected,
180 default_bm, 180 default_bm,
@@ -182,7 +182,7 @@ impl<'a> InferenceContext<'a> {
182 *ellipsis, 182 *ellipsis,
183 ), 183 ),
184 Pat::Record { path: p, args: fields, ellipsis: _ } => { 184 Pat::Record { path: p, args: fields, ellipsis: _ } => {
185 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) 185 self.infer_record_pat(p.as_deref(), fields, expected, default_bm, pat)
186 } 186 }
187 Pat::Path(path) => { 187 Pat::Path(path) => {
188 // FIXME use correct resolver for the surrounding expression 188 // FIXME use correct resolver for the surrounding expression
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 14f705173..b19d67bb1 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -10,7 +10,9 @@ use hir_def::{
10}; 10};
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use crate::{method_resolution, Interner, Substitution, Ty, TyBuilder, TyKind, ValueTyDefId}; 13use crate::{
14 method_resolution, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
15};
14 16
15use super::{ExprOrPatId, InferenceContext, TraitRef}; 17use super::{ExprOrPatId, InferenceContext, TraitRef};
16 18
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index a2a5bcc07..f5b658cba 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -30,13 +30,11 @@ mod test_db;
30 30
31use std::sync::Arc; 31use std::sync::Arc;
32 32
33use chalk_ir::UintTy;
34use itertools::Itertools;
35
36use base_db::salsa; 33use base_db::salsa;
34use chalk_ir::UintTy;
37use hir_def::{ 35use hir_def::{
38 expr::ExprId, type_ref::Rawness, AssocContainerId, ConstParamId, FunctionId, GenericDefId, 36 expr::ExprId, type_ref::Rawness, ConstParamId, LifetimeParamId, TraitId, TypeAliasId,
39 HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, 37 TypeParamId,
40}; 38};
41 39
42use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; 40use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
@@ -171,65 +169,6 @@ impl CallableSig {
171} 169}
172 170
173impl Ty { 171impl Ty {
174 pub fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
175 match self.kind(&Interner) {
176 TyKind::Ref(mutability, lifetime, ty) => Some((ty, *lifetime, *mutability)),
177 _ => None,
178 }
179 }
180
181 pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
182 match self.kind(&Interner) {
183 TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)),
184 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
185 _ => None,
186 }
187 }
188
189 pub fn strip_references(&self) -> &Ty {
190 let mut t: &Ty = self;
191
192 while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(&Interner) {
193 t = ty;
194 }
195
196 t
197 }
198
199 pub fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
200 match self.kind(&Interner) {
201 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
202 _ => None,
203 }
204 }
205
206 pub fn as_tuple(&self) -> Option<&Substitution> {
207 match self.kind(&Interner) {
208 TyKind::Tuple(_, substs) => Some(substs),
209 _ => None,
210 }
211 }
212
213 pub fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
214 match *self.kind(&Interner) {
215 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
216 TyKind::FnDef(callable, ..) => {
217 Some(db.lookup_intern_callable_def(callable.into()).into())
218 }
219 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
220 TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
221 _ => None,
222 }
223 }
224
225 pub fn is_never(&self) -> bool {
226 matches!(self.kind(&Interner), TyKind::Never)
227 }
228
229 pub fn is_unknown(&self) -> bool {
230 matches!(self.kind(&Interner), TyKind::Error)
231 }
232
233 pub fn equals_ctor(&self, other: &Ty) -> bool { 172 pub fn equals_ctor(&self, other: &Ty) -> bool {
234 match (self.kind(&Interner), other.kind(&Interner)) { 173 match (self.kind(&Interner), other.kind(&Interner)) {
235 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2, 174 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
@@ -260,24 +199,6 @@ impl Ty {
260 } 199 }
261 } 200 }
262 201
263 /// If this is a `dyn Trait` type, this returns the `Trait` part.
264 fn dyn_trait_ref(&self) -> Option<&TraitRef> {
265 match self.kind(&Interner) {
266 TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
267 match b.skip_binders() {
268 WhereClause::Implemented(trait_ref) => Some(trait_ref),
269 _ => None,
270 }
271 }),
272 _ => None,
273 }
274 }
275
276 /// If this is a `dyn Trait`, returns that trait.
277 pub fn dyn_trait(&self) -> Option<TraitId> {
278 self.dyn_trait_ref().map(|it| it.trait_id).map(from_chalk_trait_id)
279 }
280
281 fn builtin_deref(&self) -> Option<Ty> { 202 fn builtin_deref(&self) -> Option<Ty> {
282 match self.kind(&Interner) { 203 match self.kind(&Interner) {
283 TyKind::Ref(.., ty) => Some(ty.clone()), 204 TyKind::Ref(.., ty) => Some(ty.clone()),
@@ -286,37 +207,6 @@ impl Ty {
286 } 207 }
287 } 208 }
288 209
289 pub fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
290 match self.kind(&Interner) {
291 &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
292 _ => None,
293 }
294 }
295
296 pub fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
297 if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) {
298 Some(func)
299 } else {
300 None
301 }
302 }
303
304 pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
305 match self.kind(&Interner) {
306 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
307 TyKind::FnDef(def, parameters) => {
308 let callable_def = db.lookup_intern_callable_def((*def).into());
309 let sig = db.callable_item_signature(callable_def);
310 Some(sig.substitute(&Interner, &parameters))
311 }
312 TyKind::Closure(.., substs) => {
313 let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner);
314 sig_param.callable_sig(db)
315 }
316 _ => None,
317 }
318 }
319
320 /// 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
321 /// 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`.
322 pub fn substs(&self) -> Option<&Substitution> { 212 pub fn substs(&self) -> Option<&Substitution> {
@@ -344,104 +234,6 @@ impl Ty {
344 _ => None, 234 _ => None,
345 } 235 }
346 } 236 }
347
348 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
349 match self.kind(&Interner) {
350 TyKind::OpaqueType(opaque_ty_id, ..) => {
351 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
352 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
353 let krate = def.module(db.upcast()).krate();
354 if let Some(future_trait) = db
355 .lang_item(krate, "future_trait".into())
356 .and_then(|item| item.as_trait())
357 {
358 // This is only used by type walking.
359 // Parameters will be walked outside, and projection predicate is not used.
360 // So just provide the Future trait.
361 let impl_bound = Binders::empty(
362 &Interner,
363 WhereClause::Implemented(TraitRef {
364 trait_id: to_chalk_trait_id(future_trait),
365 substitution: Substitution::empty(&Interner),
366 }),
367 );
368 Some(vec![impl_bound])
369 } else {
370 None
371 }
372 }
373 ImplTraitId::ReturnTypeImplTrait(..) => None,
374 }
375 }
376 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
377 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
378 {
379 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
380 db.return_type_impl_traits(func).map(|it| {
381 let data = (*it)
382 .as_ref()
383 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
384 data.substitute(&Interner, &opaque_ty.substitution)
385 })
386 }
387 // It always has an parameter for Future::Output type.
388 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
389 };
390
391 predicates.map(|it| it.into_value_and_skipped_binders().0)
392 }
393 TyKind::Placeholder(idx) => {
394 let id = from_placeholder_idx(db, *idx);
395 let generic_params = db.generic_params(id.parent);
396 let param_data = &generic_params.types[id.local_id];
397 match param_data.provenance {
398 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
399 let substs = TyBuilder::type_params_subst(db, id.parent);
400 let predicates = db
401 .generic_predicates(id.parent)
402 .into_iter()
403 .map(|pred| pred.clone().substitute(&Interner, &substs))
404 .filter(|wc| match &wc.skip_binders() {
405 WhereClause::Implemented(tr) => {
406 tr.self_type_parameter(&Interner) == self
407 }
408 WhereClause::AliasEq(AliasEq {
409 alias: AliasTy::Projection(proj),
410 ty: _,
411 }) => proj.self_type_parameter(&Interner) == self,
412 _ => false,
413 })
414 .collect_vec();
415
416 Some(predicates)
417 }
418 _ => None,
419 }
420 }
421 _ => None,
422 }
423 }
424
425 pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
426 match self.kind(&Interner) {
427 TyKind::AssociatedType(id, ..) => {
428 match from_assoc_type_id(*id).lookup(db.upcast()).container {
429 AssocContainerId::TraitId(trait_id) => Some(trait_id),
430 _ => None,
431 }
432 }
433 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
434 match from_assoc_type_id(projection_ty.associated_ty_id)
435 .lookup(db.upcast())
436 .container
437 {
438 AssocContainerId::TraitId(trait_id) => Some(trait_id),
439 _ => None,
440 }
441 }
442 _ => None,
443 }
444 }
445} 237}
446 238
447#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 239#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 8be1bcddb..4ca6aa538 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -30,8 +30,7 @@ use crate::{
30 dummy_usize_const, static_lifetime, 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, Generics,
34 variant_data, Generics,
35 }, 34 },
36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, 35 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
37 FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, 36 FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
@@ -879,7 +878,7 @@ pub(crate) fn field_types_query(
879 db: &dyn HirDatabase, 878 db: &dyn HirDatabase,
880 variant_id: VariantId, 879 variant_id: VariantId,
881) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> { 880) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
882 let var_data = variant_data(db.upcast(), variant_id); 881 let var_data = variant_id.variant_data(db.upcast());
883 let (resolver, def): (_, GenericDefId) = match variant_id { 882 let (resolver, def): (_, GenericDefId) = match variant_id {
884 VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), 883 VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
885 VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()), 884 VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()),
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 5042bfbca..ee725fd46 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -22,7 +22,7 @@ use crate::{
22 static_lifetime, 22 static_lifetime,
23 utils::all_super_traits, 23 utils::all_super_traits,
24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, 24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyKind, 25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
26 TypeWalk, 26 TypeWalk,
27}; 27};
28 28
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 5a8b5cd86..f03b92422 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -22,7 +22,7 @@ use crate::{
22 to_assoc_type_id, to_chalk_trait_id, 22 to_assoc_type_id, to_chalk_trait_id,
23 utils::generics, 23 utils::generics,
24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, 24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution,
25 TraitRef, Ty, TyBuilder, TyKind, WhereClause, 25 TraitRef, Ty, TyBuilder, TyExt, TyKind, WhereClause,
26}; 26};
27use mapping::{ 27use mapping::{
28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, 28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index d11708299..0a424f607 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -4,7 +4,6 @@ use std::sync::Arc;
4 4
5use chalk_ir::{BoundVar, DebruijnIndex}; 5use chalk_ir::{BoundVar, DebruijnIndex};
6use hir_def::{ 6use hir_def::{
7 adt::VariantData,
8 db::DefDatabase, 7 db::DefDatabase,
9 generics::{ 8 generics::{
10 GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, 9 GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
@@ -13,7 +12,7 @@ use hir_def::{
13 path::Path, 12 path::Path,
14 resolver::{HasResolver, TypeNs}, 13 resolver::{HasResolver, TypeNs},
15 type_ref::TypeRef, 14 type_ref::TypeRef,
16 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, 15 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
17}; 16};
18use hir_expand::name::{name, Name}; 17use hir_expand::name::{name, Name};
19 18
@@ -136,16 +135,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
136 }) 135 })
137} 136}
138 137
139pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> {
140 match var {
141 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
142 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
143 VariantId::EnumVariantId(it) => {
144 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
145 }
146 }
147}
148
149/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices). 138/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
150/// The underlying values are cloned if there are other strong references. 139/// The underlying values are cloned if there are other strong references.
151pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] { 140pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index 22011cb33..f09ad37e3 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -1,6 +1,7 @@
1//! Thin wrappers around `std::path`, distinguishing between absolute and 1//! Thin wrappers around `std::path`, distinguishing between absolute and
2//! relative paths. 2//! relative paths.
3use std::{ 3use std::{
4 borrow::Borrow,
4 convert::{TryFrom, TryInto}, 5 convert::{TryFrom, TryInto},
5 ops, 6 ops,
6 path::{Component, Path, PathBuf}, 7 path::{Component, Path, PathBuf},
@@ -35,6 +36,12 @@ impl AsRef<AbsPath> for AbsPathBuf {
35 } 36 }
36} 37}
37 38
39impl Borrow<AbsPath> for AbsPathBuf {
40 fn borrow(&self) -> &AbsPath {
41 self.as_path()
42 }
43}
44
38impl TryFrom<PathBuf> for AbsPathBuf { 45impl TryFrom<PathBuf> for AbsPathBuf {
39 type Error = PathBuf; 46 type Error = PathBuf;
40 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { 47 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
index f7050be4e..0d4d39fef 100644
--- a/crates/project_model/src/build_data.rs
+++ b/crates/project_model/src/build_data.rs
@@ -13,12 +13,12 @@ use cargo_metadata::{BuildScript, Message};
13use itertools::Itertools; 13use itertools::Itertools;
14use paths::{AbsPath, AbsPathBuf}; 14use paths::{AbsPath, AbsPathBuf};
15use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
16use stdx::JodChild; 16use stdx::{format_to, JodChild};
17 17
18use crate::{cfg_flag::CfgFlag, CargoConfig}; 18use crate::{cfg_flag::CfgFlag, CargoConfig};
19 19
20#[derive(Debug, Clone, Default, PartialEq, Eq)] 20#[derive(Debug, Clone, Default, PartialEq, Eq)]
21pub(crate) struct BuildData { 21pub(crate) struct PackageBuildData {
22 /// List of config flags defined by this package's build script 22 /// List of config flags defined by this package's build script
23 pub(crate) cfgs: Vec<CfgFlag>, 23 pub(crate) cfgs: Vec<CfgFlag>,
24 /// List of cargo-related environment variables with their value 24 /// List of cargo-related environment variables with their value
@@ -32,6 +32,17 @@ pub(crate) struct BuildData {
32 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>, 32 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
33} 33}
34 34
35#[derive(Debug, Default, PartialEq, Eq, Clone)]
36pub(crate) struct WorkspaceBuildData {
37 per_package: FxHashMap<String, PackageBuildData>,
38 error: Option<String>,
39}
40
41#[derive(Debug, Default, PartialEq, Eq, Clone)]
42pub struct BuildDataResult {
43 per_workspace: FxHashMap<AbsPathBuf, WorkspaceBuildData>,
44}
45
35#[derive(Clone, Debug)] 46#[derive(Clone, Debug)]
36pub(crate) struct BuildDataConfig { 47pub(crate) struct BuildDataConfig {
37 cargo_toml: AbsPathBuf, 48 cargo_toml: AbsPathBuf,
@@ -52,13 +63,6 @@ pub struct BuildDataCollector {
52 configs: FxHashMap<AbsPathBuf, BuildDataConfig>, 63 configs: FxHashMap<AbsPathBuf, BuildDataConfig>,
53} 64}
54 65
55#[derive(Debug, Default, PartialEq, Eq)]
56pub struct BuildDataResult {
57 data: FxHashMap<AbsPathBuf, BuildDataMap>,
58}
59
60pub(crate) type BuildDataMap = FxHashMap<String, BuildData>;
61
62impl BuildDataCollector { 66impl BuildDataCollector {
63 pub(crate) fn add_config(&mut self, workspace_root: &AbsPath, config: BuildDataConfig) { 67 pub(crate) fn add_config(&mut self, workspace_root: &AbsPath, config: BuildDataConfig) {
64 self.configs.insert(workspace_root.to_path_buf(), config); 68 self.configs.insert(workspace_root.to_path_buf(), config);
@@ -67,7 +71,7 @@ impl BuildDataCollector {
67 pub fn collect(&mut self, progress: &dyn Fn(String)) -> Result<BuildDataResult> { 71 pub fn collect(&mut self, progress: &dyn Fn(String)) -> Result<BuildDataResult> {
68 let mut res = BuildDataResult::default(); 72 let mut res = BuildDataResult::default();
69 for (path, config) in self.configs.iter() { 73 for (path, config) in self.configs.iter() {
70 res.data.insert( 74 res.per_workspace.insert(
71 path.clone(), 75 path.clone(),
72 collect_from_workspace( 76 collect_from_workspace(
73 &config.cargo_toml, 77 &config.cargo_toml,
@@ -81,9 +85,28 @@ impl BuildDataCollector {
81 } 85 }
82} 86}
83 87
88impl WorkspaceBuildData {
89 pub(crate) fn get(&self, package_id: &str) -> Option<&PackageBuildData> {
90 self.per_package.get(package_id)
91 }
92}
93
84impl BuildDataResult { 94impl BuildDataResult {
85 pub(crate) fn get(&self, root: &AbsPath) -> Option<&BuildDataMap> { 95 pub(crate) fn get(&self, workspace_root: &AbsPath) -> Option<&WorkspaceBuildData> {
86 self.data.get(&root.to_path_buf()) 96 self.per_workspace.get(workspace_root)
97 }
98 pub fn error(&self) -> Option<String> {
99 let mut buf = String::new();
100 for (_workspace_root, build_data) in &self.per_workspace {
101 if let Some(err) = &build_data.error {
102 format_to!(buf, "cargo check failed:\n{}", err);
103 }
104 }
105 if buf.is_empty() {
106 return None;
107 }
108
109 Some(buf)
87 } 110 }
88} 111}
89 112
@@ -102,7 +125,7 @@ fn collect_from_workspace(
102 cargo_features: &CargoConfig, 125 cargo_features: &CargoConfig,
103 packages: &Vec<cargo_metadata::Package>, 126 packages: &Vec<cargo_metadata::Package>,
104 progress: &dyn Fn(String), 127 progress: &dyn Fn(String),
105) -> Result<BuildDataMap> { 128) -> Result<WorkspaceBuildData> {
106 let mut cmd = Command::new(toolchain::cargo()); 129 let mut cmd = Command::new(toolchain::cargo());
107 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) 130 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"])
108 .arg(cargo_toml.as_ref()); 131 .arg(cargo_toml.as_ref());
@@ -130,13 +153,13 @@ fn collect_from_workspace(
130 } 153 }
131 } 154 }
132 155
133 cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); 156 cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
134 157
135 let mut child = cmd.spawn().map(JodChild)?; 158 let mut child = cmd.spawn().map(JodChild)?;
136 let child_stdout = child.stdout.take().unwrap(); 159 let child_stdout = child.stdout.take().unwrap();
137 let stdout = BufReader::new(child_stdout); 160 let stdout = BufReader::new(child_stdout);
138 161
139 let mut res = BuildDataMap::default(); 162 let mut res = WorkspaceBuildData::default();
140 for message in cargo_metadata::Message::parse_stream(stdout).flatten() { 163 for message in cargo_metadata::Message::parse_stream(stdout).flatten() {
141 match message { 164 match message {
142 Message::BuildScriptExecuted(BuildScript { 165 Message::BuildScriptExecuted(BuildScript {
@@ -154,16 +177,17 @@ fn collect_from_workspace(
154 } 177 }
155 acc 178 acc
156 }; 179 };
157 let res = res.entry(package_id.repr.clone()).or_default(); 180 let package_build_data =
181 res.per_package.entry(package_id.repr.clone()).or_default();
158 // cargo_metadata crate returns default (empty) path for 182 // cargo_metadata crate returns default (empty) path for
159 // older cargos, which is not absolute, so work around that. 183 // older cargos, which is not absolute, so work around that.
160 if !out_dir.as_str().is_empty() { 184 if !out_dir.as_str().is_empty() {
161 let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); 185 let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string()));
162 res.out_dir = Some(out_dir); 186 package_build_data.out_dir = Some(out_dir);
163 res.cfgs = cfgs; 187 package_build_data.cfgs = cfgs;
164 } 188 }
165 189
166 res.envs = env; 190 package_build_data.envs = env;
167 } 191 }
168 Message::CompilerArtifact(message) => { 192 Message::CompilerArtifact(message) => {
169 progress(format!("metadata {}", message.target.name)); 193 progress(format!("metadata {}", message.target.name));
@@ -173,8 +197,9 @@ fn collect_from_workspace(
173 // Skip rmeta file 197 // Skip rmeta file
174 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) { 198 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) {
175 let filename = AbsPathBuf::assert(PathBuf::from(&filename)); 199 let filename = AbsPathBuf::assert(PathBuf::from(&filename));
176 let res = res.entry(package_id.repr.clone()).or_default(); 200 let package_build_data =
177 res.proc_macro_dylib_path = Some(filename); 201 res.per_package.entry(package_id.repr.clone()).or_default();
202 package_build_data.proc_macro_dylib_path = Some(filename);
178 } 203 }
179 } 204 }
180 } 205 }
@@ -188,16 +213,25 @@ fn collect_from_workspace(
188 } 213 }
189 214
190 for package in packages { 215 for package in packages {
191 let build_data = res.entry(package.id.repr.clone()).or_default(); 216 let package_build_data = res.per_package.entry(package.id.repr.clone()).or_default();
192 inject_cargo_env(package, build_data); 217 inject_cargo_env(package, package_build_data);
193 if let Some(out_dir) = &build_data.out_dir { 218 if let Some(out_dir) = &package_build_data.out_dir {
194 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() 219 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
195 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { 220 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
196 build_data.envs.push(("OUT_DIR".to_string(), out_dir)); 221 package_build_data.envs.push(("OUT_DIR".to_string(), out_dir));
197 } 222 }
198 } 223 }
199 } 224 }
200 225
226 let output = child.into_inner().wait_with_output()?;
227 if !output.status.success() {
228 let mut stderr = String::from_utf8(output.stderr).unwrap_or_default();
229 if stderr.is_empty() {
230 stderr = "cargo check failed".to_string();
231 }
232 res.error = Some(stderr)
233 }
234
201 Ok(res) 235 Ok(res)
202} 236}
203 237
@@ -212,7 +246,7 @@ fn is_dylib(path: &Utf8Path) -> bool {
212/// Recreates the compile-time environment variables that Cargo sets. 246/// Recreates the compile-time environment variables that Cargo sets.
213/// 247///
214/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> 248/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
215fn inject_cargo_env(package: &cargo_metadata::Package, build_data: &mut BuildData) { 249fn inject_cargo_env(package: &cargo_metadata::Package, build_data: &mut PackageBuildData) {
216 let env = &mut build_data.envs; 250 let env = &mut build_data.envs;
217 251
218 // FIXME: Missing variables: 252 // FIXME: Missing variables:
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 1b53fcc30..2fcd0f8fa 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -12,7 +12,7 @@ use proc_macro_api::ProcMacroClient;
12use rustc_hash::{FxHashMap, FxHashSet}; 12use rustc_hash::{FxHashMap, FxHashSet};
13 13
14use crate::{ 14use crate::{
15 build_data::{BuildData, BuildDataMap, BuildDataResult}, 15 build_data::{BuildDataResult, PackageBuildData, WorkspaceBuildData},
16 cargo_workspace, 16 cargo_workspace,
17 cfg_flag::CfgFlag, 17 cfg_flag::CfgFlag,
18 rustc_cfg, 18 rustc_cfg,
@@ -354,10 +354,10 @@ fn cargo_to_crate_graph(
354 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 354 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
355 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 355 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
356 cargo: &CargoWorkspace, 356 cargo: &CargoWorkspace,
357 build_data_map: Option<&BuildDataMap>, 357 build_data_map: Option<&WorkspaceBuildData>,
358 sysroot: &Sysroot, 358 sysroot: &Sysroot,
359 rustc: &Option<CargoWorkspace>, 359 rustc: &Option<CargoWorkspace>,
360 rustc_build_data_map: Option<&BuildDataMap>, 360 rustc_build_data_map: Option<&WorkspaceBuildData>,
361) -> CrateGraph { 361) -> CrateGraph {
362 let _p = profile::span("cargo_to_crate_graph"); 362 let _p = profile::span("cargo_to_crate_graph");
363 let mut crate_graph = CrateGraph::default(); 363 let mut crate_graph = CrateGraph::default();
@@ -464,7 +464,7 @@ fn handle_rustc_crates(
464 rustc_workspace: &CargoWorkspace, 464 rustc_workspace: &CargoWorkspace,
465 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 465 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
466 crate_graph: &mut CrateGraph, 466 crate_graph: &mut CrateGraph,
467 rustc_build_data_map: Option<&FxHashMap<String, BuildData>>, 467 rustc_build_data_map: Option<&WorkspaceBuildData>,
468 cfg_options: &CfgOptions, 468 cfg_options: &CfgOptions,
469 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 469 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
470 pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>, 470 pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
@@ -555,7 +555,7 @@ fn handle_rustc_crates(
555fn add_target_crate_root( 555fn add_target_crate_root(
556 crate_graph: &mut CrateGraph, 556 crate_graph: &mut CrateGraph,
557 pkg: &cargo_workspace::PackageData, 557 pkg: &cargo_workspace::PackageData,
558 build_data: Option<&BuildData>, 558 build_data: Option<&PackageBuildData>,
559 cfg_options: &CfgOptions, 559 cfg_options: &CfgOptions,
560 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 560 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
561 file_id: FileId, 561 file_id: FileId,
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 18fd7ea74..fe9f273b0 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -12,7 +12,7 @@ use hir::{
12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef, 12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
13}; 13};
14use hir_def::FunctionId; 14use hir_def::FunctionId;
15use hir_ty::TypeWalk; 15use hir_ty::{TyExt, TypeWalk};
16use ide::{AnalysisHost, RootDatabase}; 16use ide::{AnalysisHost, RootDatabase};
17use ide_db::base_db::{ 17use ide_db::base_db::{
18 salsa::{self, ParallelDatabase}, 18 salsa::{self, ParallelDatabase},
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index cda272fd4..e012b4452 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -445,8 +445,8 @@ impl Config {
445 pub fn hover_actions(&self) -> bool { 445 pub fn hover_actions(&self) -> bool {
446 self.experimental("hoverActions") 446 self.experimental("hoverActions")
447 } 447 }
448 pub fn status_notification(&self) -> bool { 448 pub fn server_status_notification(&self) -> bool {
449 self.experimental("statusNotification") 449 self.experimental("serverStatusNotification")
450 } 450 }
451 451
452 pub fn publish_diagnostics(&self) -> bool { 452 pub fn publish_diagnostics(&self) -> bool {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 8679c8599..adeb7a97e 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -23,6 +23,7 @@ use crate::{
23 document::DocumentData, 23 document::DocumentData,
24 from_proto, 24 from_proto,
25 line_index::{LineEndings, LineIndex}, 25 line_index::{LineEndings, LineIndex},
26 lsp_ext,
26 main_loop::Task, 27 main_loop::Task,
27 op_queue::OpQueue, 28 op_queue::OpQueue,
28 reload::SourceRootConfig, 29 reload::SourceRootConfig,
@@ -32,20 +33,6 @@ use crate::{
32 Result, 33 Result,
33}; 34};
34 35
35#[derive(Eq, PartialEq, Copy, Clone)]
36pub(crate) enum Status {
37 Loading,
38 Ready { partial: bool },
39 Invalid,
40 NeedsReload,
41}
42
43impl Default for Status {
44 fn default() -> Self {
45 Status::Loading
46 }
47}
48
49// Enforces drop order 36// Enforces drop order
50pub(crate) struct Handle<H, C> { 37pub(crate) struct Handle<H, C> {
51 pub(crate) handle: H, 38 pub(crate) handle: H,
@@ -67,26 +54,36 @@ pub(crate) struct GlobalState {
67 req_queue: ReqQueue, 54 req_queue: ReqQueue,
68 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, 55 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
69 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>, 56 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
70 pub(crate) vfs_config_version: u32,
71 pub(crate) flycheck: Vec<FlycheckHandle>,
72 pub(crate) flycheck_sender: Sender<flycheck::Message>,
73 pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
74 pub(crate) config: Arc<Config>, 57 pub(crate) config: Arc<Config>,
75 pub(crate) analysis_host: AnalysisHost, 58 pub(crate) analysis_host: AnalysisHost,
76 pub(crate) diagnostics: DiagnosticCollection, 59 pub(crate) diagnostics: DiagnosticCollection,
77 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, 60 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
78 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, 61 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
79 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
80 pub(crate) shutdown_requested: bool, 62 pub(crate) shutdown_requested: bool,
81 pub(crate) status: Status, 63 pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
82 pub(crate) source_root_config: SourceRootConfig, 64 pub(crate) source_root_config: SourceRootConfig,
83 pub(crate) proc_macro_client: Option<ProcMacroClient>, 65 pub(crate) proc_macro_client: Option<ProcMacroClient>,
84 66
85 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, 67 pub(crate) flycheck: Vec<FlycheckHandle>,
86 pub(crate) fetch_workspaces_queue: OpQueue<(), ()>, 68 pub(crate) flycheck_sender: Sender<flycheck::Message>,
69 pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
87 70
71 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
72 pub(crate) vfs_config_version: u32,
73 pub(crate) vfs_progress_config_version: u32,
74 pub(crate) vfs_progress_n_total: usize,
75 pub(crate) vfs_progress_n_done: usize,
76
77 /// For both `workspaces` and `workspace_build_data`, the field stores the
78 /// data we actually use, while the `OpQueue` stores the result of the last
79 /// fetch.
80 ///
81 /// If the fetch (partially) fails, we do not update the values.
82 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
83 pub(crate) fetch_workspaces_queue: OpQueue<(), Vec<anyhow::Result<ProjectWorkspace>>>,
88 pub(crate) workspace_build_data: Option<BuildDataResult>, 84 pub(crate) workspace_build_data: Option<BuildDataResult>,
89 pub(crate) fetch_build_data_queue: OpQueue<BuildDataCollector, ()>, 85 pub(crate) fetch_build_data_queue:
86 OpQueue<BuildDataCollector, Option<anyhow::Result<BuildDataResult>>>,
90 87
91 latest_requests: Arc<RwLock<LatestRequests>>, 88 latest_requests: Arc<RwLock<LatestRequests>>,
92} 89}
@@ -124,25 +121,32 @@ impl GlobalState {
124 GlobalState { 121 GlobalState {
125 sender, 122 sender,
126 req_queue: ReqQueue::default(), 123 req_queue: ReqQueue::default(),
127 vfs_config_version: 0,
128 task_pool, 124 task_pool,
129 loader, 125 loader,
130 flycheck: Vec::new(),
131 flycheck_sender,
132 flycheck_receiver,
133 config: Arc::new(config), 126 config: Arc::new(config),
134 analysis_host, 127 analysis_host,
135 diagnostics: Default::default(), 128 diagnostics: Default::default(),
136 mem_docs: FxHashMap::default(), 129 mem_docs: FxHashMap::default(),
137 semantic_tokens_cache: Arc::new(Default::default()), 130 semantic_tokens_cache: Arc::new(Default::default()),
138 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
139 shutdown_requested: false, 131 shutdown_requested: false,
140 status: Status::default(), 132 last_reported_status: None,
141 source_root_config: SourceRootConfig::default(), 133 source_root_config: SourceRootConfig::default(),
142 proc_macro_client: None, 134 proc_macro_client: None,
135
136 flycheck: Vec::new(),
137 flycheck_sender,
138 flycheck_receiver,
139
140 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
141 vfs_config_version: 0,
142 vfs_progress_config_version: 0,
143 vfs_progress_n_total: 0,
144 vfs_progress_n_done: 0,
145
143 workspaces: Arc::new(Vec::new()), 146 workspaces: Arc::new(Vec::new()),
144 fetch_workspaces_queue: OpQueue::default(), 147 fetch_workspaces_queue: OpQueue::default(),
145 workspace_build_data: None, 148 workspace_build_data: None,
149
146 fetch_build_data_queue: OpQueue::default(), 150 fetch_build_data_queue: OpQueue::default(),
147 latest_requests: Default::default(), 151 latest_requests: Default::default(),
148 } 152 }
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 0e1fec209..81a6f22f1 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -241,26 +241,26 @@ pub struct SsrParams {
241 pub selections: Vec<lsp_types::Range>, 241 pub selections: Vec<lsp_types::Range>,
242} 242}
243 243
244pub enum StatusNotification {} 244pub enum ServerStatusNotification {}
245 245
246#[derive(Serialize, Deserialize)] 246impl Notification for ServerStatusNotification {
247#[serde(rename_all = "camelCase")] 247 type Params = ServerStatusParams;
248pub enum Status { 248 const METHOD: &'static str = "experimental/serverStatus";
249 Loading,
250 ReadyPartial,
251 Ready,
252 NeedsReload,
253 Invalid,
254} 249}
255 250
256#[derive(Deserialize, Serialize)] 251#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
257pub struct StatusParams { 252pub struct ServerStatusParams {
258 pub status: Status, 253 pub health: Health,
254 pub quiescent: bool,
255 pub message: Option<String>,
259} 256}
260 257
261impl Notification for StatusNotification { 258#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
262 type Params = StatusParams; 259#[serde(rename_all = "camelCase")]
263 const METHOD: &'static str = "rust-analyzer/status"; 260pub enum Health {
261 Ok,
262 Warning,
263 Error,
264} 264}
265 265
266pub enum CodeActionRequest {} 266pub enum CodeActionRequest {}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index e88f16cc1..a5655116b 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -2,6 +2,7 @@
2//! requests/replies and notifications back to the client. 2//! requests/replies and notifications back to the client.
3use std::{ 3use std::{
4 env, fmt, 4 env, fmt,
5 sync::Arc,
5 time::{Duration, Instant}, 6 time::{Duration, Instant},
6}; 7};
7 8
@@ -12,6 +13,7 @@ use ide::{Canceled, FileId};
12use ide_db::base_db::VfsPath; 13use ide_db::base_db::VfsPath;
13use lsp_server::{Connection, Notification, Request, Response}; 14use lsp_server::{Connection, Notification, Request, Response};
14use lsp_types::notification::Notification as _; 15use lsp_types::notification::Notification as _;
16use project_model::BuildDataCollector;
15use vfs::ChangeKind; 17use vfs::ChangeKind;
16 18
17use crate::{ 19use crate::{
@@ -19,7 +21,7 @@ use crate::{
19 dispatch::{NotificationDispatcher, RequestDispatcher}, 21 dispatch::{NotificationDispatcher, RequestDispatcher},
20 document::DocumentData, 22 document::DocumentData,
21 from_proto, 23 from_proto,
22 global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, 24 global_state::{file_id_to_url, url_to_file_id, GlobalState},
23 handlers, lsp_ext, 25 handlers, lsp_ext,
24 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, 26 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
25 reload::{BuildDataProgress, ProjectWorkspaceProgress}, 27 reload::{BuildDataProgress, ProjectWorkspaceProgress},
@@ -187,7 +189,7 @@ impl GlobalState {
187 log::info!("task queue len: {}", task_queue_len); 189 log::info!("task queue len: {}", task_queue_len);
188 } 190 }
189 191
190 let mut new_status = self.status; 192 let was_quiescent = self.is_quiescent();
191 match event { 193 match event {
192 Event::Lsp(msg) => match msg { 194 Event::Lsp(msg) => match msg {
193 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, 195 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
@@ -227,11 +229,24 @@ impl GlobalState {
227 (Progress::Report, Some(msg)) 229 (Progress::Report, Some(msg))
228 } 230 }
229 ProjectWorkspaceProgress::End(workspaces) => { 231 ProjectWorkspaceProgress::End(workspaces) => {
230 self.fetch_workspaces_completed(); 232 self.fetch_workspaces_completed(workspaces);
231 self.switch_workspaces(workspaces, None); 233
234 let old = Arc::clone(&self.workspaces);
235 self.switch_workspaces();
236 let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
237
238 if self.config.run_build_scripts() && workspaces_updated {
239 let mut collector = BuildDataCollector::default();
240 for ws in self.workspaces.iter() {
241 ws.collect_build_data_configs(&mut collector);
242 }
243 self.fetch_build_data_request(collector)
244 }
245
232 (Progress::End, None) 246 (Progress::End, None)
233 } 247 }
234 }; 248 };
249
235 self.report_progress("fetching", state, msg, None); 250 self.report_progress("fetching", state, msg, None);
236 } 251 }
237 Task::FetchBuildData(progress) => { 252 Task::FetchBuildData(progress) => {
@@ -240,19 +255,21 @@ impl GlobalState {
240 BuildDataProgress::Report(msg) => { 255 BuildDataProgress::Report(msg) => {
241 (Some(Progress::Report), Some(msg)) 256 (Some(Progress::Report), Some(msg))
242 } 257 }
243 BuildDataProgress::End(collector) => { 258 BuildDataProgress::End(build_data_result) => {
244 self.fetch_build_data_completed(); 259 self.fetch_build_data_completed(build_data_result);
245 let workspaces = 260
246 (*self.workspaces).clone().into_iter().map(Ok).collect(); 261 self.switch_workspaces();
247 self.switch_workspaces(workspaces, Some(collector)); 262
248 (Some(Progress::End), None) 263 (Some(Progress::End), None)
249 } 264 }
250 }; 265 };
266
251 if let Some(state) = state { 267 if let Some(state) = state {
252 self.report_progress("loading", state, msg, None); 268 self.report_progress("loading", state, msg, None);
253 } 269 }
254 } 270 }
255 } 271 }
272
256 // Coalesce multiple task events into one loop turn 273 // Coalesce multiple task events into one loop turn
257 task = match self.task_pool.receiver.try_recv() { 274 task = match self.task_pool.receiver.try_recv() {
258 Ok(task) => task, 275 Ok(task) => task,
@@ -298,30 +315,25 @@ impl GlobalState {
298 } 315 }
299 vfs::loader::Message::Progress { n_total, n_done, config_version } => { 316 vfs::loader::Message::Progress { n_total, n_done, config_version } => {
300 always!(config_version <= self.vfs_config_version); 317 always!(config_version <= self.vfs_config_version);
301 if n_total == 0 { 318
302 new_status = Status::Invalid; 319 self.vfs_progress_config_version = config_version;
320 self.vfs_progress_n_total = n_total;
321 self.vfs_progress_n_done = n_done;
322
323 let state = if n_done == 0 {
324 Progress::Begin
325 } else if n_done < n_total {
326 Progress::Report
303 } else { 327 } else {
304 let state = if n_done == 0 { 328 assert_eq!(n_done, n_total);
305 new_status = Status::Loading; 329 Progress::End
306 Progress::Begin 330 };
307 } else if n_done < n_total { 331 self.report_progress(
308 Progress::Report 332 "roots scanned",
309 } else { 333 state,
310 assert_eq!(n_done, n_total); 334 Some(format!("{}/{}", n_done, n_total)),
311 new_status = Status::Ready { 335 Some(Progress::fraction(n_done, n_total)),
312 partial: self.config.run_build_scripts() 336 )
313 && self.workspace_build_data.is_none()
314 || config_version < self.vfs_config_version,
315 };
316 Progress::End
317 };
318 self.report_progress(
319 "roots scanned",
320 state,
321 Some(format!("{}/{}", n_done, n_total)),
322 Some(Progress::fraction(n_done, n_total)),
323 )
324 }
325 } 337 }
326 } 338 }
327 // Coalesce many VFS event into a single loop turn 339 // Coalesce many VFS event into a single loop turn
@@ -397,18 +409,14 @@ impl GlobalState {
397 } 409 }
398 410
399 let state_changed = self.process_changes(); 411 let state_changed = self.process_changes();
400 let prev_status = self.status; 412
401 if prev_status != new_status { 413 if self.is_quiescent() && !was_quiescent {
402 self.transition(new_status);
403 }
404 let is_ready = matches!(self.status, Status::Ready { .. });
405 if prev_status == Status::Loading && is_ready {
406 for flycheck in &self.flycheck { 414 for flycheck in &self.flycheck {
407 flycheck.update(); 415 flycheck.update();
408 } 416 }
409 } 417 }
410 418
411 if is_ready && (state_changed || prev_status == Status::Loading) { 419 if self.is_quiescent() && (!was_quiescent || state_changed) {
412 self.update_file_notifications_on_threadpool(); 420 self.update_file_notifications_on_threadpool();
413 421
414 // Refresh semantic tokens if the client supports it. 422 // Refresh semantic tokens if the client supports it.
@@ -437,9 +445,13 @@ impl GlobalState {
437 } 445 }
438 } 446 }
439 447
440 self.fetch_workspaces_if_needed(); 448 if self.config.cargo_autoreload() {
449 self.fetch_workspaces_if_needed();
450 }
441 self.fetch_build_data_if_needed(); 451 self.fetch_build_data_if_needed();
442 452
453 self.report_new_status_if_needed();
454
443 let loop_duration = loop_start.elapsed(); 455 let loop_duration = loop_start.elapsed();
444 if loop_duration > Duration::from_millis(100) { 456 if loop_duration > Duration::from_millis(100) {
445 log::warn!("overly long loop turn: {:?}", loop_duration); 457 log::warn!("overly long loop turn: {:?}", loop_duration);
@@ -466,7 +478,8 @@ impl GlobalState {
466 return Ok(()); 478 return Ok(());
467 } 479 }
468 480
469 if self.status == Status::Loading && req.method != "shutdown" { 481 // Avoid flashing a bunch of unresolved references during initial load.
482 if self.workspaces.is_empty() && !self.is_quiescent() {
470 self.respond(lsp_server::Response::new_err( 483 self.respond(lsp_server::Response::new_err(
471 req.id, 484 req.id,
472 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) 485 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
@@ -477,7 +490,11 @@ impl GlobalState {
477 } 490 }
478 491
479 RequestDispatcher { req: Some(req), global_state: self } 492 RequestDispatcher { req: Some(req), global_state: self }
480 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))? 493 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| {
494 s.fetch_workspaces_request();
495 s.fetch_workspaces_if_needed();
496 Ok(())
497 })?
481 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 498 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
482 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? 499 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
483 .on_sync::<lsp_types::request::Shutdown>(|s, ()| { 500 .on_sync::<lsp_types::request::Shutdown>(|s, ()| {
diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs
index f71b718bc..1d612a933 100644
--- a/crates/rust-analyzer/src/op_queue.rs
+++ b/crates/rust-analyzer/src/op_queue.rs
@@ -2,27 +2,27 @@
2//! at a time. 2//! at a time.
3 3
4pub(crate) struct OpQueue<Args, Output> { 4pub(crate) struct OpQueue<Args, Output> {
5 op_scheduled: Option<Args>, 5 op_requested: Option<Args>,
6 op_in_progress: bool, 6 op_in_progress: bool,
7 last_op_result: Output, 7 last_op_result: Output,
8} 8}
9 9
10impl<Args, Output: Default> Default for OpQueue<Args, Output> { 10impl<Args, Output: Default> Default for OpQueue<Args, Output> {
11 fn default() -> Self { 11 fn default() -> Self {
12 Self { op_scheduled: None, op_in_progress: false, last_op_result: Default::default() } 12 Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() }
13 } 13 }
14} 14}
15 15
16impl<Args, Output> OpQueue<Args, Output> { 16impl<Args, Output> OpQueue<Args, Output> {
17 pub(crate) fn request_op(&mut self, data: Args) { 17 pub(crate) fn request_op(&mut self, data: Args) {
18 self.op_scheduled = Some(data); 18 self.op_requested = Some(data);
19 } 19 }
20 pub(crate) fn should_start_op(&mut self) -> Option<Args> { 20 pub(crate) fn should_start_op(&mut self) -> Option<Args> {
21 if self.op_in_progress { 21 if self.op_in_progress {
22 return None; 22 return None;
23 } 23 }
24 self.op_in_progress = self.op_scheduled.is_some(); 24 self.op_in_progress = self.op_requested.is_some();
25 self.op_scheduled.take() 25 self.op_requested.take()
26 } 26 }
27 pub(crate) fn op_completed(&mut self, result: Output) { 27 pub(crate) fn op_completed(&mut self, result: Output) {
28 assert!(self.op_in_progress); 28 assert!(self.op_in_progress);
@@ -34,4 +34,10 @@ impl<Args, Output> OpQueue<Args, Output> {
34 pub(crate) fn last_op_result(&self) -> &Output { 34 pub(crate) fn last_op_result(&self) -> &Output {
35 &self.last_op_result 35 &self.last_op_result
36 } 36 }
37 pub(crate) fn op_in_progress(&self) -> bool {
38 self.op_in_progress
39 }
40 pub(crate) fn op_requested(&self) -> bool {
41 self.op_requested.is_some()
42 }
37} 43}
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index d12f891bb..d0cc1b61a 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -9,11 +9,10 @@ use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
9 9
10use crate::{ 10use crate::{
11 config::{Config, FilesWatcher, LinkedProject}, 11 config::{Config, FilesWatcher, LinkedProject},
12 global_state::{GlobalState, Status}, 12 global_state::GlobalState,
13 lsp_ext, 13 lsp_ext,
14 main_loop::Task, 14 main_loop::Task,
15}; 15};
16use lsp_ext::StatusParams;
17 16
18#[derive(Debug)] 17#[derive(Debug)]
19pub(crate) enum ProjectWorkspaceProgress { 18pub(crate) enum ProjectWorkspaceProgress {
@@ -30,6 +29,13 @@ pub(crate) enum BuildDataProgress {
30} 29}
31 30
32impl GlobalState { 31impl GlobalState {
32 pub(crate) fn is_quiescent(&self) -> bool {
33 !(self.fetch_workspaces_queue.op_in_progress()
34 || self.fetch_build_data_queue.op_in_progress()
35 || self.vfs_progress_config_version < self.vfs_config_version
36 || self.vfs_progress_n_done < self.vfs_progress_n_total)
37 }
38
33 pub(crate) fn update_configuration(&mut self, config: Config) { 39 pub(crate) fn update_configuration(&mut self, config: Config) {
34 let _p = profile::span("GlobalState::update_configuration"); 40 let _p = profile::span("GlobalState::update_configuration");
35 let old_config = mem::replace(&mut self.config, Arc::new(config)); 41 let old_config = mem::replace(&mut self.config, Arc::new(config));
@@ -46,25 +52,17 @@ impl GlobalState {
46 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { 52 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) {
47 return; 53 return;
48 } 54 }
49 match self.status {
50 Status::Loading | Status::NeedsReload => return,
51 Status::Ready { .. } | Status::Invalid => (),
52 }
53 log::info!( 55 log::info!(
54 "Reloading workspace because of the following changes: {}", 56 "Requesting workspace reload because of the following changes: {}",
55 itertools::join( 57 itertools::join(
56 changes 58 changes
57 .iter() 59 .iter()
58 .filter(|(path, kind)| is_interesting(path, *kind)) 60 .filter(|(path, kind)| is_interesting(path, *kind))
59 .map(|(path, kind)| format!("{}/{:?}", path.display(), kind)), 61 .map(|(path, kind)| format!("{}: {:?}", path.display(), kind)),
60 ", " 62 ", "
61 ) 63 )
62 ); 64 );
63 if self.config.cargo_autoreload() { 65 self.fetch_workspaces_request();
64 self.fetch_workspaces_request();
65 } else {
66 self.transition(Status::NeedsReload);
67 }
68 66
69 fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool { 67 fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool {
70 const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; 68 const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
@@ -101,46 +99,38 @@ 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| {
130 sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
131 112
132 let progress = { 113 if let Some(error) = self.build_data_error() {
133 let sender = sender.clone(); 114 status.health = lsp_ext::Health::Warning;
134 move |msg| { 115 status.message = Some(error)
135 sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap() 116 }
136 } 117 if !self.config.cargo_autoreload()
137 }; 118 && self.is_quiescent()
138 let res = build_data_collector.collect(&progress); 119 && self.fetch_workspaces_queue.op_requested()
139 sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap(); 120 {
140 }); 121 status.health = lsp_ext::Health::Warning;
141 } 122 status.message = Some("Workspace reload required".to_string())
142 pub(crate) fn fetch_build_data_completed(&mut self) { 123 }
143 self.fetch_build_data_queue.op_completed(()) 124
125 if let Some(error) = self.fetch_workspace_error() {
126 status.health = lsp_ext::Health::Error;
127 status.message = Some(error)
128 }
129
130 if self.last_reported_status.as_ref() != Some(&status) {
131 self.last_reported_status = Some(status.clone());
132 self.send_notification::<lsp_ext::ServerStatusNotification>(status);
133 }
144 } 134 }
145 135
146 pub(crate) fn fetch_workspaces_request(&mut self) { 136 pub(crate) fn fetch_workspaces_request(&mut self) {
@@ -194,54 +184,71 @@ impl GlobalState {
194 } 184 }
195 }); 185 });
196 } 186 }
197 pub(crate) fn fetch_workspaces_completed(&mut self) { 187 pub(crate) fn fetch_workspaces_completed(
198 self.fetch_workspaces_queue.op_completed(()) 188 &mut self,
189 workspaces: Vec<anyhow::Result<ProjectWorkspace>>,
190 ) {
191 self.fetch_workspaces_queue.op_completed(workspaces)
192 }
193
194 pub(crate) fn fetch_build_data_request(&mut self, build_data_collector: BuildDataCollector) {
195 self.fetch_build_data_queue.request_op(build_data_collector);
199 } 196 }
197 pub(crate) fn fetch_build_data_if_needed(&mut self) {
198 let mut build_data_collector = match self.fetch_build_data_queue.should_start_op() {
199 Some(it) => it,
200 None => return,
201 };
202 self.task_pool.handle.spawn_with_sender(move |sender| {
203 sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
200 204
201 pub(crate) fn switch_workspaces( 205 let progress = {
206 let sender = sender.clone();
207 move |msg| {
208 sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
209 }
210 };
211 let res = build_data_collector.collect(&progress);
212 sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap();
213 });
214 }
215 pub(crate) fn fetch_build_data_completed(
202 &mut self, 216 &mut self,
203 workspaces: Vec<anyhow::Result<ProjectWorkspace>>, 217 build_data: anyhow::Result<BuildDataResult>,
204 workspace_build_data: Option<anyhow::Result<BuildDataResult>>,
205 ) { 218 ) {
206 let _p = profile::span("GlobalState::switch_workspaces"); 219 self.fetch_build_data_queue.op_completed(Some(build_data))
207 log::info!("will switch workspaces: {:?}", workspaces); 220 }
208 221
209 let mut has_errors = false; 222 pub(crate) fn switch_workspaces(&mut self) {
210 let workspaces = workspaces 223 let _p = profile::span("GlobalState::switch_workspaces");
211 .into_iter() 224 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 225
227 let workspace_build_data = match workspace_build_data { 226 if let Some(error_message) = self.fetch_workspace_error() {
228 Some(Ok(it)) => Some(it), 227 log::error!("failed to switch workspaces: {}", error_message);
229 Some(Err(err)) => { 228 self.show_message(lsp_types::MessageType::Error, error_message);
230 log::error!("failed to fetch build data: {:#}", err); 229 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; 230 return;
236 } 231 }
237 None => None, 232 }
238 };
239 233
240 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data { 234 if let Some(error_message) = self.build_data_error() {
241 return; 235 log::error!("failed to switch build data: {}", error_message);
236 self.show_message(lsp_types::MessageType::Error, error_message);
242 } 237 }
243 238
244 if !self.workspaces.is_empty() && has_errors { 239 let workspaces = self
240 .fetch_workspaces_queue
241 .last_op_result()
242 .iter()
243 .filter_map(|res| res.as_ref().ok().cloned())
244 .collect::<Vec<_>>();
245
246 let workspace_build_data = match self.fetch_build_data_queue.last_op_result() {
247 Some(Ok(it)) => Some(it.clone()),
248 None | Some(Err(_)) => None,
249 };
250
251 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data {
245 return; 252 return;
246 } 253 }
247 254
@@ -337,14 +344,6 @@ impl GlobalState {
337 }; 344 };
338 change.set_crate_graph(crate_graph); 345 change.set_crate_graph(crate_graph);
339 346
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; 347 self.source_root_config = project_folders.source_root_config;
349 self.workspaces = Arc::new(workspaces); 348 self.workspaces = Arc::new(workspaces);
350 self.workspace_build_data = workspace_build_data; 349 self.workspace_build_data = workspace_build_data;
@@ -355,6 +354,32 @@ impl GlobalState {
355 log::info!("did switch workspaces"); 354 log::info!("did switch workspaces");
356 } 355 }
357 356
357 fn fetch_workspace_error(&self) -> Option<String> {
358 let mut buf = String::new();
359
360 for ws in self.fetch_workspaces_queue.last_op_result() {
361 if let Err(err) = ws {
362 stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
363 }
364 }
365
366 if buf.is_empty() {
367 return None;
368 }
369
370 Some(buf)
371 }
372
373 fn build_data_error(&self) -> Option<String> {
374 match self.fetch_build_data_queue.last_op_result() {
375 Some(Err(err)) => {
376 Some(format!("rust-analyzer failed to fetch build data: {:#}\n", err))
377 }
378 Some(Ok(data)) => data.error(),
379 None => None,
380 }
381 }
382
358 fn reload_flycheck(&mut self) { 383 fn reload_flycheck(&mut self) {
359 let _p = profile::span("GlobalState::reload_flycheck"); 384 let _p = profile::span("GlobalState::reload_flycheck");
360 let config = match self.config.flycheck() { 385 let config = match self.config.flycheck() {
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs
index 95bf26f01..8d68f1b7d 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/support.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs
@@ -103,7 +103,7 @@ impl<'a> Project<'a> {
103 ..Default::default() 103 ..Default::default()
104 }), 104 }),
105 experimental: Some(json!({ 105 experimental: Some(json!({
106 "statusNotification": true, 106 "serverStatusNotification": true,
107 })), 107 })),
108 ..Default::default() 108 ..Default::default()
109 }, 109 },
@@ -213,13 +213,12 @@ impl Server {
213 } 213 }
214 pub(crate) fn wait_until_workspace_is_loaded(self) -> Server { 214 pub(crate) fn wait_until_workspace_is_loaded(self) -> Server {
215 self.wait_for_message_cond(1, &|msg: &Message| match msg { 215 self.wait_for_message_cond(1, &|msg: &Message| match msg {
216 Message::Notification(n) if n.method == "rust-analyzer/status" => { 216 Message::Notification(n) if n.method == "experimental/serverStatus" => {
217 let status = n 217 let status = n
218 .clone() 218 .clone()
219 .extract::<lsp_ext::StatusParams>("rust-analyzer/status") 219 .extract::<lsp_ext::ServerStatusParams>("experimental/serverStatus")
220 .unwrap() 220 .unwrap();
221 .status; 221 status.quiescent
222 matches!(status, lsp_ext::Status::Ready)
223 } 222 }
224 _ => false, 223 _ => false,
225 }) 224 })
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index d26be4853..b0a18d58d 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -178,6 +178,7 @@ where
178 start..start + len 178 start..start + len
179} 179}
180 180
181#[repr(transparent)]
181pub struct JodChild(pub process::Child); 182pub struct JodChild(pub process::Child);
182 183
183impl ops::Deref for JodChild { 184impl ops::Deref for JodChild {
@@ -200,6 +201,13 @@ impl Drop for JodChild {
200 } 201 }
201} 202}
202 203
204impl JodChild {
205 pub fn into_inner(self) -> process::Child {
206 // SAFETY: repr transparent
207 unsafe { std::mem::transmute::<JodChild, process::Child>(self) }
208 }
209}
210
203#[cfg(test)] 211#[cfg(test)]
204mod tests { 212mod tests {
205 use super::*; 213 use super::*;
diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml
index c318a68f7..894944b18 100644
--- a/crates/vfs/Cargo.toml
+++ b/crates/vfs/Cargo.toml
@@ -14,3 +14,4 @@ rustc-hash = "1.0"
14fst = "0.4" 14fst = "0.4"
15 15
16paths = { path = "../paths", version = "0.0.0" } 16paths = { path = "../paths", version = "0.0.0" }
17indexmap = "1.6.2"
diff --git a/crates/vfs/src/path_interner.rs b/crates/vfs/src/path_interner.rs
index 2189e5e25..6e049f0d4 100644
--- a/crates/vfs/src/path_interner.rs
+++ b/crates/vfs/src/path_interner.rs
@@ -1,15 +1,22 @@
1//! Maps paths to compact integer ids. We don't care about clearings paths which 1//! Maps paths to compact integer ids. We don't care about clearings paths which
2//! no longer exist -- the assumption is total size of paths we ever look at is 2//! no longer exist -- the assumption is total size of paths we ever look at is
3//! not too big. 3//! not too big.
4use rustc_hash::FxHashMap; 4use std::hash::BuildHasherDefault;
5
6use indexmap::IndexSet;
7use rustc_hash::FxHasher;
5 8
6use crate::{FileId, VfsPath}; 9use crate::{FileId, VfsPath};
7 10
8/// Structure to map between [`VfsPath`] and [`FileId`]. 11/// Structure to map between [`VfsPath`] and [`FileId`].
9#[derive(Default)]
10pub(crate) struct PathInterner { 12pub(crate) struct PathInterner {
11 map: FxHashMap<VfsPath, FileId>, 13 map: IndexSet<VfsPath, BuildHasherDefault<FxHasher>>,
12 vec: Vec<VfsPath>, 14}
15
16impl Default for PathInterner {
17 fn default() -> Self {
18 Self { map: IndexSet::default() }
19 }
13} 20}
14 21
15impl PathInterner { 22impl PathInterner {
@@ -17,7 +24,7 @@ impl PathInterner {
17 /// 24 ///
18 /// If `path` does not exists in `self`, returns [`None`]. 25 /// If `path` does not exists in `self`, returns [`None`].
19 pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> { 26 pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> {
20 self.map.get(path).copied() 27 self.map.get_index_of(path).map(|i| FileId(i as u32))
21 } 28 }
22 29
23 /// Insert `path` in `self`. 30 /// Insert `path` in `self`.
@@ -25,13 +32,9 @@ impl PathInterner {
25 /// - If `path` already exists in `self`, returns its associated id; 32 /// - If `path` already exists in `self`, returns its associated id;
26 /// - Else, returns a newly allocated id. 33 /// - Else, returns a newly allocated id.
27 pub(crate) fn intern(&mut self, path: VfsPath) -> FileId { 34 pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
28 if let Some(id) = self.get(&path) { 35 let (id, _added) = self.map.insert_full(path);
29 return id; 36 assert!(id < u32::MAX as usize);
30 } 37 FileId(id as u32)
31 let id = FileId(self.vec.len() as u32);
32 self.map.insert(path.clone(), id);
33 self.vec.push(path);
34 id
35 } 38 }
36 39
37 /// Returns the path corresponding to `id`. 40 /// Returns the path corresponding to `id`.
@@ -40,6 +43,6 @@ impl PathInterner {
40 /// 43 ///
41 /// Panics if `id` does not exists in `self`. 44 /// Panics if `id` does not exists in `self`.
42 pub(crate) fn lookup(&self, id: FileId) -> &VfsPath { 45 pub(crate) fn lookup(&self, id: FileId) -> &VfsPath {
43 &self.vec[id.0 as usize] 46 self.map.get_index(id.0 as usize).unwrap()
44 } 47 }
45} 48}