diff options
Diffstat (limited to 'crates')
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 | }; |
65 | use itertools::Itertools; | 65 | use 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 | ||
19 | use crate::{ | 19 | use 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)] |
242 | pub enum Statement { | 243 | pub 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 | ||
59 | use adt::VariantData; | ||
59 | use base_db::{impl_intern_key, salsa, CrateId}; | 60 | use base_db::{impl_intern_key, salsa, CrateId}; |
60 | use hir_expand::{ | 61 | use hir_expand::{ |
61 | ast_id_map::FileAstId, | 62 | ast_id_map::FileAstId, |
@@ -442,6 +443,18 @@ pub enum VariantId { | |||
442 | } | 443 | } |
443 | impl_from!(EnumVariantId, StructId, UnionId for VariantId); | 444 | impl_from!(EnumVariantId, StructId, UnionId for VariantId); |
444 | 445 | ||
446 | impl 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 | |||
445 | trait Intern { | 458 | trait 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 | ||
292 | impl From<Name> for Box<Path> { | ||
293 | fn from(name: Name) -> Box<Path> { | ||
294 | Box::new(Path::from(name)) | ||
295 | } | ||
296 | } | ||
297 | |||
292 | impl From<Name> for ModPath { | 298 | impl 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; | |||
13 | use crate::{ | 13 | use crate::{ |
14 | db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, | 14 | db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, |
15 | CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, | 15 | CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, |
16 | TraitRef, Ty, TyDefId, TyKind, TypeWalk, ValueTyDefId, | 16 | TraitRef, Ty, TyDefId, TyExt, TyKind, TypeWalk, ValueTyDefId, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | /// This is a builder for `Ty` or anything that needs a `Substitution`. | 19 | /// This is a builder for `Ty` or anything that needs a `Substitution`. |
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs index 0f4cb43e9..8e8a1aa48 100644 --- a/crates/hir_ty/src/chalk_ext.rs +++ b/crates/hir_ty/src/chalk_ext.rs | |||
@@ -1,20 +1,243 @@ | |||
1 | //! Various extensions traits for Chalk types. | 1 | //! Various extensions traits for Chalk types. |
2 | 2 | ||
3 | use hir_def::{AssocContainerId, Lookup, TraitId}; | 3 | use chalk_ir::Mutability; |
4 | use hir_def::{ | ||
5 | type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId, | ||
6 | }; | ||
4 | 7 | ||
5 | use crate::{ | 8 | use crate::{ |
6 | db::HirDatabase, from_assoc_type_id, to_chalk_trait_id, Interner, ProjectionTy, TraitRef, Ty, | 9 | db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, |
7 | TyKind, | 10 | from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId, |
11 | CallableSig, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, | ||
12 | Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause, | ||
8 | }; | 13 | }; |
9 | 14 | ||
10 | pub trait TyExt { | 15 | pub trait TyExt { |
11 | fn is_unit(&self) -> bool; | 16 | fn is_unit(&self) -> bool; |
17 | fn is_never(&self) -> bool; | ||
18 | fn is_unknown(&self) -> bool; | ||
19 | |||
20 | fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; | ||
21 | fn as_tuple(&self) -> Option<&Substitution>; | ||
22 | fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>; | ||
23 | fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; | ||
24 | fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>; | ||
25 | fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>; | ||
26 | |||
27 | fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>; | ||
28 | fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>; | ||
29 | |||
30 | fn strip_references(&self) -> &Ty; | ||
31 | |||
32 | /// If this is a `dyn Trait`, returns that trait. | ||
33 | fn dyn_trait(&self) -> Option<TraitId>; | ||
34 | |||
35 | fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>; | ||
36 | fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>; | ||
12 | } | 37 | } |
13 | 38 | ||
14 | impl TyExt for Ty { | 39 | impl TyExt for Ty { |
15 | fn is_unit(&self) -> bool { | 40 | fn is_unit(&self) -> bool { |
16 | matches!(self.kind(&Interner), TyKind::Tuple(0, _)) | 41 | matches!(self.kind(&Interner), TyKind::Tuple(0, _)) |
17 | } | 42 | } |
43 | |||
44 | fn is_never(&self) -> bool { | ||
45 | matches!(self.kind(&Interner), TyKind::Never) | ||
46 | } | ||
47 | |||
48 | fn is_unknown(&self) -> bool { | ||
49 | matches!(self.kind(&Interner), TyKind::Error) | ||
50 | } | ||
51 | |||
52 | fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { | ||
53 | match self.kind(&Interner) { | ||
54 | TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), | ||
55 | _ => None, | ||
56 | } | ||
57 | } | ||
58 | |||
59 | fn as_tuple(&self) -> Option<&Substitution> { | ||
60 | match self.kind(&Interner) { | ||
61 | TyKind::Tuple(_, substs) => Some(substs), | ||
62 | _ => None, | ||
63 | } | ||
64 | } | ||
65 | |||
66 | fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> { | ||
67 | if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) { | ||
68 | Some(func) | ||
69 | } else { | ||
70 | None | ||
71 | } | ||
72 | } | ||
73 | fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> { | ||
74 | match self.kind(&Interner) { | ||
75 | TyKind::Ref(mutability, lifetime, ty) => Some((ty, *lifetime, *mutability)), | ||
76 | _ => None, | ||
77 | } | ||
78 | } | ||
79 | |||
80 | fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { | ||
81 | match self.kind(&Interner) { | ||
82 | TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)), | ||
83 | TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)), | ||
84 | _ => None, | ||
85 | } | ||
86 | } | ||
87 | |||
88 | fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> { | ||
89 | match *self.kind(&Interner) { | ||
90 | TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), | ||
91 | TyKind::FnDef(callable, ..) => { | ||
92 | Some(db.lookup_intern_callable_def(callable.into()).into()) | ||
93 | } | ||
94 | TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()), | ||
95 | TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()), | ||
96 | _ => None, | ||
97 | } | ||
98 | } | ||
99 | |||
100 | fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> { | ||
101 | match self.kind(&Interner) { | ||
102 | &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())), | ||
103 | _ => None, | ||
104 | } | ||
105 | } | ||
106 | |||
107 | fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> { | ||
108 | match self.kind(&Interner) { | ||
109 | TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)), | ||
110 | TyKind::FnDef(def, parameters) => { | ||
111 | let callable_def = db.lookup_intern_callable_def((*def).into()); | ||
112 | let sig = db.callable_item_signature(callable_def); | ||
113 | Some(sig.substitute(&Interner, ¶meters)) | ||
114 | } | ||
115 | TyKind::Closure(.., substs) => { | ||
116 | let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner); | ||
117 | sig_param.callable_sig(db) | ||
118 | } | ||
119 | _ => None, | ||
120 | } | ||
121 | } | ||
122 | |||
123 | fn dyn_trait(&self) -> Option<TraitId> { | ||
124 | let trait_ref = match self.kind(&Interner) { | ||
125 | TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| { | ||
126 | match b.skip_binders() { | ||
127 | WhereClause::Implemented(trait_ref) => Some(trait_ref), | ||
128 | _ => None, | ||
129 | } | ||
130 | }), | ||
131 | _ => None, | ||
132 | }?; | ||
133 | Some(from_chalk_trait_id(trait_ref.trait_id)) | ||
134 | } | ||
135 | |||
136 | fn strip_references(&self) -> &Ty { | ||
137 | let mut t: &Ty = self; | ||
138 | while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(&Interner) { | ||
139 | t = ty; | ||
140 | } | ||
141 | t | ||
142 | } | ||
143 | |||
144 | fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> { | ||
145 | match self.kind(&Interner) { | ||
146 | TyKind::OpaqueType(opaque_ty_id, ..) => { | ||
147 | match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) { | ||
148 | ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => { | ||
149 | let krate = def.module(db.upcast()).krate(); | ||
150 | if let Some(future_trait) = db | ||
151 | .lang_item(krate, "future_trait".into()) | ||
152 | .and_then(|item| item.as_trait()) | ||
153 | { | ||
154 | // This is only used by type walking. | ||
155 | // Parameters will be walked outside, and projection predicate is not used. | ||
156 | // So just provide the Future trait. | ||
157 | let impl_bound = Binders::empty( | ||
158 | &Interner, | ||
159 | WhereClause::Implemented(TraitRef { | ||
160 | trait_id: to_chalk_trait_id(future_trait), | ||
161 | substitution: Substitution::empty(&Interner), | ||
162 | }), | ||
163 | ); | ||
164 | Some(vec![impl_bound]) | ||
165 | } else { | ||
166 | None | ||
167 | } | ||
168 | } | ||
169 | ImplTraitId::ReturnTypeImplTrait(..) => None, | ||
170 | } | ||
171 | } | ||
172 | TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { | ||
173 | let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into()) | ||
174 | { | ||
175 | ImplTraitId::ReturnTypeImplTrait(func, idx) => { | ||
176 | db.return_type_impl_traits(func).map(|it| { | ||
177 | let data = (*it) | ||
178 | .as_ref() | ||
179 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
180 | data.substitute(&Interner, &opaque_ty.substitution) | ||
181 | }) | ||
182 | } | ||
183 | // It always has an parameter for Future::Output type. | ||
184 | ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(), | ||
185 | }; | ||
186 | |||
187 | predicates.map(|it| it.into_value_and_skipped_binders().0) | ||
188 | } | ||
189 | TyKind::Placeholder(idx) => { | ||
190 | let id = from_placeholder_idx(db, *idx); | ||
191 | let generic_params = db.generic_params(id.parent); | ||
192 | let param_data = &generic_params.types[id.local_id]; | ||
193 | match param_data.provenance { | ||
194 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | ||
195 | let substs = TyBuilder::type_params_subst(db, id.parent); | ||
196 | let predicates = db | ||
197 | .generic_predicates(id.parent) | ||
198 | .into_iter() | ||
199 | .map(|pred| pred.clone().substitute(&Interner, &substs)) | ||
200 | .filter(|wc| match &wc.skip_binders() { | ||
201 | WhereClause::Implemented(tr) => { | ||
202 | tr.self_type_parameter(&Interner) == self | ||
203 | } | ||
204 | WhereClause::AliasEq(AliasEq { | ||
205 | alias: AliasTy::Projection(proj), | ||
206 | ty: _, | ||
207 | }) => proj.self_type_parameter(&Interner) == self, | ||
208 | _ => false, | ||
209 | }) | ||
210 | .collect::<Vec<_>>(); | ||
211 | |||
212 | Some(predicates) | ||
213 | } | ||
214 | _ => None, | ||
215 | } | ||
216 | } | ||
217 | _ => None, | ||
218 | } | ||
219 | } | ||
220 | |||
221 | fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> { | ||
222 | match self.kind(&Interner) { | ||
223 | TyKind::AssociatedType(id, ..) => { | ||
224 | match from_assoc_type_id(*id).lookup(db.upcast()).container { | ||
225 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
226 | _ => None, | ||
227 | } | ||
228 | } | ||
229 | TyKind::Alias(AliasTy::Projection(projection_ty)) => { | ||
230 | match from_assoc_type_id(projection_ty.associated_ty_id) | ||
231 | .lookup(db.upcast()) | ||
232 | .container | ||
233 | { | ||
234 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
235 | _ => None, | ||
236 | } | ||
237 | } | ||
238 | _ => None, | ||
239 | } | ||
240 | } | ||
18 | } | 241 | } |
19 | 242 | ||
20 | pub trait ProjectionTyExt { | 243 | pub trait ProjectionTyExt { |
diff --git a/crates/hir_ty/src/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::{ | |||
227 | use la_arena::Idx; | 227 | use la_arena::Idx; |
228 | use smallvec::{smallvec, SmallVec}; | 228 | use smallvec::{smallvec, SmallVec}; |
229 | 229 | ||
230 | use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyKind}; | 230 | use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyExt, TyKind}; |
231 | 231 | ||
232 | #[derive(Debug, Clone, Copy)] | 232 | #[derive(Debug, Clone, Copy)] |
233 | /// Either a pattern from the source code being analyzed, represented as | 233 | /// Either a pattern from the source code being analyzed, represented as |
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index b5efe9df5..ed97dc0e3 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -11,7 +11,9 @@ use hir_def::{ | |||
11 | }; | 11 | }; |
12 | use hir_expand::diagnostics::DiagnosticSink; | 12 | use hir_expand::diagnostics::DiagnosticSink; |
13 | 13 | ||
14 | use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyKind}; | 14 | use crate::{ |
15 | db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyExt, TyKind, | ||
16 | }; | ||
15 | 17 | ||
16 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | 18 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { |
17 | owner: DefWithBodyId, | 19 | owner: DefWithBodyId, |
diff --git a/crates/hir_ty/src/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 | }; |
43 | use crate::{ | 43 | use crate::{ |
44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, | 44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, |
45 | to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyKind, | 45 | to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyExt, TyKind, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | // This lint has a false positive here. See the link below for details. | 48 | // This lint has a false positive here. See the link below for details. |
@@ -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 @@ | |||
7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; | 7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; |
8 | use hir_def::lang_item::LangItemTarget; | 8 | use hir_def::lang_item::LangItemTarget; |
9 | 9 | ||
10 | use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyKind}; | 10 | use crate::{autoderef, Interner, Solution, Ty, TyBuilder, TyExt, TyKind}; |
11 | 11 | ||
12 | use super::{InEnvironment, InferenceContext}; | 12 | use super::{InEnvironment, InferenceContext}; |
13 | 13 | ||
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 | ||
29 | use super::{ | 30 | use 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 | ||
14 | use super::{BindingMode, Expectation, InferenceContext}; | 14 | use super::{BindingMode, Expectation, InferenceContext}; |
15 | use crate::{ | 15 | use 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 | ||
20 | impl<'a> InferenceContext<'a> { | 20 | impl<'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 | }; |
11 | use hir_expand::name::Name; | 11 | use hir_expand::name::Name; |
12 | 12 | ||
13 | use crate::{method_resolution, Interner, Substitution, Ty, TyBuilder, TyKind, ValueTyDefId}; | 13 | use crate::{ |
14 | method_resolution, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId, | ||
15 | }; | ||
14 | 16 | ||
15 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | 17 | use super::{ExprOrPatId, InferenceContext, TraitRef}; |
16 | 18 | ||
diff --git a/crates/hir_ty/src/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 | ||
31 | use std::sync::Arc; | 31 | use std::sync::Arc; |
32 | 32 | ||
33 | use chalk_ir::UintTy; | ||
34 | use itertools::Itertools; | ||
35 | |||
36 | use base_db::salsa; | 33 | use base_db::salsa; |
34 | use chalk_ir::UintTy; | ||
37 | use hir_def::{ | 35 | use 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 | ||
42 | use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; | 40 | use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; |
@@ -171,65 +169,6 @@ impl CallableSig { | |||
171 | } | 169 | } |
172 | 170 | ||
173 | impl Ty { | 171 | impl 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, ¶meters)) | ||
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 | }; |
27 | use mapping::{ | 27 | use mapping::{ |
28 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, | 28 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, |
diff --git a/crates/hir_ty/src/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 | ||
5 | use chalk_ir::{BoundVar, DebruijnIndex}; | 5 | use chalk_ir::{BoundVar, DebruijnIndex}; |
6 | use hir_def::{ | 6 | use 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 | }; |
18 | use hir_expand::name::{name, Name}; | 17 | use 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 | ||
139 | pub(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. |
151 | pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] { | 140 | pub(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. |
3 | use std::{ | 3 | use 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 | ||
39 | impl Borrow<AbsPath> for AbsPathBuf { | ||
40 | fn borrow(&self) -> &AbsPath { | ||
41 | self.as_path() | ||
42 | } | ||
43 | } | ||
44 | |||
38 | impl TryFrom<PathBuf> for AbsPathBuf { | 45 | impl 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}; | |||
13 | use itertools::Itertools; | 13 | use itertools::Itertools; |
14 | use paths::{AbsPath, AbsPathBuf}; | 14 | use paths::{AbsPath, AbsPathBuf}; |
15 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
16 | use stdx::JodChild; | 16 | use stdx::{format_to, JodChild}; |
17 | 17 | ||
18 | use crate::{cfg_flag::CfgFlag, CargoConfig}; | 18 | use crate::{cfg_flag::CfgFlag, CargoConfig}; |
19 | 19 | ||
20 | #[derive(Debug, Clone, Default, PartialEq, Eq)] | 20 | #[derive(Debug, Clone, Default, PartialEq, Eq)] |
21 | pub(crate) struct BuildData { | 21 | pub(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)] | ||
36 | pub(crate) struct WorkspaceBuildData { | ||
37 | per_package: FxHashMap<String, PackageBuildData>, | ||
38 | error: Option<String>, | ||
39 | } | ||
40 | |||
41 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | ||
42 | pub struct BuildDataResult { | ||
43 | per_workspace: FxHashMap<AbsPathBuf, WorkspaceBuildData>, | ||
44 | } | ||
45 | |||
35 | #[derive(Clone, Debug)] | 46 | #[derive(Clone, Debug)] |
36 | pub(crate) struct BuildDataConfig { | 47 | pub(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)] | ||
56 | pub struct BuildDataResult { | ||
57 | data: FxHashMap<AbsPathBuf, BuildDataMap>, | ||
58 | } | ||
59 | |||
60 | pub(crate) type BuildDataMap = FxHashMap<String, BuildData>; | ||
61 | |||
62 | impl BuildDataCollector { | 66 | impl 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 | ||
88 | impl WorkspaceBuildData { | ||
89 | pub(crate) fn get(&self, package_id: &str) -> Option<&PackageBuildData> { | ||
90 | self.per_package.get(package_id) | ||
91 | } | ||
92 | } | ||
93 | |||
84 | impl BuildDataResult { | 94 | impl 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> |
215 | fn inject_cargo_env(package: &cargo_metadata::Package, build_data: &mut BuildData) { | 249 | fn 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; | |||
12 | use rustc_hash::{FxHashMap, FxHashSet}; | 12 | use rustc_hash::{FxHashMap, FxHashSet}; |
13 | 13 | ||
14 | use crate::{ | 14 | use 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( | |||
555 | fn add_target_crate_root( | 555 | fn 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 | }; |
14 | use hir_def::FunctionId; | 14 | use hir_def::FunctionId; |
15 | use hir_ty::TypeWalk; | 15 | use hir_ty::{TyExt, TypeWalk}; |
16 | use ide::{AnalysisHost, RootDatabase}; | 16 | use ide::{AnalysisHost, RootDatabase}; |
17 | use ide_db::base_db::{ | 17 | use ide_db::base_db::{ |
18 | salsa::{self, ParallelDatabase}, | 18 | salsa::{self, ParallelDatabase}, |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index cda272fd4..e012b4452 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -445,8 +445,8 @@ impl Config { | |||
445 | pub fn hover_actions(&self) -> bool { | 445 | pub fn hover_actions(&self) -> bool { |
446 | self.experimental("hoverActions") | 446 | self.experimental("hoverActions") |
447 | } | 447 | } |
448 | pub fn status_notification(&self) -> bool { | 448 | pub fn server_status_notification(&self) -> bool { |
449 | self.experimental("statusNotification") | 449 | self.experimental("serverStatusNotification") |
450 | } | 450 | } |
451 | 451 | ||
452 | pub fn publish_diagnostics(&self) -> bool { | 452 | pub fn publish_diagnostics(&self) -> bool { |
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 8679c8599..adeb7a97e 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -23,6 +23,7 @@ use crate::{ | |||
23 | document::DocumentData, | 23 | document::DocumentData, |
24 | from_proto, | 24 | from_proto, |
25 | line_index::{LineEndings, LineIndex}, | 25 | line_index::{LineEndings, LineIndex}, |
26 | lsp_ext, | ||
26 | main_loop::Task, | 27 | main_loop::Task, |
27 | op_queue::OpQueue, | 28 | op_queue::OpQueue, |
28 | reload::SourceRootConfig, | 29 | reload::SourceRootConfig, |
@@ -32,20 +33,6 @@ use crate::{ | |||
32 | Result, | 33 | Result, |
33 | }; | 34 | }; |
34 | 35 | ||
35 | #[derive(Eq, PartialEq, Copy, Clone)] | ||
36 | pub(crate) enum Status { | ||
37 | Loading, | ||
38 | Ready { partial: bool }, | ||
39 | Invalid, | ||
40 | NeedsReload, | ||
41 | } | ||
42 | |||
43 | impl Default for Status { | ||
44 | fn default() -> Self { | ||
45 | Status::Loading | ||
46 | } | ||
47 | } | ||
48 | |||
49 | // Enforces drop order | 36 | // Enforces drop order |
50 | pub(crate) struct Handle<H, C> { | 37 | pub(crate) struct Handle<H, C> { |
51 | pub(crate) handle: H, | 38 | pub(crate) handle: H, |
@@ -67,26 +54,36 @@ pub(crate) struct GlobalState { | |||
67 | req_queue: ReqQueue, | 54 | req_queue: ReqQueue, |
68 | pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, | 55 | pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, |
69 | pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>, | 56 | pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>, |
70 | pub(crate) vfs_config_version: u32, | ||
71 | pub(crate) flycheck: Vec<FlycheckHandle>, | ||
72 | pub(crate) flycheck_sender: Sender<flycheck::Message>, | ||
73 | pub(crate) flycheck_receiver: Receiver<flycheck::Message>, | ||
74 | pub(crate) config: Arc<Config>, | 57 | pub(crate) config: Arc<Config>, |
75 | pub(crate) analysis_host: AnalysisHost, | 58 | pub(crate) analysis_host: AnalysisHost, |
76 | pub(crate) diagnostics: DiagnosticCollection, | 59 | pub(crate) diagnostics: DiagnosticCollection, |
77 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, | 60 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, |
78 | pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, | 61 | pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, |
79 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, | ||
80 | pub(crate) shutdown_requested: bool, | 62 | pub(crate) shutdown_requested: bool, |
81 | pub(crate) status: Status, | 63 | pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>, |
82 | pub(crate) source_root_config: SourceRootConfig, | 64 | pub(crate) source_root_config: SourceRootConfig, |
83 | pub(crate) proc_macro_client: Option<ProcMacroClient>, | 65 | pub(crate) proc_macro_client: Option<ProcMacroClient>, |
84 | 66 | ||
85 | pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, | 67 | pub(crate) flycheck: Vec<FlycheckHandle>, |
86 | pub(crate) fetch_workspaces_queue: OpQueue<(), ()>, | 68 | pub(crate) flycheck_sender: Sender<flycheck::Message>, |
69 | pub(crate) flycheck_receiver: Receiver<flycheck::Message>, | ||
87 | 70 | ||
71 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, | ||
72 | pub(crate) vfs_config_version: u32, | ||
73 | pub(crate) vfs_progress_config_version: u32, | ||
74 | pub(crate) vfs_progress_n_total: usize, | ||
75 | pub(crate) vfs_progress_n_done: usize, | ||
76 | |||
77 | /// For both `workspaces` and `workspace_build_data`, the field stores the | ||
78 | /// data we actually use, while the `OpQueue` stores the result of the last | ||
79 | /// fetch. | ||
80 | /// | ||
81 | /// If the fetch (partially) fails, we do not update the values. | ||
82 | pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, | ||
83 | pub(crate) fetch_workspaces_queue: OpQueue<(), Vec<anyhow::Result<ProjectWorkspace>>>, | ||
88 | pub(crate) workspace_build_data: Option<BuildDataResult>, | 84 | pub(crate) workspace_build_data: Option<BuildDataResult>, |
89 | pub(crate) fetch_build_data_queue: OpQueue<BuildDataCollector, ()>, | 85 | pub(crate) fetch_build_data_queue: |
86 | OpQueue<BuildDataCollector, Option<anyhow::Result<BuildDataResult>>>, | ||
90 | 87 | ||
91 | latest_requests: Arc<RwLock<LatestRequests>>, | 88 | latest_requests: Arc<RwLock<LatestRequests>>, |
92 | } | 89 | } |
@@ -124,25 +121,32 @@ impl GlobalState { | |||
124 | GlobalState { | 121 | GlobalState { |
125 | sender, | 122 | sender, |
126 | req_queue: ReqQueue::default(), | 123 | req_queue: ReqQueue::default(), |
127 | vfs_config_version: 0, | ||
128 | task_pool, | 124 | task_pool, |
129 | loader, | 125 | loader, |
130 | flycheck: Vec::new(), | ||
131 | flycheck_sender, | ||
132 | flycheck_receiver, | ||
133 | config: Arc::new(config), | 126 | config: Arc::new(config), |
134 | analysis_host, | 127 | analysis_host, |
135 | diagnostics: Default::default(), | 128 | diagnostics: Default::default(), |
136 | mem_docs: FxHashMap::default(), | 129 | mem_docs: FxHashMap::default(), |
137 | semantic_tokens_cache: Arc::new(Default::default()), | 130 | semantic_tokens_cache: Arc::new(Default::default()), |
138 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), | ||
139 | shutdown_requested: false, | 131 | shutdown_requested: false, |
140 | status: Status::default(), | 132 | last_reported_status: None, |
141 | source_root_config: SourceRootConfig::default(), | 133 | source_root_config: SourceRootConfig::default(), |
142 | proc_macro_client: None, | 134 | proc_macro_client: None, |
135 | |||
136 | flycheck: Vec::new(), | ||
137 | flycheck_sender, | ||
138 | flycheck_receiver, | ||
139 | |||
140 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), | ||
141 | vfs_config_version: 0, | ||
142 | vfs_progress_config_version: 0, | ||
143 | vfs_progress_n_total: 0, | ||
144 | vfs_progress_n_done: 0, | ||
145 | |||
143 | workspaces: Arc::new(Vec::new()), | 146 | workspaces: Arc::new(Vec::new()), |
144 | fetch_workspaces_queue: OpQueue::default(), | 147 | fetch_workspaces_queue: OpQueue::default(), |
145 | workspace_build_data: None, | 148 | workspace_build_data: None, |
149 | |||
146 | fetch_build_data_queue: OpQueue::default(), | 150 | fetch_build_data_queue: OpQueue::default(), |
147 | latest_requests: Default::default(), | 151 | latest_requests: Default::default(), |
148 | } | 152 | } |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 0e1fec209..81a6f22f1 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -241,26 +241,26 @@ pub struct SsrParams { | |||
241 | pub selections: Vec<lsp_types::Range>, | 241 | pub selections: Vec<lsp_types::Range>, |
242 | } | 242 | } |
243 | 243 | ||
244 | pub enum StatusNotification {} | 244 | pub enum ServerStatusNotification {} |
245 | 245 | ||
246 | #[derive(Serialize, Deserialize)] | 246 | impl Notification for ServerStatusNotification { |
247 | #[serde(rename_all = "camelCase")] | 247 | type Params = ServerStatusParams; |
248 | pub enum Status { | 248 | const METHOD: &'static str = "experimental/serverStatus"; |
249 | Loading, | ||
250 | ReadyPartial, | ||
251 | Ready, | ||
252 | NeedsReload, | ||
253 | Invalid, | ||
254 | } | 249 | } |
255 | 250 | ||
256 | #[derive(Deserialize, Serialize)] | 251 | #[derive(Deserialize, Serialize, PartialEq, Eq, Clone)] |
257 | pub struct StatusParams { | 252 | pub struct ServerStatusParams { |
258 | pub status: Status, | 253 | pub health: Health, |
254 | pub quiescent: bool, | ||
255 | pub message: Option<String>, | ||
259 | } | 256 | } |
260 | 257 | ||
261 | impl Notification for StatusNotification { | 258 | #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] |
262 | type Params = StatusParams; | 259 | #[serde(rename_all = "camelCase")] |
263 | const METHOD: &'static str = "rust-analyzer/status"; | 260 | pub enum Health { |
261 | Ok, | ||
262 | Warning, | ||
263 | Error, | ||
264 | } | 264 | } |
265 | 265 | ||
266 | pub enum CodeActionRequest {} | 266 | pub enum CodeActionRequest {} |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index e88f16cc1..a5655116b 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | //! requests/replies and notifications back to the client. | 2 | //! requests/replies and notifications back to the client. |
3 | use std::{ | 3 | use std::{ |
4 | env, fmt, | 4 | env, fmt, |
5 | sync::Arc, | ||
5 | time::{Duration, Instant}, | 6 | time::{Duration, Instant}, |
6 | }; | 7 | }; |
7 | 8 | ||
@@ -12,6 +13,7 @@ use ide::{Canceled, FileId}; | |||
12 | use ide_db::base_db::VfsPath; | 13 | use ide_db::base_db::VfsPath; |
13 | use lsp_server::{Connection, Notification, Request, Response}; | 14 | use lsp_server::{Connection, Notification, Request, Response}; |
14 | use lsp_types::notification::Notification as _; | 15 | use lsp_types::notification::Notification as _; |
16 | use project_model::BuildDataCollector; | ||
15 | use vfs::ChangeKind; | 17 | use vfs::ChangeKind; |
16 | 18 | ||
17 | use crate::{ | 19 | use crate::{ |
@@ -19,7 +21,7 @@ use crate::{ | |||
19 | dispatch::{NotificationDispatcher, RequestDispatcher}, | 21 | dispatch::{NotificationDispatcher, RequestDispatcher}, |
20 | document::DocumentData, | 22 | document::DocumentData, |
21 | from_proto, | 23 | from_proto, |
22 | global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, | 24 | global_state::{file_id_to_url, url_to_file_id, GlobalState}, |
23 | handlers, lsp_ext, | 25 | handlers, lsp_ext, |
24 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, | 26 | lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, |
25 | reload::{BuildDataProgress, ProjectWorkspaceProgress}, | 27 | reload::{BuildDataProgress, ProjectWorkspaceProgress}, |
@@ -187,7 +189,7 @@ impl GlobalState { | |||
187 | log::info!("task queue len: {}", task_queue_len); | 189 | log::info!("task queue len: {}", task_queue_len); |
188 | } | 190 | } |
189 | 191 | ||
190 | let mut new_status = self.status; | 192 | let was_quiescent = self.is_quiescent(); |
191 | match event { | 193 | match event { |
192 | Event::Lsp(msg) => match msg { | 194 | Event::Lsp(msg) => match msg { |
193 | lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, | 195 | lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, |
@@ -227,11 +229,24 @@ impl GlobalState { | |||
227 | (Progress::Report, Some(msg)) | 229 | (Progress::Report, Some(msg)) |
228 | } | 230 | } |
229 | ProjectWorkspaceProgress::End(workspaces) => { | 231 | ProjectWorkspaceProgress::End(workspaces) => { |
230 | self.fetch_workspaces_completed(); | 232 | self.fetch_workspaces_completed(workspaces); |
231 | self.switch_workspaces(workspaces, None); | 233 | |
234 | let old = Arc::clone(&self.workspaces); | ||
235 | self.switch_workspaces(); | ||
236 | let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces); | ||
237 | |||
238 | if self.config.run_build_scripts() && workspaces_updated { | ||
239 | let mut collector = BuildDataCollector::default(); | ||
240 | for ws in self.workspaces.iter() { | ||
241 | ws.collect_build_data_configs(&mut collector); | ||
242 | } | ||
243 | self.fetch_build_data_request(collector) | ||
244 | } | ||
245 | |||
232 | (Progress::End, None) | 246 | (Progress::End, None) |
233 | } | 247 | } |
234 | }; | 248 | }; |
249 | |||
235 | self.report_progress("fetching", state, msg, None); | 250 | self.report_progress("fetching", state, msg, None); |
236 | } | 251 | } |
237 | Task::FetchBuildData(progress) => { | 252 | Task::FetchBuildData(progress) => { |
@@ -240,19 +255,21 @@ impl GlobalState { | |||
240 | BuildDataProgress::Report(msg) => { | 255 | BuildDataProgress::Report(msg) => { |
241 | (Some(Progress::Report), Some(msg)) | 256 | (Some(Progress::Report), Some(msg)) |
242 | } | 257 | } |
243 | BuildDataProgress::End(collector) => { | 258 | BuildDataProgress::End(build_data_result) => { |
244 | self.fetch_build_data_completed(); | 259 | self.fetch_build_data_completed(build_data_result); |
245 | let workspaces = | 260 | |
246 | (*self.workspaces).clone().into_iter().map(Ok).collect(); | 261 | self.switch_workspaces(); |
247 | self.switch_workspaces(workspaces, Some(collector)); | 262 | |
248 | (Some(Progress::End), None) | 263 | (Some(Progress::End), None) |
249 | } | 264 | } |
250 | }; | 265 | }; |
266 | |||
251 | if let Some(state) = state { | 267 | if let Some(state) = state { |
252 | self.report_progress("loading", state, msg, None); | 268 | self.report_progress("loading", state, msg, None); |
253 | } | 269 | } |
254 | } | 270 | } |
255 | } | 271 | } |
272 | |||
256 | // Coalesce multiple task events into one loop turn | 273 | // Coalesce multiple task events into one loop turn |
257 | task = match self.task_pool.receiver.try_recv() { | 274 | task = match self.task_pool.receiver.try_recv() { |
258 | Ok(task) => task, | 275 | Ok(task) => task, |
@@ -298,30 +315,25 @@ impl GlobalState { | |||
298 | } | 315 | } |
299 | vfs::loader::Message::Progress { n_total, n_done, config_version } => { | 316 | vfs::loader::Message::Progress { n_total, n_done, config_version } => { |
300 | always!(config_version <= self.vfs_config_version); | 317 | always!(config_version <= self.vfs_config_version); |
301 | if n_total == 0 { | 318 | |
302 | new_status = Status::Invalid; | 319 | self.vfs_progress_config_version = config_version; |
320 | self.vfs_progress_n_total = n_total; | ||
321 | self.vfs_progress_n_done = n_done; | ||
322 | |||
323 | let state = if n_done == 0 { | ||
324 | Progress::Begin | ||
325 | } else if n_done < n_total { | ||
326 | Progress::Report | ||
303 | } else { | 327 | } else { |
304 | let state = if n_done == 0 { | 328 | assert_eq!(n_done, n_total); |
305 | new_status = Status::Loading; | 329 | Progress::End |
306 | Progress::Begin | 330 | }; |
307 | } else if n_done < n_total { | 331 | self.report_progress( |
308 | Progress::Report | 332 | "roots scanned", |
309 | } else { | 333 | state, |
310 | assert_eq!(n_done, n_total); | 334 | Some(format!("{}/{}", n_done, n_total)), |
311 | new_status = Status::Ready { | 335 | Some(Progress::fraction(n_done, n_total)), |
312 | partial: self.config.run_build_scripts() | 336 | ) |
313 | && self.workspace_build_data.is_none() | ||
314 | || config_version < self.vfs_config_version, | ||
315 | }; | ||
316 | Progress::End | ||
317 | }; | ||
318 | self.report_progress( | ||
319 | "roots scanned", | ||
320 | state, | ||
321 | Some(format!("{}/{}", n_done, n_total)), | ||
322 | Some(Progress::fraction(n_done, n_total)), | ||
323 | ) | ||
324 | } | ||
325 | } | 337 | } |
326 | } | 338 | } |
327 | // Coalesce many VFS event into a single loop turn | 339 | // Coalesce many VFS event into a single loop turn |
@@ -397,18 +409,14 @@ impl GlobalState { | |||
397 | } | 409 | } |
398 | 410 | ||
399 | let state_changed = self.process_changes(); | 411 | let state_changed = self.process_changes(); |
400 | let prev_status = self.status; | 412 | |
401 | if prev_status != new_status { | 413 | if self.is_quiescent() && !was_quiescent { |
402 | self.transition(new_status); | ||
403 | } | ||
404 | let is_ready = matches!(self.status, Status::Ready { .. }); | ||
405 | if prev_status == Status::Loading && is_ready { | ||
406 | for flycheck in &self.flycheck { | 414 | for flycheck in &self.flycheck { |
407 | flycheck.update(); | 415 | flycheck.update(); |
408 | } | 416 | } |
409 | } | 417 | } |
410 | 418 | ||
411 | if is_ready && (state_changed || prev_status == Status::Loading) { | 419 | if self.is_quiescent() && (!was_quiescent || state_changed) { |
412 | self.update_file_notifications_on_threadpool(); | 420 | self.update_file_notifications_on_threadpool(); |
413 | 421 | ||
414 | // Refresh semantic tokens if the client supports it. | 422 | // Refresh semantic tokens if the client supports it. |
@@ -437,9 +445,13 @@ impl GlobalState { | |||
437 | } | 445 | } |
438 | } | 446 | } |
439 | 447 | ||
440 | self.fetch_workspaces_if_needed(); | 448 | if self.config.cargo_autoreload() { |
449 | self.fetch_workspaces_if_needed(); | ||
450 | } | ||
441 | self.fetch_build_data_if_needed(); | 451 | self.fetch_build_data_if_needed(); |
442 | 452 | ||
453 | self.report_new_status_if_needed(); | ||
454 | |||
443 | let loop_duration = loop_start.elapsed(); | 455 | let loop_duration = loop_start.elapsed(); |
444 | if loop_duration > Duration::from_millis(100) { | 456 | if loop_duration > Duration::from_millis(100) { |
445 | log::warn!("overly long loop turn: {:?}", loop_duration); | 457 | log::warn!("overly long loop turn: {:?}", loop_duration); |
@@ -466,7 +478,8 @@ impl GlobalState { | |||
466 | return Ok(()); | 478 | return Ok(()); |
467 | } | 479 | } |
468 | 480 | ||
469 | if self.status == Status::Loading && req.method != "shutdown" { | 481 | // Avoid flashing a bunch of unresolved references during initial load. |
482 | if self.workspaces.is_empty() && !self.is_quiescent() { | ||
470 | self.respond(lsp_server::Response::new_err( | 483 | self.respond(lsp_server::Response::new_err( |
471 | req.id, | 484 | req.id, |
472 | // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) | 485 | // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) |
@@ -477,7 +490,11 @@ impl GlobalState { | |||
477 | } | 490 | } |
478 | 491 | ||
479 | RequestDispatcher { req: Some(req), global_state: self } | 492 | RequestDispatcher { req: Some(req), global_state: self } |
480 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))? | 493 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| { |
494 | s.fetch_workspaces_request(); | ||
495 | s.fetch_workspaces_if_needed(); | ||
496 | Ok(()) | ||
497 | })? | ||
481 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? | 498 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? |
482 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? | 499 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? |
483 | .on_sync::<lsp_types::request::Shutdown>(|s, ()| { | 500 | .on_sync::<lsp_types::request::Shutdown>(|s, ()| { |
diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs index f71b718bc..1d612a933 100644 --- a/crates/rust-analyzer/src/op_queue.rs +++ b/crates/rust-analyzer/src/op_queue.rs | |||
@@ -2,27 +2,27 @@ | |||
2 | //! at a time. | 2 | //! at a time. |
3 | 3 | ||
4 | pub(crate) struct OpQueue<Args, Output> { | 4 | pub(crate) struct OpQueue<Args, Output> { |
5 | op_scheduled: Option<Args>, | 5 | op_requested: Option<Args>, |
6 | op_in_progress: bool, | 6 | op_in_progress: bool, |
7 | last_op_result: Output, | 7 | last_op_result: Output, |
8 | } | 8 | } |
9 | 9 | ||
10 | impl<Args, Output: Default> Default for OpQueue<Args, Output> { | 10 | impl<Args, Output: Default> Default for OpQueue<Args, Output> { |
11 | fn default() -> Self { | 11 | fn default() -> Self { |
12 | Self { op_scheduled: None, op_in_progress: false, last_op_result: Default::default() } | 12 | Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() } |
13 | } | 13 | } |
14 | } | 14 | } |
15 | 15 | ||
16 | impl<Args, Output> OpQueue<Args, Output> { | 16 | impl<Args, Output> OpQueue<Args, Output> { |
17 | pub(crate) fn request_op(&mut self, data: Args) { | 17 | pub(crate) fn request_op(&mut self, data: Args) { |
18 | self.op_scheduled = Some(data); | 18 | self.op_requested = Some(data); |
19 | } | 19 | } |
20 | pub(crate) fn should_start_op(&mut self) -> Option<Args> { | 20 | pub(crate) fn should_start_op(&mut self) -> Option<Args> { |
21 | if self.op_in_progress { | 21 | if self.op_in_progress { |
22 | return None; | 22 | return None; |
23 | } | 23 | } |
24 | self.op_in_progress = self.op_scheduled.is_some(); | 24 | self.op_in_progress = self.op_requested.is_some(); |
25 | self.op_scheduled.take() | 25 | self.op_requested.take() |
26 | } | 26 | } |
27 | pub(crate) fn op_completed(&mut self, result: Output) { | 27 | pub(crate) fn op_completed(&mut self, result: Output) { |
28 | assert!(self.op_in_progress); | 28 | assert!(self.op_in_progress); |
@@ -34,4 +34,10 @@ impl<Args, Output> OpQueue<Args, Output> { | |||
34 | pub(crate) fn last_op_result(&self) -> &Output { | 34 | pub(crate) fn last_op_result(&self) -> &Output { |
35 | &self.last_op_result | 35 | &self.last_op_result |
36 | } | 36 | } |
37 | pub(crate) fn op_in_progress(&self) -> bool { | ||
38 | self.op_in_progress | ||
39 | } | ||
40 | pub(crate) fn op_requested(&self) -> bool { | ||
41 | self.op_requested.is_some() | ||
42 | } | ||
37 | } | 43 | } |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index d12f891bb..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 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | config::{Config, FilesWatcher, LinkedProject}, | 11 | config::{Config, FilesWatcher, LinkedProject}, |
12 | global_state::{GlobalState, Status}, | 12 | global_state::GlobalState, |
13 | lsp_ext, | 13 | lsp_ext, |
14 | main_loop::Task, | 14 | main_loop::Task, |
15 | }; | 15 | }; |
16 | use lsp_ext::StatusParams; | ||
17 | 16 | ||
18 | #[derive(Debug)] | 17 | #[derive(Debug)] |
19 | pub(crate) enum ProjectWorkspaceProgress { | 18 | pub(crate) enum ProjectWorkspaceProgress { |
@@ -30,6 +29,13 @@ pub(crate) enum BuildDataProgress { | |||
30 | } | 29 | } |
31 | 30 | ||
32 | impl GlobalState { | 31 | impl GlobalState { |
32 | pub(crate) fn is_quiescent(&self) -> bool { | ||
33 | !(self.fetch_workspaces_queue.op_in_progress() | ||
34 | || self.fetch_build_data_queue.op_in_progress() | ||
35 | || self.vfs_progress_config_version < self.vfs_config_version | ||
36 | || self.vfs_progress_n_done < self.vfs_progress_n_total) | ||
37 | } | ||
38 | |||
33 | pub(crate) fn update_configuration(&mut self, config: Config) { | 39 | pub(crate) fn update_configuration(&mut self, config: Config) { |
34 | let _p = profile::span("GlobalState::update_configuration"); | 40 | let _p = profile::span("GlobalState::update_configuration"); |
35 | let old_config = mem::replace(&mut self.config, Arc::new(config)); | 41 | let old_config = mem::replace(&mut self.config, Arc::new(config)); |
@@ -46,25 +52,17 @@ impl GlobalState { | |||
46 | if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { | 52 | if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { |
47 | return; | 53 | return; |
48 | } | 54 | } |
49 | match self.status { | ||
50 | Status::Loading | Status::NeedsReload => return, | ||
51 | Status::Ready { .. } | Status::Invalid => (), | ||
52 | } | ||
53 | log::info!( | 55 | log::info!( |
54 | "Reloading workspace because of the following changes: {}", | 56 | "Requesting workspace reload because of the following changes: {}", |
55 | itertools::join( | 57 | itertools::join( |
56 | changes | 58 | changes |
57 | .iter() | 59 | .iter() |
58 | .filter(|(path, kind)| is_interesting(path, *kind)) | 60 | .filter(|(path, kind)| is_interesting(path, *kind)) |
59 | .map(|(path, kind)| format!("{}/{:?}", path.display(), kind)), | 61 | .map(|(path, kind)| format!("{}: {:?}", path.display(), kind)), |
60 | ", " | 62 | ", " |
61 | ) | 63 | ) |
62 | ); | 64 | ); |
63 | if self.config.cargo_autoreload() { | 65 | self.fetch_workspaces_request(); |
64 | self.fetch_workspaces_request(); | ||
65 | } else { | ||
66 | self.transition(Status::NeedsReload); | ||
67 | } | ||
68 | 66 | ||
69 | fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool { | 67 | fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool { |
70 | const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; | 68 | const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; |
@@ -101,46 +99,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)] | ||
181 | pub struct JodChild(pub process::Child); | 182 | pub struct JodChild(pub process::Child); |
182 | 183 | ||
183 | impl ops::Deref for JodChild { | 184 | impl ops::Deref for JodChild { |
@@ -200,6 +201,13 @@ impl Drop for JodChild { | |||
200 | } | 201 | } |
201 | } | 202 | } |
202 | 203 | ||
204 | impl 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)] |
204 | mod tests { | 212 | mod 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" | |||
14 | fst = "0.4" | 14 | fst = "0.4" |
15 | 15 | ||
16 | paths = { path = "../paths", version = "0.0.0" } | 16 | paths = { path = "../paths", version = "0.0.0" } |
17 | indexmap = "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. |
4 | use rustc_hash::FxHashMap; | 4 | use std::hash::BuildHasherDefault; |
5 | |||
6 | use indexmap::IndexSet; | ||
7 | use rustc_hash::FxHasher; | ||
5 | 8 | ||
6 | use crate::{FileId, VfsPath}; | 9 | use crate::{FileId, VfsPath}; |
7 | 10 | ||
8 | /// Structure to map between [`VfsPath`] and [`FileId`]. | 11 | /// Structure to map between [`VfsPath`] and [`FileId`]. |
9 | #[derive(Default)] | ||
10 | pub(crate) struct PathInterner { | 12 | pub(crate) struct PathInterner { |
11 | map: FxHashMap<VfsPath, FileId>, | 13 | map: IndexSet<VfsPath, BuildHasherDefault<FxHasher>>, |
12 | vec: Vec<VfsPath>, | 14 | } |
15 | |||
16 | impl Default for PathInterner { | ||
17 | fn default() -> Self { | ||
18 | Self { map: IndexSet::default() } | ||
19 | } | ||
13 | } | 20 | } |
14 | 21 | ||
15 | impl PathInterner { | 22 | impl 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 | } |