aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty')
-rw-r--r--crates/hir_ty/Cargo.toml4
-rw-r--r--crates/hir_ty/src/builder.rs2
-rw-r--r--crates/hir_ty/src/chalk_db.rs39
-rw-r--r--crates/hir_ty/src/consteval.rs2
-rw-r--r--crates/hir_ty/src/db.rs7
-rw-r--r--crates/hir_ty/src/diagnostics.rs772
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs357
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs484
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs957
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/usefulness.rs8
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs151
-rw-r--r--crates/hir_ty/src/diagnostics_sink.rs109
-rw-r--r--crates/hir_ty/src/infer.rs96
-rw-r--r--crates/hir_ty/src/infer/coerce.rs8
-rw-r--r--crates/hir_ty/src/infer/expr.rs23
-rw-r--r--crates/hir_ty/src/infer/pat.rs4
-rw-r--r--crates/hir_ty/src/infer/path.rs6
-rw-r--r--crates/hir_ty/src/interner.rs6
-rw-r--r--crates/hir_ty/src/lib.rs3
-rw-r--r--crates/hir_ty/src/lower.rs10
-rw-r--r--crates/hir_ty/src/method_resolution.rs82
-rw-r--r--crates/hir_ty/src/tests.rs98
-rw-r--r--crates/hir_ty/src/tests/coercion.rs675
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs99
-rw-r--r--crates/hir_ty/src/tests/patterns.rs133
-rw-r--r--crates/hir_ty/src/tests/regression.rs162
-rw-r--r--crates/hir_ty/src/tests/simple.rs767
-rw-r--r--crates/hir_ty/src/tests/traits.rs578
29 files changed, 1459 insertions, 4185 deletions
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 4b714c6d8..74129eb21 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14itertools = "0.10.0" 14itertools = "0.10.0"
15arrayvec = "0.7" 15arrayvec = "0.7"
16smallvec = "1.2.0" 16smallvec = "1.2.0"
@@ -20,7 +20,7 @@ rustc-hash = "1.1.0"
20scoped-tls = "1" 20scoped-tls = "1"
21chalk-solve = { version = "0.68", default-features = false } 21chalk-solve = { version = "0.68", default-features = false }
22chalk-ir = "0.68" 22chalk-ir = "0.68"
23chalk-recursive = "0.68" 23chalk-recursive = { version = "0.68", default-features = false }
24la-arena = { version = "0.2.0", path = "../../lib/arena" } 24la-arena = { version = "0.2.0", path = "../../lib/arena" }
25once_cell = { version = "1.5.0" } 25once_cell = { version = "1.5.0" }
26 26
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 893e727c2..bb9d84246 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -202,7 +202,7 @@ impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>>
202 202
203impl TyBuilder<Binders<Ty>> { 203impl TyBuilder<Binders<Ty>> {
204 pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> { 204 pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
205 TyBuilder::subst_binders(db.ty(def.into())) 205 TyBuilder::subst_binders(db.ty(def))
206 } 206 }
207 207
208 pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> { 208 pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 4e042bf42..a4c09c742 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -10,16 +10,16 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
10use base_db::CrateId; 10use base_db::CrateId;
11use hir_def::{ 11use hir_def::{
12 lang_item::{lang_attr, LangItemTarget}, 12 lang_item::{lang_attr, LangItemTarget},
13 AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId, 13 AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, ModuleId, TypeAliasId,
14}; 14};
15use hir_expand::name::name; 15use hir_expand::name::name;
16 16
17use crate::{ 17use crate::{
18 db::HirDatabase, 18 db::HirDatabase,
19 display::HirDisplay, 19 display::HirDisplay,
20 from_assoc_type_id, from_chalk_trait_id, make_only_type_binders, 20 from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_only_type_binders,
21 mapping::{from_chalk, ToChalk, TypeAliasAsValue}, 21 mapping::{from_chalk, ToChalk, TypeAliasAsValue},
22 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, 22 method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
23 to_assoc_type_id, to_chalk_trait_id, 23 to_assoc_type_id, to_chalk_trait_id,
24 traits::ChalkContext, 24 traits::ChalkContext,
25 utils::generics, 25 utils::generics,
@@ -105,12 +105,30 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
105 _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]), 105 _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
106 }; 106 };
107 107
108 fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
109 db.trait_impls_in_block(module.containing_block()?)
110 }
111
108 // Note: Since we're using impls_for_trait, only impls where the trait 112 // Note: Since we're using impls_for_trait, only impls where the trait
109 // can be resolved should ever reach Chalk. Symbol’s value as variable is void: impl_datum relies on that 113 // can be resolved should ever reach Chalk. impl_datum relies on that
110 // and will panic if the trait can't be resolved. 114 // and will panic if the trait can't be resolved.
111 let in_deps = self.db.trait_impls_in_deps(self.krate); 115 let in_deps = self.db.trait_impls_in_deps(self.krate);
112 let in_self = self.db.trait_impls_in_crate(self.krate); 116 let in_self = self.db.trait_impls_in_crate(self.krate);
113 let impl_maps = [in_deps, in_self]; 117 let trait_module = trait_.module(self.db.upcast());
118 let type_module = match self_ty_fp {
119 Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
120 Some(TyFingerprint::ForeignType(type_id)) => {
121 Some(from_foreign_def_id(type_id).module(self.db.upcast()))
122 }
123 Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
124 _ => None,
125 };
126 let impl_maps = [
127 Some(in_deps),
128 Some(in_self),
129 local_impls(self.db, trait_module),
130 type_module.and_then(|m| local_impls(self.db, m)),
131 ];
114 132
115 let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); 133 let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
116 134
@@ -118,14 +136,16 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
118 debug!("Unrestricted search for {:?} impls...", trait_); 136 debug!("Unrestricted search for {:?} impls...", trait_);
119 impl_maps 137 impl_maps
120 .iter() 138 .iter()
121 .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk)) 139 .filter_map(|o| o.as_ref())
140 .flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk))
122 .collect() 141 .collect()
123 } else { 142 } else {
124 impl_maps 143 impl_maps
125 .iter() 144 .iter()
126 .flat_map(|crate_impl_defs| { 145 .filter_map(|o| o.as_ref())
146 .flat_map(|impls| {
127 fps.iter().flat_map(move |fp| { 147 fps.iter().flat_map(move |fp| {
128 crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) 148 impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
129 }) 149 })
130 }) 150 })
131 .collect() 151 .collect()
@@ -430,8 +450,7 @@ pub(crate) fn trait_datum_query(
430 fundamental: false, 450 fundamental: false,
431 }; 451 };
432 let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); 452 let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
433 let associated_ty_ids = 453 let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();
434 trait_data.associated_types().map(|type_alias| to_assoc_type_id(type_alias)).collect();
435 let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; 454 let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
436 let well_known = 455 let well_known =
437 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); 456 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
diff --git a/crates/hir_ty/src/consteval.rs b/crates/hir_ty/src/consteval.rs
index e3ceb3d62..6f0bf8f8c 100644
--- a/crates/hir_ty/src/consteval.rs
+++ b/crates/hir_ty/src/consteval.rs
@@ -49,7 +49,7 @@ pub fn usize_const(value: Option<u64>) -> Const {
49 ConstData { 49 ConstData {
50 ty: TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(&Interner), 50 ty: TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(&Interner),
51 value: ConstValue::Concrete(chalk_ir::ConcreteConst { 51 value: ConstValue::Concrete(chalk_ir::ConcreteConst {
52 interned: value.map(|value| ConstScalar::Usize(value)).unwrap_or(ConstScalar::Unknown), 52 interned: value.map(ConstScalar::Usize).unwrap_or(ConstScalar::Unknown),
53 }), 53 }),
54 } 54 }
55 .intern(&Interner) 55 .intern(&Interner)
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index be5b9110e..b9003c413 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -5,8 +5,8 @@ use std::sync::Arc;
5 5
6use base_db::{impl_intern_key, salsa, CrateId, Upcast}; 6use base_db::{impl_intern_key, salsa, CrateId, Upcast};
7use hir_def::{ 7use hir_def::{
8 db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, 8 db::DefDatabase, expr::ExprId, BlockId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId,
9 LifetimeParamId, LocalFieldId, TypeParamId, VariantId, 9 ImplId, LifetimeParamId, LocalFieldId, TypeParamId, VariantId,
10}; 10};
11use la_arena::ArenaMap; 11use la_arena::ArenaMap;
12 12
@@ -79,6 +79,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
79 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)] 79 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
80 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>; 80 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
81 81
82 #[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
83 fn trait_impls_in_block(&self, krate: BlockId) -> Option<Arc<TraitImpls>>;
84
82 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] 85 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
83 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>; 86 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
84 87
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 283894704..6339c9687 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -4,325 +4,31 @@ mod match_check;
4mod unsafe_check; 4mod unsafe_check;
5mod decl_check; 5mod decl_check;
6 6
7use std::{any::Any, fmt}; 7use std::fmt;
8 8
9use base_db::CrateId; 9use base_db::CrateId;
10use hir_def::{DefWithBodyId, ModuleDefId}; 10use hir_def::ModuleDefId;
11use hir_expand::{name::Name, HirFileId, InFile}; 11use hir_expand::HirFileId;
12use stdx::format_to; 12use syntax::{ast, AstPtr};
13use syntax::{ast, AstPtr, SyntaxNodePtr};
14 13
15use crate::{ 14use crate::db::HirDatabase;
16 db::HirDatabase,
17 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink},
18};
19 15
20pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; 16pub use crate::diagnostics::{
17 expr::{
18 record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
19 },
20 unsafe_check::missing_unsafe,
21};
21 22
22pub fn validate_module_item( 23pub fn validate_module_item(
23 db: &dyn HirDatabase, 24 db: &dyn HirDatabase,
24 krate: CrateId, 25 krate: CrateId,
25 owner: ModuleDefId, 26 owner: ModuleDefId,
26 sink: &mut DiagnosticSink<'_>, 27) -> Vec<IncorrectCase> {
27) {
28 let _p = profile::span("validate_module_item"); 28 let _p = profile::span("validate_module_item");
29 let mut validator = decl_check::DeclValidator::new(db, krate, sink); 29 let mut validator = decl_check::DeclValidator::new(db, krate);
30 validator.validate_item(owner); 30 validator.validate_item(owner);
31} 31 validator.sink
32
33pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
34 let _p = profile::span("validate_body");
35 let infer = db.infer(owner);
36 infer.add_diagnostics(db, owner, sink);
37 let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink);
38 validator.validate_body(db);
39 let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink);
40 validator.validate_body(db);
41}
42
43// Diagnostic: no-such-field
44//
45// This diagnostic is triggered if created structure does not have field provided in record.
46#[derive(Debug)]
47pub struct NoSuchField {
48 pub file: HirFileId,
49 pub field: AstPtr<ast::RecordExprField>,
50}
51
52impl Diagnostic for NoSuchField {
53 fn code(&self) -> DiagnosticCode {
54 DiagnosticCode("no-such-field")
55 }
56
57 fn message(&self) -> String {
58 "no such field".to_string()
59 }
60
61 fn display_source(&self) -> InFile<SyntaxNodePtr> {
62 InFile::new(self.file, self.field.clone().into())
63 }
64
65 fn as_any(&self) -> &(dyn Any + Send + 'static) {
66 self
67 }
68}
69
70// Diagnostic: missing-structure-fields
71//
72// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
73//
74// Example:
75//
76// ```rust
77// struct A { a: u8, b: u8 }
78//
79// let a = A { a: 10 };
80// ```
81#[derive(Debug)]
82pub struct MissingFields {
83 pub file: HirFileId,
84 pub field_list_parent: AstPtr<ast::RecordExpr>,
85 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
86 pub missed_fields: Vec<Name>,
87}
88
89impl Diagnostic for MissingFields {
90 fn code(&self) -> DiagnosticCode {
91 DiagnosticCode("missing-structure-fields")
92 }
93 fn message(&self) -> String {
94 let mut buf = String::from("Missing structure fields:\n");
95 for field in &self.missed_fields {
96 format_to!(buf, "- {}\n", field);
97 }
98 buf
99 }
100
101 fn display_source(&self) -> InFile<SyntaxNodePtr> {
102 InFile {
103 file_id: self.file,
104 value: self
105 .field_list_parent_path
106 .clone()
107 .map(SyntaxNodePtr::from)
108 .unwrap_or_else(|| self.field_list_parent.clone().into()),
109 }
110 }
111
112 fn as_any(&self) -> &(dyn Any + Send + 'static) {
113 self
114 }
115}
116
117// Diagnostic: missing-pat-fields
118//
119// This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure.
120//
121// Example:
122//
123// ```rust
124// struct A { a: u8, b: u8 }
125//
126// let a = A { a: 10, b: 20 };
127//
128// if let A { a } = a {
129// // ...
130// }
131// ```
132#[derive(Debug)]
133pub struct MissingPatFields {
134 pub file: HirFileId,
135 pub field_list_parent: AstPtr<ast::RecordPat>,
136 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
137 pub missed_fields: Vec<Name>,
138}
139
140impl Diagnostic for MissingPatFields {
141 fn code(&self) -> DiagnosticCode {
142 DiagnosticCode("missing-pat-fields")
143 }
144 fn message(&self) -> String {
145 let mut buf = String::from("Missing structure fields:\n");
146 for field in &self.missed_fields {
147 format_to!(buf, "- {}\n", field);
148 }
149 buf
150 }
151 fn display_source(&self) -> InFile<SyntaxNodePtr> {
152 InFile {
153 file_id: self.file,
154 value: self
155 .field_list_parent_path
156 .clone()
157 .map(SyntaxNodePtr::from)
158 .unwrap_or_else(|| self.field_list_parent.clone().into()),
159 }
160 }
161 fn as_any(&self) -> &(dyn Any + Send + 'static) {
162 self
163 }
164}
165
166// Diagnostic: missing-match-arm
167//
168// This diagnostic is triggered if `match` block is missing one or more match arms.
169#[derive(Debug)]
170pub struct MissingMatchArms {
171 pub file: HirFileId,
172 pub match_expr: AstPtr<ast::Expr>,
173 pub arms: AstPtr<ast::MatchArmList>,
174}
175
176impl Diagnostic for MissingMatchArms {
177 fn code(&self) -> DiagnosticCode {
178 DiagnosticCode("missing-match-arm")
179 }
180 fn message(&self) -> String {
181 String::from("Missing match arm")
182 }
183 fn display_source(&self) -> InFile<SyntaxNodePtr> {
184 InFile { file_id: self.file, value: self.match_expr.clone().into() }
185 }
186 fn as_any(&self) -> &(dyn Any + Send + 'static) {
187 self
188 }
189}
190
191// Diagnostic: missing-ok-or-some-in-tail-expr
192//
193// This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`,
194// or if a block that should return `Option` returns a value not wrapped in `Some`.
195//
196// Example:
197//
198// ```rust
199// fn foo() -> Result<u8, ()> {
200// 10
201// }
202// ```
203#[derive(Debug)]
204pub struct MissingOkOrSomeInTailExpr {
205 pub file: HirFileId,
206 pub expr: AstPtr<ast::Expr>,
207 // `Some` or `Ok` depending on whether the return type is Result or Option
208 pub required: String,
209}
210
211impl Diagnostic for MissingOkOrSomeInTailExpr {
212 fn code(&self) -> DiagnosticCode {
213 DiagnosticCode("missing-ok-or-some-in-tail-expr")
214 }
215 fn message(&self) -> String {
216 format!("wrap return expression in {}", self.required)
217 }
218 fn display_source(&self) -> InFile<SyntaxNodePtr> {
219 InFile { file_id: self.file, value: self.expr.clone().into() }
220 }
221 fn as_any(&self) -> &(dyn Any + Send + 'static) {
222 self
223 }
224}
225
226#[derive(Debug)]
227pub struct RemoveThisSemicolon {
228 pub file: HirFileId,
229 pub expr: AstPtr<ast::Expr>,
230}
231
232impl Diagnostic for RemoveThisSemicolon {
233 fn code(&self) -> DiagnosticCode {
234 DiagnosticCode("remove-this-semicolon")
235 }
236
237 fn message(&self) -> String {
238 "Remove this semicolon".to_string()
239 }
240
241 fn display_source(&self) -> InFile<SyntaxNodePtr> {
242 InFile { file_id: self.file, value: self.expr.clone().into() }
243 }
244
245 fn as_any(&self) -> &(dyn Any + Send + 'static) {
246 self
247 }
248}
249
250// Diagnostic: break-outside-of-loop
251//
252// This diagnostic is triggered if the `break` keyword is used outside of a loop.
253#[derive(Debug)]
254pub struct BreakOutsideOfLoop {
255 pub file: HirFileId,
256 pub expr: AstPtr<ast::Expr>,
257}
258
259impl Diagnostic for BreakOutsideOfLoop {
260 fn code(&self) -> DiagnosticCode {
261 DiagnosticCode("break-outside-of-loop")
262 }
263 fn message(&self) -> String {
264 "break outside of loop".to_string()
265 }
266 fn display_source(&self) -> InFile<SyntaxNodePtr> {
267 InFile { file_id: self.file, value: self.expr.clone().into() }
268 }
269 fn as_any(&self) -> &(dyn Any + Send + 'static) {
270 self
271 }
272}
273
274// Diagnostic: missing-unsafe
275//
276// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
277#[derive(Debug)]
278pub struct MissingUnsafe {
279 pub file: HirFileId,
280 pub expr: AstPtr<ast::Expr>,
281}
282
283impl Diagnostic for MissingUnsafe {
284 fn code(&self) -> DiagnosticCode {
285 DiagnosticCode("missing-unsafe")
286 }
287 fn message(&self) -> String {
288 format!("This operation is unsafe and requires an unsafe function or block")
289 }
290 fn display_source(&self) -> InFile<SyntaxNodePtr> {
291 InFile { file_id: self.file, value: self.expr.clone().into() }
292 }
293 fn as_any(&self) -> &(dyn Any + Send + 'static) {
294 self
295 }
296}
297
298// Diagnostic: mismatched-arg-count
299//
300// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
301#[derive(Debug)]
302pub struct MismatchedArgCount {
303 pub file: HirFileId,
304 pub call_expr: AstPtr<ast::Expr>,
305 pub expected: usize,
306 pub found: usize,
307}
308
309impl Diagnostic for MismatchedArgCount {
310 fn code(&self) -> DiagnosticCode {
311 DiagnosticCode("mismatched-arg-count")
312 }
313 fn message(&self) -> String {
314 let s = if self.expected == 1 { "" } else { "s" };
315 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
316 }
317 fn display_source(&self) -> InFile<SyntaxNodePtr> {
318 InFile { file_id: self.file, value: self.call_expr.clone().into() }
319 }
320 fn as_any(&self) -> &(dyn Any + Send + 'static) {
321 self
322 }
323 fn is_experimental(&self) -> bool {
324 true
325 }
326} 32}
327 33
328#[derive(Debug)] 34#[derive(Debug)]
@@ -378,9 +84,6 @@ impl fmt::Display for IdentType {
378 } 84 }
379} 85}
380 86
381// Diagnostic: incorrect-ident-case
382//
383// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
384#[derive(Debug)] 87#[derive(Debug)]
385pub struct IncorrectCase { 88pub struct IncorrectCase {
386 pub file: HirFileId, 89 pub file: HirFileId,
@@ -390,450 +93,3 @@ pub struct IncorrectCase {
390 pub ident_text: String, 93 pub ident_text: String,
391 pub suggested_text: String, 94 pub suggested_text: String,
392} 95}
393
394impl Diagnostic for IncorrectCase {
395 fn code(&self) -> DiagnosticCode {
396 DiagnosticCode("incorrect-ident-case")
397 }
398
399 fn message(&self) -> String {
400 format!(
401 "{} `{}` should have {} name, e.g. `{}`",
402 self.ident_type,
403 self.ident_text,
404 self.expected_case.to_string(),
405 self.suggested_text
406 )
407 }
408
409 fn display_source(&self) -> InFile<SyntaxNodePtr> {
410 InFile::new(self.file, self.ident.clone().into())
411 }
412
413 fn as_any(&self) -> &(dyn Any + Send + 'static) {
414 self
415 }
416
417 fn is_experimental(&self) -> bool {
418 true
419 }
420}
421
422// Diagnostic: replace-filter-map-next-with-find-map
423//
424// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
425#[derive(Debug)]
426pub struct ReplaceFilterMapNextWithFindMap {
427 pub file: HirFileId,
428 /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
429 pub next_expr: AstPtr<ast::Expr>,
430}
431
432impl Diagnostic for ReplaceFilterMapNextWithFindMap {
433 fn code(&self) -> DiagnosticCode {
434 DiagnosticCode("replace-filter-map-next-with-find-map")
435 }
436 fn message(&self) -> String {
437 "replace filter_map(..).next() with find_map(..)".to_string()
438 }
439 fn display_source(&self) -> InFile<SyntaxNodePtr> {
440 InFile { file_id: self.file, value: self.next_expr.clone().into() }
441 }
442 fn as_any(&self) -> &(dyn Any + Send + 'static) {
443 self
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
450 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
451 use hir_expand::db::AstDatabase;
452 use rustc_hash::FxHashMap;
453 use syntax::{TextRange, TextSize};
454
455 use crate::{
456 diagnostics::{validate_body, validate_module_item},
457 diagnostics_sink::{Diagnostic, DiagnosticSinkBuilder},
458 test_db::TestDB,
459 };
460
461 impl TestDB {
462 fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
463 let crate_graph = self.crate_graph();
464 for krate in crate_graph.iter() {
465 let crate_def_map = self.crate_def_map(krate);
466
467 let mut fns = Vec::new();
468 for (module_id, _) in crate_def_map.modules() {
469 for decl in crate_def_map[module_id].scope.declarations() {
470 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
471 validate_module_item(self, krate, decl, &mut sink);
472
473 if let ModuleDefId::FunctionId(f) = decl {
474 fns.push(f)
475 }
476 }
477
478 for impl_id in crate_def_map[module_id].scope.impls() {
479 let impl_data = self.impl_data(impl_id);
480 for item in impl_data.items.iter() {
481 if let AssocItemId::FunctionId(f) = item {
482 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
483 validate_module_item(
484 self,
485 krate,
486 ModuleDefId::FunctionId(*f),
487 &mut sink,
488 );
489 fns.push(*f)
490 }
491 }
492 }
493 }
494
495 for f in fns {
496 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
497 validate_body(self, f.into(), &mut sink);
498 }
499 }
500 }
501 }
502
503 pub(crate) fn check_diagnostics(ra_fixture: &str) {
504 let db = TestDB::with_files(ra_fixture);
505 let annotations = db.extract_annotations();
506
507 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
508 db.diagnostics(|d| {
509 let src = d.display_source();
510 let root = db.parse_or_expand(src.file_id).unwrap();
511 // FIXME: macros...
512 let file_id = src.file_id.original_file(&db);
513 let range = src.value.to_node(&root).text_range();
514 let message = d.message();
515 actual.entry(file_id).or_default().push((range, message));
516 });
517
518 for (file_id, diags) in actual.iter_mut() {
519 diags.sort_by_key(|it| it.0.start());
520 let text = db.file_text(*file_id);
521 // For multiline spans, place them on line start
522 for (range, content) in diags {
523 if text[*range].contains('\n') {
524 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
525 *content = format!("... {}", content);
526 }
527 }
528 }
529
530 assert_eq!(annotations, actual);
531 }
532
533 #[test]
534 fn no_such_field_diagnostics() {
535 check_diagnostics(
536 r#"
537struct S { foo: i32, bar: () }
538impl S {
539 fn new() -> S {
540 S {
541 //^ Missing structure fields:
542 //| - bar
543 foo: 92,
544 baz: 62,
545 //^^^^^^^ no such field
546 }
547 }
548}
549"#,
550 );
551 }
552 #[test]
553 fn no_such_field_with_feature_flag_diagnostics() {
554 check_diagnostics(
555 r#"
556//- /lib.rs crate:foo cfg:feature=foo
557struct MyStruct {
558 my_val: usize,
559 #[cfg(feature = "foo")]
560 bar: bool,
561}
562
563impl MyStruct {
564 #[cfg(feature = "foo")]
565 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
566 Self { my_val, bar }
567 }
568 #[cfg(not(feature = "foo"))]
569 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
570 Self { my_val }
571 }
572}
573"#,
574 );
575 }
576
577 #[test]
578 fn no_such_field_enum_with_feature_flag_diagnostics() {
579 check_diagnostics(
580 r#"
581//- /lib.rs crate:foo cfg:feature=foo
582enum Foo {
583 #[cfg(not(feature = "foo"))]
584 Buz,
585 #[cfg(feature = "foo")]
586 Bar,
587 Baz
588}
589
590fn test_fn(f: Foo) {
591 match f {
592 Foo::Bar => {},
593 Foo::Baz => {},
594 }
595}
596"#,
597 );
598 }
599
600 #[test]
601 fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
602 check_diagnostics(
603 r#"
604//- /lib.rs crate:foo cfg:feature=foo
605struct S {
606 #[cfg(feature = "foo")]
607 foo: u32,
608 #[cfg(not(feature = "foo"))]
609 bar: u32,
610}
611
612impl S {
613 #[cfg(feature = "foo")]
614 fn new(foo: u32) -> Self {
615 Self { foo }
616 }
617 #[cfg(not(feature = "foo"))]
618 fn new(bar: u32) -> Self {
619 Self { bar }
620 }
621 fn new2(bar: u32) -> Self {
622 #[cfg(feature = "foo")]
623 { Self { foo: bar } }
624 #[cfg(not(feature = "foo"))]
625 { Self { bar } }
626 }
627 fn new2(val: u32) -> Self {
628 Self {
629 #[cfg(feature = "foo")]
630 foo: val,
631 #[cfg(not(feature = "foo"))]
632 bar: val,
633 }
634 }
635}
636"#,
637 );
638 }
639
640 #[test]
641 fn no_such_field_with_type_macro() {
642 check_diagnostics(
643 r#"
644macro_rules! Type { () => { u32 }; }
645struct Foo { bar: Type![] }
646
647impl Foo {
648 fn new() -> Self {
649 Foo { bar: 0 }
650 }
651}
652"#,
653 );
654 }
655
656 #[test]
657 fn missing_record_pat_field_diagnostic() {
658 check_diagnostics(
659 r#"
660struct S { foo: i32, bar: () }
661fn baz(s: S) {
662 let S { foo: _ } = s;
663 //^ Missing structure fields:
664 //| - bar
665}
666"#,
667 );
668 }
669
670 #[test]
671 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
672 check_diagnostics(
673 r"
674struct S { foo: i32, bar: () }
675fn baz(s: S) -> i32 {
676 match s {
677 S { foo, .. } => foo,
678 }
679}
680",
681 )
682 }
683
684 #[test]
685 fn missing_record_pat_field_box() {
686 check_diagnostics(
687 r"
688struct S { s: Box<u32> }
689fn x(a: S) {
690 let S { box s } = a;
691}
692",
693 )
694 }
695
696 #[test]
697 fn missing_record_pat_field_ref() {
698 check_diagnostics(
699 r"
700struct S { s: u32 }
701fn x(a: S) {
702 let S { ref s } = a;
703}
704",
705 )
706 }
707
708 #[test]
709 fn import_extern_crate_clash_with_inner_item() {
710 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
711
712 check_diagnostics(
713 r#"
714//- /lib.rs crate:lib deps:jwt
715mod permissions;
716
717use permissions::jwt;
718
719fn f() {
720 fn inner() {}
721 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
722}
723
724//- /permissions.rs
725pub mod jwt {
726 pub struct Claims {}
727}
728
729//- /jwt/lib.rs crate:jwt
730pub struct Claims {
731 field: u8,
732}
733 "#,
734 );
735 }
736
737 #[test]
738 fn break_outside_of_loop() {
739 check_diagnostics(
740 r#"
741fn foo() { break; }
742 //^^^^^ break outside of loop
743"#,
744 );
745 }
746
747 #[test]
748 fn missing_semicolon() {
749 check_diagnostics(
750 r#"
751 fn test() -> i32 { 123; }
752 //^^^ Remove this semicolon
753 "#,
754 );
755 }
756
757 // Register the required standard library types to make the tests work
758 fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
759 let prefix = r#"
760 //- /main.rs crate:main deps:core
761 use core::iter::Iterator;
762 use core::option::Option::{self, Some, None};
763 "#;
764 let suffix = r#"
765 //- /core/lib.rs crate:core
766 pub mod option {
767 pub enum Option<T> { Some(T), None }
768 }
769 pub mod iter {
770 pub trait Iterator {
771 type Item;
772 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
773 fn next(&mut self) -> Option<Self::Item>;
774 }
775 pub struct FilterMap {}
776 impl Iterator for FilterMap {
777 type Item = i32;
778 fn next(&mut self) -> i32 { 7 }
779 }
780 }
781 "#;
782 format!("{}{}{}", prefix, body, suffix)
783 }
784
785 #[test]
786 fn replace_filter_map_next_with_find_map2() {
787 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
788 r#"
789 fn foo() {
790 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
791 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
792 }
793 "#,
794 ));
795 }
796
797 #[test]
798 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
799 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
800 r#"
801 fn foo() {
802 let m = [1, 2, 3]
803 .iter()
804 .filter_map(|x| if *x == 2 { Some (4) } else { None })
805 .len();
806 }
807 "#,
808 ));
809 }
810
811 #[test]
812 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
813 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
814 r#"
815 fn foo() {
816 let m = [1, 2, 3]
817 .iter()
818 .filter_map(|x| if *x == 2 { Some (4) } else { None })
819 .map(|x| x + 2)
820 .len();
821 }
822 "#,
823 ));
824 }
825
826 #[test]
827 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
828 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
829 r#"
830 fn foo() {
831 let m = [1, 2, 3]
832 .iter()
833 .filter_map(|x| if *x == 2 { Some (4) } else { None });
834 let n = m.next();
835 }
836 "#,
837 ));
838 }
839}
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index cfb5d7320..f26150b77 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -29,7 +29,6 @@ use syntax::{
29use crate::{ 29use crate::{
30 db::HirDatabase, 30 db::HirDatabase,
31 diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, 31 diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase},
32 diagnostics_sink::DiagnosticSink,
33}; 32};
34 33
35mod allow { 34mod allow {
@@ -40,10 +39,10 @@ mod allow {
40 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; 39 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
41} 40}
42 41
43pub(super) struct DeclValidator<'a, 'b> { 42pub(super) struct DeclValidator<'a> {
44 db: &'a dyn HirDatabase, 43 db: &'a dyn HirDatabase,
45 krate: CrateId, 44 krate: CrateId,
46 sink: &'a mut DiagnosticSink<'b>, 45 pub(super) sink: Vec<IncorrectCase>,
47} 46}
48 47
49#[derive(Debug)] 48#[derive(Debug)]
@@ -53,13 +52,9 @@ struct Replacement {
53 expected_case: CaseType, 52 expected_case: CaseType,
54} 53}
55 54
56impl<'a, 'b> DeclValidator<'a, 'b> { 55impl<'a> DeclValidator<'a> {
57 pub(super) fn new( 56 pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> {
58 db: &'a dyn HirDatabase, 57 DeclValidator { db, krate, sink: Vec::new() }
59 krate: CrateId,
60 sink: &'a mut DiagnosticSink<'b>,
61 ) -> DeclValidator<'a, 'b> {
62 DeclValidator { db, krate, sink }
63 } 58 }
64 59
65 pub(super) fn validate_item(&mut self, item: ModuleDefId) { 60 pub(super) fn validate_item(&mut self, item: ModuleDefId) {
@@ -131,7 +126,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
131 for (_, block_def_map) in body.blocks(self.db.upcast()) { 126 for (_, block_def_map) in body.blocks(self.db.upcast()) {
132 for (_, module) in block_def_map.modules() { 127 for (_, module) in block_def_map.modules() {
133 for def_id in module.scope.declarations() { 128 for def_id in module.scope.declarations() {
134 let mut validator = DeclValidator::new(self.db, self.krate, self.sink); 129 let mut validator = DeclValidator::new(self.db, self.krate);
135 validator.validate_item(def_id); 130 validator.validate_item(def_id);
136 } 131 }
137 } 132 }
@@ -623,343 +618,3 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
623 self.sink.push(diagnostic); 618 self.sink.push(diagnostic);
624 } 619 }
625} 620}
626
627#[cfg(test)]
628mod tests {
629 use crate::diagnostics::tests::check_diagnostics;
630
631 #[test]
632 fn incorrect_function_name() {
633 check_diagnostics(
634 r#"
635fn NonSnakeCaseName() {}
636// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
637"#,
638 );
639 }
640
641 #[test]
642 fn incorrect_function_params() {
643 check_diagnostics(
644 r#"
645fn foo(SomeParam: u8) {}
646 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
647
648fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
649 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
650"#,
651 );
652 }
653
654 #[test]
655 fn incorrect_variable_names() {
656 check_diagnostics(
657 r#"
658fn foo() {
659 let SOME_VALUE = 10;
660 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
661 let AnotherValue = 20;
662 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
663}
664"#,
665 );
666 }
667
668 #[test]
669 fn incorrect_struct_names() {
670 check_diagnostics(
671 r#"
672struct non_camel_case_name {}
673 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
674
675struct SCREAMING_CASE {}
676 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
677"#,
678 );
679 }
680
681 #[test]
682 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
683 check_diagnostics(
684 r#"
685struct AABB {}
686"#,
687 );
688 }
689
690 #[test]
691 fn incorrect_struct_field() {
692 check_diagnostics(
693 r#"
694struct SomeStruct { SomeField: u8 }
695 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
696"#,
697 );
698 }
699
700 #[test]
701 fn incorrect_enum_names() {
702 check_diagnostics(
703 r#"
704enum some_enum { Val(u8) }
705 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
706
707enum SOME_ENUM
708 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
709"#,
710 );
711 }
712
713 #[test]
714 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
715 check_diagnostics(
716 r#"
717enum AABB {}
718"#,
719 );
720 }
721
722 #[test]
723 fn incorrect_enum_variant_name() {
724 check_diagnostics(
725 r#"
726enum SomeEnum { SOME_VARIANT(u8) }
727 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
728"#,
729 );
730 }
731
732 #[test]
733 fn incorrect_const_name() {
734 check_diagnostics(
735 r#"
736const some_weird_const: u8 = 10;
737 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
738
739fn func() {
740 const someConstInFunc: &str = "hi there";
741 // ^^^^^^^^^^^^^^^ Constant `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
742
743}
744"#,
745 );
746 }
747
748 #[test]
749 fn incorrect_static_name() {
750 check_diagnostics(
751 r#"
752static some_weird_const: u8 = 10;
753 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
754
755fn func() {
756 static someConstInFunc: &str = "hi there";
757 // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
758}
759"#,
760 );
761 }
762
763 #[test]
764 fn fn_inside_impl_struct() {
765 check_diagnostics(
766 r#"
767struct someStruct;
768 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
769
770impl someStruct {
771 fn SomeFunc(&self) {
772 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
773 static someConstInFunc: &str = "hi there";
774 // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
775 let WHY_VAR_IS_CAPS = 10;
776 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
777 }
778}
779"#,
780 );
781 }
782
783 #[test]
784 fn no_diagnostic_for_enum_varinats() {
785 check_diagnostics(
786 r#"
787enum Option { Some, None }
788
789fn main() {
790 match Option::None {
791 None => (),
792 Some => (),
793 }
794}
795"#,
796 );
797 }
798
799 #[test]
800 fn non_let_bind() {
801 check_diagnostics(
802 r#"
803enum Option { Some, None }
804
805fn main() {
806 match Option::None {
807 SOME_VAR @ None => (),
808 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
809 Some => (),
810 }
811}
812"#,
813 );
814 }
815
816 #[test]
817 fn allow_attributes() {
818 check_diagnostics(
819 r#"
820#[allow(non_snake_case)]
821fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
822 // cov_flags generated output from elsewhere in this file
823 extern "C" {
824 #[no_mangle]
825 static lower_case: u8;
826 }
827
828 let OtherVar = SOME_VAR + 1;
829 OtherVar
830}
831
832#[allow(nonstandard_style)]
833mod CheckNonstandardStyle {
834 fn HiImABadFnName() {}
835}
836
837#[allow(bad_style)]
838mod CheckBadStyle {
839 fn HiImABadFnName() {}
840}
841
842mod F {
843 #![allow(non_snake_case)]
844 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
845}
846
847#[allow(non_snake_case, non_camel_case_types)]
848pub struct some_type {
849 SOME_FIELD: u8,
850 SomeField: u16,
851}
852
853#[allow(non_upper_case_globals)]
854pub const some_const: u8 = 10;
855
856#[allow(non_upper_case_globals)]
857pub static SomeStatic: u8 = 10;
858 "#,
859 );
860 }
861
862 #[test]
863 fn allow_attributes_crate_attr() {
864 check_diagnostics(
865 r#"
866#![allow(non_snake_case)]
867
868mod F {
869 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
870}
871 "#,
872 );
873 }
874
875 #[test]
876 #[ignore]
877 fn bug_trait_inside_fn() {
878 // FIXME:
879 // This is broken, and in fact, should not even be looked at by this
880 // lint in the first place. There's weird stuff going on in the
881 // collection phase.
882 // It's currently being brought in by:
883 // * validate_func on `a` recursing into modules
884 // * then it finds the trait and then the function while iterating
885 // through modules
886 // * then validate_func is called on Dirty
887 // * ... which then proceeds to look at some unknown module taking no
888 // attrs from either the impl or the fn a, and then finally to the root
889 // module
890 //
891 // It should find the attribute on the trait, but it *doesn't even see
892 // the trait* as far as I can tell.
893
894 check_diagnostics(
895 r#"
896trait T { fn a(); }
897struct U {}
898impl T for U {
899 fn a() {
900 // this comes out of bitflags, mostly
901 #[allow(non_snake_case)]
902 trait __BitFlags {
903 const HiImAlsoBad: u8 = 2;
904 #[inline]
905 fn Dirty(&self) -> bool {
906 false
907 }
908 }
909
910 }
911}
912 "#,
913 );
914 }
915
916 #[test]
917 #[ignore]
918 fn bug_traits_arent_checked() {
919 // FIXME: Traits and functions in traits aren't currently checked by
920 // r-a, even though rustc will complain about them.
921 check_diagnostics(
922 r#"
923trait BAD_TRAIT {
924 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
925 fn BAD_FUNCTION();
926 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
927 fn BadFunction();
928 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
929}
930 "#,
931 );
932 }
933
934 #[test]
935 fn ignores_extern_items() {
936 cov_mark::check!(extern_func_incorrect_case_ignored);
937 cov_mark::check!(extern_static_incorrect_case_ignored);
938 check_diagnostics(
939 r#"
940extern {
941 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
942 pub static SomeStatic: u8 = 10;
943}
944 "#,
945 );
946 }
947
948 #[test]
949 fn infinite_loop_inner_items() {
950 check_diagnostics(
951 r#"
952fn qualify() {
953 mod foo {
954 use super::*;
955 }
956}
957 "#,
958 )
959 }
960
961 #[test] // Issue #8809.
962 fn parenthesized_parameter() {
963 check_diagnostics(r#"fn f((O): _) {}"#)
964 }
965}
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index a2a4d61db..b809b96a0 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -8,20 +8,15 @@ use hir_def::{
8 expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId, HasModule, 8 expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId, HasModule,
9}; 9};
10use hir_expand::name; 10use hir_expand::name;
11use itertools::Either;
11use rustc_hash::FxHashSet; 12use rustc_hash::FxHashSet;
12use syntax::{ast, AstPtr};
13 13
14use crate::{ 14use crate::{
15 db::HirDatabase, 15 db::HirDatabase,
16 diagnostics::{ 16 diagnostics::match_check::{
17 match_check::{ 17 self,
18 self, 18 usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena},
19 usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena},
20 },
21 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
22 MissingPatFields, RemoveThisSemicolon,
23 }, 19 },
24 diagnostics_sink::DiagnosticSink,
25 AdtId, InferenceResult, Interner, TyExt, TyKind, 20 AdtId, InferenceResult, Interner, TyExt, TyKind,
26}; 21};
27 22
@@ -31,38 +26,67 @@ pub(crate) use hir_def::{
31 LocalFieldId, VariantId, 26 LocalFieldId, VariantId,
32}; 27};
33 28
34use super::ReplaceFilterMapNextWithFindMap; 29pub enum BodyValidationDiagnostic {
30 RecordMissingFields {
31 record: Either<ExprId, PatId>,
32 variant: VariantId,
33 missed_fields: Vec<LocalFieldId>,
34 },
35 ReplaceFilterMapNextWithFindMap {
36 method_call_expr: ExprId,
37 },
38 MismatchedArgCount {
39 call_expr: ExprId,
40 expected: usize,
41 found: usize,
42 },
43 RemoveThisSemicolon {
44 expr: ExprId,
45 },
46 MissingOkOrSomeInTailExpr {
47 expr: ExprId,
48 required: String,
49 },
50 MissingMatchArms {
51 match_expr: ExprId,
52 },
53}
54
55impl BodyValidationDiagnostic {
56 pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec<BodyValidationDiagnostic> {
57 let _p = profile::span("BodyValidationDiagnostic::collect");
58 let infer = db.infer(owner);
59 let mut validator = ExprValidator::new(owner, infer.clone());
60 validator.validate_body(db);
61 validator.diagnostics
62 }
63}
35 64
36pub(super) struct ExprValidator<'a, 'b: 'a> { 65struct ExprValidator {
37 owner: DefWithBodyId, 66 owner: DefWithBodyId,
38 infer: Arc<InferenceResult>, 67 infer: Arc<InferenceResult>,
39 sink: &'a mut DiagnosticSink<'b>, 68 pub(super) diagnostics: Vec<BodyValidationDiagnostic>,
40} 69}
41 70
42impl<'a, 'b> ExprValidator<'a, 'b> { 71impl ExprValidator {
43 pub(super) fn new( 72 fn new(owner: DefWithBodyId, infer: Arc<InferenceResult>) -> ExprValidator {
44 owner: DefWithBodyId, 73 ExprValidator { owner, infer, diagnostics: Vec::new() }
45 infer: Arc<InferenceResult>,
46 sink: &'a mut DiagnosticSink<'b>,
47 ) -> ExprValidator<'a, 'b> {
48 ExprValidator { owner, infer, sink }
49 } 74 }
50 75
51 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { 76 fn validate_body(&mut self, db: &dyn HirDatabase) {
52 self.check_for_filter_map_next(db); 77 self.check_for_filter_map_next(db);
53 78
54 let body = db.body(self.owner); 79 let body = db.body(self.owner);
55 80
56 for (id, expr) in body.exprs.iter() { 81 for (id, expr) in body.exprs.iter() {
57 if let Some((variant_def, missed_fields, true)) = 82 if let Some((variant, missed_fields, true)) =
58 record_literal_missing_fields(db, &self.infer, id, expr) 83 record_literal_missing_fields(db, &self.infer, id, expr)
59 { 84 {
60 self.create_record_literal_missing_fields_diagnostic( 85 self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
61 id, 86 record: Either::Left(id),
62 db, 87 variant,
63 variant_def,
64 missed_fields, 88 missed_fields,
65 ); 89 });
66 } 90 }
67 91
68 match expr { 92 match expr {
@@ -76,15 +100,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
76 } 100 }
77 } 101 }
78 for (id, pat) in body.pats.iter() { 102 for (id, pat) in body.pats.iter() {
79 if let Some((variant_def, missed_fields, true)) = 103 if let Some((variant, missed_fields, true)) =
80 record_pattern_missing_fields(db, &self.infer, id, pat) 104 record_pattern_missing_fields(db, &self.infer, id, pat)
81 { 105 {
82 self.create_record_pattern_missing_fields_diagnostic( 106 self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
83 id, 107 record: Either::Right(id),
84 db, 108 variant,
85 variant_def,
86 missed_fields, 109 missed_fields,
87 ); 110 });
88 } 111 }
89 } 112 }
90 let body_expr = &body[body.body_expr]; 113 let body_expr = &body[body.body_expr];
@@ -92,71 +115,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
92 if let Some(t) = tail { 115 if let Some(t) = tail {
93 self.validate_results_in_tail_expr(body.body_expr, *t, db); 116 self.validate_results_in_tail_expr(body.body_expr, *t, db);
94 } else if let Some(Statement::Expr { expr: id, .. }) = statements.last() { 117 } else if let Some(Statement::Expr { expr: id, .. }) = statements.last() {
95 self.validate_missing_tail_expr(body.body_expr, *id, db); 118 self.validate_missing_tail_expr(body.body_expr, *id);
96 }
97 }
98 }
99
100 fn create_record_literal_missing_fields_diagnostic(
101 &mut self,
102 id: ExprId,
103 db: &dyn HirDatabase,
104 variant_def: VariantId,
105 missed_fields: Vec<LocalFieldId>,
106 ) {
107 // XXX: only look at source_map if we do have missing fields
108 let (_, source_map) = db.body_with_source_map(self.owner);
109
110 if let Ok(source_ptr) = source_map.expr_syntax(id) {
111 let root = source_ptr.file_syntax(db.upcast());
112 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) {
113 if let Some(_) = record_expr.record_expr_field_list() {
114 let variant_data = variant_def.variant_data(db.upcast());
115 let missed_fields = missed_fields
116 .into_iter()
117 .map(|idx| variant_data.fields()[idx].name.clone())
118 .collect();
119 self.sink.push(MissingFields {
120 file: source_ptr.file_id,
121 field_list_parent: AstPtr::new(&record_expr),
122 field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)),
123 missed_fields,
124 })
125 }
126 }
127 }
128 }
129
130 fn create_record_pattern_missing_fields_diagnostic(
131 &mut self,
132 id: PatId,
133 db: &dyn HirDatabase,
134 variant_def: VariantId,
135 missed_fields: Vec<LocalFieldId>,
136 ) {
137 // XXX: only look at source_map if we do have missing fields
138 let (_, source_map) = db.body_with_source_map(self.owner);
139
140 if let Ok(source_ptr) = source_map.pat_syntax(id) {
141 if let Some(expr) = source_ptr.value.as_ref().left() {
142 let root = source_ptr.file_syntax(db.upcast());
143 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
144 if let Some(_) = record_pat.record_pat_field_list() {
145 let variant_data = variant_def.variant_data(db.upcast());
146 let missed_fields = missed_fields
147 .into_iter()
148 .map(|idx| variant_data.fields()[idx].name.clone())
149 .collect();
150 self.sink.push(MissingPatFields {
151 file: source_ptr.file_id,
152 field_list_parent: AstPtr::new(&record_pat),
153 field_list_parent_path: record_pat
154 .path()
155 .map(|path| AstPtr::new(&path)),
156 missed_fields,
157 })
158 }
159 }
160 } 119 }
161 } 120 }
162 } 121 }
@@ -199,13 +158,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
199 if function_id == *next_function_id { 158 if function_id == *next_function_id {
200 if let Some(filter_map_id) = prev { 159 if let Some(filter_map_id) = prev {
201 if *receiver == filter_map_id { 160 if *receiver == filter_map_id {
202 let (_, source_map) = db.body_with_source_map(self.owner); 161 self.diagnostics.push(
203 if let Ok(next_source_ptr) = source_map.expr_syntax(id) { 162 BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap {
204 self.sink.push(ReplaceFilterMapNextWithFindMap { 163 method_call_expr: id,
205 file: next_source_ptr.file_id, 164 },
206 next_expr: next_source_ptr.value, 165 );
207 });
208 }
209 } 166 }
210 } 167 }
211 } 168 }
@@ -266,19 +223,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
266 let mut arg_count = args.len(); 223 let mut arg_count = args.len();
267 224
268 if arg_count != param_count { 225 if arg_count != param_count {
269 let (_, source_map) = db.body_with_source_map(self.owner); 226 if is_method_call {
270 if let Ok(source_ptr) = source_map.expr_syntax(call_id) { 227 param_count -= 1;
271 if is_method_call { 228 arg_count -= 1;
272 param_count -= 1;
273 arg_count -= 1;
274 }
275 self.sink.push(MismatchedArgCount {
276 file: source_ptr.file_id,
277 call_expr: source_ptr.value,
278 expected: param_count,
279 found: arg_count,
280 });
281 } 229 }
230 self.diagnostics.push(BodyValidationDiagnostic::MismatchedArgCount {
231 call_expr: call_id,
232 expected: param_count,
233 found: arg_count,
234 });
282 } 235 }
283 } 236 }
284 237
@@ -346,8 +299,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
346 // fit the match expression, we skip this diagnostic. Skipping the entire 299 // fit the match expression, we skip this diagnostic. Skipping the entire
347 // diagnostic rather than just not including this match arm is preferred 300 // diagnostic rather than just not including this match arm is preferred
348 // to avoid the chance of false positives. 301 // to avoid the chance of false positives.
349 #[cfg(test)] 302 cov_mark::hit!(validate_match_bailed_out);
350 match_check::tests::report_bail_out(db, self.owner, arm.pat, self.sink);
351 return; 303 return;
352 } 304 }
353 305
@@ -382,20 +334,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
382 // FIXME Report witnesses 334 // FIXME Report witnesses
383 // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses); 335 // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses);
384 if !witnesses.is_empty() { 336 if !witnesses.is_empty() {
385 if let Ok(source_ptr) = source_map.expr_syntax(id) { 337 self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { match_expr: id });
386 let root = source_ptr.file_syntax(db.upcast());
387 if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
388 if let (Some(match_expr), Some(arms)) =
389 (match_expr.expr(), match_expr.match_arm_list())
390 {
391 self.sink.push(MissingMatchArms {
392 file: source_ptr.file_id,
393 match_expr: AstPtr::new(&match_expr),
394 arms: AstPtr::new(&arms),
395 })
396 }
397 }
398 }
399 } 338 }
400 } 339 }
401 340
@@ -453,24 +392,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
453 if params.len(&Interner) > 0 392 if params.len(&Interner) > 0
454 && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual) 393 && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual)
455 { 394 {
456 let (_, source_map) = db.body_with_source_map(self.owner); 395 self.diagnostics
457 396 .push(BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr: id, required });
458 if let Ok(source_ptr) = source_map.expr_syntax(id) {
459 self.sink.push(MissingOkOrSomeInTailExpr {
460 file: source_ptr.file_id,
461 expr: source_ptr.value,
462 required,
463 });
464 }
465 } 397 }
466 } 398 }
467 399
468 fn validate_missing_tail_expr( 400 fn validate_missing_tail_expr(&mut self, body_id: ExprId, possible_tail_id: ExprId) {
469 &mut self,
470 body_id: ExprId,
471 possible_tail_id: ExprId,
472 db: &dyn HirDatabase,
473 ) {
474 let mismatch = match self.infer.type_mismatch_for_expr(body_id) { 401 let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
475 Some(m) => m, 402 Some(m) => m,
476 None => return, 403 None => return,
@@ -485,12 +412,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
485 return; 412 return;
486 } 413 }
487 414
488 let (_, source_map) = db.body_with_source_map(self.owner); 415 self.diagnostics
489 416 .push(BodyValidationDiagnostic::RemoveThisSemicolon { expr: possible_tail_id });
490 if let Ok(source_ptr) = source_map.expr_syntax(possible_tail_id) {
491 self.sink
492 .push(RemoveThisSemicolon { file: source_ptr.file_id, expr: source_ptr.value });
493 }
494 } 417 }
495} 418}
496 419
@@ -568,258 +491,3 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
568 walk(pat, body, infer, &mut has_type_mismatches); 491 walk(pat, body, infer, &mut has_type_mismatches);
569 !has_type_mismatches 492 !has_type_mismatches
570} 493}
571
572#[cfg(test)]
573mod tests {
574 use crate::diagnostics::tests::check_diagnostics;
575
576 #[test]
577 fn simple_free_fn_zero() {
578 check_diagnostics(
579 r#"
580fn zero() {}
581fn f() { zero(1); }
582 //^^^^^^^ Expected 0 arguments, found 1
583"#,
584 );
585
586 check_diagnostics(
587 r#"
588fn zero() {}
589fn f() { zero(); }
590"#,
591 );
592 }
593
594 #[test]
595 fn simple_free_fn_one() {
596 check_diagnostics(
597 r#"
598fn one(arg: u8) {}
599fn f() { one(); }
600 //^^^^^ Expected 1 argument, found 0
601"#,
602 );
603
604 check_diagnostics(
605 r#"
606fn one(arg: u8) {}
607fn f() { one(1); }
608"#,
609 );
610 }
611
612 #[test]
613 fn method_as_fn() {
614 check_diagnostics(
615 r#"
616struct S;
617impl S { fn method(&self) {} }
618
619fn f() {
620 S::method();
621} //^^^^^^^^^^^ Expected 1 argument, found 0
622"#,
623 );
624
625 check_diagnostics(
626 r#"
627struct S;
628impl S { fn method(&self) {} }
629
630fn f() {
631 S::method(&S);
632 S.method();
633}
634"#,
635 );
636 }
637
638 #[test]
639 fn method_with_arg() {
640 check_diagnostics(
641 r#"
642struct S;
643impl S { fn method(&self, arg: u8) {} }
644
645 fn f() {
646 S.method();
647 } //^^^^^^^^^^ Expected 1 argument, found 0
648 "#,
649 );
650
651 check_diagnostics(
652 r#"
653struct S;
654impl S { fn method(&self, arg: u8) {} }
655
656fn f() {
657 S::method(&S, 0);
658 S.method(1);
659}
660"#,
661 );
662 }
663
664 #[test]
665 fn method_unknown_receiver() {
666 // note: this is incorrect code, so there might be errors on this in the
667 // future, but we shouldn't emit an argument count diagnostic here
668 check_diagnostics(
669 r#"
670trait Foo { fn method(&self, arg: usize) {} }
671
672fn f() {
673 let x;
674 x.method();
675}
676"#,
677 );
678 }
679
680 #[test]
681 fn tuple_struct() {
682 check_diagnostics(
683 r#"
684struct Tup(u8, u16);
685fn f() {
686 Tup(0);
687} //^^^^^^ Expected 2 arguments, found 1
688"#,
689 )
690 }
691
692 #[test]
693 fn enum_variant() {
694 check_diagnostics(
695 r#"
696enum En { Variant(u8, u16), }
697fn f() {
698 En::Variant(0);
699} //^^^^^^^^^^^^^^ Expected 2 arguments, found 1
700"#,
701 )
702 }
703
704 #[test]
705 fn enum_variant_type_macro() {
706 check_diagnostics(
707 r#"
708macro_rules! Type {
709 () => { u32 };
710}
711enum Foo {
712 Bar(Type![])
713}
714impl Foo {
715 fn new() {
716 Foo::Bar(0);
717 Foo::Bar(0, 1);
718 //^^^^^^^^^^^^^^ Expected 1 argument, found 2
719 Foo::Bar();
720 //^^^^^^^^^^ Expected 1 argument, found 0
721 }
722}
723 "#,
724 );
725 }
726
727 #[test]
728 fn varargs() {
729 check_diagnostics(
730 r#"
731extern "C" {
732 fn fixed(fixed: u8);
733 fn varargs(fixed: u8, ...);
734 fn varargs2(...);
735}
736
737fn f() {
738 unsafe {
739 fixed(0);
740 fixed(0, 1);
741 //^^^^^^^^^^^ Expected 1 argument, found 2
742 varargs(0);
743 varargs(0, 1);
744 varargs2();
745 varargs2(0);
746 varargs2(0, 1);
747 }
748}
749 "#,
750 )
751 }
752
753 #[test]
754 fn arg_count_lambda() {
755 check_diagnostics(
756 r#"
757fn main() {
758 let f = |()| ();
759 f();
760 //^^^ Expected 1 argument, found 0
761 f(());
762 f((), ());
763 //^^^^^^^^^ Expected 1 argument, found 2
764}
765"#,
766 )
767 }
768
769 #[test]
770 fn cfgd_out_call_arguments() {
771 check_diagnostics(
772 r#"
773struct C(#[cfg(FALSE)] ());
774impl C {
775 fn new() -> Self {
776 Self(
777 #[cfg(FALSE)]
778 (),
779 )
780 }
781
782 fn method(&self) {}
783}
784
785fn main() {
786 C::new().method(#[cfg(FALSE)] 0);
787}
788 "#,
789 );
790 }
791
792 #[test]
793 fn cfgd_out_fn_params() {
794 check_diagnostics(
795 r#"
796fn foo(#[cfg(NEVER)] x: ()) {}
797
798struct S;
799
800impl S {
801 fn method(#[cfg(NEVER)] self) {}
802 fn method2(#[cfg(NEVER)] self, arg: u8) {}
803 fn method3(self, #[cfg(NEVER)] arg: u8) {}
804}
805
806extern "C" {
807 fn fixed(fixed: u8, #[cfg(NEVER)] ...);
808 fn varargs(#[cfg(not(NEVER))] ...);
809}
810
811fn main() {
812 foo();
813 S::method();
814 S::method2(0);
815 S::method3(S);
816 S.method3();
817 unsafe {
818 fixed(0);
819 varargs(1, 2, 3);
820 }
821}
822 "#,
823 )
824 }
825}
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index c8e1b23de..a30e42699 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -364,960 +364,3 @@ impl PatternFoldable for PatKind {
364 } 364 }
365 } 365 }
366} 366}
367
368#[cfg(test)]
369pub(super) mod tests {
370 mod report {
371 use std::any::Any;
372
373 use hir_def::{expr::PatId, DefWithBodyId};
374 use hir_expand::{HirFileId, InFile};
375 use syntax::SyntaxNodePtr;
376
377 use crate::{
378 db::HirDatabase,
379 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink},
380 };
381
382 /// In tests, match check bails out loudly.
383 /// This helps to catch incorrect tests that pass due to false negatives.
384 pub(crate) fn report_bail_out(
385 db: &dyn HirDatabase,
386 def: DefWithBodyId,
387 pat: PatId,
388 sink: &mut DiagnosticSink,
389 ) {
390 let (_, source_map) = db.body_with_source_map(def);
391 if let Ok(source_ptr) = source_map.pat_syntax(pat) {
392 let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into);
393 sink.push(BailedOut { file: source_ptr.file_id, pat_syntax_ptr });
394 }
395 }
396
397 #[derive(Debug)]
398 struct BailedOut {
399 file: HirFileId,
400 pat_syntax_ptr: SyntaxNodePtr,
401 }
402
403 impl Diagnostic for BailedOut {
404 fn code(&self) -> DiagnosticCode {
405 DiagnosticCode("internal:match-check-bailed-out")
406 }
407 fn message(&self) -> String {
408 format!("Internal: match check bailed out")
409 }
410 fn display_source(&self) -> InFile<SyntaxNodePtr> {
411 InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() }
412 }
413 fn as_any(&self) -> &(dyn Any + Send + 'static) {
414 self
415 }
416 }
417 }
418
419 use crate::diagnostics::tests::check_diagnostics;
420
421 pub(crate) use self::report::report_bail_out;
422
423 #[test]
424 fn empty_tuple() {
425 check_diagnostics(
426 r#"
427fn main() {
428 match () { }
429 //^^ Missing match arm
430 match (()) { }
431 //^^^^ Missing match arm
432
433 match () { _ => (), }
434 match () { () => (), }
435 match (()) { (()) => (), }
436}
437"#,
438 );
439 }
440
441 #[test]
442 fn tuple_of_two_empty_tuple() {
443 check_diagnostics(
444 r#"
445fn main() {
446 match ((), ()) { }
447 //^^^^^^^^ Missing match arm
448
449 match ((), ()) { ((), ()) => (), }
450}
451"#,
452 );
453 }
454
455 #[test]
456 fn boolean() {
457 check_diagnostics(
458 r#"
459fn test_main() {
460 match false { }
461 //^^^^^ Missing match arm
462 match false { true => (), }
463 //^^^^^ Missing match arm
464 match (false, true) {}
465 //^^^^^^^^^^^^^ Missing match arm
466 match (false, true) { (true, true) => (), }
467 //^^^^^^^^^^^^^ Missing match arm
468 match (false, true) {
469 //^^^^^^^^^^^^^ Missing match arm
470 (false, true) => (),
471 (false, false) => (),
472 (true, false) => (),
473 }
474 match (false, true) { (true, _x) => (), }
475 //^^^^^^^^^^^^^ Missing match arm
476
477 match false { true => (), false => (), }
478 match (false, true) {
479 (false, _) => (),
480 (true, false) => (),
481 (_, true) => (),
482 }
483 match (false, true) {
484 (true, true) => (),
485 (true, false) => (),
486 (false, true) => (),
487 (false, false) => (),
488 }
489 match (false, true) {
490 (true, _x) => (),
491 (false, true) => (),
492 (false, false) => (),
493 }
494 match (false, true, false) {
495 (false, ..) => (),
496 (true, ..) => (),
497 }
498 match (false, true, false) {
499 (.., false) => (),
500 (.., true) => (),
501 }
502 match (false, true, false) { (..) => (), }
503}
504"#,
505 );
506 }
507
508 #[test]
509 fn tuple_of_tuple_and_bools() {
510 check_diagnostics(
511 r#"
512fn main() {
513 match (false, ((), false)) {}
514 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
515 match (false, ((), false)) { (true, ((), true)) => (), }
516 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
517 match (false, ((), false)) { (true, _) => (), }
518 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
519
520 match (false, ((), false)) {
521 (true, ((), true)) => (),
522 (true, ((), false)) => (),
523 (false, ((), true)) => (),
524 (false, ((), false)) => (),
525 }
526 match (false, ((), false)) {
527 (true, ((), true)) => (),
528 (true, ((), false)) => (),
529 (false, _) => (),
530 }
531}
532"#,
533 );
534 }
535
536 #[test]
537 fn enums() {
538 check_diagnostics(
539 r#"
540enum Either { A, B, }
541
542fn main() {
543 match Either::A { }
544 //^^^^^^^^^ Missing match arm
545 match Either::B { Either::A => (), }
546 //^^^^^^^^^ Missing match arm
547
548 match &Either::B {
549 //^^^^^^^^^^ Missing match arm
550 Either::A => (),
551 }
552
553 match Either::B {
554 Either::A => (), Either::B => (),
555 }
556 match &Either::B {
557 Either::A => (), Either::B => (),
558 }
559}
560"#,
561 );
562 }
563
564 #[test]
565 fn enum_containing_bool() {
566 check_diagnostics(
567 r#"
568enum Either { A(bool), B }
569
570fn main() {
571 match Either::B { }
572 //^^^^^^^^^ Missing match arm
573 match Either::B {
574 //^^^^^^^^^ Missing match arm
575 Either::A(true) => (), Either::B => ()
576 }
577
578 match Either::B {
579 Either::A(true) => (),
580 Either::A(false) => (),
581 Either::B => (),
582 }
583 match Either::B {
584 Either::B => (),
585 _ => (),
586 }
587 match Either::B {
588 Either::A(_) => (),
589 Either::B => (),
590 }
591
592}
593 "#,
594 );
595 }
596
597 #[test]
598 fn enum_different_sizes() {
599 check_diagnostics(
600 r#"
601enum Either { A(bool), B(bool, bool) }
602
603fn main() {
604 match Either::A(false) {
605 //^^^^^^^^^^^^^^^^ Missing match arm
606 Either::A(_) => (),
607 Either::B(false, _) => (),
608 }
609
610 match Either::A(false) {
611 Either::A(_) => (),
612 Either::B(true, _) => (),
613 Either::B(false, _) => (),
614 }
615 match Either::A(false) {
616 Either::A(true) | Either::A(false) => (),
617 Either::B(true, _) => (),
618 Either::B(false, _) => (),
619 }
620}
621"#,
622 );
623 }
624
625 #[test]
626 fn tuple_of_enum_no_diagnostic() {
627 check_diagnostics(
628 r#"
629enum Either { A(bool), B(bool, bool) }
630enum Either2 { C, D }
631
632fn main() {
633 match (Either::A(false), Either2::C) {
634 (Either::A(true), _) | (Either::A(false), _) => (),
635 (Either::B(true, _), Either2::C) => (),
636 (Either::B(false, _), Either2::C) => (),
637 (Either::B(_, _), Either2::D) => (),
638 }
639}
640"#,
641 );
642 }
643
644 #[test]
645 fn or_pattern_no_diagnostic() {
646 check_diagnostics(
647 r#"
648enum Either {A, B}
649
650fn main() {
651 match (Either::A, Either::B) {
652 (Either::A | Either::B, _) => (),
653 }
654}"#,
655 )
656 }
657
658 #[test]
659 fn mismatched_types() {
660 // Match statements with arms that don't match the
661 // expression pattern do not fire this diagnostic.
662 check_diagnostics(
663 r#"
664enum Either { A, B }
665enum Either2 { C, D }
666
667fn main() {
668 match Either::A {
669 Either2::C => (),
670 // ^^^^^^^^^^ Internal: match check bailed out
671 Either2::D => (),
672 }
673 match (true, false) {
674 (true, false, true) => (),
675 // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out
676 (true) => (),
677 }
678 match (true, false) { (true,) => {} }
679 // ^^^^^^^ Internal: match check bailed out
680 match (0) { () => () }
681 // ^^ Internal: match check bailed out
682 match Unresolved::Bar { Unresolved::Baz => () }
683}
684 "#,
685 );
686 }
687
688 #[test]
689 fn mismatched_types_in_or_patterns() {
690 check_diagnostics(
691 r#"
692fn main() {
693 match false { true | () => {} }
694 // ^^^^^^^^^ Internal: match check bailed out
695 match (false,) { (true | (),) => {} }
696 // ^^^^^^^^^^^^ Internal: match check bailed out
697}
698"#,
699 );
700 }
701
702 #[test]
703 fn malformed_match_arm_tuple_enum_missing_pattern() {
704 // We are testing to be sure we don't panic here when the match
705 // arm `Either::B` is missing its pattern.
706 check_diagnostics(
707 r#"
708enum Either { A, B(u32) }
709
710fn main() {
711 match Either::A {
712 Either::A => (),
713 Either::B() => (),
714 }
715}
716"#,
717 );
718 }
719
720 #[test]
721 fn malformed_match_arm_extra_fields() {
722 check_diagnostics(
723 r#"
724enum A { B(isize, isize), C }
725fn main() {
726 match A::B(1, 2) {
727 A::B(_, _, _) => (),
728 // ^^^^^^^^^^^^^ Internal: match check bailed out
729 }
730 match A::B(1, 2) {
731 A::C(_) => (),
732 // ^^^^^^^ Internal: match check bailed out
733 }
734}
735"#,
736 );
737 }
738
739 #[test]
740 fn expr_diverges() {
741 check_diagnostics(
742 r#"
743enum Either { A, B }
744
745fn main() {
746 match loop {} {
747 Either::A => (),
748 // ^^^^^^^^^ Internal: match check bailed out
749 Either::B => (),
750 }
751 match loop {} {
752 Either::A => (),
753 // ^^^^^^^^^ Internal: match check bailed out
754 }
755 match loop { break Foo::A } {
756 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
757 Either::A => (),
758 }
759 match loop { break Foo::A } {
760 Either::A => (),
761 Either::B => (),
762 }
763}
764"#,
765 );
766 }
767
768 #[test]
769 fn expr_partially_diverges() {
770 check_diagnostics(
771 r#"
772enum Either<T> { A(T), B }
773
774fn foo() -> Either<!> { Either::B }
775fn main() -> u32 {
776 match foo() {
777 Either::A(val) => val,
778 Either::B => 0,
779 }
780}
781"#,
782 );
783 }
784
785 #[test]
786 fn enum_record() {
787 check_diagnostics(
788 r#"
789enum Either { A { foo: bool }, B }
790
791fn main() {
792 let a = Either::A { foo: true };
793 match a { }
794 //^ Missing match arm
795 match a { Either::A { foo: true } => () }
796 //^ Missing match arm
797 match a {
798 Either::A { } => (),
799 //^^^^^^^^^ Missing structure fields:
800 // | - foo
801 Either::B => (),
802 }
803 match a {
804 //^ Missing match arm
805 Either::A { } => (),
806 } //^^^^^^^^^ Missing structure fields:
807 // | - foo
808
809 match a {
810 Either::A { foo: true } => (),
811 Either::A { foo: false } => (),
812 Either::B => (),
813 }
814 match a {
815 Either::A { foo: _ } => (),
816 Either::B => (),
817 }
818}
819"#,
820 );
821 }
822
823 #[test]
824 fn enum_record_fields_out_of_order() {
825 check_diagnostics(
826 r#"
827enum Either {
828 A { foo: bool, bar: () },
829 B,
830}
831
832fn main() {
833 let a = Either::A { foo: true, bar: () };
834 match a {
835 //^ Missing match arm
836 Either::A { bar: (), foo: false } => (),
837 Either::A { foo: true, bar: () } => (),
838 }
839
840 match a {
841 Either::A { bar: (), foo: false } => (),
842 Either::A { foo: true, bar: () } => (),
843 Either::B => (),
844 }
845}
846"#,
847 );
848 }
849
850 #[test]
851 fn enum_record_ellipsis() {
852 check_diagnostics(
853 r#"
854enum Either {
855 A { foo: bool, bar: bool },
856 B,
857}
858
859fn main() {
860 let a = Either::B;
861 match a {
862 //^ Missing match arm
863 Either::A { foo: true, .. } => (),
864 Either::B => (),
865 }
866 match a {
867 //^ Missing match arm
868 Either::A { .. } => (),
869 }
870
871 match a {
872 Either::A { foo: true, .. } => (),
873 Either::A { foo: false, .. } => (),
874 Either::B => (),
875 }
876
877 match a {
878 Either::A { .. } => (),
879 Either::B => (),
880 }
881}
882"#,
883 );
884 }
885
886 #[test]
887 fn enum_tuple_partial_ellipsis() {
888 check_diagnostics(
889 r#"
890enum Either {
891 A(bool, bool, bool, bool),
892 B,
893}
894
895fn main() {
896 match Either::B {
897 //^^^^^^^^^ Missing match arm
898 Either::A(true, .., true) => (),
899 Either::A(true, .., false) => (),
900 Either::A(false, .., false) => (),
901 Either::B => (),
902 }
903 match Either::B {
904 //^^^^^^^^^ Missing match arm
905 Either::A(true, .., true) => (),
906 Either::A(true, .., false) => (),
907 Either::A(.., true) => (),
908 Either::B => (),
909 }
910
911 match Either::B {
912 Either::A(true, .., true) => (),
913 Either::A(true, .., false) => (),
914 Either::A(false, .., true) => (),
915 Either::A(false, .., false) => (),
916 Either::B => (),
917 }
918 match Either::B {
919 Either::A(true, .., true) => (),
920 Either::A(true, .., false) => (),
921 Either::A(.., true) => (),
922 Either::A(.., false) => (),
923 Either::B => (),
924 }
925}
926"#,
927 );
928 }
929
930 #[test]
931 fn never() {
932 check_diagnostics(
933 r#"
934enum Never {}
935
936fn enum_(never: Never) {
937 match never {}
938}
939fn enum_ref(never: &Never) {
940 match never {}
941 //^^^^^ Missing match arm
942}
943fn bang(never: !) {
944 match never {}
945}
946"#,
947 );
948 }
949
950 #[test]
951 fn unknown_type() {
952 check_diagnostics(
953 r#"
954enum Option<T> { Some(T), None }
955
956fn main() {
957 // `Never` is deliberately not defined so that it's an uninferred type.
958 match Option::<Never>::None {
959 None => (),
960 Some(never) => match never {},
961 // ^^^^^^^^^^^ Internal: match check bailed out
962 }
963 match Option::<Never>::None {
964 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
965 Option::Some(_never) => {},
966 }
967}
968"#,
969 );
970 }
971
972 #[test]
973 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
974 check_diagnostics(
975 r#"
976fn main() {
977 match (false, true, false) {
978 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
979 (false, ..) => (),
980 }
981}"#,
982 );
983 }
984
985 #[test]
986 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
987 check_diagnostics(
988 r#"
989fn main() {
990 match (false, true, false) {
991 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
992 (.., false) => (),
993 }
994}"#,
995 );
996 }
997
998 #[test]
999 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
1000 check_diagnostics(
1001 r#"
1002fn main() {
1003 match (false, true, false) {
1004 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1005 (true, .., false) => (),
1006 }
1007}"#,
1008 );
1009 }
1010
1011 #[test]
1012 fn record_struct() {
1013 check_diagnostics(
1014 r#"struct Foo { a: bool }
1015fn main(f: Foo) {
1016 match f {}
1017 //^ Missing match arm
1018 match f { Foo { a: true } => () }
1019 //^ Missing match arm
1020 match &f { Foo { a: true } => () }
1021 //^^ Missing match arm
1022 match f { Foo { a: _ } => () }
1023 match f {
1024 Foo { a: true } => (),
1025 Foo { a: false } => (),
1026 }
1027 match &f {
1028 Foo { a: true } => (),
1029 Foo { a: false } => (),
1030 }
1031}
1032"#,
1033 );
1034 }
1035
1036 #[test]
1037 fn tuple_struct() {
1038 check_diagnostics(
1039 r#"struct Foo(bool);
1040fn main(f: Foo) {
1041 match f {}
1042 //^ Missing match arm
1043 match f { Foo(true) => () }
1044 //^ Missing match arm
1045 match f {
1046 Foo(true) => (),
1047 Foo(false) => (),
1048 }
1049}
1050"#,
1051 );
1052 }
1053
1054 #[test]
1055 fn unit_struct() {
1056 check_diagnostics(
1057 r#"struct Foo;
1058fn main(f: Foo) {
1059 match f {}
1060 //^ Missing match arm
1061 match f { Foo => () }
1062}
1063"#,
1064 );
1065 }
1066
1067 #[test]
1068 fn record_struct_ellipsis() {
1069 check_diagnostics(
1070 r#"struct Foo { foo: bool, bar: bool }
1071fn main(f: Foo) {
1072 match f { Foo { foo: true, .. } => () }
1073 //^ Missing match arm
1074 match f {
1075 //^ Missing match arm
1076 Foo { foo: true, .. } => (),
1077 Foo { bar: false, .. } => ()
1078 }
1079 match f { Foo { .. } => () }
1080 match f {
1081 Foo { foo: true, .. } => (),
1082 Foo { foo: false, .. } => ()
1083 }
1084}
1085"#,
1086 );
1087 }
1088
1089 #[test]
1090 fn internal_or() {
1091 check_diagnostics(
1092 r#"
1093fn main() {
1094 enum Either { A(bool), B }
1095 match Either::B {
1096 //^^^^^^^^^ Missing match arm
1097 Either::A(true | false) => (),
1098 }
1099}
1100"#,
1101 );
1102 }
1103
1104 #[test]
1105 fn no_panic_at_unimplemented_subpattern_type() {
1106 check_diagnostics(
1107 r#"
1108struct S { a: char}
1109fn main(v: S) {
1110 match v { S{ a } => {} }
1111 match v { S{ a: _x } => {} }
1112 match v { S{ a: 'a' } => {} }
1113 //^^^^^^^^^^^ Internal: match check bailed out
1114 match v { S{..} => {} }
1115 match v { _ => {} }
1116 match v { }
1117 //^ Missing match arm
1118}
1119"#,
1120 );
1121 }
1122
1123 #[test]
1124 fn binding() {
1125 check_diagnostics(
1126 r#"
1127fn main() {
1128 match true {
1129 _x @ true => {}
1130 false => {}
1131 }
1132 match true { _x @ true => {} }
1133 //^^^^ Missing match arm
1134}
1135"#,
1136 );
1137 }
1138
1139 #[test]
1140 fn binding_ref_has_correct_type() {
1141 // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
1142 // If that's not true match checking will panic with "incompatible constructors"
1143 // FIXME: make facilities to test this directly like `tests::check_infer(..)`
1144 check_diagnostics(
1145 r#"
1146enum Foo { A }
1147fn main() {
1148 // FIXME: this should not bail out but current behavior is such as the old algorithm.
1149 // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
1150 match Foo::A {
1151 ref _x => {}
1152 // ^^^^^^ Internal: match check bailed out
1153 Foo::A => {}
1154 }
1155 match (true,) {
1156 (ref _x,) => {}
1157 (true,) => {}
1158 }
1159}
1160"#,
1161 );
1162 }
1163
1164 #[test]
1165 fn enum_non_exhaustive() {
1166 check_diagnostics(
1167 r#"
1168//- /lib.rs crate:lib
1169#[non_exhaustive]
1170pub enum E { A, B }
1171fn _local() {
1172 match E::A { _ => {} }
1173 match E::A {
1174 E::A => {}
1175 E::B => {}
1176 }
1177 match E::A {
1178 E::A | E::B => {}
1179 }
1180}
1181
1182//- /main.rs crate:main deps:lib
1183use lib::E;
1184fn main() {
1185 match E::A { _ => {} }
1186 match E::A {
1187 //^^^^ Missing match arm
1188 E::A => {}
1189 E::B => {}
1190 }
1191 match E::A {
1192 //^^^^ Missing match arm
1193 E::A | E::B => {}
1194 }
1195}
1196"#,
1197 );
1198 }
1199
1200 #[test]
1201 fn match_guard() {
1202 check_diagnostics(
1203 r#"
1204fn main() {
1205 match true {
1206 true if false => {}
1207 true => {}
1208 false => {}
1209 }
1210 match true {
1211 //^^^^ Missing match arm
1212 true if false => {}
1213 false => {}
1214}
1215"#,
1216 );
1217 }
1218
1219 #[test]
1220 fn pattern_type_is_of_substitution() {
1221 cov_mark::check!(match_check_wildcard_expanded_to_substitutions);
1222 check_diagnostics(
1223 r#"
1224struct Foo<T>(T);
1225struct Bar;
1226fn main() {
1227 match Foo(Bar) {
1228 _ | Foo(Bar) => {}
1229 }
1230}
1231"#,
1232 );
1233 }
1234
1235 #[test]
1236 fn record_struct_no_such_field() {
1237 check_diagnostics(
1238 r#"
1239struct Foo { }
1240fn main(f: Foo) {
1241 match f { Foo { bar } => () }
1242 // ^^^^^^^^^^^ Internal: match check bailed out
1243}
1244"#,
1245 );
1246 }
1247
1248 #[test]
1249 fn match_ergonomics_issue_9095() {
1250 check_diagnostics(
1251 r#"
1252enum Foo<T> { A(T) }
1253fn main() {
1254 match &Foo::A(true) {
1255 _ => {}
1256 Foo::A(_) => {}
1257 }
1258}
1259"#,
1260 );
1261 }
1262
1263 mod false_negatives {
1264 //! The implementation of match checking here is a work in progress. As we roll this out, we
1265 //! prefer false negatives to false positives (ideally there would be no false positives). This
1266 //! test module should document known false negatives. Eventually we will have a complete
1267 //! implementation of match checking and this module will be empty.
1268 //!
1269 //! The reasons for documenting known false negatives:
1270 //!
1271 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
1272 //! 2. It ensures the code doesn't panic when handling these cases.
1273 use super::*;
1274
1275 #[test]
1276 fn integers() {
1277 // We don't currently check integer exhaustiveness.
1278 check_diagnostics(
1279 r#"
1280fn main() {
1281 match 5 {
1282 10 => (),
1283 // ^^ Internal: match check bailed out
1284 11..20 => (),
1285 }
1286}
1287"#,
1288 );
1289 }
1290
1291 #[test]
1292 fn reference_patterns_at_top_level() {
1293 check_diagnostics(
1294 r#"
1295fn main() {
1296 match &false {
1297 &true => {}
1298 // ^^^^^ Internal: match check bailed out
1299 }
1300}
1301 "#,
1302 );
1303 }
1304
1305 #[test]
1306 fn reference_patterns_in_fields() {
1307 check_diagnostics(
1308 r#"
1309fn main() {
1310 match (&false,) {
1311 (true,) => {}
1312 // ^^^^^^^ Internal: match check bailed out
1313 }
1314 match (&false,) {
1315 (&true,) => {}
1316 // ^^^^^^^^ Internal: match check bailed out
1317 }
1318}
1319 "#,
1320 );
1321 }
1322 }
1323}
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
index 1f4219b42..471cd4921 100644
--- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -528,7 +528,7 @@ impl SplitWildcard {
528 smallvec![NonExhaustive] 528 smallvec![NonExhaustive]
529 } 529 }
530 TyKind::Never => SmallVec::new(), 530 TyKind::Never => SmallVec::new(),
531 _ if cx.is_uninhabited(&pcx.ty) => SmallVec::new(), 531 _ if cx.is_uninhabited(pcx.ty) => SmallVec::new(),
532 TyKind::Adt(..) | TyKind::Tuple(..) | TyKind::Ref(..) => smallvec![Single], 532 TyKind::Adt(..) | TyKind::Tuple(..) | TyKind::Ref(..) => smallvec![Single],
533 // This type is one for which we cannot list constructors, like `str` or `f64`. 533 // This type is one for which we cannot list constructors, like `str` or `f64`.
534 _ => smallvec![NonExhaustive], 534 _ => smallvec![NonExhaustive],
diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
index bd76a606c..8451f9df5 100644
--- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
@@ -1,5 +1,5 @@
1//! Based on rust-lang/rust 1.52.0-nightly (25c15cdbe 2021-04-22) 1//! Based on rust-lang/rust 1.52.0-nightly (25c15cdbe 2021-04-22)
2//! https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs 2//! <https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs>
3//! 3//!
4//! ----- 4//! -----
5//! 5//!
@@ -645,7 +645,7 @@ impl SubPatSet {
645 (Seq { subpats: s_set }, Seq { subpats: mut o_set }) => { 645 (Seq { subpats: s_set }, Seq { subpats: mut o_set }) => {
646 s_set.retain(|i, s_sub_set| { 646 s_set.retain(|i, s_sub_set| {
647 // Missing entries count as full. 647 // Missing entries count as full.
648 let o_sub_set = o_set.remove(&i).unwrap_or(Full); 648 let o_sub_set = o_set.remove(i).unwrap_or(Full);
649 s_sub_set.union(o_sub_set); 649 s_sub_set.union(o_sub_set);
650 // We drop full entries. 650 // We drop full entries.
651 !s_sub_set.is_full() 651 !s_sub_set.is_full()
@@ -656,7 +656,7 @@ impl SubPatSet {
656 (Alt { subpats: s_set, .. }, Alt { subpats: mut o_set, .. }) => { 656 (Alt { subpats: s_set, .. }, Alt { subpats: mut o_set, .. }) => {
657 s_set.retain(|i, s_sub_set| { 657 s_set.retain(|i, s_sub_set| {
658 // Missing entries count as empty. 658 // Missing entries count as empty.
659 let o_sub_set = o_set.remove(&i).unwrap_or(Empty); 659 let o_sub_set = o_set.remove(i).unwrap_or(Empty);
660 s_sub_set.union(o_sub_set); 660 s_sub_set.union(o_sub_set);
661 // We drop empty entries. 661 // We drop empty entries.
662 !s_sub_set.is_empty() 662 !s_sub_set.is_empty()
@@ -898,7 +898,7 @@ impl Usefulness {
898 } else { 898 } else {
899 witnesses 899 witnesses
900 .into_iter() 900 .into_iter()
901 .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns)) 901 .map(|witness| witness.apply_constructor(pcx, ctor, ctor_wild_subpatterns))
902 .collect() 902 .collect()
903 }; 903 };
904 WithWitnesses(new_witnesses) 904 WithWitnesses(new_witnesses)
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index c3c483425..777f347b8 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -1,8 +1,6 @@
1//! Provides validations for unsafe code. Currently checks if unsafe functions are missing 1//! Provides validations for unsafe code. Currently checks if unsafe functions are missing
2//! unsafe blocks. 2//! unsafe blocks.
3 3
4use std::sync::Arc;
5
6use hir_def::{ 4use hir_def::{
7 body::Body, 5 body::Body,
8 expr::{Expr, ExprId, UnaryOp}, 6 expr::{Expr, ExprId, UnaryOp},
@@ -10,60 +8,32 @@ use hir_def::{
10 DefWithBodyId, 8 DefWithBodyId,
11}; 9};
12 10
13use crate::{ 11use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind};
14 db::HirDatabase, diagnostics::MissingUnsafe, diagnostics_sink::DiagnosticSink, InferenceResult,
15 Interner, TyExt, TyKind,
16};
17 12
18pub(super) struct UnsafeValidator<'a, 'b: 'a> { 13pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
19 owner: DefWithBodyId, 14 let infer = db.infer(def);
20 infer: Arc<InferenceResult>,
21 sink: &'a mut DiagnosticSink<'b>,
22}
23 15
24impl<'a, 'b> UnsafeValidator<'a, 'b> { 16 let is_unsafe = match def {
25 pub(super) fn new( 17 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
26 owner: DefWithBodyId, 18 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
27 infer: Arc<InferenceResult>, 19 };
28 sink: &'a mut DiagnosticSink<'b>, 20 if is_unsafe {
29 ) -> UnsafeValidator<'a, 'b> { 21 return Vec::new();
30 UnsafeValidator { owner, infer, sink }
31 } 22 }
32 23
33 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { 24 unsafe_expressions(db, &infer, def)
34 let def = self.owner; 25 .into_iter()
35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); 26 .filter(|it| !it.inside_unsafe_block)
36 let is_unsafe = match self.owner { 27 .map(|it| it.expr)
37 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), 28 .collect()
38 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
39 };
40 if is_unsafe
41 || unsafe_expressions
42 .iter()
43 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block)
44 .count()
45 == 0
46 {
47 return;
48 }
49
50 let (_, body_source) = db.body_with_source_map(def);
51 for unsafe_expr in unsafe_expressions {
52 if !unsafe_expr.inside_unsafe_block {
53 if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) {
54 self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value })
55 }
56 }
57 }
58 }
59} 29}
60 30
61pub(crate) struct UnsafeExpr { 31struct UnsafeExpr {
62 pub(crate) expr: ExprId, 32 pub(crate) expr: ExprId,
63 pub(crate) inside_unsafe_block: bool, 33 pub(crate) inside_unsafe_block: bool,
64} 34}
65 35
66pub(crate) fn unsafe_expressions( 36fn unsafe_expressions(
67 db: &dyn HirDatabase, 37 db: &dyn HirDatabase,
68 infer: &InferenceResult, 38 infer: &InferenceResult,
69 def: DefWithBodyId, 39 def: DefWithBodyId,
@@ -126,92 +96,3 @@ fn walk_unsafe(
126 walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); 96 walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
127 }); 97 });
128} 98}
129
130#[cfg(test)]
131mod tests {
132 use crate::diagnostics::tests::check_diagnostics;
133
134 #[test]
135 fn missing_unsafe_diagnostic_with_raw_ptr() {
136 check_diagnostics(
137 r#"
138fn main() {
139 let x = &5 as *const usize;
140 unsafe { let y = *x; }
141 let z = *x;
142} //^^ This operation is unsafe and requires an unsafe function or block
143"#,
144 )
145 }
146
147 #[test]
148 fn missing_unsafe_diagnostic_with_unsafe_call() {
149 check_diagnostics(
150 r#"
151struct HasUnsafe;
152
153impl HasUnsafe {
154 unsafe fn unsafe_fn(&self) {
155 let x = &5 as *const usize;
156 let y = *x;
157 }
158}
159
160unsafe fn unsafe_fn() {
161 let x = &5 as *const usize;
162 let y = *x;
163}
164
165fn main() {
166 unsafe_fn();
167 //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
168 HasUnsafe.unsafe_fn();
169 //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
170 unsafe {
171 unsafe_fn();
172 HasUnsafe.unsafe_fn();
173 }
174}
175"#,
176 );
177 }
178
179 #[test]
180 fn missing_unsafe_diagnostic_with_static_mut() {
181 check_diagnostics(
182 r#"
183struct Ty {
184 a: u8,
185}
186
187static mut STATIC_MUT: Ty = Ty { a: 0 };
188
189fn main() {
190 let x = STATIC_MUT.a;
191 //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
192 unsafe {
193 let x = STATIC_MUT.a;
194 }
195}
196"#,
197 );
198 }
199
200 #[test]
201 fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
202 check_diagnostics(
203 r#"
204extern "rust-intrinsic" {
205 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
206 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
207}
208
209fn main() {
210 let _ = bitreverse(12);
211 let _ = floorf32(12.0);
212 //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
213}
214"#,
215 );
216 }
217}
diff --git a/crates/hir_ty/src/diagnostics_sink.rs b/crates/hir_ty/src/diagnostics_sink.rs
deleted file mode 100644
index 084fa8b06..000000000
--- a/crates/hir_ty/src/diagnostics_sink.rs
+++ /dev/null
@@ -1,109 +0,0 @@
1//! Semantic errors and warnings.
2//!
3//! The `Diagnostic` trait defines a trait object which can represent any
4//! diagnostic.
5//!
6//! `DiagnosticSink` struct is used as an emitter for diagnostic. When creating
7//! a `DiagnosticSink`, you supply a callback which can react to a `dyn
8//! Diagnostic` or to any concrete diagnostic (downcasting is used internally).
9//!
10//! Because diagnostics store file offsets, it's a bad idea to store them
11//! directly in salsa. For this reason, every hir subsytem defines it's own
12//! strongly-typed closed set of diagnostics which use hir ids internally, are
13//! stored in salsa and do *not* implement the `Diagnostic` trait. Instead, a
14//! subsystem provides a separate, non-query-based API which can walk all stored
15//! values and transform them into instances of `Diagnostic`.
16
17use std::{any::Any, fmt};
18
19use hir_expand::InFile;
20use syntax::SyntaxNodePtr;
21
22#[derive(Copy, Clone, Debug, PartialEq)]
23pub struct DiagnosticCode(pub &'static str);
24
25impl DiagnosticCode {
26 pub fn as_str(&self) -> &str {
27 self.0
28 }
29}
30
31pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
32 fn code(&self) -> DiagnosticCode;
33 fn message(&self) -> String;
34 /// Source element that triggered the diagnostics.
35 ///
36 /// Note that this should reflect "semantics", rather than specific span we
37 /// want to highlight. When rendering the diagnostics into an error message,
38 /// the IDE will fetch the `SyntaxNode` and will narrow the span
39 /// appropriately.
40 fn display_source(&self) -> InFile<SyntaxNodePtr>;
41 fn as_any(&self) -> &(dyn Any + Send + 'static);
42 fn is_experimental(&self) -> bool {
43 false
44 }
45}
46
47pub struct DiagnosticSink<'a> {
48 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
49 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
50 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
51}
52
53impl<'a> DiagnosticSink<'a> {
54 pub fn push(&mut self, d: impl Diagnostic) {
55 let d: &dyn Diagnostic = &d;
56 self._push(d);
57 }
58
59 fn _push(&mut self, d: &dyn Diagnostic) {
60 for filter in &mut self.filters {
61 if !filter(d) {
62 return;
63 }
64 }
65 for cb in &mut self.callbacks {
66 match cb(d) {
67 Ok(()) => return,
68 Err(()) => (),
69 }
70 }
71 (self.default_callback)(d)
72 }
73}
74
75pub struct DiagnosticSinkBuilder<'a> {
76 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
77 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
78}
79
80impl<'a> DiagnosticSinkBuilder<'a> {
81 pub fn new() -> Self {
82 Self { callbacks: Vec::new(), filters: Vec::new() }
83 }
84
85 pub fn filter<F: FnMut(&dyn Diagnostic) -> bool + 'a>(mut self, cb: F) -> Self {
86 self.filters.push(Box::new(cb));
87 self
88 }
89
90 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self {
91 let cb = move |diag: &dyn Diagnostic| match diag.as_any().downcast_ref::<D>() {
92 Some(d) => {
93 cb(d);
94 Ok(())
95 }
96 None => Err(()),
97 };
98 self.callbacks.push(Box::new(cb));
99 self
100 }
101
102 pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> {
103 DiagnosticSink {
104 callbacks: self.callbacks,
105 filters: self.filters,
106 default_callback: Box::new(default_callback),
107 }
108 }
109}
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 0e9f777da..63f37c0ab 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -35,11 +35,9 @@ use stdx::impl_from;
35use syntax::SmolStr; 35use syntax::SmolStr;
36 36
37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; 37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
38use crate::diagnostics_sink::DiagnosticSink;
39use crate::{ 38use crate::{
40 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, 39 db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy,
41 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution, 40 Goal, Interner, Substitution, TyBuilder, TyExt, TyKind,
42 TyBuilder, TyExt, TyKind,
43}; 41};
44 42
45// This lint has a false positive here. See the link below for details. 43// This lint has a false positive here. See the link below for details.
@@ -80,7 +78,7 @@ enum ExprOrPatId {
80impl_from!(ExprId, PatId for ExprOrPatId); 78impl_from!(ExprId, PatId for ExprOrPatId);
81 79
82/// Binding modes inferred for patterns. 80/// Binding modes inferred for patterns.
83/// https://doc.rust-lang.org/reference/patterns.html#binding-modes 81/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
84#[derive(Copy, Clone, Debug, Eq, PartialEq)] 82#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85enum BindingMode { 83enum BindingMode {
86 Move, 84 Move,
@@ -111,6 +109,12 @@ pub(crate) struct InferOk {
111pub(crate) struct TypeError; 109pub(crate) struct TypeError;
112pub(crate) type InferResult = Result<InferOk, TypeError>; 110pub(crate) type InferResult = Result<InferOk, TypeError>;
113 111
112#[derive(Debug, PartialEq, Eq, Clone)]
113pub enum InferenceDiagnostic {
114 NoSuchField { expr: ExprId },
115 BreakOutsideOfLoop { expr: ExprId },
116}
117
114/// A mismatch between an expected and an inferred type. 118/// A mismatch between an expected and an inferred type.
115#[derive(Clone, PartialEq, Eq, Debug, Hash)] 119#[derive(Clone, PartialEq, Eq, Debug, Hash)]
116pub struct TypeMismatch { 120pub struct TypeMismatch {
@@ -140,7 +144,7 @@ pub struct InferenceResult {
140 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, 144 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
141 /// For each associated item record what it resolves to 145 /// For each associated item record what it resolves to
142 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, 146 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
143 diagnostics: Vec<InferenceDiagnostic>, 147 pub diagnostics: Vec<InferenceDiagnostic>,
144 pub type_of_expr: ArenaMap<ExprId, Ty>, 148 pub type_of_expr: ArenaMap<ExprId, Ty>,
145 /// For each pattern record the type it resolves to. 149 /// For each pattern record the type it resolves to.
146 /// 150 ///
@@ -191,14 +195,6 @@ impl InferenceResult {
191 _ => None, 195 _ => None,
192 }) 196 })
193 } 197 }
194 pub fn add_diagnostics(
195 &self,
196 db: &dyn HirDatabase,
197 owner: DefWithBodyId,
198 sink: &mut DiagnosticSink,
199 ) {
200 self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
201 }
202} 198}
203 199
204impl Index<ExprId> for InferenceResult { 200impl Index<ExprId> for InferenceResult {
@@ -765,6 +761,38 @@ impl Expectation {
765 Expectation::RValueLikeUnsized(_) | Expectation::None => None, 761 Expectation::RValueLikeUnsized(_) | Expectation::None => None,
766 } 762 }
767 } 763 }
764
765 /// Comment copied from rustc:
766 /// Disregard "castable to" expectations because they
767 /// can lead us astray. Consider for example `if cond
768 /// {22} else {c} as u8` -- if we propagate the
769 /// "castable to u8" constraint to 22, it will pick the
770 /// type 22u8, which is overly constrained (c might not
771 /// be a u8). In effect, the problem is that the
772 /// "castable to" expectation is not the tightest thing
773 /// we can say, so we want to drop it in this case.
774 /// The tightest thing we can say is "must unify with
775 /// else branch". Note that in the case of a "has type"
776 /// constraint, this limitation does not hold.
777 ///
778 /// If the expected type is just a type variable, then don't use
779 /// an expected type. Otherwise, we might write parts of the type
780 /// when checking the 'then' block which are incompatible with the
781 /// 'else' branch.
782 fn adjust_for_branches(&self, table: &mut unify::InferenceTable) -> Expectation {
783 match self {
784 Expectation::HasType(ety) => {
785 let ety = table.resolve_ty_shallow(ety);
786 if !ety.is_ty_var() {
787 Expectation::HasType(ety)
788 } else {
789 Expectation::None
790 }
791 }
792 Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()),
793 _ => Expectation::None,
794 }
795 }
768} 796}
769 797
770#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 798#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -804,43 +832,3 @@ impl std::ops::BitOrAssign for Diverges {
804 *self = *self | other; 832 *self = *self | other;
805 } 833 }
806} 834}
807
808mod diagnostics {
809 use hir_def::{expr::ExprId, DefWithBodyId};
810
811 use crate::{
812 db::HirDatabase,
813 diagnostics::{BreakOutsideOfLoop, NoSuchField},
814 diagnostics_sink::DiagnosticSink,
815 };
816
817 #[derive(Debug, PartialEq, Eq, Clone)]
818 pub(super) enum InferenceDiagnostic {
819 NoSuchField { expr: ExprId },
820 BreakOutsideOfLoop { expr: ExprId },
821 }
822
823 impl InferenceDiagnostic {
824 pub(super) fn add_to(
825 &self,
826 db: &dyn HirDatabase,
827 owner: DefWithBodyId,
828 sink: &mut DiagnosticSink,
829 ) {
830 match self {
831 InferenceDiagnostic::NoSuchField { expr } => {
832 let (_, source_map) = db.body_with_source_map(owner);
833 let field = source_map.field_syntax(*expr);
834 sink.push(NoSuchField { file: field.file_id, field: field.value })
835 }
836 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
837 let (_, source_map) = db.body_with_source_map(owner);
838 let ptr = source_map
839 .expr_syntax(*expr)
840 .expect("break outside of loop in synthetic syntax");
841 sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
842 }
843 }
844 }
845 }
846}
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 03b97e7db..4b7f31521 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -2,8 +2,8 @@
2//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions 2//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions
3//! like going from `&Vec<T>` to `&[T]`. 3//! like going from `&Vec<T>` to `&[T]`.
4//! 4//!
5//! See https://doc.rust-lang.org/nomicon/coercions.html and 5//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
6//! librustc_typeck/check/coercion.rs. 6//! `librustc_typeck/check/coercion.rs`.
7 7
8use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 8use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
9use hir_def::{expr::ExprId, lang_item::LangItemTarget}; 9use hir_def::{expr::ExprId, lang_item::LangItemTarget};
@@ -109,7 +109,7 @@ impl<'a> InferenceContext<'a> {
109 } 109 }
110 110
111 // Consider coercing the subtype to a DST 111 // Consider coercing the subtype to a DST
112 if let Ok(ret) = self.try_coerce_unsized(&from_ty, &to_ty) { 112 if let Ok(ret) = self.try_coerce_unsized(&from_ty, to_ty) {
113 return Ok(ret); 113 return Ok(ret);
114 } 114 }
115 115
@@ -331,7 +331,7 @@ impl<'a> InferenceContext<'a> {
331 331
332 /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>` 332 /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>`
333 /// 333 ///
334 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html 334 /// See: <https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html>
335 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> InferResult { 335 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> InferResult {
336 // These 'if' statements require some explanation. 336 // These 'if' statements require some explanation.
337 // The `CoerceUnsized` trait is special - it is only 337 // The `CoerceUnsized` trait is special - it is only
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index f73bf43b2..5ea2e5934 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -54,7 +54,7 @@ impl<'a> InferenceContext<'a> {
54 /// Infer type of expression with possibly implicit coerce to the expected type. 54 /// Infer type of expression with possibly implicit coerce to the expected type.
55 /// Return the type after possible coercion. 55 /// Return the type after possible coercion.
56 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { 56 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
57 let ty = self.infer_expr_inner(expr, &expected); 57 let ty = self.infer_expr_inner(expr, expected);
58 let ty = if let Some(target) = expected.only_has_type(&mut self.table) { 58 let ty = if let Some(target) = expected.only_has_type(&mut self.table) {
59 if !self.coerce(&ty, &target) { 59 if !self.coerce(&ty, &target) {
60 self.result 60 self.result
@@ -135,11 +135,11 @@ impl<'a> InferenceContext<'a> {
135 let mut both_arms_diverge = Diverges::Always; 135 let mut both_arms_diverge = Diverges::Always;
136 136
137 let mut result_ty = self.table.new_type_var(); 137 let mut result_ty = self.table.new_type_var();
138 let then_ty = self.infer_expr_inner(*then_branch, &expected); 138 let then_ty = self.infer_expr_inner(*then_branch, expected);
139 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); 139 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
140 result_ty = self.coerce_merge_branch(Some(*then_branch), &result_ty, &then_ty); 140 result_ty = self.coerce_merge_branch(Some(*then_branch), &result_ty, &then_ty);
141 let else_ty = match else_branch { 141 let else_ty = match else_branch {
142 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), 142 Some(else_branch) => self.infer_expr_inner(*else_branch, expected),
143 None => TyBuilder::unit(), 143 None => TyBuilder::unit(),
144 }; 144 };
145 both_arms_diverge &= self.diverges; 145 both_arms_diverge &= self.diverges;
@@ -327,20 +327,19 @@ impl<'a> InferenceContext<'a> {
327 self.normalize_associated_types_in(ret_ty) 327 self.normalize_associated_types_in(ret_ty)
328 } 328 }
329 Expr::MethodCall { receiver, args, method_name, generic_args } => self 329 Expr::MethodCall { receiver, args, method_name, generic_args } => self
330 .infer_method_call( 330 .infer_method_call(tgt_expr, *receiver, args, method_name, generic_args.as_deref()),
331 tgt_expr,
332 *receiver,
333 &args,
334 &method_name,
335 generic_args.as_deref(),
336 ),
337 Expr::Match { expr, arms } => { 331 Expr::Match { expr, arms } => {
338 let input_ty = self.infer_expr(*expr, &Expectation::none()); 332 let input_ty = self.infer_expr(*expr, &Expectation::none());
339 333
334 let expected = expected.adjust_for_branches(&mut self.table);
335
340 let mut result_ty = if arms.is_empty() { 336 let mut result_ty = if arms.is_empty() {
341 TyKind::Never.intern(&Interner) 337 TyKind::Never.intern(&Interner)
342 } else { 338 } else {
343 self.table.new_type_var() 339 match &expected {
340 Expectation::HasType(ty) => ty.clone(),
341 _ => self.table.new_type_var(),
342 }
344 }; 343 };
345 344
346 let matchee_diverges = self.diverges; 345 let matchee_diverges = self.diverges;
@@ -988,7 +987,7 @@ impl<'a> InferenceContext<'a> {
988 } 987 }
989 988
990 fn register_obligations_for_call(&mut self, callable_ty: &Ty) { 989 fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
991 let callable_ty = self.resolve_ty_shallow(&callable_ty); 990 let callable_ty = self.resolve_ty_shallow(callable_ty);
992 if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(&Interner) { 991 if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(&Interner) {
993 let def: CallableDefId = from_chalk(self.db, *fn_def); 992 let def: CallableDefId = from_chalk(self.db, *fn_def);
994 let generic_predicates = self.db.generic_predicates(def.into()); 993 let generic_predicates = self.db.generic_predicates(def.into());
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 25dff7e49..035f4ded6 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -192,7 +192,7 @@ impl<'a> InferenceContext<'a> {
192 Pat::Path(path) => { 192 Pat::Path(path) => {
193 // FIXME use correct resolver for the surrounding expression 193 // FIXME use correct resolver for the surrounding expression
194 let resolver = self.resolver.clone(); 194 let resolver = self.resolver.clone();
195 self.infer_path(&resolver, &path, pat.into()).unwrap_or(self.err_ty()) 195 self.infer_path(&resolver, path, pat.into()).unwrap_or(self.err_ty())
196 } 196 }
197 Pat::Bind { mode, name: _, subpat } => { 197 Pat::Bind { mode, name: _, subpat } => {
198 let mode = if mode == &BindingAnnotation::Unannotated { 198 let mode = if mode == &BindingAnnotation::Unannotated {
@@ -275,7 +275,7 @@ impl<'a> InferenceContext<'a> {
275 if !self.unify(&ty, &expected) { 275 if !self.unify(&ty, &expected) {
276 self.result 276 self.result
277 .type_mismatches 277 .type_mismatches
278 .insert(pat.into(), TypeMismatch { expected: expected, actual: ty.clone() }); 278 .insert(pat.into(), TypeMismatch { expected, actual: ty.clone() });
279 } 279 }
280 self.write_pat_ty(pat, ty.clone()); 280 self.write_pat_ty(pat, ty.clone());
281 ty 281 ty
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 14c99eafd..056cdb5d5 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -43,11 +43,11 @@ impl<'a> InferenceContext<'a> {
43 } 43 }
44 let ty = self.make_ty(type_ref); 44 let ty = self.make_ty(type_ref);
45 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); 45 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
46 let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver); 46 let ctx = crate::lower::TyLoweringContext::new(self.db, resolver);
47 let (ty, _) = ctx.lower_ty_relative_path(ty, None, remaining_segments_for_ty); 47 let (ty, _) = ctx.lower_ty_relative_path(ty, None, remaining_segments_for_ty);
48 self.resolve_ty_assoc_item( 48 self.resolve_ty_assoc_item(
49 ty, 49 ty,
50 &path.segments().last().expect("path had at least one segment").name, 50 path.segments().last().expect("path had at least one segment").name,
51 id, 51 id,
52 )? 52 )?
53 } else { 53 } else {
@@ -154,7 +154,7 @@ impl<'a> InferenceContext<'a> {
154 let segment = 154 let segment =
155 remaining_segments.last().expect("there should be at least one segment here"); 155 remaining_segments.last().expect("there should be at least one segment here");
156 156
157 self.resolve_ty_assoc_item(ty, &segment.name, id) 157 self.resolve_ty_assoc_item(ty, segment.name, id)
158 } 158 }
159 } 159 }
160 } 160 }
diff --git a/crates/hir_ty/src/interner.rs b/crates/hir_ty/src/interner.rs
index 29ffdd9b7..5fef878e8 100644
--- a/crates/hir_ty/src/interner.rs
+++ b/crates/hir_ty/src/interner.rs
@@ -331,7 +331,7 @@ impl chalk_ir::interner::Interner for Interner {
331 &self, 331 &self,
332 clauses: &'a Self::InternedProgramClauses, 332 clauses: &'a Self::InternedProgramClauses,
333 ) -> &'a [chalk_ir::ProgramClause<Self>] { 333 ) -> &'a [chalk_ir::ProgramClause<Self>] {
334 &clauses 334 clauses
335 } 335 }
336 336
337 fn intern_quantified_where_clauses<E>( 337 fn intern_quantified_where_clauses<E>(
@@ -373,7 +373,7 @@ impl chalk_ir::interner::Interner for Interner {
373 &self, 373 &self,
374 canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, 374 canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
375 ) -> &'a [chalk_ir::CanonicalVarKind<Self>] { 375 ) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
376 &canonical_var_kinds 376 canonical_var_kinds
377 } 377 }
378 378
379 fn intern_constraints<E>( 379 fn intern_constraints<E>(
@@ -413,7 +413,7 @@ impl chalk_ir::interner::Interner for Interner {
413 &self, 413 &self,
414 variances: &'a Self::InternedVariances, 414 variances: &'a Self::InternedVariances,
415 ) -> &'a [chalk_ir::Variance] { 415 ) -> &'a [chalk_ir::Variance] {
416 &variances 416 variances
417 } 417 }
418} 418}
419 419
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 50e0d6333..128cae830 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -21,7 +21,6 @@ mod utils;
21mod walk; 21mod walk;
22pub mod db; 22pub mod db;
23pub mod diagnostics; 23pub mod diagnostics;
24pub mod diagnostics_sink;
25pub mod display; 24pub mod display;
26pub mod method_resolution; 25pub mod method_resolution;
27pub mod primitive; 26pub mod primitive;
@@ -50,7 +49,7 @@ use crate::{db::HirDatabase, utils::generics};
50pub use autoderef::autoderef; 49pub use autoderef::autoderef;
51pub use builder::TyBuilder; 50pub use builder::TyBuilder;
52pub use chalk_ext::*; 51pub use chalk_ext::*;
53pub use infer::{could_unify, InferenceResult}; 52pub use infer::{could_unify, InferenceDiagnostic, InferenceResult};
54pub use interner::Interner; 53pub use interner::Interner;
55pub use lower::{ 54pub use lower::{
56 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 55 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index c83933c73..817a65c20 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -238,7 +238,7 @@ impl<'a> TyLoweringContext<'a> {
238 // away instead of two. 238 // away instead of two.
239 let actual_opaque_type_data = self 239 let actual_opaque_type_data = self
240 .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { 240 .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
241 ctx.lower_impl_trait(&bounds) 241 ctx.lower_impl_trait(bounds)
242 }); 242 });
243 self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data; 243 self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
244 244
@@ -421,7 +421,7 @@ impl<'a> TyLoweringContext<'a> {
421 let found = self 421 let found = self
422 .db 422 .db
423 .trait_data(trait_ref.hir_trait_id()) 423 .trait_data(trait_ref.hir_trait_id())
424 .associated_type_by_name(&segment.name); 424 .associated_type_by_name(segment.name);
425 match found { 425 match found {
426 Some(associated_ty) => { 426 Some(associated_ty) => {
427 // FIXME handle type parameters on the segment 427 // FIXME handle type parameters on the segment
@@ -505,7 +505,7 @@ impl<'a> TyLoweringContext<'a> {
505 pub(crate) fn lower_path(&self, path: &Path) -> (Ty, Option<TypeNs>) { 505 pub(crate) fn lower_path(&self, path: &Path) -> (Ty, Option<TypeNs>) {
506 // Resolve the path (in type namespace) 506 // Resolve the path (in type namespace)
507 if let Some(type_ref) = path.type_anchor() { 507 if let Some(type_ref) = path.type_anchor() {
508 let (ty, res) = self.lower_ty_ext(&type_ref); 508 let (ty, res) = self.lower_ty_ext(type_ref);
509 return self.lower_ty_relative_path(ty, res, path.segments()); 509 return self.lower_ty_relative_path(ty, res, path.segments());
510 } 510 }
511 let (resolution, remaining_index) = 511 let (resolution, remaining_index) =
@@ -784,7 +784,7 @@ impl<'a> TyLoweringContext<'a> {
784 let trait_ref = match bound { 784 let trait_ref = match bound {
785 TypeBound::Path(path) => { 785 TypeBound::Path(path) => {
786 bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); 786 bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
787 bindings.clone().map(WhereClause::Implemented).map(|b| crate::wrap_empty_binders(b)) 787 bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
788 } 788 }
789 TypeBound::Lifetime(_) => None, 789 TypeBound::Lifetime(_) => None,
790 TypeBound::Error => None, 790 TypeBound::Error => None,
@@ -957,7 +957,7 @@ pub(crate) fn field_types_query(
957/// like `T::Item`. 957/// like `T::Item`.
958/// 958///
959/// See the analogous query in rustc and its comment: 959/// See the analogous query in rustc and its comment:
960/// https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46 960/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
961/// This is a query mostly to handle cycles somewhat gracefully; e.g. the 961/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
962/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but 962/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
963/// these are fine: `T: Foo<U::Item>, U: Foo<()>`. 963/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index a23527f7d..3d233b1e2 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,7 +8,7 @@ use arrayvec::ArrayVec;
8use base_db::{CrateId, Edition}; 8use base_db::{CrateId, Edition};
9use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; 9use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
10use hir_def::{ 10use hir_def::{
11 lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId, 11 lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, BlockId, FunctionId,
12 GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId, 12 GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
13}; 13};
14use hir_expand::name::Name; 14use hir_expand::name::Name;
@@ -60,7 +60,7 @@ impl TyFingerprint {
60 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), 60 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
61 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), 61 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
62 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), 62 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
63 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?, 63 TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
64 _ => return None, 64 _ => return None,
65 }; 65 };
66 Some(fp) 66 Some(fp)
@@ -77,7 +77,7 @@ impl TyFingerprint {
77 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), 77 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
78 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), 78 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
79 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), 79 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
80 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?, 80 TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
81 TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty), 81 TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
82 TyKind::Tuple(_, subst) => { 82 TyKind::Tuple(_, subst) => {
83 let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(&Interner)); 83 let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(&Interner));
@@ -139,35 +139,47 @@ impl TraitImpls {
139 let mut impls = Self { map: FxHashMap::default() }; 139 let mut impls = Self { map: FxHashMap::default() };
140 140
141 let crate_def_map = db.crate_def_map(krate); 141 let crate_def_map = db.crate_def_map(krate);
142 collect_def_map(db, &crate_def_map, &mut impls); 142 impls.collect_def_map(db, &crate_def_map);
143 143
144 return Arc::new(impls); 144 return Arc::new(impls);
145 }
145 146
146 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpls) { 147 pub(crate) fn trait_impls_in_block_query(
147 for (_module_id, module_data) in def_map.modules() { 148 db: &dyn HirDatabase,
148 for impl_id in module_data.scope.impls() { 149 block: BlockId,
149 let target_trait = match db.impl_trait(impl_id) { 150 ) -> Option<Arc<Self>> {
150 Some(tr) => tr.skip_binders().hir_trait_id(), 151 let _p = profile::span("trait_impls_in_block_query");
151 None => continue, 152 let mut impls = Self { map: FxHashMap::default() };
152 };
153 let self_ty = db.impl_self_ty(impl_id);
154 let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
155 impls
156 .map
157 .entry(target_trait)
158 .or_default()
159 .entry(self_ty_fp)
160 .or_default()
161 .push(impl_id);
162 }
163 153
164 // To better support custom derives, collect impls in all unnamed const items. 154 let block_def_map = db.block_def_map(block)?;
165 // const _: () = { ... }; 155 impls.collect_def_map(db, &block_def_map);
166 for konst in module_data.scope.unnamed_consts() { 156
167 let body = db.body(konst.into()); 157 return Some(Arc::new(impls));
168 for (_, block_def_map) in body.blocks(db.upcast()) { 158 }
169 collect_def_map(db, &block_def_map, impls); 159
170 } 160 fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
161 for (_module_id, module_data) in def_map.modules() {
162 for impl_id in module_data.scope.impls() {
163 let target_trait = match db.impl_trait(impl_id) {
164 Some(tr) => tr.skip_binders().hir_trait_id(),
165 None => continue,
166 };
167 let self_ty = db.impl_self_ty(impl_id);
168 let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
169 self.map
170 .entry(target_trait)
171 .or_default()
172 .entry(self_ty_fp)
173 .or_default()
174 .push(impl_id);
175 }
176
177 // To better support custom derives, collect impls in all unnamed const items.
178 // const _: () = { ... };
179 for konst in module_data.scope.unnamed_consts() {
180 let body = db.body(konst.into());
181 for (_, block_def_map) in body.blocks(db.upcast()) {
182 self.collect_def_map(db, &block_def_map);
171 } 183 }
172 } 184 }
173 } 185 }
@@ -372,7 +384,7 @@ pub(crate) fn lookup_method(
372 db, 384 db,
373 env, 385 env,
374 krate, 386 krate,
375 &traits_in_scope, 387 traits_in_scope,
376 visible_from_module, 388 visible_from_module,
377 Some(name), 389 Some(name),
378 LookupMode::MethodCall, 390 LookupMode::MethodCall,
@@ -484,7 +496,7 @@ fn iterate_method_candidates_impl(
484 LookupMode::Path => { 496 LookupMode::Path => {
485 // No autoderef for path lookups 497 // No autoderef for path lookups
486 iterate_method_candidates_for_self_ty( 498 iterate_method_candidates_for_self_ty(
487 &ty, 499 ty,
488 db, 500 db,
489 env, 501 env,
490 krate, 502 krate,
@@ -513,7 +525,7 @@ fn iterate_method_candidates_with_autoref(
513 db, 525 db,
514 env.clone(), 526 env.clone(),
515 krate, 527 krate,
516 &traits_in_scope, 528 traits_in_scope,
517 visible_from_module, 529 visible_from_module,
518 name, 530 name,
519 &mut callback, 531 &mut callback,
@@ -531,7 +543,7 @@ fn iterate_method_candidates_with_autoref(
531 db, 543 db,
532 env.clone(), 544 env.clone(),
533 krate, 545 krate,
534 &traits_in_scope, 546 traits_in_scope,
535 visible_from_module, 547 visible_from_module,
536 name, 548 name,
537 &mut callback, 549 &mut callback,
@@ -549,7 +561,7 @@ fn iterate_method_candidates_with_autoref(
549 db, 561 db,
550 env, 562 env,
551 krate, 563 krate,
552 &traits_in_scope, 564 traits_in_scope,
553 visible_from_module, 565 visible_from_module,
554 name, 566 name,
555 &mut callback, 567 &mut callback,
@@ -593,7 +605,7 @@ fn iterate_method_candidates_by_receiver(
593 db, 605 db,
594 env.clone(), 606 env.clone(),
595 krate, 607 krate,
596 &traits_in_scope, 608 traits_in_scope,
597 name, 609 name,
598 Some(receiver_ty), 610 Some(receiver_ty),
599 &mut callback, 611 &mut callback,
@@ -870,7 +882,7 @@ fn transform_receiver_ty(
870 .fill_with_unknown() 882 .fill_with_unknown()
871 .build(), 883 .build(),
872 AssocContainerId::ImplId(impl_id) => { 884 AssocContainerId::ImplId(impl_id) => {
873 let impl_substs = inherent_impl_substs(db, env, impl_id, &self_ty)?; 885 let impl_substs = inherent_impl_substs(db, env, impl_id, self_ty)?;
874 TyBuilder::subst_for_def(db, function_id) 886 TyBuilder::subst_for_def(db, function_id)
875 .use_parent_substs(&impl_substs) 887 .use_parent_substs(&impl_substs)
876 .fill_with_unknown() 888 .fill_with_unknown()
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 9d726b024..b873585c4 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -9,7 +9,7 @@ mod macros;
9mod display_source_code; 9mod display_source_code;
10mod incremental; 10mod incremental;
11 11
12use std::{env, sync::Arc}; 12use std::{collections::HashMap, env, sync::Arc};
13 13
14use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; 14use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
15use expect_test::Expect; 15use expect_test::Expect;
@@ -83,9 +83,105 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) {
83 checked_one = true; 83 checked_one = true;
84 } 84 }
85 } 85 }
86
86 assert!(checked_one, "no `//^` annotations found"); 87 assert!(checked_one, "no `//^` annotations found");
87} 88}
88 89
90fn check_no_mismatches(ra_fixture: &str) {
91 check_mismatches_impl(ra_fixture, true)
92}
93
94#[allow(unused)]
95fn check_mismatches(ra_fixture: &str) {
96 check_mismatches_impl(ra_fixture, false)
97}
98
99fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
100 let _tracing = setup_tracing();
101 let (db, file_id) = TestDB::with_single_file(ra_fixture);
102 let module = db.module_for_file(file_id);
103 let def_map = module.def_map(&db);
104
105 let mut defs: Vec<DefWithBodyId> = Vec::new();
106 visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
107 defs.sort_by_key(|def| match def {
108 DefWithBodyId::FunctionId(it) => {
109 let loc = it.lookup(&db);
110 loc.source(&db).value.syntax().text_range().start()
111 }
112 DefWithBodyId::ConstId(it) => {
113 let loc = it.lookup(&db);
114 loc.source(&db).value.syntax().text_range().start()
115 }
116 DefWithBodyId::StaticId(it) => {
117 let loc = it.lookup(&db);
118 loc.source(&db).value.syntax().text_range().start()
119 }
120 });
121 let mut mismatches = HashMap::new();
122 let mut push_mismatch = |src_ptr: InFile<SyntaxNode>, mismatch: TypeMismatch| {
123 let range = src_ptr.value.text_range();
124 if src_ptr.file_id.call_node(&db).is_some() {
125 panic!("type mismatch in macro expansion");
126 }
127 let file_range = FileRange { file_id: src_ptr.file_id.original_file(&db), range };
128 let actual = format!(
129 "expected {}, got {}",
130 mismatch.expected.display_test(&db),
131 mismatch.actual.display_test(&db)
132 );
133 mismatches.insert(file_range, actual);
134 };
135 for def in defs {
136 let (_body, body_source_map) = db.body_with_source_map(def);
137 let inference_result = db.infer(def);
138 for (pat, mismatch) in inference_result.pat_type_mismatches() {
139 let syntax_ptr = match body_source_map.pat_syntax(pat) {
140 Ok(sp) => {
141 let root = db.parse_or_expand(sp.file_id).unwrap();
142 sp.map(|ptr| {
143 ptr.either(
144 |it| it.to_node(&root).syntax().clone(),
145 |it| it.to_node(&root).syntax().clone(),
146 )
147 })
148 }
149 Err(SyntheticSyntax) => continue,
150 };
151 push_mismatch(syntax_ptr, mismatch.clone());
152 }
153 for (expr, mismatch) in inference_result.expr_type_mismatches() {
154 let node = match body_source_map.expr_syntax(expr) {
155 Ok(sp) => {
156 let root = db.parse_or_expand(sp.file_id).unwrap();
157 sp.map(|ptr| ptr.to_node(&root).syntax().clone())
158 }
159 Err(SyntheticSyntax) => continue,
160 };
161 push_mismatch(node, mismatch.clone());
162 }
163 }
164 let mut checked_one = false;
165 for (file_id, annotations) in db.extract_annotations() {
166 for (range, expected) in annotations {
167 let file_range = FileRange { file_id, range };
168 if let Some(mismatch) = mismatches.remove(&file_range) {
169 assert_eq!(mismatch, expected);
170 } else {
171 assert!(false, "Expected mismatch not encountered: {}\n", expected);
172 }
173 checked_one = true;
174 }
175 }
176 let mut buf = String::new();
177 for (range, mismatch) in mismatches {
178 format_to!(buf, "{:?}: {}\n", range.range, mismatch,);
179 }
180 assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf);
181
182 assert!(checked_one || allow_none, "no `//^` annotations found");
183}
184
89fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { 185fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
90 let file = db.parse(pos.file_id).ok().unwrap(); 186 let file = db.parse(pos.file_id).ok().unwrap();
91 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); 187 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap();
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 6dac7e103..713b74165 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches, check_types}; 3use super::{check_infer, check_infer_with_mismatches, check_no_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_block_expr_type_mismatch() { 6fn infer_block_expr_type_mismatch() {
@@ -23,38 +23,29 @@ fn infer_block_expr_type_mismatch() {
23fn coerce_places() { 23fn coerce_places() {
24 check_infer( 24 check_infer(
25 r#" 25 r#"
26 struct S<T> { a: T } 26//- minicore: coerce_unsized
27struct S<T> { a: T }
27 28
28 fn f<T>(_: &[T]) -> T { loop {} } 29fn f<T>(_: &[T]) -> T { loop {} }
29 fn g<T>(_: S<&[T]>) -> T { loop {} } 30fn g<T>(_: S<&[T]>) -> T { loop {} }
30 31
31 fn gen<T>() -> *mut [T; 2] { loop {} } 32fn gen<T>() -> *mut [T; 2] { loop {} }
32 fn test1<U>() -> *mut [U] { 33fn test1<U>() -> *mut [U] {
33 gen() 34 gen()
34 } 35}
35
36 fn test2() {
37 let arr: &[u8; 1] = &[1];
38
39 let a: &[_] = arr;
40 let b = f(arr);
41 let c: &[_] = { arr };
42 let d = g(S { a: arr });
43 let e: [&[_]; 1] = [arr];
44 let f: [&[_]; 2] = [arr; 2];
45 let g: (&[_], &[_]) = (arr, arr);
46 }
47 36
48 #[lang = "sized"] 37fn test2() {
49 pub trait Sized {} 38 let arr: &[u8; 1] = &[1];
50 #[lang = "unsize"]
51 pub trait Unsize<T: ?Sized> {}
52 #[lang = "coerce_unsized"]
53 pub trait CoerceUnsized<T> {}
54 39
55 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 40 let a: &[_] = arr;
56 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} 41 let b = f(arr);
57 "#, 42 let c: &[_] = { arr };
43 let d = g(S { a: arr });
44 let e: [&[_]; 1] = [arr];
45 let f: [&[_]; 2] = [arr; 2];
46 let g: (&[_], &[_]) = (arr, arr);
47}
48"#,
58 expect![[r#" 49 expect![[r#"
59 30..31 '_': &[T] 50 30..31 '_': &[T]
60 44..55 '{ loop {} }': T 51 44..55 '{ loop {} }': T
@@ -131,60 +122,52 @@ fn infer_let_stmt_coerce() {
131fn infer_custom_coerce_unsized() { 122fn infer_custom_coerce_unsized() {
132 check_infer( 123 check_infer(
133 r#" 124 r#"
134 struct A<T: ?Sized>(*const T); 125//- minicore: coerce_unsized
135 struct B<T: ?Sized>(*const T); 126use core::{marker::Unsize, ops::CoerceUnsized};
136 struct C<T: ?Sized> { inner: *const T }
137 127
138 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} 128struct A<T: ?Sized>(*const T);
139 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} 129struct B<T: ?Sized>(*const T);
130struct C<T: ?Sized> { inner: *const T }
140 131
141 fn foo1<T>(x: A<[T]>) -> A<[T]> { x } 132impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {}
142 fn foo2<T>(x: B<[T]>) -> B<[T]> { x } 133impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {}
143 fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
144
145 fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) {
146 let d = foo1(a);
147 let e = foo2(b);
148 let f = foo3(c);
149 }
150 134
135fn foo1<T>(x: A<[T]>) -> A<[T]> { x }
136fn foo2<T>(x: B<[T]>) -> B<[T]> { x }
137fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
151 138
152 #[lang = "sized"] 139fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) {
153 pub trait Sized {} 140 let d = foo1(a);
154 #[lang = "unsize"] 141 let e = foo2(b);
155 pub trait Unsize<T: ?Sized> {} 142 let f = foo3(c);
156 #[lang = "coerce_unsized"] 143}
157 pub trait CoerceUnsized<T> {} 144"#,
158
159 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
160 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
161 "#,
162 expect![[r#" 145 expect![[r#"
163 257..258 'x': A<[T]> 146 306..307 'x': A<[T]>
164 278..283 '{ x }': A<[T]> 147 327..332 '{ x }': A<[T]>
165 280..281 'x': A<[T]> 148 329..330 'x': A<[T]>
166 295..296 'x': B<[T]> 149 344..345 'x': B<[T]>
167 316..321 '{ x }': B<[T]> 150 365..370 '{ x }': B<[T]>
168 318..319 'x': B<[T]> 151 367..368 'x': B<[T]>
169 333..334 'x': C<[T]> 152 382..383 'x': C<[T]>
170 354..359 '{ x }': C<[T]> 153 403..408 '{ x }': C<[T]>
171 356..357 'x': C<[T]> 154 405..406 'x': C<[T]>
172 369..370 'a': A<[u8; 2]> 155 418..419 'a': A<[u8; 2]>
173 384..385 'b': B<[u8; 2]> 156 433..434 'b': B<[u8; 2]>
174 399..400 'c': C<[u8; 2]> 157 448..449 'c': C<[u8; 2]>
175 414..480 '{ ...(c); }': () 158 463..529 '{ ...(c); }': ()
176 424..425 'd': A<[{unknown}]> 159 473..474 'd': A<[{unknown}]>
177 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> 160 477..481 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]>
178 428..435 'foo1(a)': A<[{unknown}]> 161 477..484 'foo1(a)': A<[{unknown}]>
179 433..434 'a': A<[u8; 2]> 162 482..483 'a': A<[u8; 2]>
180 445..446 'e': B<[u8]> 163 494..495 'e': B<[u8]>
181 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> 164 498..502 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]>
182 449..456 'foo2(b)': B<[u8]> 165 498..505 'foo2(b)': B<[u8]>
183 454..455 'b': B<[u8; 2]> 166 503..504 'b': B<[u8; 2]>
184 466..467 'f': C<[u8]> 167 515..516 'f': C<[u8]>
185 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> 168 519..523 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]>
186 470..477 'foo3(c)': C<[u8]> 169 519..526 'foo3(c)': C<[u8]>
187 475..476 'c': C<[u8; 2]> 170 524..525 'c': C<[u8; 2]>
188 "#]], 171 "#]],
189 ); 172 );
190} 173}
@@ -193,21 +176,16 @@ fn infer_custom_coerce_unsized() {
193fn infer_if_coerce() { 176fn infer_if_coerce() {
194 check_infer( 177 check_infer(
195 r#" 178 r#"
196 fn foo<T>(x: &[T]) -> &[T] { loop {} } 179//- minicore: unsize
197 fn test() { 180fn foo<T>(x: &[T]) -> &[T] { loop {} }
198 let x = if true { 181fn test() {
199 foo(&[1]) 182 let x = if true {
200 } else { 183 foo(&[1])
201 &[1] 184 } else {
202 }; 185 &[1]
203 } 186 };
204 187}
205 188"#,
206 #[lang = "sized"]
207 pub trait Sized {}
208 #[lang = "unsize"]
209 pub trait Unsize<T: ?Sized> {}
210 "#,
211 expect![[r#" 189 expect![[r#"
212 10..11 'x': &[T] 190 10..11 'x': &[T]
213 27..38 '{ loop {} }': &[T] 191 27..38 '{ loop {} }': &[T]
@@ -235,25 +213,16 @@ fn infer_if_coerce() {
235fn infer_if_else_coerce() { 213fn infer_if_else_coerce() {
236 check_infer( 214 check_infer(
237 r#" 215 r#"
238 fn foo<T>(x: &[T]) -> &[T] { loop {} } 216//- minicore: coerce_unsized
239 fn test() { 217fn foo<T>(x: &[T]) -> &[T] { loop {} }
240 let x = if true { 218fn test() {
241 &[1] 219 let x = if true {
242 } else { 220 &[1]
243 foo(&[1]) 221 } else {
244 }; 222 foo(&[1])
245 } 223 };
246 224}
247 #[lang = "sized"] 225"#,
248 pub trait Sized {}
249 #[lang = "unsize"]
250 pub trait Unsize<T: ?Sized> {}
251 #[lang = "coerce_unsized"]
252 pub trait CoerceUnsized<T> {}
253
254 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
255 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
256 "#,
257 expect![[r#" 226 expect![[r#"
258 10..11 'x': &[T] 227 10..11 'x': &[T]
259 27..38 '{ loop {} }': &[T] 228 27..38 '{ loop {} }': &[T]
@@ -281,20 +250,16 @@ fn infer_if_else_coerce() {
281fn infer_match_first_coerce() { 250fn infer_match_first_coerce() {
282 check_infer( 251 check_infer(
283 r#" 252 r#"
284 fn foo<T>(x: &[T]) -> &[T] { loop {} } 253//- minicore: unsize
285 fn test(i: i32) { 254fn foo<T>(x: &[T]) -> &[T] { loop {} }
286 let x = match i { 255fn test(i: i32) {
287 2 => foo(&[2]), 256 let x = match i {
288 1 => &[1], 257 2 => foo(&[2]),
289 _ => &[3], 258 1 => &[1],
290 }; 259 _ => &[3],
291 } 260 };
292 261}
293 #[lang = "sized"] 262"#,
294 pub trait Sized {}
295 #[lang = "unsize"]
296 pub trait Unsize<T: ?Sized> {}
297 "#,
298 expect![[r#" 263 expect![[r#"
299 10..11 'x': &[T] 264 10..11 'x': &[T]
300 27..38 '{ loop {} }': &[T] 265 27..38 '{ loop {} }': &[T]
@@ -329,25 +294,16 @@ fn infer_match_first_coerce() {
329fn infer_match_second_coerce() { 294fn infer_match_second_coerce() {
330 check_infer( 295 check_infer(
331 r#" 296 r#"
332 fn foo<T>(x: &[T]) -> &[T] { loop {} } 297//- minicore: coerce_unsized
333 fn test(i: i32) { 298fn foo<T>(x: &[T]) -> &[T] { loop {} }
334 let x = match i { 299fn test(i: i32) {
335 1 => &[1], 300 let x = match i {
336 2 => foo(&[2]), 301 1 => &[1],
337 _ => &[3], 302 2 => foo(&[2]),
338 }; 303 _ => &[3],
339 } 304 };
340 305}
341 #[lang = "sized"] 306"#,
342 pub trait Sized {}
343 #[lang = "unsize"]
344 pub trait Unsize<T: ?Sized> {}
345 #[lang = "coerce_unsized"]
346 pub trait CoerceUnsized<T> {}
347
348 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
349 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
350 "#,
351 expect![[r#" 307 expect![[r#"
352 10..11 'x': &[T] 308 10..11 'x': &[T]
353 27..38 '{ loop {} }': &[T] 309 27..38 '{ loop {} }': &[T]
@@ -470,15 +426,15 @@ fn coerce_autoderef() {
470#[test] 426#[test]
471fn coerce_autoderef_generic() { 427fn coerce_autoderef_generic() {
472 check_infer_with_mismatches( 428 check_infer_with_mismatches(
473 r" 429 r#"
474 struct Foo; 430struct Foo;
475 fn takes_ref<T>(x: &T) -> T { *x } 431fn takes_ref<T>(x: &T) -> T { *x }
476 fn test() { 432fn test() {
477 takes_ref(&Foo); 433 takes_ref(&Foo);
478 takes_ref(&&Foo); 434 takes_ref(&&Foo);
479 takes_ref(&&&Foo); 435 takes_ref(&&&Foo);
480 } 436}
481 ", 437"#,
482 expect![[r" 438 expect![[r"
483 28..29 'x': &T 439 28..29 'x': &T
484 40..46 '{ *x }': T 440 40..46 '{ *x }': T
@@ -508,30 +464,29 @@ fn coerce_autoderef_generic() {
508fn coerce_autoderef_block() { 464fn coerce_autoderef_block() {
509 check_infer_with_mismatches( 465 check_infer_with_mismatches(
510 r#" 466 r#"
511 struct String {} 467//- minicore: deref
512 #[lang = "deref"] 468struct String {}
513 trait Deref { type Target; } 469impl core::ops::Deref for String { type Target = str; }
514 impl Deref for String { type Target = str; } 470fn takes_ref_str(x: &str) {}
515 fn takes_ref_str(x: &str) {} 471fn returns_string() -> String { loop {} }
516 fn returns_string() -> String { loop {} } 472fn test() {
517 fn test() { 473 takes_ref_str(&{ returns_string() });
518 takes_ref_str(&{ returns_string() }); 474}
519 } 475"#,
520 "#, 476 expect![[r#"
521 expect![[r" 477 90..91 'x': &str
522 126..127 'x': &str 478 99..101 '{}': ()
523 135..137 '{}': () 479 132..143 '{ loop {} }': String
524 168..179 '{ loop {} }': String 480 134..141 'loop {}': !
525 170..177 'loop {}': ! 481 139..141 '{}': ()
526 175..177 '{}': () 482 154..199 '{ ... }); }': ()
527 190..235 '{ ... }); }': () 483 160..173 'takes_ref_str': fn takes_ref_str(&str)
528 196..209 'takes_ref_str': fn takes_ref_str(&str) 484 160..196 'takes_...g() })': ()
529 196..232 'takes_...g() })': () 485 174..195 '&{ ret...ng() }': &String
530 210..231 '&{ ret...ng() }': &String 486 175..195 '{ retu...ng() }': String
531 211..231 '{ retu...ng() }': String 487 177..191 'returns_string': fn returns_string() -> String
532 213..227 'returns_string': fn returns_string() -> String 488 177..193 'return...ring()': String
533 213..229 'return...ring()': String 489 "#]],
534 "]],
535 ); 490 );
536} 491}
537 492
@@ -674,25 +629,19 @@ fn coerce_placeholder_ref() {
674fn coerce_unsize_array() { 629fn coerce_unsize_array() {
675 check_infer_with_mismatches( 630 check_infer_with_mismatches(
676 r#" 631 r#"
677 #[lang = "unsize"] 632//- minicore: coerce_unsized
678 pub trait Unsize<T> {} 633fn test() {
679 #[lang = "coerce_unsized"] 634 let f: &[usize] = &[1, 2, 3];
680 pub trait CoerceUnsized<T> {} 635}
681
682 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
683
684 fn test() {
685 let f: &[usize] = &[1, 2, 3];
686 }
687 "#, 636 "#,
688 expect![[r#" 637 expect![[r#"
689 161..198 '{ ... 3]; }': () 638 10..47 '{ ... 3]; }': ()
690 171..172 'f': &[usize] 639 20..21 'f': &[usize]
691 185..195 '&[1, 2, 3]': &[usize; 3] 640 34..44 '&[1, 2, 3]': &[usize; 3]
692 186..195 '[1, 2, 3]': [usize; 3] 641 35..44 '[1, 2, 3]': [usize; 3]
693 187..188 '1': usize 642 36..37 '1': usize
694 190..191 '2': usize 643 39..40 '2': usize
695 193..194 '3': usize 644 42..43 '3': usize
696 "#]], 645 "#]],
697 ); 646 );
698} 647}
@@ -701,93 +650,94 @@ fn coerce_unsize_array() {
701fn coerce_unsize_trait_object_simple() { 650fn coerce_unsize_trait_object_simple() {
702 check_infer_with_mismatches( 651 check_infer_with_mismatches(
703 r#" 652 r#"
704 #[lang = "sized"] 653//- minicore: coerce_unsized
705 pub trait Sized {} 654trait Foo<T, U> {}
706 #[lang = "unsize"] 655trait Bar<U, T, X>: Foo<T, U> {}
707 pub trait Unsize<T> {} 656trait Baz<T, X>: Bar<usize, T, X> {}
708 #[lang = "coerce_unsized"] 657
709 pub trait CoerceUnsized<T> {} 658struct S<T, X>;
710 659impl<T, X> Foo<T, usize> for S<T, X> {}
711 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 660impl<T, X> Bar<usize, T, X> for S<T, X> {}
712 661impl<T, X> Baz<T, X> for S<T, X> {}
713 trait Foo<T, U> {} 662
714 trait Bar<U, T, X>: Foo<T, U> {} 663fn test() {
715 trait Baz<T, X>: Bar<usize, T, X> {} 664 let obj: &dyn Baz<i8, i16> = &S;
716 665 let obj: &dyn Bar<_, i8, i16> = &S;
717 struct S<T, X>; 666 let obj: &dyn Foo<i8, _> = &S;
718 impl<T, X> Foo<T, usize> for S<T, X> {} 667}
719 impl<T, X> Bar<usize, T, X> for S<T, X> {} 668"#,
720 impl<T, X> Baz<T, X> for S<T, X> {} 669 expect![[r#"
721 670 236..351 '{ ... &S; }': ()
722 fn test() { 671 246..249 'obj': &dyn Baz<i8, i16>
723 let obj: &dyn Baz<i8, i16> = &S; 672 271..273 '&S': &S<i8, i16>
724 let obj: &dyn Bar<_, i8, i16> = &S; 673 272..273 'S': S<i8, i16>
725 let obj: &dyn Foo<i8, _> = &S; 674 283..286 'obj': &dyn Bar<usize, i8, i16>
726 } 675 311..313 '&S': &S<i8, i16>
727 "#, 676 312..313 'S': S<i8, i16>
728 expect![[r" 677 323..326 'obj': &dyn Foo<i8, usize>
729 424..539 '{ ... &S; }': () 678 346..348 '&S': &S<i8, {unknown}>
730 434..437 'obj': &dyn Baz<i8, i16> 679 347..348 'S': S<i8, {unknown}>
731 459..461 '&S': &S<i8, i16> 680 "#]],
732 460..461 'S': S<i8, i16>
733 471..474 'obj': &dyn Bar<usize, i8, i16>
734 499..501 '&S': &S<i8, i16>
735 500..501 'S': S<i8, i16>
736 511..514 'obj': &dyn Foo<i8, usize>
737 534..536 '&S': &S<i8, {unknown}>
738 535..536 'S': S<i8, {unknown}>
739 "]],
740 ); 681 );
741} 682}
742 683
743#[test] 684#[test]
744// The rust reference says this should be possible, but rustc doesn't implement
745// it. We used to support it, but Chalk doesn't.
746#[ignore]
747fn coerce_unsize_trait_object_to_trait_object() { 685fn coerce_unsize_trait_object_to_trait_object() {
686 // FIXME: The rust reference says this should be possible, but rustc doesn't
687 // implement it. We used to support it, but Chalk doesn't. Here's the
688 // correct expect:
689 //
690 // 424..609 '{ ...bj2; }': ()
691 // 434..437 'obj': &dyn Baz<i8, i16>
692 // 459..461 '&S': &S<i8, i16>
693 // 460..461 'S': S<i8, i16>
694 // 471..474 'obj': &dyn Bar<usize, i8, i16>
695 // 496..499 'obj': &dyn Baz<i8, i16>
696 // 509..512 'obj': &dyn Foo<i8, usize>
697 // 531..534 'obj': &dyn Bar<usize, i8, i16>
698 // 544..548 'obj2': &dyn Baz<i8, i16>
699 // 570..572 '&S': &S<i8, i16>
700 // 571..572 'S': S<i8, i16>
701 // 582..583 '_': &dyn Foo<i8, usize>
702 // 602..606 'obj2': &dyn Baz<i8, i16>
748 check_infer_with_mismatches( 703 check_infer_with_mismatches(
749 r#" 704 r#"
750 #[lang = "sized"] 705//- minicore: coerce_unsized
751 pub trait Sized {} 706trait Foo<T, U> {}
752 #[lang = "unsize"] 707trait Bar<U, T, X>: Foo<T, U> {}
753 pub trait Unsize<T> {} 708trait Baz<T, X>: Bar<usize, T, X> {}
754 #[lang = "coerce_unsized"] 709
755 pub trait CoerceUnsized<T> {} 710struct S<T, X>;
756 711impl<T, X> Foo<T, usize> for S<T, X> {}
757 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 712impl<T, X> Bar<usize, T, X> for S<T, X> {}
758 713impl<T, X> Baz<T, X> for S<T, X> {}
759 trait Foo<T, U> {} 714
760 trait Bar<U, T, X>: Foo<T, U> {} 715fn test() {
761 trait Baz<T, X>: Bar<usize, T, X> {} 716 let obj: &dyn Baz<i8, i16> = &S;
762 717 let obj: &dyn Bar<_, _, _> = obj;
763 struct S<T, X>; 718 let obj: &dyn Foo<_, _> = obj;
764 impl<T, X> Foo<T, usize> for S<T, X> {} 719 let obj2: &dyn Baz<i8, i16> = &S;
765 impl<T, X> Bar<usize, T, X> for S<T, X> {} 720 let _: &dyn Foo<_, _> = obj2;
766 impl<T, X> Baz<T, X> for S<T, X> {} 721}
767 722"#,
768 fn test() { 723 expect![[r#"
769 let obj: &dyn Baz<i8, i16> = &S; 724 236..421 '{ ...bj2; }': ()
770 let obj: &dyn Bar<_, _, _> = obj; 725 246..249 'obj': &dyn Baz<i8, i16>
771 let obj: &dyn Foo<_, _> = obj; 726 271..273 '&S': &S<i8, i16>
772 let obj2: &dyn Baz<i8, i16> = &S; 727 272..273 'S': S<i8, i16>
773 let _: &dyn Foo<_, _> = obj2; 728 283..286 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}>
774 } 729 308..311 'obj': &dyn Baz<i8, i16>
775 "#, 730 321..324 'obj': &dyn Foo<{unknown}, {unknown}>
776 expect![[r" 731 343..346 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}>
777 424..609 '{ ...bj2; }': () 732 356..360 'obj2': &dyn Baz<i8, i16>
778 434..437 'obj': &dyn Baz<i8, i16> 733 382..384 '&S': &S<i8, i16>
779 459..461 '&S': &S<i8, i16> 734 383..384 'S': S<i8, i16>
780 460..461 'S': S<i8, i16> 735 394..395 '_': &dyn Foo<{unknown}, {unknown}>
781 471..474 'obj': &dyn Bar<usize, i8, i16> 736 414..418 'obj2': &dyn Baz<i8, i16>
782 496..499 'obj': &dyn Baz<i8, i16> 737 308..311: expected &dyn Bar<{unknown}, {unknown}, {unknown}>, got &dyn Baz<i8, i16>
783 509..512 'obj': &dyn Foo<i8, usize> 738 343..346: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Bar<{unknown}, {unknown}, {unknown}>
784 531..534 'obj': &dyn Bar<usize, i8, i16> 739 414..418: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Baz<i8, i16>
785 544..548 'obj2': &dyn Baz<i8, i16> 740 "#]],
786 570..572 '&S': &S<i8, i16>
787 571..572 'S': S<i8, i16>
788 582..583 '_': &dyn Foo<i8, usize>
789 602..606 'obj2': &dyn Baz<i8, i16>
790 "]],
791 ); 741 );
792} 742}
793 743
@@ -795,40 +745,32 @@ fn coerce_unsize_trait_object_to_trait_object() {
795fn coerce_unsize_super_trait_cycle() { 745fn coerce_unsize_super_trait_cycle() {
796 check_infer_with_mismatches( 746 check_infer_with_mismatches(
797 r#" 747 r#"
798 #[lang = "sized"] 748//- minicore: coerce_unsized
799 pub trait Sized {} 749trait A {}
800 #[lang = "unsize"] 750trait B: C + A {}
801 pub trait Unsize<T> {} 751trait C: B {}
802 #[lang = "coerce_unsized"] 752trait D: C
803 pub trait CoerceUnsized<T> {} 753
804 754struct S;
805 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 755impl A for S {}
806 756impl B for S {}
807 trait A {} 757impl C for S {}
808 trait B: C + A {} 758impl D for S {}
809 trait C: B {} 759
810 trait D: C 760fn test() {
811 761 let obj: &dyn D = &S;
812 struct S; 762 let obj: &dyn A = &S;
813 impl A for S {} 763}
814 impl B for S {} 764"#,
815 impl C for S {} 765 expect![[r#"
816 impl D for S {} 766 140..195 '{ ... &S; }': ()
817 767 150..153 'obj': &dyn D
818 fn test() { 768 164..166 '&S': &S
819 let obj: &dyn D = &S; 769 165..166 'S': S
820 let obj: &dyn A = &S; 770 176..179 'obj': &dyn A
821 } 771 190..192 '&S': &S
822 "#, 772 191..192 'S': S
823 expect![[r" 773 "#]],
824 328..383 '{ ... &S; }': ()
825 338..341 'obj': &dyn D
826 352..354 '&S': &S
827 353..354 'S': S
828 364..367 'obj': &dyn A
829 378..380 '&S': &S
830 379..380 'S': S
831 "]],
832 ); 774 );
833} 775}
834 776
@@ -837,41 +779,35 @@ fn coerce_unsize_generic() {
837 // FIXME: fix the type mismatches here 779 // FIXME: fix the type mismatches here
838 check_infer_with_mismatches( 780 check_infer_with_mismatches(
839 r#" 781 r#"
840 #[lang = "unsize"] 782//- minicore: coerce_unsized
841 pub trait Unsize<T> {} 783struct Foo<T> { t: T };
842 #[lang = "coerce_unsized"] 784struct Bar<T>(Foo<T>);
843 pub trait CoerceUnsized<T> {}
844
845 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
846 785
847 struct Foo<T> { t: T }; 786fn test() {
848 struct Bar<T>(Foo<T>); 787 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
849 788 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
850 fn test() { 789}
851 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; 790"#,
852 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
853 }
854 "#,
855 expect![[r#" 791 expect![[r#"
856 209..317 '{ ... }); }': () 792 58..166 '{ ... }); }': ()
857 219..220 '_': &Foo<[usize]> 793 68..69 '_': &Foo<[usize]>
858 238..259 '&Foo {..., 3] }': &Foo<[usize]> 794 87..108 '&Foo {..., 3] }': &Foo<[usize]>
859 239..259 'Foo { ..., 3] }': Foo<[usize]> 795 88..108 'Foo { ..., 3] }': Foo<[usize]>
860 248..257 '[1, 2, 3]': [usize; 3] 796 97..106 '[1, 2, 3]': [usize; 3]
861 249..250 '1': usize 797 98..99 '1': usize
862 252..253 '2': usize 798 101..102 '2': usize
863 255..256 '3': usize 799 104..105 '3': usize
864 269..270 '_': &Bar<[usize]> 800 118..119 '_': &Bar<[usize]>
865 288..314 '&Bar(F... 3] })': &Bar<[i32; 3]> 801 137..163 '&Bar(F... 3] })': &Bar<[i32; 3]>
866 289..292 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]> 802 138..141 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]>
867 289..314 'Bar(Fo... 3] })': Bar<[i32; 3]> 803 138..163 'Bar(Fo... 3] })': Bar<[i32; 3]>
868 293..313 'Foo { ..., 3] }': Foo<[i32; 3]> 804 142..162 'Foo { ..., 3] }': Foo<[i32; 3]>
869 302..311 '[1, 2, 3]': [i32; 3] 805 151..160 '[1, 2, 3]': [i32; 3]
870 303..304 '1': i32 806 152..153 '1': i32
871 306..307 '2': i32 807 155..156 '2': i32
872 309..310 '3': i32 808 158..159 '3': i32
873 248..257: expected [usize], got [usize; 3] 809 97..106: expected [usize], got [usize; 3]
874 288..314: expected &Bar<[usize]>, got &Bar<[i32; 3]> 810 137..163: expected &Bar<[usize]>, got &Bar<[i32; 3]>
875 "#]], 811 "#]],
876 ); 812 );
877} 813}
@@ -881,15 +817,7 @@ fn coerce_unsize_apit() {
881 // FIXME: #8984 817 // FIXME: #8984
882 check_infer_with_mismatches( 818 check_infer_with_mismatches(
883 r#" 819 r#"
884#[lang = "sized"] 820//- minicore: coerce_unsized
885pub trait Sized {}
886#[lang = "unsize"]
887pub trait Unsize<T> {}
888#[lang = "coerce_unsized"]
889pub trait CoerceUnsized<T> {}
890
891impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
892
893trait Foo {} 821trait Foo {}
894 822
895fn test(f: impl Foo) { 823fn test(f: impl Foo) {
@@ -897,12 +825,12 @@ fn test(f: impl Foo) {
897} 825}
898 "#, 826 "#,
899 expect![[r#" 827 expect![[r#"
900 210..211 'f': impl Foo 828 22..23 'f': impl Foo
901 223..252 '{ ... &f; }': () 829 35..64 '{ ... &f; }': ()
902 233..234 '_': &dyn Foo 830 45..46 '_': &dyn Foo
903 247..249 '&f': &impl Foo 831 59..61 '&f': &impl Foo
904 248..249 'f': impl Foo 832 60..61 'f': impl Foo
905 247..249: expected &dyn Foo, got &impl Foo 833 59..61: expected &dyn Foo, got &impl Foo
906 "#]], 834 "#]],
907 ); 835 );
908} 836}
@@ -963,7 +891,7 @@ fn test() -> i32 {
963 891
964#[test] 892#[test]
965fn panic_macro() { 893fn panic_macro() {
966 check_infer_with_mismatches( 894 check_no_mismatches(
967 r#" 895 r#"
968mod panic { 896mod panic {
969 #[macro_export] 897 #[macro_export]
@@ -991,15 +919,26 @@ fn main() {
991 panic!() 919 panic!()
992} 920}
993 "#, 921 "#,
994 expect![[r#" 922 );
995 174..185 '{ loop {} }': ! 923}
996 176..183 'loop {}': ! 924
997 181..183 '{}': () 925#[test]
998 !0..24 '$crate...:panic': fn panic() -> ! 926fn coerce_unsize_expected_type() {
999 !0..26 '$crate...anic()': ! 927 check_no_mismatches(
1000 !0..26 '$crate...anic()': ! 928 r#"
1001 !0..28 '$crate...015!()': ! 929//- minicore: coerce_unsized
1002 454..470 '{ ...c!() }': () 930fn main() {
1003 "#]], 931 let foo: &[u32] = &[1, 2];
932 let foo: &[u32] = match true {
933 true => &[1, 2],
934 false => &[1, 2, 3],
935 };
936 let foo: &[u32] = if true {
937 &[1, 2]
938 } else {
939 &[1, 2, 3]
940 };
941}
942 "#,
1004 ); 943 );
1005} 944}
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index f26b2c8a7..d9b5ee9cf 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -780,10 +780,7 @@ fn test() { (&S).foo(); }
780fn method_resolution_unsize_array() { 780fn method_resolution_unsize_array() {
781 check_types( 781 check_types(
782 r#" 782 r#"
783#[lang = "slice"] 783//- minicore: slice
784impl<T> [T] {
785 fn len(&self) -> usize { loop {} }
786}
787fn test() { 784fn test() {
788 let a = [1, 2, 3]; 785 let a = [1, 2, 3];
789 a.len(); 786 a.len();
@@ -1178,11 +1175,7 @@ fn main() {
1178fn autoderef_visibility_field() { 1175fn autoderef_visibility_field() {
1179 check_infer( 1176 check_infer(
1180 r#" 1177 r#"
1181#[lang = "deref"] 1178//- minicore: deref
1182pub trait Deref {
1183 type Target;
1184 fn deref(&self) -> &Self::Target;
1185}
1186mod a { 1179mod a {
1187 pub struct Foo(pub char); 1180 pub struct Foo(pub char);
1188 pub struct Bar(i32); 1181 pub struct Bar(i32);
@@ -1191,7 +1184,7 @@ mod a {
1191 Self(0) 1184 Self(0)
1192 } 1185 }
1193 } 1186 }
1194 impl super::Deref for Bar { 1187 impl core::ops::Deref for Bar {
1195 type Target = Foo; 1188 type Target = Foo;
1196 fn deref(&self) -> &Foo { 1189 fn deref(&self) -> &Foo {
1197 &Foo('z') 1190 &Foo('z')
@@ -1205,22 +1198,21 @@ mod b {
1205} 1198}
1206 "#, 1199 "#,
1207 expect![[r#" 1200 expect![[r#"
1208 67..71 'self': &Self 1201 107..138 '{ ... }': Bar
1209 200..231 '{ ... }': Bar 1202 121..125 'Self': Bar(i32) -> Bar
1210 214..218 'Self': Bar(i32) -> Bar 1203 121..128 'Self(0)': Bar
1211 214..221 'Self(0)': Bar 1204 126..127 '0': i32
1212 219..220 '0': i32 1205 226..230 'self': &Bar
1213 315..319 'self': &Bar 1206 240..273 '{ ... }': &Foo
1214 329..362 '{ ... }': &Foo 1207 254..263 '&Foo('z')': &Foo
1215 343..352 '&Foo('z')': &Foo 1208 255..258 'Foo': Foo(char) -> Foo
1216 344..347 'Foo': Foo(char) -> Foo 1209 255..263 'Foo('z')': Foo
1217 344..352 'Foo('z')': Foo 1210 259..262 ''z'': char
1218 348..351 ''z'': char 1211 303..350 '{ ... }': ()
1219 392..439 '{ ... }': () 1212 317..318 'x': char
1220 406..407 'x': char 1213 321..339 'super:...r::new': fn new() -> Bar
1221 410..428 'super:...r::new': fn new() -> Bar 1214 321..341 'super:...:new()': Bar
1222 410..430 'super:...:new()': Bar 1215 321..343 'super:...ew().0': char
1223 410..432 'super:...ew().0': char
1224 "#]], 1216 "#]],
1225 ) 1217 )
1226} 1218}
@@ -1230,11 +1222,7 @@ fn autoderef_visibility_method() {
1230 cov_mark::check!(autoderef_candidate_not_visible); 1222 cov_mark::check!(autoderef_candidate_not_visible);
1231 check_infer( 1223 check_infer(
1232 r#" 1224 r#"
1233#[lang = "deref"] 1225//- minicore: deref
1234pub trait Deref {
1235 type Target;
1236 fn deref(&self) -> &Self::Target;
1237}
1238mod a { 1226mod a {
1239 pub struct Foo(pub char); 1227 pub struct Foo(pub char);
1240 impl Foo { 1228 impl Foo {
@@ -1251,7 +1239,7 @@ mod a {
1251 self.0 1239 self.0
1252 } 1240 }
1253 } 1241 }
1254 impl super::Deref for Bar { 1242 impl core::ops::Deref for Bar {
1255 type Target = Foo; 1243 type Target = Foo;
1256 fn deref(&self) -> &Foo { 1244 fn deref(&self) -> &Foo {
1257 &Foo('z') 1245 &Foo('z')
@@ -1265,30 +1253,29 @@ mod b {
1265} 1253}
1266 "#, 1254 "#,
1267 expect![[r#" 1255 expect![[r#"
1268 67..71 'self': &Self 1256 75..79 'self': &Foo
1269 168..172 'self': &Foo 1257 89..119 '{ ... }': char
1270 182..212 '{ ... }': char 1258 103..107 'self': &Foo
1271 196..200 'self': &Foo 1259 103..109 'self.0': char
1272 196..202 'self.0': char 1260 195..226 '{ ... }': Bar
1273 288..319 '{ ... }': Bar 1261 209..213 'Self': Bar(i32) -> Bar
1274 302..306 'Self': Bar(i32) -> Bar 1262 209..216 'Self(0)': Bar
1275 302..309 'Self(0)': Bar 1263 214..215 '0': i32
1276 307..308 '0': i32 1264 245..249 'self': &Bar
1277 338..342 'self': &Bar 1265 258..288 '{ ... }': i32
1278 351..381 '{ ... }': i32 1266 272..276 'self': &Bar
1279 365..369 'self': &Bar 1267 272..278 'self.0': i32
1280 365..371 'self.0': i32 1268 376..380 'self': &Bar
1281 465..469 'self': &Bar 1269 390..423 '{ ... }': &Foo
1282 479..512 '{ ... }': &Foo 1270 404..413 '&Foo('z')': &Foo
1283 493..502 '&Foo('z')': &Foo 1271 405..408 'Foo': Foo(char) -> Foo
1284 494..497 'Foo': Foo(char) -> Foo 1272 405..413 'Foo('z')': Foo
1285 494..502 'Foo('z')': Foo 1273 409..412 ''z'': char
1286 498..501 ''z'': char 1274 453..506 '{ ... }': ()
1287 542..595 '{ ... }': () 1275 467..468 'x': char
1288 556..557 'x': char 1276 471..489 'super:...r::new': fn new() -> Bar
1289 560..578 'super:...r::new': fn new() -> Bar 1277 471..491 'super:...:new()': Bar
1290 560..580 'super:...:new()': Bar 1278 471..499 'super:...ango()': char
1291 560..588 'super:...ango()': char
1292 "#]], 1279 "#]],
1293 ) 1280 )
1294} 1281}
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 7d00cee9b..5adbe9c45 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches, check_types}; 3use super::{check_infer, check_infer_with_mismatches, check_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_pattern() { 6fn infer_pattern() {
@@ -518,47 +518,24 @@ fn infer_generics_in_patterns() {
518 518
519#[test] 519#[test]
520fn infer_const_pattern() { 520fn infer_const_pattern() {
521 check_infer_with_mismatches( 521 check_mismatches(
522 r#" 522 r#"
523 enum Option<T> { None } 523enum Option<T> { None }
524 use Option::None; 524use Option::None;
525 struct Foo; 525struct Foo;
526 const Bar: usize = 1; 526const Bar: usize = 1;
527 527
528 fn test() { 528fn test() {
529 let a: Option<u32> = None; 529 let a: Option<u32> = None;
530 let b: Option<i64> = match a { 530 let b: Option<i64> = match a {
531 None => None, 531 None => None,
532 }; 532 };
533 let _: () = match () { Foo => Foo }; // Expected mismatch 533 let _: () = match () { Foo => () };
534 let _: () = match () { Bar => Bar }; // Expected mismatch 534 // ^^^ expected (), got Foo
535 } 535 let _: () = match () { Bar => () };
536 // ^^^ expected (), got usize
537}
536 "#, 538 "#,
537 expect![[r#"
538 73..74 '1': usize
539 87..309 '{ ...atch }': ()
540 97..98 'a': Option<u32>
541 114..118 'None': Option<u32>
542 128..129 'b': Option<i64>
543 145..182 'match ... }': Option<i64>
544 151..152 'a': Option<u32>
545 163..167 'None': Option<u32>
546 171..175 'None': Option<i64>
547 192..193 '_': ()
548 200..223 'match ... Foo }': Foo
549 206..208 '()': ()
550 211..214 'Foo': Foo
551 218..221 'Foo': Foo
552 254..255 '_': ()
553 262..285 'match ... Bar }': usize
554 268..270 '()': ()
555 273..276 'Bar': usize
556 280..283 'Bar': usize
557 200..223: expected (), got Foo
558 211..214: expected (), got Foo
559 262..285: expected (), got usize
560 273..276: expected (), got usize
561 "#]],
562 ); 539 );
563} 540}
564 541
@@ -594,48 +571,44 @@ fn main() {
594fn match_ergonomics_in_closure_params() { 571fn match_ergonomics_in_closure_params() {
595 check_infer( 572 check_infer(
596 r#" 573 r#"
597 #[lang = "fn_once"] 574//- minicore: fn
598 trait FnOnce<Args> { 575fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
599 type Output;
600 }
601
602 fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
603 576
604 fn test() { 577fn test() {
605 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics 578 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
606 foo(&(1, "a"), |(x, y)| x); 579 foo(&(1, "a"), |(x, y)| x);
607 } 580}
608 "#, 581"#,
609 expect![[r#" 582 expect![[r#"
610 93..94 't': T 583 32..33 't': T
611 99..100 'f': F 584 38..39 'f': F
612 110..121 '{ loop {} }': U 585 49..60 '{ loop {} }': U
613 112..119 'loop {}': ! 586 51..58 'loop {}': !
614 117..119 '{}': () 587 56..58 '{}': ()
615 133..232 '{ ... x); }': () 588 72..171 '{ ... x); }': ()
616 139..142 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 589 78..81 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
617 139..166 'foo(&(...y)| x)': i32 590 78..105 'foo(&(...y)| x)': i32
618 143..152 '&(1, "a")': &(i32, &str) 591 82..91 '&(1, "a")': &(i32, &str)
619 144..152 '(1, "a")': (i32, &str) 592 83..91 '(1, "a")': (i32, &str)
620 145..146 '1': i32 593 84..85 '1': i32
621 148..151 '"a"': &str 594 87..90 '"a"': &str
622 154..165 '|&(x, y)| x': |&(i32, &str)| -> i32 595 93..104 '|&(x, y)| x': |&(i32, &str)| -> i32
623 155..162 '&(x, y)': &(i32, &str) 596 94..101 '&(x, y)': &(i32, &str)
624 156..162 '(x, y)': (i32, &str) 597 95..101 '(x, y)': (i32, &str)
625 157..158 'x': i32 598 96..97 'x': i32
626 160..161 'y': &str 599 99..100 'y': &str
627 164..165 'x': i32 600 103..104 'x': i32
628 203..206 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 601 142..145 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
629 203..229 'foo(&(...y)| x)': &i32 602 142..168 'foo(&(...y)| x)': &i32
630 207..216 '&(1, "a")': &(i32, &str) 603 146..155 '&(1, "a")': &(i32, &str)
631 208..216 '(1, "a")': (i32, &str) 604 147..155 '(1, "a")': (i32, &str)
632 209..210 '1': i32 605 148..149 '1': i32
633 212..215 '"a"': &str 606 151..154 '"a"': &str
634 218..228 '|(x, y)| x': |&(i32, &str)| -> &i32 607 157..167 '|(x, y)| x': |&(i32, &str)| -> &i32
635 219..225 '(x, y)': (i32, &str) 608 158..164 '(x, y)': (i32, &str)
636 220..221 'x': &i32 609 159..160 'x': &i32
637 223..224 'y': &&str 610 162..163 'y': &&str
638 227..228 'x': &i32 611 166..167 'x': &i32
639 "#]], 612 "#]],
640 ); 613 );
641} 614}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 1019e783b..1edec1615 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -884,41 +884,37 @@ fn issue_4966() {
884fn issue_6628() { 884fn issue_6628() {
885 check_infer( 885 check_infer(
886 r#" 886 r#"
887 #[lang = "fn_once"] 887//- minicore: fn
888 pub trait FnOnce<Args> { 888struct S<T>();
889 type Output; 889impl<T> S<T> {
890 } 890 fn f(&self, _t: T) {}
891 891 fn g<F: FnOnce(&T)>(&self, _f: F) {}
892 struct S<T>(); 892}
893 impl<T> S<T> { 893fn main() {
894 fn f(&self, _t: T) {} 894 let s = S();
895 fn g<F: FnOnce(&T)>(&self, _f: F) {} 895 s.g(|_x| {});
896 } 896 s.f(10);
897 fn main() { 897}
898 let s = S(); 898"#,
899 s.g(|_x| {});
900 s.f(10);
901 }
902 "#,
903 expect![[r#" 899 expect![[r#"
904 105..109 'self': &S<T> 900 40..44 'self': &S<T>
905 111..113 '_t': T 901 46..48 '_t': T
906 118..120 '{}': () 902 53..55 '{}': ()
907 146..150 'self': &S<T> 903 81..85 'self': &S<T>
908 152..154 '_f': F 904 87..89 '_f': F
909 159..161 '{}': () 905 94..96 '{}': ()
910 174..225 '{ ...10); }': () 906 109..160 '{ ...10); }': ()
911 184..185 's': S<i32> 907 119..120 's': S<i32>
912 188..189 'S': S<i32>() -> S<i32> 908 123..124 'S': S<i32>() -> S<i32>
913 188..191 'S()': S<i32> 909 123..126 'S()': S<i32>
914 197..198 's': S<i32> 910 132..133 's': S<i32>
915 197..209 's.g(|_x| {})': () 911 132..144 's.g(|_x| {})': ()
916 201..208 '|_x| {}': |&i32| -> () 912 136..143 '|_x| {}': |&i32| -> ()
917 202..204 '_x': &i32 913 137..139 '_x': &i32
918 206..208 '{}': () 914 141..143 '{}': ()
919 215..216 's': S<i32> 915 150..151 's': S<i32>
920 215..222 's.f(10)': () 916 150..157 's.f(10)': ()
921 219..221 '10': i32 917 154..156 '10': i32
922 "#]], 918 "#]],
923 ); 919 );
924} 920}
@@ -927,35 +923,33 @@ fn issue_6628() {
927fn issue_6852() { 923fn issue_6852() {
928 check_infer( 924 check_infer(
929 r#" 925 r#"
930 #[lang = "deref"] 926//- minicore: deref
931 pub trait Deref { 927use core::ops::Deref;
932 type Target;
933 }
934 928
935 struct BufWriter {} 929struct BufWriter {}
936 930
937 struct Mutex<T> {} 931struct Mutex<T> {}
938 struct MutexGuard<'a, T> {} 932struct MutexGuard<'a, T> {}
939 impl<T> Mutex<T> { 933impl<T> Mutex<T> {
940 fn lock(&self) -> MutexGuard<'_, T> {} 934 fn lock(&self) -> MutexGuard<'_, T> {}
941 } 935}
942 impl<'a, T: 'a> Deref for MutexGuard<'a, T> { 936impl<'a, T: 'a> Deref for MutexGuard<'a, T> {
943 type Target = T; 937 type Target = T;
944 } 938}
945 fn flush(&self) { 939fn flush(&self) {
946 let w: &Mutex<BufWriter>; 940 let w: &Mutex<BufWriter>;
947 *(w.lock()); 941 *(w.lock());
948 } 942}
949 "#, 943"#,
950 expect![[r#" 944 expect![[r#"
951 156..160 'self': &Mutex<T> 945 123..127 'self': &Mutex<T>
952 183..185 '{}': () 946 150..152 '{}': ()
953 267..271 'self': &{unknown} 947 234..238 'self': &{unknown}
954 273..323 '{ ...()); }': () 948 240..290 '{ ...()); }': ()
955 283..284 'w': &Mutex<BufWriter> 949 250..251 'w': &Mutex<BufWriter>
956 309..320 '*(w.lock())': BufWriter 950 276..287 '*(w.lock())': BufWriter
957 311..312 'w': &Mutex<BufWriter> 951 278..279 'w': &Mutex<BufWriter>
958 311..319 'w.lock()': MutexGuard<BufWriter> 952 278..286 'w.lock()': MutexGuard<BufWriter>
959 "#]], 953 "#]],
960 ); 954 );
961} 955}
@@ -977,37 +971,33 @@ fn param_overrides_fn() {
977fn lifetime_from_chalk_during_deref() { 971fn lifetime_from_chalk_during_deref() {
978 check_types( 972 check_types(
979 r#" 973 r#"
980 #[lang = "deref"] 974//- minicore: deref
981 pub trait Deref { 975struct Box<T: ?Sized> {}
982 type Target; 976impl<T> core::ops::Deref for Box<T> {
983 } 977 type Target = T;
984
985 struct Box<T: ?Sized> {}
986 impl<T> Deref for Box<T> {
987 type Target = T;
988 978
989 fn deref(&self) -> &Self::Target { 979 fn deref(&self) -> &Self::Target {
990 loop {} 980 loop {}
991 } 981 }
992 } 982}
993 983
994 trait Iterator { 984trait Iterator {
995 type Item; 985 type Item;
996 } 986}
997 987
998 pub struct Iter<'a, T: 'a> { 988pub struct Iter<'a, T: 'a> {
999 inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>, 989 inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
1000 } 990}
1001 991
1002 trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> { 992trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
1003 fn clone_box(&self); 993 fn clone_box(&self);
1004 } 994}
1005 995
1006 fn clone_iter<T>(s: Iter<T>) { 996fn clone_iter<T>(s: Iter<T>) {
1007 s.inner.clone_box(); 997 s.inner.clone_box();
1008 //^^^^^^^^^^^^^^^^^^^ () 998 //^^^^^^^^^^^^^^^^^^^ ()
1009 } 999}
1010 "#, 1000"#,
1011 ) 1001 )
1012} 1002}
1013 1003
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 3418ed21e..68776f3c0 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -113,7 +113,7 @@ fn type_alias_in_struct_lit() {
113fn infer_ranges() { 113fn infer_ranges() {
114 check_types( 114 check_types(
115 r#" 115 r#"
116//- /main.rs crate:main deps:core 116//- minicore: range
117fn test() { 117fn test() {
118 let a = ..; 118 let a = ..;
119 let b = 1..; 119 let b = 1..;
@@ -125,32 +125,6 @@ fn test() {
125 let t = (a, b, c, d, e, f); 125 let t = (a, b, c, d, e, f);
126 t; 126 t;
127} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>) 127} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
128
129//- /core.rs crate:core
130#[prelude_import] use prelude::*;
131mod prelude {}
132
133pub mod ops {
134 pub struct Range<Idx> {
135 pub start: Idx,
136 pub end: Idx,
137 }
138 pub struct RangeFrom<Idx> {
139 pub start: Idx,
140 }
141 struct RangeFull;
142 pub struct RangeInclusive<Idx> {
143 start: Idx,
144 end: Idx,
145 is_empty: u8,
146 }
147 pub struct RangeTo<Idx> {
148 pub end: Idx,
149 }
150 pub struct RangeToInclusive<Idx> {
151 pub end: Idx,
152 }
153}
154"#, 128"#,
155 ); 129 );
156} 130}
@@ -175,16 +149,17 @@ fn test() {
175fn infer_basics() { 149fn infer_basics() {
176 check_infer( 150 check_infer(
177 r#" 151 r#"
178 fn test(a: u32, b: isize, c: !, d: &str) { 152fn test(a: u32, b: isize, c: !, d: &str) {
179 a; 153 a;
180 b; 154 b;
181 c; 155 c;
182 d; 156 d;
183 1usize; 157 1usize;
184 1isize; 158 1isize;
185 "test"; 159 "test";
186 1.0f32; 160 1.0f32;
187 }"#, 161}
162"#,
188 expect![[r#" 163 expect![[r#"
189 8..9 'a': u32 164 8..9 'a': u32
190 16..17 'b': isize 165 16..17 'b': isize
@@ -207,15 +182,15 @@ fn infer_basics() {
207fn infer_let() { 182fn infer_let() {
208 check_infer( 183 check_infer(
209 r#" 184 r#"
210 fn test() { 185fn test() {
211 let a = 1isize; 186 let a = 1isize;
212 let b: usize = 1; 187 let b: usize = 1;
213 let c = b; 188 let c = b;
214 let d: u32; 189 let d: u32;
215 let e; 190 let e;
216 let f: i32 = e; 191 let f: i32 = e;
217 } 192}
218 "#, 193"#,
219 expect![[r#" 194 expect![[r#"
220 10..117 '{ ...= e; }': () 195 10..117 '{ ...= e; }': ()
221 20..21 'a': isize 196 20..21 'a': isize
@@ -236,17 +211,17 @@ fn infer_let() {
236fn infer_paths() { 211fn infer_paths() {
237 check_infer( 212 check_infer(
238 r#" 213 r#"
239 fn a() -> u32 { 1 } 214fn a() -> u32 { 1 }
240 215
241 mod b { 216mod b {
242 fn c() -> u32 { 1 } 217 fn c() -> u32 { 1 }
243 } 218}
244 219
245 fn test() { 220fn test() {
246 a(); 221 a();
247 b::c(); 222 b::c();
248 } 223}
249 "#, 224"#,
250 expect![[r#" 225 expect![[r#"
251 14..19 '{ 1 }': u32 226 14..19 '{ 1 }': u32
252 16..17 '1': u32 227 16..17 '1': u32
@@ -265,17 +240,17 @@ fn infer_paths() {
265fn infer_path_type() { 240fn infer_path_type() {
266 check_infer( 241 check_infer(
267 r#" 242 r#"
268 struct S; 243struct S;
269 244
270 impl S { 245impl S {
271 fn foo() -> i32 { 1 } 246 fn foo() -> i32 { 1 }
272 } 247}
273 248
274 fn test() { 249fn test() {
275 S::foo(); 250 S::foo();
276 <S>::foo(); 251 <S>::foo();
277 } 252}
278 "#, 253"#,
279 expect![[r#" 254 expect![[r#"
280 40..45 '{ 1 }': i32 255 40..45 '{ 1 }': i32
281 42..43 '1': i32 256 42..43 '1': i32
@@ -292,21 +267,21 @@ fn infer_path_type() {
292fn infer_struct() { 267fn infer_struct() {
293 check_infer( 268 check_infer(
294 r#" 269 r#"
295 struct A { 270struct A {
296 b: B, 271 b: B,
297 c: C, 272 c: C,
298 } 273}
299 struct B; 274struct B;
300 struct C(usize); 275struct C(usize);
301 276
302 fn test() { 277fn test() {
303 let c = C(1); 278 let c = C(1);
304 B; 279 B;
305 let a: A = A { b: B, c: C(1) }; 280 let a: A = A { b: B, c: C(1) };
306 a.b; 281 a.b;
307 a.c; 282 a.c;
308 } 283}
309 "#, 284"#,
310 expect![[r#" 285 expect![[r#"
311 71..153 '{ ...a.c; }': () 286 71..153 '{ ...a.c; }': ()
312 81..82 'c': C 287 81..82 'c': C
@@ -332,14 +307,15 @@ fn infer_struct() {
332fn infer_enum() { 307fn infer_enum() {
333 check_infer( 308 check_infer(
334 r#" 309 r#"
335 enum E { 310enum E {
336 V1 { field: u32 }, 311 V1 { field: u32 },
337 V2 312 V2
338 } 313}
339 fn test() { 314fn test() {
340 E::V1 { field: 1 }; 315 E::V1 { field: 1 };
341 E::V2; 316 E::V2;
342 }"#, 317}
318"#,
343 expect![[r#" 319 expect![[r#"
344 51..89 '{ ...:V2; }': () 320 51..89 '{ ...:V2; }': ()
345 57..75 'E::V1 ...d: 1 }': E 321 57..75 'E::V1 ...d: 1 }': E
@@ -353,23 +329,23 @@ fn infer_enum() {
353fn infer_union() { 329fn infer_union() {
354 check_infer( 330 check_infer(
355 r#" 331 r#"
356 union MyUnion { 332union MyUnion {
357 foo: u32, 333 foo: u32,
358 bar: f32, 334 bar: f32,
359 } 335}
360 336
361 fn test() { 337fn test() {
362 let u = MyUnion { foo: 0 }; 338 let u = MyUnion { foo: 0 };
363 unsafe { baz(u); } 339 unsafe { baz(u); }
364 let u = MyUnion { bar: 0.0 }; 340 let u = MyUnion { bar: 0.0 };
365 unsafe { baz(u); } 341 unsafe { baz(u); }
366 } 342}
367 343
368 unsafe fn baz(u: MyUnion) { 344unsafe fn baz(u: MyUnion) {
369 let inner = u.foo; 345 let inner = u.foo;
370 let inner = u.bar; 346 let inner = u.bar;
371 } 347}
372 "#, 348"#,
373 expect![[r#" 349 expect![[r#"
374 57..172 '{ ...); } }': () 350 57..172 '{ ...); } }': ()
375 67..68 'u': MyUnion 351 67..68 'u': MyUnion
@@ -404,19 +380,19 @@ fn infer_union() {
404fn infer_refs() { 380fn infer_refs() {
405 check_infer( 381 check_infer(
406 r#" 382 r#"
407 fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { 383fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
408 a; 384 a;
409 *a; 385 *a;
410 &a; 386 &a;
411 &mut a; 387 &mut a;
412 b; 388 b;
413 *b; 389 *b;
414 &b; 390 &b;
415 c; 391 c;
416 *c; 392 *c;
417 d; 393 d;
418 *d; 394 *d;
419 } 395}
420 "#, 396 "#,
421 expect![[r#" 397 expect![[r#"
422 8..9 'a': &u32 398 8..9 'a': &u32
@@ -450,11 +426,11 @@ fn infer_refs() {
450fn infer_raw_ref() { 426fn infer_raw_ref() {
451 check_infer( 427 check_infer(
452 r#" 428 r#"
453 fn test(a: i32) { 429fn test(a: i32) {
454 &raw mut a; 430 &raw mut a;
455 &raw const a; 431 &raw const a;
456 } 432}
457 "#, 433"#,
458 expect![[r#" 434 expect![[r#"
459 8..9 'a': i32 435 8..9 'a': i32
460 16..53 '{ ...t a; }': () 436 16..53 '{ ...t a; }': ()
@@ -524,26 +500,26 @@ h";
524fn infer_unary_op() { 500fn infer_unary_op() {
525 check_infer( 501 check_infer(
526 r#" 502 r#"
527 enum SomeType {} 503enum SomeType {}
528 504
529 fn test(x: SomeType) { 505fn test(x: SomeType) {
530 let b = false; 506 let b = false;
531 let c = !b; 507 let c = !b;
532 let a = 100; 508 let a = 100;
533 let d: i128 = -a; 509 let d: i128 = -a;
534 let e = -100; 510 let e = -100;
535 let f = !!!true; 511 let f = !!!true;
536 let g = !42; 512 let g = !42;
537 let h = !10u32; 513 let h = !10u32;
538 let j = !a; 514 let j = !a;
539 -3.14; 515 -3.14;
540 !3; 516 !3;
541 -x; 517 -x;
542 !x; 518 !x;
543 -"hello"; 519 -"hello";
544 !"hello"; 520 !"hello";
545 } 521}
546 "#, 522"#,
547 expect![[r#" 523 expect![[r#"
548 26..27 'x': SomeType 524 26..27 'x': SomeType
549 39..271 '{ ...lo"; }': () 525 39..271 '{ ...lo"; }': ()
@@ -594,19 +570,19 @@ fn infer_unary_op() {
594fn infer_backwards() { 570fn infer_backwards() {
595 check_infer( 571 check_infer(
596 r#" 572 r#"
597 fn takes_u32(x: u32) {} 573fn takes_u32(x: u32) {}
598 574
599 struct S { i32_field: i32 } 575struct S { i32_field: i32 }
600 576
601 fn test() -> &mut &f64 { 577fn test() -> &mut &f64 {
602 let a = unknown_function(); 578 let a = unknown_function();
603 takes_u32(a); 579 takes_u32(a);
604 let b = unknown_function(); 580 let b = unknown_function();
605 S { i32_field: b }; 581 S { i32_field: b };
606 let c = unknown_function(); 582 let c = unknown_function();
607 &mut &c 583 &mut &c
608 } 584}
609 "#, 585"#,
610 expect![[r#" 586 expect![[r#"
611 13..14 'x': u32 587 13..14 'x': u32
612 21..23 '{}': () 588 21..23 '{}': ()
@@ -636,23 +612,23 @@ fn infer_backwards() {
636fn infer_self() { 612fn infer_self() {
637 check_infer( 613 check_infer(
638 r#" 614 r#"
639 struct S; 615struct S;
640 616
641 impl S { 617impl S {
642 fn test(&self) { 618 fn test(&self) {
643 self; 619 self;
644 } 620 }
645 fn test2(self: &Self) { 621 fn test2(self: &Self) {
646 self; 622 self;
647 } 623 }
648 fn test3() -> Self { 624 fn test3() -> Self {
649 S {} 625 S {}
650 } 626 }
651 fn test4() -> Self { 627 fn test4() -> Self {
652 Self {} 628 Self {}
653 } 629 }
654 } 630}
655 "#, 631"#,
656 expect![[r#" 632 expect![[r#"
657 33..37 'self': &S 633 33..37 'self': &S
658 39..60 '{ ... }': () 634 39..60 '{ ... }': ()
@@ -672,30 +648,30 @@ fn infer_self() {
672fn infer_self_as_path() { 648fn infer_self_as_path() {
673 check_infer( 649 check_infer(
674 r#" 650 r#"
675 struct S1; 651struct S1;
676 struct S2(isize); 652struct S2(isize);
677 enum E { 653enum E {
678 V1, 654 V1,
679 V2(u32), 655 V2(u32),
680 } 656}
681 657
682 impl S1 { 658impl S1 {
683 fn test() { 659 fn test() {
684 Self; 660 Self;
685 } 661 }
686 } 662}
687 impl S2 { 663impl S2 {
688 fn test() { 664 fn test() {
689 Self(1); 665 Self(1);
690 } 666 }
691 } 667}
692 impl E { 668impl E {
693 fn test() { 669 fn test() {
694 Self::V1; 670 Self::V1;
695 Self::V2(1); 671 Self::V2(1);
696 } 672 }
697 } 673}
698 "#, 674"#,
699 expect![[r#" 675 expect![[r#"
700 86..107 '{ ... }': () 676 86..107 '{ ... }': ()
701 96..100 'Self': S1 677 96..100 'Self': S1
@@ -716,26 +692,26 @@ fn infer_self_as_path() {
716fn infer_binary_op() { 692fn infer_binary_op() {
717 check_infer( 693 check_infer(
718 r#" 694 r#"
719 fn f(x: bool) -> i32 { 695fn f(x: bool) -> i32 {
720 0i32 696 0i32
721 } 697}
722 698
723 fn test() -> bool { 699fn test() -> bool {
724 let x = a && b; 700 let x = a && b;
725 let y = true || false; 701 let y = true || false;
726 let z = x == y; 702 let z = x == y;
727 let t = x != y; 703 let t = x != y;
728 let minus_forty: isize = -40isize; 704 let minus_forty: isize = -40isize;
729 let h = minus_forty <= CONST_2; 705 let h = minus_forty <= CONST_2;
730 let c = f(z || y) + 5; 706 let c = f(z || y) + 5;
731 let d = b; 707 let d = b;
732 let g = minus_forty ^= i; 708 let g = minus_forty ^= i;
733 let ten: usize = 10; 709 let ten: usize = 10;
734 let ten_is_eleven = ten == some_num; 710 let ten_is_eleven = ten == some_num;
735 711
736 ten < 3 712 ten < 3
737 } 713}
738 "#, 714"#,
739 expect![[r#" 715 expect![[r#"
740 5..6 'x': bool 716 5..6 'x': bool
741 21..33 '{ 0i32 }': i32 717 21..33 '{ 0i32 }': i32
@@ -795,11 +771,11 @@ fn infer_binary_op() {
795fn infer_shift_op() { 771fn infer_shift_op() {
796 check_infer( 772 check_infer(
797 r#" 773 r#"
798 fn test() { 774fn test() {
799 1u32 << 5u8; 775 1u32 << 5u8;
800 1u32 >> 5u8; 776 1u32 >> 5u8;
801 } 777}
802 "#, 778"#,
803 expect![[r#" 779 expect![[r#"
804 10..47 '{ ...5u8; }': () 780 10..47 '{ ...5u8; }': ()
805 16..20 '1u32': u32 781 16..20 '1u32': u32
@@ -816,29 +792,29 @@ fn infer_shift_op() {
816fn infer_field_autoderef() { 792fn infer_field_autoderef() {
817 check_infer( 793 check_infer(
818 r#" 794 r#"
819 struct A { 795struct A {
820 b: B, 796 b: B,
821 } 797}
822 struct B; 798struct B;
823
824 fn test1(a: A) {
825 let a1 = a;
826 a1.b;
827 let a2 = &a;
828 a2.b;
829 let a3 = &mut a;
830 a3.b;
831 let a4 = &&&&&&&a;
832 a4.b;
833 let a5 = &mut &&mut &&mut a;
834 a5.b;
835 }
836 799
837 fn test2(a1: *const A, a2: *mut A) { 800fn test1(a: A) {
838 a1.b; 801 let a1 = a;
839 a2.b; 802 a1.b;
840 } 803 let a2 = &a;
841 "#, 804 a2.b;
805 let a3 = &mut a;
806 a3.b;
807 let a4 = &&&&&&&a;
808 a4.b;
809 let a5 = &mut &&mut &&mut a;
810 a5.b;
811}
812
813fn test2(a1: *const A, a2: *mut A) {
814 a1.b;
815 a2.b;
816}
817"#,
842 expect![[r#" 818 expect![[r#"
843 43..44 'a': A 819 43..44 'a': A
844 49..212 '{ ...5.b; }': () 820 49..212 '{ ...5.b; }': ()
@@ -891,58 +867,53 @@ fn infer_field_autoderef() {
891fn infer_argument_autoderef() { 867fn infer_argument_autoderef() {
892 check_infer( 868 check_infer(
893 r#" 869 r#"
894 #[lang = "deref"] 870//- minicore: deref
895 pub trait Deref { 871use core::ops::Deref;
896 type Target; 872struct A<T>(T);
897 fn deref(&self) -> &Self::Target;
898 }
899
900 struct A<T>(T);
901 873
902 impl<T> A<T> { 874impl<T> A<T> {
903 fn foo(&self) -> &T { 875 fn foo(&self) -> &T {
904 &self.0 876 &self.0
905 } 877 }
906 } 878}
907 879
908 struct B<T>(T); 880struct B<T>(T);
909 881
910 impl<T> Deref for B<T> { 882impl<T> Deref for B<T> {
911 type Target = T; 883 type Target = T;
912 fn deref(&self) -> &Self::Target { 884 fn deref(&self) -> &Self::Target {
913 &self.0 885 &self.0
914 } 886 }
915 } 887}
916 888
917 fn test() { 889fn test() {
918 let t = A::foo(&&B(B(A(42)))); 890 let t = A::foo(&&B(B(A(42))));
919 } 891}
920 "#, 892"#,
921 expect![[r#" 893 expect![[r#"
922 67..71 'self': &Self 894 66..70 'self': &A<T>
923 138..142 'self': &A<T> 895 78..101 '{ ... }': &T
924 150..173 '{ ... }': &T 896 88..95 '&self.0': &T
925 160..167 '&self.0': &T 897 89..93 'self': &A<T>
926 161..165 'self': &A<T> 898 89..95 'self.0': T
927 161..167 'self.0': T 899 182..186 'self': &B<T>
928 254..258 'self': &B<T> 900 205..228 '{ ... }': &T
929 277..300 '{ ... }': &T 901 215..222 '&self.0': &T
930 287..294 '&self.0': &T 902 216..220 'self': &B<T>
931 288..292 'self': &B<T> 903 216..222 'self.0': T
932 288..294 'self.0': T 904 242..280 '{ ...))); }': ()
933 314..352 '{ ...))); }': () 905 252..253 't': &i32
934 324..325 't': &i32 906 256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32
935 328..334 'A::foo': fn foo<i32>(&A<i32>) -> &i32 907 256..277 'A::foo...42))))': &i32
936 328..349 'A::foo...42))))': &i32 908 263..276 '&&B(B(A(42)))': &&B<B<A<i32>>>
937 335..348 '&&B(B(A(42)))': &&B<B<A<i32>>> 909 264..276 '&B(B(A(42)))': &B<B<A<i32>>>
938 336..348 '&B(B(A(42)))': &B<B<A<i32>>> 910 265..266 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
939 337..338 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> 911 265..276 'B(B(A(42)))': B<B<A<i32>>>
940 337..348 'B(B(A(42)))': B<B<A<i32>>> 912 267..268 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
941 339..340 'B': B<A<i32>>(A<i32>) -> B<A<i32>> 913 267..275 'B(A(42))': B<A<i32>>
942 339..347 'B(A(42))': B<A<i32>> 914 269..270 'A': A<i32>(i32) -> A<i32>
943 341..342 'A': A<i32>(i32) -> A<i32> 915 269..274 'A(42)': A<i32>
944 341..346 'A(42)': A<i32> 916 271..273 '42': i32
945 343..345 '42': i32
946 "#]], 917 "#]],
947 ); 918 );
948} 919}
@@ -951,62 +922,57 @@ fn infer_argument_autoderef() {
951fn infer_method_argument_autoderef() { 922fn infer_method_argument_autoderef() {
952 check_infer( 923 check_infer(
953 r#" 924 r#"
954 #[lang = "deref"] 925//- minicore: deref
955 pub trait Deref { 926use core::ops::Deref;
956 type Target; 927struct A<T>(*mut T);
957 fn deref(&self) -> &Self::Target;
958 }
959 928
960 struct A<T>(*mut T); 929impl<T> A<T> {
961 930 fn foo(&self, x: &A<T>) -> &T {
962 impl<T> A<T> { 931 &*x.0
963 fn foo(&self, x: &A<T>) -> &T { 932 }
964 &*x.0 933}
965 }
966 }
967 934
968 struct B<T>(T); 935struct B<T>(T);
969 936
970 impl<T> Deref for B<T> { 937impl<T> Deref for B<T> {
971 type Target = T; 938 type Target = T;
972 fn deref(&self) -> &Self::Target { 939 fn deref(&self) -> &Self::Target {
973 &self.0 940 &self.0
974 } 941 }
975 } 942}
976 943
977 fn test(a: A<i32>) { 944fn test(a: A<i32>) {
978 let t = A(0 as *mut _).foo(&&B(B(a))); 945 let t = A(0 as *mut _).foo(&&B(B(a)));
979 } 946}
980 "#, 947"#,
981 expect![[r#" 948 expect![[r#"
982 67..71 'self': &Self 949 71..75 'self': &A<T>
983 143..147 'self': &A<T> 950 77..78 'x': &A<T>
984 149..150 'x': &A<T> 951 93..114 '{ ... }': &T
985 165..186 '{ ... }': &T 952 103..108 '&*x.0': &T
986 175..180 '&*x.0': &T 953 104..108 '*x.0': T
987 176..180 '*x.0': T 954 105..106 'x': &A<T>
988 177..178 'x': &A<T> 955 105..108 'x.0': *mut T
989 177..180 'x.0': *mut T 956 195..199 'self': &B<T>
990 267..271 'self': &B<T> 957 218..241 '{ ... }': &T
991 290..313 '{ ... }': &T 958 228..235 '&self.0': &T
992 300..307 '&self.0': &T 959 229..233 'self': &B<T>
993 301..305 'self': &B<T> 960 229..235 'self.0': T
994 301..307 'self.0': T 961 253..254 'a': A<i32>
995 325..326 'a': A<i32> 962 264..310 '{ ...))); }': ()
996 336..382 '{ ...))); }': () 963 274..275 't': &i32
997 346..347 't': &i32 964 278..279 'A': A<i32>(*mut i32) -> A<i32>
998 350..351 'A': A<i32>(*mut i32) -> A<i32> 965 278..292 'A(0 as *mut _)': A<i32>
999 350..364 'A(0 as *mut _)': A<i32> 966 278..307 'A(0 as...B(a)))': &i32
1000 350..379 'A(0 as...B(a)))': &i32 967 280..281 '0': i32
1001 352..353 '0': i32 968 280..291 '0 as *mut _': *mut i32
1002 352..363 '0 as *mut _': *mut i32 969 297..306 '&&B(B(a))': &&B<B<A<i32>>>
1003 369..378 '&&B(B(a))': &&B<B<A<i32>>> 970 298..306 '&B(B(a))': &B<B<A<i32>>>
1004 370..378 '&B(B(a))': &B<B<A<i32>>> 971 299..300 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
1005 371..372 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> 972 299..306 'B(B(a))': B<B<A<i32>>>
1006 371..378 'B(B(a))': B<B<A<i32>>> 973 301..302 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
1007 373..374 'B': B<A<i32>>(A<i32>) -> B<A<i32>> 974 301..305 'B(a)': B<A<i32>>
1008 373..377 'B(a)': B<A<i32>> 975 303..304 'a': A<i32>
1009 375..376 'a': A<i32>
1010 "#]], 976 "#]],
1011 ); 977 );
1012} 978}
@@ -1015,15 +981,15 @@ fn infer_method_argument_autoderef() {
1015fn infer_in_elseif() { 981fn infer_in_elseif() {
1016 check_infer( 982 check_infer(
1017 r#" 983 r#"
1018 struct Foo { field: i32 } 984struct Foo { field: i32 }
1019 fn main(foo: Foo) { 985fn main(foo: Foo) {
1020 if true { 986 if true {
1021 987
1022 } else if false { 988 } else if false {
1023 foo.field 989 foo.field
1024 } 990 }
1025 } 991}
1026 "#, 992"#,
1027 expect![[r#" 993 expect![[r#"
1028 34..37 'foo': Foo 994 34..37 'foo': Foo
1029 44..108 '{ ... } }': () 995 44..108 '{ ... } }': ()
@@ -1043,28 +1009,29 @@ fn infer_in_elseif() {
1043fn infer_if_match_with_return() { 1009fn infer_if_match_with_return() {
1044 check_infer( 1010 check_infer(
1045 r#" 1011 r#"
1046 fn foo() { 1012fn foo() {
1047 let _x1 = if true { 1013 let _x1 = if true {
1048 1 1014 1
1049 } else { 1015 } else {
1050 return; 1016 return;
1051 }; 1017 };
1052 let _x2 = if true { 1018 let _x2 = if true {
1053 2 1019 2
1054 } else { 1020 } else {
1055 return 1021 return
1056 }; 1022 };
1057 let _x3 = match true { 1023 let _x3 = match true {
1058 true => 3, 1024 true => 3,
1059 _ => { 1025 _ => {
1060 return; 1026 return;
1061 } 1027 }
1062 }; 1028 };
1063 let _x4 = match true { 1029 let _x4 = match true {
1064 true => 4, 1030 true => 4,
1065 _ => return 1031 _ => return
1066 }; 1032 };
1067 }"#, 1033}
1034"#,
1068 expect![[r#" 1035 expect![[r#"
1069 9..322 '{ ... }; }': () 1036 9..322 '{ ... }; }': ()
1070 19..22 '_x1': i32 1037 19..22 '_x1': i32
@@ -2639,11 +2606,8 @@ fn f() {
2639fn infer_boxed_self_receiver() { 2606fn infer_boxed_self_receiver() {
2640 check_infer( 2607 check_infer(
2641 r#" 2608 r#"
2642#[lang = "deref"] 2609//- minicore: deref
2643pub trait Deref { 2610use core::ops::Deref;
2644 type Target;
2645 fn deref(&self) -> &Self::Target;
2646}
2647 2611
2648struct Box<T>(T); 2612struct Box<T>(T);
2649 2613
@@ -2675,40 +2639,39 @@ fn main() {
2675} 2639}
2676 "#, 2640 "#,
2677 expect![[r#" 2641 expect![[r#"
2678 67..71 'self': &Self 2642 104..108 'self': &Box<T>
2679 175..179 'self': &Box<T> 2643 188..192 'self': &Box<Foo<T>>
2680 259..263 'self': &Box<Foo<T>> 2644 218..220 '{}': ()
2681 289..291 '{}': () 2645 242..246 'self': &Box<Foo<T>>
2682 313..317 'self': &Box<Foo<T>> 2646 275..277 '{}': ()
2683 346..348 '{}': () 2647 297..301 'self': Box<Foo<T>>
2684 368..372 'self': Box<Foo<T>> 2648 322..324 '{}': ()
2685 393..395 '{}': () 2649 338..559 '{ ...r(); }': ()
2686 409..630 '{ ...r(); }': () 2650 348..353 'boxed': Box<Foo<i32>>
2687 419..424 'boxed': Box<Foo<i32>> 2651 356..359 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>>
2688 427..430 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>> 2652 356..371 'Box(Foo(0_i32))': Box<Foo<i32>>
2689 427..442 'Box(Foo(0_i32))': Box<Foo<i32>> 2653 360..363 'Foo': Foo<i32>(i32) -> Foo<i32>
2690 431..434 'Foo': Foo<i32>(i32) -> Foo<i32> 2654 360..370 'Foo(0_i32)': Foo<i32>
2691 431..441 'Foo(0_i32)': Foo<i32> 2655 364..369 '0_i32': i32
2692 435..440 '0_i32': i32 2656 382..386 'bad1': &i32
2693 453..457 'bad1': &i32 2657 389..394 'boxed': Box<Foo<i32>>
2694 460..465 'boxed': Box<Foo<i32>> 2658 389..406 'boxed....nner()': &i32
2695 460..477 'boxed....nner()': &i32 2659 416..421 'good1': &i32
2696 487..492 'good1': &i32 2660 424..438 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32
2697 495..509 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32 2661 424..446 'Foo::g...boxed)': &i32
2698 495..517 'Foo::g...boxed)': &i32 2662 439..445 '&boxed': &Box<Foo<i32>>
2699 510..516 '&boxed': &Box<Foo<i32>> 2663 440..445 'boxed': Box<Foo<i32>>
2700 511..516 'boxed': Box<Foo<i32>> 2664 457..461 'bad2': &Foo<i32>
2701 528..532 'bad2': &Foo<i32> 2665 464..469 'boxed': Box<Foo<i32>>
2702 535..540 'boxed': Box<Foo<i32>> 2666 464..480 'boxed....self()': &Foo<i32>
2703 535..551 'boxed....self()': &Foo<i32> 2667 490..495 'good2': &Foo<i32>
2704 561..566 'good2': &Foo<i32> 2668 498..511 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32>
2705 569..582 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32> 2669 498..519 'Foo::g...boxed)': &Foo<i32>
2706 569..590 'Foo::g...boxed)': &Foo<i32> 2670 512..518 '&boxed': &Box<Foo<i32>>
2707 583..589 '&boxed': &Box<Foo<i32>> 2671 513..518 'boxed': Box<Foo<i32>>
2708 584..589 'boxed': Box<Foo<i32>> 2672 530..535 'inner': Foo<i32>
2709 601..606 'inner': Foo<i32> 2673 538..543 'boxed': Box<Foo<i32>>
2710 609..614 'boxed': Box<Foo<i32>> 2674 538..556 'boxed....nner()': Foo<i32>
2711 609..627 'boxed....nner()': Foo<i32>
2712 "#]], 2675 "#]],
2713 ); 2676 );
2714} 2677}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 588f0d1d4..065cca74f 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -6,10 +6,10 @@ use super::{check_infer, check_infer_with_mismatches, check_types};
6fn infer_await() { 6fn infer_await() {
7 check_types( 7 check_types(
8 r#" 8 r#"
9//- /main.rs crate:main deps:core 9//- minicore: future
10struct IntFuture; 10struct IntFuture;
11 11
12impl Future for IntFuture { 12impl core::future::Future for IntFuture {
13 type Output = u64; 13 type Output = u64;
14} 14}
15 15
@@ -18,16 +18,6 @@ fn test() {
18 let v = r.await; 18 let v = r.await;
19 v; 19 v;
20} //^ u64 20} //^ u64
21
22//- /core.rs crate:core
23pub mod prelude {
24 pub mod rust_2018 {
25 #[lang = "future_trait"]
26 pub trait Future {
27 type Output;
28 }
29 }
30}
31"#, 21"#,
32 ); 22 );
33} 23}
@@ -36,25 +26,14 @@ pub mod prelude {
36fn infer_async() { 26fn infer_async() {
37 check_types( 27 check_types(
38 r#" 28 r#"
39//- /main.rs crate:main deps:core 29//- minicore: future
40async fn foo() -> u64 { 30async fn foo() -> u64 { 128 }
41 128
42}
43 31
44fn test() { 32fn test() {
45 let r = foo(); 33 let r = foo();
46 let v = r.await; 34 let v = r.await;
47 v; 35 v;
48} //^ u64 36} //^ u64
49
50//- /core.rs crate:core
51#[prelude_import] use future::*;
52mod future {
53 #[lang = "future_trait"]
54 trait Future {
55 type Output;
56 }
57}
58"#, 37"#,
59 ); 38 );
60} 39}
@@ -63,24 +42,13 @@ mod future {
63fn infer_desugar_async() { 42fn infer_desugar_async() {
64 check_types( 43 check_types(
65 r#" 44 r#"
66//- /main.rs crate:main deps:core 45//- minicore: future
67async fn foo() -> u64 { 46async fn foo() -> u64 { 128 }
68 128
69}
70 47
71fn test() { 48fn test() {
72 let r = foo(); 49 let r = foo();
73 r; 50 r;
74} //^ impl Future<Output = u64> 51} //^ impl Future<Output = u64>
75
76//- /core.rs crate:core
77#[prelude_import] use future::*;
78mod future {
79 trait Future {
80 type Output;
81 }
82}
83
84"#, 52"#,
85 ); 53 );
86} 54}
@@ -89,7 +57,7 @@ mod future {
89fn infer_async_block() { 57fn infer_async_block() {
90 check_types( 58 check_types(
91 r#" 59 r#"
92//- /main.rs crate:main deps:core 60//- minicore: future, option
93async fn test() { 61async fn test() {
94 let a = async { 42 }; 62 let a = async { 42 };
95 a; 63 a;
@@ -101,7 +69,7 @@ async fn test() {
101 b; 69 b;
102// ^ () 70// ^ ()
103 let c = async { 71 let c = async {
104 let y = Option::None; 72 let y = None;
105 y 73 y
106 // ^ Option<u64> 74 // ^ Option<u64>
107 }; 75 };
@@ -109,18 +77,6 @@ async fn test() {
109 c; 77 c;
110// ^ impl Future<Output = Option<u64>> 78// ^ impl Future<Output = Option<u64>>
111} 79}
112
113enum Option<T> { None, Some(T) }
114
115//- /core.rs crate:core
116#[prelude_import] use future::*;
117mod future {
118 #[lang = "future_trait"]
119 trait Future {
120 type Output;
121 }
122}
123
124"#, 80"#,
125 ); 81 );
126} 82}
@@ -704,14 +660,9 @@ mod ops {
704fn deref_trait() { 660fn deref_trait() {
705 check_types( 661 check_types(
706 r#" 662 r#"
707#[lang = "deref"] 663//- minicore: deref
708trait Deref {
709 type Target;
710 fn deref(&self) -> &Self::Target;
711}
712
713struct Arc<T>; 664struct Arc<T>;
714impl<T> Deref for Arc<T> { 665impl<T> core::ops::Deref for Arc<T> {
715 type Target = T; 666 type Target = T;
716} 667}
717 668
@@ -731,16 +682,10 @@ fn test(s: Arc<S>) {
731fn deref_trait_with_inference_var() { 682fn deref_trait_with_inference_var() {
732 check_types( 683 check_types(
733 r#" 684 r#"
734//- /main.rs 685//- minicore: deref
735#[lang = "deref"]
736trait Deref {
737 type Target;
738 fn deref(&self) -> &Self::Target;
739}
740
741struct Arc<T>; 686struct Arc<T>;
742fn new_arc<T>() -> Arc<T> {} 687fn new_arc<T>() -> Arc<T> {}
743impl<T> Deref for Arc<T> { 688impl<T> core::ops::Deref for Arc<T> {
744 type Target = T; 689 type Target = T;
745} 690}
746 691
@@ -761,15 +706,10 @@ fn test() {
761fn deref_trait_infinite_recursion() { 706fn deref_trait_infinite_recursion() {
762 check_types( 707 check_types(
763 r#" 708 r#"
764#[lang = "deref"] 709//- minicore: deref
765trait Deref {
766 type Target;
767 fn deref(&self) -> &Self::Target;
768}
769
770struct S; 710struct S;
771 711
772impl Deref for S { 712impl core::ops::Deref for S {
773 type Target = S; 713 type Target = S;
774} 714}
775 715
@@ -784,14 +724,9 @@ fn test(s: S) {
784fn deref_trait_with_question_mark_size() { 724fn deref_trait_with_question_mark_size() {
785 check_types( 725 check_types(
786 r#" 726 r#"
787#[lang = "deref"] 727//- minicore: deref
788trait Deref {
789 type Target;
790 fn deref(&self) -> &Self::Target;
791}
792
793struct Arc<T>; 728struct Arc<T>;
794impl<T> Deref for Arc<T> { 729impl<T: ?Sized> core::ops::Deref for Arc<T> {
795 type Target = T; 730 type Target = T;
796} 731}
797 732
@@ -1475,7 +1410,6 @@ fn test(
1475} 1410}
1476 1411
1477#[test] 1412#[test]
1478#[ignore]
1479fn error_bound_chalk() { 1413fn error_bound_chalk() {
1480 check_types( 1414 check_types(
1481 r#" 1415 r#"
@@ -1912,11 +1846,7 @@ fn test() {
1912fn closure_1() { 1846fn closure_1() {
1913 check_infer_with_mismatches( 1847 check_infer_with_mismatches(
1914 r#" 1848 r#"
1915#[lang = "fn_once"] 1849//- minicore: fn
1916trait FnOnce<Args> {
1917 type Output;
1918}
1919
1920enum Option<T> { Some(T), None } 1850enum Option<T> { Some(T), None }
1921impl<T> Option<T> { 1851impl<T> Option<T> {
1922 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} } 1852 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
@@ -1929,34 +1859,34 @@ fn test() {
1929 let y: Option<i64> = x.map(|_v| 1); 1859 let y: Option<i64> = x.map(|_v| 1);
1930}"#, 1860}"#,
1931 expect![[r#" 1861 expect![[r#"
1932 147..151 'self': Option<T> 1862 86..90 'self': Option<T>
1933 153..154 'f': F 1863 92..93 'f': F
1934 172..183 '{ loop {} }': Option<U> 1864 111..122 '{ loop {} }': Option<U>
1935 174..181 'loop {}': ! 1865 113..120 'loop {}': !
1936 179..181 '{}': () 1866 118..120 '{}': ()
1937 197..316 '{ ... 1); }': () 1867 136..255 '{ ... 1); }': ()
1938 207..208 'x': Option<u32> 1868 146..147 'x': Option<u32>
1939 211..223 'Option::Some': Some<u32>(u32) -> Option<u32> 1869 150..162 'Option::Some': Some<u32>(u32) -> Option<u32>
1940 211..229 'Option...(1u32)': Option<u32> 1870 150..168 'Option...(1u32)': Option<u32>
1941 224..228 '1u32': u32 1871 163..167 '1u32': u32
1942 235..236 'x': Option<u32> 1872 174..175 'x': Option<u32>
1943 235..251 'x.map(...v + 1)': Option<u32> 1873 174..190 'x.map(...v + 1)': Option<u32>
1944 241..250 '|v| v + 1': |u32| -> u32 1874 180..189 '|v| v + 1': |u32| -> u32
1945 242..243 'v': u32 1875 181..182 'v': u32
1946 245..246 'v': u32 1876 184..185 'v': u32
1947 245..250 'v + 1': u32 1877 184..189 'v + 1': u32
1948 249..250 '1': u32 1878 188..189 '1': u32
1949 257..258 'x': Option<u32> 1879 196..197 'x': Option<u32>
1950 257..273 'x.map(... 1u64)': Option<u64> 1880 196..212 'x.map(... 1u64)': Option<u64>
1951 263..272 '|_v| 1u64': |u32| -> u64 1881 202..211 '|_v| 1u64': |u32| -> u64
1952 264..266 '_v': u32 1882 203..205 '_v': u32
1953 268..272 '1u64': u64 1883 207..211 '1u64': u64
1954 283..284 'y': Option<i64> 1884 222..223 'y': Option<i64>
1955 300..301 'x': Option<u32> 1885 239..240 'x': Option<u32>
1956 300..313 'x.map(|_v| 1)': Option<i64> 1886 239..252 'x.map(|_v| 1)': Option<i64>
1957 306..312 '|_v| 1': |u32| -> i64 1887 245..251 '|_v| 1': |u32| -> i64
1958 307..309 '_v': u32 1888 246..248 '_v': u32
1959 311..312 '1': i64 1889 250..251 '1': i64
1960 "#]], 1890 "#]],
1961 ); 1891 );
1962} 1892}
@@ -2030,11 +1960,7 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
2030fn closure_as_argument_inference_order() { 1960fn closure_as_argument_inference_order() {
2031 check_infer_with_mismatches( 1961 check_infer_with_mismatches(
2032 r#" 1962 r#"
2033#[lang = "fn_once"] 1963//- minicore: fn
2034trait FnOnce<Args> {
2035 type Output;
2036}
2037
2038fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} } 1964fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
2039fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} } 1965fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
2040 1966
@@ -2053,62 +1979,62 @@ fn test() {
2053 let x4 = S.foo2(|s| s.method(), S); 1979 let x4 = S.foo2(|s| s.method(), S);
2054}"#, 1980}"#,
2055 expect![[r#" 1981 expect![[r#"
2056 94..95 'x': T 1982 33..34 'x': T
2057 100..101 'f': F 1983 39..40 'f': F
2058 111..122 '{ loop {} }': U 1984 50..61 '{ loop {} }': U
2059 113..120 'loop {}': ! 1985 52..59 'loop {}': !
2060 118..120 '{}': () 1986 57..59 '{}': ()
2061 156..157 'f': F 1987 95..96 'f': F
2062 162..163 'x': T 1988 101..102 'x': T
2063 173..184 '{ loop {} }': U 1989 112..123 '{ loop {} }': U
2064 175..182 'loop {}': ! 1990 114..121 'loop {}': !
2065 180..182 '{}': () 1991 119..121 '{}': ()
2066 219..223 'self': S 1992 158..162 'self': S
2067 271..275 'self': S 1993 210..214 'self': S
2068 277..278 'x': T 1994 216..217 'x': T
2069 283..284 'f': F 1995 222..223 'f': F
2070 294..305 '{ loop {} }': U 1996 233..244 '{ loop {} }': U
2071 296..303 'loop {}': ! 1997 235..242 'loop {}': !
2072 301..303 '{}': () 1998 240..242 '{}': ()
2073 343..347 'self': S 1999 282..286 'self': S
2074 349..350 'f': F 2000 288..289 'f': F
2075 355..356 'x': T 2001 294..295 'x': T
2076 366..377 '{ loop {} }': U 2002 305..316 '{ loop {} }': U
2077 368..375 'loop {}': ! 2003 307..314 'loop {}': !
2078 373..375 '{}': () 2004 312..314 '{}': ()
2079 391..550 '{ ... S); }': () 2005 330..489 '{ ... S); }': ()
2080 401..403 'x1': u64 2006 340..342 'x1': u64
2081 406..410 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64 2007 345..349 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
2082 406..429 'foo1(S...hod())': u64 2008 345..368 'foo1(S...hod())': u64
2083 411..412 'S': S 2009 350..351 'S': S
2084 414..428 '|s| s.method()': |S| -> u64 2010 353..367 '|s| s.method()': |S| -> u64
2085 415..416 's': S 2011 354..355 's': S
2086 418..419 's': S 2012 357..358 's': S
2087 418..428 's.method()': u64 2013 357..367 's.method()': u64
2088 439..441 'x2': u64 2014 378..380 'x2': u64
2089 444..448 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64 2015 383..387 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
2090 444..467 'foo2(|...(), S)': u64 2016 383..406 'foo2(|...(), S)': u64
2091 449..463 '|s| s.method()': |S| -> u64 2017 388..402 '|s| s.method()': |S| -> u64
2092 450..451 's': S 2018 389..390 's': S
2093 453..454 's': S 2019 392..393 's': S
2094 453..463 's.method()': u64 2020 392..402 's.method()': u64
2095 465..466 'S': S 2021 404..405 'S': S
2096 477..479 'x3': u64 2022 416..418 'x3': u64
2097 482..483 'S': S 2023 421..422 'S': S
2098 482..507 'S.foo1...hod())': u64 2024 421..446 'S.foo1...hod())': u64
2099 489..490 'S': S 2025 428..429 'S': S
2100 492..506 '|s| s.method()': |S| -> u64 2026 431..445 '|s| s.method()': |S| -> u64
2101 493..494 's': S 2027 432..433 's': S
2102 496..497 's': S 2028 435..436 's': S
2103 496..506 's.method()': u64 2029 435..445 's.method()': u64
2104 517..519 'x4': u64 2030 456..458 'x4': u64
2105 522..523 'S': S 2031 461..462 'S': S
2106 522..547 'S.foo2...(), S)': u64 2032 461..486 'S.foo2...(), S)': u64
2107 529..543 '|s| s.method()': |S| -> u64 2033 468..482 '|s| s.method()': |S| -> u64
2108 530..531 's': S 2034 469..470 's': S
2109 533..534 's': S 2035 472..473 's': S
2110 533..543 's.method()': u64 2036 472..482 's.method()': u64
2111 545..546 'S': S 2037 484..485 'S': S
2112 "#]], 2038 "#]],
2113 ); 2039 );
2114} 2040}
@@ -2117,11 +2043,7 @@ fn test() {
2117fn fn_item_fn_trait() { 2043fn fn_item_fn_trait() {
2118 check_types( 2044 check_types(
2119 r#" 2045 r#"
2120#[lang = "fn_once"] 2046//- minicore: fn
2121trait FnOnce<Args> {
2122 type Output;
2123}
2124
2125struct S; 2047struct S;
2126 2048
2127fn foo() -> S {} 2049fn foo() -> S {}
@@ -2560,12 +2482,7 @@ fn test() -> impl Trait<i32> {
2560fn assoc_types_from_bounds() { 2482fn assoc_types_from_bounds() {
2561 check_infer( 2483 check_infer(
2562 r#" 2484 r#"
2563//- /main.rs 2485//- minicore: fn
2564#[lang = "fn_once"]
2565trait FnOnce<Args> {
2566 type Output;
2567}
2568
2569trait T { 2486trait T {
2570 type O; 2487 type O;
2571} 2488}
@@ -2584,15 +2501,15 @@ fn main() {
2584 f::<(), _>(|z| { z; }); 2501 f::<(), _>(|z| { z; });
2585}"#, 2502}"#,
2586 expect![[r#" 2503 expect![[r#"
2587 133..135 '_v': F 2504 72..74 '_v': F
2588 178..181 '{ }': () 2505 117..120 '{ }': ()
2589 193..224 '{ ... }); }': () 2506 132..163 '{ ... }); }': ()
2590 199..209 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) 2507 138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ())
2591 199..221 'f::<()... z; })': () 2508 138..160 'f::<()... z; })': ()
2592 210..220 '|z| { z; }': |&()| -> () 2509 149..159 '|z| { z; }': |&()| -> ()
2593 211..212 'z': &() 2510 150..151 'z': &()
2594 214..220 '{ z; }': () 2511 153..159 '{ z; }': ()
2595 216..217 'z': &() 2512 155..156 'z': &()
2596 "#]], 2513 "#]],
2597 ); 2514 );
2598} 2515}
@@ -2626,12 +2543,9 @@ fn test<T: Trait>() {
2626fn dyn_trait_through_chalk() { 2543fn dyn_trait_through_chalk() {
2627 check_types( 2544 check_types(
2628 r#" 2545 r#"
2546//- minicore: deref
2629struct Box<T> {} 2547struct Box<T> {}
2630#[lang = "deref"] 2548impl<T> core::ops::Deref for Box<T> {
2631trait Deref {
2632 type Target;
2633}
2634impl<T> Deref for Box<T> {
2635 type Target = T; 2549 type Target = T;
2636} 2550}
2637trait Trait { 2551trait Trait {
@@ -2668,17 +2582,7 @@ fn test() {
2668fn iterator_chain() { 2582fn iterator_chain() {
2669 check_infer_with_mismatches( 2583 check_infer_with_mismatches(
2670 r#" 2584 r#"
2671//- /main.rs 2585//- minicore: fn, option
2672#[lang = "fn_once"]
2673trait FnOnce<Args> {
2674 type Output;
2675}
2676#[lang = "fn_mut"]
2677trait FnMut<Args>: FnOnce<Args> { }
2678
2679enum Option<T> { Some(T), None }
2680use Option::*;
2681
2682pub trait Iterator { 2586pub trait Iterator {
2683 type Item; 2587 type Item;
2684 2588
@@ -2738,46 +2642,46 @@ fn main() {
2738 .for_each(|y| { y; }); 2642 .for_each(|y| { y; });
2739}"#, 2643}"#,
2740 expect![[r#" 2644 expect![[r#"
2741 226..230 'self': Self 2645 61..65 'self': Self
2742 232..233 'f': F 2646 67..68 'f': F
2743 317..328 '{ loop {} }': FilterMap<Self, F> 2647 152..163 '{ loop {} }': FilterMap<Self, F>
2744 319..326 'loop {}': ! 2648 154..161 'loop {}': !
2745 324..326 '{}': () 2649 159..161 '{}': ()
2746 349..353 'self': Self 2650 184..188 'self': Self
2747 355..356 'f': F 2651 190..191 'f': F
2748 405..416 '{ loop {} }': () 2652 240..251 '{ loop {} }': ()
2749 407..414 'loop {}': ! 2653 242..249 'loop {}': !
2750 412..414 '{}': () 2654 247..249 '{}': ()
2751 525..529 'self': Self 2655 360..364 'self': Self
2752 854..858 'self': I 2656 689..693 'self': I
2753 865..885 '{ ... }': I 2657 700..720 '{ ... }': I
2754 875..879 'self': I 2658 710..714 'self': I
2755 944..955 '{ loop {} }': Vec<T> 2659 779..790 '{ loop {} }': Vec<T>
2756 946..953 'loop {}': ! 2660 781..788 'loop {}': !
2757 951..953 '{}': () 2661 786..788 '{}': ()
2758 1142..1269 '{ ... }); }': () 2662 977..1104 '{ ... }); }': ()
2759 1148..1163 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> 2663 983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
2760 1148..1165 'Vec::<...:new()': Vec<i32> 2664 983..1000 'Vec::<...:new()': Vec<i32>
2761 1148..1177 'Vec::<...iter()': IntoIter<i32> 2665 983..1012 'Vec::<...iter()': IntoIter<i32>
2762 1148..1240 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>> 2666 983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>>
2763 1148..1266 'Vec::<... y; })': () 2667 983..1101 'Vec::<... y; })': ()
2764 1194..1239 '|x| if...None }': |i32| -> Option<u32> 2668 1029..1074 '|x| if...None }': |i32| -> Option<u32>
2765 1195..1196 'x': i32 2669 1030..1031 'x': i32
2766 1198..1239 'if x >...None }': Option<u32> 2670 1033..1074 'if x >...None }': Option<u32>
2767 1201..1202 'x': i32 2671 1036..1037 'x': i32
2768 1201..1206 'x > 0': bool 2672 1036..1041 'x > 0': bool
2769 1205..1206 '0': i32 2673 1040..1041 '0': i32
2770 1207..1225 '{ Some...u32) }': Option<u32> 2674 1042..1060 '{ Some...u32) }': Option<u32>
2771 1209..1213 'Some': Some<u32>(u32) -> Option<u32> 2675 1044..1048 'Some': Some<u32>(u32) -> Option<u32>
2772 1209..1223 'Some(x as u32)': Option<u32> 2676 1044..1058 'Some(x as u32)': Option<u32>
2773 1214..1215 'x': i32 2677 1049..1050 'x': i32
2774 1214..1222 'x as u32': u32 2678 1049..1057 'x as u32': u32
2775 1231..1239 '{ None }': Option<u32> 2679 1066..1074 '{ None }': Option<u32>
2776 1233..1237 'None': Option<u32> 2680 1068..1072 'None': Option<u32>
2777 1255..1265 '|y| { y; }': |u32| -> () 2681 1090..1100 '|y| { y; }': |u32| -> ()
2778 1256..1257 'y': u32 2682 1091..1092 'y': u32
2779 1259..1265 '{ y; }': () 2683 1094..1100 '{ y; }': ()
2780 1261..1262 'y': u32 2684 1096..1097 'y': u32
2781 "#]], 2685 "#]],
2782 ); 2686 );
2783} 2687}
@@ -3064,45 +2968,23 @@ fn foo() {
3064fn infer_fn_trait_arg() { 2968fn infer_fn_trait_arg() {
3065 check_infer_with_mismatches( 2969 check_infer_with_mismatches(
3066 r#" 2970 r#"
3067 //- /lib.rs deps:std 2971//- minicore: fn, option
3068 2972fn foo<F, T>(f: F) -> T
3069 #[lang = "fn_once"] 2973where
3070 pub trait FnOnce<Args> { 2974 F: Fn(Option<i32>) -> T,
3071 type Output; 2975{
3072 2976 let s = None;
3073 extern "rust-call" fn call_once(&self, args: Args) -> Self::Output; 2977 f(s)
3074 } 2978}
3075 2979"#,
3076 #[lang = "fn"]
3077 pub trait Fn<Args>:FnOnce<Args> {
3078 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
3079 }
3080
3081 enum Option<T> {
3082 None,
3083 Some(T)
3084 }
3085
3086 fn foo<F, T>(f: F) -> T
3087 where
3088 F: Fn(Option<i32>) -> T,
3089 {
3090 let s = None;
3091 f(s)
3092 }
3093 "#,
3094 expect![[r#" 2980 expect![[r#"
3095 101..105 'self': &Self 2981 13..14 'f': F
3096 107..111 'args': Args 2982 59..89 '{ ...f(s) }': T
3097 220..224 'self': &Self 2983 69..70 's': Option<i32>
3098 226..230 'args': Args 2984 73..77 'None': Option<i32>
3099 313..314 'f': F 2985 83..84 'f': F
3100 359..389 '{ ...f(s) }': T 2986 83..87 'f(s)': T
3101 369..370 's': Option<i32> 2987 85..86 's': Option<i32>
3102 373..377 'None': Option<i32>
3103 383..384 'f': F
3104 383..387 'f(s)': T
3105 385..386 's': Option<i32>
3106 "#]], 2988 "#]],
3107 ); 2989 );
3108} 2990}
@@ -3181,17 +3063,7 @@ fn foo() {
3181fn infer_dyn_fn_output() { 3063fn infer_dyn_fn_output() {
3182 check_types( 3064 check_types(
3183 r#" 3065 r#"
3184#[lang = "fn_once"] 3066//- minicore: fn
3185pub trait FnOnce<Args> {
3186 type Output;
3187 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3188}
3189
3190#[lang = "fn"]
3191pub trait Fn<Args>: FnOnce<Args> {
3192 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
3193}
3194
3195fn foo() { 3067fn foo() {
3196 let f: &dyn Fn() -> i32; 3068 let f: &dyn Fn() -> i32;
3197 f(); 3069 f();
@@ -3204,12 +3076,7 @@ fn foo() {
3204fn infer_dyn_fn_once_output() { 3076fn infer_dyn_fn_once_output() {
3205 check_types( 3077 check_types(
3206 r#" 3078 r#"
3207#[lang = "fn_once"] 3079//- minicore: fn
3208pub trait FnOnce<Args> {
3209 type Output;
3210 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3211}
3212
3213fn foo() { 3080fn foo() {
3214 let f: dyn FnOnce() -> i32; 3081 let f: dyn FnOnce() -> i32;
3215 f(); 3082 f();
@@ -3644,20 +3511,16 @@ fn main() {
3644fn fn_returning_unit() { 3511fn fn_returning_unit() {
3645 check_infer_with_mismatches( 3512 check_infer_with_mismatches(
3646 r#" 3513 r#"
3647#[lang = "fn_once"] 3514//- minicore: fn
3648trait FnOnce<Args> {
3649 type Output;
3650}
3651
3652fn test<F: FnOnce()>(f: F) { 3515fn test<F: FnOnce()>(f: F) {
3653 let _: () = f(); 3516 let _: () = f();
3654}"#, 3517}"#,
3655 expect![[r#" 3518 expect![[r#"
3656 82..83 'f': F 3519 21..22 'f': F
3657 88..112 '{ ...f(); }': () 3520 27..51 '{ ...f(); }': ()
3658 98..99 '_': () 3521 37..38 '_': ()
3659 106..107 'f': F 3522 45..46 'f': F
3660 106..109 'f()': () 3523 45..48 'f()': ()
3661 "#]], 3524 "#]],
3662 ); 3525 );
3663} 3526}
@@ -3696,16 +3559,7 @@ impl foo::Foo for u32 {
3696fn infer_async_ret_type() { 3559fn infer_async_ret_type() {
3697 check_types( 3560 check_types(
3698 r#" 3561 r#"
3699//- /main.rs crate:main deps:core 3562//- minicore: future, result
3700
3701enum Result<T, E> {
3702 Ok(T),
3703 Err(E),
3704}
3705
3706use Result::*;
3707
3708
3709struct Fooey; 3563struct Fooey;
3710 3564
3711impl Fooey { 3565impl Fooey {
@@ -3728,13 +3582,71 @@ async fn get_accounts() -> Result<u32, ()> {
3728 // ^ u32 3582 // ^ u32
3729 Ok(ret) 3583 Ok(ret)
3730} 3584}
3585"#,
3586 );
3587}
3731 3588
3732//- /core.rs crate:core 3589#[test]
3733#[prelude_import] use future::*; 3590fn local_impl_1() {
3734mod future { 3591 check_types(
3735 #[lang = "future_trait"] 3592 r#"
3736 trait Future { 3593trait Trait<T> {
3737 type Output; 3594 fn foo(&self) -> T;
3595}
3596
3597fn test() {
3598 struct S;
3599 impl Trait<u32> for S {
3600 fn foo(&self) { 0 }
3601 }
3602
3603 S.foo();
3604 // ^^^^^^^ u32
3605}
3606"#,
3607 );
3608}
3609
3610#[test]
3611fn local_impl_2() {
3612 check_types(
3613 r#"
3614struct S;
3615
3616fn test() {
3617 trait Trait<T> {
3618 fn foo(&self) -> T;
3619 }
3620 impl Trait<u32> for S {
3621 fn foo(&self) { 0 }
3622 }
3623
3624 S.foo();
3625 // ^^^^^^^ u32
3626}
3627"#,
3628 );
3629}
3630
3631#[test]
3632fn local_impl_3() {
3633 check_types(
3634 r#"
3635trait Trait<T> {
3636 fn foo(&self) -> T;
3637}
3638
3639fn test() {
3640 struct S1;
3641 {
3642 struct S2;
3643
3644 impl Trait<S1> for S2 {
3645 fn foo(&self) { S1 }
3646 }
3647
3648 S2.foo();
3649 // ^^^^^^^^ S1
3738 } 3650 }
3739} 3651}
3740"#, 3652"#,