aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/Cargo.toml12
-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
31 files changed, 8279 insertions, 8870 deletions
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index d6df48db2..623ce261a 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_hir_ty" 3name = "ra_hir_ty"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -27,8 +28,13 @@ test_utils = { path = "../test_utils" }
27 28
28scoped-tls = "1" 29scoped-tls = "1"
29 30
30chalk-solve = { version = "0.15.0" } 31chalk-solve = { version = "0.19.0" }
31chalk-ir = { version = "0.15.0" } 32chalk-ir = { version = "0.19.0" }
33chalk-recursive = { version = "0.19.0" }
32 34
33[dev-dependencies] 35[dev-dependencies]
34insta = "0.16.0" 36expect = { path = "../expect" }
37
38tracing = "0.1"
39tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
40tracing-tree = { version = "0.1.4" }
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<_>>();
1075 let ret = type_for_adt(db, def.parent.into()); 1076 let ret = type_for_adt(db, def.parent.into());
1076 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) 1077 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
1077} 1078}
1078 1079
1079/// Build the type of a tuple enum variant constructor. 1080/// Build the type of a tuple enum variant constructor.
@@ -1106,31 +1107,31 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
1106} 1107}
1107 1108
1108#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 1109#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1109pub enum CallableDef { 1110pub enum CallableDefId {
1110 FunctionId(FunctionId), 1111 FunctionId(FunctionId),
1111 StructId(StructId), 1112 StructId(StructId),
1112 EnumVariantId(EnumVariantId), 1113 EnumVariantId(EnumVariantId),
1113} 1114}
1114impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId); 1115impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
1115 1116
1116impl CallableDef { 1117impl CallableDefId {
1117 pub fn krate(self, db: &dyn HirDatabase) -> CrateId { 1118 pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
1118 let db = db.upcast(); 1119 let db = db.upcast();
1119 match self { 1120 match self {
1120 CallableDef::FunctionId(f) => f.lookup(db).module(db), 1121 CallableDefId::FunctionId(f) => f.lookup(db).module(db),
1121 CallableDef::StructId(s) => s.lookup(db).container.module(db), 1122 CallableDefId::StructId(s) => s.lookup(db).container.module(db),
1122 CallableDef::EnumVariantId(e) => e.parent.lookup(db).container.module(db), 1123 CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container.module(db),
1123 } 1124 }
1124 .krate 1125 .krate
1125 } 1126 }
1126} 1127}
1127 1128
1128impl From<CallableDef> for GenericDefId { 1129impl From<CallableDefId> for GenericDefId {
1129 fn from(def: CallableDef) -> GenericDefId { 1130 fn from(def: CallableDefId) -> GenericDefId {
1130 match def { 1131 match def {
1131 CallableDef::FunctionId(f) => f.into(), 1132 CallableDefId::FunctionId(f) => f.into(),
1132 CallableDef::StructId(s) => s.into(), 1133 CallableDefId::StructId(s) => s.into(),
1133 CallableDef::EnumVariantId(e) => e.into(), 1134 CallableDefId::EnumVariantId(e) => e.into(),
1134 } 1135 }
1135 } 1136 }
1136} 1137}
@@ -1141,7 +1142,7 @@ pub enum TyDefId {
1141 AdtId(AdtId), 1142 AdtId(AdtId),
1142 TypeAliasId(TypeAliasId), 1143 TypeAliasId(TypeAliasId),
1143} 1144}
1144impl_froms!(TyDefId: BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId); 1145impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId);
1145 1146
1146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1147pub enum ValueTyDefId { 1148pub enum ValueTyDefId {
@@ -1151,7 +1152,7 @@ pub enum ValueTyDefId {
1151 ConstId(ConstId), 1152 ConstId(ConstId),
1152 StaticId(StaticId), 1153 StaticId(StaticId),
1153} 1154}
1154impl_froms!(ValueTyDefId: FunctionId, StructId, EnumVariantId, ConstId, StaticId); 1155impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
1155 1156
1156/// Build the declared type of an item. This depends on the namespace; e.g. for 1157/// Build the declared type of an item. This depends on the namespace; e.g. for
1157/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 1158/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
@@ -1216,7 +1217,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
1216} 1217}
1217 1218
1218pub(crate) fn return_type_impl_traits( 1219pub(crate) fn return_type_impl_traits(
1219 db: &impl HirDatabase, 1220 db: &dyn HirDatabase,
1220 def: hir_def::FunctionId, 1221 def: hir_def::FunctionId,
1221) -> Option<Arc<Binders<ReturnTypeImplTraits>>> { 1222) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
1222 // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe 1223 // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index c19519cf1..fb4b30a13 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -2,12 +2,14 @@
2//! For details about how this works in rustc, see the method lookup page in the 2//! For details about how this works in rustc, see the method lookup page in the
3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) 3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
4//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. 4//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
5use std::sync::Arc; 5use std::{iter, sync::Arc};
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
9 lang_item::LangItemTarget, type_ref::Mutability, AssocContainerId, AssocItemId, FunctionId, 9 builtin_type::{IntBitness, Signedness},
10 HasModule, ImplId, Lookup, TraitId, 10 lang_item::LangItemTarget,
11 type_ref::Mutability,
12 AssocContainerId, AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId,
11}; 13};
12use hir_expand::name::Name; 14use hir_expand::name::Name;
13use ra_db::CrateId; 15use ra_db::CrateId;
@@ -16,8 +18,12 @@ use rustc_hash::{FxHashMap, FxHashSet};
16 18
17use super::Substs; 19use super::Substs;
18use crate::{ 20use crate::{
19 autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, 21 autoderef,
20 Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 22 db::HirDatabase,
23 primitive::{FloatBitness, FloatTy, IntTy},
24 utils::all_super_traits,
25 ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind,
26 TypeCtor, TypeWalk,
21}; 27};
22 28
23/// This is used as a key for indexing impls. 29/// This is used as a key for indexing impls.
@@ -38,136 +44,187 @@ impl TyFingerprint {
38 } 44 }
39} 45}
40 46
41/// A queryable and mergeable collection of impls. 47pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
42#[derive(Debug, PartialEq, Eq)] 48 TyFingerprint::Apply(TypeCtor::Int(IntTy {
43pub struct CrateImplDefs { 49 signedness: Signedness::Unsigned,
44 inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>, 50 bitness: IntBitness::X8,
45 impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, 51 })),
52 TyFingerprint::Apply(TypeCtor::Int(IntTy {
53 signedness: Signedness::Unsigned,
54 bitness: IntBitness::X16,
55 })),
56 TyFingerprint::Apply(TypeCtor::Int(IntTy {
57 signedness: Signedness::Unsigned,
58 bitness: IntBitness::X32,
59 })),
60 TyFingerprint::Apply(TypeCtor::Int(IntTy {
61 signedness: Signedness::Unsigned,
62 bitness: IntBitness::X64,
63 })),
64 TyFingerprint::Apply(TypeCtor::Int(IntTy {
65 signedness: Signedness::Unsigned,
66 bitness: IntBitness::X128,
67 })),
68 TyFingerprint::Apply(TypeCtor::Int(IntTy {
69 signedness: Signedness::Unsigned,
70 bitness: IntBitness::Xsize,
71 })),
72 TyFingerprint::Apply(TypeCtor::Int(IntTy {
73 signedness: Signedness::Signed,
74 bitness: IntBitness::X8,
75 })),
76 TyFingerprint::Apply(TypeCtor::Int(IntTy {
77 signedness: Signedness::Signed,
78 bitness: IntBitness::X16,
79 })),
80 TyFingerprint::Apply(TypeCtor::Int(IntTy {
81 signedness: Signedness::Signed,
82 bitness: IntBitness::X32,
83 })),
84 TyFingerprint::Apply(TypeCtor::Int(IntTy {
85 signedness: Signedness::Signed,
86 bitness: IntBitness::X64,
87 })),
88 TyFingerprint::Apply(TypeCtor::Int(IntTy {
89 signedness: Signedness::Signed,
90 bitness: IntBitness::X128,
91 })),
92 TyFingerprint::Apply(TypeCtor::Int(IntTy {
93 signedness: Signedness::Signed,
94 bitness: IntBitness::Xsize,
95 })),
96];
97
98pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
99 TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })),
100 TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })),
101];
102
103/// Trait impls defined or available in some crate.
104#[derive(Debug, Eq, PartialEq)]
105pub struct TraitImpls {
106 // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
107 map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
46} 108}
47 109
48impl CrateImplDefs { 110impl TraitImpls {
49 pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { 111 pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
50 let _p = profile("impls_in_crate_query"); 112 let _p = profile("trait_impls_in_crate_query");
51 let mut res = CrateImplDefs { 113 let mut impls = Self { map: FxHashMap::default() };
52 inherent_impls: FxHashMap::default(),
53 impls_by_trait: FxHashMap::default(),
54 };
55 res.fill(db, krate);
56 114
57 Arc::new(res) 115 let crate_def_map = db.crate_def_map(krate);
116 for (_module_id, module_data) in crate_def_map.modules.iter() {
117 for impl_id in module_data.scope.impls() {
118 let target_trait = match db.impl_trait(impl_id) {
119 Some(tr) => tr.value.trait_,
120 None => continue,
121 };
122 let self_ty = db.impl_self_ty(impl_id);
123 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
124 impls
125 .map
126 .entry(target_trait)
127 .or_default()
128 .entry(self_ty_fp)
129 .or_default()
130 .push(impl_id);
131 }
132 }
133
134 Arc::new(impls)
58 } 135 }
59 136
60 /// Collects all impls from transitive dependencies of `krate` that may be used by `krate`. 137 pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
61 /// 138 let _p = profile("trait_impls_in_deps_query");
62 /// The full set of impls that can be used by `krate` is the returned map plus all the impls
63 /// from `krate` itself.
64 pub(crate) fn impls_from_deps_query(
65 db: &dyn HirDatabase,
66 krate: CrateId,
67 ) -> Arc<CrateImplDefs> {
68 let _p = profile("impls_from_deps_query");
69 let crate_graph = db.crate_graph(); 139 let crate_graph = db.crate_graph();
70 let mut res = CrateImplDefs { 140 let mut res = Self { map: FxHashMap::default() };
71 inherent_impls: FxHashMap::default(),
72 impls_by_trait: FxHashMap::default(),
73 };
74 141
75 // For each dependency, calculate `impls_from_deps` recursively, then add its own 142 for krate in crate_graph.transitive_deps(krate) {
76 // `impls_in_crate`. 143 res.merge(&db.trait_impls_in_crate(krate));
77 // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid
78 // wasting memory.
79 for dep in &crate_graph[krate].dependencies {
80 res.merge(&db.impls_from_deps(dep.crate_id));
81 res.merge(&db.impls_in_crate(dep.crate_id));
82 } 144 }
83 145
84 Arc::new(res) 146 Arc::new(res)
85 } 147 }
86 148
87 fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) {
88 let crate_def_map = db.crate_def_map(krate);
89 for (_module_id, module_data) in crate_def_map.modules.iter() {
90 for impl_id in module_data.scope.impls() {
91 match db.impl_trait(impl_id) {
92 Some(tr) => {
93 let self_ty = db.impl_self_ty(impl_id);
94 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
95 self.impls_by_trait
96 .entry(tr.value.trait_)
97 .or_default()
98 .entry(self_ty_fp)
99 .or_default()
100 .push(impl_id);
101 }
102 None => {
103 let self_ty = db.impl_self_ty(impl_id);
104 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) {
105 self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id);
106 }
107 }
108 }
109 }
110 }
111 }
112
113 fn merge(&mut self, other: &Self) { 149 fn merge(&mut self, other: &Self) {
114 for (fp, impls) in &other.inherent_impls { 150 for (trait_, other_map) in &other.map {
115 let vec = self.inherent_impls.entry(*fp).or_default(); 151 let map = self.map.entry(*trait_).or_default();
116 vec.extend(impls);
117 vec.sort();
118 vec.dedup();
119 }
120
121 for (trait_, other_map) in &other.impls_by_trait {
122 let map = self.impls_by_trait.entry(*trait_).or_default();
123 for (fp, impls) in other_map { 152 for (fp, impls) in other_map {
124 let vec = map.entry(*fp).or_default(); 153 let vec = map.entry(*fp).or_default();
125 vec.extend(impls); 154 vec.extend(impls);
126 vec.sort();
127 vec.dedup();
128 } 155 }
129 } 156 }
130 } 157 }
131 158
132 pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { 159 /// Queries all impls of the given trait.
133 let fingerprint = TyFingerprint::for_impl(ty); 160 pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
134 fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() 161 self.map
135 } 162 .get(&trait_)
136
137 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
138 self.impls_by_trait
139 .get(&tr)
140 .into_iter() 163 .into_iter()
141 .flat_map(|m| m.values().flat_map(|v| v.iter().copied())) 164 .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
142 } 165 }
143 166
144 pub fn lookup_impl_defs_for_trait_and_ty( 167 /// Queries all impls of `trait_` that may apply to `self_ty`.
168 pub fn for_trait_and_self_ty(
145 &self, 169 &self,
146 tr: TraitId, 170 trait_: TraitId,
147 fp: TyFingerprint, 171 self_ty: TyFingerprint,
148 ) -> impl Iterator<Item = ImplId> + '_ { 172 ) -> impl Iterator<Item = ImplId> + '_ {
149 self.impls_by_trait 173 self.map
150 .get(&tr) 174 .get(&trait_)
151 .and_then(|m| m.get(&Some(fp)))
152 .into_iter() 175 .into_iter()
153 .flatten() 176 .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty))))
154 .copied() 177 .flat_map(|v| v.iter().copied())
155 .chain( 178 }
156 self.impls_by_trait 179
157 .get(&tr) 180 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
158 .and_then(|m| m.get(&None)) 181 self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
159 .into_iter() 182 }
160 .flatten() 183}
161 .copied(), 184
162 ) 185/// Inherent impls defined in some crate.
186///
187/// Inherent impls can only be defined in the crate that also defines the self type of the impl
188/// (note that some primitives are considered to be defined by both libcore and liballoc).
189///
190/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
191/// single crate.
192#[derive(Debug, Eq, PartialEq)]
193pub struct InherentImpls {
194 map: FxHashMap<TyFingerprint, Vec<ImplId>>,
195}
196
197impl InherentImpls {
198 pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
199 let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default();
200
201 let crate_def_map = db.crate_def_map(krate);
202 for (_module_id, module_data) in crate_def_map.modules.iter() {
203 for impl_id in module_data.scope.impls() {
204 let data = db.impl_data(impl_id);
205 if data.target_trait.is_some() {
206 continue;
207 }
208
209 let self_ty = db.impl_self_ty(impl_id);
210 if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) {
211 map.entry(fp).or_default().push(impl_id);
212 }
213 }
214 }
215
216 Arc::new(Self { map })
217 }
218
219 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
220 match TyFingerprint::for_impl(self_ty) {
221 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
222 None => &[],
223 }
163 } 224 }
164 225
165 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { 226 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
166 self.inherent_impls 227 self.map.values().flat_map(|v| v.iter().copied())
167 .values()
168 .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
169 .flatten()
170 .copied()
171 } 228 }
172} 229}
173 230
@@ -377,7 +434,7 @@ fn iterate_method_candidates_with_autoref(
377 return true; 434 return true;
378 } 435 }
379 let refed = Canonical { 436 let refed = Canonical {
380 num_vars: deref_chain[0].num_vars, 437 kinds: deref_chain[0].kinds.clone(),
381 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), 438 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
382 }; 439 };
383 if iterate_method_candidates_by_receiver( 440 if iterate_method_candidates_by_receiver(
@@ -393,7 +450,7 @@ fn iterate_method_candidates_with_autoref(
393 return true; 450 return true;
394 } 451 }
395 let ref_muted = Canonical { 452 let ref_muted = Canonical {
396 num_vars: deref_chain[0].num_vars, 453 kinds: deref_chain[0].kinds.clone(),
397 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), 454 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
398 }; 455 };
399 if iterate_method_candidates_by_receiver( 456 if iterate_method_candidates_by_receiver(
@@ -524,9 +581,9 @@ fn iterate_inherent_methods(
524 None => return false, 581 None => return false,
525 }; 582 };
526 for krate in def_crates { 583 for krate in def_crates {
527 let impls = db.impls_in_crate(krate); 584 let impls = db.inherent_impls_in_crate(krate);
528 585
529 for impl_def in impls.lookup_impl_defs(&self_ty.value) { 586 for &impl_def in impls.for_self_ty(&self_ty.value) {
530 for &item in db.impl_data(impl_def).items.iter() { 587 for &item in db.impl_data(impl_def).items.iter() {
531 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { 588 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
532 continue; 589 continue;
@@ -612,18 +669,19 @@ pub(crate) fn inherent_impl_substs(
612 // we create a var for each type parameter of the impl; we need to keep in 669 // we create a var for each type parameter of the impl; we need to keep in
613 // mind here that `self_ty` might have vars of its own 670 // mind here that `self_ty` might have vars of its own
614 let vars = Substs::build_for_def(db, impl_id) 671 let vars = Substs::build_for_def(db, impl_id)
615 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.num_vars) 672 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len())
616 .build(); 673 .build();
617 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); 674 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
618 let self_ty_with_vars = 675 let mut kinds = self_ty.kinds.to_vec();
619 Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; 676 kinds.extend(iter::repeat(TyKind::General).take(vars.len()));
620 let substs = super::infer::unify(&self_ty_with_vars, self_ty); 677 let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) };
678 let substs = super::infer::unify(&tys);
621 // We only want the substs for the vars we added, not the ones from self_ty. 679 // We only want the substs for the vars we added, not the ones from self_ty.
622 // Also, if any of the vars we added are still in there, we replace them by 680 // Also, if any of the vars we added are still in there, we replace them by
623 // Unknown. I think this can only really happen if self_ty contained 681 // Unknown. I think this can only really happen if self_ty contained
624 // Unknown, and in that case we want the result to contain Unknown in those 682 // Unknown, and in that case we want the result to contain Unknown in those
625 // places again. 683 // places again.
626 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars)) 684 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len()))
627} 685}
628 686
629/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 687/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
@@ -683,15 +741,15 @@ fn generic_implements_goal(
683 trait_: TraitId, 741 trait_: TraitId,
684 self_ty: Canonical<Ty>, 742 self_ty: Canonical<Ty>,
685) -> Canonical<InEnvironment<super::Obligation>> { 743) -> Canonical<InEnvironment<super::Obligation>> {
686 let num_vars = self_ty.num_vars; 744 let mut kinds = self_ty.kinds.to_vec();
687 let substs = super::Substs::build_for_def(db, trait_) 745 let substs = super::Substs::build_for_def(db, trait_)
688 .push(self_ty.value) 746 .push(self_ty.value)
689 .fill_with_bound_vars(DebruijnIndex::INNERMOST, num_vars) 747 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
690 .build(); 748 .build();
691 let num_vars = substs.len() - 1 + self_ty.num_vars; 749 kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1));
692 let trait_ref = TraitRef { trait_, substs }; 750 let trait_ref = TraitRef { trait_, substs };
693 let obligation = super::Obligation::Trait(trait_ref); 751 let obligation = super::Obligation::Trait(trait_ref);
694 Canonical { num_vars, value: InEnvironment::new(env, obligation) } 752 Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
695} 753}
696 754
697fn autoderef_method_receiver( 755fn autoderef_method_receiver(
@@ -704,9 +762,9 @@ fn autoderef_method_receiver(
704 if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = 762 if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
705 deref_chain.last().map(|ty| &ty.value) 763 deref_chain.last().map(|ty| &ty.value)
706 { 764 {
707 let num_vars = deref_chain.last().unwrap().num_vars; 765 let kinds = deref_chain.last().unwrap().kinds.clone();
708 let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); 766 let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
709 deref_chain.push(Canonical { value: unsized_ty, num_vars }) 767 deref_chain.push(Canonical { value: unsized_ty, kinds })
710 } 768 }
711 deref_chain 769 deref_chain
712} 770}
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 0481a7b12..a1714ff0f 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -1,20 +1,16 @@
1//! Database used for testing `hir`. 1//! Database used for testing `hir`.
2 2
3use std::{ 3use std::{
4 panic, 4 fmt, panic,
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; 8use hir_def::{db::DefDatabase, ModuleId};
9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; 9use hir_expand::db::AstDatabase;
10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; 10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
11use rustc_hash::FxHashSet; 11use ra_syntax::TextRange;
12use stdx::format_to; 12use rustc_hash::{FxHashMap, FxHashSet};
13 13use test_utils::extract_annotations;
14use crate::{
15 db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator,
16 unsafe_validation::UnsafeValidator,
17};
18 14
19#[salsa::database( 15#[salsa::database(
20 ra_db::SourceDatabaseExtStorage, 16 ra_db::SourceDatabaseExtStorage,
@@ -24,10 +20,15 @@ use crate::{
24 hir_def::db::DefDatabaseStorage, 20 hir_def::db::DefDatabaseStorage,
25 crate::db::HirDatabaseStorage 21 crate::db::HirDatabaseStorage
26)] 22)]
27#[derive(Debug, Default)] 23#[derive(Default)]
28pub struct TestDB { 24pub struct TestDB {
29 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, 25 storage: salsa::Storage<TestDB>,
30 runtime: salsa::Runtime<TestDB>, 26 events: Mutex<Option<Vec<salsa::Event>>>,
27}
28impl fmt::Debug for TestDB {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_struct("TestDB").finish()
31 }
31} 32}
32 33
33impl Upcast<dyn AstDatabase> for TestDB { 34impl Upcast<dyn AstDatabase> for TestDB {
@@ -43,18 +44,10 @@ impl Upcast<dyn DefDatabase> for TestDB {
43} 44}
44 45
45impl salsa::Database for TestDB { 46impl salsa::Database for TestDB {
46 fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> { 47 fn salsa_event(&self, event: salsa::Event) {
47 &self.runtime
48 }
49
50 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
51 &mut self.runtime
52 }
53
54 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
55 let mut events = self.events.lock().unwrap(); 48 let mut events = self.events.lock().unwrap();
56 if let Some(events) = &mut *events { 49 if let Some(events) = &mut *events {
57 events.push(event()); 50 events.push(event);
58 } 51 }
59 } 52 }
60} 53}
@@ -62,8 +55,8 @@ impl salsa::Database for TestDB {
62impl salsa::ParallelDatabase for TestDB { 55impl salsa::ParallelDatabase for TestDB {
63 fn snapshot(&self) -> salsa::Snapshot<TestDB> { 56 fn snapshot(&self) -> salsa::Snapshot<TestDB> {
64 salsa::Snapshot::new(TestDB { 57 salsa::Snapshot::new(TestDB {
58 storage: self.storage.snapshot(),
65 events: Default::default(), 59 events: Default::default(),
66 runtime: self.runtime.snapshot(self),
67 }) 60 })
68 } 61 }
69} 62}
@@ -83,7 +76,7 @@ impl FileLoader for TestDB {
83} 76}
84 77
85impl TestDB { 78impl TestDB {
86 pub fn module_for_file(&self, file_id: FileId) -> ModuleId { 79 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
87 for &krate in self.relevant_crates(file_id).iter() { 80 for &krate in self.relevant_crates(file_id).iter() {
88 let crate_def_map = self.crate_def_map(krate); 81 let crate_def_map = self.crate_def_map(krate);
89 for (local_id, data) in crate_def_map.modules.iter() { 82 for (local_id, data) in crate_def_map.modules.iter() {
@@ -95,82 +88,32 @@ impl TestDB {
95 panic!("Can't find module for file") 88 panic!("Can't find module for file")
96 } 89 }
97 90
98 fn diag<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { 91 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
99 let crate_graph = self.crate_graph(); 92 let mut files = Vec::new();
100 for krate in crate_graph.iter() {
101 let crate_def_map = self.crate_def_map(krate);
102
103 let mut fns = Vec::new();
104 for (module_id, _) in crate_def_map.modules.iter() {
105 for decl in crate_def_map[module_id].scope.declarations() {
106 if let ModuleDefId::FunctionId(f) = decl {
107 fns.push(f)
108 }
109 }
110
111 for impl_id in crate_def_map[module_id].scope.impls() {
112 let impl_data = self.impl_data(impl_id);
113 for item in impl_data.items.iter() {
114 if let AssocItemId::FunctionId(f) = item {
115 fns.push(*f)
116 }
117 }
118 }
119 }
120
121 for f in fns {
122 let infer = self.infer(f.into());
123 let mut sink = DiagnosticSink::new(&mut cb);
124 infer.add_diagnostics(self, f, &mut sink);
125 let mut validator = ExprValidator::new(f, infer.clone(), &mut sink);
126 validator.validate_body(self);
127 let mut validator = UnsafeValidator::new(f, infer, &mut sink);
128 validator.validate_body(self);
129 }
130 }
131 }
132
133 pub fn diagnostics(&self) -> (String, u32) {
134 let mut buf = String::new();
135 let mut count = 0;
136 self.diag(|d| {
137 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
138 count += 1;
139 });
140 (buf, count)
141 }
142
143 /// Like `diagnostics`, but filtered for a single diagnostic.
144 pub fn diagnostic<D: Diagnostic>(&self) -> (String, u32) {
145 let mut buf = String::new();
146 let mut count = 0;
147 self.diag(|d| {
148 // We want to filter diagnostics by the particular one we are testing for, to
149 // avoid surprising results in tests.
150 if d.downcast_ref::<D>().is_some() {
151 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
152 count += 1;
153 };
154 });
155 (buf, count)
156 }
157
158 pub fn all_files(&self) -> Vec<FileId> {
159 let mut res = Vec::new();
160 let crate_graph = self.crate_graph(); 93 let crate_graph = self.crate_graph();
161 for krate in crate_graph.iter() { 94 for krate in crate_graph.iter() {
162 let crate_def_map = self.crate_def_map(krate); 95 let crate_def_map = self.crate_def_map(krate);
163 for (module_id, _) in crate_def_map.modules.iter() { 96 for (module_id, _) in crate_def_map.modules.iter() {
164 let file_id = crate_def_map[module_id].origin.file_id(); 97 let file_id = crate_def_map[module_id].origin.file_id();
165 res.extend(file_id) 98 files.extend(file_id)
166 } 99 }
167 } 100 }
168 res 101 files
102 .into_iter()
103 .filter_map(|file_id| {
104 let text = self.file_text(file_id);
105 let annotations = extract_annotations(&text);
106 if annotations.is_empty() {
107 return None;
108 }
109 Some((file_id, annotations))
110 })
111 .collect()
169 } 112 }
170} 113}
171 114
172impl TestDB { 115impl TestDB {
173 pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { 116 pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
174 *self.events.lock().unwrap() = Some(Vec::new()); 117 *self.events.lock().unwrap() = Some(Vec::new());
175 f(); 118 f();
176 self.events.lock().unwrap().take().unwrap() 119 self.events.lock().unwrap().take().unwrap()
@@ -184,7 +127,7 @@ impl TestDB {
184 // This pretty horrible, but `Debug` is the only way to inspect 127 // This pretty horrible, but `Debug` is the only way to inspect
185 // QueryDescriptor at the moment. 128 // QueryDescriptor at the moment.
186 salsa::EventKind::WillExecute { database_key } => { 129 salsa::EventKind::WillExecute { database_key } => {
187 Some(format!("{:?}", database_key)) 130 Some(format!("{:?}", database_key.debug(self)))
188 } 131 }
189 _ => None, 132 _ => None,
190 }) 133 })
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 5424e6bb1..016e689ff 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -10,6 +10,7 @@ mod display_source_code;
10 10
11use std::sync::Arc; 11use std::sync::Arc;
12 12
13use expect::Expect;
13use hir_def::{ 14use hir_def::{
14 body::{BodySourceMap, SyntheticSyntax}, 15 body::{BodySourceMap, SyntheticSyntax},
15 child_by_source::ChildBySource, 16 child_by_source::ChildBySource,
@@ -20,23 +21,34 @@ use hir_def::{
20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 21 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
21}; 22};
22use hir_expand::{db::AstDatabase, InFile}; 23use hir_expand::{db::AstDatabase, InFile};
23use insta::assert_snapshot; 24use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
24use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase};
25use ra_syntax::{ 25use ra_syntax::{
26 algo, 26 algo,
27 ast::{self, AstNode}, 27 ast::{self, AstNode},
28 SyntaxNode, 28 SyntaxNode,
29}; 29};
30use stdx::format_to; 30use stdx::format_to;
31use test_utils::extract_annotations;
32 31
33use crate::{ 32use crate::{
34 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, 33 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
35}; 34};
36 35
37// These tests compare the inference results for all expressions in a file 36// These tests compare the inference results for all expressions in a file
38// against snapshots of the expected results using insta. Use cargo-insta to 37// against snapshots of the expected results using expect. Use
39// update the snapshots. 38// `env UPDATE_EXPECT=1 cargo test -p ra_hir_ty` to update the snapshots.
39
40fn setup_tracing() -> tracing::subscriber::DefaultGuard {
41 use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
42 use tracing_tree::HierarchicalLayer;
43 let filter = EnvFilter::from_env("CHALK_DEBUG");
44 let layer = HierarchicalLayer::default()
45 .with_indent_lines(true)
46 .with_ansi(false)
47 .with_indent_amount(2)
48 .with_writer(std::io::stderr);
49 let subscriber = Registry::default().with(filter).with(layer);
50 tracing::subscriber::set_default(subscriber)
51}
40 52
41fn check_types(ra_fixture: &str) { 53fn check_types(ra_fixture: &str) {
42 check_types_impl(ra_fixture, false) 54 check_types_impl(ra_fixture, false)
@@ -47,11 +59,10 @@ fn check_types_source_code(ra_fixture: &str) {
47} 59}
48 60
49fn check_types_impl(ra_fixture: &str, display_source: bool) { 61fn check_types_impl(ra_fixture: &str, display_source: bool) {
62 let _tracing = setup_tracing();
50 let db = TestDB::with_files(ra_fixture); 63 let db = TestDB::with_files(ra_fixture);
51 let mut checked_one = false; 64 let mut checked_one = false;
52 for file_id in db.all_files() { 65 for (file_id, annotations) in db.extract_annotations() {
53 let text = db.parse(file_id).syntax_node().to_string();
54 let annotations = extract_annotations(&text);
55 for (range, expected) in annotations { 66 for (range, expected) in annotations {
56 let ty = type_at_range(&db, FileRange { file_id, range }); 67 let ty = type_at_range(&db, FileRange { file_id, range });
57 let actual = if display_source { 68 let actual = if display_source {
@@ -70,7 +81,7 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) {
70fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { 81fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
71 let file = db.parse(pos.file_id).ok().unwrap(); 82 let file = db.parse(pos.file_id).ok().unwrap();
72 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); 83 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap();
73 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 84 let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap();
74 let module = db.module_for_file(pos.file_id); 85 let module = db.module_for_file(pos.file_id);
75 let func = *module.child_by_source(db)[keys::FUNCTION] 86 let func = *module.child_by_source(db)[keys::FUNCTION]
76 .get(&InFile::new(pos.file_id.into(), fn_def)) 87 .get(&InFile::new(pos.file_id.into(), fn_def))
@@ -89,6 +100,7 @@ fn infer(ra_fixture: &str) -> String {
89} 100}
90 101
91fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { 102fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
103 let _tracing = setup_tracing();
92 let (db, file_id) = TestDB::with_single_file(content); 104 let (db, file_id) = TestDB::with_single_file(content);
93 105
94 let mut buf = String::new(); 106 let mut buf = String::new();
@@ -320,7 +332,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
320 " 332 "
321 .to_string(); 333 .to_string();
322 334
323 db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); 335 db.set_file_text(pos.file_id, Arc::new(new_text));
324 336
325 { 337 {
326 let events = db.log_executed(|| { 338 let events = db.log_executed(|| {
@@ -334,385 +346,14 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
334 } 346 }
335} 347}
336 348
337#[test] 349fn check_infer(ra_fixture: &str, expect: Expect) {
338fn no_such_field_diagnostics() { 350 let mut actual = infer(ra_fixture);
339 let diagnostics = TestDB::with_files( 351 actual.push('\n');
340 r" 352 expect.assert_eq(&actual);
341 //- /lib.rs
342 struct S { foo: i32, bar: () }
343 impl S {
344 fn new() -> S {
345 S {
346 foo: 92,
347 baz: 62,
348 }
349 }
350 }
351 ",
352 )
353 .diagnostics()
354 .0;
355
356 assert_snapshot!(diagnostics, @r###"
357 "baz: 62": no such field
358 "{\n foo: 92,\n baz: 62,\n }": Missing structure fields:
359 - bar
360 "###
361 );
362}
363
364#[test]
365fn no_such_field_with_feature_flag_diagnostics() {
366 let diagnostics = TestDB::with_files(
367 r#"
368 //- /lib.rs crate:foo cfg:feature=foo
369 struct MyStruct {
370 my_val: usize,
371 #[cfg(feature = "foo")]
372 bar: bool,
373 }
374
375 impl MyStruct {
376 #[cfg(feature = "foo")]
377 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
378 Self { my_val, bar }
379 }
380
381 #[cfg(not(feature = "foo"))]
382 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
383 Self { my_val }
384 }
385 }
386 "#,
387 )
388 .diagnostics()
389 .0;
390
391 assert_snapshot!(diagnostics, @r###""###);
392}
393
394#[test]
395fn no_such_field_enum_with_feature_flag_diagnostics() {
396 let diagnostics = TestDB::with_files(
397 r#"
398 //- /lib.rs crate:foo cfg:feature=foo
399 enum Foo {
400 #[cfg(not(feature = "foo"))]
401 Buz,
402 #[cfg(feature = "foo")]
403 Bar,
404 Baz
405 }
406
407 fn test_fn(f: Foo) {
408 match f {
409 Foo::Bar => {},
410 Foo::Baz => {},
411 }
412 }
413 "#,
414 )
415 .diagnostics()
416 .0;
417
418 assert_snapshot!(diagnostics, @r###""###);
419}
420
421#[test]
422fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
423 let diagnostics = TestDB::with_files(
424 r#"
425 //- /lib.rs crate:foo cfg:feature=foo
426 struct S {
427 #[cfg(feature = "foo")]
428 foo: u32,
429 #[cfg(not(feature = "foo"))]
430 bar: u32,
431 }
432
433 impl S {
434 #[cfg(feature = "foo")]
435 fn new(foo: u32) -> Self {
436 Self { foo }
437 }
438 #[cfg(not(feature = "foo"))]
439 fn new(bar: u32) -> Self {
440 Self { bar }
441 }
442 }
443 "#,
444 )
445 .diagnostics()
446 .0;
447
448 assert_snapshot!(diagnostics, @r###""###);
449}
450
451#[test]
452fn no_such_field_with_feature_flag_diagnostics_on_block_expr() {
453 let diagnostics = TestDB::with_files(
454 r#"
455 //- /lib.rs crate:foo cfg:feature=foo
456 struct S {
457 #[cfg(feature = "foo")]
458 foo: u32,
459 #[cfg(not(feature = "foo"))]
460 bar: u32,
461 }
462
463 impl S {
464 fn new(bar: u32) -> Self {
465 #[cfg(feature = "foo")]
466 {
467 Self { foo: bar }
468 }
469 #[cfg(not(feature = "foo"))]
470 {
471 Self { bar }
472 }
473 }
474 }
475 "#,
476 )
477 .diagnostics()
478 .0;
479
480 assert_snapshot!(diagnostics, @r###""###);
481}
482
483#[test]
484fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
485 let diagnostics = TestDB::with_files(
486 r#"
487 //- /lib.rs crate:foo cfg:feature=foo
488 struct S {
489 #[cfg(feature = "foo")]
490 foo: u32,
491 #[cfg(not(feature = "foo"))]
492 bar: u32,
493 }
494
495 impl S {
496 fn new(val: u32) -> Self {
497 Self {
498 #[cfg(feature = "foo")]
499 foo: val,
500 #[cfg(not(feature = "foo"))]
501 bar: val,
502 }
503 }
504 }
505 "#,
506 )
507 .diagnostics()
508 .0;
509
510 assert_snapshot!(diagnostics, @r###""###);
511}
512
513#[test]
514fn missing_record_pat_field_diagnostic() {
515 let diagnostics = TestDB::with_files(
516 r"
517 //- /lib.rs
518 struct S { foo: i32, bar: () }
519 fn baz(s: S) {
520 let S { foo: _ } = s;
521 }
522 ",
523 )
524 .diagnostics()
525 .0;
526
527 assert_snapshot!(diagnostics, @r###"
528 "{ foo: _ }": Missing structure fields:
529 - bar
530 "###
531 );
532}
533
534#[test]
535fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
536 let diagnostics = TestDB::with_files(
537 r"
538 //- /lib.rs
539 struct S { foo: i32, bar: () }
540 fn baz(s: S) -> i32 {
541 match s {
542 S { foo, .. } => foo,
543 }
544 }
545 ",
546 )
547 .diagnostics()
548 .0;
549
550 assert_snapshot!(diagnostics, @"");
551}
552
553#[test]
554fn missing_unsafe_diagnostic_with_raw_ptr() {
555 let diagnostics = TestDB::with_files(
556 r"
557//- /lib.rs
558fn missing_unsafe() {
559 let x = &5 as *const usize;
560 let y = *x;
561}
562",
563 )
564 .diagnostics()
565 .0;
566
567 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
568}
569
570#[test]
571fn missing_unsafe_diagnostic_with_unsafe_call() {
572 let diagnostics = TestDB::with_files(
573 r"
574//- /lib.rs
575unsafe fn unsafe_fn() {
576 let x = &5 as *const usize;
577 let y = *x;
578}
579
580fn missing_unsafe() {
581 unsafe_fn();
582}
583",
584 )
585 .diagnostics()
586 .0;
587
588 assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
589}
590
591#[test]
592fn missing_unsafe_diagnostic_with_unsafe_method_call() {
593 let diagnostics = TestDB::with_files(
594 r"
595struct HasUnsafe;
596
597impl HasUnsafe {
598 unsafe fn unsafe_fn(&self) {
599 let x = &5 as *const usize;
600 let y = *x;
601 }
602}
603
604fn missing_unsafe() {
605 HasUnsafe.unsafe_fn();
606} 353}
607 354
608", 355fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) {
609 ) 356 let mut actual = infer_with_mismatches(ra_fixture, true);
610 .diagnostics() 357 actual.push('\n');
611 .0; 358 expect.assert_eq(&actual);
612
613 assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
614}
615
616#[test]
617fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() {
618 let diagnostics = TestDB::with_files(
619 r"
620fn nothing_to_see_move_along() {
621 let x = &5 as *const usize;
622 unsafe {
623 let y = *x;
624 }
625}
626",
627 )
628 .diagnostics()
629 .0;
630
631 assert_snapshot!(diagnostics, @"");
632}
633
634#[test]
635fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() {
636 let diagnostics = TestDB::with_files(
637 r"
638fn nothing_to_see_move_along() {
639 let x = &5 as *const usize;
640 unsafe {
641 let y = *x;
642 }
643 let z = *x;
644}
645",
646 )
647 .diagnostics()
648 .0;
649
650 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
651}
652
653#[test]
654fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() {
655 let diagnostics = TestDB::with_files(
656 r"
657unsafe fn unsafe_fn() {
658 let x = &5 as *const usize;
659 let y = *x;
660}
661
662fn nothing_to_see_move_along() {
663 unsafe {
664 unsafe_fn();
665 }
666}
667",
668 )
669 .diagnostics()
670 .0;
671
672 assert_snapshot!(diagnostics, @"");
673}
674
675#[test]
676fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() {
677 let diagnostics = TestDB::with_files(
678 r"
679struct HasUnsafe;
680
681impl HasUnsafe {
682 unsafe fn unsafe_fn() {
683 let x = &5 as *const usize;
684 let y = *x;
685 }
686}
687
688fn nothing_to_see_move_along() {
689 unsafe {
690 HasUnsafe.unsafe_fn();
691 }
692}
693
694",
695 )
696 .diagnostics()
697 .0;
698
699 assert_snapshot!(diagnostics, @"");
700}
701
702#[test]
703fn break_outside_of_loop() {
704 let diagnostics = TestDB::with_files(
705 r"
706 //- /lib.rs
707 fn foo() {
708 break;
709 }
710 ",
711 )
712 .diagnostics()
713 .0;
714
715 assert_snapshot!(diagnostics, @r###""break": break outside of loop
716 "###
717 );
718} 359}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 136d28a91..17efd75cb 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,345 +1,381 @@
1use insta::assert_snapshot; 1use expect::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::infer_with_mismatches; 4use super::{check_infer, check_infer_with_mismatches};
5
6// Infer with some common definitions and impls.
7fn infer(source: &str) -> String {
8 let defs = r#"
9 #[lang = "sized"]
10 pub trait Sized {}
11 #[lang = "unsize"]
12 pub trait Unsize<T: ?Sized> {}
13 #[lang = "coerce_unsized"]
14 pub trait CoerceUnsized<T> {}
15
16 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
17 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
18 "#;
19
20 // Append to the end to keep positions unchanged.
21 super::infer(&format!("{}{}", source, defs))
22}
23 5
24#[test] 6#[test]
25fn infer_block_expr_type_mismatch() { 7fn infer_block_expr_type_mismatch() {
26 assert_snapshot!( 8 check_infer(
27 infer(r#" 9 r"
28fn test() { 10 fn test() {
29 let a: i32 = { 1i64 }; 11 let a: i32 = { 1i64 };
30} 12 }
31"#), 13 ",
32 @r###" 14 expect![[r"
33 10..40 '{ ...4 }; }': () 15 10..40 '{ ...4 }; }': ()
34 20..21 'a': i32 16 20..21 'a': i32
35 29..37 '{ 1i64 }': i64 17 29..37 '{ 1i64 }': i64
36 31..35 '1i64': i64 18 31..35 '1i64': i64
37 "###); 19 "]],
20 );
38} 21}
39 22
40#[test] 23#[test]
41fn coerce_places() { 24fn coerce_places() {
42 assert_snapshot!( 25 check_infer(
43 infer(r#" 26 r#"
44struct S<T> { a: T } 27 struct S<T> { a: T }
45 28
46fn f<T>(_: &[T]) -> T { loop {} } 29 fn f<T>(_: &[T]) -> T { loop {} }
47fn g<T>(_: S<&[T]>) -> T { loop {} } 30 fn g<T>(_: S<&[T]>) -> T { loop {} }
48 31
49fn gen<T>() -> *mut [T; 2] { loop {} } 32 fn gen<T>() -> *mut [T; 2] { loop {} }
50fn test1<U>() -> *mut [U] { 33 fn test1<U>() -> *mut [U] {
51 gen() 34 gen()
52} 35 }
53 36
54fn test2() { 37 fn test2() {
55 let arr: &[u8; 1] = &[1]; 38 let arr: &[u8; 1] = &[1];
56 39
57 let a: &[_] = arr; 40 let a: &[_] = arr;
58 let b = f(arr); 41 let b = f(arr);
59 let c: &[_] = { arr }; 42 let c: &[_] = { arr };
60 let d = g(S { a: arr }); 43 let d = g(S { a: arr });
61 let e: [&[_]; 1] = [arr]; 44 let e: [&[_]; 1] = [arr];
62 let f: [&[_]; 2] = [arr; 2]; 45 let f: [&[_]; 2] = [arr; 2];
63 let g: (&[_], &[_]) = (arr, arr); 46 let g: (&[_], &[_]) = (arr, arr);
64} 47 }
65"#), 48
66 @r###" 49 #[lang = "sized"]
67 30..31 '_': &[T] 50 pub trait Sized {}
68 44..55 '{ loop {} }': T 51 #[lang = "unsize"]
69 46..53 'loop {}': ! 52 pub trait Unsize<T: ?Sized> {}
70 51..53 '{}': () 53 #[lang = "coerce_unsized"]
71 64..65 '_': S<&[T]> 54 pub trait CoerceUnsized<T> {}
72 81..92 '{ loop {} }': T 55
73 83..90 'loop {}': ! 56 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
74 88..90 '{}': () 57 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
75 121..132 '{ loop {} }': *mut [T; _] 58 "#,
76 123..130 'loop {}': ! 59 expect![[r"
77 128..130 '{}': () 60 30..31 '_': &[T]
78 159..172 '{ gen() }': *mut [U] 61 44..55 '{ loop {} }': T
79 165..168 'gen': fn gen<U>() -> *mut [U; _] 62 46..53 'loop {}': !
80 165..170 'gen()': *mut [U; _] 63 51..53 '{}': ()
81 185..419 '{ ...rr); }': () 64 64..65 '_': S<&[T]>
82 195..198 'arr': &[u8; _] 65 81..92 '{ loop {} }': T
83 211..215 '&[1]': &[u8; _] 66 83..90 'loop {}': !
84 212..215 '[1]': [u8; _] 67 88..90 '{}': ()
85 213..214 '1': u8 68 121..132 '{ loop {} }': *mut [T; _]
86 226..227 'a': &[u8] 69 123..130 'loop {}': !
87 236..239 'arr': &[u8; _] 70 128..130 '{}': ()
88 249..250 'b': u8 71 159..172 '{ gen() }': *mut [U]
89 253..254 'f': fn f<u8>(&[u8]) -> u8 72 165..168 'gen': fn gen<U>() -> *mut [U; _]
90 253..259 'f(arr)': u8 73 165..170 'gen()': *mut [U; _]
91 255..258 'arr': &[u8; _] 74 185..419 '{ ...rr); }': ()
92 269..270 'c': &[u8] 75 195..198 'arr': &[u8; _]
93 279..286 '{ arr }': &[u8] 76 211..215 '&[1]': &[u8; _]
94 281..284 'arr': &[u8; _] 77 212..215 '[1]': [u8; _]
95 296..297 'd': u8 78 213..214 '1': u8
96 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 79 226..227 'a': &[u8]
97 300..315 'g(S { a: arr })': u8 80 236..239 'arr': &[u8; _]
98 302..314 'S { a: arr }': S<&[u8]> 81 249..250 'b': u8
99 309..312 'arr': &[u8; _] 82 253..254 'f': fn f<u8>(&[u8]) -> u8
100 325..326 'e': [&[u8]; _] 83 253..259 'f(arr)': u8
101 340..345 '[arr]': [&[u8]; _] 84 255..258 'arr': &[u8; _]
102 341..344 'arr': &[u8; _] 85 269..270 'c': &[u8]
103 355..356 'f': [&[u8]; _] 86 279..286 '{ arr }': &[u8]
104 370..378 '[arr; 2]': [&[u8]; _] 87 281..284 'arr': &[u8; _]
105 371..374 'arr': &[u8; _] 88 296..297 'd': u8
106 376..377 '2': usize 89 300..301 'g': fn g<u8>(S<&[u8]>) -> u8
107 388..389 'g': (&[u8], &[u8]) 90 300..315 'g(S { a: arr })': u8
108 406..416 '(arr, arr)': (&[u8], &[u8]) 91 302..314 'S { a: arr }': S<&[u8]>
109 407..410 'arr': &[u8; _] 92 309..312 'arr': &[u8; _]
110 412..415 'arr': &[u8; _] 93 325..326 'e': [&[u8]; _]
111 "### 94 340..345 '[arr]': [&[u8]; _]
95 341..344 'arr': &[u8; _]
96 355..356 'f': [&[u8]; _]
97 370..378 '[arr; 2]': [&[u8]; _]
98 371..374 'arr': &[u8; _]
99 376..377 '2': usize
100 388..389 'g': (&[u8], &[u8])
101 406..416 '(arr, arr)': (&[u8], &[u8])
102 407..410 'arr': &[u8; _]
103 412..415 'arr': &[u8; _]
104 "]],
112 ); 105 );
113} 106}
114 107
115#[test] 108#[test]
116fn infer_let_stmt_coerce() { 109fn infer_let_stmt_coerce() {
117 assert_snapshot!( 110 check_infer(
118 infer(r#" 111 r"
119fn test() { 112 fn test() {
120 let x: &[isize] = &[1]; 113 let x: &[isize] = &[1];
121 let x: *const [isize] = &[1]; 114 let x: *const [isize] = &[1];
122} 115 }
123"#), 116 ",
124 @r###" 117 expect![[r"
125 10..75 '{ ...[1]; }': () 118 10..75 '{ ...[1]; }': ()
126 20..21 'x': &[isize] 119 20..21 'x': &[isize]
127 34..38 '&[1]': &[isize; _] 120 34..38 '&[1]': &[isize; _]
128 35..38 '[1]': [isize; _] 121 35..38 '[1]': [isize; _]
129 36..37 '1': isize 122 36..37 '1': isize
130 48..49 'x': *const [isize] 123 48..49 'x': *const [isize]
131 68..72 '&[1]': &[isize; _] 124 68..72 '&[1]': &[isize; _]
132 69..72 '[1]': [isize; _] 125 69..72 '[1]': [isize; _]
133 70..71 '1': isize 126 70..71 '1': isize
134 "###); 127 "]],
128 );
135} 129}
136 130
137#[test] 131#[test]
138fn infer_custom_coerce_unsized() { 132fn infer_custom_coerce_unsized() {
139 assert_snapshot!( 133 check_infer(
140 infer(r#" 134 r#"
141struct A<T: ?Sized>(*const T); 135 struct A<T: ?Sized>(*const T);
142struct B<T: ?Sized>(*const T); 136 struct B<T: ?Sized>(*const T);
143struct C<T: ?Sized> { inner: *const T } 137 struct C<T: ?Sized> { inner: *const T }
144 138
145impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} 139 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {}
146impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} 140 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {}
147 141
148fn foo1<T>(x: A<[T]>) -> A<[T]> { x } 142 fn foo1<T>(x: A<[T]>) -> A<[T]> { x }
149fn foo2<T>(x: B<[T]>) -> B<[T]> { x } 143 fn foo2<T>(x: B<[T]>) -> B<[T]> { x }
150fn foo3<T>(x: C<[T]>) -> C<[T]> { x } 144 fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
151 145
152fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { 146 fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) {
153 let d = foo1(a); 147 let d = foo1(a);
154 let e = foo2(b); 148 let e = foo2(b);
155 let f = foo3(c); 149 let f = foo3(c);
156} 150 }
157"#), 151
158 @r###" 152
159 257..258 'x': A<[T]> 153 #[lang = "sized"]
160 278..283 '{ x }': A<[T]> 154 pub trait Sized {}
161 280..281 'x': A<[T]> 155 #[lang = "unsize"]
162 295..296 'x': B<[T]> 156 pub trait Unsize<T: ?Sized> {}
163 316..321 '{ x }': B<[T]> 157 #[lang = "coerce_unsized"]
164 318..319 'x': B<[T]> 158 pub trait CoerceUnsized<T> {}
165 333..334 'x': C<[T]> 159
166 354..359 '{ x }': C<[T]> 160 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
167 356..357 'x': C<[T]> 161 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
168 369..370 'a': A<[u8; _]> 162 "#,
169 384..385 'b': B<[u8; _]> 163 expect![[r"
170 399..400 'c': C<[u8; _]> 164 257..258 'x': A<[T]>
171 414..480 '{ ...(c); }': () 165 278..283 '{ x }': A<[T]>
172 424..425 'd': A<[{unknown}]> 166 280..281 'x': A<[T]>
173 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> 167 295..296 'x': B<[T]>
174 428..435 'foo1(a)': A<[{unknown}]> 168 316..321 '{ x }': B<[T]>
175 433..434 'a': A<[u8; _]> 169 318..319 'x': B<[T]>
176 445..446 'e': B<[u8]> 170 333..334 'x': C<[T]>
177 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> 171 354..359 '{ x }': C<[T]>
178 449..456 'foo2(b)': B<[u8]> 172 356..357 'x': C<[T]>
179 454..455 'b': B<[u8; _]> 173 369..370 'a': A<[u8; _]>
180 466..467 'f': C<[u8]> 174 384..385 'b': B<[u8; _]>
181 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> 175 399..400 'c': C<[u8; _]>
182 470..477 'foo3(c)': C<[u8]> 176 414..480 '{ ...(c); }': ()
183 475..476 'c': C<[u8; _]> 177 424..425 'd': A<[{unknown}]>
184 "### 178 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]>
179 428..435 'foo1(a)': A<[{unknown}]>
180 433..434 'a': A<[u8; _]>
181 445..446 'e': B<[u8]>
182 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]>
183 449..456 'foo2(b)': B<[u8]>
184 454..455 'b': B<[u8; _]>
185 466..467 'f': C<[u8]>
186 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]>
187 470..477 'foo3(c)': C<[u8]>
188 475..476 'c': C<[u8; _]>
189 "]],
185 ); 190 );
186} 191}
187 192
188#[test] 193#[test]
189fn infer_if_coerce() { 194fn infer_if_coerce() {
190 assert_snapshot!( 195 check_infer(
191 infer(r#" 196 r#"
192fn foo<T>(x: &[T]) -> &[T] { loop {} } 197 fn foo<T>(x: &[T]) -> &[T] { loop {} }
193fn test() { 198 fn test() {
194 let x = if true { 199 let x = if true {
195 foo(&[1]) 200 foo(&[1])
196 } else { 201 } else {
197 &[1] 202 &[1]
198 }; 203 };
199} 204 }
200"#), 205
201 @r###" 206
202 10..11 'x': &[T] 207 #[lang = "sized"]
203 27..38 '{ loop {} }': &[T] 208 pub trait Sized {}
204 29..36 'loop {}': ! 209 #[lang = "unsize"]
205 34..36 '{}': () 210 pub trait Unsize<T: ?Sized> {}
206 49..125 '{ ... }; }': () 211 "#,
207 59..60 'x': &[i32] 212 expect![[r"
208 63..122 'if tru... }': &[i32] 213 10..11 'x': &[T]
209 66..70 'true': bool 214 27..38 '{ loop {} }': &[T]
210 71..96 '{ ... }': &[i32] 215 29..36 'loop {}': !
211 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] 216 34..36 '{}': ()
212 81..90 'foo(&[1])': &[i32] 217 49..125 '{ ... }; }': ()
213 85..89 '&[1]': &[i32; _] 218 59..60 'x': &[i32]
214 86..89 '[1]': [i32; _] 219 63..122 'if tru... }': &[i32]
215 87..88 '1': i32 220 66..70 'true': bool
216 102..122 '{ ... }': &[i32; _] 221 71..96 '{ ... }': &[i32]
217 112..116 '&[1]': &[i32; _] 222 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32]
218 113..116 '[1]': [i32; _] 223 81..90 'foo(&[1])': &[i32]
219 114..115 '1': i32 224 85..89 '&[1]': &[i32; _]
220 "### 225 86..89 '[1]': [i32; _]
226 87..88 '1': i32
227 102..122 '{ ... }': &[i32; _]
228 112..116 '&[1]': &[i32; _]
229 113..116 '[1]': [i32; _]
230 114..115 '1': i32
231 "]],
221 ); 232 );
222} 233}
223 234
224#[test] 235#[test]
225fn infer_if_else_coerce() { 236fn infer_if_else_coerce() {
226 assert_snapshot!( 237 check_infer(
227 infer(r#" 238 r#"
228fn foo<T>(x: &[T]) -> &[T] { loop {} } 239 fn foo<T>(x: &[T]) -> &[T] { loop {} }
229fn test() { 240 fn test() {
230 let x = if true { 241 let x = if true {
231 &[1] 242 &[1]
232 } else { 243 } else {
233 foo(&[1]) 244 foo(&[1])
234 }; 245 };
235} 246 }
236"#), 247
237 @r###" 248 #[lang = "sized"]
238 10..11 'x': &[T] 249 pub trait Sized {}
239 27..38 '{ loop {} }': &[T] 250 #[lang = "unsize"]
240 29..36 'loop {}': ! 251 pub trait Unsize<T: ?Sized> {}
241 34..36 '{}': () 252 #[lang = "coerce_unsized"]
242 49..125 '{ ... }; }': () 253 pub trait CoerceUnsized<T> {}
243 59..60 'x': &[i32] 254
244 63..122 'if tru... }': &[i32] 255 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
245 66..70 'true': bool 256 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
246 71..91 '{ ... }': &[i32; _] 257 "#,
247 81..85 '&[1]': &[i32; _] 258 expect![[r"
248 82..85 '[1]': [i32; _] 259 10..11 'x': &[T]
249 83..84 '1': i32 260 27..38 '{ loop {} }': &[T]
250 97..122 '{ ... }': &[i32] 261 29..36 'loop {}': !
251 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] 262 34..36 '{}': ()
252 107..116 'foo(&[1])': &[i32] 263 49..125 '{ ... }; }': ()
253 111..115 '&[1]': &[i32; _] 264 59..60 'x': &[i32]
254 112..115 '[1]': [i32; _] 265 63..122 'if tru... }': &[i32]
255 113..114 '1': i32 266 66..70 'true': bool
256 "### 267 71..91 '{ ... }': &[i32; _]
257 ); 268 81..85 '&[1]': &[i32; _]
269 82..85 '[1]': [i32; _]
270 83..84 '1': i32
271 97..122 '{ ... }': &[i32]
272 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32]
273 107..116 'foo(&[1])': &[i32]
274 111..115 '&[1]': &[i32; _]
275 112..115 '[1]': [i32; _]
276 113..114 '1': i32
277 "]],
278 )
258} 279}
259 280
260#[test] 281#[test]
261fn infer_match_first_coerce() { 282fn infer_match_first_coerce() {
262 assert_snapshot!( 283 check_infer(
263 infer(r#" 284 r#"
264fn foo<T>(x: &[T]) -> &[T] { loop {} } 285 fn foo<T>(x: &[T]) -> &[T] { loop {} }
265fn test(i: i32) { 286 fn test(i: i32) {
266 let x = match i { 287 let x = match i {
267 2 => foo(&[2]), 288 2 => foo(&[2]),
268 1 => &[1], 289 1 => &[1],
269 _ => &[3], 290 _ => &[3],
270 }; 291 };
271} 292 }
272"#), 293
273 @r###" 294 #[lang = "sized"]
274 10..11 'x': &[T] 295 pub trait Sized {}
275 27..38 '{ loop {} }': &[T] 296 #[lang = "unsize"]
276 29..36 'loop {}': ! 297 pub trait Unsize<T: ?Sized> {}
277 34..36 '{}': () 298 "#,
278 47..48 'i': i32 299 expect![[r"
279 55..149 '{ ... }; }': () 300 10..11 'x': &[T]
280 65..66 'x': &[i32] 301 27..38 '{ loop {} }': &[T]
281 69..146 'match ... }': &[i32] 302 29..36 'loop {}': !
282 75..76 'i': i32 303 34..36 '{}': ()
283 87..88 '2': i32 304 47..48 'i': i32
284 87..88 '2': i32 305 55..149 '{ ... }; }': ()
285 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] 306 65..66 'x': &[i32]
286 92..101 'foo(&[2])': &[i32] 307 69..146 'match ... }': &[i32]
287 96..100 '&[2]': &[i32; _] 308 75..76 'i': i32
288 97..100 '[2]': [i32; _] 309 87..88 '2': i32
289 98..99 '2': i32 310 87..88 '2': i32
290 111..112 '1': i32 311 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32]
291 111..112 '1': i32 312 92..101 'foo(&[2])': &[i32]
292 116..120 '&[1]': &[i32; _] 313 96..100 '&[2]': &[i32; _]
293 117..120 '[1]': [i32; _] 314 97..100 '[2]': [i32; _]
294 118..119 '1': i32 315 98..99 '2': i32
295 130..131 '_': i32 316 111..112 '1': i32
296 135..139 '&[3]': &[i32; _] 317 111..112 '1': i32
297 136..139 '[3]': [i32; _] 318 116..120 '&[1]': &[i32; _]
298 137..138 '3': i32 319 117..120 '[1]': [i32; _]
299 "### 320 118..119 '1': i32
321 130..131 '_': i32
322 135..139 '&[3]': &[i32; _]
323 136..139 '[3]': [i32; _]
324 137..138 '3': i32
325 "]],
300 ); 326 );
301} 327}
302 328
303#[test] 329#[test]
304fn infer_match_second_coerce() { 330fn infer_match_second_coerce() {
305 assert_snapshot!( 331 check_infer(
306 infer(r#" 332 r#"
307fn foo<T>(x: &[T]) -> &[T] { loop {} } 333 fn foo<T>(x: &[T]) -> &[T] { loop {} }
308fn test(i: i32) { 334 fn test(i: i32) {
309 let x = match i { 335 let x = match i {
310 1 => &[1], 336 1 => &[1],
311 2 => foo(&[2]), 337 2 => foo(&[2]),
312 _ => &[3], 338 _ => &[3],
313 }; 339 };
314} 340 }
315"#), 341
316 @r###" 342 #[lang = "sized"]
317 10..11 'x': &[T] 343 pub trait Sized {}
318 27..38 '{ loop {} }': &[T] 344 #[lang = "unsize"]
319 29..36 'loop {}': ! 345 pub trait Unsize<T: ?Sized> {}
320 34..36 '{}': () 346 #[lang = "coerce_unsized"]
321 47..48 'i': i32 347 pub trait CoerceUnsized<T> {}
322 55..149 '{ ... }; }': () 348
323 65..66 'x': &[i32] 349 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
324 69..146 'match ... }': &[i32] 350 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
325 75..76 'i': i32 351 "#,
326 87..88 '1': i32 352 expect![[r"
327 87..88 '1': i32 353 10..11 'x': &[T]
328 92..96 '&[1]': &[i32; _] 354 27..38 '{ loop {} }': &[T]
329 93..96 '[1]': [i32; _] 355 29..36 'loop {}': !
330 94..95 '1': i32 356 34..36 '{}': ()
331 106..107 '2': i32 357 47..48 'i': i32
332 106..107 '2': i32 358 55..149 '{ ... }; }': ()
333 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] 359 65..66 'x': &[i32]
334 111..120 'foo(&[2])': &[i32] 360 69..146 'match ... }': &[i32]
335 115..119 '&[2]': &[i32; _] 361 75..76 'i': i32
336 116..119 '[2]': [i32; _] 362 87..88 '1': i32
337 117..118 '2': i32 363 87..88 '1': i32
338 130..131 '_': i32 364 92..96 '&[1]': &[i32; _]
339 135..139 '&[3]': &[i32; _] 365 93..96 '[1]': [i32; _]
340 136..139 '[3]': [i32; _] 366 94..95 '1': i32
341 137..138 '3': i32 367 106..107 '2': i32
342 "### 368 106..107 '2': i32
369 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32]
370 111..120 'foo(&[2])': &[i32]
371 115..119 '&[2]': &[i32; _]
372 116..119 '[2]': [i32; _]
373 117..118 '2': i32
374 130..131 '_': i32
375 135..139 '&[3]': &[i32; _]
376 136..139 '[3]': [i32; _]
377 137..138 '3': i32
378 "]],
343 ); 379 );
344} 380}
345 381
@@ -347,405 +383,453 @@ fn test(i: i32) {
347fn coerce_merge_one_by_one1() { 383fn coerce_merge_one_by_one1() {
348 mark::check!(coerce_merge_fail_fallback); 384 mark::check!(coerce_merge_fail_fallback);
349 385
350 assert_snapshot!( 386 check_infer(
351 infer(r#" 387 r"
352fn test() { 388 fn test() {
353 let t = &mut 1; 389 let t = &mut 1;
354 let x = match 1 { 390 let x = match 1 {
355 1 => t as *mut i32, 391 1 => t as *mut i32,
356 2 => t as &i32, 392 2 => t as &i32,
357 _ => t as *const i32, 393 _ => t as *const i32,
358 }; 394 };
359} 395 }
360"#), 396 ",
361 @r###" 397 expect![[r"
362 10..144 '{ ... }; }': () 398 10..144 '{ ... }; }': ()
363 20..21 't': &mut i32 399 20..21 't': &mut i32
364 24..30 '&mut 1': &mut i32 400 24..30 '&mut 1': &mut i32
365 29..30 '1': i32 401 29..30 '1': i32
366 40..41 'x': *const i32 402 40..41 'x': *const i32
367 44..141 'match ... }': *const i32 403 44..141 'match ... }': *const i32
368 50..51 '1': i32 404 50..51 '1': i32
369 62..63 '1': i32 405 62..63 '1': i32
370 62..63 '1': i32 406 62..63 '1': i32
371 67..68 't': &mut i32 407 67..68 't': &mut i32
372 67..80 't as *mut i32': *mut i32 408 67..80 't as *mut i32': *mut i32
373 90..91 '2': i32 409 90..91 '2': i32
374 90..91 '2': i32 410 90..91 '2': i32
375 95..96 't': &mut i32 411 95..96 't': &mut i32
376 95..104 't as &i32': &i32 412 95..104 't as &i32': &i32
377 114..115 '_': i32 413 114..115 '_': i32
378 119..120 't': &mut i32 414 119..120 't': &mut i32
379 119..134 't as *const i32': *const i32 415 119..134 't as *const i32': *const i32
380 "### 416 "]],
381 ); 417 );
382} 418}
383 419
384#[test] 420#[test]
385fn return_coerce_unknown() { 421fn return_coerce_unknown() {
386 assert_snapshot!( 422 check_infer_with_mismatches(
387 infer_with_mismatches(r#" 423 r"
388fn foo() -> u32 { 424 fn foo() -> u32 {
389 return unknown; 425 return unknown;
390} 426 }
391"#, true), 427 ",
392 @r###" 428 expect![[r"
393 16..39 '{ ...own; }': u32 429 16..39 '{ ...own; }': u32
394 22..36 'return unknown': ! 430 22..36 'return unknown': !
395 29..36 'unknown': u32 431 29..36 'unknown': u32
396 "### 432 "]],
397 ); 433 );
398} 434}
399 435
400#[test] 436#[test]
401fn coerce_autoderef() { 437fn coerce_autoderef() {
402 assert_snapshot!( 438 check_infer_with_mismatches(
403 infer_with_mismatches(r#" 439 r"
404struct Foo; 440 struct Foo;
405fn takes_ref_foo(x: &Foo) {} 441 fn takes_ref_foo(x: &Foo) {}
406fn test() { 442 fn test() {
407 takes_ref_foo(&Foo); 443 takes_ref_foo(&Foo);
408 takes_ref_foo(&&Foo); 444 takes_ref_foo(&&Foo);
409 takes_ref_foo(&&&Foo); 445 takes_ref_foo(&&&Foo);
410} 446 }
411"#, true), 447 ",
412 @r###" 448 expect![[r"
413 29..30 'x': &Foo 449 29..30 'x': &Foo
414 38..40 '{}': () 450 38..40 '{}': ()
415 51..132 '{ ...oo); }': () 451 51..132 '{ ...oo); }': ()
416 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) 452 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo)
417 57..76 'takes_...(&Foo)': () 453 57..76 'takes_...(&Foo)': ()
418 71..75 '&Foo': &Foo 454 71..75 '&Foo': &Foo
419 72..75 'Foo': Foo 455 72..75 'Foo': Foo
420 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) 456 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo)
421 82..102 'takes_...&&Foo)': () 457 82..102 'takes_...&&Foo)': ()
422 96..101 '&&Foo': &&Foo 458 96..101 '&&Foo': &&Foo
423 97..101 '&Foo': &Foo 459 97..101 '&Foo': &Foo
424 98..101 'Foo': Foo 460 98..101 'Foo': Foo
425 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) 461 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo)
426 108..129 'takes_...&&Foo)': () 462 108..129 'takes_...&&Foo)': ()
427 122..128 '&&&Foo': &&&Foo 463 122..128 '&&&Foo': &&&Foo
428 123..128 '&&Foo': &&Foo 464 123..128 '&&Foo': &&Foo
429 124..128 '&Foo': &Foo 465 124..128 '&Foo': &Foo
430 125..128 'Foo': Foo 466 125..128 'Foo': Foo
431 "### 467 "]],
432 ); 468 );
433} 469}
434 470
435#[test] 471#[test]
436fn coerce_autoderef_generic() { 472fn coerce_autoderef_generic() {
437 assert_snapshot!( 473 check_infer_with_mismatches(
438 infer_with_mismatches(r#" 474 r"
439struct Foo; 475 struct Foo;
440fn takes_ref<T>(x: &T) -> T { *x } 476 fn takes_ref<T>(x: &T) -> T { *x }
441fn test() { 477 fn test() {
442 takes_ref(&Foo); 478 takes_ref(&Foo);
443 takes_ref(&&Foo); 479 takes_ref(&&Foo);
444 takes_ref(&&&Foo); 480 takes_ref(&&&Foo);
445} 481 }
446"#, true), 482 ",
447 @r###" 483 expect![[r"
448 28..29 'x': &T 484 28..29 'x': &T
449 40..46 '{ *x }': T 485 40..46 '{ *x }': T
450 42..44 '*x': T 486 42..44 '*x': T
451 43..44 'x': &T 487 43..44 'x': &T
452 57..126 '{ ...oo); }': () 488 57..126 '{ ...oo); }': ()
453 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo 489 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo
454 63..78 'takes_ref(&Foo)': Foo 490 63..78 'takes_ref(&Foo)': Foo
455 73..77 '&Foo': &Foo 491 73..77 '&Foo': &Foo
456 74..77 'Foo': Foo 492 74..77 'Foo': Foo
457 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo 493 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo
458 84..100 'takes_...&&Foo)': &Foo 494 84..100 'takes_...&&Foo)': &Foo
459 94..99 '&&Foo': &&Foo 495 94..99 '&&Foo': &&Foo
460 95..99 '&Foo': &Foo 496 95..99 '&Foo': &Foo
461 96..99 'Foo': Foo 497 96..99 'Foo': Foo
462 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo 498 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo
463 106..123 'takes_...&&Foo)': &&Foo 499 106..123 'takes_...&&Foo)': &&Foo
464 116..122 '&&&Foo': &&&Foo 500 116..122 '&&&Foo': &&&Foo
465 117..122 '&&Foo': &&Foo 501 117..122 '&&Foo': &&Foo
466 118..122 '&Foo': &Foo 502 118..122 '&Foo': &Foo
467 119..122 'Foo': Foo 503 119..122 'Foo': Foo
468 "### 504 "]],
469 ); 505 );
470} 506}
471 507
472#[test] 508#[test]
473fn coerce_autoderef_block() { 509fn coerce_autoderef_block() {
474 assert_snapshot!( 510 check_infer_with_mismatches(
475 infer_with_mismatches(r#" 511 r#"
476struct String {} 512 struct String {}
477#[lang = "deref"] 513 #[lang = "deref"]
478trait Deref { type Target; } 514 trait Deref { type Target; }
479impl Deref for String { type Target = str; } 515 impl Deref for String { type Target = str; }
480fn takes_ref_str(x: &str) {} 516 fn takes_ref_str(x: &str) {}
481fn returns_string() -> String { loop {} } 517 fn returns_string() -> String { loop {} }
482fn test() { 518 fn test() {
483 takes_ref_str(&{ returns_string() }); 519 takes_ref_str(&{ returns_string() });
484} 520 }
485"#, true), 521 "#,
486 @r###" 522 expect![[r"
487 126..127 'x': &str 523 126..127 'x': &str
488 135..137 '{}': () 524 135..137 '{}': ()
489 168..179 '{ loop {} }': String 525 168..179 '{ loop {} }': String
490 170..177 'loop {}': ! 526 170..177 'loop {}': !
491 175..177 '{}': () 527 175..177 '{}': ()
492 190..235 '{ ... }); }': () 528 190..235 '{ ... }); }': ()
493 196..209 'takes_ref_str': fn takes_ref_str(&str) 529 196..209 'takes_ref_str': fn takes_ref_str(&str)
494 196..232 'takes_...g() })': () 530 196..232 'takes_...g() })': ()
495 210..231 '&{ ret...ng() }': &String 531 210..231 '&{ ret...ng() }': &String
496 211..231 '{ retu...ng() }': String 532 211..231 '{ retu...ng() }': String
497 213..227 'returns_string': fn returns_string() -> String 533 213..227 'returns_string': fn returns_string() -> String
498 213..229 'return...ring()': String 534 213..229 'return...ring()': String
499 "### 535 "]],
500 ); 536 );
501} 537}
502 538
503#[test] 539#[test]
504fn closure_return_coerce() { 540fn closure_return_coerce() {
505 assert_snapshot!( 541 check_infer_with_mismatches(
506 infer_with_mismatches(r#" 542 r"
507fn foo() { 543 fn foo() {
508 let x = || { 544 let x = || {
509 if true { 545 if true {
510 return &1u32; 546 return &1u32;
547 }
548 &&1u32
549 };
511 } 550 }
512 &&1u32 551 ",
513 }; 552 expect![[r"
514} 553 9..105 '{ ... }; }': ()
515"#, true), 554 19..20 'x': || -> &u32
516 @r###" 555 23..102 '|| { ... }': || -> &u32
517 9..105 '{ ... }; }': () 556 26..102 '{ ... }': &u32
518 19..20 'x': || -> &u32 557 36..81 'if tru... }': ()
519 23..102 '|| { ... }': || -> &u32 558 39..43 'true': bool
520 26..102 '{ ... }': &u32 559 44..81 '{ ... }': ()
521 36..81 'if tru... }': () 560 58..70 'return &1u32': !
522 39..43 'true': bool 561 65..70 '&1u32': &u32
523 44..81 '{ ... }': () 562 66..70 '1u32': u32
524 58..70 'return &1u32': ! 563 90..96 '&&1u32': &&u32
525 65..70 '&1u32': &u32 564 91..96 '&1u32': &u32
526 66..70 '1u32': u32 565 92..96 '1u32': u32
527 90..96 '&&1u32': &&u32 566 "]],
528 91..96 '&1u32': &u32
529 92..96 '1u32': u32
530 "###
531 ); 567 );
532} 568}
533 569
534#[test] 570#[test]
535fn coerce_fn_item_to_fn_ptr() { 571fn coerce_fn_item_to_fn_ptr() {
536 assert_snapshot!( 572 check_infer_with_mismatches(
537 infer_with_mismatches(r#" 573 r"
538fn foo(x: u32) -> isize { 1 } 574 fn foo(x: u32) -> isize { 1 }
539fn test() { 575 fn test() {
540 let f: fn(u32) -> isize = foo; 576 let f: fn(u32) -> isize = foo;
541} 577 }
542"#, true), 578 ",
543 @r###" 579 expect![[r"
544 7..8 'x': u32 580 7..8 'x': u32
545 24..29 '{ 1 }': isize 581 24..29 '{ 1 }': isize
546 26..27 '1': isize 582 26..27 '1': isize
547 40..78 '{ ...foo; }': () 583 40..78 '{ ...foo; }': ()
548 50..51 'f': fn(u32) -> isize 584 50..51 'f': fn(u32) -> isize
549 72..75 'foo': fn foo(u32) -> isize 585 72..75 'foo': fn foo(u32) -> isize
550 "### 586 "]],
551 ); 587 );
552} 588}
553 589
554#[test] 590#[test]
555fn coerce_fn_items_in_match_arms() { 591fn coerce_fn_items_in_match_arms() {
556 mark::check!(coerce_fn_reification); 592 mark::check!(coerce_fn_reification);
557 assert_snapshot!( 593
558 infer_with_mismatches(r#" 594 check_infer_with_mismatches(
559fn foo1(x: u32) -> isize { 1 } 595 r"
560fn foo2(x: u32) -> isize { 2 } 596 fn foo1(x: u32) -> isize { 1 }
561fn foo3(x: u32) -> isize { 3 } 597 fn foo2(x: u32) -> isize { 2 }
562fn test() { 598 fn foo3(x: u32) -> isize { 3 }
563 let x = match 1 { 599 fn test() {
564 1 => foo1, 600 let x = match 1 {
565 2 => foo2, 601 1 => foo1,
566 _ => foo3, 602 2 => foo2,
567 }; 603 _ => foo3,
568} 604 };
569"#, true), 605 }
570 @r###" 606 ",
571 8..9 'x': u32 607 expect![[r"
572 25..30 '{ 1 }': isize 608 8..9 'x': u32
573 27..28 '1': isize 609 25..30 '{ 1 }': isize
574 39..40 'x': u32 610 27..28 '1': isize
575 56..61 '{ 2 }': isize 611 39..40 'x': u32
576 58..59 '2': isize 612 56..61 '{ 2 }': isize
577 70..71 'x': u32 613 58..59 '2': isize
578 87..92 '{ 3 }': isize 614 70..71 'x': u32
579 89..90 '3': isize 615 87..92 '{ 3 }': isize
580 103..192 '{ ... }; }': () 616 89..90 '3': isize
581 113..114 'x': fn(u32) -> isize 617 103..192 '{ ... }; }': ()
582 117..189 'match ... }': fn(u32) -> isize 618 113..114 'x': fn(u32) -> isize
583 123..124 '1': i32 619 117..189 'match ... }': fn(u32) -> isize
584 135..136 '1': i32 620 123..124 '1': i32
585 135..136 '1': i32 621 135..136 '1': i32
586 140..144 'foo1': fn foo1(u32) -> isize 622 135..136 '1': i32
587 154..155 '2': i32 623 140..144 'foo1': fn foo1(u32) -> isize
588 154..155 '2': i32 624 154..155 '2': i32
589 159..163 'foo2': fn foo2(u32) -> isize 625 154..155 '2': i32
590 173..174 '_': i32 626 159..163 'foo2': fn foo2(u32) -> isize
591 178..182 'foo3': fn foo3(u32) -> isize 627 173..174 '_': i32
592 "### 628 178..182 'foo3': fn foo3(u32) -> isize
629 "]],
593 ); 630 );
594} 631}
595 632
596#[test] 633#[test]
597fn coerce_closure_to_fn_ptr() { 634fn coerce_closure_to_fn_ptr() {
598 assert_snapshot!( 635 check_infer_with_mismatches(
599 infer_with_mismatches(r#" 636 r"
600fn test() { 637 fn test() {
601 let f: fn(u32) -> isize = |x| { 1 }; 638 let f: fn(u32) -> isize = |x| { 1 };
602} 639 }
603"#, true), 640 ",
604 @r###" 641 expect![[r"
605 10..54 '{ ...1 }; }': () 642 10..54 '{ ...1 }; }': ()
606 20..21 'f': fn(u32) -> isize 643 20..21 'f': fn(u32) -> isize
607 42..51 '|x| { 1 }': |u32| -> isize 644 42..51 '|x| { 1 }': |u32| -> isize
608 43..44 'x': u32 645 43..44 'x': u32
609 46..51 '{ 1 }': isize 646 46..51 '{ 1 }': isize
610 48..49 '1': isize 647 48..49 '1': isize
611 "### 648 "]],
612 ); 649 );
613} 650}
614 651
615#[test] 652#[test]
616fn coerce_placeholder_ref() { 653fn coerce_placeholder_ref() {
617 // placeholders should unify, even behind references 654 // placeholders should unify, even behind references
618 assert_snapshot!( 655 check_infer_with_mismatches(
619 infer_with_mismatches(r#" 656 r"
620struct S<T> { t: T } 657 struct S<T> { t: T }
621impl<TT> S<TT> { 658 impl<TT> S<TT> {
622 fn get(&self) -> &TT { 659 fn get(&self) -> &TT {
623 &self.t 660 &self.t
624 } 661 }
625} 662 }
626"#, true), 663 ",
627 @r###" 664 expect![[r"
628 50..54 'self': &S<TT> 665 50..54 'self': &S<TT>
629 63..86 '{ ... }': &TT 666 63..86 '{ ... }': &TT
630 73..80 '&self.t': &TT 667 73..80 '&self.t': &TT
631 74..78 'self': &S<TT> 668 74..78 'self': &S<TT>
632 74..80 'self.t': TT 669 74..80 'self.t': TT
633 "### 670 "]],
634 ); 671 );
635} 672}
636 673
637#[test] 674#[test]
638fn coerce_unsize_array() { 675fn coerce_unsize_array() {
639 assert_snapshot!( 676 check_infer_with_mismatches(
640 infer_with_mismatches(r#" 677 r#"
641#[lang = "unsize"] 678 #[lang = "unsize"]
642pub trait Unsize<T> {} 679 pub trait Unsize<T> {}
643#[lang = "coerce_unsized"] 680 #[lang = "coerce_unsized"]
644pub trait CoerceUnsized<T> {} 681 pub trait CoerceUnsized<T> {}
645 682
646impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 683 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
647 684
648fn test() { 685 fn test() {
649 let f: &[usize] = &[1, 2, 3]; 686 let f: &[usize] = &[1, 2, 3];
650} 687 }
651"#, true), 688 "#,
652 @r###" 689 expect![[r"
653 161..198 '{ ... 3]; }': () 690 161..198 '{ ... 3]; }': ()
654 171..172 'f': &[usize] 691 171..172 'f': &[usize]
655 185..195 '&[1, 2, 3]': &[usize; _] 692 185..195 '&[1, 2, 3]': &[usize; _]
656 186..195 '[1, 2, 3]': [usize; _] 693 186..195 '[1, 2, 3]': [usize; _]
657 187..188 '1': usize 694 187..188 '1': usize
658 190..191 '2': usize 695 190..191 '2': usize
659 193..194 '3': usize 696 193..194 '3': usize
660 "### 697 "]],
661 ); 698 );
662} 699}
663 700
664#[test] 701#[test]
665fn coerce_unsize_trait_object() { 702fn coerce_unsize_trait_object_simple() {
666 assert_snapshot!( 703 check_infer_with_mismatches(
667 infer_with_mismatches(r#" 704 r#"
668#[lang = "sized"] 705 #[lang = "sized"]
669pub trait Sized {} 706 pub trait Sized {}
670#[lang = "unsize"] 707 #[lang = "unsize"]
671pub trait Unsize<T> {} 708 pub trait Unsize<T> {}
672#[lang = "coerce_unsized"] 709 #[lang = "coerce_unsized"]
673pub trait CoerceUnsized<T> {} 710 pub trait CoerceUnsized<T> {}
674 711
675impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 712 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
676 713
677trait Foo<T, U> {} 714 trait Foo<T, U> {}
678trait Bar<U, T, X>: Foo<T, U> {} 715 trait Bar<U, T, X>: Foo<T, U> {}
679trait Baz<T, X>: Bar<usize, T, X> {} 716 trait Baz<T, X>: Bar<usize, T, X> {}
680 717
681struct S<T, X>; 718 struct S<T, X>;
682impl<T, X> Foo<T, usize> for S<T, X> {} 719 impl<T, X> Foo<T, usize> for S<T, X> {}
683impl<T, X> Bar<usize, T, X> for S<T, X> {} 720 impl<T, X> Bar<usize, T, X> for S<T, X> {}
684impl<T, X> Baz<T, X> for S<T, X> {} 721 impl<T, X> Baz<T, X> for S<T, X> {}
685 722
686fn test() { 723 fn test() {
687 let obj: &dyn Baz<i8, i16> = &S; 724 let obj: &dyn Baz<i8, i16> = &S;
688 let obj: &dyn Bar<_, _, _> = obj; 725 let obj: &dyn Bar<_, i8, i16> = &S;
689 let obj: &dyn Foo<_, _> = obj; 726 let obj: &dyn Foo<i8, _> = &S;
690 let obj2: &dyn Baz<i8, i16> = &S; 727 }
691 let _: &dyn Foo<_, _> = obj2; 728 "#,
729 expect![[r"
730 424..539 '{ ... &S; }': ()
731 434..437 'obj': &dyn Baz<i8, i16>
732 459..461 '&S': &S<i8, i16>
733 460..461 'S': S<i8, i16>
734 471..474 'obj': &dyn Bar<usize, i8, i16>
735 499..501 '&S': &S<i8, i16>
736 500..501 'S': S<i8, i16>
737 511..514 'obj': &dyn Foo<i8, usize>
738 534..536 '&S': &S<i8, {unknown}>
739 535..536 'S': S<i8, {unknown}>
740 "]],
741 );
692} 742}
693"#, true), 743
694 @r###" 744#[test]
695 424..609 '{ ...bj2; }': () 745// The rust reference says this should be possible, but rustc doesn't implement
696 434..437 'obj': &dyn Baz<i8, i16> 746// it. We used to support it, but Chalk doesn't.
697 459..461 '&S': &S<i8, i16> 747#[ignore]
698 460..461 'S': S<i8, i16> 748fn coerce_unsize_trait_object_to_trait_object() {
699 471..474 'obj': &dyn Bar<usize, i8, i16> 749 check_infer_with_mismatches(
700 496..499 'obj': &dyn Baz<i8, i16> 750 r#"
701 509..512 'obj': &dyn Foo<i8, usize> 751 #[lang = "sized"]
702 531..534 'obj': &dyn Bar<usize, i8, i16> 752 pub trait Sized {}
703 544..548 'obj2': &dyn Baz<i8, i16> 753 #[lang = "unsize"]
704 570..572 '&S': &S<i8, i16> 754 pub trait Unsize<T> {}
705 571..572 'S': S<i8, i16> 755 #[lang = "coerce_unsized"]
706 582..583 '_': &dyn Foo<i8, usize> 756 pub trait CoerceUnsized<T> {}
707 602..606 'obj2': &dyn Baz<i8, i16> 757
708 "### 758 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
759
760 trait Foo<T, U> {}
761 trait Bar<U, T, X>: Foo<T, U> {}
762 trait Baz<T, X>: Bar<usize, T, X> {}
763
764 struct S<T, X>;
765 impl<T, X> Foo<T, usize> for S<T, X> {}
766 impl<T, X> Bar<usize, T, X> for S<T, X> {}
767 impl<T, X> Baz<T, X> for S<T, X> {}
768
769 fn test() {
770 let obj: &dyn Baz<i8, i16> = &S;
771 let obj: &dyn Bar<_, _, _> = obj;
772 let obj: &dyn Foo<_, _> = obj;
773 let obj2: &dyn Baz<i8, i16> = &S;
774 let _: &dyn Foo<_, _> = obj2;
775 }
776 "#,
777 expect![[r"
778 424..609 '{ ...bj2; }': ()
779 434..437 'obj': &dyn Baz<i8, i16>
780 459..461 '&S': &S<i8, i16>
781 460..461 'S': S<i8, i16>
782 471..474 'obj': &dyn Bar<usize, i8, i16>
783 496..499 'obj': &dyn Baz<i8, i16>
784 509..512 'obj': &dyn Foo<i8, usize>
785 531..534 'obj': &dyn Bar<usize, i8, i16>
786 544..548 'obj2': &dyn Baz<i8, i16>
787 570..572 '&S': &S<i8, i16>
788 571..572 'S': S<i8, i16>
789 582..583 '_': &dyn Foo<i8, usize>
790 602..606 'obj2': &dyn Baz<i8, i16>
791 "]],
709 ); 792 );
710} 793}
711 794
712#[test] 795#[test]
713fn coerce_unsize_super_trait_cycle() { 796fn coerce_unsize_super_trait_cycle() {
714 assert_snapshot!( 797 check_infer_with_mismatches(
715 infer_with_mismatches(r#" 798 r#"
716#[lang = "sized"] 799 #[lang = "sized"]
717pub trait Sized {} 800 pub trait Sized {}
718#[lang = "unsize"] 801 #[lang = "unsize"]
719pub trait Unsize<T> {} 802 pub trait Unsize<T> {}
720#[lang = "coerce_unsized"] 803 #[lang = "coerce_unsized"]
721pub trait CoerceUnsized<T> {} 804 pub trait CoerceUnsized<T> {}
722 805
723impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 806 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
724 807
725trait A {} 808 trait A {}
726trait B: C + A {} 809 trait B: C + A {}
727trait C: B {} 810 trait C: B {}
728trait D: C 811 trait D: C
729 812
730struct S; 813 struct S;
731impl A for S {} 814 impl A for S {}
732impl B for S {} 815 impl B for S {}
733impl C for S {} 816 impl C for S {}
734impl D for S {} 817 impl D for S {}
735 818
736fn test() { 819 fn test() {
737 let obj: &dyn D = &S; 820 let obj: &dyn D = &S;
738 let obj: &dyn A = obj; 821 let obj: &dyn A = &S;
739} 822 }
740"#, true), 823 "#,
741 @r###" 824 expect![[r"
742 328..384 '{ ...obj; }': () 825 328..383 '{ ... &S; }': ()
743 338..341 'obj': &dyn D 826 338..341 'obj': &dyn D
744 352..354 '&S': &S 827 352..354 '&S': &S
745 353..354 'S': S 828 353..354 'S': S
746 364..367 'obj': &dyn A 829 364..367 'obj': &dyn A
747 378..381 'obj': &dyn D 830 378..380 '&S': &S
748 "### 831 379..380 'S': S
832 "]],
749 ); 833 );
750} 834}
751 835
@@ -754,24 +838,24 @@ fn test() {
754fn coerce_unsize_generic() { 838fn coerce_unsize_generic() {
755 // FIXME: Implement this 839 // FIXME: Implement this
756 // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions 840 // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions
757 assert_snapshot!( 841 check_infer_with_mismatches(
758 infer_with_mismatches(r#" 842 r#"
759#[lang = "unsize"] 843 #[lang = "unsize"]
760pub trait Unsize<T> {} 844 pub trait Unsize<T> {}
761#[lang = "coerce_unsized"] 845 #[lang = "coerce_unsized"]
762pub trait CoerceUnsized<T> {} 846 pub trait CoerceUnsized<T> {}
763 847
764impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 848 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
765 849
766struct Foo<T> { t: T }; 850 struct Foo<T> { t: T };
767struct Bar<T>(Foo<T>); 851 struct Bar<T>(Foo<T>);
768 852
769fn test() { 853 fn test() {
770 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; 854 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
771 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); 855 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
772} 856 }
773"#, true), 857 "#,
774 @r###" 858 expect![[r"
775 "### 859 "]],
776 ); 860 );
777} 861}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 45c4e309e..24c53eb02 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -1,9 +1,9 @@
1use std::fs; 1use std::fs;
2 2
3use insta::assert_snapshot; 3use expect::expect;
4use test_utils::project_dir; 4use test_utils::project_dir;
5 5
6use super::{check_types, infer}; 6use super::{check_infer, check_types};
7 7
8#[test] 8#[test]
9fn cfg_impl_def() { 9fn cfg_impl_def() {
@@ -46,204 +46,204 @@ impl S {
46 46
47#[test] 47#[test]
48fn infer_macros_expanded() { 48fn infer_macros_expanded() {
49 assert_snapshot!( 49 check_infer(
50 infer(r#" 50 r#"
51struct Foo(Vec<i32>); 51 struct Foo(Vec<i32>);
52 52
53macro_rules! foo { 53 macro_rules! foo {
54 ($($item:expr),*) => { 54 ($($item:expr),*) => {
55 { 55 {
56 Foo(vec![$($item,)*]) 56 Foo(vec![$($item,)*])
57 } 57 }
58 }; 58 };
59} 59 }
60 60
61fn main() { 61 fn main() {
62 let x = foo!(1,2); 62 let x = foo!(1,2);
63} 63 }
64"#), 64 "#,
65 @r###" 65 expect![[r#"
66 !0..17 '{Foo(v...,2,])}': Foo 66 !0..17 '{Foo(v...,2,])}': Foo
67 !1..4 'Foo': Foo({unknown}) -> Foo 67 !1..4 'Foo': Foo({unknown}) -> Foo
68 !1..16 'Foo(vec![1,2,])': Foo 68 !1..16 'Foo(vec![1,2,])': Foo
69 !5..15 'vec![1,2,]': {unknown} 69 !5..15 'vec![1,2,]': {unknown}
70 155..181 '{ ...,2); }': () 70 155..181 '{ ...,2); }': ()
71 165..166 'x': Foo 71 165..166 'x': Foo
72 "### 72 "#]],
73 ); 73 );
74} 74}
75 75
76#[test] 76#[test]
77fn infer_legacy_textual_scoped_macros_expanded() { 77fn infer_legacy_textual_scoped_macros_expanded() {
78 assert_snapshot!( 78 check_infer(
79 infer(r#" 79 r#"
80struct Foo(Vec<i32>); 80 struct Foo(Vec<i32>);
81 81
82#[macro_use] 82 #[macro_use]
83mod m { 83 mod m {
84 macro_rules! foo { 84 macro_rules! foo {
85 ($($item:expr),*) => { 85 ($($item:expr),*) => {
86 { 86 {
87 Foo(vec![$($item,)*]) 87 Foo(vec![$($item,)*])
88 }
89 };
88 } 90 }
89 }; 91 }
90 }
91}
92 92
93fn main() { 93 fn main() {
94 let x = foo!(1,2); 94 let x = foo!(1,2);
95 let y = crate::foo!(1,2); 95 let y = crate::foo!(1,2);
96} 96 }
97"#), 97 "#,
98 @r###" 98 expect![[r#"
99 !0..17 '{Foo(v...,2,])}': Foo 99 !0..17 '{Foo(v...,2,])}': Foo
100 !1..4 'Foo': Foo({unknown}) -> Foo 100 !1..4 'Foo': Foo({unknown}) -> Foo
101 !1..16 'Foo(vec![1,2,])': Foo 101 !1..16 'Foo(vec![1,2,])': Foo
102 !5..15 'vec![1,2,]': {unknown} 102 !5..15 'vec![1,2,]': {unknown}
103 194..250 '{ ...,2); }': () 103 194..250 '{ ...,2); }': ()
104 204..205 'x': Foo 104 204..205 'x': Foo
105 227..228 'y': {unknown} 105 227..228 'y': {unknown}
106 231..247 'crate:...!(1,2)': {unknown} 106 231..247 'crate:...!(1,2)': {unknown}
107 "### 107 "#]],
108 ); 108 );
109} 109}
110 110
111#[test] 111#[test]
112fn infer_path_qualified_macros_expanded() { 112fn infer_path_qualified_macros_expanded() {
113 assert_snapshot!( 113 check_infer(
114 infer(r#" 114 r#"
115#[macro_export] 115 #[macro_export]
116macro_rules! foo { 116 macro_rules! foo {
117 () => { 42i32 } 117 () => { 42i32 }
118} 118 }
119 119
120mod m { 120 mod m {
121 pub use super::foo as bar; 121 pub use super::foo as bar;
122} 122 }
123 123
124fn main() { 124 fn main() {
125 let x = crate::foo!(); 125 let x = crate::foo!();
126 let y = m::bar!(); 126 let y = m::bar!();
127} 127 }
128"#), 128 "#,
129 @r###" 129 expect![[r#"
130 !0..5 '42i32': i32 130 !0..5 '42i32': i32
131 !0..5 '42i32': i32 131 !0..5 '42i32': i32
132 110..163 '{ ...!(); }': () 132 110..163 '{ ...!(); }': ()
133 120..121 'x': i32 133 120..121 'x': i32
134 147..148 'y': i32 134 147..148 'y': i32
135 "### 135 "#]],
136 ); 136 );
137} 137}
138 138
139#[test] 139#[test]
140fn expr_macro_expanded_in_various_places() { 140fn expr_macro_expanded_in_various_places() {
141 assert_snapshot!( 141 check_infer(
142 infer(r#" 142 r#"
143macro_rules! spam { 143 macro_rules! spam {
144 () => (1isize); 144 () => (1isize);
145} 145 }
146 146
147fn spam() { 147 fn spam() {
148 spam!(); 148 spam!();
149 (spam!()); 149 (spam!());
150 spam!().spam(spam!()); 150 spam!().spam(spam!());
151 for _ in spam!() {} 151 for _ in spam!() {}
152 || spam!(); 152 || spam!();
153 while spam!() {} 153 while spam!() {}
154 break spam!(); 154 break spam!();
155 return spam!(); 155 return spam!();
156 match spam!() { 156 match spam!() {
157 _ if spam!() => spam!(), 157 _ if spam!() => spam!(),
158 } 158 }
159 spam!()(spam!()); 159 spam!()(spam!());
160 Spam { spam: spam!() }; 160 Spam { spam: spam!() };
161 spam!()[spam!()]; 161 spam!()[spam!()];
162 await spam!(); 162 await spam!();
163 spam!() as usize; 163 spam!() as usize;
164 &spam!(); 164 &spam!();
165 -spam!(); 165 -spam!();
166 spam!()..spam!(); 166 spam!()..spam!();
167 spam!() + spam!(); 167 spam!() + spam!();
168} 168 }
169"#), 169 "#,
170 @r###" 170 expect![[r#"
171 !0..6 '1isize': isize 171 !0..6 '1isize': isize
172 !0..6 '1isize': isize 172 !0..6 '1isize': isize
173 !0..6 '1isize': isize 173 !0..6 '1isize': isize
174 !0..6 '1isize': isize 174 !0..6 '1isize': isize
175 !0..6 '1isize': isize 175 !0..6 '1isize': isize
176 !0..6 '1isize': isize 176 !0..6 '1isize': isize
177 !0..6 '1isize': isize 177 !0..6 '1isize': isize
178 !0..6 '1isize': isize 178 !0..6 '1isize': isize
179 !0..6 '1isize': isize 179 !0..6 '1isize': isize
180 !0..6 '1isize': isize 180 !0..6 '1isize': isize
181 !0..6 '1isize': isize 181 !0..6 '1isize': isize
182 !0..6 '1isize': isize 182 !0..6 '1isize': isize
183 !0..6 '1isize': isize 183 !0..6 '1isize': isize
184 !0..6 '1isize': isize 184 !0..6 '1isize': isize
185 !0..6 '1isize': isize 185 !0..6 '1isize': isize
186 !0..6 '1isize': isize 186 !0..6 '1isize': isize
187 !0..6 '1isize': isize 187 !0..6 '1isize': isize
188 !0..6 '1isize': isize 188 !0..6 '1isize': isize
189 !0..6 '1isize': isize 189 !0..6 '1isize': isize
190 !0..6 '1isize': isize 190 !0..6 '1isize': isize
191 !0..6 '1isize': isize 191 !0..6 '1isize': isize
192 !0..6 '1isize': isize 192 !0..6 '1isize': isize
193 !0..6 '1isize': isize 193 !0..6 '1isize': isize
194 !0..6 '1isize': isize 194 !0..6 '1isize': isize
195 !0..6 '1isize': isize 195 !0..6 '1isize': isize
196 53..456 '{ ...!(); }': () 196 53..456 '{ ...!(); }': ()
197 87..108 'spam!(...am!())': {unknown} 197 87..108 'spam!(...am!())': {unknown}
198 114..133 'for _ ...!() {}': () 198 114..133 'for _ ...!() {}': ()
199 118..119 '_': {unknown} 199 118..119 '_': {unknown}
200 131..133 '{}': () 200 131..133 '{}': ()
201 138..148 '|| spam!()': || -> isize 201 138..148 '|| spam!()': || -> isize
202 154..170 'while ...!() {}': () 202 154..170 'while ...!() {}': ()
203 168..170 '{}': () 203 168..170 '{}': ()
204 175..188 'break spam!()': ! 204 175..188 'break spam!()': !
205 194..208 'return spam!()': ! 205 194..208 'return spam!()': !
206 214..268 'match ... }': isize 206 214..268 'match ... }': isize
207 238..239 '_': isize 207 238..239 '_': isize
208 273..289 'spam!(...am!())': {unknown} 208 273..289 'spam!(...am!())': {unknown}
209 295..317 'Spam {...m!() }': {unknown} 209 295..317 'Spam {...m!() }': {unknown}
210 323..339 'spam!(...am!()]': {unknown} 210 323..339 'spam!(...am!()]': {unknown}
211 364..380 'spam!(... usize': usize 211 364..380 'spam!(... usize': usize
212 386..394 '&spam!()': &isize 212 386..394 '&spam!()': &isize
213 400..408 '-spam!()': isize 213 400..408 '-spam!()': isize
214 414..430 'spam!(...pam!()': {unknown} 214 414..430 'spam!(...pam!()': {unknown}
215 436..453 'spam!(...pam!()': isize 215 436..453 'spam!(...pam!()': isize
216 "### 216 "#]],
217 ); 217 );
218} 218}
219 219
220#[test] 220#[test]
221fn infer_type_value_macro_having_same_name() { 221fn infer_type_value_macro_having_same_name() {
222 assert_snapshot!( 222 check_infer(
223 infer(r#" 223 r#"
224#[macro_export] 224 #[macro_export]
225macro_rules! foo { 225 macro_rules! foo {
226 () => { 226 () => {
227 mod foo { 227 mod foo {
228 pub use super::foo; 228 pub use super::foo;
229 }
230 };
231 ($x:tt) => {
232 $x
233 };
229 } 234 }
230 };
231 ($x:tt) => {
232 $x
233 };
234}
235 235
236foo!(); 236 foo!();
237 237
238fn foo() { 238 fn foo() {
239 let foo = foo::foo!(42i32); 239 let foo = foo::foo!(42i32);
240} 240 }
241"#), 241 "#,
242 @r###" 242 expect![[r#"
243 !0..5 '42i32': i32 243 !0..5 '42i32': i32
244 170..205 '{ ...32); }': () 244 170..205 '{ ...32); }': ()
245 180..183 'foo': i32 245 180..183 'foo': i32
246 "### 246 "#]],
247 ); 247 );
248} 248}
249 249
@@ -372,50 +372,50 @@ expand!();
372 372
373#[test] 373#[test]
374fn infer_type_value_non_legacy_macro_use_as() { 374fn infer_type_value_non_legacy_macro_use_as() {
375 assert_snapshot!( 375 check_infer(
376 infer(r#" 376 r#"
377mod m { 377 mod m {
378 macro_rules! _foo { 378 macro_rules! _foo {
379 ($x:ident) => { type $x = u64; } 379 ($x:ident) => { type $x = u64; }
380 } 380 }
381 pub(crate) use _foo as foo; 381 pub(crate) use _foo as foo;
382} 382 }
383 383
384m::foo!(foo); 384 m::foo!(foo);
385use foo as bar; 385 use foo as bar;
386fn f() -> bar { 0 } 386 fn f() -> bar { 0 }
387fn main() { 387 fn main() {
388 let _a = f(); 388 let _a = f();
389} 389 }
390"#), 390 "#,
391 @r###" 391 expect![[r#"
392 158..163 '{ 0 }': u64 392 158..163 '{ 0 }': u64
393 160..161 '0': u64 393 160..161 '0': u64
394 174..196 '{ ...f(); }': () 394 174..196 '{ ...f(); }': ()
395 184..186 '_a': u64 395 184..186 '_a': u64
396 190..191 'f': fn f() -> u64 396 190..191 'f': fn f() -> u64
397 190..193 'f()': u64 397 190..193 'f()': u64
398 "### 398 "#]],
399 ); 399 );
400} 400}
401 401
402#[test] 402#[test]
403fn infer_local_macro() { 403fn infer_local_macro() {
404 assert_snapshot!( 404 check_infer(
405 infer(r#" 405 r#"
406fn main() { 406 fn main() {
407 macro_rules! foo { 407 macro_rules! foo {
408 () => { 1usize } 408 () => { 1usize }
409 } 409 }
410 let _a = foo!(); 410 let _a = foo!();
411} 411 }
412"#), 412 "#,
413 @r###" 413 expect![[r#"
414 !0..6 '1usize': usize 414 !0..6 '1usize': usize
415 10..89 '{ ...!(); }': () 415 10..89 '{ ...!(); }': ()
416 16..65 'macro_... }': {unknown} 416 16..65 'macro_... }': {unknown}
417 74..76 '_a': usize 417 74..76 '_a': usize
418 "### 418 "#]],
419 ); 419 );
420} 420}
421 421
@@ -446,77 +446,77 @@ macro_rules! bar {
446 446
447#[test] 447#[test]
448fn infer_builtin_macros_line() { 448fn infer_builtin_macros_line() {
449 assert_snapshot!( 449 check_infer(
450 infer(r#" 450 r#"
451#[rustc_builtin_macro] 451 #[rustc_builtin_macro]
452macro_rules! line {() => {}} 452 macro_rules! line {() => {}}
453 453
454fn main() { 454 fn main() {
455 let x = line!(); 455 let x = line!();
456} 456 }
457"#), 457 "#,
458 @r###" 458 expect![[r#"
459 !0..1 '0': i32 459 !0..1 '0': i32
460 63..87 '{ ...!(); }': () 460 63..87 '{ ...!(); }': ()
461 73..74 'x': i32 461 73..74 'x': i32
462 "### 462 "#]],
463 ); 463 );
464} 464}
465 465
466#[test] 466#[test]
467fn infer_builtin_macros_file() { 467fn infer_builtin_macros_file() {
468 assert_snapshot!( 468 check_infer(
469 infer(r#" 469 r#"
470#[rustc_builtin_macro] 470 #[rustc_builtin_macro]
471macro_rules! file {() => {}} 471 macro_rules! file {() => {}}
472 472
473fn main() { 473 fn main() {
474 let x = file!(); 474 let x = file!();
475} 475 }
476"#), 476 "#,
477 @r###" 477 expect![[r#"
478 !0..2 '""': &str 478 !0..2 '""': &str
479 63..87 '{ ...!(); }': () 479 63..87 '{ ...!(); }': ()
480 73..74 'x': &str 480 73..74 'x': &str
481 "### 481 "#]],
482 ); 482 );
483} 483}
484 484
485#[test] 485#[test]
486fn infer_builtin_macros_column() { 486fn infer_builtin_macros_column() {
487 assert_snapshot!( 487 check_infer(
488 infer(r#" 488 r#"
489#[rustc_builtin_macro] 489 #[rustc_builtin_macro]
490macro_rules! column {() => {}} 490 macro_rules! column {() => {}}
491 491
492fn main() { 492 fn main() {
493 let x = column!(); 493 let x = column!();
494} 494 }
495"#), 495 "#,
496 @r###" 496 expect![[r#"
497 !0..1 '0': i32 497 !0..1 '0': i32
498 65..91 '{ ...!(); }': () 498 65..91 '{ ...!(); }': ()
499 75..76 'x': i32 499 75..76 'x': i32
500 "### 500 "#]],
501 ); 501 );
502} 502}
503 503
504#[test] 504#[test]
505fn infer_builtin_macros_concat() { 505fn infer_builtin_macros_concat() {
506 assert_snapshot!( 506 check_infer(
507 infer(r#" 507 r#"
508#[rustc_builtin_macro] 508 #[rustc_builtin_macro]
509macro_rules! concat {() => {}} 509 macro_rules! concat {() => {}}
510 510
511fn main() { 511 fn main() {
512 let x = concat!("hello", concat!("world", "!")); 512 let x = concat!("hello", concat!("world", "!"));
513} 513 }
514"#), 514 "#,
515 @r###" 515 expect![[r#"
516 !0..13 '"helloworld!"': &str 516 !0..13 '"helloworld!"': &str
517 65..121 '{ ...")); }': () 517 65..121 '{ ...")); }': ()
518 75..76 'x': &str 518 75..76 'x': &str
519 "### 519 "#]],
520 ); 520 );
521} 521}
522 522
@@ -622,7 +622,7 @@ macro_rules! include {() => {}}
622include!("main.rs"); 622include!("main.rs");
623 623
624fn main() { 624fn main() {
625 0 625 0
626} //^ i32 626} //^ i32
627"#, 627"#,
628 ); 628 );
@@ -630,42 +630,42 @@ fn main() {
630 630
631#[test] 631#[test]
632fn infer_builtin_macros_concat_with_lazy() { 632fn infer_builtin_macros_concat_with_lazy() {
633 assert_snapshot!( 633 check_infer(
634 infer(r#" 634 r#"
635macro_rules! hello {() => {"hello"}} 635 macro_rules! hello {() => {"hello"}}
636 636
637#[rustc_builtin_macro] 637 #[rustc_builtin_macro]
638macro_rules! concat {() => {}} 638 macro_rules! concat {() => {}}
639 639
640fn main() { 640 fn main() {
641 let x = concat!(hello!(), concat!("world", "!")); 641 let x = concat!(hello!(), concat!("world", "!"));
642} 642 }
643"#), 643 "#,
644 @r###" 644 expect![[r#"
645 !0..13 '"helloworld!"': &str 645 !0..13 '"helloworld!"': &str
646 103..160 '{ ...")); }': () 646 103..160 '{ ...")); }': ()
647 113..114 'x': &str 647 113..114 'x': &str
648 "### 648 "#]],
649 ); 649 );
650} 650}
651 651
652#[test] 652#[test]
653fn infer_builtin_macros_env() { 653fn infer_builtin_macros_env() {
654 assert_snapshot!( 654 check_infer(
655 infer(r#" 655 r#"
656//- /main.rs env:foo=bar 656 //- /main.rs env:foo=bar
657#[rustc_builtin_macro] 657 #[rustc_builtin_macro]
658macro_rules! env {() => {}} 658 macro_rules! env {() => {}}
659 659
660fn main() { 660 fn main() {
661 let x = env!("foo"); 661 let x = env!("foo");
662} 662 }
663"#), 663 "#,
664 @r###" 664 expect![[r#"
665 !0..22 '"__RA_...TED__"': &str 665 !0..22 '"__RA_...TED__"': &str
666 62..90 '{ ...o"); }': () 666 62..90 '{ ...o"); }': ()
667 72..73 'x': &str 667 72..73 'x': &str
668 "### 668 "#]],
669 ); 669 );
670} 670}
671 671
@@ -763,25 +763,25 @@ fn test() {
763 763
764#[test] 764#[test]
765fn macro_in_arm() { 765fn macro_in_arm() {
766 assert_snapshot!( 766 check_infer(
767 infer(r#" 767 r#"
768macro_rules! unit { 768 macro_rules! unit {
769 () => { () }; 769 () => { () };
770} 770 }
771 771
772fn main() { 772 fn main() {
773 let x = match () { 773 let x = match () {
774 unit!() => 92u32, 774 unit!() => 92u32,
775 }; 775 };
776} 776 }
777"#), 777 "#,
778 @r###" 778 expect![[r#"
779 51..110 '{ ... }; }': () 779 51..110 '{ ... }; }': ()
780 61..62 'x': u32 780 61..62 'x': u32
781 65..107 'match ... }': u32 781 65..107 'match ... }': u32
782 71..73 '()': () 782 71..73 '()': ()
783 84..91 'unit!()': () 783 84..91 'unit!()': ()
784 95..100 '92u32': u32 784 95..100 '92u32': u32
785 "### 785 "#]],
786 ); 786 );
787} 787}
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 9c8f22314..fa68355aa 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -1,245 +1,245 @@
1use insta::assert_snapshot; 1use expect::expect;
2 2
3use super::{check_types, infer}; 3use super::{check_infer, check_types};
4 4
5#[test] 5#[test]
6fn infer_slice_method() { 6fn infer_slice_method() {
7 assert_snapshot!( 7 check_infer(
8 infer(r#" 8 r#"
9#[lang = "slice"] 9 #[lang = "slice"]
10impl<T> [T] { 10 impl<T> [T] {
11 fn foo(&self) -> T { 11 fn foo(&self) -> T {
12 loop {} 12 loop {}
13 } 13 }
14} 14 }
15 15
16#[lang = "slice_alloc"] 16 #[lang = "slice_alloc"]
17impl<T> [T] {} 17 impl<T> [T] {}
18 18
19fn test(x: &[u8]) { 19 fn test(x: &[u8]) {
20 <[_]>::foo(x); 20 <[_]>::foo(x);
21} 21 }
22"#), 22 "#,
23 @r###" 23 expect![[r#"
24 44..48 'self': &[T] 24 44..48 'self': &[T]
25 55..78 '{ ... }': T 25 55..78 '{ ... }': T
26 65..72 'loop {}': ! 26 65..72 'loop {}': !
27 70..72 '{}': () 27 70..72 '{}': ()
28 130..131 'x': &[u8] 28 130..131 'x': &[u8]
29 140..162 '{ ...(x); }': () 29 140..162 '{ ...(x); }': ()
30 146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8 30 146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
31 146..159 '<[_]>::foo(x)': u8 31 146..159 '<[_]>::foo(x)': u8
32 157..158 'x': &[u8] 32 157..158 'x': &[u8]
33 "### 33 "#]],
34 ); 34 );
35} 35}
36 36
37#[test] 37#[test]
38fn infer_associated_method_struct() { 38fn infer_associated_method_struct() {
39 assert_snapshot!( 39 check_infer(
40 infer(r#" 40 r#"
41struct A { x: u32 } 41 struct A { x: u32 }
42 42
43impl A { 43 impl A {
44 fn new() -> A { 44 fn new() -> A {
45 A { x: 0 } 45 A { x: 0 }
46 } 46 }
47} 47 }
48fn test() { 48 fn test() {
49 let a = A::new(); 49 let a = A::new();
50 a.x; 50 a.x;
51} 51 }
52"#), 52 "#,
53 @r###" 53 expect![[r#"
54 48..74 '{ ... }': A 54 48..74 '{ ... }': A
55 58..68 'A { x: 0 }': A 55 58..68 'A { x: 0 }': A
56 65..66 '0': u32 56 65..66 '0': u32
57 87..121 '{ ...a.x; }': () 57 87..121 '{ ...a.x; }': ()
58 97..98 'a': A 58 97..98 'a': A
59 101..107 'A::new': fn new() -> A 59 101..107 'A::new': fn new() -> A
60 101..109 'A::new()': A 60 101..109 'A::new()': A
61 115..116 'a': A 61 115..116 'a': A
62 115..118 'a.x': u32 62 115..118 'a.x': u32
63 "### 63 "#]],
64 ); 64 );
65} 65}
66 66
67#[test] 67#[test]
68fn infer_associated_method_enum() { 68fn infer_associated_method_enum() {
69 assert_snapshot!( 69 check_infer(
70 infer(r#" 70 r#"
71enum A { B, C } 71 enum A { B, C }
72 72
73impl A { 73 impl A {
74 pub fn b() -> A { 74 pub fn b() -> A {
75 A::B 75 A::B
76 } 76 }
77 pub fn c() -> A { 77 pub fn c() -> A {
78 A::C 78 A::C
79 } 79 }
80} 80 }
81fn test() { 81 fn test() {
82 let a = A::b(); 82 let a = A::b();
83 a; 83 a;
84 let c = A::c(); 84 let c = A::c();
85 c; 85 c;
86} 86 }
87"#), 87 "#,
88 @r###" 88 expect![[r#"
89 46..66 '{ ... }': A 89 46..66 '{ ... }': A
90 56..60 'A::B': A 90 56..60 'A::B': A
91 87..107 '{ ... }': A 91 87..107 '{ ... }': A
92 97..101 'A::C': A 92 97..101 'A::C': A
93 120..177 '{ ... c; }': () 93 120..177 '{ ... c; }': ()
94 130..131 'a': A 94 130..131 'a': A
95 134..138 'A::b': fn b() -> A 95 134..138 'A::b': fn b() -> A
96 134..140 'A::b()': A 96 134..140 'A::b()': A
97 146..147 'a': A 97 146..147 'a': A
98 157..158 'c': A 98 157..158 'c': A
99 161..165 'A::c': fn c() -> A 99 161..165 'A::c': fn c() -> A
100 161..167 'A::c()': A 100 161..167 'A::c()': A
101 173..174 'c': A 101 173..174 'c': A
102 "### 102 "#]],
103 ); 103 );
104} 104}
105 105
106#[test] 106#[test]
107fn infer_associated_method_with_modules() { 107fn infer_associated_method_with_modules() {
108 assert_snapshot!( 108 check_infer(
109 infer(r#" 109 r#"
110mod a { 110 mod a {
111 struct A; 111 struct A;
112 impl A { pub fn thing() -> A { A {} }} 112 impl A { pub fn thing() -> A { A {} }}
113} 113 }
114 114
115mod b { 115 mod b {
116 struct B; 116 struct B;
117 impl B { pub fn thing() -> u32 { 99 }} 117 impl B { pub fn thing() -> u32 { 99 }}
118 118
119 mod c { 119 mod c {
120 struct C; 120 struct C;
121 impl C { pub fn thing() -> C { C {} }} 121 impl C { pub fn thing() -> C { C {} }}
122 } 122 }
123} 123 }
124use b::c; 124 use b::c;
125 125
126fn test() { 126 fn test() {
127 let x = a::A::thing(); 127 let x = a::A::thing();
128 let y = b::B::thing(); 128 let y = b::B::thing();
129 let z = c::C::thing(); 129 let z = c::C::thing();
130} 130 }
131"#), 131 "#,
132 @r###" 132 expect![[r#"
133 55..63 '{ A {} }': A 133 55..63 '{ A {} }': A
134 57..61 'A {}': A 134 57..61 'A {}': A
135 125..131 '{ 99 }': u32 135 125..131 '{ 99 }': u32
136 127..129 '99': u32 136 127..129 '99': u32
137 201..209 '{ C {} }': C 137 201..209 '{ C {} }': C
138 203..207 'C {}': C 138 203..207 'C {}': C
139 240..324 '{ ...g(); }': () 139 240..324 '{ ...g(); }': ()
140 250..251 'x': A 140 250..251 'x': A
141 254..265 'a::A::thing': fn thing() -> A 141 254..265 'a::A::thing': fn thing() -> A
142 254..267 'a::A::thing()': A 142 254..267 'a::A::thing()': A
143 277..278 'y': u32 143 277..278 'y': u32
144 281..292 'b::B::thing': fn thing() -> u32 144 281..292 'b::B::thing': fn thing() -> u32
145 281..294 'b::B::thing()': u32 145 281..294 'b::B::thing()': u32
146 304..305 'z': C 146 304..305 'z': C
147 308..319 'c::C::thing': fn thing() -> C 147 308..319 'c::C::thing': fn thing() -> C
148 308..321 'c::C::thing()': C 148 308..321 'c::C::thing()': C
149 "### 149 "#]],
150 ); 150 );
151} 151}
152 152
153#[test] 153#[test]
154fn infer_associated_method_generics() { 154fn infer_associated_method_generics() {
155 assert_snapshot!( 155 check_infer(
156 infer(r#" 156 r#"
157struct Gen<T> { 157 struct Gen<T> {
158 val: T 158 val: T
159} 159 }
160 160
161impl<T> Gen<T> { 161 impl<T> Gen<T> {
162 pub fn make(val: T) -> Gen<T> { 162 pub fn make(val: T) -> Gen<T> {
163 Gen { val } 163 Gen { val }
164 } 164 }
165} 165 }
166 166
167fn test() { 167 fn test() {
168 let a = Gen::make(0u32); 168 let a = Gen::make(0u32);
169} 169 }
170"#), 170 "#,
171 @r###" 171 expect![[r#"
172 63..66 'val': T 172 63..66 'val': T
173 81..108 '{ ... }': Gen<T> 173 81..108 '{ ... }': Gen<T>
174 91..102 'Gen { val }': Gen<T> 174 91..102 'Gen { val }': Gen<T>
175 97..100 'val': T 175 97..100 'val': T
176 122..154 '{ ...32); }': () 176 122..154 '{ ...32); }': ()
177 132..133 'a': Gen<u32> 177 132..133 'a': Gen<u32>
178 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32> 178 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32>
179 136..151 'Gen::make(0u32)': Gen<u32> 179 136..151 'Gen::make(0u32)': Gen<u32>
180 146..150 '0u32': u32 180 146..150 '0u32': u32
181 "### 181 "#]],
182 ); 182 );
183} 183}
184 184
185#[test] 185#[test]
186fn infer_associated_method_generics_without_args() { 186fn infer_associated_method_generics_without_args() {
187 assert_snapshot!( 187 check_infer(
188 infer(r#" 188 r#"
189struct Gen<T> { 189 struct Gen<T> {
190 val: T 190 val: T
191} 191 }
192 192
193impl<T> Gen<T> { 193 impl<T> Gen<T> {
194 pub fn make() -> Gen<T> { 194 pub fn make() -> Gen<T> {
195 loop { } 195 loop { }
196 } 196 }
197} 197 }
198 198
199fn test() { 199 fn test() {
200 let a = Gen::<u32>::make(); 200 let a = Gen::<u32>::make();
201} 201 }
202"#), 202 "#,
203 @r###" 203 expect![[r#"
204 75..99 '{ ... }': Gen<T> 204 75..99 '{ ... }': Gen<T>
205 85..93 'loop { }': ! 205 85..93 'loop { }': !
206 90..93 '{ }': () 206 90..93 '{ }': ()
207 113..148 '{ ...e(); }': () 207 113..148 '{ ...e(); }': ()
208 123..124 'a': Gen<u32> 208 123..124 'a': Gen<u32>
209 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32> 209 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32>
210 127..145 'Gen::<...make()': Gen<u32> 210 127..145 'Gen::<...make()': Gen<u32>
211 "### 211 "#]],
212 ); 212 );
213} 213}
214 214
215#[test] 215#[test]
216fn infer_associated_method_generics_2_type_params_without_args() { 216fn infer_associated_method_generics_2_type_params_without_args() {
217 assert_snapshot!( 217 check_infer(
218 infer(r#" 218 r#"
219struct Gen<T, U> { 219 struct Gen<T, U> {
220 val: T, 220 val: T,
221 val2: U, 221 val2: U,
222} 222 }
223 223
224impl<T> Gen<u32, T> { 224 impl<T> Gen<u32, T> {
225 pub fn make() -> Gen<u32,T> { 225 pub fn make() -> Gen<u32,T> {
226 loop { } 226 loop { }
227 } 227 }
228} 228 }
229 229
230fn test() { 230 fn test() {
231 let a = Gen::<u32, u64>::make(); 231 let a = Gen::<u32, u64>::make();
232} 232 }
233"#), 233 "#,
234 @r###" 234 expect![[r#"
235 101..125 '{ ... }': Gen<u32, T> 235 101..125 '{ ... }': Gen<u32, T>
236 111..119 'loop { }': ! 236 111..119 'loop { }': !
237 116..119 '{ }': () 237 116..119 '{ }': ()
238 139..179 '{ ...e(); }': () 238 139..179 '{ ...e(); }': ()
239 149..150 'a': Gen<u32, u64> 239 149..150 'a': Gen<u32, u64>
240 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64> 240 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64>
241 153..176 'Gen::<...make()': Gen<u32, u64> 241 153..176 'Gen::<...make()': Gen<u32, u64>
242 "### 242 "#]],
243 ); 243 );
244} 244}
245 245
@@ -267,416 +267,416 @@ mod foo {
267#[test] 267#[test]
268fn infer_trait_method_simple() { 268fn infer_trait_method_simple() {
269 // the trait implementation is intentionally incomplete -- it shouldn't matter 269 // the trait implementation is intentionally incomplete -- it shouldn't matter
270 assert_snapshot!( 270 check_infer(
271 infer(r#" 271 r#"
272trait Trait1 { 272 trait Trait1 {
273 fn method(&self) -> u32; 273 fn method(&self) -> u32;
274} 274 }
275struct S1; 275 struct S1;
276impl Trait1 for S1 {} 276 impl Trait1 for S1 {}
277trait Trait2 { 277 trait Trait2 {
278 fn method(&self) -> i128; 278 fn method(&self) -> i128;
279} 279 }
280struct S2; 280 struct S2;
281impl Trait2 for S2 {} 281 impl Trait2 for S2 {}
282fn test() { 282 fn test() {
283 S1.method(); // -> u32 283 S1.method(); // -> u32
284 S2.method(); // -> i128 284 S2.method(); // -> i128
285} 285 }
286"#), 286 "#,
287 @r###" 287 expect![[r#"
288 30..34 'self': &Self 288 30..34 'self': &Self
289 109..113 'self': &Self 289 109..113 'self': &Self
290 169..227 '{ ...i128 }': () 290 169..227 '{ ...i128 }': ()
291 175..177 'S1': S1 291 175..177 'S1': S1
292 175..186 'S1.method()': u32 292 175..186 'S1.method()': u32
293 202..204 'S2': S2 293 202..204 'S2': S2
294 202..213 'S2.method()': i128 294 202..213 'S2.method()': i128
295 "### 295 "#]],
296 ); 296 );
297} 297}
298 298
299#[test] 299#[test]
300fn infer_trait_method_scoped() { 300fn infer_trait_method_scoped() {
301 // the trait implementation is intentionally incomplete -- it shouldn't matter 301 // the trait implementation is intentionally incomplete -- it shouldn't matter
302 assert_snapshot!( 302 check_infer(
303 infer(r#" 303 r#"
304struct S