aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs15
-rw-r--r--crates/ra_hir_ty/src/db.rs44
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs308
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs (renamed from crates/ra_hir_ty/src/expr.rs)291
-rw-r--r--crates/ra_hir_ty/src/diagnostics/match_check.rs (renamed from crates/ra_hir_ty/src/_match.rs)1678
-rw-r--r--crates/ra_hir_ty/src/diagnostics/unsafe_check.rs (renamed from crates/ra_hir_ty/src/unsafe_validation.rs)77
-rw-r--r--crates/ra_hir_ty/src/display.rs47
-rw-r--r--crates/ra_hir_ty/src/infer.rs37
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs25
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs55
-rw-r--r--crates/ra_hir_ty/src/lib.rs107
-rw-r--r--crates/ra_hir_ty/src/lower.rs61
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs302
-rw-r--r--crates/ra_hir_ty/src/test_db.rs125
-rw-r--r--crates/ra_hir_ty/src/tests.rs419
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs1386
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs620
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs1150
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs315
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs1102
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs1137
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs3398
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs3460
-rw-r--r--crates/ra_hir_ty/src/traits.rs80
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs371
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs205
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/interner.rs29
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs233
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs28
-rw-r--r--crates/ra_hir_ty/src/utils.rs32
30 files changed, 8270 insertions, 8867 deletions
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index 1b0f84c5c..c727012c6 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -37,7 +37,7 @@ pub(crate) fn deref(
37 ty: InEnvironment<&Canonical<Ty>>, 37 ty: InEnvironment<&Canonical<Ty>>,
38) -> Option<Canonical<Ty>> { 38) -> Option<Canonical<Ty>> {
39 if let Some(derefed) = ty.value.value.builtin_deref() { 39 if let Some(derefed) = ty.value.value.builtin_deref() {
40 Some(Canonical { value: derefed, num_vars: ty.value.num_vars }) 40 Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() })
41 } else { 41 } else {
42 deref_by_trait(db, krate, ty) 42 deref_by_trait(db, krate, ty)
43 } 43 }
@@ -68,8 +68,8 @@ fn deref_by_trait(
68 68
69 // Check that the type implements Deref at all 69 // Check that the type implements Deref at all
70 let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; 70 let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
71 let implements_goal = super::Canonical { 71 let implements_goal = Canonical {
72 num_vars: ty.value.num_vars, 72 kinds: ty.value.kinds.clone(),
73 value: InEnvironment { 73 value: InEnvironment {
74 value: Obligation::Trait(trait_ref), 74 value: Obligation::Trait(trait_ref),
75 environment: ty.environment.clone(), 75 environment: ty.environment.clone(),
@@ -81,7 +81,7 @@ fn deref_by_trait(
81 81
82 // Now do the assoc type projection 82 // Now do the assoc type projection
83 let projection = super::traits::ProjectionPredicate { 83 let projection = super::traits::ProjectionPredicate {
84 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)), 84 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())),
85 projection_ty: super::ProjectionTy { associated_ty: target, parameters }, 85 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
86 }; 86 };
87 87
@@ -89,7 +89,8 @@ fn deref_by_trait(
89 89
90 let in_env = InEnvironment { value: obligation, environment: ty.environment }; 90 let in_env = InEnvironment { value: obligation, environment: ty.environment };
91 91
92 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; 92 let canonical =
93 Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General)));
93 94
94 let solution = db.trait_solve(krate, canonical)?; 95 let solution = db.trait_solve(krate, canonical)?;
95 96
@@ -110,7 +111,7 @@ fn deref_by_trait(
110 // assumptions will be broken. We would need to properly introduce 111 // assumptions will be broken. We would need to properly introduce
111 // new variables in that case 112 // new variables in that case
112 113
113 for i in 1..vars.0.num_vars { 114 for i in 1..vars.0.kinds.len() {
114 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 115 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
115 { 116 {
116 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); 117 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
@@ -119,7 +120,7 @@ fn deref_by_trait(
119 } 120 }
120 Some(Canonical { 121 Some(Canonical {
121 value: vars.0.value[vars.0.value.len() - 1].clone(), 122 value: vars.0.value[vars.0.value.len() - 1].clone(),
122 num_vars: vars.0.num_vars, 123 kinds: vars.0.kinds.clone(),
123 }) 124 })
124 } 125 }
125 Solution::Ambig(_) => { 126 Solution::Ambig(_) => {
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index cad553273..c773adc67 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -3,23 +3,22 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TypeParamId, 6 db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId,
7 VariantId, 7 TypeParamId, VariantId,
8}; 8};
9use ra_arena::map::ArenaMap; 9use ra_arena::map::ArenaMap;
10use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; 10use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
11use ra_prof::profile; 11use ra_prof::profile;
12 12
13use crate::{ 13use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::{InherentImpls, TraitImpls},
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::chalk,
16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, 16 Binders, CallableDefId, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, 17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
18}; 18};
19use hir_expand::name::Name; 19use hir_expand::name::Name;
20 20
21#[salsa::query_group(HirDatabaseStorage)] 21#[salsa::query_group(HirDatabaseStorage)]
22#[salsa::requires(salsa::Database)]
23pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { 22pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
24 #[salsa::invoke(infer_wait)] 23 #[salsa::invoke(infer_wait)]
25 #[salsa::transparent] 24 #[salsa::transparent]
@@ -46,7 +45,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
46 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; 45 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
47 46
48 #[salsa::invoke(crate::callable_item_sig)] 47 #[salsa::invoke(crate::callable_item_sig)]
49 fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; 48 fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
50 49
51 #[salsa::invoke(crate::lower::return_type_impl_traits)] 50 #[salsa::invoke(crate::lower::return_type_impl_traits)]
52 fn return_type_impl_traits( 51 fn return_type_impl_traits(
@@ -67,25 +66,24 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
67 #[salsa::invoke(crate::lower::generic_defaults_query)] 66 #[salsa::invoke(crate::lower::generic_defaults_query)]
68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; 67 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
69 68
70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] 69 #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 70 fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
72 71
73 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)] 72 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
74 fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>; 73 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
74
75 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
76 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
75 77
76 // Interned IDs for Chalk integration 78 // Interned IDs for Chalk integration
77 #[salsa::interned] 79 #[salsa::interned]
78 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; 80 fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
79 #[salsa::interned]
80 fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId;
81 #[salsa::interned] 81 #[salsa::interned]
82 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; 82 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
83 #[salsa::interned] 83 #[salsa::interned]
84 fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId; 84 fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId;
85 #[salsa::interned] 85 #[salsa::interned]
86 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; 86 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> ClosureId;
87 #[salsa::interned]
88 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
89 87
90 #[salsa::invoke(chalk::associated_ty_data_query)] 88 #[salsa::invoke(chalk::associated_ty_data_query)]
91 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>; 89 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>;
@@ -149,3 +147,13 @@ impl_intern_key!(GlobalTypeParamId);
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
150pub struct InternedOpaqueTyId(salsa::InternId); 148pub struct InternedOpaqueTyId(salsa::InternId);
151impl_intern_key!(InternedOpaqueTyId); 149impl_intern_key!(InternedOpaqueTyId);
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
152pub struct ClosureId(salsa::InternId);
153impl_intern_key!(ClosureId);
154
155/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
156/// we have different IDs for struct and enum variant constructors.
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
158pub struct InternedCallableDefId(salsa::InternId);
159impl_intern_key!(InternedCallableDefId);
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index a59efb347..f210c305a 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -1,18 +1,35 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2mod expr;
3mod match_check;
4mod unsafe_check;
2 5
3use std::any::Any; 6use std::any::Any;
4 7
8use hir_def::DefWithBodyId;
9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
5use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; 10use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
11use ra_prof::profile;
6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 12use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
7use stdx::format_to; 13use stdx::format_to;
8 14
9pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path}; 15use crate::db::HirDatabase;
10pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 16
17pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields};
18
19pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
20 let _p = profile("validate_body");
21 let infer = db.infer(owner);
22 infer.add_diagnostics(db, owner, sink);
23 let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink);
24 validator.validate_body(db);
25 let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink);
26 validator.validate_body(db);
27}
11 28
12#[derive(Debug)] 29#[derive(Debug)]
13pub struct NoSuchField { 30pub struct NoSuchField {
14 pub file: HirFileId, 31 pub file: HirFileId,
15 pub field: AstPtr<ast::RecordField>, 32 pub field: AstPtr<ast::RecordExprField>,
16} 33}
17 34
18impl Diagnostic for NoSuchField { 35impl Diagnostic for NoSuchField {
@@ -30,19 +47,19 @@ impl Diagnostic for NoSuchField {
30} 47}
31 48
32impl AstDiagnostic for NoSuchField { 49impl AstDiagnostic for NoSuchField {
33 type AST = ast::RecordField; 50 type AST = ast::RecordExprField;
34 51
35 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 52 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
36 let root = db.parse_or_expand(self.source().file_id).unwrap(); 53 let root = db.parse_or_expand(self.source().file_id).unwrap();
37 let node = self.source().value.to_node(&root); 54 let node = self.source().value.to_node(&root);
38 ast::RecordField::cast(node).unwrap() 55 ast::RecordExprField::cast(node).unwrap()
39 } 56 }
40} 57}
41 58
42#[derive(Debug)] 59#[derive(Debug)]
43pub struct MissingFields { 60pub struct MissingFields {
44 pub file: HirFileId, 61 pub file: HirFileId,
45 pub field_list: AstPtr<ast::RecordFieldList>, 62 pub field_list: AstPtr<ast::RecordExprFieldList>,
46 pub missed_fields: Vec<Name>, 63 pub missed_fields: Vec<Name>,
47} 64}
48 65
@@ -63,12 +80,12 @@ impl Diagnostic for MissingFields {
63} 80}
64 81
65impl AstDiagnostic for MissingFields { 82impl AstDiagnostic for MissingFields {
66 type AST = ast::RecordFieldList; 83 type AST = ast::RecordExprFieldList;
67 84
68 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 85 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
69 let root = db.parse_or_expand(self.source().file_id).unwrap(); 86 let root = db.parse_or_expand(self.source().file_id).unwrap();
70 let node = self.source().value.to_node(&root); 87 let node = self.source().value.to_node(&root);
71 ast::RecordFieldList::cast(node).unwrap() 88 ast::RecordExprFieldList::cast(node).unwrap()
72 } 89 }
73} 90}
74 91
@@ -135,7 +152,7 @@ impl Diagnostic for MissingOkInTailExpr {
135impl AstDiagnostic for MissingOkInTailExpr { 152impl AstDiagnostic for MissingOkInTailExpr {
136 type AST = ast::Expr; 153 type AST = ast::Expr;
137 154
138 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 155 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
139 let root = db.parse_or_expand(self.file).unwrap(); 156 let root = db.parse_or_expand(self.file).unwrap();
140 let node = self.source().value.to_node(&root); 157 let node = self.source().value.to_node(&root);
141 ast::Expr::cast(node).unwrap() 158 ast::Expr::cast(node).unwrap()
@@ -163,7 +180,7 @@ impl Diagnostic for BreakOutsideOfLoop {
163impl AstDiagnostic for BreakOutsideOfLoop { 180impl AstDiagnostic for BreakOutsideOfLoop {
164 type AST = ast::Expr; 181 type AST = ast::Expr;
165 182
166 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 183 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
167 let root = db.parse_or_expand(self.file).unwrap(); 184 let root = db.parse_or_expand(self.file).unwrap();
168 let node = self.source().value.to_node(&root); 185 let node = self.source().value.to_node(&root);
169 ast::Expr::cast(node).unwrap() 186 ast::Expr::cast(node).unwrap()
@@ -191,9 +208,274 @@ impl Diagnostic for MissingUnsafe {
191impl AstDiagnostic for MissingUnsafe { 208impl AstDiagnostic for MissingUnsafe {
192 type AST = ast::Expr; 209 type AST = ast::Expr;
193 210
194 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 211 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
195 let root = db.parse_or_expand(self.source().file_id).unwrap(); 212 let root = db.parse_or_expand(self.source().file_id).unwrap();
196 let node = self.source().value.to_node(&root); 213 let node = self.source().value.to_node(&root);
197 ast::Expr::cast(node).unwrap() 214 ast::Expr::cast(node).unwrap()
198 } 215 }
199} 216}
217
218#[derive(Debug)]
219pub struct MismatchedArgCount {
220 pub file: HirFileId,
221 pub call_expr: AstPtr<ast::Expr>,
222 pub expected: usize,
223 pub found: usize,
224}
225
226impl Diagnostic for MismatchedArgCount {
227 fn message(&self) -> String {
228 let s = if self.expected == 1 { "" } else { "s" };
229 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
230 }
231 fn source(&self) -> InFile<SyntaxNodePtr> {
232 InFile { file_id: self.file, value: self.call_expr.clone().into() }
233 }
234 fn as_any(&self) -> &(dyn Any + Send + 'static) {
235 self
236 }
237 fn is_experimental(&self) -> bool {
238 true
239 }
240}
241
242impl AstDiagnostic for MismatchedArgCount {
243 type AST = ast::CallExpr;
244 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
245 let root = db.parse_or_expand(self.source().file_id).unwrap();
246 let node = self.source().value.to_node(&root);
247 ast::CallExpr::cast(node).unwrap()
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
254 use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder};
255 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
256 use ra_syntax::{TextRange, TextSize};
257 use rustc_hash::FxHashMap;
258
259 use crate::{diagnostics::validate_body, test_db::TestDB};
260
261 impl TestDB {
262 fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
263 let crate_graph = self.crate_graph();
264 for krate in crate_graph.iter() {
265 let crate_def_map = self.crate_def_map(krate);
266
267 let mut fns = Vec::new();
268 for (module_id, _) in crate_def_map.modules.iter() {
269 for decl in crate_def_map[module_id].scope.declarations() {
270 if let ModuleDefId::FunctionId(f) = decl {
271 fns.push(f)
272 }
273 }
274
275 for impl_id in crate_def_map[module_id].scope.impls() {
276 let impl_data = self.impl_data(impl_id);
277 for item in impl_data.items.iter() {
278 if let AssocItemId::FunctionId(f) = item {
279 fns.push(*f)
280 }
281 }
282 }
283 }
284
285 for f in fns {
286 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
287 validate_body(self, f.into(), &mut sink);
288 }
289 }
290 }
291 }
292
293 pub(crate) fn check_diagnostics(ra_fixture: &str) {
294 let db = TestDB::with_files(ra_fixture);
295 let annotations = db.extract_annotations();
296
297 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
298 db.diagnostics(|d| {
299 // FXIME: macros...
300 let file_id = d.source().file_id.original_file(&db);
301 let range = d.syntax_node(&db).text_range();
302 let message = d.message().to_owned();
303 actual.entry(file_id).or_default().push((range, message));
304 });
305
306 for (file_id, diags) in actual.iter_mut() {
307 diags.sort_by_key(|it| it.0.start());
308 let text = db.file_text(*file_id);
309 // For multiline spans, place them on line start
310 for (range, content) in diags {
311 if text[*range].contains('\n') {
312 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
313 *content = format!("... {}", content);
314 }
315 }
316 }
317
318 assert_eq!(annotations, actual);
319 }
320
321 #[test]
322 fn no_such_field_diagnostics() {
323 check_diagnostics(
324 r#"
325struct S { foo: i32, bar: () }
326impl S {
327 fn new() -> S {
328 S {
329 //^... Missing structure fields:
330 //| - bar
331 foo: 92,
332 baz: 62,
333 //^^^^^^^ no such field
334 }
335 }
336}
337"#,
338 );
339 }
340 #[test]
341 fn no_such_field_with_feature_flag_diagnostics() {
342 check_diagnostics(
343 r#"
344//- /lib.rs crate:foo cfg:feature=foo
345struct MyStruct {
346 my_val: usize,
347 #[cfg(feature = "foo")]
348 bar: bool,
349}
350
351impl MyStruct {
352 #[cfg(feature = "foo")]
353 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
354 Self { my_val, bar }
355 }
356 #[cfg(not(feature = "foo"))]
357 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
358 Self { my_val }
359 }
360}
361"#,
362 );
363 }
364
365 #[test]
366 fn no_such_field_enum_with_feature_flag_diagnostics() {
367 check_diagnostics(
368 r#"
369//- /lib.rs crate:foo cfg:feature=foo
370enum Foo {
371 #[cfg(not(feature = "foo"))]
372 Buz,
373 #[cfg(feature = "foo")]
374 Bar,
375 Baz
376}
377
378fn test_fn(f: Foo) {
379 match f {
380 Foo::Bar => {},
381 Foo::Baz => {},
382 }
383}
384"#,
385 );
386 }
387
388 #[test]
389 fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
390 check_diagnostics(
391 r#"
392//- /lib.rs crate:foo cfg:feature=foo
393struct S {
394 #[cfg(feature = "foo")]
395 foo: u32,
396 #[cfg(not(feature = "foo"))]
397 bar: u32,
398}
399
400impl S {
401 #[cfg(feature = "foo")]
402 fn new(foo: u32) -> Self {
403 Self { foo }
404 }
405 #[cfg(not(feature = "foo"))]
406 fn new(bar: u32) -> Self {
407 Self { bar }
408 }
409 fn new2(bar: u32) -> Self {
410 #[cfg(feature = "foo")]
411 { Self { foo: bar } }
412 #[cfg(not(feature = "foo"))]
413 { Self { bar } }
414 }
415 fn new2(val: u32) -> Self {
416 Self {
417 #[cfg(feature = "foo")]
418 foo: val,
419 #[cfg(not(feature = "foo"))]
420 bar: val,
421 }
422 }
423}
424"#,
425 );
426 }
427
428 #[test]
429 fn no_such_field_with_type_macro() {
430 check_diagnostics(
431 r#"
432macro_rules! Type { () => { u32 }; }
433struct Foo { bar: Type![] }
434
435impl Foo {
436 fn new() -> Self {
437 Foo { bar: 0 }
438 }
439}
440"#,
441 );
442 }
443
444 #[test]
445 fn missing_record_pat_field_diagnostic() {
446 check_diagnostics(
447 r#"
448struct S { foo: i32, bar: () }
449fn baz(s: S) {
450 let S { foo: _ } = s;
451 //^^^^^^^^^^ Missing structure fields:
452 // | - bar
453}
454"#,
455 );
456 }
457
458 #[test]
459 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
460 check_diagnostics(
461 r"
462struct S { foo: i32, bar: () }
463fn baz(s: S) -> i32 {
464 match s {
465 S { foo, .. } => foo,
466 }
467}
468",
469 )
470 }
471
472 #[test]
473 fn break_outside_of_loop() {
474 check_diagnostics(
475 r#"
476fn foo() { break; }
477 //^^^^^ break outside of loop
478"#,
479 );
480 }
481}
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 7db928dde..f0e0f2988 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -2,17 +2,19 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId}; 5use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId};
6use hir_expand::diagnostics::DiagnosticSink; 6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::{ast, AstPtr}; 7use ra_syntax::{ast, AstPtr};
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use crate::{ 10use crate::{
11 db::HirDatabase, 11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields}, 12 diagnostics::{
13 match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields,
15 },
13 utils::variant_data, 16 utils::variant_data,
14 ApplicationTy, InferenceResult, Ty, TypeCtor, 17 ApplicationTy, InferenceResult, Ty, TypeCtor,
15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
16}; 18};
17 19
18pub use hir_def::{ 20pub use hir_def::{
@@ -24,26 +26,27 @@ pub use hir_def::{
24 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, 26 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
25 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, 27 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp,
26 }, 28 },
27 LocalFieldId, VariantId, 29 src::HasSource,
30 LocalFieldId, Lookup, VariantId,
28}; 31};
29 32
30pub struct ExprValidator<'a, 'b: 'a> { 33pub(super) struct ExprValidator<'a, 'b: 'a> {
31 func: FunctionId, 34 owner: DefWithBodyId,
32 infer: Arc<InferenceResult>, 35 infer: Arc<InferenceResult>,
33 sink: &'a mut DiagnosticSink<'b>, 36 sink: &'a mut DiagnosticSink<'b>,
34} 37}
35 38
36impl<'a, 'b> ExprValidator<'a, 'b> { 39impl<'a, 'b> ExprValidator<'a, 'b> {
37 pub fn new( 40 pub(super) fn new(
38 func: FunctionId, 41 owner: DefWithBodyId,
39 infer: Arc<InferenceResult>, 42 infer: Arc<InferenceResult>,
40 sink: &'a mut DiagnosticSink<'b>, 43 sink: &'a mut DiagnosticSink<'b>,
41 ) -> ExprValidator<'a, 'b> { 44 ) -> ExprValidator<'a, 'b> {
42 ExprValidator { func, infer, sink } 45 ExprValidator { owner, infer, sink }
43 } 46 }
44 47
45 pub fn validate_body(&mut self, db: &dyn HirDatabase) { 48 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
46 let body = db.body(self.func.into()); 49 let body = db.body(self.owner.into());
47 50
48 for (id, expr) in body.exprs.iter() { 51 for (id, expr) in body.exprs.iter() {
49 if let Some((variant_def, missed_fields, true)) = 52 if let Some((variant_def, missed_fields, true)) =
@@ -56,8 +59,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
56 missed_fields, 59 missed_fields,
57 ); 60 );
58 } 61 }
59 if let Expr::Match { expr, arms } = expr { 62
60 self.validate_match(id, *expr, arms, db, self.infer.clone()); 63 match expr {
64 Expr::Match { expr, arms } => {
65 self.validate_match(id, *expr, arms, db, self.infer.clone());
66 }
67 Expr::Call { .. } | Expr::MethodCall { .. } => {
68 self.validate_call(db, id, expr);
69 }
70 _ => {}
61 } 71 }
62 } 72 }
63 for (id, pat) in body.pats.iter() { 73 for (id, pat) in body.pats.iter() {
@@ -86,12 +96,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
86 missed_fields: Vec<LocalFieldId>, 96 missed_fields: Vec<LocalFieldId>,
87 ) { 97 ) {
88 // XXX: only look at source_map if we do have missing fields 98 // XXX: only look at source_map if we do have missing fields
89 let (_, source_map) = db.body_with_source_map(self.func.into()); 99 let (_, source_map) = db.body_with_source_map(self.owner.into());
90 100
91 if let Ok(source_ptr) = source_map.expr_syntax(id) { 101 if let Ok(source_ptr) = source_map.expr_syntax(id) {
92 let root = source_ptr.file_syntax(db.upcast()); 102 let root = source_ptr.file_syntax(db.upcast());
93 if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) { 103 if let ast::Expr::RecordExpr(record_lit) = &source_ptr.value.to_node(&root) {
94 if let Some(field_list) = record_lit.record_field_list() { 104 if let Some(field_list) = record_lit.record_expr_field_list() {
95 let variant_data = variant_data(db.upcast(), variant_def); 105 let variant_data = variant_data(db.upcast(), variant_def);
96 let missed_fields = missed_fields 106 let missed_fields = missed_fields
97 .into_iter() 107 .into_iter()
@@ -115,7 +125,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
115 missed_fields: Vec<LocalFieldId>, 125 missed_fields: Vec<LocalFieldId>,
116 ) { 126 ) {
117 // XXX: only look at source_map if we do have missing fields 127 // XXX: only look at source_map if we do have missing fields
118 let (_, source_map) = db.body_with_source_map(self.func.into()); 128 let (_, source_map) = db.body_with_source_map(self.owner.into());
119 129
120 if let Ok(source_ptr) = source_map.pat_syntax(id) { 130 if let Ok(source_ptr) = source_map.pat_syntax(id) {
121 if let Some(expr) = source_ptr.value.as_ref().left() { 131 if let Some(expr) = source_ptr.value.as_ref().left() {
@@ -138,6 +148,65 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
138 } 148 }
139 } 149 }
140 150
151 fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> {
152 // Check that the number of arguments matches the number of parameters.
153
154 // FIXME: Due to shortcomings in the current type system implementation, only emit this
155 // diagnostic if there are no type mismatches in the containing function.
156 if self.infer.type_mismatches.iter().next().is_some() {
157 return Some(());
158 }
159
160 let is_method_call = matches!(expr, Expr::MethodCall { .. });
161 let (sig, args) = match expr {
162 Expr::Call { callee, args } => {
163 let callee = &self.infer.type_of_expr[*callee];
164 let sig = callee.callable_sig(db)?;
165 (sig, args.clone())
166 }
167 Expr::MethodCall { receiver, args, .. } => {
168 let mut args = args.clone();
169 args.insert(0, *receiver);
170
171 // FIXME: note that we erase information about substs here. This
172 // is not right, but, luckily, doesn't matter as we care only
173 // about the number of params
174 let callee = self.infer.method_resolution(call_id)?;
175 let sig = db.callable_item_signature(callee.into()).value;
176
177 (sig, args)
178 }
179 _ => return None,
180 };
181
182 if sig.is_varargs {
183 return None;
184 }
185
186 let params = sig.params();
187
188 let mut param_count = params.len();
189 let mut arg_count = args.len();
190
191 if arg_count != param_count {
192 let (_, source_map) = db.body_with_source_map(self.owner.into());
193 if let Ok(source_ptr) = source_map.expr_syntax(call_id) {
194 if is_method_call {
195 param_count -= 1;
196 arg_count -= 1;
197 }
198 self.sink.push(MismatchedArgCount {
199 file: source_ptr.file_id,
200 call_expr: source_ptr.value,
201 expected: param_count,
202 found: arg_count,
203 });
204 }
205 }
206
207 None
208 }
209
141 fn validate_match( 210 fn validate_match(
142 &mut self, 211 &mut self,
143 id: ExprId, 212 id: ExprId,
@@ -147,7 +216,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
147 infer: Arc<InferenceResult>, 216 infer: Arc<InferenceResult>,
148 ) { 217 ) {
149 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) = 218 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
150 db.body_with_source_map(self.func.into()); 219 db.body_with_source_map(self.owner.into());
151 220
152 let match_expr_ty = match infer.type_of_expr.get(match_expr) { 221 let match_expr_ty = match infer.type_of_expr.get(match_expr) {
153 Some(ty) => ty, 222 Some(ty) => ty,
@@ -228,7 +297,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
228 297
229 let core_result_path = path![core::result::Result]; 298 let core_result_path = path![core::result::Result];
230 299
231 let resolver = self.func.resolver(db.upcast()); 300 let resolver = self.owner.resolver(db.upcast());
232 let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { 301 let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) {
233 Some(it) => it, 302 Some(it) => it,
234 _ => return, 303 _ => return,
@@ -243,7 +312,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
243 }; 312 };
244 313
245 if params.len() == 2 && params[0] == mismatch.actual { 314 if params.len() == 2 && params[0] == mismatch.actual {
246 let (_, source_map) = db.body_with_source_map(self.func.into()); 315 let (_, source_map) = db.body_with_source_map(self.owner.into());
247 316
248 if let Ok(source_ptr) = source_map.expr_syntax(id) { 317 if let Ok(source_ptr) = source_map.expr_syntax(id) {
249 self.sink 318 self.sink
@@ -312,3 +381,185 @@ pub fn record_pattern_missing_fields(
312 } 381 }
313 Some((variant_def, missed_fields, exhaustive)) 382 Some((variant_def, missed_fields, exhaustive))
314} 383}
384
385#[cfg(test)]
386mod tests {
387 use crate::diagnostics::tests::check_diagnostics;
388
389 #[test]
390 fn simple_free_fn_zero() {
391 check_diagnostics(
392 r#"
393fn zero() {}
394fn f() { zero(1); }
395 //^^^^^^^ Expected 0 arguments, found 1
396"#,
397 );
398
399 check_diagnostics(
400 r#"
401fn zero() {}
402fn f() { zero(); }
403"#,
404 );
405 }
406
407 #[test]
408 fn simple_free_fn_one() {
409 check_diagnostics(
410 r#"
411fn one(arg: u8) {}
412fn f() { one(); }
413 //^^^^^ Expected 1 argument, found 0
414"#,
415 );
416
417 check_diagnostics(
418 r#"
419fn one(arg: u8) {}
420fn f() { one(1); }
421"#,
422 );
423 }
424
425 #[test]
426 fn method_as_fn() {
427 check_diagnostics(
428 r#"
429struct S;
430impl S { fn method(&self) {} }
431
432fn f() {
433 S::method();
434} //^^^^^^^^^^^ Expected 1 argument, found 0
435"#,
436 );
437
438 check_diagnostics(
439 r#"
440struct S;
441impl S { fn method(&self) {} }
442
443fn f() {
444 S::method(&S);
445 S.method();
446}
447"#,
448 );
449 }
450
451 #[test]
452 fn method_with_arg() {
453 check_diagnostics(
454 r#"
455struct S;
456impl S { fn method(&self, arg: u8) {} }
457
458 fn f() {
459 S.method();
460 } //^^^^^^^^^^ Expected 1 argument, found 0
461 "#,
462 );
463
464 check_diagnostics(
465 r#"
466struct S;
467impl S { fn method(&self, arg: u8) {} }
468
469fn f() {
470 S::method(&S, 0);
471 S.method(1);
472}
473"#,
474 );
475 }
476
477 #[test]
478 fn tuple_struct() {
479 check_diagnostics(
480 r#"
481struct Tup(u8, u16);
482fn f() {
483 Tup(0);
484} //^^^^^^ Expected 2 arguments, found 1
485"#,
486 )
487 }
488
489 #[test]
490 fn enum_variant() {
491 check_diagnostics(
492 r#"
493enum En { Variant(u8, u16), }
494fn f() {
495 En::Variant(0);
496} //^^^^^^^^^^^^^^ Expected 2 arguments, found 1
497"#,
498 )
499 }
500
501 #[test]
502 fn enum_variant_type_macro() {
503 check_diagnostics(
504 r#"
505macro_rules! Type {
506 () => { u32 };
507}
508enum Foo {
509 Bar(Type![])
510}
511impl Foo {
512 fn new() {
513 Foo::Bar(0);
514 Foo::Bar(0, 1);
515 //^^^^^^^^^^^^^^ Expected 1 argument, found 2
516 Foo::Bar();
517 //^^^^^^^^^^ Expected 1 argument, found 0
518 }
519}
520 "#,
521 );
522 }
523
524 #[test]
525 fn varargs() {
526 check_diagnostics(
527 r#"
528extern "C" {
529 fn fixed(fixed: u8);
530 fn varargs(fixed: u8, ...);
531 fn varargs2(...);
532}
533
534fn f() {
535 unsafe {
536 fixed(0);
537 fixed(0, 1);
538 //^^^^^^^^^^^ Expected 1 argument, found 2
539 varargs(0);
540 varargs(0, 1);
541 varargs2();
542 varargs2(0);
543 varargs2(0, 1);
544 }
545}
546 "#,
547 )
548 }
549
550 #[test]
551 fn arg_count_lambda() {
552 check_diagnostics(
553 r#"
554fn main() {
555 let f = |()| ();
556 f();
557 //^^^ Expected 1 argument, found 0
558 f(());
559 f((), ());
560 //^^^^^^^^^ Expected 1 argument, found 2
561}
562"#,
563 )
564 }
565}
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs
index 5495ce284..507edcb7d 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs
@@ -41,9 +41,9 @@
41//! ```ignore 41//! ```ignore
42//! // x: (Option<bool>, Result<()>) 42//! // x: (Option<bool>, Result<()>)
43//! match x { 43//! match x {
44//! (Some(true), _) => {} 44//! (Some(true), _) => (),
45//! (None, Err(())) => {} 45//! (None, Err(())) => (),
46//! (None, Err(_)) => {} 46//! (None, Err(_)) => (),
47//! } 47//! }
48//! ``` 48//! ```
49//! 49//!
@@ -218,15 +218,16 @@
218//! ``` 218//! ```
219use std::sync::Arc; 219use std::sync::Arc;
220 220
221use smallvec::{smallvec, SmallVec}; 221use hir_def::{
222 222 adt::VariantData,
223use crate::{ 223 body::Body,
224 db::HirDatabase, 224 expr::{Expr, Literal, Pat, PatId},
225 expr::{Body, Expr, Literal, Pat, PatId}, 225 AdtId, EnumVariantId, VariantId,
226 ApplicationTy, InferenceResult, Ty, TypeCtor,
227}; 226};
228use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId};
229use ra_arena::Idx; 227use ra_arena::Idx;
228use smallvec::{smallvec, SmallVec};
229
230use crate::{db::HirDatabase, ApplicationTy, InferenceResult, Ty, TypeCtor};
230 231
231#[derive(Debug, Clone, Copy)] 232#[derive(Debug, Clone, Copy)]
232/// Either a pattern from the source code being analyzed, represented as 233/// Either a pattern from the source code being analyzed, represented as
@@ -271,7 +272,7 @@ impl From<&PatId> for PatIdOrWild {
271} 272}
272 273
273#[derive(Debug, Clone, Copy, PartialEq)] 274#[derive(Debug, Clone, Copy, PartialEq)]
274pub enum MatchCheckErr { 275pub(super) enum MatchCheckErr {
275 NotImplemented, 276 NotImplemented,
276 MalformedMatchArm, 277 MalformedMatchArm,
277 /// Used when type inference cannot resolve the type of 278 /// Used when type inference cannot resolve the type of
@@ -286,21 +287,21 @@ pub enum MatchCheckErr {
286/// 287///
287/// The `std::result::Result` type is used here rather than a custom enum 288/// The `std::result::Result` type is used here rather than a custom enum
288/// to allow the use of `?`. 289/// to allow the use of `?`.
289pub type MatchCheckResult<T> = Result<T, MatchCheckErr>; 290pub(super) type MatchCheckResult<T> = Result<T, MatchCheckErr>;
290 291
291#[derive(Debug)] 292#[derive(Debug)]
292/// A row in a Matrix. 293/// A row in a Matrix.
293/// 294///
294/// This type is modeled from the struct of the same name in `rustc`. 295/// This type is modeled from the struct of the same name in `rustc`.
295pub(crate) struct PatStack(PatStackInner); 296pub(super) struct PatStack(PatStackInner);
296type PatStackInner = SmallVec<[PatIdOrWild; 2]>; 297type PatStackInner = SmallVec<[PatIdOrWild; 2]>;
297 298
298impl PatStack { 299impl PatStack {
299 pub(crate) fn from_pattern(pat_id: PatId) -> PatStack { 300 pub(super) fn from_pattern(pat_id: PatId) -> PatStack {
300 Self(smallvec!(pat_id.into())) 301 Self(smallvec!(pat_id.into()))
301 } 302 }
302 303
303 pub(crate) fn from_wild() -> PatStack { 304 pub(super) fn from_wild() -> PatStack {
304 Self(smallvec!(PatIdOrWild::Wild)) 305 Self(smallvec!(PatIdOrWild::Wild))
305 } 306 }
306 307
@@ -509,14 +510,14 @@ impl PatStack {
509/// A collection of PatStack. 510/// A collection of PatStack.
510/// 511///
511/// This type is modeled from the struct of the same name in `rustc`. 512/// This type is modeled from the struct of the same name in `rustc`.
512pub(crate) struct Matrix(Vec<PatStack>); 513pub(super) struct Matrix(Vec<PatStack>);
513 514
514impl Matrix { 515impl Matrix {
515 pub(crate) fn empty() -> Self { 516 pub(super) fn empty() -> Self {
516 Self(vec![]) 517 Self(vec![])
517 } 518 }
518 519
519 pub(crate) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) { 520 pub(super) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) {
520 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { 521 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) {
521 // Or patterns are expanded here 522 // Or patterns are expanded here
522 for pat_id in pat_ids { 523 for pat_id in pat_ids {
@@ -578,16 +579,16 @@ impl Matrix {
578/// not matched by an prior match arms. 579/// not matched by an prior match arms.
579/// 580///
580/// We may eventually need an `Unknown` variant here. 581/// We may eventually need an `Unknown` variant here.
581pub enum Usefulness { 582pub(super) enum Usefulness {
582 Useful, 583 Useful,
583 NotUseful, 584 NotUseful,
584} 585}
585 586
586pub struct MatchCheckCtx<'a> { 587pub(super) struct MatchCheckCtx<'a> {
587 pub match_expr: Idx<Expr>, 588 pub(super) match_expr: Idx<Expr>,
588 pub body: Arc<Body>, 589 pub(super) body: Arc<Body>,
589 pub infer: Arc<InferenceResult>, 590 pub(super) infer: Arc<InferenceResult>,
590 pub db: &'a dyn HirDatabase, 591 pub(super) db: &'a dyn HirDatabase,
591} 592}
592 593
593/// Given a set of patterns `matrix`, and pattern to consider `v`, determines 594/// Given a set of patterns `matrix`, and pattern to consider `v`, determines
@@ -598,7 +599,7 @@ pub struct MatchCheckCtx<'a> {
598/// expected that you have already type checked the match arms. All patterns in 599/// expected that you have already type checked the match arms. All patterns in
599/// matrix should be the same type as v, as well as they should all be the same 600/// matrix should be the same type as v, as well as they should all be the same
600/// type as the match expression. 601/// type as the match expression.
601pub(crate) fn is_useful( 602pub(super) fn is_useful(
602 cx: &MatchCheckCtx, 603 cx: &MatchCheckCtx,
603 matrix: &Matrix, 604 matrix: &Matrix,
604 v: &PatStack, 605 v: &PatStack,
@@ -836,685 +837,251 @@ fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: Enum
836 837
837#[cfg(test)] 838#[cfg(test)]
838mod tests { 839mod tests {
839 pub(super) use insta::assert_snapshot; 840 use crate::diagnostics::tests::check_diagnostics;
840 pub(super) use ra_db::fixture::WithFixture;
841
842 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB};
843
844 pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String {
845 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0
846 }
847
848 pub(super) fn check_diagnostic(ra_fixture: &str) {
849 let diagnostic_count =
850 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1;
851
852 assert_eq!(1, diagnostic_count, "no diagnostic reported");
853 }
854
855 pub(super) fn check_no_diagnostic(ra_fixture: &str) {
856 let (s, diagnostic_count) =
857 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>();
858
859 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one: {}", s);
860 }
861
862 #[test]
863 fn empty_tuple_no_arms_diagnostic_message() {
864 assert_snapshot!(
865 check_diagnostic_message(r"
866 fn test_fn() {
867 match () {
868 }
869 }
870 "),
871 @"\"()\": Missing match arm\n"
872 );
873 }
874
875 #[test]
876 fn empty_tuple_no_arms() {
877 check_diagnostic(
878 r"
879 fn test_fn() {
880 match () {
881 }
882 }
883 ",
884 );
885 }
886
887 #[test]
888 fn empty_tuple_wild() {
889 check_no_diagnostic(
890 r"
891 fn test_fn() {
892 match () {
893 _ => {}
894 }
895 }
896 ",
897 );
898 }
899
900 #[test]
901 fn empty_tuple_no_diagnostic() {
902 check_no_diagnostic(
903 r"
904 fn test_fn() {
905 match () {
906 () => {}
907 }
908 }
909 ",
910 );
911 }
912
913 #[test]
914 fn tuple_of_empty_tuple_no_arms() {
915 check_diagnostic(
916 r"
917 fn test_fn() {
918 match (()) {
919 }
920 }
921 ",
922 );
923 }
924
925 #[test]
926 fn tuple_of_empty_tuple_no_diagnostic() {
927 check_no_diagnostic(
928 r"
929 fn test_fn() {
930 match (()) {
931 (()) => {}
932 }
933 }
934 ",
935 );
936 }
937 841
938 #[test] 842 #[test]
939 fn tuple_of_two_empty_tuple_no_arms() { 843 fn empty_tuple() {
940 check_diagnostic( 844 check_diagnostics(
941 r" 845 r#"
942 fn test_fn() { 846fn main() {
943 match ((), ()) { 847 match () { }
944 } 848 //^^ Missing match arm
945 } 849 match (()) { }
946 ", 850 //^^^^ Missing match arm
947 );
948 }
949 851
950 #[test] 852 match () { _ => (), }
951 fn tuple_of_two_empty_tuple_no_diagnostic() { 853 match () { () => (), }
952 check_no_diagnostic( 854 match (()) { (()) => (), }
953 r" 855}
954 fn test_fn() { 856"#,
955 match ((), ()) {
956 ((), ()) => {}
957 }
958 }
959 ",
960 );
961 }
962
963 #[test]
964 fn bool_no_arms() {
965 check_diagnostic(
966 r"
967 fn test_fn() {
968 match false {
969 }
970 }
971 ",
972 );
973 }
974
975 #[test]
976 fn bool_missing_arm() {
977 check_diagnostic(
978 r"
979 fn test_fn() {
980 match false {
981 true => {}
982 }
983 }
984 ",
985 );
986 }
987
988 #[test]
989 fn bool_no_diagnostic() {
990 check_no_diagnostic(
991 r"
992 fn test_fn() {
993 match false {
994 true => {}
995 false => {}
996 }
997 }
998 ",
999 );
1000 }
1001
1002 #[test]
1003 fn tuple_of_bools_no_arms() {
1004 check_diagnostic(
1005 r"
1006 fn test_fn() {
1007 match (false, true) {
1008 }
1009 }
1010 ",
1011 );
1012 }
1013
1014 #[test]
1015 fn tuple_of_bools_missing_arms() {
1016 check_diagnostic(
1017 r"
1018 fn test_fn() {
1019 match (false, true) {
1020 (true, true) => {},
1021 }
1022 }
1023 ",
1024 );
1025 }
1026
1027 #[test]
1028 fn tuple_of_bools_missing_arm() {
1029 check_diagnostic(
1030 r"
1031 fn test_fn() {
1032 match (false, true) {
1033 (false, true) => {},
1034 (false, false) => {},
1035 (true, false) => {},
1036 }
1037 }
1038 ",
1039 );
1040 }
1041
1042 #[test]
1043 fn tuple_of_bools_with_wilds() {
1044 check_no_diagnostic(
1045 r"
1046 fn test_fn() {
1047 match (false, true) {
1048 (false, _) => {},
1049 (true, false) => {},
1050 (_, true) => {},
1051 }
1052 }
1053 ",
1054 ); 857 );
1055 } 858 }
1056 859
1057 #[test] 860 #[test]
1058 fn tuple_of_bools_no_diagnostic() { 861 fn tuple_of_two_empty_tuple() {
1059 check_no_diagnostic( 862 check_diagnostics(
1060 r" 863 r#"
1061 fn test_fn() { 864fn main() {
1062 match (false, true) { 865 match ((), ()) { }
1063 (true, true) => {}, 866 //^^^^^^^^ Missing match arm
1064 (true, false) => {},
1065 (false, true) => {},
1066 (false, false) => {},
1067 }
1068 }
1069 ",
1070 );
1071 }
1072 867
1073 #[test] 868 match ((), ()) { ((), ()) => (), }
1074 fn tuple_of_bools_binding_missing_arms() { 869}
1075 check_diagnostic( 870"#,
1076 r" 871 );
1077 fn test_fn() { 872 }
1078 match (false, true) { 873
1079 (true, _x) => {}, 874 #[test]
1080 } 875 fn boolean() {
1081 } 876 check_diagnostics(
1082 ", 877 r#"
1083 ); 878fn test_main() {
1084 } 879 match false { }
1085 880 //^^^^^ Missing match arm
1086 #[test] 881 match false { true => (), }
1087 fn tuple_of_bools_binding_no_diagnostic() { 882 //^^^^^ Missing match arm
1088 check_no_diagnostic( 883 match (false, true) {}
1089 r" 884 //^^^^^^^^^^^^^ Missing match arm
1090 fn test_fn() { 885 match (false, true) { (true, true) => (), }
1091 match (false, true) { 886 //^^^^^^^^^^^^^ Missing match arm
1092 (true, _x) => {}, 887 match (false, true) {
1093 (false, true) => {}, 888 //^^^^^^^^^^^^^ Missing match arm
1094 (false, false) => {}, 889 (false, true) => (),
1095 } 890 (false, false) => (),
1096 } 891 (true, false) => (),
1097 ", 892 }
893 match (false, true) { (true, _x) => (), }
894 //^^^^^^^^^^^^^ Missing match arm
895
896 match false { true => (), false => (), }
897 match (false, true) {
898 (false, _) => (),
899 (true, false) => (),
900 (_, true) => (),
901 }
902 match (false, true) {
903 (true, true) => (),
904 (true, false) => (),
905 (false, true) => (),
906 (false, false) => (),
907 }
908 match (false, true) {
909 (true, _x) => (),
910 (false, true) => (),
911 (false, false) => (),
912 }
913 match (false, true, false) {
914 (false, ..) => (),
915 (true, ..) => (),
916 }
917 match (false, true, false) {
918 (.., false) => (),
919 (.., true) => (),
920 }
921 match (false, true, false) { (..) => (), }
922}
923"#,
1098 ); 924 );
1099 } 925 }
1100 926
1101 #[test] 927 #[test]
1102 fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { 928 fn tuple_of_tuple_and_bools() {
1103 check_no_diagnostic( 929 check_diagnostics(
1104 r" 930 r#"
1105 fn test_fn() { 931fn main() {
1106 match (false, true, false) { 932 match (false, ((), false)) {}
1107 (false, ..) => {}, 933 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1108 (true, ..) => {}, 934 match (false, ((), false)) { (true, ((), true)) => (), }
1109 } 935 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1110 } 936 match (false, ((), false)) { (true, _) => (), }
1111 ", 937 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1112 );
1113 }
1114 938
1115 #[test] 939 match (false, ((), false)) {
1116 fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { 940 (true, ((), true)) => (),
1117 check_no_diagnostic( 941 (true, ((), false)) => (),
1118 r" 942 (false, ((), true)) => (),
1119 fn test_fn() { 943 (false, ((), false)) => (),
1120 match (false, true, false) {
1121 (.., false) => {},
1122 (.., true) => {},
1123 }
1124 }
1125 ",
1126 );
1127 } 944 }
1128 945 match (false, ((), false)) {
1129 #[test] 946 (true, ((), true)) => (),
1130 fn tuple_of_bools_with_ellipsis_no_diagnostic() { 947 (true, ((), false)) => (),
1131 check_no_diagnostic( 948 (false, _) => (),
1132 r"
1133 fn test_fn() {
1134 match (false, true, false) {
1135 (..) => {},
1136 }
1137 }
1138 ",
1139 );
1140 } 949 }
1141 950}
1142 #[test] 951"#,
1143 fn tuple_of_tuple_and_bools_no_arms() {
1144 check_diagnostic(
1145 r"
1146 fn test_fn() {
1147 match (false, ((), false)) {
1148 }
1149 }
1150 ",
1151 ); 952 );
1152 } 953 }
1153 954
1154 #[test] 955 #[test]
1155 fn tuple_of_tuple_and_bools_missing_arms() { 956 fn enums() {
1156 check_diagnostic( 957 check_diagnostics(
1157 r" 958 r#"
1158 fn test_fn() { 959enum Either { A, B, }
1159 match (false, ((), false)) {
1160 (true, ((), true)) => {},
1161 }
1162 }
1163 ",
1164 );
1165 }
1166 960
1167 #[test] 961fn main() {
1168 fn tuple_of_tuple_and_bools_no_diagnostic() { 962 match Either::A { }
1169 check_no_diagnostic( 963 //^^^^^^^^^ Missing match arm
1170 r" 964 match Either::B { Either::A => (), }
1171 fn test_fn() { 965 //^^^^^^^^^ Missing match arm
1172 match (false, ((), false)) {
1173 (true, ((), true)) => {},
1174 (true, ((), false)) => {},
1175 (false, ((), true)) => {},
1176 (false, ((), false)) => {},
1177 }
1178 }
1179 ",
1180 );
1181 }
1182 966
1183 #[test] 967 match &Either::B {
1184 fn tuple_of_tuple_and_bools_wildcard_missing_arms() { 968 //^^^^^^^^^^ Missing match arm
1185 check_diagnostic( 969 Either::A => (),
1186 r"
1187 fn test_fn() {
1188 match (false, ((), false)) {
1189 (true, _) => {},
1190 }
1191 }
1192 ",
1193 );
1194 } 970 }
1195 971
1196 #[test] 972 match Either::B {
1197 fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { 973 Either::A => (), Either::B => (),
1198 check_no_diagnostic(
1199 r"
1200 fn test_fn() {
1201 match (false, ((), false)) {
1202 (true, ((), true)) => {},
1203 (true, ((), false)) => {},
1204 (false, _) => {},
1205 }
1206 }
1207 ",
1208 );
1209 } 974 }
1210 975 match &Either::B {
1211 #[test] 976 Either::A => (), Either::B => (),
1212 fn enum_no_arms() {
1213 check_diagnostic(
1214 r"
1215 enum Either {
1216 A,
1217 B,
1218 }
1219 fn test_fn() {
1220 match Either::A {
1221 }
1222 }
1223 ",
1224 );
1225 } 977 }
1226 978}
1227 #[test] 979"#,
1228 fn enum_missing_arms() {
1229 check_diagnostic(
1230 r"
1231 enum Either {
1232 A,
1233 B,
1234 }
1235 fn test_fn() {
1236 match Either::B {
1237 Either::A => {},
1238 }
1239 }
1240 ",
1241 ); 980 );
1242 } 981 }
1243 982
1244 #[test] 983 #[test]
1245 fn enum_no_diagnostic() { 984 fn enum_containing_bool() {
1246 check_no_diagnostic( 985 check_diagnostics(
1247 r" 986 r#"
1248 enum Either { 987enum Either { A(bool), B }
1249 A,
1250 B,
1251 }
1252 fn test_fn() {
1253 match Either::B {
1254 Either::A => {},
1255 Either::B => {},
1256 }
1257 }
1258 ",
1259 );
1260 }
1261 988
1262 #[test] 989fn main() {
1263 fn enum_ref_missing_arms() { 990 match Either::B { }
1264 check_diagnostic( 991 //^^^^^^^^^ Missing match arm
1265 r" 992 match Either::B {
1266 enum Either { 993 //^^^^^^^^^ Missing match arm
1267 A, 994 Either::A(true) => (), Either::B => ()
1268 B,
1269 }
1270 fn test_fn() {
1271 match &Either::B {
1272 Either::A => {},
1273 }
1274 }
1275 ",
1276 );
1277 } 995 }
1278 996
1279 #[test] 997 match Either::B {
1280 fn enum_ref_no_diagnostic() { 998 Either::A(true) => (),
1281 check_no_diagnostic( 999 Either::A(false) => (),
1282 r" 1000 Either::B => (),
1283 enum Either {
1284 A,
1285 B,
1286 }
1287 fn test_fn() {
1288 match &Either::B {
1289 Either::A => {},
1290 Either::B => {},
1291 }
1292 }
1293 ",
1294 );
1295 } 1001 }
1296 1002 match Either::B {
1297 #[test] 1003 Either::B => (),
1298 fn enum_containing_bool_no_arms() { 1004 _ => (),
1299 check_diagnostic(
1300 r"
1301 enum Either {
1302 A(bool),
1303 B,
1304 }
1305 fn test_fn() {
1306 match Either::B {
1307 }
1308 }
1309 ",
1310 );
1311 } 1005 }
1312 1006 match Either::B {
1313 #[test] 1007 Either::A(_) => (),
1314 fn enum_containing_bool_missing_arms() { 1008 Either::B => (),
1315 check_diagnostic(
1316 r"
1317 enum Either {
1318 A(bool),
1319 B,
1320 }
1321 fn test_fn() {
1322 match Either::B {
1323 Either::A(true) => (),
1324 Either::B => (),
1325 }
1326 }
1327 ",
1328 );
1329 } 1009 }
1330 1010
1331 #[test] 1011}
1332 fn enum_containing_bool_no_diagnostic() { 1012 "#,
1333 check_no_diagnostic(
1334 r"
1335 enum Either {
1336 A(bool),
1337 B,
1338 }
1339 fn test_fn() {
1340 match Either::B {
1341 Either::A(true) => (),
1342 Either::A(false) => (),
1343 Either::B => (),
1344 }
1345 }
1346 ",
1347 ); 1013 );
1348 } 1014 }
1349 1015
1350 #[test] 1016 #[test]
1351 fn enum_containing_bool_with_wild_no_diagnostic() { 1017 fn enum_different_sizes() {
1352 check_no_diagnostic( 1018 check_diagnostics(
1353 r" 1019 r#"
1354 enum Either { 1020enum Either { A(bool), B(bool, bool) }
1355 A(bool),
1356 B,
1357 }
1358 fn test_fn() {
1359 match Either::B {
1360 Either::B => (),
1361 _ => (),
1362 }
1363 }
1364 ",
1365 );
1366 }
1367 1021
1368 #[test] 1022fn main() {
1369 fn enum_containing_bool_with_wild_2_no_diagnostic() { 1023 match Either::A(false) {
1370 check_no_diagnostic( 1024 //^^^^^^^^^^^^^^^^ Missing match arm
1371 r" 1025 Either::A(_) => (),
1372 enum Either { 1026 Either::B(false, _) => (),
1373 A(bool),
1374 B,
1375 }
1376 fn test_fn() {
1377 match Either::B {
1378 Either::A(_) => (),
1379 Either::B => (),
1380 }
1381 }
1382 ",
1383 );
1384 } 1027 }
1385 1028
1386 #[test] 1029 match Either::A(false) {
1387 fn enum_different_sizes_missing_arms() { 1030 Either::A(_) => (),
1388 check_diagnostic( 1031 Either::B(true, _) => (),
1389 r" 1032 Either::B(false, _) => (),
1390 enum Either {
1391 A(bool),
1392 B(bool, bool),
1393 }
1394 fn test_fn() {
1395 match Either::A(false) {
1396 Either::A(_) => (),
1397 Either::B(false, _) => (),
1398 }
1399 }
1400 ",
1401 );
1402 } 1033 }
1403 1034 match Either::A(false) {
1404 #[test] 1035 Either::A(true) | Either::A(false) => (),
1405 fn enum_different_sizes_no_diagnostic() { 1036 Either::B(true, _) => (),
1406 check_no_diagnostic( 1037 Either::B(false, _) => (),
1407 r"
1408 enum Either {
1409 A(bool),
1410 B(bool, bool),
1411 }
1412 fn test_fn() {
1413 match Either::A(false) {
1414 Either::A(_) => (),
1415 Either::B(true, _) => (),
1416 Either::B(false, _) => (),
1417 }
1418 }
1419 ",
1420 );
1421 } 1038 }
1422 1039}
1423 #[test] 1040"#,
1424 fn or_no_diagnostic() {
1425 check_no_diagnostic(
1426 r"
1427 enum Either {
1428 A(bool),
1429 B(bool, bool),
1430 }
1431 fn test_fn() {
1432 match Either::A(false) {
1433 Either::A(true) | Either::A(false) => (),
1434 Either::B(true, _) => (),
1435 Either::B(false, _) => (),
1436 }
1437 }
1438 ",
1439 ); 1041 );
1440 } 1042 }
1441 1043
1442 #[test] 1044 #[test]
1443 fn tuple_of_enum_no_diagnostic() { 1045 fn tuple_of_enum_no_diagnostic() {
1444 check_no_diagnostic( 1046 check_diagnostics(
1445 r" 1047 r#"
1446 enum Either { 1048enum Either { A(bool), B(bool, bool) }
1447 A(bool), 1049enum Either2 { C, D }
1448 B(bool, bool), 1050
1449 } 1051fn main() {
1450 enum Either2 { 1052 match (Either::A(false), Either2::C) {
1451 C, 1053 (Either::A(true), _) | (Either::A(false), _) => (),
1452 D, 1054 (Either::B(true, _), Either2::C) => (),
1453 } 1055 (Either::B(false, _), Either2::C) => (),
1454 fn test_fn() { 1056 (Either::B(_, _), Either2::D) => (),
1455 match (Either::A(false), Either2::C) {
1456 (Either::A(true), _) | (Either::A(false), _) => (),
1457 (Either::B(true, _), Either2::C) => (),
1458 (Either::B(false, _), Either2::C) => (),
1459 (Either::B(_, _), Either2::D) => (),
1460 }
1461 }
1462 ",
1463 );
1464 }
1465
1466 #[test]
1467 fn mismatched_types() {
1468 // Match statements with arms that don't match the
1469 // expression pattern do not fire this diagnostic.
1470 check_no_diagnostic(
1471 r"
1472 enum Either {
1473 A,
1474 B,
1475 }
1476 enum Either2 {
1477 C,
1478 D,
1479 }
1480 fn test_fn() {
1481 match Either::A {
1482 Either2::C => (),
1483 Either2::D => (),
1484 }
1485 }
1486 ",
1487 );
1488 } 1057 }
1489 1058}
1490 #[test] 1059"#,
1491 fn mismatched_types_with_different_arity() {
1492 // Match statements with arms that don't match the
1493 // expression pattern do not fire this diagnostic.
1494 check_no_diagnostic(
1495 r"
1496 fn test_fn() {
1497 match (true, false) {
1498 (true, false, true) => (),
1499 (true) => (),
1500 }
1501 }
1502 ",
1503 ); 1060 );
1504 } 1061 }
1505 1062
1506 #[test] 1063 #[test]
1507 fn malformed_match_arm_tuple_missing_pattern() { 1064 fn mismatched_types() {
1508 // Match statements with arms that don't match the 1065 // Match statements with arms that don't match the
1509 // expression pattern do not fire this diagnostic. 1066 // expression pattern do not fire this diagnostic.
1510 check_no_diagnostic( 1067 check_diagnostics(
1511 r" 1068 r#"
1512 fn test_fn() { 1069enum Either { A, B }
1513 match (0) { 1070enum Either2 { C, D }
1514 () => (), 1071
1515 } 1072fn main() {
1516 } 1073 match Either::A {
1517 ", 1074 Either2::C => (),
1075 Either2::D => (),
1076 }
1077 match (true, false) {
1078 (true, false, true) => (),
1079 (true) => (),
1080 }
1081 match (0) { () => () }
1082 match Unresolved::Bar { Unresolved::Baz => () }
1083}
1084 "#,
1518 ); 1085 );
1519 } 1086 }
1520 1087
@@ -1522,636 +1089,333 @@ mod tests {
1522 fn malformed_match_arm_tuple_enum_missing_pattern() { 1089 fn malformed_match_arm_tuple_enum_missing_pattern() {
1523 // We are testing to be sure we don't panic here when the match 1090 // We are testing to be sure we don't panic here when the match
1524 // arm `Either::B` is missing its pattern. 1091 // arm `Either::B` is missing its pattern.
1525 check_no_diagnostic( 1092 check_diagnostics(
1526 r" 1093 r#"
1527 enum Either { 1094enum Either { A, B(u32) }
1528 A,
1529 B(u32),
1530 }
1531 fn test_fn() {
1532 match Either::A {
1533 Either::A => (),
1534 Either::B() => (),
1535 }
1536 }
1537 ",
1538 );
1539 }
1540 1095
1541 #[test] 1096fn main() {
1542 fn enum_not_in_scope() { 1097 match Either::A {
1543 // The enum is not in scope so we don't perform exhaustiveness 1098 Either::A => (),
1544 // checking, but we want to be sure we don't panic here (and 1099 Either::B() => (),
1545 // we don't create a diagnostic). 1100 }
1546 check_no_diagnostic( 1101}
1547 r" 1102"#,
1548 fn test_fn() {
1549 match Foo::Bar {
1550 Foo::Baz => (),
1551 }
1552 }
1553 ",
1554 ); 1103 );
1555 } 1104 }
1556 1105
1557 #[test] 1106 #[test]
1558 fn expr_diverges() { 1107 fn expr_diverges() {
1559 check_no_diagnostic( 1108 check_diagnostics(
1560 r" 1109 r#"
1561 enum Either { 1110enum Either { A, B }
1562 A,
1563 B,
1564 }
1565 fn test_fn() {
1566 match loop {} {
1567 Either::A => (),
1568 Either::B => (),
1569 }
1570 }
1571 ",
1572 );
1573 }
1574 1111
1575 #[test] 1112fn main() {
1576 fn expr_loop_with_break() { 1113 match loop {} {
1577 check_no_diagnostic( 1114 Either::A => (),
1578 r" 1115 Either::B => (),
1579 enum Either { 1116 }
1580 A, 1117 match loop {} {
1581 B, 1118 Either::A => (),
1582 } 1119 }
1583 fn test_fn() { 1120 match loop { break Foo::A } {
1584 match loop { break Foo::A } { 1121 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1585 Either::A => (), 1122 Either::A => (),
1586 Either::B => (), 1123 }
1587 } 1124 match loop { break Foo::A } {
1588 } 1125 Either::A => (),
1589 ", 1126 Either::B => (),
1127 }
1128}
1129"#,
1590 ); 1130 );
1591 } 1131 }
1592 1132
1593 #[test] 1133 #[test]
1594 fn expr_partially_diverges() { 1134 fn expr_partially_diverges() {
1595 check_no_diagnostic( 1135 check_diagnostics(
1596 r" 1136 r#"
1597 enum Either<T> { 1137enum Either<T> { A(T), B }
1598 A(T),
1599 B,
1600 }
1601 fn foo() -> Either<!> {
1602 Either::B
1603 }
1604 fn test_fn() -> u32 {
1605 match foo() {
1606 Either::A(val) => val,
1607 Either::B => 0,
1608 }
1609 }
1610 ",
1611 );
1612 }
1613 1138
1614 #[test] 1139fn foo() -> Either<!> { Either::B }
1615 fn enum_record_no_arms() { 1140fn main() -> u32 {
1616 check_diagnostic( 1141 match foo() {
1617 r" 1142 Either::A(val) => val,
1618 enum Either { 1143 Either::B => 0,
1619 A { foo: bool },
1620 B,
1621 }
1622 fn test_fn() {
1623 let a = Either::A { foo: true };
1624 match a {
1625 }
1626 }
1627 ",
1628 );
1629 } 1144 }
1630 1145}
1631 #[test] 1146"#,
1632 fn enum_record_missing_arms() {
1633 check_diagnostic(
1634 r"
1635 enum Either {
1636 A { foo: bool },
1637 B,
1638 }
1639 fn test_fn() {
1640 let a = Either::A { foo: true };
1641 match a {
1642 Either::A { foo: true } => (),
1643 }
1644 }
1645 ",
1646 ); 1147 );
1647 } 1148 }
1648 1149
1649 #[test] 1150 #[test]
1650 fn enum_record_no_diagnostic() { 1151 fn enum_record() {
1651 check_no_diagnostic( 1152 check_diagnostics(
1652 r" 1153 r#"
1653 enum Either { 1154enum Either { A { foo: bool }, B }
1654 A { foo: bool },
1655 B,
1656 }
1657 fn test_fn() {
1658 let a = Either::A { foo: true };
1659 match a {
1660 Either::A { foo: true } => (),
1661 Either::A { foo: false } => (),
1662 Either::B => (),
1663 }
1664 }
1665 ",
1666 );
1667 }
1668 1155
1669 #[test] 1156fn main() {
1670 fn enum_record_missing_field_no_diagnostic() { 1157 let a = Either::A { foo: true };
1671 // When `Either::A` is missing a struct member, we don't want 1158 match a { }
1672 // to fire the missing match arm diagnostic. This should fire 1159 //^ Missing match arm
1673 // some other diagnostic. 1160 match a { Either::A { foo: true } => () }
1674 check_no_diagnostic( 1161 //^ Missing match arm
1675 r" 1162 match a {
1676 enum Either { 1163 Either::A { } => (),
1677 A { foo: bool }, 1164 //^^^ Missing structure fields:
1678 B, 1165 // | - foo
1679 } 1166 Either::B => (),
1680 fn test_fn() {
1681 let a = Either::B;
1682 match a {
1683 Either::A { } => (),
1684 Either::B => (),
1685 }
1686 }
1687 ",
1688 );
1689 } 1167 }
1168 match a {
1169 //^ Missing match arm
1170 Either::A { } => (),
1171 } //^^^ Missing structure fields:
1172 // | - foo
1690 1173
1691 #[test] 1174 match a {
1692 fn enum_record_missing_field_missing_match_arm() { 1175 Either::A { foo: true } => (),
1693 // Even though `Either::A` is missing fields, we still want to fire 1176 Either::A { foo: false } => (),
1694 // the missing arm diagnostic here, since we know `Either::B` is missing. 1177 Either::B => (),
1695 check_diagnostic(
1696 r"
1697 enum Either {
1698 A { foo: bool },
1699 B,
1700 }
1701 fn test_fn() {
1702 let a = Either::B;
1703 match a {
1704 Either::A { } => (),
1705 }
1706 }
1707 ",
1708 );
1709 } 1178 }
1710 1179 match a {
1711 #[test] 1180 Either::A { foo: _ } => (),
1712 fn enum_record_no_diagnostic_wild() { 1181 Either::B => (),
1713 check_no_diagnostic(
1714 r"
1715 enum Either {
1716 A { foo: bool },
1717 B,
1718 }
1719 fn test_fn() {
1720 let a = Either::A { foo: true };
1721 match a {
1722 Either::A { foo: _ } => (),
1723 Either::B => (),
1724 }
1725 }
1726 ",
1727 );
1728 } 1182 }
1729 1183}
1730 #[test] 1184"#,
1731 fn enum_record_fields_out_of_order_missing_arm() {
1732 check_diagnostic(
1733 r"
1734 enum Either {
1735 A { foo: bool, bar: () },
1736 B,
1737 }
1738 fn test_fn() {
1739 let a = Either::A { foo: true };
1740 match a {
1741 Either::A { bar: (), foo: false } => (),
1742 Either::A { foo: true, bar: () } => (),
1743 }
1744 }
1745 ",
1746 ); 1185 );
1747 } 1186 }
1748 1187
1749 #[test] 1188 #[test]
1750 fn enum_record_fields_out_of_order_no_diagnostic() { 1189 fn enum_record_fields_out_of_order() {
1751 check_no_diagnostic( 1190 check_diagnostics(
1752 r" 1191 r#"
1753 enum Either { 1192enum Either {
1754 A { foo: bool, bar: () }, 1193 A { foo: bool, bar: () },
1755 B, 1194 B,
1756 } 1195}
1757 fn test_fn() {
1758 let a = Either::A { foo: true };
1759 match a {
1760 Either::A { bar: (), foo: false } => (),
1761 Either::A { foo: true, bar: () } => (),
1762 Either::B => (),
1763 }
1764 }
1765 ",
1766 );
1767 }
1768 1196
1769 #[test] 1197fn main() {
1770 fn enum_record_ellipsis_missing_arm() { 1198 let a = Either::A { foo: true, bar: () };
1771 check_diagnostic( 1199 match a {
1772 r" 1200 //^ Missing match arm
1773 enum Either { 1201 Either::A { bar: (), foo: false } => (),
1774 A { foo: bool, bar: bool }, 1202 Either::A { foo: true, bar: () } => (),
1775 B,
1776 }
1777 fn test_fn() {
1778 match Either::B {
1779 Either::A { foo: true, .. } => (),
1780 Either::B => (),
1781 }
1782 }
1783 ",
1784 );
1785 } 1203 }
1786 1204
1787 #[test] 1205 match a {
1788 fn enum_record_ellipsis_no_diagnostic() { 1206 Either::A { bar: (), foo: false } => (),
1789 check_no_diagnostic( 1207 Either::A { foo: true, bar: () } => (),
1790 r" 1208 Either::B => (),
1791 enum Either {
1792 A { foo: bool, bar: bool },
1793 B,
1794 }
1795 fn test_fn() {
1796 let a = Either::A { foo: true };
1797 match a {
1798 Either::A { foo: true, .. } => (),
1799 Either::A { foo: false, .. } => (),
1800 Either::B => (),
1801 }
1802 }
1803 ",
1804 );
1805 } 1209 }
1806 1210}
1807 #[test] 1211"#,
1808 fn enum_record_ellipsis_all_fields_missing_arm() {
1809 check_diagnostic(
1810 r"
1811 enum Either {
1812 A { foo: bool, bar: bool },
1813 B,
1814 }
1815 fn test_fn() {
1816 let a = Either::B;
1817 match a {
1818 Either::A { .. } => (),
1819 }
1820 }
1821 ",
1822 ); 1212 );
1823 } 1213 }
1824 1214
1825 #[test] 1215 #[test]
1826 fn enum_record_ellipsis_all_fields_no_diagnostic() { 1216 fn enum_record_ellipsis() {
1827 check_no_diagnostic( 1217 check_diagnostics(
1828 r" 1218 r#"
1829 enum Either { 1219enum Either {
1830 A { foo: bool, bar: bool }, 1220 A { foo: bool, bar: bool },
1831 B, 1221 B,
1832 } 1222}
1833 fn test_fn() {
1834 let a = Either::B;
1835 match a {
1836 Either::A { .. } => (),
1837 Either::B => (),
1838 }
1839 }
1840 ",
1841 );
1842 }
1843 1223
1844 #[test] 1224fn main() {
1845 fn enum_tuple_partial_ellipsis_no_diagnostic() { 1225 let a = Either::B;
1846 check_no_diagnostic( 1226 match a {
1847 r" 1227 //^ Missing match arm
1848 enum Either { 1228 Either::A { foo: true, .. } => (),
1849 A(bool, bool, bool, bool), 1229 Either::B => (),
1850 B,
1851 }
1852 fn test_fn() {
1853 match Either::B {
1854 Either::A(true, .., true) => {},
1855 Either::A(true, .., false) => {},
1856 Either::A(false, .., true) => {},
1857 Either::A(false, .., false) => {},
1858 Either::B => {},
1859 }
1860 }
1861 ",
1862 );
1863 } 1230 }
1864 1231 match a {
1865 #[test] 1232 //^ Missing match arm
1866 fn enum_tuple_partial_ellipsis_2_no_diagnostic() { 1233 Either::A { .. } => (),
1867 check_no_diagnostic(
1868 r"
1869 enum Either {
1870 A(bool, bool, bool, bool),
1871 B,
1872 }
1873 fn test_fn() {
1874 match Either::B {
1875 Either::A(true, .., true) => {},
1876 Either::A(true, .., false) => {},
1877 Either::A(.., true) => {},
1878 Either::A(.., false) => {},
1879 Either::B => {},
1880 }
1881 }
1882 ",
1883 );
1884 } 1234 }
1885 1235
1886 #[test] 1236 match a {
1887 fn enum_tuple_partial_ellipsis_missing_arm() { 1237 Either::A { foo: true, .. } => (),
1888 check_diagnostic( 1238 Either::A { foo: false, .. } => (),
1889 r" 1239 Either::B => (),
1890 enum Either {
1891 A(bool, bool, bool, bool),
1892 B,
1893 }
1894 fn test_fn() {
1895 match Either::B {
1896 Either::A(true, .., true) => {},
1897 Either::A(true, .., false) => {},
1898 Either::A(false, .., false) => {},
1899 Either::B => {},
1900 }
1901 }
1902 ",
1903 );
1904 } 1240 }
1905 1241
1906 #[test] 1242 match a {
1907 fn enum_tuple_partial_ellipsis_2_missing_arm() { 1243 Either::A { .. } => (),
1908 check_diagnostic( 1244 Either::B => (),
1909 r"
1910 enum Either {
1911 A(bool, bool, bool, bool),
1912 B,
1913 }
1914 fn test_fn() {
1915 match Either::B {
1916 Either::A(true, .., true) => {},
1917 Either::A(true, .., false) => {},
1918 Either::A(.., true) => {},
1919 Either::B => {},
1920 }
1921 }
1922 ",
1923 );
1924 } 1245 }
1925 1246}
1926 #[test] 1247"#,
1927 fn enum_tuple_ellipsis_no_diagnostic() {
1928 check_no_diagnostic(
1929 r"
1930 enum Either {
1931 A(bool, bool, bool, bool),
1932 B,
1933 }
1934 fn test_fn() {
1935 match Either::B {
1936 Either::A(..) => {},
1937 Either::B => {},
1938 }
1939 }
1940 ",
1941 ); 1248 );
1942 } 1249 }
1943 1250
1944 #[test] 1251 #[test]
1945 fn enum_never() { 1252 fn enum_tuple_partial_ellipsis() {
1946 check_no_diagnostic( 1253 check_diagnostics(
1947 r" 1254 r#"
1948 enum Never {} 1255enum Either {
1256 A(bool, bool, bool, bool),
1257 B,
1258}
1949 1259
1950 fn test_fn(never: Never) { 1260fn main() {
1951 match never {} 1261 match Either::B {
1952 } 1262 //^^^^^^^^^ Missing match arm
1953 ", 1263 Either::A(true, .., true) => (),
1954 ); 1264 Either::A(true, .., false) => (),
1265 Either::A(false, .., false) => (),
1266 Either::B => (),
1267 }
1268 match Either::B {
1269 //^^^^^^^^^ Missing match arm
1270 Either::A(true, .., true) => (),
1271 Either::A(true, .., false) => (),
1272 Either::A(.., true) => (),
1273 Either::B => (),
1274 }
1275
1276 match Either::B {
1277 Either::A(true, .., true) => (),
1278 Either::A(true, .., false) => (),
1279 Either::A(false, .., true) => (),
1280 Either::A(false, .., false) => (),
1281 Either::B => (),
1282 }
1283 match Either::B {
1284 Either::A(true, .., true) => (),
1285 Either::A(true, .., false) => (),
1286 Either::A(.., true) => (),
1287 Either::A(.., false) => (),
1288 Either::B => (),
1955 } 1289 }
1956 1290}
1957 #[test] 1291"#,
1958 fn type_never() {
1959 check_no_diagnostic(
1960 r"
1961 fn test_fn(never: !) {
1962 match never {}
1963 }
1964 ",
1965 ); 1292 );
1966 } 1293 }
1967 1294
1968 #[test] 1295 #[test]
1969 fn enum_never_ref() { 1296 fn never() {
1970 check_no_diagnostic( 1297 check_diagnostics(
1971 r" 1298 r#"
1972 enum Never {} 1299enum Never {}
1973 1300
1974 fn test_fn(never: &Never) { 1301fn enum_(never: Never) {
1975 match never {} 1302 match never {}
1976 } 1303}
1977 ", 1304fn enum_ref(never: &Never) {
1978 ); 1305 match never {}
1979 } 1306}
1980 1307fn bang(never: !) {
1981 #[test] 1308 match never {}
1982 fn expr_diverges_missing_arm() { 1309}
1983 check_no_diagnostic( 1310"#,
1984 r"
1985 enum Either {
1986 A,
1987 B,
1988 }
1989 fn test_fn() {
1990 match loop {} {
1991 Either::A => (),
1992 }
1993 }
1994 ",
1995 ); 1311 );
1996 } 1312 }
1997 1313
1998 #[test] 1314 #[test]
1999 fn or_pattern_panic() { 1315 fn or_pattern_panic() {
2000 check_no_diagnostic( 1316 check_diagnostics(
2001 r" 1317 r#"
2002 pub enum Category { 1318pub enum Category { Infinity, Zero }
2003 Infinity,
2004 Zero,
2005 }
2006 1319
2007 fn panic(a: Category, b: Category) { 1320fn panic(a: Category, b: Category) {
2008 match (a, b) { 1321 match (a, b) {
2009 (Category::Zero | Category::Infinity, _) => {} 1322 (Category::Zero | Category::Infinity, _) => (),
2010 (_, Category::Zero | Category::Infinity) => {} 1323 (_, Category::Zero | Category::Infinity) => (),
2011 }
2012 }
2013 ",
2014 );
2015 } 1324 }
2016 1325
2017 #[test] 1326 // FIXME: This is a false positive, but the code used to cause a panic in the match checker,
2018 fn or_pattern_panic_2() { 1327 // so this acts as a regression test for that.
2019 // FIXME: This is a false positive, but the code used to cause a panic in the match checker, 1328 match (a, b) {
2020 // so this acts as a regression test for that. 1329 //^^^^^^ Missing match arm
2021 check_diagnostic( 1330 (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => (),
2022 r" 1331 (Category::Infinity | Category::Zero, _) => (),
2023 pub enum Category {
2024 Infinity,
2025 Zero,
2026 }
2027
2028 fn panic(a: Category, b: Category) {
2029 match (a, b) {
2030 (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {}
2031
2032 (Category::Infinity | Category::Zero, _) => {}
2033 }
2034 }
2035 ",
2036 );
2037 } 1332 }
2038} 1333}
2039 1334"#,
2040#[cfg(test)] 1335 );
2041mod false_negatives { 1336 }
2042 //! The implementation of match checking here is a work in progress. As we roll this out, we 1337
2043 //! prefer false negatives to false positives (ideally there would be no false positives). This 1338 mod false_negatives {
2044 //! test module should document known false negatives. Eventually we will have a complete 1339 //! The implementation of match checking here is a work in progress. As we roll this out, we
2045 //! implementation of match checking and this module will be empty. 1340 //! prefer false negatives to false positives (ideally there would be no false positives). This
2046 //! 1341 //! test module should document known false negatives. Eventually we will have a complete
2047 //! The reasons for documenting known false negatives: 1342 //! implementation of match checking and this module will be empty.
2048 //! 1343 //!
2049 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. 1344 //! The reasons for documenting known false negatives:
2050 //! 2. It ensures the code doesn't panic when handling these cases. 1345 //!
2051 1346 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
2052 use super::tests::*; 1347 //! 2. It ensures the code doesn't panic when handling these cases.
2053 1348 use super::*;
2054 #[test] 1349
2055 fn integers() { 1350 #[test]
2056 // This is a false negative. 1351 fn integers() {
2057 // We don't currently check integer exhaustiveness. 1352 // We don't currently check integer exhaustiveness.
2058 check_no_diagnostic( 1353 check_diagnostics(
2059 r" 1354 r#"
2060 fn test_fn() { 1355fn main() {
2061 match 5 { 1356 match 5 {
2062 10 => (), 1357 10 => (),
2063 11..20 => (), 1358 11..20 => (),
2064 }
2065 }
2066 ",
2067 );
2068 }
2069
2070 #[test]
2071 fn internal_or() {
2072 // This is a false negative.
2073 // We do not currently handle patterns with internal `or`s.
2074 check_no_diagnostic(
2075 r"
2076 fn test_fn() {
2077 enum Either {
2078 A(bool),
2079 B,
2080 }
2081 match Either::B {
2082 Either::A(true | false) => (),
2083 }
2084 }
2085 ",
2086 );
2087 } 1359 }
1360}
1361"#,
1362 );
1363 }
2088 1364
2089 #[test] 1365 #[test]
2090 fn expr_loop_missing_arm() { 1366 fn internal_or() {
2091 // This is a false negative. 1367 // We do not currently handle patterns with internal `or`s.
2092 // We currently infer the type of `loop { break Foo::A }` to `!`, which 1368 check_diagnostics(
2093 // causes us to skip the diagnostic since `Either::A` doesn't type check 1369 r#"
2094 // with `!`. 1370fn main() {
2095 check_diagnostic( 1371 enum Either { A(bool), B }
2096 r" 1372 match Either::B {
2097 enum Either { 1373 Either::A(true | false) => (),
2098 A,
2099 B,
2100 }
2101 fn test_fn() {
2102 match loop { break Foo::A } {
2103 Either::A => (),
2104 }
2105 }
2106 ",
2107 );
2108 } 1374 }
1375}
1376"#,
1377 );
1378 }
2109 1379
2110 #[test] 1380 #[test]
2111 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { 1381 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
2112 // This is a false negative. 1382 // We don't currently handle tuple patterns with ellipsis.
2113 // We don't currently handle tuple patterns with ellipsis. 1383 check_diagnostics(
2114 check_no_diagnostic( 1384 r#"
2115 r" 1385fn main() {
2116 fn test_fn() { 1386 match (false, true, false) {
2117 match (false, true, false) { 1387 (false, ..) => (),
2118 (false, ..) => {},
2119 }
2120 }
2121 ",
2122 );
2123 } 1388 }
1389}
1390"#,
1391 );
1392 }
2124 1393
2125 #[test] 1394 #[test]
2126 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { 1395 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
2127 // This is a false negative. 1396 // We don't currently handle tuple patterns with ellipsis.
2128 // We don't currently handle tuple patterns with ellipsis. 1397 check_diagnostics(
2129 check_no_diagnostic( 1398 r#"
2130 r" 1399fn main() {
2131 fn test_fn() { 1400 match (false, true, false) {
2132 match (false, true, false) { 1401 (.., false) => (),
2133 (.., false) => {},
2134 }
2135 }
2136 ",
2137 );
2138 } 1402 }
1403}
1404"#,
1405 );
1406 }
2139 1407
2140 #[test] 1408 #[test]
2141 fn struct_missing_arm() { 1409 fn struct_missing_arm() {
2142 // This is a false negative. 1410 // We don't currently handle structs.
2143 // We don't currently handle structs. 1411 check_diagnostics(
2144 check_no_diagnostic( 1412 r#"
2145 r" 1413struct Foo { a: bool }
2146 struct Foo { 1414fn main(f: Foo) {
2147 a: bool, 1415 match f { Foo { a: true } => () }
2148 } 1416}
2149 fn test_fn(f: Foo) { 1417"#,
2150 match f { 1418 );
2151 Foo { a: true } => {}, 1419 }
2152 }
2153 }
2154 ",
2155 );
2156 } 1420 }
2157} 1421}
diff --git a/crates/ra_hir_ty/src/unsafe_validation.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
index c512c4f8e..5cc76bdce 100644
--- a/crates/ra_hir_ty/src/unsafe_validation.rs
+++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
@@ -6,35 +6,38 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 body::Body, 7 body::Body,
8 expr::{Expr, ExprId, UnaryOp}, 8 expr::{Expr, ExprId, UnaryOp},
9 DefWithBodyId, FunctionId, 9 DefWithBodyId,
10}; 10};
11use hir_expand::diagnostics::DiagnosticSink; 11use hir_expand::diagnostics::DiagnosticSink;
12 12
13use crate::{ 13use crate::{
14 db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDef, ApplicationTy, 14 db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDefId, ApplicationTy,
15 InferenceResult, Ty, TypeCtor, 15 InferenceResult, Ty, TypeCtor,
16}; 16};
17 17
18pub struct UnsafeValidator<'a, 'b: 'a> { 18pub(super) struct UnsafeValidator<'a, 'b: 'a> {
19 func: FunctionId, 19 owner: DefWithBodyId,
20 infer: Arc<InferenceResult>, 20 infer: Arc<InferenceResult>,
21 sink: &'a mut DiagnosticSink<'b>, 21 sink: &'a mut DiagnosticSink<'b>,
22} 22}
23 23
24impl<'a, 'b> UnsafeValidator<'a, 'b> { 24impl<'a, 'b> UnsafeValidator<'a, 'b> {
25 pub fn new( 25 pub(super) fn new(
26 func: FunctionId, 26 owner: DefWithBodyId,
27 infer: Arc<InferenceResult>, 27 infer: Arc<InferenceResult>,
28 sink: &'a mut DiagnosticSink<'b>, 28 sink: &'a mut DiagnosticSink<'b>,
29 ) -> UnsafeValidator<'a, 'b> { 29 ) -> UnsafeValidator<'a, 'b> {
30 UnsafeValidator { func, infer, sink } 30 UnsafeValidator { owner, infer, sink }
31 } 31 }
32 32
33 pub fn validate_body(&mut self, db: &dyn HirDatabase) { 33 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
34 let def = self.func.into(); 34 let def = self.owner.into();
35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); 35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
36 let func_data = db.function_data(self.func); 36 let is_unsafe = match self.owner {
37 if func_data.is_unsafe 37 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe,
38 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
39 };
40 if is_unsafe
38 || unsafe_expressions 41 || unsafe_expressions
39 .iter() 42 .iter()
40 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) 43 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block)
@@ -85,7 +88,7 @@ fn walk_unsafe(
85 Expr::Call { callee, .. } => { 88 Expr::Call { callee, .. } => {
86 let ty = &infer[*callee]; 89 let ty = &infer[*callee];
87 if let &Ty::Apply(ApplicationTy { 90 if let &Ty::Apply(ApplicationTy {
88 ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), 91 ctor: TypeCtor::FnDef(CallableDefId::FunctionId(func)),
89 .. 92 ..
90 }) = ty 93 }) = ty
91 { 94 {
@@ -118,3 +121,53 @@ fn walk_unsafe(
118 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); 121 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block);
119 }); 122 });
120} 123}
124
125#[cfg(test)]
126mod tests {
127 use crate::diagnostics::tests::check_diagnostics;
128
129 #[test]
130 fn missing_unsafe_diagnostic_with_raw_ptr() {
131 check_diagnostics(
132 r#"
133fn main() {
134 let x = &5 as *const usize;
135 unsafe { let y = *x; }
136 let z = *x;
137} //^^ This operation is unsafe and requires an unsafe function or block
138"#,
139 )
140 }
141
142 #[test]
143 fn missing_unsafe_diagnostic_with_unsafe_call() {
144 check_diagnostics(
145 r#"
146struct HasUnsafe;
147
148impl HasUnsafe {
149 unsafe fn unsafe_fn(&self) {
150 let x = &5 as *const usize;
151 let y = *x;
152 }
153}
154
155unsafe fn unsafe_fn() {
156 let x = &5 as *const usize;
157 let y = *x;
158}
159
160fn main() {
161 unsafe_fn();
162 //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
163 HasUnsafe.unsafe_fn();
164 //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
165 unsafe {
166 unsafe_fn();
167 HasUnsafe.unsafe_fn();
168 }
169}
170"#,
171 );
172 }
173}
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 23cea1a2a..19770e609 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -3,7 +3,7 @@
3use std::fmt; 3use std::fmt;
4 4
5use crate::{ 5use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, 6 db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate,
7 Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8}; 8};
9use hir_def::{ 9use hir_def::{
@@ -243,22 +243,36 @@ impl HirDisplay for ApplicationTy {
243 write!(f, ")")?; 243 write!(f, ")")?;
244 } 244 }
245 } 245 }
246 TypeCtor::FnPtr { .. } => { 246 TypeCtor::FnPtr { is_varargs, .. } => {
247 let sig = FnSig::from_fn_ptr_substs(&self.parameters); 247 let sig = FnSig::from_fn_ptr_substs(&self.parameters, is_varargs);
248 write!(f, "fn(")?; 248 write!(f, "fn(")?;
249 f.write_joined(sig.params(), ", ")?; 249 f.write_joined(sig.params(), ", ")?;
250 if is_varargs {
251 if sig.params().is_empty() {
252 write!(f, "...")?;
253 } else {
254 write!(f, ", ...")?;
255 }
256 }
250 write!(f, ")")?; 257 write!(f, ")")?;
251 let ret = sig.ret(); 258 let ret = sig.ret();
252 if *ret != Ty::unit() { 259 if *ret != Ty::unit() {
253 write!(f, " -> {}", ret.display(f.db))?; 260 let ret_display = if f.omit_verbose_types() {
261 ret.display_truncated(f.db, f.max_size)
262 } else {
263 ret.display(f.db)
264 };
265 write!(f, " -> {}", ret_display)?;
254 } 266 }
255 } 267 }
256 TypeCtor::FnDef(def) => { 268 TypeCtor::FnDef(def) => {
257 let sig = f.db.callable_item_signature(def).subst(&self.parameters); 269 let sig = f.db.callable_item_signature(def).subst(&self.parameters);
258 match def { 270 match def {
259 CallableDef::FunctionId(ff) => write!(f, "fn {}", f.db.function_data(ff).name)?, 271 CallableDefId::FunctionId(ff) => {
260 CallableDef::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, 272 write!(f, "fn {}", f.db.function_data(ff).name)?
261 CallableDef::EnumVariantId(e) => { 273 }
274 CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
275 CallableDefId::EnumVariantId(e) => {
262 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? 276 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
263 } 277 }
264 }; 278 };
@@ -279,7 +293,12 @@ impl HirDisplay for ApplicationTy {
279 write!(f, ")")?; 293 write!(f, ")")?;
280 let ret = sig.ret(); 294 let ret = sig.ret();
281 if *ret != Ty::unit() { 295 if *ret != Ty::unit() {
282 write!(f, " -> {}", ret.display(f.db))?; 296 let ret_display = if f.omit_verbose_types() {
297 ret.display_truncated(f.db, f.max_size)
298 } else {
299 ret.display(f.db)
300 };
301 write!(f, " -> {}", ret_display)?;
283 } 302 }
284 } 303 }
285 TypeCtor::Adt(def_id) => { 304 TypeCtor::Adt(def_id) => {
@@ -369,7 +388,7 @@ impl HirDisplay for ApplicationTy {
369 let data = (*datas) 388 let data = (*datas)
370 .as_ref() 389 .as_ref()
371 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 390 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
372 data.clone().subst(&self.parameters) 391 data.subst(&self.parameters)
373 } 392 }
374 }; 393 };
375 write!(f, "impl ")?; 394 write!(f, "impl ")?;
@@ -388,7 +407,13 @@ impl HirDisplay for ApplicationTy {
388 f.write_joined(sig.params(), ", ")?; 407 f.write_joined(sig.params(), ", ")?;
389 write!(f, "|")?; 408 write!(f, "|")?;
390 }; 409 };
391 write!(f, " -> {}", sig.ret().display(f.db))?; 410
411 let ret_display = if f.omit_verbose_types() {
412 sig.ret().display_truncated(f.db, f.max_size)
413 } else {
414 sig.ret().display(f.db)
415 };
416 write!(f, " -> {}", ret_display)?;
392 } else { 417 } else {
393 write!(f, "{{closure}}")?; 418 write!(f, "{{closure}}")?;
394 } 419 }
@@ -456,7 +481,7 @@ impl HirDisplay for Ty {
456 let data = (*datas) 481 let data = (*datas)
457 .as_ref() 482 .as_ref()
458 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 483 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
459 data.clone().subst(&opaque_ty.parameters) 484 data.subst(&opaque_ty.parameters)
460 } 485 }
461 }; 486 };
462 write!(f, "impl ")?; 487 write!(f, "impl ")?;
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 3719f76a6..28f32a0a4 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -18,8 +18,6 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use rustc_hash::FxHashMap;
22
23use hir_def::{ 21use hir_def::{
24 body::Body, 22 body::Body,
25 data::{ConstData, FunctionData, StaticData}, 23 data::{ConstData, FunctionData, StaticData},
@@ -28,13 +26,15 @@ use hir_def::{
28 path::{path, Path}, 26 path::{path, Path},
29 resolver::{HasResolver, Resolver, TypeNs}, 27 resolver::{HasResolver, Resolver, TypeNs},
30 type_ref::{Mutability, TypeRef}, 28 type_ref::{Mutability, TypeRef},
31 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, TraitId, TypeAliasId, 29 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId,
32 VariantId, 30 TypeAliasId, VariantId,
33}; 31};
34use hir_expand::{diagnostics::DiagnosticSink, name::name}; 32use hir_expand::{diagnostics::DiagnosticSink, name::name};
35use ra_arena::map::ArenaMap; 33use ra_arena::map::ArenaMap;
36use ra_prof::profile; 34use ra_prof::profile;
37use ra_syntax::SmolStr; 35use ra_syntax::SmolStr;
36use rustc_hash::FxHashMap;
37use stdx::impl_from;
38 38
39use super::{ 39use super::{
40 primitive::{FloatTy, IntTy}, 40 primitive::{FloatTy, IntTy},
@@ -84,8 +84,7 @@ enum ExprOrPatId {
84 ExprId(ExprId), 84 ExprId(ExprId),
85 PatId(PatId), 85 PatId(PatId),
86} 86}
87 87impl_from!(ExprId, PatId for ExprOrPatId);
88impl_froms!(ExprOrPatId: ExprId, PatId);
89 88
90/// Binding modes inferred for patterns. 89/// Binding modes inferred for patterns.
91/// https://doc.rust-lang.org/reference/patterns.html#binding-modes 90/// https://doc.rust-lang.org/reference/patterns.html#binding-modes
@@ -169,7 +168,7 @@ impl InferenceResult {
169 pub fn add_diagnostics( 168 pub fn add_diagnostics(
170 &self, 169 &self,
171 db: &dyn HirDatabase, 170 db: &dyn HirDatabase,
172 owner: FunctionId, 171 owner: DefWithBodyId,
173 sink: &mut DiagnosticSink, 172 sink: &mut DiagnosticSink,
174 ) { 173 ) {
175 self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink)) 174 self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
@@ -376,17 +375,21 @@ impl<'a> InferenceContext<'a> {
376 ) -> Ty { 375 ) -> Ty {
377 match assoc_ty { 376 match assoc_ty {
378 Some(res_assoc_ty) => { 377 Some(res_assoc_ty) => {
378 let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
379 hir_def::AssocContainerId::TraitId(trait_) => trait_,
380 _ => panic!("resolve_associated_type called with non-associated type"),
381 };
379 let ty = self.table.new_type_var(); 382 let ty = self.table.new_type_var();
380 let builder = Substs::build_for_def(self.db, res_assoc_ty) 383 let substs = Substs::build_for_def(self.db, res_assoc_ty)
381 .push(inner_ty) 384 .push(inner_ty)
382 .fill(params.iter().cloned()); 385 .fill(params.iter().cloned())
386 .build();
387 let trait_ref = TraitRef { trait_, substs: substs.clone() };
383 let projection = ProjectionPredicate { 388 let projection = ProjectionPredicate {
384 ty: ty.clone(), 389 ty: ty.clone(),
385 projection_ty: ProjectionTy { 390 projection_ty: ProjectionTy { associated_ty: res_assoc_ty, parameters: substs },
386 associated_ty: res_assoc_ty,
387 parameters: builder.build(),
388 },
389 }; 391 };
392 self.obligations.push(Obligation::Trait(trait_ref));
390 self.obligations.push(Obligation::Projection(projection)); 393 self.obligations.push(Obligation::Projection(projection));
391 self.resolve_ty_as_possible(ty) 394 self.resolve_ty_as_possible(ty)
392 } 395 }
@@ -757,7 +760,7 @@ impl std::ops::BitOrAssign for Diverges {
757} 760}
758 761
759mod diagnostics { 762mod diagnostics {
760 use hir_def::{expr::ExprId, FunctionId}; 763 use hir_def::{expr::ExprId, DefWithBodyId};
761 use hir_expand::diagnostics::DiagnosticSink; 764 use hir_expand::diagnostics::DiagnosticSink;
762 765
763 use crate::{ 766 use crate::{
@@ -775,17 +778,17 @@ mod diagnostics {
775 pub(super) fn add_to( 778 pub(super) fn add_to(
776 &self, 779 &self,
777 db: &dyn HirDatabase, 780 db: &dyn HirDatabase,
778 owner: FunctionId, 781 owner: DefWithBodyId,
779 sink: &mut DiagnosticSink, 782 sink: &mut DiagnosticSink,
780 ) { 783 ) {
781 match self { 784 match self {
782 InferenceDiagnostic::NoSuchField { expr, field } => { 785 InferenceDiagnostic::NoSuchField { expr, field } => {
783 let (_, source_map) = db.body_with_source_map(owner.into()); 786 let (_, source_map) = db.body_with_source_map(owner);
784 let field = source_map.field_syntax(*expr, *field); 787 let field = source_map.field_syntax(*expr, *field);
785 sink.push(NoSuchField { file: field.file_id, field: field.value }) 788 sink.push(NoSuchField { file: field.file_id, field: field.value })
786 } 789 }
787 InferenceDiagnostic::BreakOutsideOfLoop { expr } => { 790 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
788 let (_, source_map) = db.body_with_source_map(owner.into()); 791 let (_, source_map) = db.body_with_source_map(owner);
789 let ptr = source_map 792 let ptr = source_map
790 .expr_syntax(*expr) 793 .expr_syntax(*expr)
791 .expect("break outside of loop in synthetic syntax"); 794 .expect("break outside of loop in synthetic syntax");
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 22884522a..731b062c2 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -17,7 +17,7 @@ use crate::{
17 autoderef, method_resolution, op, 17 autoderef, method_resolution, op,
18 traits::{FnTrait, InEnvironment}, 18 traits::{FnTrait, InEnvironment},
19 utils::{generics, variant_data, Generics}, 19 utils::{generics, variant_data, Generics},
20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, 20 ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
21 TraitRef, Ty, TypeCtor, 21 TraitRef, Ty, TypeCtor,
22}; 22};
23 23
@@ -85,10 +85,8 @@ impl<'a> InferenceContext<'a> {
85 ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, 85 ctor: TypeCtor::Tuple { cardinality: num_args as u16 },
86 parameters, 86 parameters,
87 }); 87 });
88 let substs = Substs::build_for_generics(&generic_params) 88 let substs =
89 .push(ty.clone()) 89 Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
90 .push(arg_ty.clone())
91 .build();
92 90
93 let trait_env = Arc::clone(&self.trait_env); 91 let trait_env = Arc::clone(&self.trait_env);
94 let implements_fn_trait = 92 let implements_fn_trait =
@@ -222,7 +220,7 @@ impl<'a> InferenceContext<'a> {
222 }; 220 };
223 sig_tys.push(ret_ty.clone()); 221 sig_tys.push(ret_ty.clone());
224 let sig_ty = Ty::apply( 222 let sig_ty = Ty::apply(
225 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 223 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false },
226 Substs(sig_tys.clone().into()), 224 Substs(sig_tys.clone().into()),
227 ); 225 );
228 let closure_ty = 226 let closure_ty =
@@ -407,8 +405,15 @@ impl<'a> InferenceContext<'a> {
407 .subst(&a_ty.parameters) 405 .subst(&a_ty.parameters)
408 }) 406 })
409 } 407 }
410 // FIXME: 408 TypeCtor::Adt(AdtId::UnionId(u)) => {
411 TypeCtor::Adt(AdtId::UnionId(_)) => None, 409 self.db.union_data(u).variant_data.field(name).map(|local_id| {
410 let field = FieldId { parent: u.into(), local_id };
411 self.write_field_resolution(tgt_expr, field);
412 self.db.field_types(u.into())[field.local_id]
413 .clone()
414 .subst(&a_ty.parameters)
415 })
416 }
412 _ => None, 417 _ => None,
413 }, 418 },
414 _ => None, 419 _ => None,
@@ -849,7 +854,7 @@ impl<'a> InferenceContext<'a> {
849 } 854 }
850 // add obligation for trait implementation, if this is a trait method 855 // add obligation for trait implementation, if this is a trait method
851 match def { 856 match def {
852 CallableDef::FunctionId(f) => { 857 CallableDefId::FunctionId(f) => {
853 if let AssocContainerId::TraitId(trait_) = 858 if let AssocContainerId::TraitId(trait_) =
854 f.lookup(self.db.upcast()).container 859 f.lookup(self.db.upcast()).container
855 { 860 {
@@ -860,7 +865,7 @@ impl<'a> InferenceContext<'a> {
860 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); 865 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
861 } 866 }
862 } 867 }
863 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {} 868 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
864 } 869 }
865 } 870 }
866 } 871 }
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index 269495ca0..2e895d911 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -9,7 +9,7 @@ use test_utils::mark;
9use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
10use crate::{ 10use crate::{
11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, 11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
12 TypeCtor, TypeWalk, 12 TyKind, TypeCtor, TypeWalk,
13}; 13};
14 14
15impl<'a> InferenceContext<'a> { 15impl<'a> InferenceContext<'a> {
@@ -86,10 +86,20 @@ where
86 } 86 }
87 87
88 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 88 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
89 Canonicalized { 89 let kinds = self
90 value: Canonical { value: result, num_vars: self.free_vars.len() }, 90 .free_vars
91 free_vars: self.free_vars, 91 .iter()
92 } 92 .map(|v| match v {
93 // mapping MaybeNeverTypeVar to the same kind as general ones
94 // should be fine, because as opposed to int or float type vars,
95 // they don't restrict what kind of type can go into them, they
96 // just affect fallback.
97 InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General,
98 InferTy::IntVar(_) => TyKind::Integer,
99 InferTy::FloatVar(_) => TyKind::Float,
100 })
101 .collect();
102 Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars }
93 } 103 }
94 104
95 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { 105 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
@@ -131,26 +141,41 @@ impl<T> Canonicalized<T> {
131 ty 141 ty
132 } 142 }
133 143
134 pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) { 144 pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) {
135 // the solution may contain new variables, which we need to convert to new inference vars 145 // the solution may contain new variables, which we need to convert to new inference vars
136 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect()); 146 let new_vars = Substs(
147 solution
148 .kinds
149 .iter()
150 .map(|k| match k {
151 TyKind::General => ctx.table.new_type_var(),
152 TyKind::Integer => ctx.table.new_integer_var(),
153 TyKind::Float => ctx.table.new_float_var(),
154 })
155 .collect(),
156 );
137 for (i, ty) in solution.value.into_iter().enumerate() { 157 for (i, ty) in solution.value.into_iter().enumerate() {
138 let var = self.free_vars[i]; 158 let var = self.free_vars[i];
139 // eagerly replace projections in the type; we may be getting types 159 // eagerly replace projections in the type; we may be getting types
140 // e.g. from where clauses where this hasn't happened yet 160 // e.g. from where clauses where this hasn't happened yet
141 let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars)); 161 let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars));
142 ctx.table.unify(&Ty::Infer(var), &ty); 162 ctx.table.unify(&Ty::Infer(var), &ty);
143 } 163 }
144 } 164 }
145} 165}
146 166
147pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { 167pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> {
148 let mut table = InferenceTable::new(); 168 let mut table = InferenceTable::new();
149 let num_vars = ty1.num_vars.max(ty2.num_vars); 169 let vars = Substs(
150 let vars = 170 tys.kinds
151 Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); 171 .iter()
152 let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); 172 // we always use type vars here because we want everything to
153 let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); 173 // fallback to Unknown in the end (kind of hacky, as below)
174 .map(|_| table.new_type_var())
175 .collect(),
176 );
177 let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars);
178 let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars);
154 if !table.unify(&ty1_with_vars, &ty2_with_vars) { 179 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
155 return None; 180 return None;
156 } 181 }
@@ -162,7 +187,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
162 } 187 }
163 } 188 }
164 Some( 189 Some(
165 Substs::builder(ty1.num_vars) 190 Substs::builder(tys.kinds.len())
166 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) 191 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
167 .build(), 192 .build(),
168 ) 193 )
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index c9513b752..7698cb0d4 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -6,25 +6,6 @@ macro_rules! eprintln {
6 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; 6 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
7} 7}
8 8
9macro_rules! impl_froms {
10 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
11 $(
12 impl From<$v> for $e {
13 fn from(it: $v) -> $e {
14 $e::$v(it)
15 }
16 }
17 $($(
18 impl From<$sv> for $e {
19 fn from(it: $sv) -> $e {
20 $e::$v($v::$sv(it))
21 }
22 }
23 )*)?
24 )*
25 }
26}
27
28mod autoderef; 9mod autoderef;
29pub mod primitive; 10pub mod primitive;
30pub mod traits; 11pub mod traits;
@@ -32,22 +13,18 @@ pub mod method_resolution;
32mod op; 13mod op;
33mod lower; 14mod lower;
34pub(crate) mod infer; 15pub(crate) mod infer;
35pub mod display;
36pub(crate) mod utils; 16pub(crate) mod utils;
17
18pub mod display;
37pub mod db; 19pub mod db;
38pub mod diagnostics; 20pub mod diagnostics;
39pub mod expr;
40pub mod unsafe_validation;
41 21
42#[cfg(test)] 22#[cfg(test)]
43mod tests; 23mod tests;
44#[cfg(test)] 24#[cfg(test)]
45mod test_db; 25mod test_db;
46mod _match;
47 26
48use std::ops::Deref; 27use std::{iter, mem, ops::Deref, sync::Arc};
49use std::sync::Arc;
50use std::{iter, mem};
51 28
52use hir_def::{ 29use hir_def::{
53 expr::ExprId, 30 expr::ExprId,
@@ -55,18 +32,19 @@ use hir_def::{
55 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, 32 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
56 TypeParamId, 33 TypeParamId,
57}; 34};
58use ra_db::{impl_intern_key, salsa, CrateId}; 35use itertools::Itertools;
36use ra_db::{salsa, CrateId};
59 37
60use crate::{ 38use crate::{
61 db::HirDatabase, 39 db::HirDatabase,
40 display::HirDisplay,
62 primitive::{FloatTy, IntTy}, 41 primitive::{FloatTy, IntTy},
63 utils::{generics, make_mut_slice, Generics}, 42 utils::{generics, make_mut_slice, Generics},
64}; 43};
65use display::HirDisplay;
66 44
67pub use autoderef::autoderef; 45pub use autoderef::autoderef;
68pub use infer::{InferTy, InferenceResult}; 46pub use infer::{InferTy, InferenceResult};
69pub use lower::CallableDef; 47pub use lower::CallableDefId;
70pub use lower::{ 48pub use lower::{
71 associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, 49 associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId,
72 TyLoweringContext, ValueTyDefId, 50 TyLoweringContext, ValueTyDefId,
@@ -74,7 +52,6 @@ pub use lower::{
74pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 52pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
75 53
76pub use chalk_ir::{BoundVar, DebruijnIndex}; 54pub use chalk_ir::{BoundVar, DebruijnIndex};
77use itertools::Itertools;
78 55
79/// A type constructor or type name: this might be something like the primitive 56/// A type constructor or type name: this might be something like the primitive
80/// type `bool`, a struct like `Vec`, or things like function pointers or 57/// type `bool`, a struct like `Vec`, or things like function pointers or
@@ -125,7 +102,7 @@ pub enum TypeCtor {
125 /// fn foo() -> i32 { 1 } 102 /// fn foo() -> i32 { 1 }
126 /// let bar = foo; // bar: fn() -> i32 {foo} 103 /// let bar = foo; // bar: fn() -> i32 {foo}
127 /// ``` 104 /// ```
128 FnDef(CallableDef), 105 FnDef(CallableDefId),
129 106
130 /// A pointer to a function. Written as `fn() -> i32`. 107 /// A pointer to a function. Written as `fn() -> i32`.
131 /// 108 ///
@@ -135,7 +112,8 @@ pub enum TypeCtor {
135 /// fn foo() -> i32 { 1 } 112 /// fn foo() -> i32 { 1 }
136 /// let bar: fn() -> i32 = foo; 113 /// let bar: fn() -> i32 = foo;
137 /// ``` 114 /// ```
138 FnPtr { num_args: u16 }, 115 // FIXME make this a Ty variant like in Chalk
116 FnPtr { num_args: u16, is_varargs: bool },
139 117
140 /// The never type `!`. 118 /// The never type `!`.
141 Never, 119 Never,
@@ -162,19 +140,6 @@ pub enum TypeCtor {
162 Closure { def: DefWithBodyId, expr: ExprId }, 140 Closure { def: DefWithBodyId, expr: ExprId },
163} 141}
164 142
165/// This exists just for Chalk, because Chalk just has a single `StructId` where
166/// we have different kinds of ADTs, primitive types and special type
167/// constructors like tuples and function pointers.
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
169pub struct TypeCtorId(salsa::InternId);
170impl_intern_key!(TypeCtorId);
171
172/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
173/// we have different IDs for struct and enum variant constructors.
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
175pub struct CallableDefId(salsa::InternId);
176impl_intern_key!(CallableDefId);
177
178impl TypeCtor { 143impl TypeCtor {
179 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { 144 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
180 match self { 145 match self {
@@ -210,7 +175,7 @@ impl TypeCtor {
210 } 175 }
211 } 176 }
212 } 177 }
213 TypeCtor::FnPtr { num_args } => num_args as usize + 1, 178 TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
214 TypeCtor::Tuple { cardinality } => cardinality as usize, 179 TypeCtor::Tuple { cardinality } => cardinality as usize,
215 } 180 }
216 } 181 }
@@ -662,13 +627,27 @@ impl TypeWalk for GenericPredicate {
662 627
663/// Basically a claim (currently not validated / checked) that the contained 628/// Basically a claim (currently not validated / checked) that the contained
664/// type / trait ref contains no inference variables; any inference variables it 629/// type / trait ref contains no inference variables; any inference variables it
665/// contained have been replaced by bound variables, and `num_vars` tells us how 630/// contained have been replaced by bound variables, and `kinds` tells us how
666/// many there are. This is used to erase irrelevant differences between types 631/// many there are and whether they were normal or float/int variables. This is
667/// before using them in queries. 632/// used to erase irrelevant differences between types before using them in
633/// queries.
668#[derive(Debug, Clone, PartialEq, Eq, Hash)] 634#[derive(Debug, Clone, PartialEq, Eq, Hash)]
669pub struct Canonical<T> { 635pub struct Canonical<T> {
670 pub value: T, 636 pub value: T,
671 pub num_vars: usize, 637 pub kinds: Arc<[TyKind]>,
638}
639
640impl<T> Canonical<T> {
641 pub fn new(value: T, kinds: impl IntoIterator<Item = TyKind>) -> Self {
642 Self { value, kinds: kinds.into_iter().collect() }
643 }
644}
645
646#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
647pub enum TyKind {
648 General,
649 Integer,
650 Float,
672} 651}
673 652
674/// A function signature as seen by type inference: Several parameter types and 653/// A function signature as seen by type inference: Several parameter types and
@@ -676,19 +655,20 @@ pub struct Canonical<T> {
676#[derive(Clone, PartialEq, Eq, Debug)] 655#[derive(Clone, PartialEq, Eq, Debug)]
677pub struct FnSig { 656pub struct FnSig {
678 params_and_return: Arc<[Ty]>, 657 params_and_return: Arc<[Ty]>,
658 is_varargs: bool,
679} 659}
680 660
681/// A polymorphic function signature. 661/// A polymorphic function signature.
682pub type PolyFnSig = Binders<FnSig>; 662pub type PolyFnSig = Binders<FnSig>;
683 663
684impl FnSig { 664impl FnSig {
685 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig { 665 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> FnSig {
686 params.push(ret); 666 params.push(ret);
687 FnSig { params_and_return: params.into() } 667 FnSig { params_and_return: params.into(), is_varargs }
688 } 668 }
689 669
690 pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig { 670 pub fn from_fn_ptr_substs(substs: &Substs, is_varargs: bool) -> FnSig {
691 FnSig { params_and_return: Arc::clone(&substs.0) } 671 FnSig { params_and_return: Arc::clone(&substs.0), is_varargs }
692 } 672 }
693 673
694 pub fn params(&self) -> &[Ty] { 674 pub fn params(&self) -> &[Ty] {
@@ -733,7 +713,7 @@ impl Ty {
733 } 713 }
734 pub fn fn_ptr(sig: FnSig) -> Self { 714 pub fn fn_ptr(sig: FnSig) -> Self {
735 Ty::apply( 715 Ty::apply(
736 TypeCtor::FnPtr { num_args: sig.params().len() as u16 }, 716 TypeCtor::FnPtr { num_args: sig.params().len() as u16, is_varargs: sig.is_varargs },
737 Substs(sig.params_and_return), 717 Substs(sig.params_and_return),
738 ) 718 )
739 } 719 }
@@ -787,15 +767,6 @@ impl Ty {
787 } 767 }
788 } 768 }
789 769
790 pub fn as_callable(&self) -> Option<(CallableDef, &Substs)> {
791 match self {
792 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => {
793 Some((*callable_def, parameters))
794 }
795 _ => None,
796 }
797 }
798
799 pub fn is_never(&self) -> bool { 770 pub fn is_never(&self) -> bool {
800 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) 771 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
801 } 772 }
@@ -827,10 +798,12 @@ impl Ty {
827 } 798 }
828 } 799 }
829 800
830 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { 801 pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> {
831 match self { 802 match self {
832 Ty::Apply(a_ty) => match a_ty.ctor { 803 Ty::Apply(a_ty) => match a_ty.ctor {
833 TypeCtor::FnPtr { .. } => Some(FnSig::from_fn_ptr_substs(&a_ty.parameters)), 804 TypeCtor::FnPtr { is_varargs, .. } => {
805 Some(FnSig::from_fn_ptr_substs(&a_ty.parameters, is_varargs))
806 }
834 TypeCtor::FnDef(def) => { 807 TypeCtor::FnDef(def) => {
835 let sig = db.callable_item_signature(def); 808 let sig = db.callable_item_signature(def);
836 Some(sig.subst(&a_ty.parameters)) 809 Some(sig.subst(&a_ty.parameters))
@@ -877,7 +850,7 @@ impl Ty {
877 let data = (*it) 850 let data = (*it)
878 .as_ref() 851 .as_ref()
879 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 852 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
880 data.clone().subst(&opaque_ty.parameters) 853 data.subst(&opaque_ty.parameters)
881 }) 854 })
882 } 855 }
883 }; 856 };
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 3dc154e92..1eacc6f95 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -5,10 +5,7 @@
5//! - Building the type for an item: This happens through the `type_for_def` query. 5//! - Building the type for an item: This happens through the `type_for_def` query.
6//! 6//!
7//! This usually involves resolving names, collecting generic arguments etc. 7//! This usually involves resolving names, collecting generic arguments etc.
8use std::iter; 8use std::{iter, sync::Arc};
9use std::sync::Arc;
10
11use smallvec::SmallVec;
12 9
13use hir_def::{ 10use hir_def::{
14 adt::StructKind, 11 adt::StructKind,
@@ -24,6 +21,8 @@ use hir_def::{
24use hir_expand::name::Name; 21use hir_expand::name::Name;
25use ra_arena::map::ArenaMap; 22use ra_arena::map::ArenaMap;
26use ra_db::CrateId; 23use ra_db::CrateId;
24use smallvec::SmallVec;
25use stdx::impl_from;
27use test_utils::mark; 26use test_utils::mark;
28 27
29use crate::{ 28use crate::{
@@ -177,9 +176,12 @@ impl Ty {
177 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 176 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
178 } 177 }
179 TypeRef::Placeholder => Ty::Unknown, 178 TypeRef::Placeholder => Ty::Unknown,
180 TypeRef::Fn(params) => { 179 TypeRef::Fn(params, is_varargs) => {
181 let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect()); 180 let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect());
182 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) 181 Ty::apply(
182 TypeCtor::FnPtr { num_args: sig.len() as u16 - 1, is_varargs: *is_varargs },
183 sig,
184 )
183 } 185 }
184 TypeRef::DynTrait(bounds) => { 186 TypeRef::DynTrait(bounds) => {
185 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); 187 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
@@ -339,7 +341,7 @@ impl Ty {
339 let segment = remaining_segments.first().unwrap(); 341 let segment = remaining_segments.first().unwrap();
340 let found = associated_type_by_name_including_super_traits( 342 let found = associated_type_by_name_including_super_traits(
341 ctx.db, 343 ctx.db,
342 trait_ref.clone(), 344 trait_ref,
343 &segment.name, 345 &segment.name,
344 ); 346 );
345 match found { 347 match found {
@@ -720,8 +722,7 @@ fn assoc_type_bindings_from_type_bound<'a>(
720 None => return SmallVec::<[GenericPredicate; 1]>::new(), 722 None => return SmallVec::<[GenericPredicate; 1]>::new(),
721 Some(t) => t, 723 Some(t) => t,
722 }; 724 };
723 let projection_ty = 725 let projection_ty = ProjectionTy { associated_ty, parameters: super_trait_ref.substs };
724 ProjectionTy { associated_ty, parameters: super_trait_ref.substs.clone() };
725 let mut preds = SmallVec::with_capacity( 726 let mut preds = SmallVec::with_capacity(
726 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), 727 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
727 ); 728 );
@@ -767,11 +768,11 @@ fn count_impl_traits(type_ref: &TypeRef) -> usize {
767} 768}
768 769
769/// Build the signature of a callable item (function, struct or enum variant). 770/// Build the signature of a callable item (function, struct or enum variant).
770pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { 771pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
771 match def { 772 match def {
772 CallableDef::FunctionId(f) => fn_sig_for_fn(db, f), 773 CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
773 CallableDef::StructId(s) => fn_sig_for_struct_constructor(db, s), 774 CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
774 CallableDef::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), 775 CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
775 } 776 }
776} 777}
777 778
@@ -998,7 +999,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
998 let ret = Ty::from_hir(&ctx_ret, &data.ret_type); 999 let ret = Ty::from_hir(&ctx_ret, &data.ret_type);
999 let generics = generics(db.upcast(), def.into()); 1000 let generics = generics(db.upcast(), def.into());
1000 let num_binders = generics.len(); 1001 let num_binders = generics.len();
1001 Binders::new(num_binders, FnSig::from_params_and_return(params, ret)) 1002 Binders::new(num_binders, FnSig::from_params_and_return(params, ret, data.is_varargs))
1002} 1003}
1003 1004
1004/// Build the declared type of a function. This should not need to look at the 1005/// Build the declared type of a function. This should not need to look at the
@@ -1049,7 +1050,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
1049 let params = 1050 let params =
1050 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); 1051 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
1051 let ret = type_for_adt(db, def.into()); 1052 let ret = type_for_adt(db, def.into());
1052 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) 1053 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
1053} 1054}
1054 1055
1055/// Build the type of a tuple struct constructor. 1056/// Build the type of a tuple struct constructor.
@@ -1073,7 +1074,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
1073 let params = 1074 let params =
1074 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); 1075 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();