diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
30 files changed, 8270 insertions, 8867 deletions
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index 1b0f84c5c..c727012c6 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs | |||
@@ -37,7 +37,7 @@ pub(crate) fn deref( | |||
37 | ty: InEnvironment<&Canonical<Ty>>, | 37 | ty: InEnvironment<&Canonical<Ty>>, |
38 | ) -> Option<Canonical<Ty>> { | 38 | ) -> Option<Canonical<Ty>> { |
39 | if let Some(derefed) = ty.value.value.builtin_deref() { | 39 | if let Some(derefed) = ty.value.value.builtin_deref() { |
40 | Some(Canonical { value: derefed, num_vars: ty.value.num_vars }) | 40 | Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() }) |
41 | } else { | 41 | } else { |
42 | deref_by_trait(db, krate, ty) | 42 | deref_by_trait(db, krate, ty) |
43 | } | 43 | } |
@@ -68,8 +68,8 @@ fn deref_by_trait( | |||
68 | 68 | ||
69 | // Check that the type implements Deref at all | 69 | // Check that the type implements Deref at all |
70 | let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; | 70 | let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; |
71 | let implements_goal = super::Canonical { | 71 | let implements_goal = Canonical { |
72 | num_vars: ty.value.num_vars, | 72 | kinds: ty.value.kinds.clone(), |
73 | value: InEnvironment { | 73 | value: InEnvironment { |
74 | value: Obligation::Trait(trait_ref), | 74 | value: Obligation::Trait(trait_ref), |
75 | environment: ty.environment.clone(), | 75 | environment: ty.environment.clone(), |
@@ -81,7 +81,7 @@ fn deref_by_trait( | |||
81 | 81 | ||
82 | // Now do the assoc type projection | 82 | // Now do the assoc type projection |
83 | let projection = super::traits::ProjectionPredicate { | 83 | let projection = super::traits::ProjectionPredicate { |
84 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)), | 84 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())), |
85 | projection_ty: super::ProjectionTy { associated_ty: target, parameters }, | 85 | projection_ty: super::ProjectionTy { associated_ty: target, parameters }, |
86 | }; | 86 | }; |
87 | 87 | ||
@@ -89,7 +89,8 @@ fn deref_by_trait( | |||
89 | 89 | ||
90 | let in_env = InEnvironment { value: obligation, environment: ty.environment }; | 90 | let in_env = InEnvironment { value: obligation, environment: ty.environment }; |
91 | 91 | ||
92 | let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; | 92 | let canonical = |
93 | Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General))); | ||
93 | 94 | ||
94 | let solution = db.trait_solve(krate, canonical)?; | 95 | let solution = db.trait_solve(krate, canonical)?; |
95 | 96 | ||
@@ -110,7 +111,7 @@ fn deref_by_trait( | |||
110 | // assumptions will be broken. We would need to properly introduce | 111 | // assumptions will be broken. We would need to properly introduce |
111 | // new variables in that case | 112 | // new variables in that case |
112 | 113 | ||
113 | for i in 1..vars.0.num_vars { | 114 | for i in 1..vars.0.kinds.len() { |
114 | if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) | 115 | if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) |
115 | { | 116 | { |
116 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); | 117 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); |
@@ -119,7 +120,7 @@ fn deref_by_trait( | |||
119 | } | 120 | } |
120 | Some(Canonical { | 121 | Some(Canonical { |
121 | value: vars.0.value[vars.0.value.len() - 1].clone(), | 122 | value: vars.0.value[vars.0.value.len() - 1].clone(), |
122 | num_vars: vars.0.num_vars, | 123 | kinds: vars.0.kinds.clone(), |
123 | }) | 124 | }) |
124 | } | 125 | } |
125 | Solution::Ambig(_) => { | 126 | Solution::Ambig(_) => { |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index cad553273..c773adc67 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -3,23 +3,22 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{ | 5 | use 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 | }; |
9 | use ra_arena::map::ArenaMap; | 9 | use ra_arena::map::ArenaMap; |
10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; | 10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | 12 | ||
13 | use crate::{ | 13 | use 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 | }; |
19 | use hir_expand::name::Name; | 19 | use hir_expand::name::Name; |
20 | 20 | ||
21 | #[salsa::query_group(HirDatabaseStorage)] | 21 | #[salsa::query_group(HirDatabaseStorage)] |
22 | #[salsa::requires(salsa::Database)] | ||
23 | pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | 22 | pub 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)] |
150 | pub struct InternedOpaqueTyId(salsa::InternId); | 148 | pub struct InternedOpaqueTyId(salsa::InternId); |
151 | impl_intern_key!(InternedOpaqueTyId); | 149 | impl_intern_key!(InternedOpaqueTyId); |
150 | |||
151 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
152 | pub struct ClosureId(salsa::InternId); | ||
153 | impl_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)] | ||
158 | pub struct InternedCallableDefId(salsa::InternId); | ||
159 | impl_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 |
2 | mod expr; | ||
3 | mod match_check; | ||
4 | mod unsafe_check; | ||
2 | 5 | ||
3 | use std::any::Any; | 6 | use std::any::Any; |
4 | 7 | ||
8 | use hir_def::DefWithBodyId; | ||
9 | use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | ||
5 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; | 10 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; |
11 | use ra_prof::profile; | ||
6 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; | 12 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; |
7 | use stdx::format_to; | 13 | use stdx::format_to; |
8 | 14 | ||
9 | pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path}; | 15 | use crate::db::HirDatabase; |
10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | 16 | |
17 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; | ||
18 | |||
19 | pub 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)] |
13 | pub struct NoSuchField { | 30 | pub 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 | ||
18 | impl Diagnostic for NoSuchField { | 35 | impl Diagnostic for NoSuchField { |
@@ -30,19 +47,19 @@ impl Diagnostic for NoSuchField { | |||
30 | } | 47 | } |
31 | 48 | ||
32 | impl AstDiagnostic for NoSuchField { | 49 | impl 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)] |
43 | pub struct MissingFields { | 60 | pub 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 | ||
65 | impl AstDiagnostic for MissingFields { | 82 | impl 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 { | |||
135 | impl AstDiagnostic for MissingOkInTailExpr { | 152 | impl 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 { | |||
163 | impl AstDiagnostic for BreakOutsideOfLoop { | 180 | impl 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 { | |||
191 | impl AstDiagnostic for MissingUnsafe { | 208 | impl 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)] | ||
219 | pub struct MismatchedArgCount { | ||
220 | pub file: HirFileId, | ||
221 | pub call_expr: AstPtr<ast::Expr>, | ||
222 | pub expected: usize, | ||
223 | pub found: usize, | ||
224 | } | ||
225 | |||
226 | impl 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 | |||
242 | impl 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)] | ||
252 | mod 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#" | ||
325 | struct S { foo: i32, bar: () } | ||
326 | impl 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 | ||
345 | struct MyStruct { | ||
346 | my_val: usize, | ||
347 | #[cfg(feature = "foo")] | ||
348 | bar: bool, | ||
349 | } | ||
350 | |||
351 | impl 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 | ||
370 | enum Foo { | ||
371 | #[cfg(not(feature = "foo"))] | ||
372 | Buz, | ||
373 | #[cfg(feature = "foo")] | ||
374 | Bar, | ||
375 | Baz | ||
376 | } | ||
377 | |||
378 | fn 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 | ||
393 | struct S { | ||
394 | #[cfg(feature = "foo")] | ||
395 | foo: u32, | ||
396 | #[cfg(not(feature = "foo"))] | ||
397 | bar: u32, | ||
398 | } | ||
399 | |||
400 | impl 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#" | ||
432 | macro_rules! Type { () => { u32 }; } | ||
433 | struct Foo { bar: Type![] } | ||
434 | |||
435 | impl 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#" | ||
448 | struct S { foo: i32, bar: () } | ||
449 | fn 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" | ||
462 | struct S { foo: i32, bar: () } | ||
463 | fn 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#" | ||
476 | fn 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 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId}; | 5 | use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId}; |
6 | use hir_expand::diagnostics::DiagnosticSink; | 6 | use hir_expand::diagnostics::DiagnosticSink; |
7 | use ra_syntax::{ast, AstPtr}; | 7 | use ra_syntax::{ast, AstPtr}; |
8 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
9 | 9 | ||
10 | use crate::{ | 10 | use 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 | ||
18 | pub use hir_def::{ | 20 | pub 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 | ||
30 | pub struct ExprValidator<'a, 'b: 'a> { | 33 | pub(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 | ||
36 | impl<'a, 'b> ExprValidator<'a, 'b> { | 39 | impl<'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)] | ||
386 | mod tests { | ||
387 | use crate::diagnostics::tests::check_diagnostics; | ||
388 | |||
389 | #[test] | ||
390 | fn simple_free_fn_zero() { | ||
391 | check_diagnostics( | ||
392 | r#" | ||
393 | fn zero() {} | ||
394 | fn f() { zero(1); } | ||
395 | //^^^^^^^ Expected 0 arguments, found 1 | ||
396 | "#, | ||
397 | ); | ||
398 | |||
399 | check_diagnostics( | ||
400 | r#" | ||
401 | fn zero() {} | ||
402 | fn f() { zero(); } | ||
403 | "#, | ||
404 | ); | ||
405 | } | ||
406 | |||
407 | #[test] | ||
408 | fn simple_free_fn_one() { | ||
409 | check_diagnostics( | ||
410 | r#" | ||
411 | fn one(arg: u8) {} | ||
412 | fn f() { one(); } | ||
413 | //^^^^^ Expected 1 argument, found 0 | ||
414 | "#, | ||
415 | ); | ||
416 | |||
417 | check_diagnostics( | ||
418 | r#" | ||
419 | fn one(arg: u8) {} | ||
420 | fn f() { one(1); } | ||
421 | "#, | ||
422 | ); | ||
423 | } | ||
424 | |||
425 | #[test] | ||
426 | fn method_as_fn() { | ||
427 | check_diagnostics( | ||
428 | r#" | ||
429 | struct S; | ||
430 | impl S { fn method(&self) {} } | ||
431 | |||
432 | fn f() { | ||
433 | S::method(); | ||
434 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
435 | "#, | ||
436 | ); | ||
437 | |||
438 | check_diagnostics( | ||
439 | r#" | ||
440 | struct S; | ||
441 | impl S { fn method(&self) {} } | ||
442 | |||
443 | fn 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#" | ||
455 | struct S; | ||
456 | impl 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#" | ||
466 | struct S; | ||
467 | impl S { fn method(&self, arg: u8) {} } | ||
468 | |||
469 | fn 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#" | ||
481 | struct Tup(u8, u16); | ||
482 | fn 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#" | ||
493 | enum En { Variant(u8, u16), } | ||
494 | fn 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#" | ||
505 | macro_rules! Type { | ||
506 | () => { u32 }; | ||
507 | } | ||
508 | enum Foo { | ||
509 | Bar(Type![]) | ||
510 | } | ||
511 | impl 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#" | ||
528 | extern "C" { | ||
529 | fn fixed(fixed: u8); | ||
530 | fn varargs(fixed: u8, ...); | ||
531 | fn varargs2(...); | ||
532 | } | ||
533 | |||
534 | fn 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#" | ||
554 | fn 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 | //! ``` |
219 | use std::sync::Arc; | 219 | use std::sync::Arc; |
220 | 220 | ||
221 | use smallvec::{smallvec, SmallVec}; | 221 | use hir_def::{ |
222 | 222 | adt::VariantData, | |
223 | use 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 | }; |
228 | use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId}; | ||
229 | use ra_arena::Idx; | 227 | use ra_arena::Idx; |
228 | use smallvec::{smallvec, SmallVec}; | ||
229 | |||
230 | use 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)] |
274 | pub enum MatchCheckErr { | 275 | pub(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 `?`. |
289 | pub type MatchCheckResult<T> = Result<T, MatchCheckErr>; | 290 | pub(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`. |
295 | pub(crate) struct PatStack(PatStackInner); | 296 | pub(super) struct PatStack(PatStackInner); |
296 | type PatStackInner = SmallVec<[PatIdOrWild; 2]>; | 297 | type PatStackInner = SmallVec<[PatIdOrWild; 2]>; |
297 | 298 | ||
298 | impl PatStack { | 299 | impl 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`. |
512 | pub(crate) struct Matrix(Vec<PatStack>); | 513 | pub(super) struct Matrix(Vec<PatStack>); |
513 | 514 | ||
514 | impl Matrix { | 515 | impl 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. |
581 | pub enum Usefulness { | 582 | pub(super) enum Usefulness { |
582 | Useful, | 583 | Useful, |
583 | NotUseful, | 584 | NotUseful, |
584 | } | 585 | } |
585 | 586 | ||
586 | pub struct MatchCheckCtx<'a> { | 587 | pub(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. |
601 | pub(crate) fn is_useful( | 602 | pub(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)] |
838 | mod tests { | 839 | mod 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() { | 846 | fn 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() { | 864 | fn 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 | ); | 878 | fn 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() { | 931 | fn 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() { | 959 | enum Either { A, B, } |
1159 | match (false, ((), false)) { | ||
1160 | (true, ((), true)) => {}, | ||
1161 | } | ||
1162 | } | ||
1163 | ", | ||
1164 | ); | ||
1165 | } | ||
1166 | 960 | ||
1167 | #[test] | 961 | fn 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 { | 987 | enum 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] | 989 | fn 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 { | 1020 | enum 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] | 1022 | fn 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 { | 1048 | enum Either { A(bool), B(bool, bool) } |
1447 | A(bool), | 1049 | enum Either2 { C, D } |
1448 | B(bool, bool), | 1050 | |
1449 | } | 1051 | fn 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() { | 1069 | enum Either { A, B } |
1513 | match (0) { | 1070 | enum Either2 { C, D } |
1514 | () => (), | 1071 | |
1515 | } | 1072 | fn 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 { | 1094 | enum 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] | 1096 | fn 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 { | 1110 | enum 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] | 1112 | fn 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> { | 1137 | enum 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] | 1139 | fn foo() -> Either<!> { Either::B } |
1615 | fn enum_record_no_arms() { | 1140 | fn 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 { | 1154 | enum 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] | 1156 | fn 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 { | 1192 | enum 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] | 1197 | fn 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 { | 1219 | enum 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] | 1224 | fn 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 {} | 1255 | enum Either { |
1256 | A(bool, bool, bool, bool), | ||
1257 | B, | ||
1258 | } | ||
1949 | 1259 | ||
1950 | fn test_fn(never: Never) { | 1260 | fn 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 {} | 1299 | enum Never {} |
1973 | 1300 | ||
1974 | fn test_fn(never: &Never) { | 1301 | fn enum_(never: Never) { |
1975 | match never {} | 1302 | match never {} |
1976 | } | 1303 | } |
1977 | ", | 1304 | fn enum_ref(never: &Never) { |
1978 | ); | 1305 | match never {} |
1979 | } | 1306 | } |
1980 | 1307 | fn 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 { | 1318 | pub enum Category { Infinity, Zero } |
2003 | Infinity, | ||
2004 | Zero, | ||
2005 | } | ||
2006 | 1319 | ||
2007 | fn panic(a: Category, b: Category) { | 1320 | fn 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 | ); |
2041 | mod 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() { | 1355 | fn 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 `!`. | 1370 | fn 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" | 1385 | fn 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" | 1399 | fn 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" | 1413 | struct Foo { a: bool } |
2146 | struct Foo { | 1414 | fn 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; | |||
6 | use hir_def::{ | 6 | use 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 | }; |
11 | use hir_expand::diagnostics::DiagnosticSink; | 11 | use hir_expand::diagnostics::DiagnosticSink; |
12 | 12 | ||
13 | use crate::{ | 13 | use 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 | ||
18 | pub struct UnsafeValidator<'a, 'b: 'a> { | 18 | pub(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 | ||
24 | impl<'a, 'b> UnsafeValidator<'a, 'b> { | 24 | impl<'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)] | ||
126 | mod tests { | ||
127 | use crate::diagnostics::tests::check_diagnostics; | ||
128 | |||
129 | #[test] | ||
130 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
131 | check_diagnostics( | ||
132 | r#" | ||
133 | fn 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#" | ||
146 | struct HasUnsafe; | ||
147 | |||
148 | impl HasUnsafe { | ||
149 | unsafe fn unsafe_fn(&self) { | ||
150 | let x = &5 as *const usize; | ||
151 | let y = *x; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | unsafe fn unsafe_fn() { | ||
156 | let x = &5 as *const usize; | ||
157 | let y = *x; | ||
158 | } | ||
159 | |||
160 | fn 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 @@ | |||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use crate::{ | 5 | use 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 | }; |
9 | use hir_def::{ | 9 | use 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; | |||
18 | use std::ops::Index; | 18 | use std::ops::Index; |
19 | use std::sync::Arc; | 19 | use std::sync::Arc; |
20 | 20 | ||
21 | use rustc_hash::FxHashMap; | ||
22 | |||
23 | use hir_def::{ | 21 | use 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 | }; |
34 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | 32 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; |
35 | use ra_arena::map::ArenaMap; | 33 | use ra_arena::map::ArenaMap; |
36 | use ra_prof::profile; | 34 | use ra_prof::profile; |
37 | use ra_syntax::SmolStr; | 35 | use ra_syntax::SmolStr; |
36 | use rustc_hash::FxHashMap; | ||
37 | use stdx::impl_from; | ||
38 | 38 | ||
39 | use super::{ | 39 | use 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 | 87 | impl_from!(ExprId, PatId for ExprOrPatId); | |
88 | impl_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 | ||
759 | mod diagnostics { | 762 | mod 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; | |||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use 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 | ||
15 | impl<'a> InferenceContext<'a> { | 15 | impl<'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 | ||
147 | pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | 167 | pub 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 | ||
9 | macro_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 | |||
28 | mod autoderef; | 9 | mod autoderef; |
29 | pub mod primitive; | 10 | pub mod primitive; |
30 | pub mod traits; | 11 | pub mod traits; |
@@ -32,22 +13,18 @@ pub mod method_resolution; | |||
32 | mod op; | 13 | mod op; |
33 | mod lower; | 14 | mod lower; |
34 | pub(crate) mod infer; | 15 | pub(crate) mod infer; |
35 | pub mod display; | ||
36 | pub(crate) mod utils; | 16 | pub(crate) mod utils; |
17 | |||
18 | pub mod display; | ||
37 | pub mod db; | 19 | pub mod db; |
38 | pub mod diagnostics; | 20 | pub mod diagnostics; |
39 | pub mod expr; | ||
40 | pub mod unsafe_validation; | ||
41 | 21 | ||
42 | #[cfg(test)] | 22 | #[cfg(test)] |
43 | mod tests; | 23 | mod tests; |
44 | #[cfg(test)] | 24 | #[cfg(test)] |
45 | mod test_db; | 25 | mod test_db; |
46 | mod _match; | ||
47 | 26 | ||
48 | use std::ops::Deref; | 27 | use std::{iter, mem, ops::Deref, sync::Arc}; |
49 | use std::sync::Arc; | ||
50 | use std::{iter, mem}; | ||
51 | 28 | ||
52 | use hir_def::{ | 29 | use 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 | }; |
58 | use ra_db::{impl_intern_key, salsa, CrateId}; | 35 | use itertools::Itertools; |
36 | use ra_db::{salsa, CrateId}; | ||
59 | 37 | ||
60 | use crate::{ | 38 | use 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 | }; |
65 | use display::HirDisplay; | ||
66 | 44 | ||
67 | pub use autoderef::autoderef; | 45 | pub use autoderef::autoderef; |
68 | pub use infer::{InferTy, InferenceResult}; | 46 | pub use infer::{InferTy, InferenceResult}; |
69 | pub use lower::CallableDef; | 47 | pub use lower::CallableDefId; |
70 | pub use lower::{ | 48 | pub 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::{ | |||
74 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 52 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
75 | 53 | ||
76 | pub use chalk_ir::{BoundVar, DebruijnIndex}; | 54 | pub use chalk_ir::{BoundVar, DebruijnIndex}; |
77 | use 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)] | ||
169 | pub struct TypeCtorId(salsa::InternId); | ||
170 | impl_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)] | ||
175 | pub struct CallableDefId(salsa::InternId); | ||
176 | impl_intern_key!(CallableDefId); | ||
177 | |||
178 | impl TypeCtor { | 143 | impl 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)] |
669 | pub struct Canonical<T> { | 635 | pub struct Canonical<T> { |
670 | pub value: T, | 636 | pub value: T, |
671 | pub num_vars: usize, | 637 | pub kinds: Arc<[TyKind]>, |
638 | } | ||
639 | |||
640 | impl<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)] | ||
647 | pub 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)] |
677 | pub struct FnSig { | 656 | pub 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. |
682 | pub type PolyFnSig = Binders<FnSig>; | 662 | pub type PolyFnSig = Binders<FnSig>; |
683 | 663 | ||
684 | impl FnSig { | 664 | impl 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. |
8 | use std::iter; | 8 | use std::{iter, sync::Arc}; |
9 | use std::sync::Arc; | ||
10 | |||
11 | use smallvec::SmallVec; | ||
12 | 9 | ||
13 | use hir_def::{ | 10 | use hir_def::{ |
14 | adt::StructKind, | 11 | adt::StructKind, |
@@ -24,6 +21,8 @@ use hir_def::{ | |||
24 | use hir_expand::name::Name; | 21 | use hir_expand::name::Name; |
25 | use ra_arena::map::ArenaMap; | 22 | use ra_arena::map::ArenaMap; |
26 | use ra_db::CrateId; | 23 | use ra_db::CrateId; |
24 | use smallvec::SmallVec; | ||
25 | use stdx::impl_from; | ||
27 | use test_utils::mark; | 26 | use test_utils::mark; |
28 | 27 | ||
29 | use crate::{ | 28 | use 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). |
770 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { | 771 | pub 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<_>>(); |