diff options
Diffstat (limited to 'crates/ra_hir_ty')
29 files changed, 7927 insertions, 8688 deletions
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index d6df48db2..cdabb359f 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml | |||
@@ -3,6 +3,7 @@ edition = "2018" | |||
3 | name = "ra_hir_ty" | 3 | name = "ra_hir_ty" |
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | license = "MIT OR Apache-2.0" | ||
6 | 7 | ||
7 | [lib] | 8 | [lib] |
8 | doctest = false | 9 | doctest = false |
@@ -27,8 +28,13 @@ test_utils = { path = "../test_utils" } | |||
27 | 28 | ||
28 | scoped-tls = "1" | 29 | scoped-tls = "1" |
29 | 30 | ||
30 | chalk-solve = { version = "0.15.0" } | 31 | chalk-solve = { version = "0.18.0" } |
31 | chalk-ir = { version = "0.15.0" } | 32 | chalk-ir = { version = "0.18.0" } |
33 | chalk-recursive = { version = "0.18.0" } | ||
32 | 34 | ||
33 | [dev-dependencies] | 35 | [dev-dependencies] |
34 | insta = "0.16.0" | 36 | expect = { path = "../expect" } |
37 | |||
38 | tracing = "0.1" | ||
39 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } | ||
40 | tracing-tree = { version = "0.1.3" } | ||
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index dc06c0ee7..c773adc67 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -3,8 +3,8 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TypeParamId, | 6 | db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, |
7 | VariantId, | 7 | TypeParamId, VariantId, |
8 | }; | 8 | }; |
9 | use ra_arena::map::ArenaMap; | 9 | use ra_arena::map::ArenaMap; |
10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; | 10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; |
@@ -12,14 +12,13 @@ use ra_prof::profile; | |||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | method_resolution::{InherentImpls, TraitImpls}, | 14 | method_resolution::{InherentImpls, TraitImpls}, |
15 | traits::{chalk, AssocTyValue, Impl}, | 15 | traits::chalk, |
16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, | 16 | Binders, CallableDefId, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, |
17 | ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, | 17 | ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId, |
18 | }; | 18 | }; |
19 | use hir_expand::name::Name; | 19 | use hir_expand::name::Name; |
20 | 20 | ||
21 | #[salsa::query_group(HirDatabaseStorage)] | 21 | #[salsa::query_group(HirDatabaseStorage)] |
22 | #[salsa::requires(salsa::Database)] | ||
23 | pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | 22 | pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { |
24 | #[salsa::invoke(infer_wait)] | 23 | #[salsa::invoke(infer_wait)] |
25 | #[salsa::transparent] | 24 | #[salsa::transparent] |
@@ -46,7 +45,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
46 | fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; | 45 | fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; |
47 | 46 | ||
48 | #[salsa::invoke(crate::callable_item_sig)] | 47 | #[salsa::invoke(crate::callable_item_sig)] |
49 | fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; | 48 | fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig; |
50 | 49 | ||
51 | #[salsa::invoke(crate::lower::return_type_impl_traits)] | 50 | #[salsa::invoke(crate::lower::return_type_impl_traits)] |
52 | fn return_type_impl_traits( | 51 | fn return_type_impl_traits( |
@@ -78,17 +77,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
78 | 77 | ||
79 | // Interned IDs for Chalk integration | 78 | // Interned IDs for Chalk integration |
80 | #[salsa::interned] | 79 | #[salsa::interned] |
81 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; | 80 | fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId; |
82 | #[salsa::interned] | ||
83 | fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId; | ||
84 | #[salsa::interned] | 81 | #[salsa::interned] |
85 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; | 82 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; |
86 | #[salsa::interned] | 83 | #[salsa::interned] |
87 | fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId; | 84 | fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId; |
88 | #[salsa::interned] | 85 | #[salsa::interned] |
89 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; | 86 | fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> ClosureId; |
90 | #[salsa::interned] | ||
91 | fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; | ||
92 | 87 | ||
93 | #[salsa::invoke(chalk::associated_ty_data_query)] | 88 | #[salsa::invoke(chalk::associated_ty_data_query)] |
94 | fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>; | 89 | fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>; |
@@ -152,3 +147,13 @@ impl_intern_key!(GlobalTypeParamId); | |||
152 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
153 | pub struct InternedOpaqueTyId(salsa::InternId); | 148 | pub struct InternedOpaqueTyId(salsa::InternId); |
154 | impl_intern_key!(InternedOpaqueTyId); | 149 | impl_intern_key!(InternedOpaqueTyId); |
150 | |||
151 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
152 | pub struct ClosureId(salsa::InternId); | ||
153 | impl_intern_key!(ClosureId); | ||
154 | |||
155 | /// This exists just for Chalk, because Chalk just has a single `FnDefId` where | ||
156 | /// we have different IDs for struct and enum variant constructors. | ||
157 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
158 | pub struct InternedCallableDefId(salsa::InternId); | ||
159 | impl_intern_key!(InternedCallableDefId); | ||
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 0289911de..d3ee9cf55 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -1,13 +1,30 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | mod expr; | ||
3 | mod match_check; | ||
4 | mod unsafe_check; | ||
2 | 5 | ||
3 | use std::any::Any; | 6 | use std::any::Any; |
4 | 7 | ||
8 | use hir_def::DefWithBodyId; | ||
9 | use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | ||
5 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; | 10 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; |
11 | use ra_prof::profile; | ||
6 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; | 12 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; |
7 | use stdx::format_to; | 13 | use stdx::format_to; |
8 | 14 | ||
9 | pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path}; | 15 | use crate::db::HirDatabase; |
10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | 16 | |
17 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; | ||
18 | |||
19 | pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { | ||
20 | let _p = profile("validate_body"); | ||
21 | let infer = db.infer(owner); | ||
22 | infer.add_diagnostics(db, owner, sink); | ||
23 | let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink); | ||
24 | validator.validate_body(db); | ||
25 | let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink); | ||
26 | validator.validate_body(db); | ||
27 | } | ||
11 | 28 | ||
12 | #[derive(Debug)] | 29 | #[derive(Debug)] |
13 | pub struct NoSuchField { | 30 | pub struct NoSuchField { |
@@ -197,3 +214,265 @@ impl AstDiagnostic for MissingUnsafe { | |||
197 | ast::Expr::cast(node).unwrap() | 214 | ast::Expr::cast(node).unwrap() |
198 | } | 215 | } |
199 | } | 216 | } |
217 | |||
218 | #[derive(Debug)] | ||
219 | pub struct MismatchedArgCount { | ||
220 | pub file: HirFileId, | ||
221 | pub call_expr: AstPtr<ast::Expr>, | ||
222 | pub expected: usize, | ||
223 | pub found: usize, | ||
224 | } | ||
225 | |||
226 | impl Diagnostic for MismatchedArgCount { | ||
227 | fn message(&self) -> String { | ||
228 | let s = if self.expected == 1 { "" } else { "s" }; | ||
229 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | ||
230 | } | ||
231 | fn source(&self) -> InFile<SyntaxNodePtr> { | ||
232 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | ||
233 | } | ||
234 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
235 | self | ||
236 | } | ||
237 | } | ||
238 | |||
239 | impl AstDiagnostic for MismatchedArgCount { | ||
240 | type AST = ast::CallExpr; | ||
241 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
242 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
243 | let node = self.source().value.to_node(&root); | ||
244 | ast::CallExpr::cast(node).unwrap() | ||
245 | } | ||
246 | } | ||
247 | |||
248 | #[cfg(test)] | ||
249 | mod tests { | ||
250 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; | ||
251 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSink}; | ||
252 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | ||
253 | use ra_syntax::{TextRange, TextSize}; | ||
254 | use rustc_hash::FxHashMap; | ||
255 | |||
256 | use crate::{diagnostics::validate_body, test_db::TestDB}; | ||
257 | |||
258 | impl TestDB { | ||
259 | fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { | ||
260 | let crate_graph = self.crate_graph(); | ||
261 | for krate in crate_graph.iter() { | ||
262 | let crate_def_map = self.crate_def_map(krate); | ||
263 | |||
264 | let mut fns = Vec::new(); | ||
265 | for (module_id, _) in crate_def_map.modules.iter() { | ||
266 | for decl in crate_def_map[module_id].scope.declarations() { | ||
267 | if let ModuleDefId::FunctionId(f) = decl { | ||
268 | fns.push(f) | ||
269 | } | ||
270 | } | ||
271 | |||
272 | for impl_id in crate_def_map[module_id].scope.impls() { | ||
273 | let impl_data = self.impl_data(impl_id); | ||
274 | for item in impl_data.items.iter() { | ||
275 | if let AssocItemId::FunctionId(f) = item { | ||
276 | fns.push(*f) | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | for f in fns { | ||
283 | let mut sink = DiagnosticSink::new(&mut cb); | ||
284 | validate_body(self, f.into(), &mut sink); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | |||
290 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
291 | let db = TestDB::with_files(ra_fixture); | ||
292 | let annotations = db.extract_annotations(); | ||
293 | |||
294 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | ||
295 | db.diagnostics(|d| { | ||
296 | // FXIME: macros... | ||
297 | let file_id = d.source().file_id.original_file(&db); | ||
298 | let range = d.syntax_node(&db).text_range(); | ||
299 | let message = d.message().to_owned(); | ||
300 | actual.entry(file_id).or_default().push((range, message)); | ||
301 | }); | ||
302 | |||
303 | for (file_id, diags) in actual.iter_mut() { | ||
304 | diags.sort_by_key(|it| it.0.start()); | ||
305 | let text = db.file_text(*file_id); | ||
306 | // For multiline spans, place them on line start | ||
307 | for (range, content) in diags { | ||
308 | if text[*range].contains('\n') { | ||
309 | *range = TextRange::new(range.start(), range.start() + TextSize::from(1)); | ||
310 | *content = format!("... {}", content); | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | |||
315 | assert_eq!(annotations, actual); | ||
316 | } | ||
317 | |||
318 | #[test] | ||
319 | fn no_such_field_diagnostics() { | ||
320 | check_diagnostics( | ||
321 | r#" | ||
322 | struct S { foo: i32, bar: () } | ||
323 | impl S { | ||
324 | fn new() -> S { | ||
325 | S { | ||
326 | //^... Missing structure fields: | ||
327 | //| - bar | ||
328 | foo: 92, | ||
329 | baz: 62, | ||
330 | //^^^^^^^ no such field | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | "#, | ||
335 | ); | ||
336 | } | ||
337 | #[test] | ||
338 | fn no_such_field_with_feature_flag_diagnostics() { | ||
339 | check_diagnostics( | ||
340 | r#" | ||
341 | //- /lib.rs crate:foo cfg:feature=foo | ||
342 | struct MyStruct { | ||
343 | my_val: usize, | ||
344 | #[cfg(feature = "foo")] | ||
345 | bar: bool, | ||
346 | } | ||
347 | |||
348 | impl MyStruct { | ||
349 | #[cfg(feature = "foo")] | ||
350 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
351 | Self { my_val, bar } | ||
352 | } | ||
353 | #[cfg(not(feature = "foo"))] | ||
354 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
355 | Self { my_val } | ||
356 | } | ||
357 | } | ||
358 | "#, | ||
359 | ); | ||
360 | } | ||
361 | |||
362 | #[test] | ||
363 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
364 | check_diagnostics( | ||
365 | r#" | ||
366 | //- /lib.rs crate:foo cfg:feature=foo | ||
367 | enum Foo { | ||
368 | #[cfg(not(feature = "foo"))] | ||
369 | Buz, | ||
370 | #[cfg(feature = "foo")] | ||
371 | Bar, | ||
372 | Baz | ||
373 | } | ||
374 | |||
375 | fn test_fn(f: Foo) { | ||
376 | match f { | ||
377 | Foo::Bar => {}, | ||
378 | Foo::Baz => {}, | ||
379 | } | ||
380 | } | ||
381 | "#, | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
387 | check_diagnostics( | ||
388 | r#" | ||
389 | //- /lib.rs crate:foo cfg:feature=foo | ||
390 | struct S { | ||
391 | #[cfg(feature = "foo")] | ||
392 | foo: u32, | ||
393 | #[cfg(not(feature = "foo"))] | ||
394 | bar: u32, | ||
395 | } | ||
396 | |||
397 | impl S { | ||
398 | #[cfg(feature = "foo")] | ||
399 | fn new(foo: u32) -> Self { | ||
400 | Self { foo } | ||
401 | } | ||
402 | #[cfg(not(feature = "foo"))] | ||
403 | fn new(bar: u32) -> Self { | ||
404 | Self { bar } | ||
405 | } | ||
406 | fn new2(bar: u32) -> Self { | ||
407 | #[cfg(feature = "foo")] | ||
408 | { Self { foo: bar } } | ||
409 | #[cfg(not(feature = "foo"))] | ||
410 | { Self { bar } } | ||
411 | } | ||
412 | fn new2(val: u32) -> Self { | ||
413 | Self { | ||
414 | #[cfg(feature = "foo")] | ||
415 | foo: val, | ||
416 | #[cfg(not(feature = "foo"))] | ||
417 | bar: val, | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | "#, | ||
422 | ); | ||
423 | } | ||
424 | |||
425 | #[test] | ||
426 | fn no_such_field_with_type_macro() { | ||
427 | check_diagnostics( | ||
428 | r#" | ||
429 | macro_rules! Type { () => { u32 }; } | ||
430 | struct Foo { bar: Type![] } | ||
431 | |||
432 | impl Foo { | ||
433 | fn new() -> Self { | ||
434 | Foo { bar: 0 } | ||
435 | } | ||
436 | } | ||
437 | "#, | ||
438 | ); | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn missing_record_pat_field_diagnostic() { | ||
443 | check_diagnostics( | ||
444 | r#" | ||
445 | struct S { foo: i32, bar: () } | ||
446 | fn baz(s: S) { | ||
447 | let S { foo: _ } = s; | ||
448 | //^^^^^^^^^^ Missing structure fields: | ||
449 | // | - bar | ||
450 | } | ||
451 | "#, | ||
452 | ); | ||
453 | } | ||
454 | |||
455 | #[test] | ||
456 | fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | ||
457 | check_diagnostics( | ||
458 | r" | ||
459 | struct S { foo: i32, bar: () } | ||
460 | fn baz(s: S) -> i32 { | ||
461 | match s { | ||
462 | S { foo, .. } => foo, | ||
463 | } | ||
464 | } | ||
465 | ", | ||
466 | ) | ||
467 | } | ||
468 | |||
469 | #[test] | ||
470 | fn break_outside_of_loop() { | ||
471 | check_diagnostics( | ||
472 | r#" | ||
473 | fn foo() { break; } | ||
474 | //^^^^^ break outside of loop | ||
475 | "#, | ||
476 | ); | ||
477 | } | ||
478 | } | ||
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs index 7db928dde..fd930eab1 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/diagnostics/expr.rs | |||
@@ -2,17 +2,19 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId}; | 5 | use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId}; |
6 | use hir_expand::diagnostics::DiagnosticSink; | 6 | use hir_expand::diagnostics::DiagnosticSink; |
7 | use ra_syntax::{ast, AstPtr}; | 7 | use ra_syntax::{ast, AstPtr}; |
8 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::HirDatabase, | 11 | db::HirDatabase, |
12 | diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields}, | 12 | diagnostics::{ |
13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | ||
14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, | ||
15 | }, | ||
13 | utils::variant_data, | 16 | utils::variant_data, |
14 | ApplicationTy, InferenceResult, Ty, TypeCtor, | 17 | ApplicationTy, InferenceResult, Ty, TypeCtor, |
15 | _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | ||
16 | }; | 18 | }; |
17 | 19 | ||
18 | pub use hir_def::{ | 20 | pub use hir_def::{ |
@@ -24,26 +26,27 @@ pub use hir_def::{ | |||
24 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, | 26 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, |
25 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, | 27 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, |
26 | }, | 28 | }, |
27 | LocalFieldId, VariantId, | 29 | src::HasSource, |
30 | LocalFieldId, Lookup, VariantId, | ||
28 | }; | 31 | }; |
29 | 32 | ||
30 | pub struct ExprValidator<'a, 'b: 'a> { | 33 | pub(super) struct ExprValidator<'a, 'b: 'a> { |
31 | func: FunctionId, | 34 | owner: DefWithBodyId, |
32 | infer: Arc<InferenceResult>, | 35 | infer: Arc<InferenceResult>, |
33 | sink: &'a mut DiagnosticSink<'b>, | 36 | sink: &'a mut DiagnosticSink<'b>, |
34 | } | 37 | } |
35 | 38 | ||
36 | impl<'a, 'b> ExprValidator<'a, 'b> { | 39 | impl<'a, 'b> ExprValidator<'a, 'b> { |
37 | pub fn new( | 40 | pub(super) fn new( |
38 | func: FunctionId, | 41 | owner: DefWithBodyId, |
39 | infer: Arc<InferenceResult>, | 42 | infer: Arc<InferenceResult>, |
40 | sink: &'a mut DiagnosticSink<'b>, | 43 | sink: &'a mut DiagnosticSink<'b>, |
41 | ) -> ExprValidator<'a, 'b> { | 44 | ) -> ExprValidator<'a, 'b> { |
42 | ExprValidator { func, infer, sink } | 45 | ExprValidator { owner, infer, sink } |
43 | } | 46 | } |
44 | 47 | ||
45 | pub fn validate_body(&mut self, db: &dyn HirDatabase) { | 48 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { |
46 | let body = db.body(self.func.into()); | 49 | let body = db.body(self.owner.into()); |
47 | 50 | ||
48 | for (id, expr) in body.exprs.iter() { | 51 | for (id, expr) in body.exprs.iter() { |
49 | if let Some((variant_def, missed_fields, true)) = | 52 | if let Some((variant_def, missed_fields, true)) = |
@@ -56,8 +59,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
56 | missed_fields, | 59 | missed_fields, |
57 | ); | 60 | ); |
58 | } | 61 | } |
59 | if let Expr::Match { expr, arms } = expr { | 62 | |
60 | self.validate_match(id, *expr, arms, db, self.infer.clone()); | 63 | match expr { |
64 | Expr::Match { expr, arms } => { | ||
65 | self.validate_match(id, *expr, arms, db, self.infer.clone()); | ||
66 | } | ||
67 | Expr::Call { .. } | Expr::MethodCall { .. } => { | ||
68 | self.validate_call(db, id, expr); | ||
69 | } | ||
70 | _ => {} | ||
61 | } | 71 | } |
62 | } | 72 | } |
63 | for (id, pat) in body.pats.iter() { | 73 | for (id, pat) in body.pats.iter() { |
@@ -86,7 +96,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
86 | missed_fields: Vec<LocalFieldId>, | 96 | missed_fields: Vec<LocalFieldId>, |
87 | ) { | 97 | ) { |
88 | // XXX: only look at source_map if we do have missing fields | 98 | // XXX: only look at source_map if we do have missing fields |
89 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 99 | let (_, source_map) = db.body_with_source_map(self.owner.into()); |
90 | 100 | ||
91 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 101 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
92 | let root = source_ptr.file_syntax(db.upcast()); | 102 | let root = source_ptr.file_syntax(db.upcast()); |
@@ -115,7 +125,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
115 | missed_fields: Vec<LocalFieldId>, | 125 | missed_fields: Vec<LocalFieldId>, |
116 | ) { | 126 | ) { |
117 | // XXX: only look at source_map if we do have missing fields | 127 | // XXX: only look at source_map if we do have missing fields |
118 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 128 | let (_, source_map) = db.body_with_source_map(self.owner.into()); |
119 | 129 | ||
120 | if let Ok(source_ptr) = source_map.pat_syntax(id) { | 130 | if let Ok(source_ptr) = source_map.pat_syntax(id) { |
121 | if let Some(expr) = source_ptr.value.as_ref().left() { | 131 | if let Some(expr) = source_ptr.value.as_ref().left() { |
@@ -138,6 +148,65 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
138 | } | 148 | } |
139 | } | 149 | } |
140 | 150 | ||
151 | fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> { | ||
152 | // Check that the number of arguments matches the number of parameters. | ||
153 | |||
154 | // FIXME: Due to shortcomings in the current type system implementation, only emit this | ||
155 | // diagnostic if there are no type mismatches in the containing function. | ||
156 | if self.infer.type_mismatches.iter().next().is_some() { | ||
157 | return Some(()); | ||
158 | } | ||
159 | |||
160 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); | ||
161 | let (sig, args) = match expr { | ||
162 | Expr::Call { callee, args } => { | ||
163 | let callee = &self.infer.type_of_expr[*callee]; | ||
164 | let sig = callee.callable_sig(db)?; | ||
165 | (sig, args.clone()) | ||
166 | } | ||
167 | Expr::MethodCall { receiver, args, .. } => { | ||
168 | let mut args = args.clone(); | ||
169 | args.insert(0, *receiver); | ||
170 | |||
171 | // FIXME: note that we erase information about substs here. This | ||
172 | // is not right, but, luckily, doesn't matter as we care only | ||
173 | // about the number of params | ||
174 | let callee = self.infer.method_resolution(call_id)?; | ||
175 | let sig = db.callable_item_signature(callee.into()).value; | ||
176 | |||
177 | (sig, args) | ||
178 | } | ||
179 | _ => return None, | ||
180 | }; | ||
181 | |||
182 | if sig.is_varargs { | ||
183 | return None; | ||
184 | } | ||
185 | |||
186 | let params = sig.params(); | ||
187 | |||
188 | let mut param_count = params.len(); | ||
189 | let mut arg_count = args.len(); | ||
190 | |||
191 | if arg_count != param_count { | ||
192 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | ||
193 | if let Ok(source_ptr) = source_map.expr_syntax(call_id) { | ||
194 | if is_method_call { | ||
195 | param_count -= 1; | ||
196 | arg_count -= 1; | ||
197 | } | ||
198 | self.sink.push(MismatchedArgCount { | ||
199 | file: source_ptr.file_id, | ||
200 | call_expr: source_ptr.value, | ||
201 | expected: param_count, | ||
202 | found: arg_count, | ||
203 | }); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | None | ||
208 | } | ||
209 | |||
141 | fn validate_match( | 210 | fn validate_match( |
142 | &mut self, | 211 | &mut self, |
143 | id: ExprId, | 212 | id: ExprId, |
@@ -147,7 +216,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
147 | infer: Arc<InferenceResult>, | 216 | infer: Arc<InferenceResult>, |
148 | ) { | 217 | ) { |
149 | let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) = | 218 | let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) = |
150 | db.body_with_source_map(self.func.into()); | 219 | db.body_with_source_map(self.owner.into()); |
151 | 220 | ||
152 | let match_expr_ty = match infer.type_of_expr.get(match_expr) { | 221 | let match_expr_ty = match infer.type_of_expr.get(match_expr) { |
153 | Some(ty) => ty, | 222 | Some(ty) => ty, |
@@ -228,7 +297,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
228 | 297 | ||
229 | let core_result_path = path![core::result::Result]; | 298 | let core_result_path = path![core::result::Result]; |
230 | 299 | ||
231 | let resolver = self.func.resolver(db.upcast()); | 300 | let resolver = self.owner.resolver(db.upcast()); |
232 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { | 301 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { |
233 | Some(it) => it, | 302 | Some(it) => it, |
234 | _ => return, | 303 | _ => return, |
@@ -243,7 +312,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
243 | }; | 312 | }; |
244 | 313 | ||
245 | if params.len() == 2 && params[0] == mismatch.actual { | 314 | if params.len() == 2 && params[0] == mismatch.actual { |
246 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 315 | let (_, source_map) = db.body_with_source_map(self.owner.into()); |
247 | 316 | ||
248 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 317 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
249 | self.sink | 318 | self.sink |
@@ -312,3 +381,185 @@ pub fn record_pattern_missing_fields( | |||
312 | } | 381 | } |
313 | Some((variant_def, missed_fields, exhaustive)) | 382 | Some((variant_def, missed_fields, exhaustive)) |
314 | } | 383 | } |
384 | |||
385 | #[cfg(test)] | ||
386 | mod tests { | ||
387 | use crate::diagnostics::tests::check_diagnostics; | ||
388 | |||
389 | #[test] | ||
390 | fn simple_free_fn_zero() { | ||
391 | check_diagnostics( | ||
392 | r#" | ||
393 | fn zero() {} | ||
394 | fn f() { zero(1); } | ||
395 | //^^^^^^^ Expected 0 arguments, found 1 | ||
396 | "#, | ||
397 | ); | ||
398 | |||
399 | check_diagnostics( | ||
400 | r#" | ||
401 | fn zero() {} | ||
402 | fn f() { zero(); } | ||
403 | "#, | ||
404 | ); | ||
405 | } | ||
406 | |||
407 | #[test] | ||
408 | fn simple_free_fn_one() { | ||
409 | check_diagnostics( | ||
410 | r#" | ||
411 | fn one(arg: u8) {} | ||
412 | fn f() { one(); } | ||
413 | //^^^^^ Expected 1 argument, found 0 | ||
414 | "#, | ||
415 | ); | ||
416 | |||
417 | check_diagnostics( | ||
418 | r#" | ||
419 | fn one(arg: u8) {} | ||
420 | fn f() { one(1); } | ||
421 | "#, | ||
422 | ); | ||
423 | } | ||
424 | |||
425 | #[test] | ||
426 | fn method_as_fn() { | ||
427 | check_diagnostics( | ||
428 | r#" | ||
429 | struct S; | ||
430 | impl S { fn method(&self) {} } | ||
431 | |||
432 | fn f() { | ||
433 | S::method(); | ||
434 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
435 | "#, | ||
436 | ); | ||
437 | |||
438 | check_diagnostics( | ||
439 | r#" | ||
440 | struct S; | ||
441 | impl S { fn method(&self) {} } | ||
442 | |||
443 | fn f() { | ||
444 | S::method(&S); | ||
445 | S.method(); | ||
446 | } | ||
447 | "#, | ||
448 | ); | ||
449 | } | ||
450 | |||
451 | #[test] | ||
452 | fn method_with_arg() { | ||
453 | check_diagnostics( | ||
454 | r#" | ||
455 | struct S; | ||
456 | impl S { fn method(&self, arg: u8) {} } | ||
457 | |||
458 | fn f() { | ||
459 | S.method(); | ||
460 | } //^^^^^^^^^^ Expected 1 argument, found 0 | ||
461 | "#, | ||
462 | ); | ||
463 | |||
464 | check_diagnostics( | ||
465 | r#" | ||
466 | struct S; | ||
467 | impl S { fn method(&self, arg: u8) {} } | ||
468 | |||
469 | fn f() { | ||
470 | S::method(&S, 0); | ||
471 | S.method(1); | ||
472 | } | ||
473 | "#, | ||
474 | ); | ||
475 | } | ||
476 | |||
477 | #[test] | ||
478 | fn tuple_struct() { | ||
479 | check_diagnostics( | ||
480 | r#" | ||
481 | struct Tup(u8, u16); | ||
482 | fn f() { | ||
483 | Tup(0); | ||
484 | } //^^^^^^ Expected 2 arguments, found 1 | ||
485 | "#, | ||
486 | ) | ||
487 | } | ||
488 | |||
489 | #[test] | ||
490 | fn enum_variant() { | ||
491 | check_diagnostics( | ||
492 | r#" | ||
493 | enum En { Variant(u8, u16), } | ||
494 | fn f() { | ||
495 | En::Variant(0); | ||
496 | } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1 | ||
497 | "#, | ||
498 | ) | ||
499 | } | ||
500 | |||
501 | #[test] | ||
502 | fn enum_variant_type_macro() { | ||
503 | check_diagnostics( | ||
504 | r#" | ||
505 | macro_rules! Type { | ||
506 | () => { u32 }; | ||
507 | } | ||
508 | enum Foo { | ||
509 | Bar(Type![]) | ||
510 | } | ||
511 | impl Foo { | ||
512 | fn new() { | ||
513 | Foo::Bar(0); | ||
514 | Foo::Bar(0, 1); | ||
515 | //^^^^^^^^^^^^^^ Expected 1 argument, found 2 | ||
516 | Foo::Bar(); | ||
517 | //^^^^^^^^^^ Expected 1 argument, found 0 | ||
518 | } | ||
519 | } | ||
520 | "#, | ||
521 | ); | ||
522 | } | ||
523 | |||
524 | #[test] | ||
525 | fn varargs() { | ||
526 | check_diagnostics( | ||
527 | r#" | ||
528 | extern "C" { | ||
529 | fn fixed(fixed: u8); | ||
530 | fn varargs(fixed: u8, ...); | ||
531 | fn varargs2(...); | ||
532 | } | ||
533 | |||
534 | fn f() { | ||
535 | unsafe { | ||
536 | fixed(0); | ||
537 | fixed(0, 1); | ||
538 | //^^^^^^^^^^^ Expected 1 argument, found 2 | ||
539 | varargs(0); | ||
540 | varargs(0, 1); | ||
541 | varargs2(); | ||
542 | varargs2(0); | ||
543 | varargs2(0, 1); | ||
544 | } | ||
545 | } | ||
546 | "#, | ||
547 | ) | ||
548 | } | ||
549 | |||
550 | #[test] | ||
551 | fn arg_count_lambda() { | ||
552 | check_diagnostics( | ||
553 | r#" | ||
554 | fn main() { | ||
555 | let f = |()| (); | ||
556 | f(); | ||
557 | //^^^ Expected 1 argument, found 0 | ||
558 | f(()); | ||
559 | f((), ()); | ||
560 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
561 | } | ||
562 | "#, | ||
563 | ) | ||
564 | } | ||
565 | } | ||
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs index 5495ce284..507edcb7d 100644 --- a/crates/ra_hir_ty/src/_match.rs +++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs | |||
@@ -41,9 +41,9 @@ | |||
41 | //! ```ignore | 41 | //! ```ignore |
42 | //! // x: (Option<bool>, Result<()>) | 42 | //! // x: (Option<bool>, Result<()>) |
43 | //! match x { | 43 | //! match x { |
44 | //! (Some(true), _) => {} | 44 | //! (Some(true), _) => (), |
45 | //! (None, Err(())) => {} | 45 | //! (None, Err(())) => (), |
46 | //! (None, Err(_)) => {} | 46 | //! (None, Err(_)) => (), |
47 | //! } | 47 | //! } |
48 | //! ``` | 48 | //! ``` |
49 | //! | 49 | //! |
@@ -218,15 +218,16 @@ | |||
218 | //! ``` | 218 | //! ``` |
219 | use std::sync::Arc; | 219 | use std::sync::Arc; |
220 | 220 | ||
221 | use smallvec::{smallvec, SmallVec}; | 221 | use hir_def::{ |
222 | 222 | adt::VariantData, | |
223 | use crate::{ | 223 | body::Body, |
224 | db::HirDatabase, | 224 | expr::{Expr, Literal, Pat, PatId}, |
225 | expr::{Body, Expr, Literal, Pat, PatId}, | 225 | AdtId, EnumVariantId, VariantId, |
226 | ApplicationTy, InferenceResult, Ty, TypeCtor, | ||
227 | }; | 226 | }; |
228 | use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId}; | ||
229 | use ra_arena::Idx; | 227 | use ra_arena::Idx; |
228 | use smallvec::{smallvec, SmallVec}; | ||
229 | |||
230 | use crate::{db::HirDatabase, ApplicationTy, InferenceResult, Ty, TypeCtor}; | ||
230 | 231 | ||
231 | #[derive(Debug, Clone, Copy)] | 232 | #[derive(Debug, Clone, Copy)] |
232 | /// Either a pattern from the source code being analyzed, represented as | 233 | /// Either a pattern from the source code being analyzed, represented as |
@@ -271,7 +272,7 @@ impl From<&PatId> for PatIdOrWild { | |||
271 | } | 272 | } |
272 | 273 | ||
273 | #[derive(Debug, Clone, Copy, PartialEq)] | 274 | #[derive(Debug, Clone, Copy, PartialEq)] |
274 | pub enum MatchCheckErr { | 275 | pub(super) enum MatchCheckErr { |
275 | NotImplemented, | 276 | NotImplemented, |
276 | MalformedMatchArm, | 277 | MalformedMatchArm, |
277 | /// Used when type inference cannot resolve the type of | 278 | /// Used when type inference cannot resolve the type of |
@@ -286,21 +287,21 @@ pub enum MatchCheckErr { | |||
286 | /// | 287 | /// |
287 | /// The `std::result::Result` type is used here rather than a custom enum | 288 | /// The `std::result::Result` type is used here rather than a custom enum |
288 | /// to allow the use of `?`. | 289 | /// to allow the use of `?`. |
289 | pub type MatchCheckResult<T> = Result<T, MatchCheckErr>; | 290 | pub(super) type MatchCheckResult<T> = Result<T, MatchCheckErr>; |
290 | 291 | ||
291 | #[derive(Debug)] | 292 | #[derive(Debug)] |
292 | /// A row in a Matrix. | 293 | /// A row in a Matrix. |
293 | /// | 294 | /// |
294 | /// This type is modeled from the struct of the same name in `rustc`. | 295 | /// This type is modeled from the struct of the same name in `rustc`. |
295 | pub(crate) struct PatStack(PatStackInner); | 296 | pub(super) struct PatStack(PatStackInner); |
296 | type PatStackInner = SmallVec<[PatIdOrWild; 2]>; | 297 | type PatStackInner = SmallVec<[PatIdOrWild; 2]>; |
297 | 298 | ||
298 | impl PatStack { | 299 | impl PatStack { |
299 | pub(crate) fn from_pattern(pat_id: PatId) -> PatStack { | 300 | pub(super) fn from_pattern(pat_id: PatId) -> PatStack { |
300 | Self(smallvec!(pat_id.into())) | 301 | Self(smallvec!(pat_id.into())) |
301 | } | 302 | } |
302 | 303 | ||
303 | pub(crate) fn from_wild() -> PatStack { | 304 | pub(super) fn from_wild() -> PatStack { |
304 | Self(smallvec!(PatIdOrWild::Wild)) | 305 | Self(smallvec!(PatIdOrWild::Wild)) |
305 | } | 306 | } |
306 | 307 | ||
@@ -509,14 +510,14 @@ impl PatStack { | |||
509 | /// A collection of PatStack. | 510 | /// A collection of PatStack. |
510 | /// | 511 | /// |
511 | /// This type is modeled from the struct of the same name in `rustc`. | 512 | /// This type is modeled from the struct of the same name in `rustc`. |
512 | pub(crate) struct Matrix(Vec<PatStack>); | 513 | pub(super) struct Matrix(Vec<PatStack>); |
513 | 514 | ||
514 | impl Matrix { | 515 | impl Matrix { |
515 | pub(crate) fn empty() -> Self { | 516 | pub(super) fn empty() -> Self { |
516 | Self(vec![]) | 517 | Self(vec![]) |
517 | } | 518 | } |
518 | 519 | ||
519 | pub(crate) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) { | 520 | pub(super) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) { |
520 | if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { | 521 | if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { |
521 | // Or patterns are expanded here | 522 | // Or patterns are expanded here |
522 | for pat_id in pat_ids { | 523 | for pat_id in pat_ids { |
@@ -578,16 +579,16 @@ impl Matrix { | |||
578 | /// not matched by an prior match arms. | 579 | /// not matched by an prior match arms. |
579 | /// | 580 | /// |
580 | /// We may eventually need an `Unknown` variant here. | 581 | /// We may eventually need an `Unknown` variant here. |
581 | pub enum Usefulness { | 582 | pub(super) enum Usefulness { |
582 | Useful, | 583 | Useful, |
583 | NotUseful, | 584 | NotUseful, |
584 | } | 585 | } |
585 | 586 | ||
586 | pub struct MatchCheckCtx<'a> { | 587 | pub(super) struct MatchCheckCtx<'a> { |
587 | pub match_expr: Idx<Expr>, | 588 | pub(super) match_expr: Idx<Expr>, |
588 | pub body: Arc<Body>, | 589 | pub(super) body: Arc<Body>, |
589 | pub infer: Arc<InferenceResult>, | 590 | pub(super) infer: Arc<InferenceResult>, |
590 | pub db: &'a dyn HirDatabase, | 591 | pub(super) db: &'a dyn HirDatabase, |
591 | } | 592 | } |
592 | 593 | ||
593 | /// Given a set of patterns `matrix`, and pattern to consider `v`, determines | 594 | /// Given a set of patterns `matrix`, and pattern to consider `v`, determines |
@@ -598,7 +599,7 @@ pub struct MatchCheckCtx<'a> { | |||
598 | /// expected that you have already type checked the match arms. All patterns in | 599 | /// expected that you have already type checked the match arms. All patterns in |
599 | /// matrix should be the same type as v, as well as they should all be the same | 600 | /// matrix should be the same type as v, as well as they should all be the same |
600 | /// type as the match expression. | 601 | /// type as the match expression. |
601 | pub(crate) fn is_useful( | 602 | pub(super) fn is_useful( |
602 | cx: &MatchCheckCtx, | 603 | cx: &MatchCheckCtx, |
603 | matrix: &Matrix, | 604 | matrix: &Matrix, |
604 | v: &PatStack, | 605 | v: &PatStack, |
@@ -836,685 +837,251 @@ fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: Enum | |||
836 | 837 | ||
837 | #[cfg(test)] | 838 | #[cfg(test)] |
838 | mod tests { | 839 | mod tests { |
839 | pub(super) use insta::assert_snapshot; | 840 | use crate::diagnostics::tests::check_diagnostics; |
840 | pub(super) use ra_db::fixture::WithFixture; | ||
841 | |||
842 | pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; | ||
843 | |||
844 | pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String { | ||
845 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0 | ||
846 | } | ||
847 | |||
848 | pub(super) fn check_diagnostic(ra_fixture: &str) { | ||
849 | let diagnostic_count = | ||
850 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1; | ||
851 | |||
852 | assert_eq!(1, diagnostic_count, "no diagnostic reported"); | ||
853 | } | ||
854 | |||
855 | pub(super) fn check_no_diagnostic(ra_fixture: &str) { | ||
856 | let (s, diagnostic_count) = | ||
857 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>(); | ||
858 | |||
859 | assert_eq!(0, diagnostic_count, "expected no diagnostic, found one: {}", s); | ||
860 | } | ||
861 | |||
862 | #[test] | ||
863 | fn empty_tuple_no_arms_diagnostic_message() { | ||
864 | assert_snapshot!( | ||
865 | check_diagnostic_message(r" | ||
866 | fn test_fn() { | ||
867 | match () { | ||
868 | } | ||
869 | } | ||
870 | "), | ||
871 | @"\"()\": Missing match arm\n" | ||
872 | ); | ||
873 | } | ||
874 | |||
875 | #[test] | ||
876 | fn empty_tuple_no_arms() { | ||
877 | check_diagnostic( | ||
878 | r" | ||
879 | fn test_fn() { | ||
880 | match () { | ||
881 | } | ||
882 | } | ||
883 | ", | ||
884 | ); | ||
885 | } | ||
886 | |||
887 | #[test] | ||
888 | fn empty_tuple_wild() { | ||
889 | check_no_diagnostic( | ||
890 | r" | ||
891 | fn test_fn() { | ||
892 | match () { | ||
893 | _ => {} | ||
894 | } | ||
895 | } | ||
896 | ", | ||
897 | ); | ||
898 | } | ||
899 | |||
900 | #[test] | ||
901 | fn empty_tuple_no_diagnostic() { | ||
902 | check_no_diagnostic( | ||
903 | r" | ||
904 | fn test_fn() { | ||
905 | match () { | ||
906 | () => {} | ||
907 | } | ||
908 | } | ||
909 | ", | ||
910 | ); | ||
911 | } | ||
912 | |||
913 | #[test] | ||
914 | fn tuple_of_empty_tuple_no_arms() { | ||
915 | check_diagnostic( | ||
916 | r" | ||
917 | fn test_fn() { | ||
918 | match (()) { | ||
919 | } | ||
920 | } | ||
921 | ", | ||
922 | ); | ||
923 | } | ||
924 | |||
925 | #[test] | ||
926 | fn tuple_of_empty_tuple_no_diagnostic() { | ||
927 | check_no_diagnostic( | ||
928 | r" | ||
929 | fn test_fn() { | ||
930 | match (()) { | ||
931 | (()) => {} | ||
932 | } | ||
933 | } | ||
934 | ", | ||
935 | ); | ||
936 | } | ||
937 | 841 | ||
938 | #[test] | 842 | #[test] |
939 | fn tuple_of_two_empty_tuple_no_arms() { | 843 | fn empty_tuple() { |
940 | check_diagnostic( | 844 | check_diagnostics( |
941 | r" | 845 | r#" |
942 | fn test_fn() { | 846 | fn main() { |
943 | match ((), ()) { | 847 | match () { } |
944 | } | 848 | //^^ Missing match arm |
945 | } | 849 | match (()) { } |
946 | ", | 850 | //^^^^ Missing match arm |
947 | ); | ||
948 | } | ||
949 | 851 | ||
950 | #[test] | 852 | match () { _ => (), } |
951 | fn tuple_of_two_empty_tuple_no_diagnostic() { | 853 | match () { () => (), } |
952 | check_no_diagnostic( | 854 | match (()) { (()) => (), } |
953 | r" | 855 | } |
954 | fn test_fn() { | 856 | "#, |
955 | match ((), ()) { | ||
956 | ((), ()) => {} | ||
957 | } | ||
958 | } | ||
959 | ", | ||
960 | ); | ||
961 | } | ||
962 | |||
963 | #[test] | ||
964 | fn bool_no_arms() { | ||
965 | check_diagnostic( | ||
966 | r" | ||
967 | fn test_fn() { | ||
968 | match false { | ||
969 | } | ||
970 | } | ||
971 | ", | ||
972 | ); | ||
973 | } | ||
974 | |||
975 | #[test] | ||
976 | fn bool_missing_arm() { | ||
977 | check_diagnostic( | ||
978 | r" | ||
979 | fn test_fn() { | ||
980 | match false { | ||
981 | true => {} | ||
982 | } | ||
983 | } | ||
984 | ", | ||
985 | ); | ||
986 | } | ||
987 | |||
988 | #[test] | ||
989 | fn bool_no_diagnostic() { | ||
990 | check_no_diagnostic( | ||
991 | r" | ||
992 | fn test_fn() { | ||
993 | match false { | ||
994 | true => {} | ||
995 | false => {} | ||
996 | } | ||
997 | } | ||
998 | ", | ||
999 | ); | ||
1000 | } | ||
1001 | |||
1002 | #[test] | ||
1003 | fn tuple_of_bools_no_arms() { | ||
1004 | check_diagnostic( | ||
1005 | r" | ||
1006 | fn test_fn() { | ||
1007 | match (false, true) { | ||
1008 | } | ||
1009 | } | ||
1010 | ", | ||
1011 | ); | ||
1012 | } | ||
1013 | |||
1014 | #[test] | ||
1015 | fn tuple_of_bools_missing_arms() { | ||
1016 | check_diagnostic( | ||
1017 | r" | ||
1018 | fn test_fn() { | ||
1019 | match (false, true) { | ||
1020 | (true, true) => {}, | ||
1021 | } | ||
1022 | } | ||
1023 | ", | ||
1024 | ); | ||
1025 | } | ||
1026 | |||
1027 | #[test] | ||
1028 | fn tuple_of_bools_missing_arm() { | ||
1029 | check_diagnostic( | ||
1030 | r" | ||
1031 | fn test_fn() { | ||
1032 | match (false, true) { | ||
1033 | (false, true) => {}, | ||
1034 | (false, false) => {}, | ||
1035 | (true, false) => {}, | ||
1036 | } | ||
1037 | } | ||
1038 | ", | ||
1039 | ); | ||
1040 | } | ||
1041 | |||
1042 | #[test] | ||
1043 | fn tuple_of_bools_with_wilds() { | ||
1044 | check_no_diagnostic( | ||
1045 | r" | ||
1046 | fn test_fn() { | ||
1047 | match (false, true) { | ||
1048 | (false, _) => {}, | ||
1049 | (true, false) => {}, | ||
1050 | (_, true) => {}, | ||
1051 | } | ||
1052 | } | ||
1053 | ", | ||
1054 | ); | 857 | ); |
1055 | } | 858 | } |
1056 | 859 | ||
1057 | #[test] | 860 | #[test] |
1058 | fn tuple_of_bools_no_diagnostic() { | 861 | fn tuple_of_two_empty_tuple() { |
1059 | check_no_diagnostic( | 862 | check_diagnostics( |
1060 | r" | 863 | r#" |
1061 | fn test_fn() { | 864 | fn main() { |
1062 | match (false, true) { | 865 | match ((), ()) { } |
1063 | (true, true) => {}, | 866 | //^^^^^^^^ Missing match arm |
1064 | (true, false) => {}, | ||
1065 | (false, true) => {}, | ||
1066 | (false, false) => {}, | ||
1067 | } | ||
1068 | } | ||
1069 | ", | ||
1070 | ); | ||
1071 | } | ||
1072 | 867 | ||
1073 | #[test] | 868 | match ((), ()) { ((), ()) => (), } |
1074 | fn tuple_of_bools_binding_missing_arms() { | 869 | } |
1075 | check_diagnostic( | 870 | "#, |
1076 | r" | 871 | ); |
1077 | fn test_fn() { | 872 | } |
1078 | match (false, true) { | 873 | |
1079 | (true, _x) => {}, | 874 | #[test] |
1080 | } | 875 | fn boolean() { |
1081 | } | 876 | check_diagnostics( |
1082 | ", | 877 | r#" |
1083 | ); | 878 | fn test_main() { |
1084 | } | 879 | match false { } |
1085 | 880 | //^^^^^ Missing match arm | |
1086 | #[test] | 881 | match false { true => (), } |
1087 | fn tuple_of_bools_binding_no_diagnostic() { | 882 | //^^^^^ Missing match arm |
1088 | check_no_diagnostic( | 883 | match (false, true) {} |
1089 | r" | 884 | //^^^^^^^^^^^^^ Missing match arm |
1090 | fn test_fn() { | 885 | match (false, true) { (true, true) => (), } |
1091 | match (false, true) { | 886 | //^^^^^^^^^^^^^ Missing match arm |
1092 | (true, _x) => {}, | 887 | match (false, true) { |
1093 | (false, true) => {}, | 888 | //^^^^^^^^^^^^^ Missing match arm |
1094 | (false, false) => {}, | 889 | (false, true) => (), |
1095 | } | 890 | (false, false) => (), |
1096 | } | 891 | (true, false) => (), |
1097 | ", | 892 | } |
893 | match (false, true) { (true, _x) => (), } | ||
894 | //^^^^^^^^^^^^^ Missing match arm | ||
895 | |||
896 | match false { true => (), false => (), } | ||
897 | match (false, true) { | ||
898 | (false, _) => (), | ||
899 | (true, false) => (), | ||
900 | (_, true) => (), | ||
901 | } | ||
902 | match (false, true) { | ||
903 | (true, true) => (), | ||
904 | (true, false) => (), | ||
905 | (false, true) => (), | ||
906 | (false, false) => (), | ||
907 | } | ||
908 | match (false, true) { | ||
909 | (true, _x) => (), | ||
910 | (false, true) => (), | ||
911 | (false, false) => (), | ||
912 | } | ||
913 | match (false, true, false) { | ||
914 | (false, ..) => (), | ||
915 | (true, ..) => (), | ||
916 | } | ||
917 | match (false, true, false) { | ||
918 | (.., false) => (), | ||
919 | (.., true) => (), | ||
920 | } | ||
921 | match (false, true, false) { (..) => (), } | ||
922 | } | ||
923 | "#, | ||
1098 | ); | 924 | ); |
1099 | } | 925 | } |
1100 | 926 | ||
1101 | #[test] | 927 | #[test] |
1102 | fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { | 928 | fn tuple_of_tuple_and_bools() { |
1103 | check_no_diagnostic( | 929 | check_diagnostics( |
1104 | r" | 930 | r#" |
1105 | fn test_fn() { | 931 | fn main() { |
1106 | match (false, true, false) { | 932 | match (false, ((), false)) {} |
1107 | (false, ..) => {}, | 933 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm |
1108 | (true, ..) => {}, | 934 | match (false, ((), false)) { (true, ((), true)) => (), } |
1109 | } | 935 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm |
1110 | } | 936 | match (false, ((), false)) { (true, _) => (), } |
1111 | ", | 937 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm |
1112 | ); | ||
1113 | } | ||
1114 | 938 | ||
1115 | #[test] | 939 | match (false, ((), false)) { |
1116 | fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { | 940 | (true, ((), true)) => (), |
1117 | check_no_diagnostic( | 941 | (true, ((), false)) => (), |
1118 | r" | 942 | (false, ((), true)) => (), |
1119 | fn test_fn() { | 943 | (false, ((), false)) => (), |
1120 | match (false, true, false) { | ||
1121 | (.., false) => {}, | ||
1122 | (.., true) => {}, | ||
1123 | } | ||
1124 | } | ||
1125 | ", | ||
1126 | ); | ||
1127 | } | 944 | } |
1128 | 945 | match (false, ((), false)) { | |
1129 | #[test] | 946 | (true, ((), true)) => (), |
1130 | fn tuple_of_bools_with_ellipsis_no_diagnostic() { | 947 | (true, ((), false)) => (), |
1131 | check_no_diagnostic( | 948 | (false, _) => (), |
1132 | r" | ||
1133 | fn test_fn() { | ||
1134 | match (false, true, false) { | ||
1135 | (..) => {}, | ||
1136 | } | ||
1137 | } | ||
1138 | ", | ||
1139 | ); | ||
1140 | } | 949 | } |
1141 | 950 | } | |
1142 | #[test] | 951 | "#, |
1143 | fn tuple_of_tuple_and_bools_no_arms() { | ||
1144 | check_diagnostic( | ||
1145 | r" | ||
1146 | fn test_fn() { | ||
1147 | match (false, ((), false)) { | ||
1148 | } | ||
1149 | } | ||
1150 | ", | ||
1151 | ); | 952 | ); |
1152 | } | 953 | } |
1153 | 954 | ||
1154 | #[test] | 955 | #[test] |
1155 | fn tuple_of_tuple_and_bools_missing_arms() { | 956 | fn enums() { |
1156 | check_diagnostic( | 957 | check_diagnostics( |
1157 | r" | 958 | r#" |
1158 | fn test_fn() { | 959 | enum Either { A, B, } |
1159 | match (false, ((), false)) { | ||
1160 | (true, ((), true)) => {}, | ||
1161 | } | ||
1162 | } | ||
1163 | ", | ||
1164 | ); | ||
1165 | } | ||
1166 | 960 | ||
1167 | #[test] | 961 | fn main() { |
1168 | fn tuple_of_tuple_and_bools_no_diagnostic() { | 962 | match Either::A { } |
1169 | check_no_diagnostic( | 963 | //^^^^^^^^^ Missing match arm |
1170 | r" | 964 | match Either::B { Either::A => (), } |
1171 | fn test_fn() { | 965 | //^^^^^^^^^ Missing match arm |
1172 | match (false, ((), false)) { | ||
1173 | (true, ((), true)) => {}, | ||
1174 | (true, ((), false)) => {}, | ||
1175 | (false, ((), true)) => {}, | ||
1176 | (false, ((), false)) => {}, | ||
1177 | } | ||
1178 | } | ||
1179 | ", | ||
1180 | ); | ||
1181 | } | ||
1182 | 966 | ||
1183 | #[test] | 967 | match &Either::B { |
1184 | fn tuple_of_tuple_and_bools_wildcard_missing_arms() { | 968 | //^^^^^^^^^^ Missing match arm |
1185 | check_diagnostic( | 969 | Either::A => (), |
1186 | r" | ||
1187 | fn test_fn() { | ||
1188 | match (false, ((), false)) { | ||
1189 | (true, _) => {}, | ||
1190 | } | ||
1191 | } | ||
1192 | ", | ||
1193 | ); | ||
1194 | } | 970 | } |
1195 | 971 | ||
1196 | #[test] | 972 | match Either::B { |
1197 | fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { | 973 | Either::A => (), Either::B => (), |
1198 | check_no_diagnostic( | ||
1199 | r" | ||
1200 | fn test_fn() { | ||
1201 | match (false, ((), false)) { | ||
1202 | (true, ((), true)) => {}, | ||
1203 | (true, ((), false)) => {}, | ||
1204 | (false, _) => {}, | ||
1205 | } | ||
1206 | } | ||
1207 | ", | ||
1208 | ); | ||
1209 | } | 974 | } |
1210 | 975 | match &Either::B { | |
1211 | #[test] | 976 | Either::A => (), Either::B => (), |
1212 | fn enum_no_arms() { | ||
1213 | check_diagnostic( | ||
1214 | r" | ||
1215 | enum Either { | ||
1216 | A, | ||
1217 | B, | ||
1218 | } | ||
1219 | fn test_fn() { | ||
1220 | match Either::A { | ||
1221 | } | ||
1222 | } | ||
1223 | ", | ||
1224 | ); | ||
1225 | } | 977 | } |
1226 | 978 | } | |
1227 | #[test] | 979 | "#, |
1228 | fn enum_missing_arms() { | ||
1229 | check_diagnostic( | ||
1230 | r" | ||
1231 | enum Either { | ||
1232 | A, | ||
1233 | B, | ||
1234 | } | ||
1235 | fn test_fn() { | ||
1236 | match Either::B { | ||
1237 | Either::A => {}, | ||
1238 | } | ||
1239 | } | ||
1240 | ", | ||
1241 | ); | 980 | ); |
1242 | } | 981 | } |
1243 | 982 | ||
1244 | #[test] | 983 | #[test] |
1245 | fn enum_no_diagnostic() { | 984 | fn enum_containing_bool() { |
1246 | check_no_diagnostic( | 985 | check_diagnostics( |
1247 | r" | 986 | r#" |
1248 | enum Either { | 987 | enum Either { A(bool), B } |
1249 | A, | ||
1250 | B, | ||
1251 | } | ||
1252 | fn test_fn() { | ||
1253 | match Either::B { | ||
1254 | Either::A => {}, | ||
1255 | Either::B => {}, | ||
1256 | } | ||
1257 | } | ||
1258 | ", | ||
1259 | ); | ||
1260 | } | ||
1261 | 988 | ||
1262 | #[test] | 989 | fn main() { |
1263 | fn enum_ref_missing_arms() { | 990 | match Either::B { } |
1264 | check_diagnostic( | 991 | //^^^^^^^^^ Missing match arm |
1265 | r" | 992 | match Either::B { |
1266 | enum Either { | 993 | //^^^^^^^^^ Missing match arm |
1267 | A, | 994 | Either::A(true) => (), Either::B => () |
1268 | B, | ||
1269 | } | ||
1270 | fn test_fn() { | ||
1271 | match &Either::B { | ||
1272 | Either::A => {}, | ||
1273 | } | ||
1274 | } | ||
1275 | ", | ||
1276 | ); | ||
1277 | } | 995 | } |
1278 | 996 | ||
1279 | #[test] | 997 | match Either::B { |
1280 | fn enum_ref_no_diagnostic() { | 998 | Either::A(true) => (), |
1281 | check_no_diagnostic( | 999 | Either::A(false) => (), |
1282 | r" | 1000 | Either::B => (), |
1283 | enum Either { | ||
1284 | A, | ||
1285 | B, | ||
1286 | } | ||
1287 | fn test_fn() { | ||
1288 | match &Either::B { | ||
1289 | Either::A => {}, | ||
1290 | Either::B => {}, | ||
1291 | } | ||
1292 | } | ||
1293 | ", | ||
1294 | ); | ||
1295 | } | 1001 | } |
1296 | 1002 | match Either::B { | |
1297 | #[test] | 1003 | Either::B => (), |
1298 | fn enum_containing_bool_no_arms() { | 1004 | _ => (), |
1299 | check_diagnostic( | ||
1300 | r" | ||
1301 | enum Either { | ||
1302 | A(bool), | ||
1303 | B, | ||
1304 | } | ||
1305 | fn test_fn() { | ||
1306 | match Either::B { | ||
1307 | } | ||
1308 | } | ||
1309 | ", | ||
1310 | ); | ||
1311 | } | 1005 | } |
1312 | 1006 | match Either::B { | |
1313 | #[test] | 1007 | Either::A(_) => (), |
1314 | fn enum_containing_bool_missing_arms() { | 1008 | Either::B => (), |
1315 | check_diagnostic( | ||
1316 | r" | ||
1317 | enum Either { | ||
1318 | A(bool), | ||
1319 | B, | ||
1320 | } | ||
1321 | fn test_fn() { | ||
1322 | match Either::B { | ||
1323 | Either::A(true) => (), | ||
1324 | Either::B => (), | ||
1325 | } | ||
1326 | } | ||
1327 | ", | ||
1328 | ); | ||
1329 | } | 1009 | } |
1330 | 1010 | ||
1331 | #[test] | 1011 | } |
1332 | fn enum_containing_bool_no_diagnostic() { | 1012 | "#, |
1333 | check_no_diagnostic( | ||
1334 | r" | ||
1335 | enum Either { | ||
1336 | A(bool), | ||
1337 | B, | ||
1338 | } | ||
1339 | fn test_fn() { | ||
1340 | match Either::B { | ||
1341 | Either::A(true) => (), | ||
1342 | Either::A(false) => (), | ||
1343 | Either::B => (), | ||
1344 | } | ||
1345 | } | ||
1346 | ", | ||
1347 | ); | 1013 | ); |
1348 | } | 1014 | } |
1349 | 1015 | ||
1350 | #[test] | 1016 | #[test] |
1351 | fn enum_containing_bool_with_wild_no_diagnostic() { | 1017 | fn enum_different_sizes() { |
1352 | check_no_diagnostic( | 1018 | check_diagnostics( |
1353 | r" | 1019 | r#" |
1354 | enum Either { | 1020 | enum Either { A(bool), B(bool, bool) } |
1355 | A(bool), | ||
1356 | B, | ||
1357 | } | ||
1358 | fn test_fn() { | ||
1359 | match Either::B { | ||
1360 | Either::B => (), | ||
1361 | _ => (), | ||
1362 | } | ||
1363 | } | ||
1364 | ", | ||
1365 | ); | ||
1366 | } | ||
1367 | 1021 | ||
1368 | #[test] | 1022 | fn main() { |
1369 | fn enum_containing_bool_with_wild_2_no_diagnostic() { | 1023 | match Either::A(false) { |
1370 | check_no_diagnostic( | 1024 | //^^^^^^^^^^^^^^^^ Missing match arm |
1371 | r" | 1025 | Either::A(_) => (), |
1372 | enum Either { | 1026 | Either::B(false, _) => (), |
1373 | A(bool), | ||
1374 | B, | ||
1375 | } | ||
1376 | fn test_fn() { | ||
1377 | match Either::B { | ||
1378 | Either::A(_) => (), | ||
1379 | Either::B => (), | ||
1380 | } | ||
1381 | } | ||
1382 | ", | ||
1383 | ); | ||
1384 | } | 1027 | } |
1385 | 1028 | ||
1386 | #[test] | 1029 | match Either::A(false) { |
1387 | fn enum_different_sizes_missing_arms() { | 1030 | Either::A(_) => (), |
1388 | check_diagnostic( | 1031 | Either::B(true, _) => (), |
1389 | r" | 1032 | Either::B(false, _) => (), |
1390 | enum Either { | ||
1391 | A(bool), | ||
1392 | B(bool, bool), | ||
1393 | } | ||
1394 | fn test_fn() { | ||
1395 | match Either::A(false) { | ||
1396 | Either::A(_) => (), | ||
1397 | Either::B(false, _) => (), | ||
1398 | } | ||
1399 | } | ||
1400 | ", | ||
1401 | ); | ||
1402 | } | 1033 | } |
1403 | 1034 | match Either::A(false) { | |
1404 | #[test] | 1035 | Either::A(true) | Either::A(false) => (), |
1405 | fn enum_different_sizes_no_diagnostic() { | 1036 | Either::B(true, _) => (), |
1406 | check_no_diagnostic( | 1037 | Either::B(false, _) => (), |
1407 | r" | ||
1408 | enum Either { | ||
1409 | A(bool), | ||
1410 | B(bool, bool), | ||
1411 | } | ||
1412 | fn test_fn() { | ||
1413 | match Either::A(false) { | ||
1414 | Either::A(_) => (), | ||
1415 | Either::B(true, _) => (), | ||
1416 | Either::B(false, _) => (), | ||
1417 | } | ||
1418 | } | ||
1419 | ", | ||
1420 | ); | ||
1421 | } | 1038 | } |
1422 | 1039 | } | |
1423 | #[test] | 1040 | "#, |
1424 | fn or_no_diagnostic() { | ||
1425 | check_no_diagnostic( | ||
1426 | r" | ||
1427 | enum Either { | ||
1428 | A(bool), | ||
1429 | B(bool, bool), | ||
1430 | } | ||
1431 | fn test_fn() { | ||
1432 | match Either::A(false) { | ||
1433 | Either::A(true) | Either::A(false) => (), | ||
1434 | Either::B(true, _) => (), | ||
1435 | Either::B(false, _) => (), | ||
1436 | } | ||
1437 | } | ||
1438 | ", | ||
1439 | ); | 1041 | ); |
1440 | } | 1042 | } |
1441 | 1043 | ||
1442 | #[test] | 1044 | #[test] |
1443 | fn tuple_of_enum_no_diagnostic() { | 1045 | fn tuple_of_enum_no_diagnostic() { |
1444 | check_no_diagnostic( | 1046 | check_diagnostics( |
1445 | r" | 1047 | r#" |
1446 | enum Either { | 1048 | enum Either { A(bool), B(bool, bool) } |
1447 | A(bool), | 1049 | enum Either2 { C, D } |
1448 | B(bool, bool), | 1050 | |
1449 | } | 1051 | fn main() { |
1450 | enum Either2 { | 1052 | match (Either::A(false), Either2::C) { |
1451 | C, | 1053 | (Either::A(true), _) | (Either::A(false), _) => (), |
1452 | D, | 1054 | (Either::B(true, _), Either2::C) => (), |
1453 | } | 1055 | (Either::B(false, _), Either2::C) => (), |
1454 | fn test_fn() { | 1056 | (Either::B(_, _), Either2::D) => (), |
1455 | match (Either::A(false), Either2::C) { | ||
1456 | (Either::A(true), _) | (Either::A(false), _) => (), | ||
1457 | (Either::B(true, _), Either2::C) => (), | ||
1458 | (Either::B(false, _), Either2::C) => (), | ||
1459 | (Either::B(_, _), Either2::D) => (), | ||
1460 | } | ||
1461 | } | ||
1462 | ", | ||
1463 | ); | ||
1464 | } | ||
1465 | |||
1466 | #[test] | ||
1467 | fn mismatched_types() { | ||
1468 | // Match statements with arms that don't match the | ||
1469 | // expression pattern do not fire this diagnostic. | ||
1470 | check_no_diagnostic( | ||
1471 | r" | ||
1472 | enum Either { | ||
1473 | A, | ||
1474 | B, | ||
1475 | } | ||
1476 | enum Either2 { | ||
1477 | C, | ||
1478 | D, | ||
1479 | } | ||
1480 | fn test_fn() { | ||
1481 | match Either::A { | ||
1482 | Either2::C => (), | ||
1483 | Either2::D => (), | ||
1484 | } | ||
1485 | } | ||
1486 | ", | ||
1487 | ); | ||
1488 | } | 1057 | } |
1489 | 1058 | } | |
1490 | #[test] | 1059 | "#, |
1491 | fn mismatched_types_with_different_arity() { | ||
1492 | // Match statements with arms that don't match the | ||
1493 | // expression pattern do not fire this diagnostic. | ||
1494 | check_no_diagnostic( | ||
1495 | r" | ||
1496 | fn test_fn() { | ||
1497 | match (true, false) { | ||
1498 | (true, false, true) => (), | ||
1499 | (true) => (), | ||
1500 | } | ||
1501 | } | ||
1502 | ", | ||
1503 | ); | 1060 | ); |
1504 | } | 1061 | } |
1505 | 1062 | ||
1506 | #[test] | 1063 | #[test] |
1507 | fn malformed_match_arm_tuple_missing_pattern() { | 1064 | fn mismatched_types() { |
1508 | // Match statements with arms that don't match the | 1065 | // Match statements with arms that don't match the |
1509 | // expression pattern do not fire this diagnostic. | 1066 | // expression pattern do not fire this diagnostic. |
1510 | check_no_diagnostic( | 1067 | check_diagnostics( |
1511 | r" | 1068 | r#" |
1512 | fn test_fn() { | 1069 | enum Either { A, B } |
1513 | match (0) { | 1070 | enum Either2 { C, D } |
1514 | () => (), | 1071 | |
1515 | } | 1072 | fn main() { |
1516 | } | 1073 | match Either::A { |
1517 | ", | 1074 | Either2::C => (), |
1075 | Either2::D => (), | ||
1076 | } | ||
1077 | match (true, false) { | ||
1078 | (true, false, true) => (), | ||
1079 | (true) => (), | ||
1080 | } | ||
1081 | match (0) { () => () } | ||
1082 | match Unresolved::Bar { Unresolved::Baz => () } | ||
1083 | } | ||
1084 | "#, | ||
1518 | ); | 1085 | ); |
1519 | } | 1086 | } |
1520 | 1087 | ||
@@ -1522,636 +1089,333 @@ mod tests { | |||
1522 | fn malformed_match_arm_tuple_enum_missing_pattern() { | 1089 | fn malformed_match_arm_tuple_enum_missing_pattern() { |
1523 | // We are testing to be sure we don't panic here when the match | 1090 | // We are testing to be sure we don't panic here when the match |
1524 | // arm `Either::B` is missing its pattern. | 1091 | // arm `Either::B` is missing its pattern. |
1525 | check_no_diagnostic( | 1092 | check_diagnostics( |
1526 | r" | 1093 | r#" |
1527 | enum Either { | 1094 | enum Either { A, B(u32) } |
1528 | A, | ||
1529 | B(u32), | ||
1530 | } | ||
1531 | fn test_fn() { | ||
1532 | match Either::A { | ||
1533 | Either::A => (), | ||
1534 | Either::B() => (), | ||
1535 | } | ||
1536 | } | ||
1537 | ", | ||
1538 | ); | ||
1539 | } | ||
1540 | 1095 | ||
1541 | #[test] | 1096 | fn main() { |
1542 | fn enum_not_in_scope() { | 1097 | match Either::A { |
1543 | // The enum is not in scope so we don't perform exhaustiveness | 1098 | Either::A => (), |
1544 | // checking, but we want to be sure we don't panic here (and | 1099 | Either::B() => (), |
1545 | // we don't create a diagnostic). | 1100 | } |
1546 | check_no_diagnostic( | 1101 | } |
1547 | r" | 1102 | "#, |
1548 | fn test_fn() { | ||
1549 | match Foo::Bar { | ||
1550 | Foo::Baz => (), | ||
1551 | } | ||
1552 | } | ||
1553 | ", | ||
1554 | ); | 1103 | ); |
1555 | } | 1104 | } |
1556 | 1105 | ||
1557 | #[test] | 1106 | #[test] |
1558 | fn expr_diverges() { | 1107 | fn expr_diverges() { |
1559 | check_no_diagnostic( | 1108 | check_diagnostics( |
1560 | r" | 1109 | r#" |
1561 | enum Either { | 1110 | enum Either { A, B } |
1562 | A, | ||
1563 | B, | ||
1564 | } | ||
1565 | fn test_fn() { | ||
1566 | match loop {} { | ||
1567 | Either::A => (), | ||
1568 | Either::B => (), | ||
1569 | } | ||
1570 | } | ||
1571 | ", | ||
1572 | ); | ||
1573 | } | ||
1574 | 1111 | ||
1575 | #[test] | 1112 | fn main() { |
1576 | fn expr_loop_with_break() { | 1113 | match loop {} { |
1577 | check_no_diagnostic( | 1114 | Either::A => (), |
1578 | r" | 1115 | Either::B => (), |
1579 | enum Either { | 1116 | } |
1580 | A, | 1117 | match loop {} { |
1581 | B, | 1118 | Either::A => (), |
1582 | } | 1119 | } |
1583 | fn test_fn() { | 1120 | match loop { break Foo::A } { |
1584 | match loop { break Foo::A } { | 1121 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm |
1585 | Either::A => (), | 1122 | Either::A => (), |
1586 | Either::B => (), | 1123 | } |
1587 | } | 1124 | match loop { break Foo::A } { |
1588 | } | 1125 | Either::A => (), |
1589 | ", | 1126 | Either::B => (), |
1127 | } | ||
1128 | } | ||
1129 | "#, | ||
1590 | ); | 1130 | ); |
1591 | } | 1131 | } |
1592 | 1132 | ||
1593 | #[test] | 1133 | #[test] |
1594 | fn expr_partially_diverges() { | 1134 | fn expr_partially_diverges() { |
1595 | check_no_diagnostic( | 1135 | check_diagnostics( |
1596 | r" | 1136 | r#" |
1597 | enum Either<T> { | 1137 | enum Either<T> { A(T), B } |
1598 | A(T), | ||
1599 | B, | ||
1600 | } | ||
1601 | fn foo() -> Either<!> { | ||
1602 | Either::B | ||
1603 | } | ||
1604 | fn test_fn() -> u32 { | ||
1605 | match foo() { | ||
1606 | Either::A(val) => val, | ||
1607 | Either::B => 0, | ||
1608 | } | ||
1609 | } | ||
1610 | ", | ||
1611 | ); | ||
1612 | } | ||
1613 | 1138 | ||
1614 | #[test] | 1139 | fn foo() -> Either<!> { Either::B } |
1615 | fn enum_record_no_arms() { | 1140 | fn main() -> u32 { |
1616 | check_diagnostic( | 1141 | match foo() { |
1617 | r" | 1142 | Either::A(val) => val, |
1618 | enum Either { | 1143 | Either::B => 0, |
1619 | A { foo: bool }, | ||
1620 | B, | ||
1621 | } | ||
1622 | fn test_fn() { | ||
1623 | let a = Either::A { foo: true }; | ||
1624 | match a { | ||
1625 | } | ||
1626 | } | ||
1627 | ", | ||
1628 | ); | ||
1629 | } | 1144 | } |
1630 | 1145 | } | |
1631 | #[test] | 1146 | "#, |
1632 | fn enum_record_missing_arms() { | ||
1633 | check_diagnostic( | ||
1634 | r" | ||
1635 | enum Either { | ||
1636 | A { foo: bool }, | ||
1637 | B, | ||
1638 | } | ||
1639 | fn test_fn() { | ||
1640 | let a = Either::A { foo: true }; | ||
1641 | match a { | ||
1642 | Either::A { foo: true } => (), | ||
1643 | } | ||
1644 | } | ||
1645 | ", | ||
1646 | ); | 1147 | ); |
1647 | } | 1148 | } |
1648 | 1149 | ||
1649 | #[test] | 1150 | #[test] |
1650 | fn enum_record_no_diagnostic() { | 1151 | fn enum_record() { |
1651 | check_no_diagnostic( | 1152 | check_diagnostics( |
1652 | r" | 1153 | r#" |
1653 | enum Either { | 1154 | enum Either { A { foo: bool }, B } |
1654 | A { foo: bool }, | ||
1655 | B, | ||
1656 | } | ||
1657 | fn test_fn() { | ||
1658 | let a = Either::A { foo: true }; | ||
1659 | match a { | ||
1660 | Either::A { foo: true } => (), | ||
1661 | Either::A { foo: false } => (), | ||
1662 | Either::B => (), | ||
1663 | } | ||
1664 | } | ||
1665 | ", | ||
1666 | ); | ||
1667 | } | ||
1668 | 1155 | ||
1669 | #[test] | 1156 | fn main() { |
1670 | fn enum_record_missing_field_no_diagnostic() { | 1157 | let a = Either::A { foo: true }; |
1671 | // When `Either::A` is missing a struct member, we don't want | 1158 | match a { } |
1672 | // to fire the missing match arm diagnostic. This should fire | 1159 | //^ Missing match arm |
1673 | // some other diagnostic. | 1160 | match a { Either::A { foo: true } => () } |
1674 | check_no_diagnostic( | 1161 | //^ Missing match arm |
1675 | r" | 1162 | match a { |
1676 | enum Either { | 1163 | Either::A { } => (), |
1677 | A { foo: bool }, | 1164 | //^^^ Missing structure fields: |
1678 | B, | 1165 | // | - foo |
1679 | } | 1166 | Either::B => (), |
1680 | fn test_fn() { | ||
1681 | let a = Either::B; | ||
1682 | match a { | ||
1683 | Either::A { } => (), | ||
1684 | Either::B => (), | ||
1685 | } | ||
1686 | } | ||
1687 | ", | ||
1688 | ); | ||
1689 | } | 1167 | } |
1168 | match a { | ||
1169 | //^ Missing match arm | ||
1170 | Either::A { } => (), | ||
1171 | } //^^^ Missing structure fields: | ||
1172 | // | - foo | ||
1690 | 1173 | ||
1691 | #[test] | 1174 | match a { |
1692 | fn enum_record_missing_field_missing_match_arm() { | 1175 | Either::A { foo: true } => (), |
1693 | // Even though `Either::A` is missing fields, we still want to fire | 1176 | Either::A { foo: false } => (), |
1694 | // the missing arm diagnostic here, since we know `Either::B` is missing. | 1177 | Either::B => (), |
1695 | check_diagnostic( | ||
1696 | r" | ||
1697 | enum Either { | ||
1698 | A { foo: bool }, | ||
1699 | B, | ||
1700 | } | ||
1701 | fn test_fn() { | ||
1702 | let a = Either::B; | ||
1703 | match a { | ||
1704 | Either::A { } => (), | ||
1705 | } | ||
1706 | } | ||
1707 | ", | ||
1708 | ); | ||
1709 | } | 1178 | } |
1710 | 1179 | match a { | |
1711 | #[test] | 1180 | Either::A { foo: _ } => (), |
1712 | fn enum_record_no_diagnostic_wild() { | 1181 | Either::B => (), |
1713 | check_no_diagnostic( | ||
1714 | r" | ||
1715 | enum Either { | ||
1716 | A { foo: bool }, | ||
1717 | B, | ||
1718 | } | ||
1719 | fn test_fn() { | ||
1720 | let a = Either::A { foo: true }; | ||
1721 | match a { | ||
1722 | Either::A { foo: _ } => (), | ||
1723 | Either::B => (), | ||
1724 | } | ||
1725 | } | ||
1726 | ", | ||
1727 | ); | ||
1728 | } | 1182 | } |
1729 | 1183 | } | |
1730 | #[test] | 1184 | "#, |
1731 | fn enum_record_fields_out_of_order_missing_arm() { | ||
1732 | check_diagnostic( | ||
1733 | r" | ||
1734 | enum Either { | ||
1735 | A { foo: bool, bar: () }, | ||
1736 | B, | ||
1737 | } | ||
1738 | fn test_fn() { | ||
1739 | let a = Either::A { foo: true }; | ||
1740 | match a { | ||
1741 | Either::A { bar: (), foo: false } => (), | ||
1742 | Either::A { foo: true, bar: () } => (), | ||
1743 | } | ||
1744 | } | ||
1745 | ", | ||
1746 | ); | 1185 | ); |
1747 | } | 1186 | } |
1748 | 1187 | ||
1749 | #[test] | 1188 | #[test] |
1750 | fn enum_record_fields_out_of_order_no_diagnostic() { | 1189 | fn enum_record_fields_out_of_order() { |
1751 | check_no_diagnostic( | 1190 | check_diagnostics( |
1752 | r" | 1191 | r#" |
1753 | enum Either { | 1192 | enum Either { |
1754 | A { foo: bool, bar: () }, | 1193 | A { foo: bool, bar: () }, |
1755 | B, | 1194 | B, |
1756 | } | 1195 | } |
1757 | fn test_fn() { | ||
1758 | let a = Either::A { foo: true }; | ||
1759 | match a { | ||
1760 | Either::A { bar: (), foo: false } => (), | ||
1761 | Either::A { foo: true, bar: () } => (), | ||
1762 | Either::B => (), | ||
1763 | } | ||
1764 | } | ||
1765 | ", | ||
1766 | ); | ||
1767 | } | ||
1768 | 1196 | ||
1769 | #[test] | 1197 | fn main() { |
1770 | fn enum_record_ellipsis_missing_arm() { | 1198 | let a = Either::A { foo: true, bar: () }; |
1771 | check_diagnostic( | 1199 | match a { |
1772 | r" | 1200 | //^ Missing match arm |
1773 | enum Either { | 1201 | Either::A { bar: (), foo: false } => (), |
1774 | A { foo: bool, bar: bool }, | 1202 | Either::A { foo: true, bar: () } => (), |
1775 | B, | ||
1776 | } | ||
1777 | fn test_fn() { | ||
1778 | match Either::B { | ||
1779 | Either::A { foo: true, .. } => (), | ||
1780 | Either::B => (), | ||
1781 | } | ||
1782 | } | ||
1783 | ", | ||
1784 | ); | ||
1785 | } | 1203 | } |
1786 | 1204 | ||
1787 | #[test] | 1205 | match a { |
1788 | fn enum_record_ellipsis_no_diagnostic() { | 1206 | Either::A { bar: (), foo: false } => (), |
1789 | check_no_diagnostic( | 1207 | Either::A { foo: true, bar: () } => (), |
1790 | r" | 1208 | Either::B => (), |
1791 | enum Either { | ||
1792 | A { foo: bool, bar: bool }, | ||
1793 | B, | ||
1794 | } | ||
1795 | fn test_fn() { | ||
1796 | let a = Either::A { foo: true }; | ||
1797 | match a { | ||
1798 | Either::A { foo: true, .. } => (), | ||
1799 | Either::A { foo: false, .. } => (), | ||
1800 | Either::B => (), | ||
1801 | } | ||
1802 | } | ||
1803 | ", | ||
1804 | ); | ||
1805 | } | 1209 | } |
1806 | 1210 | } | |
1807 | #[test] | 1211 | "#, |
1808 | fn enum_record_ellipsis_all_fields_missing_arm() { | ||
1809 | check_diagnostic( | ||
1810 | r" | ||
1811 | enum Either { | ||
1812 | A { foo: bool, bar: bool }, | ||
1813 | B, | ||
1814 | } | ||
1815 | fn test_fn() { | ||
1816 | let a = Either::B; | ||
1817 | match a { | ||
1818 | Either::A { .. } => (), | ||
1819 | } | ||
1820 | } | ||
1821 | ", | ||
1822 | ); | 1212 | ); |
1823 | } | 1213 | } |
1824 | 1214 | ||
1825 | #[test] | 1215 | #[test] |
1826 | fn enum_record_ellipsis_all_fields_no_diagnostic() { | 1216 | fn enum_record_ellipsis() { |
1827 | check_no_diagnostic( | 1217 | check_diagnostics( |
1828 | r" | 1218 | r#" |
1829 | enum Either { | 1219 | enum Either { |
1830 | A { foo: bool, bar: bool }, | 1220 | A { foo: bool, bar: bool }, |
1831 | B, | 1221 | B, |
1832 | } | 1222 | } |
1833 | fn test_fn() { | ||
1834 | let a = Either::B; | ||
1835 | match a { | ||
1836 | Either::A { .. } => (), | ||
1837 | Either::B => (), | ||
1838 | } | ||
1839 | } | ||
1840 | ", | ||
1841 | ); | ||
1842 | } | ||
1843 | 1223 | ||
1844 | #[test] | 1224 | fn main() { |
1845 | fn enum_tuple_partial_ellipsis_no_diagnostic() { | 1225 | let a = Either::B; |
1846 | check_no_diagnostic( | 1226 | match a { |
1847 | r" | 1227 | //^ Missing match arm |
1848 | enum Either { | 1228 | Either::A { foo: true, .. } => (), |
1849 | A(bool, bool, bool, bool), | 1229 | Either::B => (), |
1850 | B, | ||
1851 | } | ||
1852 | fn test_fn() { | ||
1853 | match Either::B { | ||
1854 | Either::A(true, .., true) => {}, | ||
1855 | Either::A(true, .., false) => {}, | ||
1856 | Either::A(false, .., true) => {}, | ||
1857 | Either::A(false, .., false) => {}, | ||
1858 | Either::B => {}, | ||
1859 | } | ||
1860 | } | ||
1861 | ", | ||
1862 | ); | ||
1863 | } | 1230 | } |
1864 | 1231 | match a { | |
1865 | #[test] | 1232 | //^ Missing match arm |
1866 | fn enum_tuple_partial_ellipsis_2_no_diagnostic() { | 1233 | Either::A { .. } => (), |
1867 | check_no_diagnostic( | ||
1868 | r" | ||
1869 | enum Either { | ||
1870 | A(bool, bool, bool, bool), | ||
1871 | B, | ||
1872 | } | ||
1873 | fn test_fn() { | ||
1874 | match Either::B { | ||
1875 | Either::A(true, .., true) => {}, | ||
1876 | Either::A(true, .., false) => {}, | ||
1877 | Either::A(.., true) => {}, | ||
1878 | Either::A(.., false) => {}, | ||
1879 | Either::B => {}, | ||
1880 | } | ||
1881 | } | ||
1882 | ", | ||
1883 | ); | ||
1884 | } | 1234 | } |
1885 | 1235 | ||
1886 | #[test] | 1236 | match a { |
1887 | fn enum_tuple_partial_ellipsis_missing_arm() { | 1237 | Either::A { foo: true, .. } => (), |
1888 | check_diagnostic( | 1238 | Either::A { foo: false, .. } => (), |
1889 | r" | 1239 | Either::B => (), |
1890 | enum Either { | ||
1891 | A(bool, bool, bool, bool), | ||
1892 | B, | ||
1893 | } | ||
1894 | fn test_fn() { | ||
1895 | match Either::B { | ||
1896 | Either::A(true, .., true) => {}, | ||
1897 | Either::A(true, .., false) => {}, | ||
1898 | Either::A(false, .., false) => {}, | ||
1899 | Either::B => {}, | ||
1900 | } | ||
1901 | } | ||
1902 | ", | ||
1903 | ); | ||
1904 | } | 1240 | } |
1905 | 1241 | ||
1906 | #[test] | 1242 | match a { |
1907 | fn enum_tuple_partial_ellipsis_2_missing_arm() { | 1243 | Either::A { .. } => (), |
1908 | check_diagnostic( | 1244 | Either::B => (), |
1909 | r" | ||
1910 | enum Either { | ||
1911 | A(bool, bool, bool, bool), | ||
1912 | B, | ||
1913 | } | ||
1914 | fn test_fn() { | ||
1915 | match Either::B { | ||
1916 | Either::A(true, .., true) => {}, | ||
1917 | Either::A(true, .., false) => {}, | ||
1918 | Either::A(.., true) => {}, | ||
1919 | Either::B => {}, | ||
1920 | } | ||
1921 | } | ||
1922 | ", | ||
1923 | ); | ||
1924 | } | 1245 | } |
1925 | 1246 | } | |
1926 | #[test] | 1247 | "#, |
1927 | fn enum_tuple_ellipsis_no_diagnostic() { | ||
1928 | check_no_diagnostic( | ||
1929 | r" | ||
1930 | enum Either { | ||
1931 | A(bool, bool, bool, bool), | ||
1932 | B, | ||
1933 | } | ||
1934 | fn test_fn() { | ||
1935 | match Either::B { | ||
1936 | Either::A(..) => {}, | ||
1937 | Either::B => {}, | ||
1938 | } | ||
1939 | } | ||
1940 | ", | ||
1941 | ); | 1248 | ); |
1942 | } | 1249 | } |
1943 | 1250 | ||
1944 | #[test] | 1251 | #[test] |
1945 | fn enum_never() { | 1252 | fn enum_tuple_partial_ellipsis() { |
1946 | check_no_diagnostic( | 1253 | check_diagnostics( |
1947 | r" | 1254 | r#" |
1948 | enum Never {} | 1255 | enum Either { |
1256 | A(bool, bool, bool, bool), | ||
1257 | B, | ||
1258 | } | ||
1949 | 1259 | ||
1950 | fn test_fn(never: Never) { | 1260 | fn main() { |
1951 | match never {} | 1261 | match Either::B { |
1952 | } | 1262 | //^^^^^^^^^ Missing match arm |
1953 | ", | 1263 | Either::A(true, .., true) => (), |
1954 | ); | 1264 | Either::A(true, .., false) => (), |
1265 | Either::A(false, .., false) => (), | ||
1266 | Either::B => (), | ||
1267 | } | ||
1268 | match Either::B { | ||
1269 | //^^^^^^^^^ Missing match arm | ||
1270 | Either::A(true, .., true) => (), | ||
1271 | Either::A(true, .., false) => (), | ||
1272 | Either::A(.., true) => (), | ||
1273 | Either::B => (), | ||
1274 | } | ||
1275 | |||
1276 | match Either::B { | ||
1277 | Either::A(true, .., true) => (), | ||
1278 | Either::A(true, .., false) => (), | ||
1279 | Either::A(false, .., true) => (), | ||
1280 | Either::A(false, .., false) => (), | ||
1281 | Either::B => (), | ||
1282 | } | ||
1283 | match Either::B { | ||
1284 | Either::A(true, .., true) => (), | ||
1285 | Either::A(true, .., false) => (), | ||
1286 | Either::A(.., true) => (), | ||
1287 | Either::A(.., false) => (), | ||
1288 | Either::B => (), | ||
1955 | } | 1289 | } |
1956 | 1290 | } | |
1957 | #[test] | 1291 | "#, |
1958 | fn type_never() { | ||
1959 | check_no_diagnostic( | ||
1960 | r" | ||
1961 | fn test_fn(never: !) { | ||
1962 | match never {} | ||
1963 | } | ||
1964 | ", | ||
1965 | ); | 1292 | ); |
1966 | } | 1293 | } |
1967 | 1294 | ||
1968 | #[test] | 1295 | #[test] |
1969 | fn enum_never_ref() { | 1296 | fn never() { |
1970 | check_no_diagnostic( | 1297 | check_diagnostics( |
1971 | r" | 1298 | r#" |
1972 | enum Never {} | 1299 | enum Never {} |
1973 | 1300 | ||
1974 | fn test_fn(never: &Never) { | 1301 | fn enum_(never: Never) { |
1975 | match never {} | 1302 | match never {} |
1976 | } | 1303 | } |
1977 | ", | 1304 | fn enum_ref(never: &Never) { |
1978 | ); | 1305 | match never {} |
1979 | } | 1306 | } |
1980 | 1307 | fn bang(never: !) { | |
1981 | #[test] | 1308 | match never {} |
1982 | fn expr_diverges_missing_arm() { | 1309 | } |
1983 | check_no_diagnostic( | 1310 | "#, |
1984 | r" | ||
1985 | enum Either { | ||
1986 | A, | ||
1987 | B, | ||
1988 | } | ||
1989 | fn test_fn() { | ||
1990 | match loop {} { | ||
1991 | Either::A => (), | ||
1992 | } | ||
1993 | } | ||
1994 | ", | ||
1995 | ); | 1311 | ); |
1996 | } | 1312 | } |
1997 | 1313 | ||
1998 | #[test] | 1314 | #[test] |
1999 | fn or_pattern_panic() { | 1315 | fn or_pattern_panic() { |
2000 | check_no_diagnostic( | 1316 | check_diagnostics( |
2001 | r" | 1317 | r#" |
2002 | pub enum Category { | 1318 | pub enum Category { Infinity, Zero } |
2003 | Infinity, | ||
2004 | Zero, | ||
2005 | } | ||
2006 | 1319 | ||
2007 | fn panic(a: Category, b: Category) { | 1320 | fn panic(a: Category, b: Category) { |
2008 | match (a, b) { | 1321 | match (a, b) { |
2009 | (Category::Zero | Category::Infinity, _) => {} | 1322 | (Category::Zero | Category::Infinity, _) => (), |
2010 | (_, Category::Zero | Category::Infinity) => {} | 1323 | (_, Category::Zero | Category::Infinity) => (), |
2011 | } | ||
2012 | } | ||
2013 | ", | ||
2014 | ); | ||
2015 | } | 1324 | } |
2016 | 1325 | ||
2017 | #[test] | 1326 | // FIXME: This is a false positive, but the code used to cause a panic in the match checker, |
2018 | fn or_pattern_panic_2() { | 1327 | // so this acts as a regression test for that. |
2019 | // FIXME: This is a false positive, but the code used to cause a panic in the match checker, | 1328 | match (a, b) { |
2020 | // so this acts as a regression test for that. | 1329 | //^^^^^^ Missing match arm |
2021 | check_diagnostic( | 1330 | (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => (), |
2022 | r" | 1331 | (Category::Infinity | Category::Zero, _) => (), |
2023 | pub enum Category { | ||
2024 | Infinity, | ||
2025 | Zero, | ||
2026 | } | ||
2027 | |||
2028 | fn panic(a: Category, b: Category) { | ||
2029 | match (a, b) { | ||
2030 | (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {} | ||
2031 | |||
2032 | (Category::Infinity | Category::Zero, _) => {} | ||
2033 | } | ||
2034 | } | ||
2035 | ", | ||
2036 | ); | ||
2037 | } | 1332 | } |
2038 | } | 1333 | } |
2039 | 1334 | "#, | |
2040 | #[cfg(test)] | 1335 | ); |
2041 | mod false_negatives { | 1336 | } |
2042 | //! The implementation of match checking here is a work in progress. As we roll this out, we | 1337 | |
2043 | //! prefer false negatives to false positives (ideally there would be no false positives). This | 1338 | mod false_negatives { |
2044 | //! test module should document known false negatives. Eventually we will have a complete | 1339 | //! The implementation of match checking here is a work in progress. As we roll this out, we |
2045 | //! implementation of match checking and this module will be empty. | 1340 | //! prefer false negatives to false positives (ideally there would be no false positives). This |
2046 | //! | 1341 | //! test module should document known false negatives. Eventually we will have a complete |
2047 | //! The reasons for documenting known false negatives: | 1342 | //! implementation of match checking and this module will be empty. |
2048 | //! | 1343 | //! |
2049 | //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. | 1344 | //! The reasons for documenting known false negatives: |
2050 | //! 2. It ensures the code doesn't panic when handling these cases. | 1345 | //! |
2051 | 1346 | //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. | |
2052 | use super::tests::*; | 1347 | //! 2. It ensures the code doesn't panic when handling these cases. |
2053 | 1348 | use super::*; | |
2054 | #[test] | 1349 | |
2055 | fn integers() { | 1350 | #[test] |
2056 | // This is a false negative. | 1351 | fn integers() { |
2057 | // We don't currently check integer exhaustiveness. | 1352 | // We don't currently check integer exhaustiveness. |
2058 | check_no_diagnostic( | 1353 | check_diagnostics( |
2059 | r" | 1354 | r#" |
2060 | fn test_fn() { | 1355 | fn main() { |
2061 | match 5 { | 1356 | match 5 { |
2062 | 10 => (), | 1357 | 10 => (), |
2063 | 11..20 => (), | 1358 | 11..20 => (), |
2064 | } | ||
2065 | } | ||
2066 | ", | ||
2067 | ); | ||
2068 | } | ||
2069 | |||
2070 | #[test] | ||
2071 | fn internal_or() { | ||
2072 | // This is a false negative. | ||
2073 | // We do not currently handle patterns with internal `or`s. | ||
2074 | check_no_diagnostic( | ||
2075 | r" | ||
2076 | fn test_fn() { | ||
2077 | enum Either { | ||
2078 | A(bool), | ||
2079 | B, | ||
2080 | } | ||
2081 | match Either::B { | ||
2082 | Either::A(true | false) => (), | ||
2083 | } | ||
2084 | } | ||
2085 | ", | ||
2086 | ); | ||
2087 | } | 1359 | } |
1360 | } | ||
1361 | "#, | ||
1362 | ); | ||
1363 | } | ||
2088 | 1364 | ||
2089 | #[test] | 1365 | #[test] |
2090 | fn expr_loop_missing_arm() { | 1366 | fn internal_or() { |
2091 | // This is a false negative. | 1367 | // We do not currently handle patterns with internal `or`s. |
2092 | // We currently infer the type of `loop { break Foo::A }` to `!`, which | 1368 | check_diagnostics( |
2093 | // causes us to skip the diagnostic since `Either::A` doesn't type check | 1369 | r#" |
2094 | // with `!`. | 1370 | fn main() { |
2095 | check_diagnostic( | 1371 | enum Either { A(bool), B } |
2096 | r" | 1372 | match Either::B { |
2097 | enum Either { | 1373 | Either::A(true | false) => (), |
2098 | A, | ||
2099 | B, | ||
2100 | } | ||
2101 | fn test_fn() { | ||
2102 | match loop { break Foo::A } { | ||
2103 | Either::A => (), | ||
2104 | } | ||
2105 | } | ||
2106 | ", | ||
2107 | ); | ||
2108 | } | 1374 | } |
1375 | } | ||
1376 | "#, | ||
1377 | ); | ||
1378 | } | ||
2109 | 1379 | ||
2110 | #[test] | 1380 | #[test] |
2111 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | 1381 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { |
2112 | // This is a false negative. | 1382 | // We don't currently handle tuple patterns with ellipsis. |
2113 | // We don't currently handle tuple patterns with ellipsis. | 1383 | check_diagnostics( |
2114 | check_no_diagnostic( | 1384 | r#" |
2115 | r" | 1385 | fn main() { |
2116 | fn test_fn() { | 1386 | match (false, true, false) { |
2117 | match (false, true, false) { | 1387 | (false, ..) => (), |
2118 | (false, ..) => {}, | ||
2119 | } | ||
2120 | } | ||
2121 | ", | ||
2122 | ); | ||
2123 | } | 1388 | } |
1389 | } | ||
1390 | "#, | ||
1391 | ); | ||
1392 | } | ||
2124 | 1393 | ||
2125 | #[test] | 1394 | #[test] |
2126 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | 1395 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { |
2127 | // This is a false negative. | 1396 | // We don't currently handle tuple patterns with ellipsis. |
2128 | // We don't currently handle tuple patterns with ellipsis. | 1397 | check_diagnostics( |
2129 | check_no_diagnostic( | 1398 | r#" |
2130 | r" | 1399 | fn main() { |
2131 | fn test_fn() { | 1400 | match (false, true, false) { |
2132 | match (false, true, false) { | 1401 | (.., false) => (), |
2133 | (.., false) => {}, | ||
2134 | } | ||
2135 | } | ||
2136 | ", | ||
2137 | ); | ||
2138 | } | 1402 | } |
1403 | } | ||
1404 | "#, | ||
1405 | ); | ||
1406 | } | ||
2139 | 1407 | ||
2140 | #[test] | 1408 | #[test] |
2141 | fn struct_missing_arm() { | 1409 | fn struct_missing_arm() { |
2142 | // This is a false negative. | 1410 | // We don't currently handle structs. |
2143 | // We don't currently handle structs. | 1411 | check_diagnostics( |
2144 | check_no_diagnostic( | 1412 | r#" |
2145 | r" | 1413 | struct Foo { a: bool } |
2146 | struct Foo { | 1414 | fn main(f: Foo) { |
2147 | a: bool, | 1415 | match f { Foo { a: true } => () } |
2148 | } | 1416 | } |
2149 | fn test_fn(f: Foo) { | 1417 | "#, |
2150 | match f { | 1418 | ); |
2151 | Foo { a: true } => {}, | 1419 | } |
2152 | } | ||
2153 | } | ||
2154 | ", | ||
2155 | ); | ||
2156 | } | 1420 | } |
2157 | } | 1421 | } |
diff --git a/crates/ra_hir_ty/src/unsafe_validation.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs index c512c4f8e..5cc76bdce 100644 --- a/crates/ra_hir_ty/src/unsafe_validation.rs +++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -6,35 +6,38 @@ use std::sync::Arc; | |||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | body::Body, | 7 | body::Body, |
8 | expr::{Expr, ExprId, UnaryOp}, | 8 | expr::{Expr, ExprId, UnaryOp}, |
9 | DefWithBodyId, FunctionId, | 9 | DefWithBodyId, |
10 | }; | 10 | }; |
11 | use hir_expand::diagnostics::DiagnosticSink; | 11 | use hir_expand::diagnostics::DiagnosticSink; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDef, ApplicationTy, | 14 | db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDefId, ApplicationTy, |
15 | InferenceResult, Ty, TypeCtor, | 15 | InferenceResult, Ty, TypeCtor, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub struct UnsafeValidator<'a, 'b: 'a> { | 18 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { |
19 | func: FunctionId, | 19 | owner: DefWithBodyId, |
20 | infer: Arc<InferenceResult>, | 20 | infer: Arc<InferenceResult>, |
21 | sink: &'a mut DiagnosticSink<'b>, | 21 | sink: &'a mut DiagnosticSink<'b>, |
22 | } | 22 | } |
23 | 23 | ||
24 | impl<'a, 'b> UnsafeValidator<'a, 'b> { | 24 | impl<'a, 'b> UnsafeValidator<'a, 'b> { |
25 | pub fn new( | 25 | pub(super) fn new( |
26 | func: FunctionId, | 26 | owner: DefWithBodyId, |
27 | infer: Arc<InferenceResult>, | 27 | infer: Arc<InferenceResult>, |
28 | sink: &'a mut DiagnosticSink<'b>, | 28 | sink: &'a mut DiagnosticSink<'b>, |
29 | ) -> UnsafeValidator<'a, 'b> { | 29 | ) -> UnsafeValidator<'a, 'b> { |
30 | UnsafeValidator { func, infer, sink } | 30 | UnsafeValidator { owner, infer, sink } |
31 | } | 31 | } |
32 | 32 | ||
33 | pub fn validate_body(&mut self, db: &dyn HirDatabase) { | 33 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { |
34 | let def = self.func.into(); | 34 | let def = self.owner.into(); |
35 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); | 35 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); |
36 | let func_data = db.function_data(self.func); | 36 | let is_unsafe = match self.owner { |
37 | if func_data.is_unsafe | 37 | DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe, |
38 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, | ||
39 | }; | ||
40 | if is_unsafe | ||
38 | || unsafe_expressions | 41 | || unsafe_expressions |
39 | .iter() | 42 | .iter() |
40 | .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) | 43 | .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) |
@@ -85,7 +88,7 @@ fn walk_unsafe( | |||
85 | Expr::Call { callee, .. } => { | 88 | Expr::Call { callee, .. } => { |
86 | let ty = &infer[*callee]; | 89 | let ty = &infer[*callee]; |
87 | if let &Ty::Apply(ApplicationTy { | 90 | if let &Ty::Apply(ApplicationTy { |
88 | ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), | 91 | ctor: TypeCtor::FnDef(CallableDefId::FunctionId(func)), |
89 | .. | 92 | .. |
90 | }) = ty | 93 | }) = ty |
91 | { | 94 | { |
@@ -118,3 +121,53 @@ fn walk_unsafe( | |||
118 | walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); | 121 | walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); |
119 | }); | 122 | }); |
120 | } | 123 | } |
124 | |||
125 | #[cfg(test)] | ||
126 | mod tests { | ||
127 | use crate::diagnostics::tests::check_diagnostics; | ||
128 | |||
129 | #[test] | ||
130 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
131 | check_diagnostics( | ||
132 | r#" | ||
133 | fn main() { | ||
134 | let x = &5 as *const usize; | ||
135 | unsafe { let y = *x; } | ||
136 | let z = *x; | ||
137 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
138 | "#, | ||
139 | ) | ||
140 | } | ||
141 | |||
142 | #[test] | ||
143 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
144 | check_diagnostics( | ||
145 | r#" | ||
146 | struct HasUnsafe; | ||
147 | |||
148 | impl HasUnsafe { | ||
149 | unsafe fn unsafe_fn(&self) { | ||
150 | let x = &5 as *const usize; | ||
151 | let y = *x; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | unsafe fn unsafe_fn() { | ||
156 | let x = &5 as *const usize; | ||
157 | let y = *x; | ||
158 | } | ||
159 | |||
160 | fn main() { | ||
161 | unsafe_fn(); | ||
162 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
163 | HasUnsafe.unsafe_fn(); | ||
164 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
165 | unsafe { | ||
166 | unsafe_fn(); | ||
167 | HasUnsafe.unsafe_fn(); | ||
168 | } | ||
169 | } | ||
170 | "#, | ||
171 | ); | ||
172 | } | ||
173 | } | ||
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index 23cea1a2a..19770e609 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, | 6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, |
7 | Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 7 | Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
8 | }; | 8 | }; |
9 | use hir_def::{ | 9 | use hir_def::{ |
@@ -243,22 +243,36 @@ impl HirDisplay for ApplicationTy { | |||
243 | write!(f, ")")?; | 243 | write!(f, ")")?; |
244 | } | 244 | } |
245 | } | 245 | } |
246 | TypeCtor::FnPtr { .. } => { | 246 | TypeCtor::FnPtr { is_varargs, .. } => { |
247 | let sig = FnSig::from_fn_ptr_substs(&self.parameters); | 247 | let sig = FnSig::from_fn_ptr_substs(&self.parameters, is_varargs); |
248 | write!(f, "fn(")?; | 248 | write!(f, "fn(")?; |
249 | f.write_joined(sig.params(), ", ")?; | 249 | f.write_joined(sig.params(), ", ")?; |
250 | if is_varargs { | ||
251 | if sig.params().is_empty() { | ||
252 | write!(f, "...")?; | ||
253 | } else { | ||
254 | write!(f, ", ...")?; | ||
255 | } | ||
256 | } | ||
250 | write!(f, ")")?; | 257 | write!(f, ")")?; |
251 | let ret = sig.ret(); | 258 | let ret = sig.ret(); |
252 | if *ret != Ty::unit() { | 259 | if *ret != Ty::unit() { |
253 | write!(f, " -> {}", ret.display(f.db))?; | 260 | let ret_display = if f.omit_verbose_types() { |
261 | ret.display_truncated(f.db, f.max_size) | ||
262 | } else { | ||
263 | ret.display(f.db) | ||
264 | }; | ||
265 | write!(f, " -> {}", ret_display)?; | ||
254 | } | 266 | } |
255 | } | 267 | } |
256 | TypeCtor::FnDef(def) => { | 268 | TypeCtor::FnDef(def) => { |
257 | let sig = f.db.callable_item_signature(def).subst(&self.parameters); | 269 | let sig = f.db.callable_item_signature(def).subst(&self.parameters); |
258 | match def { | 270 | match def { |
259 | CallableDef::FunctionId(ff) => write!(f, "fn {}", f.db.function_data(ff).name)?, | 271 | CallableDefId::FunctionId(ff) => { |
260 | CallableDef::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, | 272 | write!(f, "fn {}", f.db.function_data(ff).name)? |
261 | CallableDef::EnumVariantId(e) => { | 273 | } |
274 | CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, | ||
275 | CallableDefId::EnumVariantId(e) => { | ||
262 | write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? | 276 | write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? |
263 | } | 277 | } |
264 | }; | 278 | }; |
@@ -279,7 +293,12 @@ impl HirDisplay for ApplicationTy { | |||
279 | write!(f, ")")?; | 293 | write!(f, ")")?; |
280 | let ret = sig.ret(); | 294 | let ret = sig.ret(); |
281 | if *ret != Ty::unit() { | 295 | if *ret != Ty::unit() { |
282 | write!(f, " -> {}", ret.display(f.db))?; | 296 | let ret_display = if f.omit_verbose_types() { |
297 | ret.display_truncated(f.db, f.max_size) | ||
298 | } else { | ||
299 | ret.display(f.db) | ||
300 | }; | ||
301 | write!(f, " -> {}", ret_display)?; | ||
283 | } | 302 | } |
284 | } | 303 | } |
285 | TypeCtor::Adt(def_id) => { | 304 | TypeCtor::Adt(def_id) => { |
@@ -369,7 +388,7 @@ impl HirDisplay for ApplicationTy { | |||
369 | let data = (*datas) | 388 | let data = (*datas) |
370 | .as_ref() | 389 | .as_ref() |
371 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | 390 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); |
372 | data.clone().subst(&self.parameters) | 391 | data.subst(&self.parameters) |
373 | } | 392 | } |
374 | }; | 393 | }; |
375 | write!(f, "impl ")?; | 394 | write!(f, "impl ")?; |
@@ -388,7 +407,13 @@ impl HirDisplay for ApplicationTy { | |||
388 | f.write_joined(sig.params(), ", ")?; | 407 | f.write_joined(sig.params(), ", ")?; |
389 | write!(f, "|")?; | 408 | write!(f, "|")?; |
390 | }; | 409 | }; |
391 | write!(f, " -> {}", sig.ret().display(f.db))?; | 410 | |
411 | let ret_display = if f.omit_verbose_types() { | ||
412 | sig.ret().display_truncated(f.db, f.max_size) | ||
413 | } else { | ||
414 | sig.ret().display(f.db) | ||
415 | }; | ||
416 | write!(f, " -> {}", ret_display)?; | ||
392 | } else { | 417 | } else { |
393 | write!(f, "{{closure}}")?; | 418 | write!(f, "{{closure}}")?; |
394 | } | 419 | } |
@@ -456,7 +481,7 @@ impl HirDisplay for Ty { | |||
456 | let data = (*datas) | 481 | let data = (*datas) |
457 | .as_ref() | 482 | .as_ref() |
458 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | 483 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); |
459 | data.clone().subst(&opaque_ty.parameters) | 484 | data.subst(&opaque_ty.parameters) |
460 | } | 485 | } |
461 | }; | 486 | }; |
462 | write!(f, "impl ")?; | 487 | write!(f, "impl ")?; |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 5c56c2eb0..28f32a0a4 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -18,8 +18,6 @@ use std::mem; | |||
18 | use std::ops::Index; | 18 | use std::ops::Index; |
19 | use std::sync::Arc; | 19 | use std::sync::Arc; |
20 | 20 | ||
21 | use rustc_hash::FxHashMap; | ||
22 | |||
23 | use hir_def::{ | 21 | use hir_def::{ |
24 | body::Body, | 22 | body::Body, |
25 | data::{ConstData, FunctionData, StaticData}, | 23 | data::{ConstData, FunctionData, StaticData}, |
@@ -35,6 +33,8 @@ use hir_expand::{diagnostics::DiagnosticSink, name::name}; | |||
35 | use ra_arena::map::ArenaMap; | 33 | use ra_arena::map::ArenaMap; |
36 | use ra_prof::profile; | 34 | use ra_prof::profile; |
37 | use ra_syntax::SmolStr; | 35 | use ra_syntax::SmolStr; |
36 | use rustc_hash::FxHashMap; | ||
37 | use stdx::impl_from; | ||
38 | 38 | ||
39 | use super::{ | 39 | use super::{ |
40 | primitive::{FloatTy, IntTy}, | 40 | primitive::{FloatTy, IntTy}, |
@@ -84,8 +84,7 @@ enum ExprOrPatId { | |||
84 | ExprId(ExprId), | 84 | ExprId(ExprId), |
85 | PatId(PatId), | 85 | PatId(PatId), |
86 | } | 86 | } |
87 | 87 | impl_from!(ExprId, PatId for ExprOrPatId); | |
88 | impl_froms!(ExprOrPatId: ExprId, PatId); | ||
89 | 88 | ||
90 | /// Binding modes inferred for patterns. | 89 | /// Binding modes inferred for patterns. |
91 | /// https://doc.rust-lang.org/reference/patterns.html#binding-modes | 90 | /// https://doc.rust-lang.org/reference/patterns.html#binding-modes |
@@ -169,7 +168,7 @@ impl InferenceResult { | |||
169 | pub fn add_diagnostics( | 168 | pub fn add_diagnostics( |
170 | &self, | 169 | &self, |
171 | db: &dyn HirDatabase, | 170 | db: &dyn HirDatabase, |
172 | owner: FunctionId, | 171 | owner: DefWithBodyId, |
173 | sink: &mut DiagnosticSink, | 172 | sink: &mut DiagnosticSink, |
174 | ) { | 173 | ) { |
175 | self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink)) | 174 | self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink)) |
@@ -761,7 +760,7 @@ impl std::ops::BitOrAssign for Diverges { | |||
761 | } | 760 | } |
762 | 761 | ||
763 | mod diagnostics { | 762 | mod diagnostics { |
764 | use hir_def::{expr::ExprId, FunctionId}; | 763 | use hir_def::{expr::ExprId, DefWithBodyId}; |
765 | use hir_expand::diagnostics::DiagnosticSink; | 764 | use hir_expand::diagnostics::DiagnosticSink; |
766 | 765 | ||
767 | use crate::{ | 766 | use crate::{ |
@@ -779,17 +778,17 @@ mod diagnostics { | |||
779 | pub(super) fn add_to( | 778 | pub(super) fn add_to( |
780 | &self, | 779 | &self, |
781 | db: &dyn HirDatabase, | 780 | db: &dyn HirDatabase, |
782 | owner: FunctionId, | 781 | owner: DefWithBodyId, |
783 | sink: &mut DiagnosticSink, | 782 | sink: &mut DiagnosticSink, |
784 | ) { | 783 | ) { |
785 | match self { | 784 | match self { |
786 | InferenceDiagnostic::NoSuchField { expr, field } => { | 785 | InferenceDiagnostic::NoSuchField { expr, field } => { |
787 | let (_, source_map) = db.body_with_source_map(owner.into()); | 786 | let (_, source_map) = db.body_with_source_map(owner); |
788 | let field = source_map.field_syntax(*expr, *field); | 787 | let field = source_map.field_syntax(*expr, *field); |
789 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | 788 | sink.push(NoSuchField { file: field.file_id, field: field.value }) |
790 | } | 789 | } |
791 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | 790 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { |
792 | let (_, source_map) = db.body_with_source_map(owner.into()); | 791 | let (_, source_map) = db.body_with_source_map(owner); |
793 | let ptr = source_map | 792 | let ptr = source_map |
794 | .expr_syntax(*expr) | 793 | .expr_syntax(*expr) |
795 | .expect("break outside of loop in synthetic syntax"); | 794 | .expect("break outside of loop in synthetic syntax"); |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 22884522a..731b062c2 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -17,7 +17,7 @@ use crate::{ | |||
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::{FnTrait, InEnvironment}, | 18 | traits::{FnTrait, InEnvironment}, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, |
21 | TraitRef, Ty, TypeCtor, | 21 | TraitRef, Ty, TypeCtor, |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -85,10 +85,8 @@ impl<'a> InferenceContext<'a> { | |||
85 | ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, | 85 | ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, |
86 | parameters, | 86 | parameters, |
87 | }); | 87 | }); |
88 | let substs = Substs::build_for_generics(&generic_params) | 88 | let substs = |
89 | .push(ty.clone()) | 89 | Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); |
90 | .push(arg_ty.clone()) | ||
91 | .build(); | ||
92 | 90 | ||
93 | let trait_env = Arc::clone(&self.trait_env); | 91 | let trait_env = Arc::clone(&self.trait_env); |
94 | let implements_fn_trait = | 92 | let implements_fn_trait = |
@@ -222,7 +220,7 @@ impl<'a> InferenceContext<'a> { | |||
222 | }; | 220 | }; |
223 | sig_tys.push(ret_ty.clone()); | 221 | sig_tys.push(ret_ty.clone()); |
224 | let sig_ty = Ty::apply( | 222 | let sig_ty = Ty::apply( |
225 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, | 223 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false }, |
226 | Substs(sig_tys.clone().into()), | 224 | Substs(sig_tys.clone().into()), |
227 | ); | 225 | ); |
228 | let closure_ty = | 226 | let closure_ty = |
@@ -407,8 +405,15 @@ impl<'a> InferenceContext<'a> { | |||
407 | .subst(&a_ty.parameters) | 405 | .subst(&a_ty.parameters) |
408 | }) | 406 | }) |
409 | } | 407 | } |
410 | // FIXME: | 408 | TypeCtor::Adt(AdtId::UnionId(u)) => { |
411 | TypeCtor::Adt(AdtId::UnionId(_)) => None, | 409 | self.db.union_data(u).variant_data.field(name).map(|local_id| { |
410 | let field = FieldId { parent: u.into(), local_id }; | ||
411 | self.write_field_resolution(tgt_expr, field); | ||
412 | self.db.field_types(u.into())[field.local_id] | ||
413 | .clone() | ||
414 | .subst(&a_ty.parameters) | ||
415 | }) | ||
416 | } | ||
412 | _ => None, | 417 | _ => None, |
413 | }, | 418 | }, |
414 | _ => None, | 419 | _ => None, |
@@ -849,7 +854,7 @@ impl<'a> InferenceContext<'a> { | |||
849 | } | 854 | } |
850 | // add obligation for trait implementation, if this is a trait method | 855 | // add obligation for trait implementation, if this is a trait method |
851 | match def { | 856 | match def { |
852 | CallableDef::FunctionId(f) => { | 857 | CallableDefId::FunctionId(f) => { |
853 | if let AssocContainerId::TraitId(trait_) = | 858 | if let AssocContainerId::TraitId(trait_) = |
854 | f.lookup(self.db.upcast()).container | 859 | f.lookup(self.db.upcast()).container |
855 | { | 860 | { |
@@ -860,7 +865,7 @@ impl<'a> InferenceContext<'a> { | |||
860 | self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); | 865 | self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); |
861 | } | 866 | } |
862 | } | 867 | } |
863 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {} | 868 | CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {} |
864 | } | 869 | } |
865 | } | 870 | } |
866 | } | 871 | } |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 7f3f5e771..7698cb0d4 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -6,25 +6,6 @@ macro_rules! eprintln { | |||
6 | ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; | 6 | ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; |
7 | } | 7 | } |
8 | 8 | ||
9 | macro_rules! impl_froms { | ||
10 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | ||
11 | $( | ||
12 | impl From<$v> for $e { | ||
13 | fn from(it: $v) -> $e { | ||
14 | $e::$v(it) | ||
15 | } | ||
16 | } | ||
17 | $($( | ||
18 | impl From<$sv> for $e { | ||
19 | fn from(it: $sv) -> $e { | ||
20 | $e::$v($v::$sv(it)) | ||
21 | } | ||
22 | } | ||
23 | )*)? | ||
24 | )* | ||
25 | } | ||
26 | } | ||
27 | |||
28 | mod autoderef; | 9 | mod autoderef; |
29 | pub mod primitive; | 10 | pub mod primitive; |
30 | pub mod traits; | 11 | pub mod traits; |
@@ -32,22 +13,18 @@ pub mod method_resolution; | |||
32 | mod op; | 13 | mod op; |
33 | mod lower; | 14 | mod lower; |
34 | pub(crate) mod infer; | 15 | pub(crate) mod infer; |
35 | pub mod display; | ||
36 | pub(crate) mod utils; | 16 | pub(crate) mod utils; |
17 | |||
18 | pub mod display; | ||
37 | pub mod db; | 19 | pub mod db; |
38 | pub mod diagnostics; | 20 | pub mod diagnostics; |
39 | pub mod expr; | ||
40 | pub mod unsafe_validation; | ||
41 | 21 | ||
42 | #[cfg(test)] | 22 | #[cfg(test)] |
43 | mod tests; | 23 | mod tests; |
44 | #[cfg(test)] | 24 | #[cfg(test)] |
45 | mod test_db; | 25 | mod test_db; |
46 | mod _match; | ||
47 | 26 | ||
48 | use std::ops::Deref; | 27 | use std::{iter, mem, ops::Deref, sync::Arc}; |
49 | use std::sync::Arc; | ||
50 | use std::{iter, mem}; | ||
51 | 28 | ||
52 | use hir_def::{ | 29 | use hir_def::{ |
53 | expr::ExprId, | 30 | expr::ExprId, |
@@ -55,18 +32,19 @@ use hir_def::{ | |||
55 | AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, | 32 | AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, |
56 | TypeParamId, | 33 | TypeParamId, |
57 | }; | 34 | }; |
58 | use ra_db::{impl_intern_key, salsa, CrateId}; | 35 | use itertools::Itertools; |
36 | use ra_db::{salsa, CrateId}; | ||
59 | 37 | ||
60 | use crate::{ | 38 | use crate::{ |
61 | db::HirDatabase, | 39 | db::HirDatabase, |
40 | display::HirDisplay, | ||
62 | primitive::{FloatTy, IntTy}, | 41 | primitive::{FloatTy, IntTy}, |
63 | utils::{generics, make_mut_slice, Generics}, | 42 | utils::{generics, make_mut_slice, Generics}, |
64 | }; | 43 | }; |
65 | use display::HirDisplay; | ||
66 | 44 | ||
67 | pub use autoderef::autoderef; | 45 | pub use autoderef::autoderef; |
68 | pub use infer::{InferTy, InferenceResult}; | 46 | pub use infer::{InferTy, InferenceResult}; |
69 | pub use lower::CallableDef; | 47 | pub use lower::CallableDefId; |
70 | pub use lower::{ | 48 | pub use lower::{ |
71 | associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, | 49 | associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, |
72 | TyLoweringContext, ValueTyDefId, | 50 | TyLoweringContext, ValueTyDefId, |
@@ -74,7 +52,6 @@ pub use lower::{ | |||
74 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 52 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
75 | 53 | ||
76 | pub use chalk_ir::{BoundVar, DebruijnIndex}; | 54 | pub use chalk_ir::{BoundVar, DebruijnIndex}; |
77 | use itertools::Itertools; | ||
78 | 55 | ||
79 | /// A type constructor or type name: this might be something like the primitive | 56 | /// A type constructor or type name: this might be something like the primitive |
80 | /// type `bool`, a struct like `Vec`, or things like function pointers or | 57 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
@@ -125,7 +102,7 @@ pub enum TypeCtor { | |||
125 | /// fn foo() -> i32 { 1 } | 102 | /// fn foo() -> i32 { 1 } |
126 | /// let bar = foo; // bar: fn() -> i32 {foo} | 103 | /// let bar = foo; // bar: fn() -> i32 {foo} |
127 | /// ``` | 104 | /// ``` |
128 | FnDef(CallableDef), | 105 | FnDef(CallableDefId), |
129 | 106 | ||
130 | /// A pointer to a function. Written as `fn() -> i32`. | 107 | /// A pointer to a function. Written as `fn() -> i32`. |
131 | /// | 108 | /// |
@@ -135,7 +112,8 @@ pub enum TypeCtor { | |||
135 | /// fn foo() -> i32 { 1 } | 112 | /// fn foo() -> i32 { 1 } |
136 | /// let bar: fn() -> i32 = foo; | 113 | /// let bar: fn() -> i32 = foo; |
137 | /// ``` | 114 | /// ``` |
138 | FnPtr { num_args: u16 }, | 115 | // FIXME make this a Ty variant like in Chalk |
116 | FnPtr { num_args: u16, is_varargs: bool }, | ||
139 | 117 | ||
140 | /// The never type `!`. | 118 | /// The never type `!`. |
141 | Never, | 119 | Never, |
@@ -162,19 +140,6 @@ pub enum TypeCtor { | |||
162 | Closure { def: DefWithBodyId, expr: ExprId }, | 140 | Closure { def: DefWithBodyId, expr: ExprId }, |
163 | } | 141 | } |
164 | 142 | ||
165 | /// This exists just for Chalk, because Chalk just has a single `StructId` where | ||
166 | /// we have different kinds of ADTs, primitive types and special type | ||
167 | /// constructors like tuples and function pointers. | ||
168 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
169 | pub struct TypeCtorId(salsa::InternId); | ||
170 | impl_intern_key!(TypeCtorId); | ||
171 | |||
172 | /// This exists just for Chalk, because Chalk just has a single `FnDefId` where | ||
173 | /// we have different IDs for struct and enum variant constructors. | ||
174 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
175 | pub struct CallableDefId(salsa::InternId); | ||
176 | impl_intern_key!(CallableDefId); | ||
177 | |||
178 | impl TypeCtor { | 143 | impl TypeCtor { |
179 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { | 144 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { |
180 | match self { | 145 | match self { |
@@ -210,7 +175,7 @@ impl TypeCtor { | |||
210 | } | 175 | } |
211 | } | 176 | } |
212 | } | 177 | } |
213 | TypeCtor::FnPtr { num_args } => num_args as usize + 1, | 178 | TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1, |
214 | TypeCtor::Tuple { cardinality } => cardinality as usize, | 179 | TypeCtor::Tuple { cardinality } => cardinality as usize, |
215 | } | 180 | } |
216 | } | 181 | } |
@@ -690,19 +655,20 @@ pub enum TyKind { | |||
690 | #[derive(Clone, PartialEq, Eq, Debug)] | 655 | #[derive(Clone, PartialEq, Eq, Debug)] |
691 | pub struct FnSig { | 656 | pub struct FnSig { |
692 | params_and_return: Arc<[Ty]>, | 657 | params_and_return: Arc<[Ty]>, |
658 | is_varargs: bool, | ||
693 | } | 659 | } |
694 | 660 | ||
695 | /// A polymorphic function signature. | 661 | /// A polymorphic function signature. |
696 | pub type PolyFnSig = Binders<FnSig>; | 662 | pub type PolyFnSig = Binders<FnSig>; |
697 | 663 | ||
698 | impl FnSig { | 664 | impl FnSig { |
699 | pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig { | 665 | pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> FnSig { |
700 | params.push(ret); | 666 | params.push(ret); |
701 | FnSig { params_and_return: params.into() } | 667 | FnSig { params_and_return: params.into(), is_varargs } |
702 | } | 668 | } |
703 | 669 | ||
704 | pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig { | 670 | pub fn from_fn_ptr_substs(substs: &Substs, is_varargs: bool) -> FnSig { |
705 | FnSig { params_and_return: Arc::clone(&substs.0) } | 671 | FnSig { params_and_return: Arc::clone(&substs.0), is_varargs } |
706 | } | 672 | } |
707 | 673 | ||
708 | pub fn params(&self) -> &[Ty] { | 674 | pub fn params(&self) -> &[Ty] { |
@@ -747,7 +713,7 @@ impl Ty { | |||
747 | } | 713 | } |
748 | pub fn fn_ptr(sig: FnSig) -> Self { | 714 | pub fn fn_ptr(sig: FnSig) -> Self { |
749 | Ty::apply( | 715 | Ty::apply( |
750 | TypeCtor::FnPtr { num_args: sig.params().len() as u16 }, | 716 | TypeCtor::FnPtr { num_args: sig.params().len() as u16, is_varargs: sig.is_varargs }, |
751 | Substs(sig.params_and_return), | 717 | Substs(sig.params_and_return), |
752 | ) | 718 | ) |
753 | } | 719 | } |
@@ -801,15 +767,6 @@ impl Ty { | |||
801 | } | 767 | } |
802 | } | 768 | } |
803 | 769 | ||
804 | pub fn as_callable(&self) -> Option<(CallableDef, &Substs)> { | ||
805 | match self { | ||
806 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => { | ||
807 | Some((*callable_def, parameters)) | ||
808 | } | ||
809 | _ => None, | ||
810 | } | ||
811 | } | ||
812 | |||
813 | pub fn is_never(&self) -> bool { | 770 | pub fn is_never(&self) -> bool { |
814 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) | 771 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) |
815 | } | 772 | } |
@@ -841,10 +798,12 @@ impl Ty { | |||
841 | } | 798 | } |
842 | } | 799 | } |
843 | 800 | ||
844 | fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { | 801 | pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { |
845 | match self { | 802 | match self { |
846 | Ty::Apply(a_ty) => match a_ty.ctor { | 803 | Ty::Apply(a_ty) => match a_ty.ctor { |
847 | TypeCtor::FnPtr { .. } => Some(FnSig::from_fn_ptr_substs(&a_ty.parameters)), | 804 | TypeCtor::FnPtr { is_varargs, .. } => { |
805 | Some(FnSig::from_fn_ptr_substs(&a_ty.parameters, is_varargs)) | ||
806 | } | ||
848 | TypeCtor::FnDef(def) => { | 807 | TypeCtor::FnDef(def) => { |
849 | let sig = db.callable_item_signature(def); | 808 | let sig = db.callable_item_signature(def); |
850 | Some(sig.subst(&a_ty.parameters)) | 809 | Some(sig.subst(&a_ty.parameters)) |
@@ -891,7 +850,7 @@ impl Ty { | |||
891 | let data = (*it) | 850 | let data = (*it) |
892 | .as_ref() | 851 | .as_ref() |
893 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | 852 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); |
894 | data.clone().subst(&opaque_ty.parameters) | 853 | data.subst(&opaque_ty.parameters) |
895 | }) | 854 | }) |
896 | } | 855 | } |
897 | }; | 856 | }; |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 3dc154e92..1eacc6f95 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -5,10 +5,7 @@ | |||
5 | //! - Building the type for an item: This happens through the `type_for_def` query. | 5 | //! - Building the type for an item: This happens through the `type_for_def` query. |
6 | //! | 6 | //! |
7 | //! This usually involves resolving names, collecting generic arguments etc. | 7 | //! This usually involves resolving names, collecting generic arguments etc. |
8 | use std::iter; | 8 | use std::{iter, sync::Arc}; |
9 | use std::sync::Arc; | ||
10 | |||
11 | use smallvec::SmallVec; | ||
12 | 9 | ||
13 | use hir_def::{ | 10 | use hir_def::{ |
14 | adt::StructKind, | 11 | adt::StructKind, |
@@ -24,6 +21,8 @@ use hir_def::{ | |||
24 | use hir_expand::name::Name; | 21 | use hir_expand::name::Name; |
25 | use ra_arena::map::ArenaMap; | 22 | use ra_arena::map::ArenaMap; |
26 | use ra_db::CrateId; | 23 | use ra_db::CrateId; |
24 | use smallvec::SmallVec; | ||
25 | use stdx::impl_from; | ||
27 | use test_utils::mark; | 26 | use test_utils::mark; |
28 | 27 | ||
29 | use crate::{ | 28 | use crate::{ |
@@ -177,9 +176,12 @@ impl Ty { | |||
177 | Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) | 176 | Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) |
178 | } | 177 | } |
179 | TypeRef::Placeholder => Ty::Unknown, | 178 | TypeRef::Placeholder => Ty::Unknown, |
180 | TypeRef::Fn(params) => { | 179 | TypeRef::Fn(params, is_varargs) => { |
181 | let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect()); | 180 | let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect()); |
182 | Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) | 181 | Ty::apply( |
182 | TypeCtor::FnPtr { num_args: sig.len() as u16 - 1, is_varargs: *is_varargs }, | ||
183 | sig, | ||
184 | ) | ||
183 | } | 185 | } |
184 | TypeRef::DynTrait(bounds) => { | 186 | TypeRef::DynTrait(bounds) => { |
185 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | 187 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); |
@@ -339,7 +341,7 @@ impl Ty { | |||
339 | let segment = remaining_segments.first().unwrap(); | 341 | let segment = remaining_segments.first().unwrap(); |
340 | let found = associated_type_by_name_including_super_traits( | 342 | let found = associated_type_by_name_including_super_traits( |
341 | ctx.db, | 343 | ctx.db, |
342 | trait_ref.clone(), | 344 | trait_ref, |
343 | &segment.name, | 345 | &segment.name, |
344 | ); | 346 | ); |
345 | match found { | 347 | match found { |
@@ -720,8 +722,7 @@ fn assoc_type_bindings_from_type_bound<'a>( | |||
720 | None => return SmallVec::<[GenericPredicate; 1]>::new(), | 722 | None => return SmallVec::<[GenericPredicate; 1]>::new(), |
721 | Some(t) => t, | 723 | Some(t) => t, |
722 | }; | 724 | }; |
723 | let projection_ty = | 725 | let projection_ty = ProjectionTy { associated_ty, parameters: super_trait_ref.substs }; |
724 | ProjectionTy { associated_ty, parameters: super_trait_ref.substs.clone() }; | ||
725 | let mut preds = SmallVec::with_capacity( | 726 | let mut preds = SmallVec::with_capacity( |
726 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), | 727 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), |
727 | ); | 728 | ); |
@@ -767,11 +768,11 @@ fn count_impl_traits(type_ref: &TypeRef) -> usize { | |||
767 | } | 768 | } |
768 | 769 | ||
769 | /// Build the signature of a callable item (function, struct or enum variant). | 770 | /// Build the signature of a callable item (function, struct or enum variant). |
770 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { | 771 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig { |
771 | match def { | 772 | match def { |
772 | CallableDef::FunctionId(f) => fn_sig_for_fn(db, f), | 773 | CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), |
773 | CallableDef::StructId(s) => fn_sig_for_struct_constructor(db, s), | 774 | CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), |
774 | CallableDef::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), | 775 | CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), |
775 | } | 776 | } |
776 | } | 777 | } |
777 | 778 | ||
@@ -998,7 +999,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | |||
998 | let ret = Ty::from_hir(&ctx_ret, &data.ret_type); | 999 | let ret = Ty::from_hir(&ctx_ret, &data.ret_type); |
999 | let generics = generics(db.upcast(), def.into()); | 1000 | let generics = generics(db.upcast(), def.into()); |
1000 | let num_binders = generics.len(); | 1001 | let num_binders = generics.len(); |
1001 | Binders::new(num_binders, FnSig::from_params_and_return(params, ret)) | 1002 | Binders::new(num_binders, FnSig::from_params_and_return(params, ret, data.is_varargs)) |
1002 | } | 1003 | } |
1003 | 1004 | ||
1004 | /// Build the declared type of a function. This should not need to look at the | 1005 | /// Build the declared type of a function. This should not need to look at the |
@@ -1049,7 +1050,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS | |||
1049 | let params = | 1050 | let params = |
1050 | fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); | 1051 | fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); |
1051 | let ret = type_for_adt(db, def.into()); | 1052 | let ret = type_for_adt(db, def.into()); |
1052 | Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) | 1053 | Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false)) |
1053 | } | 1054 | } |
1054 | 1055 | ||
1055 | /// Build the type of a tuple struct constructor. | 1056 | /// Build the type of a tuple struct constructor. |
@@ -1073,7 +1074,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) | |||
1073 | let params = | 1074 | let params = |
1074 | fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); | 1075 | fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); |
1075 | let ret = type_for_adt(db, def.parent.into()); | 1076 | let ret = type_for_adt(db, def.parent.into()); |
1076 | Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) | 1077 | Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false)) |
1077 | } | 1078 | } |
1078 | 1079 | ||
1079 | /// Build the type of a tuple enum variant constructor. | 1080 | /// Build the type of a tuple enum variant constructor. |
@@ -1106,31 +1107,31 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { | |||
1106 | } | 1107 | } |
1107 | 1108 | ||
1108 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1109 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1109 | pub enum CallableDef { | 1110 | pub enum CallableDefId { |
1110 | FunctionId(FunctionId), | 1111 | FunctionId(FunctionId), |
1111 | StructId(StructId), | 1112 | StructId(StructId), |
1112 | EnumVariantId(EnumVariantId), | 1113 | EnumVariantId(EnumVariantId), |
1113 | } | 1114 | } |
1114 | impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId); | 1115 | impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); |
1115 | 1116 | ||
1116 | impl CallableDef { | 1117 | impl CallableDefId { |
1117 | pub fn krate(self, db: &dyn HirDatabase) -> CrateId { | 1118 | pub fn krate(self, db: &dyn HirDatabase) -> CrateId { |
1118 | let db = db.upcast(); | 1119 | let db = db.upcast(); |
1119 | match self { | 1120 | match self { |
1120 | CallableDef::FunctionId(f) => f.lookup(db).module(db), | 1121 | CallableDefId::FunctionId(f) => f.lookup(db).module(db), |
1121 | CallableDef::StructId(s) => s.lookup(db).container.module(db), | 1122 | CallableDefId::StructId(s) => s.lookup(db).container.module(db), |
1122 | CallableDef::EnumVariantId(e) => e.parent.lookup(db).container.module(db), | 1123 | CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container.module(db), |
1123 | } | 1124 | } |
1124 | .krate | 1125 | .krate |
1125 | } | 1126 | } |
1126 | } | 1127 | } |
1127 | 1128 | ||
1128 | impl From<CallableDef> for GenericDefId { | 1129 | impl From<CallableDefId> for GenericDefId { |
1129 | fn from(def: CallableDef) -> GenericDefId { | 1130 | fn from(def: CallableDefId) -> GenericDefId { |
1130 | match def { | 1131 | match def { |
1131 | CallableDef::FunctionId(f) => f.into(), | 1132 | CallableDefId::FunctionId(f) => f.into(), |
1132 | CallableDef::StructId(s) => s.into(), | 1133 | CallableDefId::StructId(s) => s.into(), |
1133 | CallableDef::EnumVariantId(e) => e.into(), | 1134 | CallableDefId::EnumVariantId(e) => e.into(), |
1134 | } | 1135 | } |
1135 | } | 1136 | } |
1136 | } | 1137 | } |
@@ -1141,7 +1142,7 @@ pub enum TyDefId { | |||
1141 | AdtId(AdtId), | 1142 | AdtId(AdtId), |
1142 | TypeAliasId(TypeAliasId), | 1143 | TypeAliasId(TypeAliasId), |
1143 | } | 1144 | } |
1144 | impl_froms!(TyDefId: BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId); | 1145 | impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId); |
1145 | 1146 | ||
1146 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1147 | pub enum ValueTyDefId { | 1148 | pub enum ValueTyDefId { |
@@ -1151,7 +1152,7 @@ pub enum ValueTyDefId { | |||
1151 | ConstId(ConstId), | 1152 | ConstId(ConstId), |
1152 | StaticId(StaticId), | 1153 | StaticId(StaticId), |
1153 | } | 1154 | } |
1154 | impl_froms!(ValueTyDefId: FunctionId, StructId, EnumVariantId, ConstId, StaticId); | 1155 | impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId); |
1155 | 1156 | ||
1156 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 1157 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
1157 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 1158 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
@@ -1216,7 +1217,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< | |||
1216 | } | 1217 | } |
1217 | 1218 | ||
1218 | pub(crate) fn return_type_impl_traits( | 1219 | pub(crate) fn return_type_impl_traits( |
1219 | db: &impl HirDatabase, | 1220 | db: &dyn HirDatabase, |
1220 | def: hir_def::FunctionId, | 1221 | def: hir_def::FunctionId, |
1221 | ) -> Option<Arc<Binders<ReturnTypeImplTraits>>> { | 1222 | ) -> Option<Arc<Binders<ReturnTypeImplTraits>>> { |
1222 | // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe | 1223 | // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index a45febbf7..fb4b30a13 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -6,8 +6,10 @@ use std::{iter, sync::Arc}; | |||
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::{ | 8 | use hir_def::{ |
9 | lang_item::LangItemTarget, type_ref::Mutability, AssocContainerId, AssocItemId, FunctionId, | 9 | builtin_type::{IntBitness, Signedness}, |
10 | HasModule, ImplId, Lookup, TraitId, | 10 | lang_item::LangItemTarget, |
11 | type_ref::Mutability, | ||
12 | AssocContainerId, AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId, | ||
11 | }; | 13 | }; |
12 | use hir_expand::name::Name; | 14 | use hir_expand::name::Name; |
13 | use ra_db::CrateId; | 15 | use ra_db::CrateId; |
@@ -16,9 +18,12 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
16 | 18 | ||
17 | use super::Substs; | 19 | use super::Substs; |
18 | use crate::{ | 20 | use crate::{ |
19 | autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, | 21 | autoderef, |
20 | Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor, | 22 | db::HirDatabase, |
21 | TypeWalk, | 23 | primitive::{FloatBitness, FloatTy, IntTy}, |
24 | utils::all_super_traits, | ||
25 | ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, | ||
26 | TypeCtor, TypeWalk, | ||
22 | }; | 27 | }; |
23 | 28 | ||
24 | /// This is used as a key for indexing impls. | 29 | /// This is used as a key for indexing impls. |
@@ -39,6 +44,62 @@ impl TyFingerprint { | |||
39 | } | 44 | } |
40 | } | 45 | } |
41 | 46 | ||
47 | pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ | ||
48 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
49 | signedness: Signedness::Unsigned, | ||
50 | bitness: IntBitness::X8, | ||
51 | })), | ||
52 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
53 | signedness: Signedness::Unsigned, | ||
54 | bitness: IntBitness::X16, | ||
55 | })), | ||
56 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
57 | signedness: Signedness::Unsigned, | ||
58 | bitness: IntBitness::X32, | ||
59 | })), | ||
60 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
61 | signedness: Signedness::Unsigned, | ||
62 | bitness: IntBitness::X64, | ||
63 | })), | ||
64 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
65 | signedness: Signedness::Unsigned, | ||
66 | bitness: IntBitness::X128, | ||
67 | })), | ||
68 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
69 | signedness: Signedness::Unsigned, | ||
70 | bitness: IntBitness::Xsize, | ||
71 | })), | ||
72 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
73 | signedness: Signedness::Signed, | ||
74 | bitness: IntBitness::X8, | ||
75 | })), | ||
76 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
77 | signedness: Signedness::Signed, | ||
78 | bitness: IntBitness::X16, | ||
79 | })), | ||
80 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
81 | signedness: Signedness::Signed, | ||
82 | bitness: IntBitness::X32, | ||
83 | })), | ||
84 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
85 | signedness: Signedness::Signed, | ||
86 | bitness: IntBitness::X64, | ||
87 | })), | ||
88 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
89 | signedness: Signedness::Signed, | ||
90 | bitness: IntBitness::X128, | ||
91 | })), | ||
92 | TyFingerprint::Apply(TypeCtor::Int(IntTy { | ||
93 | signedness: Signedness::Signed, | ||
94 | bitness: IntBitness::Xsize, | ||
95 | })), | ||
96 | ]; | ||
97 | |||
98 | pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ | ||
99 | TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })), | ||
100 | TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })), | ||
101 | ]; | ||
102 | |||
42 | /// Trait impls defined or available in some crate. | 103 | /// Trait impls defined or available in some crate. |
43 | #[derive(Debug, Eq, PartialEq)] | 104 | #[derive(Debug, Eq, PartialEq)] |
44 | pub struct TraitImpls { | 105 | pub struct TraitImpls { |
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index fddf0604d..a1714ff0f 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -1,23 +1,17 @@ | |||
1 | //! Database used for testing `hir`. | 1 | //! Database used for testing `hir`. |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | panic, | 4 | fmt, panic, |
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | 8 | use hir_def::{db::DefDatabase, ModuleId}; |
9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; | 9 | use hir_expand::db::AstDatabase; |
10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; | 10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; |
11 | use ra_syntax::TextRange; | 11 | use ra_syntax::TextRange; |
12 | use rustc_hash::{FxHashMap, FxHashSet}; | 12 | use rustc_hash::{FxHashMap, FxHashSet}; |
13 | use stdx::format_to; | ||
14 | use test_utils::extract_annotations; | 13 | use test_utils::extract_annotations; |
15 | 14 | ||
16 | use crate::{ | ||
17 | db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator, | ||
18 | unsafe_validation::UnsafeValidator, | ||
19 | }; | ||
20 | |||
21 | #[salsa::database( | 15 | #[salsa::database( |
22 | ra_db::SourceDatabaseExtStorage, | 16 | ra_db::SourceDatabaseExtStorage, |
23 | ra_db::SourceDatabaseStorage, | 17 | ra_db::SourceDatabaseStorage, |
@@ -26,10 +20,15 @@ use crate::{ | |||
26 | hir_def::db::DefDatabaseStorage, | 20 | hir_def::db::DefDatabaseStorage, |
27 | crate::db::HirDatabaseStorage | 21 | crate::db::HirDatabaseStorage |
28 | )] | 22 | )] |
29 | #[derive(Debug, Default)] | 23 | #[derive(Default)] |
30 | pub struct TestDB { | 24 | pub struct TestDB { |
31 | events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, | 25 | storage: salsa::Storage<TestDB>, |
32 | runtime: salsa::Runtime<TestDB>, | 26 | events: Mutex<Option<Vec<salsa::Event>>>, |
27 | } | ||
28 | impl fmt::Debug for TestDB { | ||
29 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
30 | f.debug_struct("TestDB").finish() | ||
31 | } | ||
33 | } | 32 | } |
34 | 33 | ||
35 | impl Upcast<dyn AstDatabase> for TestDB { | 34 | impl Upcast<dyn AstDatabase> for TestDB { |
@@ -45,18 +44,10 @@ impl Upcast<dyn DefDatabase> for TestDB { | |||
45 | } | 44 | } |
46 | 45 | ||
47 | impl salsa::Database for TestDB { | 46 | impl salsa::Database for TestDB { |
48 | fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> { | 47 | fn salsa_event(&self, event: salsa::Event) { |
49 | &self.runtime | ||
50 | } | ||
51 | |||
52 | fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> { | ||
53 | &mut self.runtime | ||
54 | } | ||
55 | |||
56 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { | ||
57 | let mut events = self.events.lock().unwrap(); | 48 | let mut events = self.events.lock().unwrap(); |
58 | if let Some(events) = &mut *events { | 49 | if let Some(events) = &mut *events { |
59 | events.push(event()); | 50 | events.push(event); |
60 | } | 51 | } |
61 | } | 52 | } |
62 | } | 53 | } |
@@ -64,8 +55,8 @@ impl salsa::Database for TestDB { | |||
64 | impl salsa::ParallelDatabase for TestDB { | 55 | impl salsa::ParallelDatabase for TestDB { |
65 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { | 56 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { |
66 | salsa::Snapshot::new(TestDB { | 57 | salsa::Snapshot::new(TestDB { |
58 | storage: self.storage.snapshot(), | ||
67 | events: Default::default(), | 59 | events: Default::default(), |
68 | runtime: self.runtime.snapshot(self), | ||
69 | }) | 60 | }) |
70 | } | 61 | } |
71 | } | 62 | } |
@@ -85,7 +76,7 @@ impl FileLoader for TestDB { | |||
85 | } | 76 | } |
86 | 77 | ||
87 | impl TestDB { | 78 | impl TestDB { |
88 | pub fn module_for_file(&self, file_id: FileId) -> ModuleId { | 79 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { |
89 | for &krate in self.relevant_crates(file_id).iter() { | 80 | for &krate in self.relevant_crates(file_id).iter() { |
90 | let crate_def_map = self.crate_def_map(krate); | 81 | let crate_def_map = self.crate_def_map(krate); |
91 | for (local_id, data) in crate_def_map.modules.iter() { | 82 | for (local_id, data) in crate_def_map.modules.iter() { |
@@ -97,67 +88,7 @@ impl TestDB { | |||
97 | panic!("Can't find module for file") | 88 | panic!("Can't find module for file") |
98 | } | 89 | } |
99 | 90 | ||
100 | fn diag<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { | 91 | pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { |
101 | let crate_graph = self.crate_graph(); | ||
102 | for krate in crate_graph.iter() { | ||
103 | let crate_def_map = self.crate_def_map(krate); | ||
104 | |||
105 | let mut fns = Vec::new(); | ||
106 | for (module_id, _) in crate_def_map.modules.iter() { | ||
107 | for decl in crate_def_map[module_id].scope.declarations() { | ||
108 | if let ModuleDefId::FunctionId(f) = decl { | ||
109 | fns.push(f) | ||
110 | } | ||
111 | } | ||
112 | |||
113 | for impl_id in crate_def_map[module_id].scope.impls() { | ||
114 | let impl_data = self.impl_data(impl_id); | ||
115 | for item in impl_data.items.iter() { | ||
116 | if let AssocItemId::FunctionId(f) = item { | ||
117 | fns.push(*f) | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | for f in fns { | ||
124 | let infer = self.infer(f.into()); | ||
125 | let mut sink = DiagnosticSink::new(&mut cb); | ||
126 | infer.add_diagnostics(self, f, &mut sink); | ||
127 | let mut validator = ExprValidator::new(f, infer.clone(), &mut sink); | ||
128 | validator.validate_body(self); | ||
129 | let mut validator = UnsafeValidator::new(f, infer, &mut sink); | ||
130 | validator.validate_body(self); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | pub fn diagnostics(&self) -> (String, u32) { | ||
136 | let mut buf = String::new(); | ||
137 | let mut count = 0; | ||
138 | self.diag(|d| { | ||
139 | format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
140 | count += 1; | ||
141 | }); | ||
142 | (buf, count) | ||
143 | } | ||
144 | |||
145 | /// Like `diagnostics`, but filtered for a single diagnostic. | ||
146 | pub fn diagnostic<D: Diagnostic>(&self) -> (String, u32) { | ||
147 | let mut buf = String::new(); | ||
148 | let mut count = 0; | ||
149 | self.diag(|d| { | ||
150 | // We want to filter diagnostics by the particular one we are testing for, to | ||
151 | // avoid surprising results in tests. | ||
152 | if d.downcast_ref::<D>().is_some() { | ||
153 | format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
154 | count += 1; | ||
155 | }; | ||
156 | }); | ||
157 | (buf, count) | ||
158 | } | ||
159 | |||
160 | pub fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { | ||
161 | let mut files = Vec::new(); | 92 | let mut files = Vec::new(); |
162 | let crate_graph = self.crate_graph(); | 93 | let crate_graph = self.crate_graph(); |
163 | for krate in crate_graph.iter() { | 94 | for krate in crate_graph.iter() { |
@@ -182,7 +113,7 @@ impl TestDB { | |||
182 | } | 113 | } |
183 | 114 | ||
184 | impl TestDB { | 115 | impl TestDB { |
185 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { | 116 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> { |
186 | *self.events.lock().unwrap() = Some(Vec::new()); | 117 | *self.events.lock().unwrap() = Some(Vec::new()); |
187 | f(); | 118 | f(); |
188 | self.events.lock().unwrap().take().unwrap() | 119 | self.events.lock().unwrap().take().unwrap() |
@@ -196,7 +127,7 @@ impl TestDB { | |||
196 | // This pretty horrible, but `Debug` is the only way to inspect | 127 | // This pretty horrible, but `Debug` is the only way to inspect |
197 | // QueryDescriptor at the moment. | 128 | // QueryDescriptor at the moment. |
198 | salsa::EventKind::WillExecute { database_key } => { | 129 | salsa::EventKind::WillExecute { database_key } => { |
199 | Some(format!("{:?}", database_key)) | 130 | Some(format!("{:?}", database_key.debug(self))) |
200 | } | 131 | } |
201 | _ => None, | 132 | _ => None, |
202 | }) | 133 | }) |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index eeac34d14..45bc14c37 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -10,6 +10,7 @@ mod display_source_code; | |||
10 | 10 | ||
11 | use std::sync::Arc; | 11 | use std::sync::Arc; |
12 | 12 | ||
13 | use expect::Expect; | ||
13 | use hir_def::{ | 14 | use hir_def::{ |
14 | body::{BodySourceMap, SyntheticSyntax}, | 15 | body::{BodySourceMap, SyntheticSyntax}, |
15 | child_by_source::ChildBySource, | 16 | child_by_source::ChildBySource, |
@@ -20,8 +21,7 @@ use hir_def::{ | |||
20 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, | 21 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, |
21 | }; | 22 | }; |
22 | use hir_expand::{db::AstDatabase, InFile}; | 23 | use hir_expand::{db::AstDatabase, InFile}; |
23 | use insta::assert_snapshot; | 24 | use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; |
24 | use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase}; | ||
25 | use ra_syntax::{ | 25 | use ra_syntax::{ |
26 | algo, | 26 | algo, |
27 | ast::{self, AstNode}, | 27 | ast::{self, AstNode}, |
@@ -34,8 +34,21 @@ use crate::{ | |||
34 | }; | 34 | }; |
35 | 35 | ||
36 | // These tests compare the inference results for all expressions in a file | 36 | // These tests compare the inference results for all expressions in a file |
37 | // against snapshots of the expected results using insta. Use cargo-insta to | 37 | // against snapshots of the expected results using expect. Use |
38 | // update the snapshots. | 38 | // `env UPDATE_EXPECT=1 cargo test -p ra_hir_ty` to update the snapshots. |
39 | |||
40 | fn setup_tracing() -> tracing::subscriber::DefaultGuard { | ||
41 | use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; | ||
42 | use tracing_tree::HierarchicalLayer; | ||
43 | let filter = EnvFilter::from_env("CHALK_DEBUG"); | ||
44 | let layer = HierarchicalLayer::default() | ||
45 | .with_indent_lines(true) | ||
46 | .with_ansi(false) | ||
47 | .with_indent_amount(2) | ||
48 | .with_writer(std::io::stderr); | ||
49 | let subscriber = Registry::default().with(filter).with(layer); | ||
50 | tracing::subscriber::set_default(subscriber) | ||
51 | } | ||
39 | 52 | ||
40 | fn check_types(ra_fixture: &str) { | 53 | fn check_types(ra_fixture: &str) { |
41 | check_types_impl(ra_fixture, false) | 54 | check_types_impl(ra_fixture, false) |
@@ -46,6 +59,7 @@ fn check_types_source_code(ra_fixture: &str) { | |||
46 | } | 59 | } |
47 | 60 | ||
48 | fn check_types_impl(ra_fixture: &str, display_source: bool) { | 61 | fn check_types_impl(ra_fixture: &str, display_source: bool) { |
62 | let _tracing = setup_tracing(); | ||
49 | let db = TestDB::with_files(ra_fixture); | 63 | let db = TestDB::with_files(ra_fixture); |
50 | let mut checked_one = false; | 64 | let mut checked_one = false; |
51 | for (file_id, annotations) in db.extract_annotations() { | 65 | for (file_id, annotations) in db.extract_annotations() { |
@@ -86,6 +100,7 @@ fn infer(ra_fixture: &str) -> String { | |||
86 | } | 100 | } |
87 | 101 | ||
88 | fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | 102 | fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { |
103 | let _tracing = setup_tracing(); | ||
89 | let (db, file_id) = TestDB::with_single_file(content); | 104 | let (db, file_id) = TestDB::with_single_file(content); |
90 | 105 | ||
91 | let mut buf = String::new(); | 106 | let mut buf = String::new(); |
@@ -317,7 +332,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
317 | " | 332 | " |
318 | .to_string(); | 333 | .to_string(); |
319 | 334 | ||
320 | db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); | 335 | db.set_file_text(pos.file_id, Arc::new(new_text)); |
321 | 336 | ||
322 | { | 337 | { |
323 | let events = db.log_executed(|| { | 338 | let events = db.log_executed(|| { |
@@ -331,409 +346,14 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
331 | } | 346 | } |
332 | } | 347 | } |
333 | 348 | ||
334 | #[test] | 349 | fn check_infer(ra_fixture: &str, expect: Expect) { |
335 | fn no_such_field_diagnostics() { | 350 | let mut actual = infer(ra_fixture); |
336 | let diagnostics = TestDB::with_files( | 351 | actual.push('\n'); |
337 | r" | 352 | expect.assert_eq(&actual); |
338 | //- /lib.rs | ||
339 | struct S { foo: i32, bar: () } | ||
340 | impl S { | ||
341 | fn new() -> S { | ||
342 | S { | ||
343 | foo: 92, | ||
344 | baz: 62, | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | ", | ||
349 | ) | ||
350 | .diagnostics() | ||
351 | .0; | ||
352 | |||
353 | assert_snapshot!(diagnostics, @r###" | ||
354 | "baz: 62": no such field | ||
355 | "{\n foo: 92,\n baz: 62,\n }": Missing structure fields: | ||
356 | - bar | ||
357 | "### | ||
358 | ); | ||
359 | } | ||
360 | |||
361 | #[test] | ||
362 | fn no_such_field_with_feature_flag_diagnostics() { | ||
363 | let diagnostics = TestDB::with_files( | ||
364 | r#" | ||
365 | //- /lib.rs crate:foo cfg:feature=foo | ||
366 | struct MyStruct { | ||
367 | my_val: usize, | ||
368 | #[cfg(feature = "foo")] | ||
369 | bar: bool, | ||
370 | } | ||
371 | |||
372 | impl MyStruct { | ||
373 | #[cfg(feature = "foo")] | ||
374 | pub(crate) fn new(my_val: usize, bar: bool) -> Self { | ||
375 | Self { my_val, bar } | ||
376 | } | ||
377 | |||
378 | #[cfg(not(feature = "foo"))] | ||
379 | pub(crate) fn new(my_val: usize, _bar: bool) -> Self { | ||
380 | Self { my_val } | ||
381 | } | ||
382 | } | ||
383 | "#, | ||
384 | ) | ||
385 | .diagnostics() | ||
386 | .0; | ||
387 | |||
388 | assert_snapshot!(diagnostics, @r###""###); | ||
389 | } | ||
390 | |||
391 | #[test] | ||
392 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
393 | let diagnostics = TestDB::with_files( | ||
394 | r#" | ||
395 | //- /lib.rs crate:foo cfg:feature=foo | ||
396 | enum Foo { | ||
397 | #[cfg(not(feature = "foo"))] | ||
398 | Buz, | ||
399 | #[cfg(feature = "foo")] | ||
400 | Bar, | ||
401 | Baz | ||
402 | } | ||
403 | |||
404 | fn test_fn(f: Foo) { | ||
405 | match f { | ||
406 | Foo::Bar => {}, | ||
407 | Foo::Baz => {}, | ||
408 | } | ||
409 | } | ||
410 | "#, | ||
411 | ) | ||
412 | .diagnostics() | ||
413 | .0; | ||
414 | |||
415 | assert_snapshot!(diagnostics, @r###""###); | ||
416 | } | ||
417 | |||
418 | #[test] | ||
419 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | ||
420 | let diagnostics = TestDB::with_files( | ||
421 | r#" | ||
422 | //- /lib.rs crate:foo cfg:feature=foo | ||
423 | struct S { | ||
424 | #[cfg(feature = "foo")] | ||
425 | foo: u32, | ||
426 | #[cfg(not(feature = "foo"))] | ||
427 | bar: u32, | ||
428 | } | ||
429 | |||
430 | impl S { | ||
431 | #[cfg(feature = "foo")] | ||
432 | fn new(foo: u32) -> Self { | ||
433 | Self { foo } | ||
434 | } | ||
435 | #[cfg(not(feature = "foo"))] | ||
436 | fn new(bar: u32) -> Self { | ||
437 | Self { bar } | ||
438 | } | ||
439 | } | ||
440 | "#, | ||
441 | ) | ||
442 | .diagnostics() | ||
443 | .0; | ||
444 | |||
445 | assert_snapshot!(diagnostics, @r###""###); | ||
446 | } | ||
447 | |||
448 | #[test] | ||
449 | fn no_such_field_with_feature_flag_diagnostics_on_block_expr() { | ||
450 | let diagnostics = TestDB::with_files( | ||
451 | r#" | ||
452 | //- /lib.rs crate:foo cfg:feature=foo | ||
453 | struct S { | ||
454 | #[cfg(feature = "foo")] | ||
455 | foo: u32, | ||
456 | #[cfg(not(feature = "foo"))] | ||
457 | bar: u32, | ||
458 | } | ||
459 | |||
460 | impl S { | ||
461 | fn new(bar: u32) -> Self { | ||
462 | #[cfg(feature = "foo")] | ||
463 | { | ||
464 | Self { foo: bar } | ||
465 | } | ||
466 | #[cfg(not(feature = "foo"))] | ||
467 | { | ||
468 | Self { bar } | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | "#, | ||
473 | ) | ||
474 | .diagnostics() | ||
475 | .0; | ||
476 | |||
477 | assert_snapshot!(diagnostics, @r###""###); | ||
478 | } | ||
479 | |||
480 | #[test] | ||
481 | fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { | ||
482 | let diagnostics = TestDB::with_files( | ||
483 | r#" | ||
484 | //- /lib.rs crate:foo cfg:feature=foo | ||
485 | struct S { | ||
486 | #[cfg(feature = "foo")] | ||
487 | foo: u32, | ||
488 | #[cfg(not(feature = "foo"))] | ||
489 | bar: u32, | ||
490 | } | ||
491 | |||
492 | impl S { | ||
493 | fn new(val: u32) -> Self { | ||
494 | Self { | ||
495 | #[cfg(feature = "foo")] | ||
496 | foo: val, | ||
497 | #[cfg(not(feature = "foo"))] | ||
498 | bar: val, | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | "#, | ||
503 | ) | ||
504 | .diagnostics() | ||
505 | .0; | ||
506 | |||
507 | assert_snapshot!(diagnostics, @r###""###); | ||
508 | } | ||
509 | |||
510 | #[test] | ||
511 | fn no_such_field_with_type_macro() { | ||
512 | let diagnostics = TestDB::with_files( | ||
513 | r" | ||
514 | macro_rules! Type { | ||
515 | () => { u32 }; | ||
516 | } | ||
517 | |||
518 | struct Foo { | ||
519 | bar: Type![], | ||
520 | } | ||
521 | impl Foo { | ||
522 | fn new() -> Self { | ||
523 | Foo { bar: 0 } | ||
524 | } | ||
525 | } | ||
526 | ", | ||
527 | ) | ||
528 | .diagnostics() | ||
529 | .0; | ||
530 | |||
531 | assert_snapshot!(diagnostics, @r###""###); | ||
532 | } | 353 | } |
533 | 354 | ||
534 | #[test] | 355 | fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) { |
535 | fn missing_record_pat_field_diagnostic() { | 356 | let mut actual = infer_with_mismatches(ra_fixture, true); |
536 | let diagnostics = TestDB::with_files( | 357 | actual.push('\n'); |
537 | r" | 358 | expect.assert_eq(&actual); |
538 | //- /lib.rs | ||
539 | struct S { foo: i32, bar: () } | ||
540 | fn baz(s: S) { | ||
541 | let S { foo: _ } = s; | ||
542 | } | ||
543 | ", | ||
544 | ) | ||
545 | .diagnostics() | ||
546 | .0; | ||
547 | |||
548 | assert_snapshot!(diagnostics, @r###" | ||
549 | "{ foo: _ }": Missing structure fields: | ||
550 | - bar | ||
551 | "### | ||
552 | ); | ||
553 | } | ||
554 | |||
555 | #[test] | ||
556 | fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | ||
557 | let diagnostics = TestDB::with_files( | ||
558 | r" | ||
559 | //- /lib.rs | ||
560 | struct S { foo: i32, bar: () } | ||
561 | fn baz(s: S) -> i32 { | ||
562 | match s { | ||
563 | S { foo, .. } => foo, | ||
564 | } | ||
565 | } | ||
566 | ", | ||
567 | ) | ||
568 | .diagnostics() | ||
569 | .0; | ||
570 | |||
571 | assert_snapshot!(diagnostics, @""); | ||
572 | } | ||
573 | |||
574 | #[test] | ||
575 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
576 | let diagnostics = TestDB::with_files( | ||
577 | r" | ||
578 | //- /lib.rs | ||
579 | fn missing_unsafe() { | ||
580 | let x = &5 as *const usize; | ||
581 | let y = *x; | ||
582 | } | ||
583 | ", | ||
584 | ) | ||
585 | .diagnostics() | ||
586 | .0; | ||
587 | |||
588 | assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#); | ||
589 | } | ||
590 | |||
591 | #[test] | ||
592 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
593 | let diagnostics = TestDB::with_files( | ||
594 | r" | ||
595 | //- /lib.rs | ||
596 | unsafe fn unsafe_fn() { | ||
597 | let x = &5 as *const usize; | ||
598 | let y = *x; | ||
599 | } | ||
600 | |||
601 | fn missing_unsafe() { | ||
602 | unsafe_fn(); | ||
603 | } | ||
604 | ", | ||
605 | ) | ||
606 | .diagnostics() | ||
607 | .0; | ||
608 | |||
609 | assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#); | ||
610 | } | ||
611 | |||
612 | #[test] | ||
613 | fn missing_unsafe_diagnostic_with_unsafe_method_call() { | ||
614 | let diagnostics = TestDB::with_files( | ||
615 | r" | ||
616 | struct HasUnsafe; | ||
617 | |||
618 | impl HasUnsafe { | ||
619 | unsafe fn unsafe_fn(&self) { | ||
620 | let x = &5 as *const usize; | ||
621 | let y = *x; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | fn missing_unsafe() { | ||
626 | HasUnsafe.unsafe_fn(); | ||
627 | } | ||
628 | |||
629 | ", | ||
630 | ) | ||
631 | .diagnostics() | ||
632 | .0; | ||
633 | |||
634 | assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#); | ||
635 | } | ||
636 | |||
637 | #[test] | ||
638 | fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() { | ||
639 | let diagnostics = TestDB::with_files( | ||
640 | r" | ||
641 | fn nothing_to_see_move_along() { | ||
642 | let x = &5 as *const usize; | ||
643 | unsafe { | ||
644 | let y = *x; | ||
645 | } | ||
646 | } | ||
647 | ", | ||
648 | ) | ||
649 | .diagnostics() | ||
650 | .0; | ||
651 | |||
652 | assert_snapshot!(diagnostics, @""); | ||
653 | } | ||
654 | |||
655 | #[test] | ||
656 | fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() { | ||
657 | let diagnostics = TestDB::with_files( | ||
658 | r" | ||
659 | fn nothing_to_see_move_along() { | ||
660 | let x = &5 as *const usize; | ||
661 | unsafe { | ||
662 | let y = *x; | ||
663 | } | ||
664 | let z = *x; | ||
665 | } | ||
666 | ", | ||
667 | ) | ||
668 | .diagnostics() | ||
669 | .0; | ||
670 | |||
671 | assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#); | ||
672 | } | ||
673 | |||
674 | #[test] | ||
675 | fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() { | ||
676 | let diagnostics = TestDB::with_files( | ||
677 | r" | ||
678 | unsafe fn unsafe_fn() { | ||
679 | let x = &5 as *const usize; | ||
680 | let y = *x; | ||
681 | } | ||
682 | |||
683 | fn nothing_to_see_move_along() { | ||
684 | unsafe { | ||
685 | unsafe_fn(); | ||
686 | } | ||
687 | } | ||
688 | ", | ||
689 | ) | ||
690 | .diagnostics() | ||
691 | .0; | ||
692 | |||
693 | assert_snapshot!(diagnostics, @""); | ||
694 | } | ||
695 | |||
696 | #[test] | ||
697 | fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() { | ||
698 | let diagnostics = TestDB::with_files( | ||
699 | r" | ||
700 | struct HasUnsafe; | ||
701 | |||
702 | impl HasUnsafe { | ||
703 | unsafe fn unsafe_fn() { | ||
704 | let x = &5 as *const usize; | ||
705 | let y = *x; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | fn nothing_to_see_move_along() { | ||
710 | unsafe { | ||
711 | HasUnsafe.unsafe_fn(); | ||
712 | } | ||
713 | } | ||
714 | |||
715 | ", | ||
716 | ) | ||
717 | .diagnostics() | ||
718 | .0; | ||
719 | |||
720 | assert_snapshot!(diagnostics, @""); | ||
721 | } | ||
722 | |||
723 | #[test] | ||
724 | fn break_outside_of_loop() { | ||
725 | let diagnostics = TestDB::with_files( | ||
726 | r" | ||
727 | //- /lib.rs | ||
728 | fn foo() { | ||
729 | break; | ||
730 | } | ||
731 | ", | ||
732 | ) | ||
733 | .diagnostics() | ||
734 | .0; | ||
735 | |||
736 | assert_snapshot!(diagnostics, @r###""break": break outside of loop | ||
737 | "### | ||
738 | ); | ||
739 | } | 359 | } |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 136d28a91..17efd75cb 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -1,345 +1,381 @@ | |||
1 | use insta::assert_snapshot; | 1 | use expect::expect; |
2 | use test_utils::mark; | 2 | use test_utils::mark; |
3 | 3 | ||
4 | use super::infer_with_mismatches; | 4 | use super::{check_infer, check_infer_with_mismatches}; |
5 | |||
6 | // Infer with some common definitions and impls. | ||
7 | fn infer(source: &str) -> String { | ||
8 | let defs = r#" | ||
9 | #[lang = "sized"] | ||
10 | pub trait Sized {} | ||
11 | #[lang = "unsize"] | ||
12 | pub trait Unsize<T: ?Sized> {} | ||
13 | #[lang = "coerce_unsized"] | ||
14 | pub trait CoerceUnsized<T> {} | ||
15 | |||
16 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
17 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
18 | "#; | ||
19 | |||
20 | // Append to the end to keep positions unchanged. | ||
21 | super::infer(&format!("{}{}", source, defs)) | ||
22 | } | ||
23 | 5 | ||
24 | #[test] | 6 | #[test] |
25 | fn infer_block_expr_type_mismatch() { | 7 | fn infer_block_expr_type_mismatch() { |
26 | assert_snapshot!( | 8 | check_infer( |
27 | infer(r#" | 9 | r" |
28 | fn test() { | 10 | fn test() { |
29 | let a: i32 = { 1i64 }; | 11 | let a: i32 = { 1i64 }; |
30 | } | 12 | } |
31 | "#), | 13 | ", |
32 | @r###" | 14 | expect![[r" |
33 | 10..40 '{ ...4 }; }': () | 15 | 10..40 '{ ...4 }; }': () |
34 | 20..21 'a': i32 | 16 | 20..21 'a': i32 |
35 | 29..37 '{ 1i64 }': i64 | 17 | 29..37 '{ 1i64 }': i64 |
36 | 31..35 '1i64': i64 | 18 | 31..35 '1i64': i64 |
37 | "###); | 19 | "]], |
20 | ); | ||
38 | } | 21 | } |
39 | 22 | ||
40 | #[test] | 23 | #[test] |
41 | fn coerce_places() { | 24 | fn coerce_places() { |
42 | assert_snapshot!( | 25 | check_infer( |
43 | infer(r#" | 26 | r#" |
44 | struct S<T> { a: T } | 27 | struct S<T> { a: T } |
45 | 28 | ||
46 | fn f<T>(_: &[T]) -> T { loop {} } | 29 | fn f<T>(_: &[T]) -> T { loop {} } |
47 | fn g<T>(_: S<&[T]>) -> T { loop {} } | 30 | fn g<T>(_: S<&[T]>) -> T { loop {} } |
48 | 31 | ||
49 | fn gen<T>() -> *mut [T; 2] { loop {} } | 32 | fn gen<T>() -> *mut [T; 2] { loop {} } |
50 | fn test1<U>() -> *mut [U] { | 33 | fn test1<U>() -> *mut [U] { |
51 | gen() | 34 | gen() |
52 | } | 35 | } |
53 | 36 | ||
54 | fn test2() { | 37 | fn test2() { |
55 | let arr: &[u8; 1] = &[1]; | 38 | let arr: &[u8; 1] = &[1]; |
56 | 39 | ||
57 | let a: &[_] = arr; | 40 | let a: &[_] = arr; |
58 | let b = f(arr); | 41 | let b = f(arr); |
59 | let c: &[_] = { arr }; | 42 | let c: &[_] = { arr }; |
60 | let d = g(S { a: arr }); | 43 | let d = g(S { a: arr }); |
61 | let e: [&[_]; 1] = [arr]; | 44 | let e: [&[_]; 1] = [arr]; |
62 | let f: [&[_]; 2] = [arr; 2]; | 45 | let f: [&[_]; 2] = [arr; 2]; |
63 | let g: (&[_], &[_]) = (arr, arr); | 46 | let g: (&[_], &[_]) = (arr, arr); |
64 | } | 47 | } |
65 | "#), | 48 | |
66 | @r###" | 49 | #[lang = "sized"] |
67 | 30..31 '_': &[T] | 50 | pub trait Sized {} |
68 | 44..55 '{ loop {} }': T | 51 | #[lang = "unsize"] |
69 | 46..53 'loop {}': ! | 52 | pub trait Unsize<T: ?Sized> {} |
70 | 51..53 '{}': () | 53 | #[lang = "coerce_unsized"] |
71 | 64..65 '_': S<&[T]> | 54 | pub trait CoerceUnsized<T> {} |
72 | 81..92 '{ loop {} }': T | 55 | |
73 | 83..90 'loop {}': ! | 56 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} |
74 | 88..90 '{}': () | 57 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} |
75 | 121..132 '{ loop {} }': *mut [T; _] | 58 | "#, |
76 | 123..130 'loop {}': ! | 59 | expect![[r" |
77 | 128..130 '{}': () | 60 | 30..31 '_': &[T] |
78 | 159..172 '{ gen() }': *mut [U] | 61 | 44..55 '{ loop {} }': T |
79 | 165..168 'gen': fn gen<U>() -> *mut [U; _] | 62 | 46..53 'loop {}': ! |
80 | 165..170 'gen()': *mut [U; _] | 63 | 51..53 '{}': () |
81 | 185..419 '{ ...rr); }': () | 64 | 64..65 '_': S<&[T]> |
82 | 195..198 'arr': &[u8; _] | 65 | 81..92 '{ loop {} }': T |
83 | 211..215 '&[1]': &[u8; _] | 66 | 83..90 'loop {}': ! |
84 | 212..215 '[1]': [u8; _] | 67 | 88..90 '{}': () |
85 | 213..214 '1': u8 | 68 | 121..132 '{ loop {} }': *mut [T; _] |
86 | 226..227 'a': &[u8] | 69 | 123..130 'loop {}': ! |
87 | 236..239 'arr': &[u8; _] | 70 | 128..130 '{}': () |
88 | 249..250 'b': u8 | 71 | 159..172 '{ gen() }': *mut [U] |
89 | 253..254 'f': fn f<u8>(&[u8]) -> u8 | 72 | 165..168 'gen': fn gen<U>() -> *mut [U; _] |
90 | 253..259 'f(arr)': u8 | 73 | 165..170 'gen()': *mut [U; _] |
91 | 255..258 'arr': &[u8; _] | 74 | 185..419 '{ ...rr); }': () |
92 | 269..270 'c': &[u8] | 75 | 195..198 'arr': &[u8; _] |
93 | 279..286 '{ arr }': &[u8] | 76 | 211..215 '&[1]': &[u8; _] |
94 | 281..284 'arr': &[u8; _] | 77 | 212..215 '[1]': [u8; _] |
95 | 296..297 'd': u8 | 78 | 213..214 '1': u8 |
96 | 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 | 79 | 226..227 'a': &[u8] |
97 | 300..315 'g(S { a: arr })': u8 | 80 | 236..239 'arr': &[u8; _] |
98 | 302..314 'S { a: arr }': S<&[u8]> | 81 | 249..250 'b': u8 |
99 | 309..312 'arr': &[u8; _] | 82 | 253..254 'f': fn f<u8>(&[u8]) -> u8 |
100 | 325..326 'e': [&[u8]; _] | 83 | 253..259 'f(arr)': u8 |
101 | 340..345 '[arr]': [&[u8]; _] | 84 | 255..258 'arr': &[u8; _] |
102 | 341..344 'arr': &[u8; _] | 85 | 269..270 'c': &[u8] |
103 | 355..356 'f': [&[u8]; _] | 86 | 279..286 '{ arr }': &[u8] |
104 | 370..378 '[arr; 2]': [&[u8]; _] | 87 | 281..284 'arr': &[u8; _] |
105 | 371..374 'arr': &[u8; _] | 88 | 296..297 'd': u8 |
106 | 376..377 '2': usize | 89 | 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 |
107 | 388..389 'g': (&[u8], &[u8]) | 90 | 300..315 'g(S { a: arr })': u8 |
108 | 406..416 '(arr, arr)': (&[u8], &[u8]) | 91 | 302..314 'S { a: arr }': S<&[u8]> |
109 | 407..410 'arr': &[u8; _] | 92 | 309..312 'arr': &[u8; _] |
110 | 412..415 'arr': &[u8; _] | 93 | 325..326 'e': [&[u8]; _] |
111 | "### | 94 | 340..345 '[arr]': [&[u8]; _] |
95 | 341..344 'arr': &[u8; _] | ||
96 | 355..356 'f': [&[u8]; _] | ||
97 | 370..378 '[arr; 2]': [&[u8]; _] | ||
98 | 371..374 'arr': &[u8; _] | ||
99 | 376..377 '2': usize | ||
100 | 388..389 'g': (&[u8], &[u8]) | ||
101 | 406..416 '(arr, arr)': (&[u8], &[u8]) | ||
102 | 407..410 'arr': &[u8; _] | ||
103 | 412..415 'arr': &[u8; _] | ||
104 | "]], | ||
112 | ); | 105 | ); |
113 | } | 106 | } |
114 | 107 | ||
115 | #[test] | 108 | #[test] |
116 | fn infer_let_stmt_coerce() { | 109 | fn infer_let_stmt_coerce() { |
117 | assert_snapshot!( | 110 | check_infer( |
118 | infer(r#" | 111 | r" |
119 | fn test() { | 112 | fn test() { |
120 | let x: &[isize] = &[1]; | 113 | let x: &[isize] = &[1]; |
121 | let x: *const [isize] = &[1]; | 114 | let x: *const [isize] = &[1]; |
122 | } | 115 | } |
123 | "#), | 116 | ", |
124 | @r###" | 117 | expect![[r" |
125 | 10..75 '{ ...[1]; }': () | 118 | 10..75 '{ ...[1]; }': () |
126 | 20..21 'x': &[isize] | 119 | 20..21 'x': &[isize] |
127 | 34..38 '&[1]': &[isize; _] | 120 | 34..38 '&[1]': &[isize; _] |
128 | 35..38 '[1]': [isize; _] | 121 | 35..38 '[1]': [isize; _] |
129 | 36..37 '1': isize | 122 | 36..37 '1': isize |
130 | 48..49 'x': *const [isize] | 123 | 48..49 'x': *const [isize] |
131 | 68..72 '&[1]': &[isize; _] | 124 | 68..72 '&[1]': &[isize; _] |
132 | 69..72 '[1]': [isize; _] | 125 | 69..72 '[1]': [isize; _] |
133 | 70..71 '1': isize | 126 | 70..71 '1': isize |
134 | "###); | 127 | "]], |
128 | ); | ||
135 | } | 129 | } |
136 | 130 | ||
137 | #[test] | 131 | #[test] |
138 | fn infer_custom_coerce_unsized() { | 132 | fn infer_custom_coerce_unsized() { |
139 | assert_snapshot!( | 133 | check_infer( |
140 | infer(r#" | 134 | r#" |
141 | struct A<T: ?Sized>(*const T); | 135 | struct A<T: ?Sized>(*const T); |
142 | struct B<T: ?Sized>(*const T); | 136 | struct B<T: ?Sized>(*const T); |
143 | struct C<T: ?Sized> { inner: *const T } | 137 | struct C<T: ?Sized> { inner: *const T } |
144 | 138 | ||
145 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} | 139 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} |
146 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} | 140 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} |
147 | 141 | ||
148 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } | 142 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } |
149 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } | 143 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } |
150 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } | 144 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } |
151 | 145 | ||
152 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { | 146 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { |
153 | let d = foo1(a); | 147 | let d = foo1(a); |
154 | let e = foo2(b); | 148 | let e = foo2(b); |
155 | let f = foo3(c); | 149 | let f = foo3(c); |
156 | } | 150 | } |
157 | "#), | 151 | |
158 | @r###" | 152 | |
159 | 257..258 'x': A<[T]> | 153 | #[lang = "sized"] |
160 | 278..283 '{ x }': A<[T]> | 154 | pub trait Sized {} |
161 | 280..281 'x': A<[T]> | 155 | #[lang = "unsize"] |
162 | 295..296 'x': B<[T]> | 156 | pub trait Unsize<T: ?Sized> {} |
163 | 316..321 '{ x }': B<[T]> | 157 | #[lang = "coerce_unsized"] |
164 | 318..319 'x': B<[T]> | 158 | pub trait CoerceUnsized<T> {} |
165 | 333..334 'x': C<[T]> | 159 | |
166 | 354..359 '{ x }': C<[T]> | 160 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} |
167 | 356..357 'x': C<[T]> | 161 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} |
168 | 369..370 'a': A<[u8; _]> | 162 | "#, |
169 | 384..385 'b': B<[u8; _]> | 163 | expect![[r" |
170 | 399..400 'c': C<[u8; _]> | 164 | 257..258 'x': A<[T]> |
171 | 414..480 '{ ...(c); }': () | 165 | 278..283 '{ x }': A<[T]> |
172 | 424..425 'd': A<[{unknown}]> | 166 | 280..281 'x': A<[T]> |
173 | 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> | 167 | 295..296 'x': B<[T]> |
174 | 428..435 'foo1(a)': A<[{unknown}]> | 168 | 316..321 '{ x }': B<[T]> |
175 | 433..434 'a': A<[u8; _]> | 169 | 318..319 'x': B<[T]> |
176 | 445..446 'e': B<[u8]> | 170 | 333..334 'x': C<[T]> |
177 | 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> | 171 | 354..359 '{ x }': C<[T]> |
178 | 449..456 'foo2(b)': B<[u8]> | 172 | 356..357 'x': C<[T]> |
179 | 454..455 'b': B<[u8; _]> | 173 | 369..370 'a': A<[u8; _]> |
180 | 466..467 'f': C<[u8]> | 174 | 384..385 'b': B<[u8; _]> |
181 | 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> | 175 | 399..400 'c': C<[u8; _]> |
182 | 470..477 'foo3(c)': C<[u8]> | 176 | 414..480 '{ ...(c); }': () |
183 | 475..476 'c': C<[u8; _]> | 177 | 424..425 'd': A<[{unknown}]> |
184 | "### | 178 | 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> |
179 | 428..435 'foo1(a)': A<[{unknown}]> | ||
180 | 433..434 'a': A<[u8; _]> | ||
181 | 445..446 'e': B<[u8]> | ||
182 | 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> | ||
183 | 449..456 'foo2(b)': B<[u8]> | ||
184 | 454..455 'b': B<[u8; _]> | ||
185 | 466..467 'f': C<[u8]> | ||
186 | 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> | ||
187 | 470..477 'foo3(c)': C<[u8]> | ||
188 | 475..476 'c': C<[u8; _]> | ||
189 | "]], | ||
185 | ); | 190 | ); |
186 | } | 191 | } |
187 | 192 | ||
188 | #[test] | 193 | #[test] |
189 | fn infer_if_coerce() { | 194 | fn infer_if_coerce() { |
190 | assert_snapshot!( | 195 | check_infer( |
191 | infer(r#" | 196 | r#" |
192 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 197 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
193 | fn test() { | 198 | fn test() { |
194 | let x = if true { | 199 | let x = if true { |
195 | foo(&[1]) | 200 | foo(&[1]) |
196 | } else { | 201 | } else { |
197 | &[1] | 202 | &[1] |
198 | }; | 203 | }; |
199 | } | 204 | } |
200 | "#), | 205 | |
201 | @r###" | 206 | |
202 | 10..11 'x': &[T] | 207 | #[lang = "sized"] |
203 | 27..38 '{ loop {} }': &[T] | 208 | pub trait Sized {} |
204 | 29..36 'loop {}': ! | 209 | #[lang = "unsize"] |
205 | 34..36 '{}': () | 210 | pub trait Unsize<T: ?Sized> {} |
206 | 49..125 '{ ... }; }': () | 211 | "#, |
207 | 59..60 'x': &[i32] | 212 | expect![[r" |
208 | 63..122 'if tru... }': &[i32] | 213 | 10..11 'x': &[T] |
209 | 66..70 'true': bool | 214 | 27..38 '{ loop {} }': &[T] |
210 | 71..96 '{ ... }': &[i32] | 215 | 29..36 'loop {}': ! |
211 | 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] | 216 | 34..36 '{}': () |
212 | 81..90 'foo(&[1])': &[i32] | 217 | 49..125 '{ ... }; }': () |
213 | 85..89 '&[1]': &[i32; _] | 218 | 59..60 'x': &[i32] |
214 | 86..89 '[1]': [i32; _] | 219 | 63..122 'if tru... }': &[i32] |
215 | 87..88 '1': i32 | 220 | 66..70 'true': bool |
216 | 102..122 '{ ... }': &[i32; _] | 221 | 71..96 '{ ... }': &[i32] |
217 | 112..116 '&[1]': &[i32; _] | 222 | 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] |
218 | 113..116 '[1]': [i32; _] | 223 | 81..90 'foo(&[1])': &[i32] |
219 | 114..115 '1': i32 | 224 | 85..89 '&[1]': &[i32; _] |
220 | "### | 225 | 86..89 '[1]': [i32; _] |
226 | 87..88 '1': i32 | ||
227 | 102..122 '{ ... }': &[i32; _] | ||
228 | 112..116 '&[1]': &[i32; _] | ||
229 | 113..116 '[1]': [i32; _] | ||
230 | 114..115 '1': i32 | ||
231 | "]], | ||
221 | ); | 232 | ); |
222 | } | 233 | } |
223 | 234 | ||
224 | #[test] | 235 | #[test] |
225 | fn infer_if_else_coerce() { | 236 | fn infer_if_else_coerce() { |
226 | assert_snapshot!( | 237 | check_infer( |
227 | infer(r#" | 238 | r#" |
228 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 239 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
229 | fn test() { | 240 | fn test() { |
230 | let x = if true { | 241 | let x = if true { |
231 | &[1] | 242 | &[1] |
232 | } else { | 243 | } else { |
233 | foo(&[1]) | 244 | foo(&[1]) |
234 | }; | 245 | }; |
235 | } | 246 | } |
236 | "#), | 247 | |
237 | @r###" | 248 | #[lang = "sized"] |
238 | 10..11 'x': &[T] | 249 | pub trait Sized {} |
239 | 27..38 '{ loop {} }': &[T] | 250 | #[lang = "unsize"] |
240 | 29..36 'loop {}': ! | 251 | pub trait Unsize<T: ?Sized> {} |
241 | 34..36 '{}': () | 252 | #[lang = "coerce_unsized"] |
242 | 49..125 '{ ... }; }': () | 253 | pub trait CoerceUnsized<T> {} |
243 | 59..60 'x': &[i32] | 254 | |
244 | 63..122 'if tru... }': &[i32] | 255 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} |
245 | 66..70 'true': bool | 256 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} |
246 | 71..91 '{ ... }': &[i32; _] | 257 | "#, |
247 | 81..85 '&[1]': &[i32; _] | 258 | expect![[r" |
248 | 82..85 '[1]': [i32; _] | 259 | 10..11 'x': &[T] |
249 | 83..84 '1': i32 | 260 | 27..38 '{ loop {} }': &[T] |
250 | 97..122 '{ ... }': &[i32] | 261 | 29..36 'loop {}': ! |
251 | 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] | 262 | 34..36 '{}': () |
252 | 107..116 'foo(&[1])': &[i32] | 263 | 49..125 '{ ... }; }': () |
253 | 111..115 '&[1]': &[i32; _] | 264 | 59..60 'x': &[i32] |
254 | 112..115 '[1]': [i32; _] | 265 | 63..122 'if tru... }': &[i32] |
255 | 113..114 '1': i32 | 266 | 66..70 'true': bool |
256 | "### | 267 | 71..91 '{ ... }': &[i32; _] |
257 | ); | 268 | 81..85 '&[1]': &[i32; _] |
269 | 82..85 '[1]': [i32; _] | ||
270 | 83..84 '1': i32 | ||
271 | 97..122 '{ ... }': &[i32] | ||
272 | 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
273 | 107..116 'foo(&[1])': &[i32] | ||
274 | 111..115 '&[1]': &[i32; _] | ||
275 | 112..115 '[1]': [i32; _] | ||
276 | 113..114 '1': i32 | ||
277 | "]], | ||
278 | ) | ||
258 | } | 279 | } |
259 | 280 | ||
260 | #[test] | 281 | #[test] |
261 | fn infer_match_first_coerce() { | 282 | fn infer_match_first_coerce() { |
262 | assert_snapshot!( | 283 | check_infer( |
263 | infer(r#" | 284 | r#" |
264 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 285 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
265 | fn test(i: i32) { | 286 | fn test(i: i32) { |
266 | let x = match i { | 287 | let x = match i { |
267 | 2 => foo(&[2]), | 288 | 2 => foo(&[2]), |
268 | 1 => &[1], | 289 | 1 => &[1], |
269 | _ => &[3], | 290 | _ => &[3], |
270 | }; | 291 | }; |
271 | } | 292 | } |
272 | "#), | 293 | |
273 | @r###" | 294 | #[lang = "sized"] |
274 | 10..11 'x': &[T] | 295 | pub trait Sized {} |
275 | 27..38 '{ loop {} }': &[T] | 296 | #[lang = "unsize"] |
276 | 29..36 'loop {}': ! | 297 | pub trait Unsize<T: ?Sized> {} |
277 | 34..36 '{}': () | 298 | "#, |
278 | 47..48 'i': i32 | 299 | expect![[r" |
279 | 55..149 '{ ... }; }': () | 300 | 10..11 'x': &[T] |
280 | 65..66 'x': &[i32] | 301 | 27..38 '{ loop {} }': &[T] |
281 | 69..146 'match ... }': &[i32] | 302 | 29..36 'loop {}': ! |
282 | 75..76 'i': i32 | 303 | 34..36 '{}': () |
283 | 87..88 '2': i32 | 304 | 47..48 'i': i32 |
284 | 87..88 '2': i32 | 305 | 55..149 '{ ... }; }': () |
285 | 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] | 306 | 65..66 'x': &[i32] |
286 | 92..101 'foo(&[2])': &[i32] | 307 | 69..146 'match ... }': &[i32] |
287 | 96..100 '&[2]': &[i32; _] | 308 | 75..76 'i': i32 |
288 | 97..100 '[2]': [i32; _] | 309 | 87..88 '2': i32 |
289 | 98..99 '2': i32 | 310 | 87..88 '2': i32 |
290 | 111..112 '1': i32 | 311 | 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] |
291 | 111..112 '1': i32 | 312 | 92..101 'foo(&[2])': &[i32] |
292 | 116..120 '&[1]': &[i32; _] | 313 | 96..100 '&[2]': &[i32; _] |
293 | 117..120 '[1]': [i32; _] | 314 | 97..100 '[2]': [i32; _] |
294 | 118..119 '1': i32 | 315 | 98..99 '2': i32 |
295 | 130..131 '_': i32 | 316 | 111..112 '1': i32 |
296 | 135..139 '&[3]': &[i32; _] | 317 | 111..112 '1': i32 |
297 | 136..139 '[3]': [i32; _] | 318 | 116..120 '&[1]': &[i32; _] |
298 | 137..138 '3': i32 | 319 | 117..120 '[1]': [i32; _] |
299 | "### | 320 | 118..119 '1': i32 |
321 | 130..131 '_': i32 | ||
322 | 135..139 '&[3]': &[i32; _] | ||
323 | 136..139 '[3]': [i32; _] | ||
324 | 137..138 '3': i32 | ||
325 | "]], | ||
300 | ); | 326 | ); |
301 | } | 327 | } |
302 | 328 | ||
303 | #[test] | 329 | #[test] |
304 | fn infer_match_second_coerce() { | 330 | fn infer_match_second_coerce() { |
305 | assert_snapshot!( | 331 | check_infer( |
306 | infer(r#" | 332 | r#" |
307 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 333 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
308 | fn test(i: i32) { | 334 | fn test(i: i32) { |
309 | let x = match i { | 335 | let x = match i { |
310 | 1 => &[1], | 336 | 1 => &[1], |
311 | 2 => foo(&[2]), | 337 | 2 => foo(&[2]), |
312 | _ => &[3], | 338 | _ => &[3], |
313 | }; | 339 | }; |
314 | } | 340 | } |
315 | "#), | 341 | |
316 | @r###" | 342 | #[lang = "sized"] |
317 | 10..11 'x': &[T] | 343 | pub trait Sized {} |
318 | 27..38 '{ loop {} }': &[T] | 344 | #[lang = "unsize"] |
319 | 29..36 'loop {}': ! | 345 | pub trait Unsize<T: ?Sized> {} |
320 | 34..36 '{}': () | 346 | #[lang = "coerce_unsized"] |
321 | 47..48 'i': i32 | 347 | pub trait CoerceUnsized<T> {} |
322 | 55..149 '{ ... }; }': () | 348 | |
323 | 65..66 'x': &[i32] | 349 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} |
324 | 69..146 'match ... }': &[i32] | 350 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} |
325 | 75..76 'i': i32 | 351 | "#, |
326 | 87..88 '1': i32 | 352 | expect![[r" |
327 | 87..88 '1': i32 | 353 | 10..11 'x': &[T] |
328 | 92..96 '&[1]': &[i32; _] | 354 | 27..38 '{ loop {} }': &[T] |
329 | 93..96 '[1]': [i32; _] | 355 | 29..36 'loop {}': ! |
330 | 94..95 '1': i32 | 356 | 34..36 '{}': () |
331 | 106..107 '2': i32 | 357 | 47..48 'i': i32 |
332 | 106..107 '2': i32 | 358 | 55..149 '{ ... }; }': () |
333 | 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] | 359 | 65..66 'x': &[i32] |
334 | 111..120 'foo(&[2])': &[i32] | 360 | 69..146 'match ... }': &[i32] |
335 | 115..119 '&[2]': &[i32; _] | 361 | 75..76 'i': i32 |
336 | 116..119 '[2]': [i32; _] | 362 | 87..88 '1': i32 |
337 | 117..118 '2': i32 | 363 | 87..88 '1': i32 |
338 | 130..131 '_': i32 | 364 | 92..96 '&[1]': &[i32; _] |
339 | 135..139 '&[3]': &[i32; _] | 365 | 93..96 '[1]': [i32; _] |
340 | 136..139 '[3]': [i32; _] | 366 | 94..95 '1': i32 |
341 | 137..138 '3': i32 | 367 | 106..107 '2': i32 |
342 | "### | 368 | 106..107 '2': i32 |
369 | 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
370 | 111..120 'foo(&[2])': &[i32] | ||
371 | 115..119 '&[2]': &[i32; _] | ||
372 | 116..119 '[2]': [i32; _] | ||
373 | 117..118 '2': i32 | ||
374 | 130..131 '_': i32 | ||
375 | 135..139 '&[3]': &[i32; _] | ||
376 | 136..139 '[3]': [i32; _] | ||
377 | 137..138 '3': i32 | ||
378 | "]], | ||
343 | ); | 379 | ); |
344 | } | 380 | } |
345 | 381 | ||
@@ -347,405 +383,453 @@ fn test(i: i32) { | |||
347 | fn coerce_merge_one_by_one1() { | 383 | fn coerce_merge_one_by_one1() { |
348 | mark::check!(coerce_merge_fail_fallback); | 384 | mark::check!(coerce_merge_fail_fallback); |
349 | 385 | ||
350 | assert_snapshot!( | 386 | check_infer( |
351 | infer(r#" | 387 | r" |
352 | fn test() { | 388 | fn test() { |
353 | let t = &mut 1; | 389 | let t = &mut 1; |
354 | let x = match 1 { | 390 | let x = match 1 { |
355 | 1 => t as *mut i32, | 391 | 1 => t as *mut i32, |
356 | 2 => t as &i32, | 392 | 2 => t as &i32, |
357 | _ => t as *const i32, | 393 | _ => t as *const i32, |
358 | }; | 394 | }; |
359 | } | 395 | } |
360 | "#), | 396 | ", |
361 | @r###" | 397 | expect![[r" |
362 | 10..144 '{ ... }; }': () | 398 | 10..144 '{ ... }; }': () |
363 | 20..21 't': &mut i32 | 399 | 20..21 't': &mut i32 |
364 | 24..30 '&mut 1': &mut i32 | 400 | 24..30 '&mut 1': &mut i32 |
365 | 29..30 '1': i32 | 401 | 29..30 '1': i32 |
366 | 40..41 'x': *const i32 | 402 | 40..41 'x': *const i32 |
367 | 44..141 'match ... }': *const i32 | 403 | 44..141 'match ... }': *const i32 |
368 | 50..51 '1': i32 | 404 | 50..51 '1': i32 |
369 | 62..63 '1': i32 | 405 | 62..63 '1': i32 |
370 | 62..63 '1': i32 | 406 | 62..63 '1': i32 |
371 | 67..68 't': &mut i32 | 407 | 67..68 't': &mut i32 |
372 | 67..80 't as *mut i32': *mut i32 | 408 | 67..80 't as *mut i32': *mut i32 |
373 | 90..91 '2': i32 | 409 | 90..91 '2': i32 |
374 | 90..91 '2': i32 | 410 | 90..91 '2': i32 |
375 | 95..96 't': &mut i32 | 411 | 95..96 't': &mut i32 |
376 | 95..104 't as &i32': &i32 | 412 | 95..104 't as &i32': &i32 |
377 | 114..115 '_': i32 | 413 | 114..115 '_': i32 |
378 | 119..120 't': &mut i32 | 414 | 119..120 't': &mut i32 |
379 | 119..134 't as *const i32': *const i32 | 415 | 119..134 't as *const i32': *const i32 |
380 | "### | 416 | "]], |
381 | ); | 417 | ); |
382 | } | 418 | } |
383 | 419 | ||
384 | #[test] | 420 | #[test] |
385 | fn return_coerce_unknown() { | 421 | fn return_coerce_unknown() { |
386 | assert_snapshot!( | 422 | check_infer_with_mismatches( |
387 | infer_with_mismatches(r#" | 423 | r" |
388 | fn foo() -> u32 { | 424 | fn foo() -> u32 { |
389 | return unknown; | 425 | return unknown; |
390 | } | 426 | } |
391 | "#, true), | 427 | ", |
392 | @r###" | 428 | expect![[r" |
393 | 16..39 '{ ...own; }': u32 | 429 | 16..39 '{ ...own; }': u32 |
394 | 22..36 'return unknown': ! | 430 | 22..36 'return unknown': ! |
395 | 29..36 'unknown': u32 | 431 | 29..36 'unknown': u32 |
396 | "### | 432 | "]], |
397 | ); | 433 | ); |
398 | } | 434 | } |
399 | 435 | ||
400 | #[test] | 436 | #[test] |
401 | fn coerce_autoderef() { | 437 | fn coerce_autoderef() { |
402 | assert_snapshot!( | 438 | check_infer_with_mismatches( |
403 | infer_with_mismatches(r#" | 439 | r" |
404 | struct Foo; | 440 | struct Foo; |
405 | fn takes_ref_foo(x: &Foo) {} | 441 | fn takes_ref_foo(x: &Foo) {} |
406 | fn test() { | 442 | fn test() { |
407 | takes_ref_foo(&Foo); | 443 | takes_ref_foo(&Foo); |
408 | takes_ref_foo(&&Foo); | 444 | takes_ref_foo(&&Foo); |
409 | takes_ref_foo(&&&Foo); | 445 | takes_ref_foo(&&&Foo); |
410 | } | 446 | } |
411 | "#, true), | 447 | ", |
412 | @r###" | 448 | expect![[r" |
413 | 29..30 'x': &Foo | 449 | 29..30 'x': &Foo |
414 | 38..40 '{}': () | 450 | 38..40 '{}': () |
415 | 51..132 '{ ...oo); }': () | 451 | 51..132 '{ ...oo); }': () |
416 | 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) | 452 | 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) |
417 | 57..76 'takes_...(&Foo)': () | 453 | 57..76 'takes_...(&Foo)': () |
418 | 71..75 '&Foo': &Foo | 454 | 71..75 '&Foo': &Foo |
419 | 72..75 'Foo': Foo | 455 | 72..75 'Foo': Foo |
420 | 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) | 456 | 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) |
421 | 82..102 'takes_...&&Foo)': () | 457 | 82..102 'takes_...&&Foo)': () |
422 | 96..101 '&&Foo': &&Foo | 458 | 96..101 '&&Foo': &&Foo |
423 | 97..101 '&Foo': &Foo | 459 | 97..101 '&Foo': &Foo |
424 | 98..101 'Foo': Foo | 460 | 98..101 'Foo': Foo |
425 | 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) | 461 | 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) |
426 | 108..129 'takes_...&&Foo)': () | 462 | 108..129 'takes_...&&Foo)': () |
427 | 122..128 '&&&Foo': &&&Foo | 463 | 122..128 '&&&Foo': &&&Foo |
428 | 123..128 '&&Foo': &&Foo | 464 | 123..128 '&&Foo': &&Foo |
429 | 124..128 '&Foo': &Foo | 465 | 124..128 '&Foo': &Foo |
430 | 125..128 'Foo': Foo | 466 | 125..128 'Foo': Foo |
431 | "### | 467 | "]], |
432 | ); | 468 | ); |
433 | } | 469 | } |
434 | 470 | ||
435 | #[test] | 471 | #[test] |
436 | fn coerce_autoderef_generic() { | 472 | fn coerce_autoderef_generic() { |
437 | assert_snapshot!( | 473 | check_infer_with_mismatches( |
438 | infer_with_mismatches(r#" | 474 | r" |
439 | struct Foo; | 475 | struct Foo; |
440 | fn takes_ref<T>(x: &T) -> T { *x } | 476 | fn takes_ref<T>(x: &T) -> T { *x } |
441 | fn test() { | 477 | fn test() { |
442 | takes_ref(&Foo); | 478 | takes_ref(&Foo); |
443 | takes_ref(&&Foo); | 479 | takes_ref(&&Foo); |
444 | takes_ref(&&&Foo); | 480 | takes_ref(&&&Foo); |
445 | } | 481 | } |
446 | "#, true), | 482 | ", |
447 | @r###" | 483 | expect![[r" |
448 | 28..29 'x': &T | 484 | 28..29 'x': &T |
449 | 40..46 '{ *x }': T | 485 | 40..46 '{ *x }': T |
450 | 42..44 '*x': T | 486 | 42..44 '*x': T |
451 | 43..44 'x': &T | 487 | 43..44 'x': &T |
452 | 57..126 '{ ...oo); }': () | 488 | 57..126 '{ ...oo); }': () |
453 | 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo | 489 | 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo |
454 | 63..78 'takes_ref(&Foo)': Foo | 490 | 63..78 'takes_ref(&Foo)': Foo |
455 | 73..77 '&Foo': &Foo | 491 | 73..77 '&Foo': &Foo |
456 | 74..77 'Foo': Foo | 492 | 74..77 'Foo': Foo |
457 | 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo | 493 | 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo |
458 | 84..100 'takes_...&&Foo)': &Foo | 494 | 84..100 'takes_...&&Foo)': &Foo |
459 | 94..99 '&&Foo': &&Foo | 495 | 94..99 '&&Foo': &&Foo |
460 | 95..99 '&Foo': &Foo | 496 | 95..99 '&Foo': &Foo |
461 | 96..99 'Foo': Foo | 497 | 96..99 'Foo': Foo |
462 | 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo | 498 | 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo |
463 | 106..123 'takes_...&&Foo)': &&Foo | 499 | 106..123 'takes_...&&Foo)': &&Foo |
464 | 116..122 '&&&Foo': &&&Foo | 500 | 116..122 '&&&Foo': &&&Foo |
465 | 117..122 '&&Foo': &&Foo | 501 | 117..122 '&&Foo': &&Foo |
466 | 118..122 '&Foo': &Foo | 502 | 118..122 '&Foo': &Foo |
467 | 119..122 'Foo': Foo | 503 | 119..122 'Foo': Foo |
468 | "### | 504 | "]], |
469 | ); | 505 | ); |
470 | } | 506 | } |
471 | 507 | ||
472 | #[test] | 508 | #[test] |
473 | fn coerce_autoderef_block() { | 509 | fn coerce_autoderef_block() { |
474 | assert_snapshot!( | 510 | check_infer_with_mismatches( |
475 | infer_with_mismatches(r#" | 511 | r#" |
476 | struct String {} | 512 | struct String {} |
477 | #[lang = "deref"] | 513 | #[lang = "deref"] |
478 | trait Deref { type Target; } | 514 | trait Deref { type Target; } |
479 | impl Deref for String { type Target = str; } | 515 | impl Deref for String { type Target = str; } |
480 | fn takes_ref_str(x: &str) {} | 516 | fn takes_ref_str(x: &str) {} |
481 | fn returns_string() -> String { loop {} } | 517 | fn returns_string() -> String { loop {} } |
482 | fn test() { | 518 | fn test() { |
483 | takes_ref_str(&{ returns_string() }); | 519 | takes_ref_str(&{ returns_string() }); |
484 | } | 520 | } |
485 | "#, true), | 521 | "#, |
486 | @r###" | 522 | expect![[r" |
487 | 126..127 'x': &str | 523 | 126..127 'x': &str |
488 | 135..137 '{}': () | 524 | 135..137 '{}': () |
489 | 168..179 '{ loop {} }': String | 525 | 168..179 '{ loop {} }': String |
490 | 170..177 'loop {}': ! | 526 | 170..177 'loop {}': ! |
491 | 175..177 '{}': () | 527 | 175..177 '{}': () |
492 | 190..235 '{ ... }); }': () | 528 | 190..235 '{ ... }); }': () |
493 | 196..209 'takes_ref_str': fn takes_ref_str(&str) | 529 | 196..209 'takes_ref_str': fn takes_ref_str(&str) |
494 | 196..232 'takes_...g() })': () | 530 | 196..232 'takes_...g() })': () |
495 | 210..231 '&{ ret...ng() }': &String | 531 | 210..231 '&{ ret...ng() }': &String |
496 | 211..231 '{ retu...ng() }': String | 532 | 211..231 '{ retu...ng() }': String |
497 | 213..227 'returns_string': fn returns_string() -> String | 533 | 213..227 'returns_string': fn returns_string() -> String |
498 | 213..229 'return...ring()': String | 534 | 213..229 'return...ring()': String |
499 | "### | 535 | "]], |
500 | ); | 536 | ); |
501 | } | 537 | } |
502 | 538 | ||
503 | #[test] | 539 | #[test] |
504 | fn closure_return_coerce() { | 540 | fn closure_return_coerce() { |
505 | assert_snapshot!( | 541 | check_infer_with_mismatches( |
506 | infer_with_mismatches(r#" | 542 | r" |
507 | fn foo() { | 543 | fn foo() { |
508 | let x = || { | 544 | let x = || { |
509 | if true { | 545 | if true { |
510 | return &1u32; | 546 | return &1u32; |
547 | } | ||
548 | &&1u32 | ||
549 | }; | ||
511 | } | 550 | } |
512 | &&1u32 | 551 | ", |
513 | }; | 552 | expect![[r" |
514 | } | 553 | 9..105 '{ ... }; }': () |
515 | "#, true), | 554 | 19..20 'x': || -> &u32 |
516 | @r###" | 555 | 23..102 '|| { ... }': || -> &u32 |
517 | 9..105 '{ ... }; }': () | 556 | 26..102 '{ ... }': &u32 |
518 | 19..20 'x': || -> &u32 | 557 | 36..81 'if tru... }': () |
519 | 23..102 '|| { ... }': || -> &u32 | 558 | 39..43 'true': bool |
520 | 26..102 '{ ... }': &u32 | 559 | 44..81 '{ ... }': () |
521 | 36..81 'if tru... }': () | 560 | 58..70 'return &1u32': ! |
522 | 39..43 'true': bool | 561 | 65..70 '&1u32': &u32 |
523 | 44..81 '{ ... }': () | 562 | 66..70 '1u32': u32 |
524 | 58..70 'return &1u32': ! | 563 | 90..96 '&&1u32': &&u32 |
525 | 65..70 '&1u32': &u32 | 564 | 91..96 '&1u32': &u32 |
526 | 66..70 '1u32': u32 | 565 | 92..96 '1u32': u32 |
527 | 90..96 '&&1u32': &&u32 | 566 | "]], |
528 | 91..96 '&1u32': &u32 | ||
529 | 92..96 '1u32': u32 | ||
530 | "### | ||
531 | ); | 567 | ); |
532 | } | 568 | } |
533 | 569 | ||
534 | #[test] | 570 | #[test] |
535 | fn coerce_fn_item_to_fn_ptr() { | 571 | fn coerce_fn_item_to_fn_ptr() { |
536 | assert_snapshot!( | 572 | check_infer_with_mismatches( |
537 | infer_with_mismatches(r#" | 573 | r" |
538 | fn foo(x: u32) -> isize { 1 } | 574 | fn foo(x: u32) -> isize { 1 } |
539 | fn test() { | 575 | fn test() { |
540 | let f: fn(u32) -> isize = foo; | 576 | let f: fn(u32) -> isize = foo; |
541 | } | 577 | } |
542 | "#, true), | 578 | ", |
543 | @r###" | 579 | expect![[r" |
544 | 7..8 'x': u32 | 580 | 7..8 'x': u32 |
545 | 24..29 '{ 1 }': isize | 581 | 24..29 '{ 1 }': isize |
546 | 26..27 '1': isize | 582 | 26..27 '1': isize |
547 | 40..78 '{ ...foo; }': () | 583 | 40..78 '{ ...foo; }': () |
548 | 50..51 'f': fn(u32) -> isize | 584 | 50..51 'f': fn(u32) -> isize |
549 | 72..75 'foo': fn foo(u32) -> isize | 585 | 72..75 'foo': fn foo(u32) -> isize |
550 | "### | 586 | "]], |
551 | ); | 587 | ); |
552 | } | 588 | } |
553 | 589 | ||
554 | #[test] | 590 | #[test] |
555 | fn coerce_fn_items_in_match_arms() { | 591 | fn coerce_fn_items_in_match_arms() { |
556 | mark::check!(coerce_fn_reification); | 592 | mark::check!(coerce_fn_reification); |
557 | assert_snapshot!( | 593 | |
558 | infer_with_mismatches(r#" | 594 | check_infer_with_mismatches( |
559 | fn foo1(x: u32) -> isize { 1 } | 595 | r" |
560 | fn foo2(x: u32) -> isize { 2 } | 596 | fn foo1(x: u32) -> isize { 1 } |
561 | fn foo3(x: u32) -> isize { 3 } | 597 | fn foo2(x: u32) -> isize { 2 } |
562 | fn test() { | 598 | fn foo3(x: u32) -> isize { 3 } |
563 | let x = match 1 { | 599 | fn test() { |
564 | 1 => foo1, | 600 | let x = match 1 { |
565 | 2 => foo2, | 601 | 1 => foo1, |
566 | _ => foo3, | 602 | 2 => foo2, |
567 | }; | 603 | _ => foo3, |
568 | } | 604 | }; |
569 | "#, true), | 605 | } |
570 | @r###" | 606 | ", |
571 | 8..9 'x': u32 | 607 | expect![[r" |
572 | 25..30 '{ 1 }': isize | 608 | 8..9 'x': u32 |
573 | 27..28 '1': isize | 609 | 25..30 '{ 1 }': isize |
574 | 39..40 'x': u32 | 610 | 27..28 '1': isize |
575 | 56..61 '{ 2 }': isize | 611 | 39..40 'x': u32 |
576 | 58..59 '2': isize | 612 | 56..61 '{ 2 }': isize |
577 | 70..71 'x': u32 | 613 | 58..59 '2': isize |
578 | 87..92 '{ 3 }': isize | 614 | 70..71 'x': u32 |
579 | 89..90 '3': isize | 615 | 87..92 '{ 3 }': isize |
580 | 103..192 '{ ... }; }': () | 616 | 89..90 '3': isize |
581 | 113..114 'x': fn(u32) -> isize | 617 | 103..192 '{ ... }; }': () |
582 | 117..189 'match ... }': fn(u32) -> isize | 618 | 113..114 'x': fn(u32) -> isize |
583 | 123..124 '1': i32 | 619 | 117..189 'match ... }': fn(u32) -> isize |
584 | 135..136 '1': i32 | 620 | 123..124 '1': i32 |
585 | 135..136 '1': i32 | 621 | 135..136 '1': i32 |
586 | 140..144 'foo1': fn foo1(u32) -> isize | 622 | 135..136 '1': i32 |
587 | 154..155 '2': i32 | 623 | 140..144 'foo1': fn foo1(u32) -> isize |
588 | 154..155 '2': i32 | 624 | 154..155 '2': i32 |
589 | 159..163 'foo2': fn foo2(u32) -> isize | 625 | 154..155 '2': i32 |
590 | 173..174 '_': i32 | 626 | 159..163 'foo2': fn foo2(u32) -> isize |
591 | 178..182 'foo3': fn foo3(u32) -> isize | 627 | 173..174 '_': i32 |
592 | "### | 628 | 178..182 'foo3': fn foo3(u32) -> isize |
629 | "]], | ||
593 | ); | 630 | ); |
594 | } | 631 | } |
595 | 632 | ||
596 | #[test] | 633 | #[test] |
597 | fn coerce_closure_to_fn_ptr() { | 634 | fn coerce_closure_to_fn_ptr() { |
598 | assert_snapshot!( | 635 | check_infer_with_mismatches( |
599 | infer_with_mismatches(r#" | 636 | r" |
600 | fn test() { | 637 | fn test() { |
601 | let f: fn(u32) -> isize = |x| { 1 }; | 638 | let f: fn(u32) -> isize = |x| { 1 }; |
602 | } | 639 | } |
603 | "#, true), | 640 | ", |
604 | @r###" | 641 | expect![[r" |
605 | 10..54 '{ ...1 }; }': () | 642 | 10..54 '{ ...1 }; }': () |
606 | 20..21 'f': fn(u32) -> isize | 643 | 20..21 'f': fn(u32) -> isize |
607 | 42..51 '|x| { 1 }': |u32| -> isize | 644 | 42..51 '|x| { 1 }': |u32| -> isize |
608 | 43..44 'x': u32 | 645 | 43..44 'x': u32 |
609 | 46..51 '{ 1 }': isize | 646 | 46..51 '{ 1 }': isize |
610 | 48..49 '1': isize | 647 | 48..49 '1': isize |
611 | "### | 648 | "]], |
612 | ); | 649 | ); |
613 | } | 650 | } |
614 | 651 | ||
615 | #[test] | 652 | #[test] |
616 | fn coerce_placeholder_ref() { | 653 | fn coerce_placeholder_ref() { |
617 | // placeholders should unify, even behind references | 654 | // placeholders should unify, even behind references |
618 | assert_snapshot!( | 655 | check_infer_with_mismatches( |
619 | infer_with_mismatches(r#" | 656 | r" |
620 | struct S<T> { t: T } | 657 | struct S<T> { t: T } |
621 | impl<TT> S<TT> { | 658 | impl<TT> S<TT> { |
622 | fn get(&self) -> &TT { | 659 | fn get(&self) -> &TT { |
623 | &self.t | 660 | &self.t |
624 | } | 661 | } |
625 | } | 662 | } |
626 | "#, true), | 663 | ", |
627 | @r###" | 664 | expect![[r" |
628 | 50..54 'self': &S<TT> | 665 | 50..54 'self': &S<TT> |
629 | 63..86 '{ ... }': &TT | 666 | 63..86 '{ ... }': &TT |
630 | 73..80 '&self.t': &TT | 667 | 73..80 '&self.t': &TT |
631 | 74..78 'self': &S<TT> | 668 | 74..78 'self': &S<TT> |
632 | 74..80 'self.t': TT | 669 | 74..80 'self.t': TT |
633 | "### | 670 | "]], |
634 | ); | 671 | ); |
635 | } | 672 | } |
636 | 673 | ||
637 | #[test] | 674 | #[test] |
638 | fn coerce_unsize_array() { | 675 | fn coerce_unsize_array() { |
639 | assert_snapshot!( | 676 | check_infer_with_mismatches( |
640 | infer_with_mismatches(r#" | 677 | r#" |
641 | #[lang = "unsize"] | 678 | #[lang = "unsize"] |
642 | pub trait Unsize<T> {} | 679 | pub trait Unsize<T> {} |
643 | #[lang = "coerce_unsized"] | 680 | #[lang = "coerce_unsized"] |
644 | pub trait CoerceUnsized<T> {} | 681 | pub trait CoerceUnsized<T> {} |
645 | 682 | ||
646 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 683 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} |
647 | 684 | ||
648 | fn test() { | 685 | fn test() { |
649 | let f: &[usize] = &[1, 2, 3]; | 686 | let f: &[usize] = &[1, 2, 3]; |
650 | } | 687 | } |
651 | "#, true), | 688 | "#, |
652 | @r###" | 689 | expect![[r" |
653 | 161..198 '{ ... 3]; }': () | 690 | 161..198 '{ ... 3]; }': () |
654 | 171..172 'f': &[usize] | 691 | 171..172 'f': &[usize] |
655 | 185..195 '&[1, 2, 3]': &[usize; _] | 692 | 185..195 '&[1, 2, 3]': &[usize; _] |
656 | 186..195 '[1, 2, 3]': [usize; _] | 693 | 186..195 '[1, 2, 3]': [usize; _] |
657 | 187..188 '1': usize | 694 | 187..188 '1': usize |
658 | 190..191 '2': usize | 695 | 190..191 '2': usize |
659 | 193..194 '3': usize | 696 | 193..194 '3': usize |
660 | "### | 697 | "]], |
661 | ); | 698 | ); |
662 | } | 699 | } |
663 | 700 | ||
664 | #[test] | 701 | #[test] |
665 | fn coerce_unsize_trait_object() { | 702 | fn coerce_unsize_trait_object_simple() { |
666 | assert_snapshot!( | 703 | check_infer_with_mismatches( |
667 | infer_with_mismatches(r#" | 704 | r#" |
668 | #[lang = "sized"] | 705 | #[lang = "sized"] |
669 | pub trait Sized {} | 706 | pub trait Sized {} |
670 | #[lang = "unsize"] | 707 | #[lang = "unsize"] |
671 | pub trait Unsize<T> {} | 708 | pub trait Unsize<T> {} |
672 | #[lang = "coerce_unsized"] | 709 | #[lang = "coerce_unsized"] |
673 | pub trait CoerceUnsized<T> {} | 710 | pub trait CoerceUnsized<T> {} |
674 | 711 | ||
675 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 712 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} |
676 | 713 | ||
677 | trait Foo<T, U> {} | 714 | trait Foo<T, U> {} |
678 | trait Bar<U, T, X>: Foo<T, U> {} | 715 | trait Bar<U, T, X>: Foo<T, U> {} |
679 | trait Baz<T, X>: Bar<usize, T, X> {} | 716 | trait Baz<T, X>: Bar<usize, T, X> {} |
680 | 717 | ||
681 | struct S<T, X>; | 718 | struct S<T, X>; |
682 | impl<T, X> Foo<T, usize> for S<T, X> {} | 719 | impl<T, X> Foo<T, usize> for S<T, X> {} |
683 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | 720 | impl<T, X> Bar<usize, T, X> for S<T, X> {} |
684 | impl<T, X> Baz<T, X> for S<T, X> {} | 721 | impl<T, X> Baz<T, X> for S<T, X> {} |
685 | 722 | ||
686 | fn test() { | 723 | fn test() { |
687 | let obj: &dyn Baz<i8, i16> = &S; | 724 | let obj: &dyn Baz<i8, i16> = &S; |
688 | let obj: &dyn Bar<_, _, _> = obj; | 725 | let obj: &dyn Bar<_, i8, i16> = &S; |
689 | let obj: &dyn Foo<_, _> = obj; | 726 | let obj: &dyn Foo<i8, _> = &S; |
690 | let obj2: &dyn Baz<i8, i16> = &S; | 727 | } |
691 | let _: &dyn Foo<_, _> = obj2; | 728 | "#, |
729 | expect![[r" | ||
730 | 424..539 '{ ... &S; }': () | ||
731 | 434..437 'obj': &dyn Baz<i8, i16> | ||
732 | 459..461 '&S': &S<i8, i16> | ||
733 | 460..461 'S': S<i8, i16> | ||
734 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
735 | 499..501 '&S': &S<i8, i16> | ||
736 | 500..501 'S': S<i8, i16> | ||
737 | 511..514 'obj': &dyn Foo<i8, usize> | ||
738 | 534..536 '&S': &S<i8, {unknown}> | ||
739 | 535..536 'S': S<i8, {unknown}> | ||
740 | "]], | ||
741 | ); | ||
692 | } | 742 | } |
693 | "#, true), | 743 | |
694 | @r###" | 744 | #[test] |
695 | 424..609 '{ ...bj2; }': () | 745 | // The rust reference says this should be possible, but rustc doesn't implement |
696 | 434..437 'obj': &dyn Baz<i8, i16> | 746 | // it. We used to support it, but Chalk doesn't. |
697 | 459..461 '&S': &S<i8, i16> | 747 | #[ignore] |
698 | 460..461 'S': S<i8, i16> | 748 | fn coerce_unsize_trait_object_to_trait_object() { |
699 | 471..474 'obj': &dyn Bar<usize, i8, i16> | 749 | check_infer_with_mismatches( |
700 | 496..499 'obj': &dyn Baz<i8, i16> | 750 | r#" |
701 | 509..512 'obj': &dyn Foo<i8, usize> | 751 | #[lang = "sized"] |
702 | 531..534 'obj': &dyn Bar<usize, i8, i16> | 752 | pub trait Sized {} |
703 | 544..548 'obj2': &dyn Baz<i8, i16> | 753 | #[lang = "unsize"] |
704 | 570..572 '&S': &S<i8, i16> | 754 | pub trait Unsize<T> {} |
705 | 571..572 'S': S<i8, i16> | 755 | #[lang = "coerce_unsized"] |
706 | 582..583 '_': &dyn Foo<i8, usize> | 756 | pub trait CoerceUnsized<T> {} |
707 | 602..606 'obj2': &dyn Baz<i8, i16> | 757 | |
708 | "### | 758 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} |
759 | |||
760 | trait Foo<T, U> {} | ||
761 | trait Bar<U, T, X>: Foo<T, U> {} | ||
762 | trait Baz<T, X>: Bar<usize, T, X> {} | ||
763 | |||
764 | struct S<T, X>; | ||
765 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
766 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
767 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
768 | |||
769 | fn test() { | ||
770 | let obj: &dyn Baz<i8, i16> = &S; | ||
771 | let obj: &dyn Bar<_, _, _> = obj; | ||
772 | let obj: &dyn Foo<_, _> = obj; | ||
773 | let obj2: &dyn Baz<i8, i16> = &S; | ||
774 | let _: &dyn Foo<_, _> = obj2; | ||
775 | } | ||
776 | "#, | ||
777 | expect![[r" | ||
778 | 424..609 '{ ...bj2; }': () | ||
779 | 434..437 'obj': &dyn Baz<i8, i16> | ||
780 | 459..461 '&S': &S<i8, i16> | ||
781 | 460..461 'S': S<i8, i16> | ||
782 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
783 | 496..499 'obj': &dyn Baz<i8, i16> | ||
784 | 509..512 'obj': &dyn Foo<i8, usize> | ||
785 | 531..534 'obj': &dyn Bar<usize, i8, i16> | ||
786 | 544..548 'obj2': &dyn Baz<i8, i16> | ||
787 | 570..572 '&S': &S<i8, i16> | ||
788 | 571..572 'S': S<i8, i16> | ||
789 | 582..583 '_': &dyn Foo<i8, usize> | ||
790 | 602..606 'obj2': &dyn Baz<i8, i16> | ||
791 | "]], | ||
709 | ); | 792 | ); |
710 | } | 793 | } |
711 | 794 | ||
712 | #[test] | 795 | #[test] |
713 | fn coerce_unsize_super_trait_cycle() { | 796 | fn coerce_unsize_super_trait_cycle() { |
714 | assert_snapshot!( | 797 | check_infer_with_mismatches( |
715 | infer_with_mismatches(r#" | 798 | r#" |
716 | #[lang = "sized"] | 799 | #[lang = "sized"] |
717 | pub trait Sized {} | 800 | pub trait Sized {} |
718 | #[lang = "unsize"] | 801 | #[lang = "unsize"] |
719 | pub trait Unsize<T> {} | 802 | pub trait Unsize<T> {} |
720 | #[lang = "coerce_unsized"] | 803 | #[lang = "coerce_unsized"] |
721 | pub trait CoerceUnsized<T> {} | 804 | pub trait CoerceUnsized<T> {} |
722 | 805 | ||
723 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 806 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} |
724 | 807 | ||
725 | trait A {} | 808 | trait A {} |
726 | trait B: C + A {} | 809 | trait B: C + A {} |
727 | trait C: B {} | 810 | trait C: B {} |
728 | trait D: C | 811 | trait D: C |
729 | 812 | ||
730 | struct S; | 813 | struct S; |
731 | impl A for S {} | 814 | impl A for S {} |
732 | impl B for S {} | 815 | impl B for S {} |
733 | impl C for S {} | 816 | impl C for S {} |
734 | impl D for S {} | 817 | impl D for S {} |
735 | 818 | ||
736 | fn test() { | 819 | fn test() { |
737 | let obj: &dyn D = &S; | 820 | let obj: &dyn D = &S; |
738 | let obj: &dyn A = obj; | 821 | let obj: &dyn A = &S; |
739 | } | 822 | } |
740 | "#, true), | 823 | "#, |
741 | @r###" | 824 | expect![[r" |
742 | 328..384 '{ ...obj; }': () | 825 | 328..383 '{ ... &S; }': () |
743 | 338..341 'obj': &dyn D | 826 | 338..341 'obj': &dyn D |
744 | 352..354 '&S': &S | 827 | 352..354 '&S': &S |
745 | 353..354 'S': S | 828 | 353..354 'S': S |
746 | 364..367 'obj': &dyn A | 829 | 364..367 'obj': &dyn A |
747 | 378..381 'obj': &dyn D | 830 | 378..380 '&S': &S |
748 | "### | 831 | 379..380 'S': S |
832 | "]], | ||
749 | ); | 833 | ); |
750 | } | 834 | } |
751 | 835 | ||
@@ -754,24 +838,24 @@ fn test() { | |||
754 | fn coerce_unsize_generic() { | 838 | fn coerce_unsize_generic() { |
755 | // FIXME: Implement this | 839 | // FIXME: Implement this |
756 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions | 840 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions |
757 | assert_snapshot!( | 841 | check_infer_with_mismatches( |
758 | infer_with_mismatches(r#" | 842 | r#" |
759 | #[lang = "unsize"] | 843 | #[lang = "unsize"] |
760 | pub trait Unsize<T> {} | 844 | pub trait Unsize<T> {} |
761 | #[lang = "coerce_unsized"] | 845 | #[lang = "coerce_unsized"] |
762 | pub trait CoerceUnsized<T> {} | 846 | pub trait CoerceUnsized<T> {} |
763 | 847 | ||
764 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 848 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} |
765 | 849 | ||
766 | struct Foo<T> { t: T }; | 850 | struct Foo<T> { t: T }; |
767 | struct Bar<T>(Foo<T>); | 851 | struct Bar<T>(Foo<T>); |
768 | 852 | ||
769 | fn test() { | 853 | fn test() { |
770 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; | 854 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; |
771 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | 855 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); |
772 | } | 856 | } |
773 | "#, true), | 857 | "#, |
774 | @r###" | 858 | expect![[r" |
775 | "### | 859 | "]], |
776 | ); | 860 | ); |
777 | } | 861 | } |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 45c4e309e..24c53eb02 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use std::fs; | 1 | use std::fs; |
2 | 2 | ||
3 | use insta::assert_snapshot; | 3 | use expect::expect; |
4 | use test_utils::project_dir; | 4 | use test_utils::project_dir; |
5 | 5 | ||
6 | use super::{check_types, infer}; | 6 | use super::{check_infer, check_types}; |
7 | 7 | ||
8 | #[test] | 8 | #[test] |
9 | fn cfg_impl_def() { | 9 | fn cfg_impl_def() { |
@@ -46,204 +46,204 @@ impl S { | |||
46 | 46 | ||
47 | #[test] | 47 | #[test] |
48 | fn infer_macros_expanded() { | 48 | fn infer_macros_expanded() { |
49 | assert_snapshot!( | 49 | check_infer( |
50 | infer(r#" | 50 | r#" |
51 | struct Foo(Vec<i32>); | 51 | struct Foo(Vec<i32>); |
52 | 52 | ||
53 | macro_rules! foo { | 53 | macro_rules! foo { |
54 | ($($item:expr),*) => { | 54 | ($($item:expr),*) => { |
55 | { | 55 | { |
56 | Foo(vec![$($item,)*]) | 56 | Foo(vec![$($item,)*]) |
57 | } | 57 | } |
58 | }; | 58 | }; |
59 | } | 59 | } |
60 | 60 | ||
61 | fn main() { | 61 | fn main() { |
62 | let x = foo!(1,2); | 62 | let x = foo!(1,2); |
63 | } | 63 | } |
64 | "#), | 64 | "#, |
65 | @r###" | 65 | expect![[r#" |
66 | !0..17 '{Foo(v...,2,])}': Foo | 66 | !0..17 '{Foo(v...,2,])}': Foo |
67 | !1..4 'Foo': Foo({unknown}) -> Foo | 67 | !1..4 'Foo': Foo({unknown}) -> Foo |
68 | !1..16 'Foo(vec![1,2,])': Foo | 68 | !1..16 'Foo(vec![1,2,])': Foo |
69 | !5..15 'vec![1,2,]': {unknown} | 69 | !5..15 'vec![1,2,]': {unknown} |
70 | 155..181 '{ ...,2); }': () | 70 | 155..181 '{ ...,2); }': () |
71 | 165..166 'x': Foo | 71 | 165..166 'x': Foo |
72 | "### | 72 | "#]], |
73 | ); | 73 | ); |
74 | } | 74 | } |
75 | 75 | ||
76 | #[test] | 76 | #[test] |
77 | fn infer_legacy_textual_scoped_macros_expanded() { | 77 | fn infer_legacy_textual_scoped_macros_expanded() { |
78 | assert_snapshot!( | 78 | check_infer( |
79 | infer(r#" | 79 | r#" |
80 | struct Foo(Vec<i32>); | 80 | struct Foo(Vec<i32>); |
81 | 81 | ||
82 | #[macro_use] | 82 | #[macro_use] |
83 | mod m { | 83 | mod m { |
84 | macro_rules! foo { | 84 | macro_rules! foo { |
85 | ($($item:expr),*) => { | 85 | ($($item:expr),*) => { |
86 | { | 86 | { |
87 | Foo(vec![$($item,)*]) | 87 | Foo(vec![$($item,)*]) |
88 | } | ||
89 | }; | ||
88 | } | 90 | } |
89 | }; | 91 | } |
90 | } | ||
91 | } | ||
92 | 92 | ||
93 | fn main() { | 93 | fn main() { |
94 | let x = foo!(1,2); | 94 | let x = foo!(1,2); |
95 | let y = crate::foo!(1,2); | 95 | let y = crate::foo!(1,2); |
96 | } | 96 | } |
97 | "#), | 97 | "#, |
98 | @r###" | 98 | expect![[r#" |
99 | !0..17 '{Foo(v...,2,])}': Foo | 99 | !0..17 '{Foo(v...,2,])}': Foo |
100 | !1..4 'Foo': Foo({unknown}) -> Foo | 100 | !1..4 'Foo': Foo({unknown}) -> Foo |
101 | !1..16 'Foo(vec![1,2,])': Foo | 101 | !1..16 'Foo(vec![1,2,])': Foo |
102 | !5..15 'vec![1,2,]': {unknown} | 102 | !5..15 'vec![1,2,]': {unknown} |
103 | 194..250 '{ ...,2); }': () | 103 | 194..250 '{ ...,2); }': () |
104 | 204..205 'x': Foo | 104 | 204..205 'x': Foo |
105 | 227..228 'y': {unknown} | 105 | 227..228 'y': {unknown} |
106 | 231..247 'crate:...!(1,2)': {unknown} | 106 | 231..247 'crate:...!(1,2)': {unknown} |
107 | "### | 107 | "#]], |
108 | ); | 108 | ); |
109 | } | 109 | } |
110 | 110 | ||
111 | #[test] | 111 | #[test] |
112 | fn infer_path_qualified_macros_expanded() { | 112 | fn infer_path_qualified_macros_expanded() { |
113 | assert_snapshot!( | 113 | check_infer( |
114 | infer(r#" | 114 | r#" |
115 | #[macro_export] | 115 | #[macro_export] |
116 | macro_rules! foo { | 116 | macro_rules! foo { |
117 | () => { 42i32 } | 117 | () => { 42i32 } |
118 | } | 118 | } |
119 | 119 | ||
120 | mod m { | 120 | mod m { |
121 | pub use super::foo as bar; | 121 | pub use super::foo as bar; |
122 | } | 122 | } |
123 | 123 | ||
124 | fn main() { | 124 | fn main() { |
125 | let x = crate::foo!(); | 125 | let x = crate::foo!(); |
126 | let y = m::bar!(); | 126 | let y = m::bar!(); |
127 | } | 127 | } |
128 | "#), | 128 | "#, |
129 | @r###" | 129 | expect![[r#" |
130 | !0..5 '42i32': i32 | 130 | !0..5 '42i32': i32 |
131 | !0..5 '42i32': i32 | 131 | !0..5 '42i32': i32 |
132 | 110..163 '{ ...!(); }': () | 132 | 110..163 '{ ...!(); }': () |
133 | 120..121 'x': i32 | 133 | 120..121 'x': i32 |
134 | 147..148 'y': i32 | 134 | 147..148 'y': i32 |
135 | "### | 135 | "#]], |
136 | ); | 136 | ); |
137 | } | 137 | } |
138 | 138 | ||
139 | #[test] | 139 | #[test] |
140 | fn expr_macro_expanded_in_various_places() { | 140 | fn expr_macro_expanded_in_various_places() { |
141 | assert_snapshot!( | 141 | check_infer( |
142 | infer(r#" | 142 | r#" |
143 | macro_rules! spam { | 143 | macro_rules! spam { |
144 | () => (1isize); | 144 | () => (1isize); |
145 | } | 145 | } |
146 | 146 | ||
147 | fn spam() { | 147 | fn spam() { |
148 | spam!(); | 148 | spam!(); |
149 | (spam!()); | 149 | (spam!()); |
150 | spam!().spam(spam!()); | 150 | spam!().spam(spam!()); |
151 | for _ in spam!() {} | 151 | for _ in spam!() {} |
152 | || spam!(); | 152 | || spam!(); |
153 | while spam!() {} | 153 | while spam!() {} |
154 | break spam!(); | 154 | break spam!(); |
155 | return spam!(); | 155 | return spam!(); |
156 | match spam!() { | 156 | match spam!() { |
157 | _ if spam!() => spam!(), | 157 | _ if spam!() => spam!(), |
158 | } | 158 | } |
159 | spam!()(spam!()); | 159 | spam!()(spam!()); |
160 | Spam { spam: spam!() }; | 160 | Spam { spam: spam!() }; |
161 | spam!()[spam!()]; | 161 | spam!()[spam!()]; |
162 | await spam!(); | 162 | await spam!(); |
163 | spam!() as usize; | 163 | spam!() as usize; |
164 | &spam!(); | 164 | &spam!(); |
165 | -spam!(); | 165 | -spam!(); |
166 | spam!()..spam!(); | 166 | spam!()..spam!(); |
167 | spam!() + spam!(); | 167 | spam!() + spam!(); |
168 | } | 168 | } |
169 | "#), | 169 | "#, |
170 | @r###" | 170 | expect![[r#" |
171 | !0..6 '1isize': isize | 171 | !0..6 '1isize': isize |
172 | !0..6 '1isize': isize | 172 | !0..6 '1isize': isize |
173 | !0..6 '1isize': isize | 173 | !0..6 '1isize': isize |
174 | !0..6 '1isize': isize | 174 | !0..6 '1isize': isize |
175 | !0..6 '1isize': isize | 175 | !0..6 '1isize': isize |
176 | !0..6 '1isize': isize | 176 | !0..6 '1isize': isize |
177 | !0..6 '1isize': isize | 177 | !0..6 '1isize': isize |
178 | !0..6 '1isize': isize | 178 | !0..6 '1isize': isize |
179 | !0..6 '1isize': isize | 179 | !0..6 '1isize': isize |
180 | !0..6 '1isize': isize | 180 | !0..6 '1isize': isize |
181 | !0..6 '1isize': isize | 181 | !0..6 '1isize': isize |
182 | !0..6 '1isize': isize | 182 | !0..6 '1isize': isize |
183 | !0..6 '1isize': isize | 183 | !0..6 '1isize': isize |
184 | !0..6 '1isize': isize | 184 | !0..6 '1isize': isize |
185 | !0..6 '1isize': isize | 185 | !0..6 '1isize': isize |
186 | !0..6 '1isize': isize | 186 | !0..6 '1isize': isize |
187 | !0..6 '1isize': isize | 187 | !0..6 '1isize': isize |
188 | !0..6 '1isize': isize | 188 | !0..6 '1isize': isize |
189 | !0..6 '1isize': isize | 189 | !0..6 '1isize': isize |
190 | !0..6 '1isize': isize | 190 | !0..6 '1isize': isize |
191 | !0..6 '1isize': isize | 191 | !0..6 '1isize': isize |
192 | !0..6 '1isize': isize | 192 | !0..6 '1isize': isize |
193 | !0..6 '1isize': isize | 193 | !0..6 '1isize': isize |
194 | !0..6 '1isize': isize | 194 | !0..6 '1isize': isize |
195 | !0..6 '1isize': isize | 195 | !0..6 '1isize': isize |
196 | 53..456 '{ ...!(); }': () | 196 | 53..456 '{ ...!(); }': () |
197 | 87..108 'spam!(...am!())': {unknown} | 197 | 87..108 'spam!(...am!())': {unknown} |
198 | 114..133 'for _ ...!() {}': () | 198 | 114..133 'for _ ...!() {}': () |
199 | 118..119 '_': {unknown} | 199 | 118..119 '_': {unknown} |
200 | 131..133 '{}': () | 200 | 131..133 '{}': () |
201 | 138..148 '|| spam!()': || -> isize | 201 | 138..148 '|| spam!()': || -> isize |
202 | 154..170 'while ...!() {}': () | 202 | 154..170 'while ...!() {}': () |
203 | 168..170 '{}': () | 203 | 168..170 '{}': () |
204 | 175..188 'break spam!()': ! | 204 | 175..188 'break spam!()': ! |
205 | 194..208 'return spam!()': ! | 205 | 194..208 'return spam!()': ! |
206 | 214..268 'match ... }': isize | 206 | 214..268 'match ... }': isize |
207 | 238..239 '_': isize | 207 | 238..239 '_': isize |
208 | 273..289 'spam!(...am!())': {unknown} | 208 | 273..289 'spam!(...am!())': {unknown} |
209 | 295..317 'Spam {...m!() }': {unknown} | 209 | 295..317 'Spam {...m!() }': {unknown} |
210 | 323..339 'spam!(...am!()]': {unknown} | 210 | 323..339 'spam!(...am!()]': {unknown} |
211 | 364..380 'spam!(... usize': usize | 211 | 364..380 'spam!(... usize': usize |
212 | 386..394 '&spam!()': &isize | 212 | 386..394 '&spam!()': &isize |
213 | 400..408 '-spam!()': isize | 213 | 400..408 '-spam!()': isize |
214 | 414..430 'spam!(...pam!()': {unknown} | 214 | 414..430 'spam!(...pam!()': {unknown} |
215 | 436..453 'spam!(...pam!()': isize | 215 | 436..453 'spam!(...pam!()': isize |
216 | "### | 216 | "#]], |
217 | ); | 217 | ); |
218 | } | 218 | } |
219 | 219 | ||
220 | #[test] | 220 | #[test] |
221 | fn infer_type_value_macro_having_same_name() { | 221 | fn infer_type_value_macro_having_same_name() { |
222 | assert_snapshot!( | 222 | check_infer( |
223 | infer(r#" | 223 | r#" |
224 | #[macro_export] | 224 | #[macro_export] |
225 | macro_rules! foo { | 225 | macro_rules! foo { |
226 | () => { | 226 | () => { |
227 | mod foo { | 227 | mod foo { |
228 | pub use super::foo; | 228 | pub use super::foo; |
229 | } | ||
230 | }; | ||
231 | ($x:tt) => { | ||
232 | $x | ||
233 | }; | ||
229 | } | 234 | } |
230 | }; | ||
231 | ($x:tt) => { | ||
232 | $x | ||
233 | }; | ||
234 | } | ||
235 | 235 | ||
236 | foo!(); | 236 | foo!(); |
237 | 237 | ||
238 | fn foo() { | 238 | fn foo() { |
239 | let foo = foo::foo!(42i32); | 239 | let foo = foo::foo!(42i32); |
240 | } | 240 | } |
241 | "#), | 241 | "#, |
242 | @r###" | 242 | expect![[r#" |
243 | !0..5 '42i32': i32 | 243 | !0..5 '42i32': i32 |
244 | 170..205 '{ ...32); }': () | 244 | 170..205 '{ ...32); }': () |
245 | 180..183 'foo': i32 | 245 | 180..183 'foo': i32 |
246 | "### | 246 | "#]], |
247 | ); | 247 | ); |
248 | } | 248 | } |
249 | 249 | ||
@@ -372,50 +372,50 @@ expand!(); | |||
372 | 372 | ||
373 | #[test] | 373 | #[test] |
374 | fn infer_type_value_non_legacy_macro_use_as() { | 374 | fn infer_type_value_non_legacy_macro_use_as() { |
375 | assert_snapshot!( | 375 | check_infer( |
376 | infer(r#" | 376 | r#" |
377 | mod m { | 377 | mod m { |
378 | macro_rules! _foo { | 378 | macro_rules! _foo { |
379 | ($x:ident) => { type $x = u64; } | 379 | ($x:ident) => { type $x = u64; } |
380 | } | 380 | } |
381 | pub(crate) use _foo as foo; | 381 | pub(crate) use _foo as foo; |
382 | } | 382 | } |
383 | 383 | ||
384 | m::foo!(foo); | 384 | m::foo!(foo); |
385 | use foo as bar; | 385 | use foo as bar; |
386 | fn f() -> bar { 0 } | 386 | fn f() -> bar { 0 } |
387 | fn main() { | 387 | fn main() { |
388 | let _a = f(); | 388 | let _a = f(); |
389 | } | 389 | } |
390 | "#), | 390 | "#, |
391 | @r###" | 391 | expect![[r#" |
392 | 158..163 '{ 0 }': u64 | 392 | 158..163 '{ 0 }': u64 |
393 | 160..161 '0': u64 | 393 | 160..161 '0': u64 |
394 | 174..196 '{ ...f(); }': () | 394 | 174..196 '{ ...f(); }': () |
395 | 184..186 '_a': u64 | 395 | 184..186 '_a': u64 |
396 | 190..191 'f': fn f() -> u64 | 396 | 190..191 'f': fn f() -> u64 |
397 | 190..193 'f()': u64 | 397 | 190..193 'f()': u64 |
398 | "### | 398 | "#]], |
399 | ); | 399 | ); |
400 | } | 400 | } |
401 | 401 | ||
402 | #[test] | 402 | #[test] |
403 | fn infer_local_macro() { | 403 | fn infer_local_macro() { |
404 | assert_snapshot!( | 404 | check_infer( |
405 | infer(r#" | 405 | r#" |
406 | fn main() { | 406 | fn main() { |
407 | macro_rules! foo { | 407 | macro_rules! foo { |
408 | () => { 1usize } | 408 | () => { 1usize } |
409 | } | 409 | } |
410 | let _a = foo!(); | 410 | let _a = foo!(); |
411 | } | 411 | } |
412 | "#), | 412 | "#, |
413 | @r###" | 413 | expect![[r#" |
414 | !0..6 '1usize': usize | 414 | !0..6 '1usize': usize |
415 | 10..89 '{ ...!(); }': () | 415 | 10..89 '{ ...!(); }': () |
416 | 16..65 'macro_... }': {unknown} | 416 | 16..65 'macro_... }': {unknown} |
417 | 74..76 '_a': usize | 417 | 74..76 '_a': usize |
418 | "### | 418 | "#]], |
419 | ); | 419 | ); |
420 | } | 420 | } |
421 | 421 | ||
@@ -446,77 +446,77 @@ macro_rules! bar { | |||
446 | 446 | ||
447 | #[test] | 447 | #[test] |
448 | fn infer_builtin_macros_line() { | 448 | fn infer_builtin_macros_line() { |
449 | assert_snapshot!( | 449 | check_infer( |
450 | infer(r#" | 450 | r#" |
451 | #[rustc_builtin_macro] | 451 | #[rustc_builtin_macro] |
452 | macro_rules! line {() => {}} | 452 | macro_rules! line {() => {}} |
453 | 453 | ||
454 | fn main() { | 454 | fn main() { |
455 | let x = line!(); | 455 | let x = line!(); |
456 | } | 456 | } |
457 | "#), | 457 | "#, |
458 | @r###" | 458 | expect![[r#" |
459 | !0..1 '0': i32 | 459 | !0..1 '0': i32 |
460 | 63..87 '{ ...!(); }': () | 460 | 63..87 '{ ...!(); }': () |
461 | 73..74 'x': i32 | 461 | 73..74 'x': i32 |
462 | "### | 462 | "#]], |
463 | ); | 463 | ); |
464 | } | 464 | } |
465 | 465 | ||
466 | #[test] | 466 | #[test] |
467 | fn infer_builtin_macros_file() { | 467 | fn infer_builtin_macros_file() { |
468 | assert_snapshot!( | 468 | check_infer( |
469 | infer(r#" | 469 | r#" |
470 | #[rustc_builtin_macro] | 470 | #[rustc_builtin_macro] |
471 | macro_rules! file {() => {}} | 471 | macro_rules! file {() => {}} |
472 | 472 | ||
473 | fn main() { | 473 | fn main() { |
474 | let x = file!(); | 474 | let x = file!(); |
475 | } | 475 | } |
476 | "#), | 476 | "#, |
477 | @r###" | 477 | expect![[r#" |
478 | !0..2 '""': &str | 478 | !0..2 '""': &str |
479 | 63..87 '{ ...!(); }': () | 479 | 63..87 '{ ...!(); }': () |
480 | 73..74 'x': &str | 480 | 73..74 'x': &str |
481 | "### | 481 | "#]], |
482 | ); | 482 | ); |
483 | } | 483 | } |
484 | 484 | ||
485 | #[test] | 485 | #[test] |
486 | fn infer_builtin_macros_column() { | 486 | fn infer_builtin_macros_column() { |
487 | assert_snapshot!( | 487 | check_infer( |
488 | infer(r#" | 488 | r#" |
489 | #[rustc_builtin_macro] | 489 | #[rustc_builtin_macro] |
490 | macro_rules! column {() => {}} | 490 | macro_rules! column {() => {}} |
491 | 491 | ||
492 | fn main() { | 492 | fn main() { |
493 | let x = column!(); | 493 | let x = column!(); |
494 | } | 494 | } |
495 | "#), | 495 | "#, |
496 | @r###" | 496 | expect![[r#" |
497 | !0..1 '0': i32 | 497 | !0..1 '0': i32 |
498 | 65..91 '{ ...!(); }': () | 498 | 65..91 '{ ...!(); }': () |
499 | 75..76 'x': i32 | 499 | 75..76 'x': i32 |
500 | "### | 500 | "#]], |
501 | ); | 501 | ); |
502 | } | 502 | } |
503 | 503 | ||
504 | #[test] | 504 | #[test] |
505 | fn infer_builtin_macros_concat() { | 505 | fn infer_builtin_macros_concat() { |
506 | assert_snapshot!( | 506 | check_infer( |
507 | infer(r#" | 507 | r#" |
508 | #[rustc_builtin_macro] | 508 | #[rustc_builtin_macro] |
509 | macro_rules! concat {() => {}} | 509 | macro_rules! concat {() => {}} |
510 | 510 | ||
511 | fn main() { | 511 | fn main() { |
512 | let x = concat!("hello", concat!("world", "!")); | 512 | let x = concat!("hello", concat!("world", "!")); |
513 | } | 513 | } |
514 | "#), | 514 | "#, |
515 | @r###" | 515 | expect![[r#" |
516 | !0..13 '"helloworld!"': &str | 516 | !0..13 '"helloworld!"': &str |
517 | 65..121 '{ ...")); }': () | 517 | 65..121 '{ ...")); }': () |
518 | 75..76 'x': &str | 518 | 75..76 'x': &str |
519 | "### | 519 | "#]], |
520 | ); | 520 | ); |
521 | } | 521 | } |
522 | 522 | ||
@@ -622,7 +622,7 @@ macro_rules! include {() => {}} | |||
622 | include!("main.rs"); | 622 | include!("main.rs"); |
623 | 623 | ||
624 | fn main() { | 624 | fn main() { |
625 | 0 | 625 | 0 |
626 | } //^ i32 | 626 | } //^ i32 |
627 | "#, | 627 | "#, |
628 | ); | 628 | ); |
@@ -630,42 +630,42 @@ fn main() { | |||
630 | 630 | ||
631 | #[test] | 631 | #[test] |
632 | fn infer_builtin_macros_concat_with_lazy() { | 632 | fn infer_builtin_macros_concat_with_lazy() { |
633 | assert_snapshot!( | 633 | check_infer( |
634 | infer(r#" | 634 | r#" |
635 | macro_rules! hello {() => {"hello"}} | 635 | macro_rules! hello {() => {"hello"}} |
636 | 636 | ||
637 | #[rustc_builtin_macro] | 637 | #[rustc_builtin_macro] |
638 | macro_rules! concat {() => {}} | 638 | macro_rules! concat {() => {}} |
639 | 639 | ||
640 | fn main() { | 640 | fn main() { |
641 | let x = concat!(hello!(), concat!("world", "!")); | 641 | let x = concat!(hello!(), concat!("world", "!")); |
642 | } | 642 | } |
643 | "#), | 643 | "#, |
644 | @r###" | 644 | expect![[r#" |
645 | !0..13 '"helloworld!"': &str | 645 | !0..13 '"helloworld!"': &str |
646 | 103..160 '{ ...")); }': () | 646 | 103..160 '{ ...")); }': () |
647 | 113..114 'x': &str | 647 | 113..114 'x': &str |
648 | "### | 648 | "#]], |
649 | ); | 649 | ); |
650 | } | 650 | } |
651 | 651 | ||
652 | #[test] | 652 | #[test] |
653 | fn infer_builtin_macros_env() { | 653 | fn infer_builtin_macros_env() { |
654 | assert_snapshot!( | 654 | check_infer( |
655 | infer(r#" | 655 | r#" |
656 | //- /main.rs env:foo=bar | 656 | //- /main.rs env:foo=bar |
657 | #[rustc_builtin_macro] | 657 | #[rustc_builtin_macro] |
658 | macro_rules! env {() => {}} | 658 | macro_rules! env {() => {}} |
659 | 659 | ||
660 | fn main() { | 660 | fn main() { |
661 | let x = env!("foo"); | 661 | let x = env!("foo"); |
662 | } | 662 | } |
663 | "#), | 663 | "#, |
664 | @r###" | 664 | expect![[r#" |
665 | !0..22 '"__RA_...TED__"': &str | 665 | !0..22 '"__RA_...TED__"': &str |
666 | 62..90 '{ ...o"); }': () | 666 | 62..90 '{ ...o"); }': () |
667 | 72..73 'x': &str | 667 | 72..73 'x': &str |
668 | "### | 668 | "#]], |
669 | ); | 669 | ); |
670 | } | 670 | } |
671 | 671 | ||
@@ -763,25 +763,25 @@ fn test() { | |||
763 | 763 | ||
764 | #[test] | 764 | #[test] |
765 | fn macro_in_arm() { | 765 | fn macro_in_arm() { |
766 | assert_snapshot!( | 766 | check_infer( |
767 | infer(r#" | 767 | r#" |
768 | macro_rules! unit { | 768 | macro_rules! unit { |
769 | () => { () }; | 769 | () => { () }; |
770 | } | 770 | } |
771 | 771 | ||
772 | fn main() { | 772 | fn main() { |
773 | let x = match () { | 773 | let x = match () { |
774 | unit!() => 92u32, | 774 | unit!() => 92u32, |
775 | }; | 775 | }; |
776 | } | 776 | } |
777 | "#), | 777 | "#, |
778 | @r###" | 778 | expect![[r#" |
779 | 51..110 '{ ... }; }': () | 779 | 51..110 '{ ... }; }': () |
780 | 61..62 'x': u32 | 780 | 61..62 'x': u32 |
781 | 65..107 'match ... }': u32 | 781 | 65..107 'match ... }': u32 |
782 | 71..73 '()': () | 782 | 71..73 '()': () |
783 | 84..91 'unit!()': () | 783 | 84..91 'unit!()': () |
784 | 95..100 '92u32': u32 | 784 | 95..100 '92u32': u32 |
785 | "### | 785 | "#]], |
786 | ); | 786 | ); |
787 | } | 787 | } |
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 9c8f22314..fa68355aa 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -1,245 +1,245 @@ | |||
1 | use insta::assert_snapshot; | 1 | use expect::expect; |
2 | 2 | ||
3 | use super::{check_types, infer}; | 3 | use super::{check_infer, check_types}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn infer_slice_method() { | 6 | fn infer_slice_method() { |
7 | assert_snapshot!( | 7 | check_infer( |
8 | infer(r#" | 8 | r#" |
9 | #[lang = "slice"] | 9 | #[lang = "slice"] |
10 | impl<T> [T] { | 10 | impl<T> [T] { |
11 | fn foo(&self) -> T { | 11 | fn foo(&self) -> T { |
12 | loop {} | 12 | loop {} |
13 | } | 13 | } |
14 | } | 14 | } |
15 | 15 | ||
16 | #[lang = "slice_alloc"] | 16 | #[lang = "slice_alloc"] |
17 | impl<T> [T] {} | 17 | impl<T> [T] {} |
18 | 18 | ||
19 | fn test(x: &[u8]) { | 19 | fn test(x: &[u8]) { |
20 | <[_]>::foo(x); | 20 | <[_]>::foo(x); |
21 | } | 21 | } |
22 | "#), | 22 | "#, |
23 | @r###" | 23 | expect![[r#" |
24 | 44..48 'self': &[T] | 24 | 44..48 'self': &[T] |
25 | 55..78 '{ ... }': T | 25 | 55..78 '{ ... }': T |
26 | 65..72 'loop {}': ! | 26 | 65..72 'loop {}': ! |
27 | 70..72 '{}': () | 27 | 70..72 '{}': () |
28 | 130..131 'x': &[u8] | 28 | 130..131 'x': &[u8] |
29 | 140..162 '{ ...(x); }': () | 29 | 140..162 '{ ...(x); }': () |
30 | 146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8 | 30 | 146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8 |
31 | 146..159 '<[_]>::foo(x)': u8 | 31 | 146..159 '<[_]>::foo(x)': u8 |
32 | 157..158 'x': &[u8] | 32 | 157..158 'x': &[u8] |
33 | "### | 33 | "#]], |
34 | ); | 34 | ); |
35 | } | 35 | } |
36 | 36 | ||
37 | #[test] | 37 | #[test] |
38 | fn infer_associated_method_struct() { | 38 | fn infer_associated_method_struct() { |
39 | assert_snapshot!( | 39 | check_infer( |
40 | infer(r#" | 40 | r#" |
41 | struct A { x: u32 } | 41 | struct A { x: u32 } |
42 | 42 | ||
43 | impl A { | 43 | impl A { |
44 | fn new() -> A { | 44 | fn new() -> A { |
45 | A { x: 0 } | 45 | A { x: 0 } |
46 | } | 46 | } |
47 | } | 47 | } |
48 | fn test() { | 48 | fn test() { |
49 | let a = A::new(); | 49 | let a = A::new(); |
50 | a.x; | 50 | a.x; |
51 | } | 51 | } |
52 | "#), | 52 | "#, |
53 | @r###" | 53 | expect![[r#" |
54 | 48..74 '{ ... }': A | 54 | 48..74 '{ ... }': A |
55 | 58..68 'A { x: 0 }': A | 55 | 58..68 'A { x: 0 }': A |
56 | 65..66 '0': u32 | 56 | 65..66 '0': u32 |
57 | 87..121 '{ ...a.x; }': () | 57 | 87..121 '{ ...a.x; }': () |
58 | 97..98 'a': A | 58 | 97..98 'a': A |
59 | 101..107 'A::new': fn new() -> A | 59 | 101..107 'A::new': fn new() -> A |
60 | 101..109 'A::new()': A | 60 | 101..109 'A::new()': A |
61 | 115..116 'a': A | 61 | 115..116 'a': A |
62 | 115..118 'a.x': u32 | 62 | 115..118 'a.x': u32 |
63 | "### | 63 | "#]], |
64 | ); | 64 | ); |
65 | } | 65 | } |
66 | 66 | ||
67 | #[test] | 67 | #[test] |
68 | fn infer_associated_method_enum() { | 68 | fn infer_associated_method_enum() { |
69 | assert_snapshot!( | 69 | check_infer( |
70 | infer(r#" | 70 | r#" |
71 | enum A { B, C } | 71 | enum A { B, C } |
72 | 72 | ||
73 | impl A { | 73 | impl A { |
74 | pub fn b() -> A { | 74 | pub fn b() -> A { |
75 | A::B | 75 | A::B |
76 | } | 76 | } |
77 | pub fn c() -> A { | 77 | pub fn c() -> A { |
78 | A::C | 78 | A::C |
79 | } | 79 | } |
80 | } | 80 | } |
81 | fn test() { | 81 | fn test() { |
82 | let a = A::b(); | 82 | let a = A::b(); |
83 | a; | 83 | a; |
84 | let c = A::c(); | 84 | let c = A::c(); |
85 | c; | 85 | c; |
86 | } | 86 | } |
87 | "#), | 87 | "#, |
88 | @r###" | 88 | expect![[r#" |
89 | 46..66 '{ ... }': A | 89 | 46..66 '{ ... }': A |
90 | 56..60 'A::B': A | 90 | 56..60 'A::B': A |
91 | 87..107 '{ ... }': A | 91 | 87..107 '{ ... }': A |
92 | 97..101 'A::C': A | 92 | 97..101 'A::C': A |
93 | 120..177 '{ ... c; }': () | 93 | 120..177 '{ ... c; }': () |
94 | 130..131 'a': A | 94 | 130..131 'a': A |
95 | 134..138 'A::b': fn b() -> A | 95 | 134..138 'A::b': fn b() -> A |
96 | 134..140 'A::b()': A | 96 | 134..140 'A::b()': A |
97 | 146..147 'a': A | 97 | 146..147 'a': A |
98 | 157..158 'c': A | 98 | 157..158 'c': A |
99 | 161..165 'A::c': fn c() -> A | 99 | 161..165 'A::c': fn c() -> A |
100 | 161..167 'A::c()': A | 100 | 161..167 'A::c()': A |
101 | 173..174 'c': A | 101 | 173..174 'c': A |
102 | "### | 102 | "#]], |
103 | ); | 103 | ); |
104 | } | 104 | } |
105 | 105 | ||
106 | #[test] | 106 | #[test] |
107 | fn infer_associated_method_with_modules() { | 107 | fn infer_associated_method_with_modules() { |
108 | assert_snapshot!( | 108 | check_infer( |
109 | infer(r#" | 109 | r#" |
110 | mod a { | 110 | mod a { |
111 | struct A; | 111 | struct A; |
112 | impl A { pub fn thing() -> A { A {} }} | 112 | impl A { pub fn thing() -> A { A {} }} |
113 | } | 113 | } |
114 | 114 | ||
115 | mod b { | 115 | mod b { |
116 | struct B; | 116 | struct B; |
117 | impl B { pub fn thing() -> u32 { 99 }} | 117 | impl B { pub fn thing() -> u32 { 99 }} |
118 | 118 | ||
119 | mod c { | 119 | mod c { |
120 | struct C; | 120 | struct C; |
121 | impl C { pub fn thing() -> C { C {} }} | 121 | impl C { pub fn thing() -> C { C {} }} |
122 | } | 122 | } |
123 | } | 123 | } |
124 | use b::c; | 124 | use b::c; |
125 | 125 | ||
126 | fn test() { | 126 | fn test() { |
127 | let x = a::A::thing(); | 127 | let x = a::A::thing(); |
128 | let y = b::B::thing(); | 128 | let y = b::B::thing(); |
129 | let z = c::C::thing(); | 129 | let z = c::C::thing(); |
130 | } | 130 | } |
131 | "#), | 131 | "#, |
132 | @r###" | 132 | expect![[r#" |
133 | 55..63 '{ A {} }': A | 133 | 55..63 '{ A {} }': A |
134 | 57..61 'A {}': A | 134 | 57..61 'A {}': A |
135 | 125..131 '{ 99 }': u32 | 135 | 125..131 '{ 99 }': u32 |
136 | 127..129 '99': u32 | 136 | 127..129 '99': u32 |
137 | 201..209 '{ C {} }': C | 137 | 201..209 '{ C {} }': C |
138 | 203..207 'C {}': C | 138 | 203..207 'C {}': C |
139 | 240..324 '{ ...g(); }': () | 139 | 240..324 '{ ...g(); }': () |
140 | 250..251 'x': A | 140 | 250..251 'x': A |
141 | 254..265 'a::A::thing': fn thing() -> A | 141 | 254..265 'a::A::thing': fn thing() -> A |
142 | 254..267 'a::A::thing()': A | 142 | 254..267 'a::A::thing()': A |
143 | 277..278 'y': u32 | 143 | 277..278 'y': u32 |
144 | 281..292 'b::B::thing': fn thing() -> u32 | 144 | 281..292 'b::B::thing': fn thing() -> u32 |
145 | 281..294 'b::B::thing()': u32 | 145 | 281..294 'b::B::thing()': u32 |
146 | 304..305 'z': C | 146 | 304..305 'z': C |
147 | 308..319 'c::C::thing': fn thing() -> C | 147 | 308..319 'c::C::thing': fn thing() -> C |
148 | 308..321 'c::C::thing()': C | 148 | 308..321 'c::C::thing()': C |
149 | "### | 149 | "#]], |
150 | ); | 150 | ); |
151 | } | 151 | } |
152 | 152 | ||
153 | #[test] | 153 | #[test] |
154 | fn infer_associated_method_generics() { | 154 | fn infer_associated_method_generics() { |
155 | assert_snapshot!( | 155 | check_infer( |
156 | infer(r#" | 156 | r#" |
157 | struct Gen<T> { | 157 | struct Gen<T> { |
158 | val: T | 158 | val: T |
159 | } | 159 | } |
160 | 160 | ||
161 | impl<T> Gen<T> { | 161 | impl<T> Gen<T> { |
162 | pub fn make(val: T) -> Gen<T> { | 162 | pub fn make(val: T) -> Gen<T> { |
163 | Gen { val } | 163 | Gen { val } |
164 | } | 164 | } |
165 | } | 165 | } |
166 | 166 | ||
167 | fn test() { | 167 | fn test() { |
168 | let a = Gen::make(0u32); | 168 | let a = Gen::make(0u32); |
169 | } | 169 | } |
170 | "#), | 170 | "#, |
171 | @r###" | 171 | expect![[r#" |
172 | 63..66 'val': T | 172 | 63..66 'val': T |
173 | 81..108 '{ ... }': Gen<T> | 173 | 81..108 '{ ... }': Gen<T> |
174 | 91..102 'Gen { val }': Gen<T> | 174 | 91..102 'Gen { val }': Gen<T> |
175 | 97..100 'val': T | 175 | 97..100 'val': T |
176 | 122..154 '{ ...32); }': () | 176 | 122..154 '{ ...32); }': () |
177 | 132..133 'a': Gen<u32> | 177 | 132..133 'a': Gen<u32> |
178 | 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32> | 178 | 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32> |
179 | 136..151 'Gen::make(0u32)': Gen<u32> | 179 | 136..151 'Gen::make(0u32)': Gen<u32> |
180 | 146..150 '0u32': u32 | 180 | 146..150 '0u32': u32 |
181 | "### | 181 | "#]], |
182 | ); | 182 | ); |
183 | } | 183 | } |
184 | 184 | ||
185 | #[test] | 185 | #[test] |
186 | fn infer_associated_method_generics_without_args() { | 186 | fn infer_associated_method_generics_without_args() { |
187 | assert_snapshot!( | 187 | check_infer( |
188 | infer(r#" | 188 | r#" |
189 | struct Gen<T> { | 189 | struct Gen<T> { |
190 | val: T | 190 | val: T |
191 | } | 191 | } |
192 | 192 | ||
193 | impl<T> Gen<T> { | 193 | impl<T> Gen<T> { |
194 | pub fn make() -> Gen<T> { | 194 | pub fn make() -> Gen<T> { |
195 | loop { } | 195 | loop { } |
196 | } | 196 | } |
197 | } | 197 | } |
198 | 198 | ||
199 | fn test() { | 199 | fn test() { |
200 | let a = Gen::<u32>::make(); | 200 | let a = Gen::<u32>::make(); |
201 | } | 201 | } |
202 | "#), | 202 | "#, |
203 | @r###" | 203 | expect![[r#" |
204 | 75..99 '{ ... }': Gen<T> | 204 | 75..99 '{ ... }': Gen<T> |
205 | 85..93 'loop { }': ! | 205 | 85..93 'loop { }': ! |
206 | 90..93 '{ }': () | 206 | 90..93 '{ }': () |
207 | 113..148 '{ ...e(); }': () | 207 | 113..148 '{ ...e(); }': () |
208 | 123..124 'a': Gen<u32> | 208 | 123..124 'a': Gen<u32> |
209 | 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32> | 209 | 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32> |
210 | 127..145 'Gen::<...make()': Gen<u32> | 210 | 127..145 'Gen::<...make()': Gen<u32> |
211 | "### | 211 | "#]], |
212 | ); | 212 | ); |
213 | } | 213 | } |
214 | 214 | ||
215 | #[test] | 215 | #[test] |
216 | fn infer_associated_method_generics_2_type_params_without_args() { | 216 | fn infer_associated_method_generics_2_type_params_without_args() { |
217 | assert_snapshot!( | 217 | check_infer( |
218 | infer(r#" | 218 | r#" |
219 | struct Gen<T, U> { | 219 | struct Gen<T, U> { |
220 | val: T, | 220 | val: T, |
221 | val2: U, | 221 | val2: U, |
222 | } | 222 | } |
223 | 223 | ||
224 | impl<T> Gen<u32, T> { | 224 | impl<T> Gen<u32, T> { |
225 | pub fn make() -> Gen<u32,T> { | 225 | pub fn make() -> Gen<u32,T> { |
226 | loop { } | 226 | loop { } |
227 | } | 227 | } |
228 | } | 228 | } |
229 | 229 | ||
230 | fn test() { | 230 | fn test() { |
231 | let a = Gen::<u32, u64>::make(); | 231 | let a = Gen::<u32, u64>::make(); |
232 | } | 232 | } |
233 | "#), | 233 | "#, |
234 | @r###" | 234 | expect![[r#" |
235 | 101..125 '{ ... }': Gen<u32, T> | 235 | 101..125 '{ ... }': Gen<u32, T> |
236 | 111..119 'loop { }': ! | 236 | 111..119 'loop { }': ! |
237 | 116..119 '{ }': () | 237 | 116..119 '{ }': () |
238 | 139..179 '{ ...e(); }': () | 238 | 139..179 '{ ...e(); }': () |
239 | 149..150 'a': Gen<u32, u64> | 239 | 149..150 'a': Gen<u32, u64> |
240 | 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64> | 240 | 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64> |
241 | 153..176 'Gen::<...make()': Gen<u32, u64> | 241 | 153..176 'Gen::<...make()': Gen<u32, u64> |
242 | "### | 242 | "#]], |
243 | ); | 243 | ); |
244 | } | 244 | } |
245 | 245 | ||
@@ -267,416 +267,416 @@ mod foo { | |||
267 | #[test] | 267 | #[test] |
268 | fn infer_trait_method_simple() { | 268 | fn infer_trait_method_simple() { |
269 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 269 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
270 | assert_snapshot!( | 270 | check_infer( |
271 | infer(r#" | 271 | r#" |
272 | trait Trait1 { | 272 | trait Trait1 { |
273 | fn method(&self) -> u32; | 273 | fn method(&self) -> u32; |
274 | } | 274 | } |
275 | struct S1; | 275 | struct S1; |
276 | impl Trait1 for S1 {} | 276 | impl Trait1 for S1 {} |
277 | trait Trait2 { | 277 | trait Trait2 { |
278 | fn method(&self) -> i128; | 278 | fn method(&self) -> i128; |
279 | } | 279 | } |
280 | struct S2; | 280 | struct S2; |
281 | impl Trait2 for S2 {} | 281 | impl Trait2 for S2 {} |
282 | fn test() { | 282 | fn test() { |
283 | S1.method(); // -> u32 | 283 | S1.method(); // -> u32 |
284 | S2.method(); // -> i128 | 284 | S2.method(); // -> i128 |
285 | } | 285 | } |
286 | "#), | 286 | "#, |
287 | @r###" | 287 | expect![[r#" |
288 | 30..34 'self': &Self | 288 | 30..34 'self': &Self |
289 | 109..113 'self': &Self | 289 | 109..113 'self': &Self |
290 | 169..227 '{ ...i128 }': () | 290 | 169..227 '{ ...i128 }': () |
291 | 175..177 'S1': S1 | 291 | 175..177 'S1': S1 |
292 | 175..186 'S1.method()': u32 | 292 | 175..186 'S1.method()': u32 |
293 | 202..204 'S2': S2 | 293 | 202..204 'S2': S2 |
294 | 202..213 'S2.method()': i128 | 294 | 202..213 'S2.method()': i128 |
295 | "### | 295 | "#]], |
296 | ); | 296 | ); |
297 | } | 297 | } |
298 | 298 | ||
299 | #[test] | 299 | #[test] |
300 | fn infer_trait_method_scoped() { | 300 | fn infer_trait_method_scoped() { |
301 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 301 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
302 | assert_snapshot!( | 302 | check_infer( |
303 | infer(r#" | 303 | r#" |
304 | struct S; | 304 | struct S; |
305 | mod foo { | 305 | mod foo { |
306 | pub trait Trait1 { | 306 | pub trait Trait1 { |
307 | fn method(&self) -> u32; | 307 | fn method(&self) -> u32; |
308 | } | 308 | } |
309 | impl Trait1 for super::S {} | 309 | impl Trait1 for super::S {} |
310 | } | 310 | } |
311 | mod bar { | 311 | mod bar { |
312 | pub trait Trait2 { | 312 | pub trait Trait2 { |
313 | fn method(&self) -> i128; | 313 | fn method(&self) -> i128; |
314 | } | 314 | } |
315 | impl Trait2 for super::S {} | 315 | impl Trait2 for super::S {} |
316 | } | 316 | } |
317 | 317 | ||
318 | mod foo_test { | 318 | mod foo_test { |
319 | use super::S; | 319 | use super::S; |
320 | use super::foo::Trait1; | 320 | use super::foo::Trait1; |
321 | fn test() { | 321 | fn test() { |
322 | S.method(); // -> u32 | 322 | S.method(); // -> u32 |
323 | } | 323 | } |
324 | } | 324 | } |
325 | 325 | ||
326 | mod bar_test { | 326 | mod bar_test { |
327 | use super::S; | 327 | use super::S; |
328 | use super::bar::Trait2; | 328 | use super::bar::Trait2; |
329 | fn test() { | 329 | fn test() { |
330 | S.method(); // -> i128 | 330 | S.method(); // -> i128 |
331 | } | 331 | } |
332 | } | 332 | } |
333 | "#), | 333 | "#, |
334 | @r###" | 334 | expect![[r#" |
335 | 62..66 'self': &Self | 335 | 62..66 'self': &Self |
336 | 168..172 'self': &Self | 336 | 168..172 'self': &Self |
337 | 299..336 '{ ... }': () | 337 | 299..336 '{ ... }': () |
338 | 309..310 'S': S | 338 | 309..310 'S': S |
339 | 309..319 'S.method()': u32 | 339 | 309..319 'S.method()': u32 |
340 | 415..453 '{ ... }': () | 340 | 415..453 '{ ... }': () |
341 | 425..426 'S': S | 341 | 425..426 'S': S |
342 | 425..435 'S.method()': i128 | 342 | 425..435 'S.method()': i128 |
343 | "### | 343 | "#]], |
344 | ); | 344 | ); |
345 | } | 345 | } |
346 | 346 | ||
347 | #[test] | 347 | #[test] |
348 | fn infer_trait_method_generic_1() { | 348 | fn infer_trait_method_generic_1() { |
349 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 349 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
350 | assert_snapshot!( | 350 | check_infer( |
351 | infer(r#" | 351 | r#" |
352 | trait Trait<T> { | 352 | trait Trait<T> { |
353 | fn method(&self) -> T; | 353 | fn method(&self) -> T; |
354 | } | 354 | } |
355 | struct S; | 355 | struct S; |
356 | impl Trait<u32> for S {} | 356 | impl Trait<u32> for S {} |
357 | fn test() { | 357 | fn test() { |
358 | S.method(); | 358 | S.method(); |
359 | } | 359 | } |
360 | "#), | 360 | "#, |
361 | @r###" | 361 | expect![[r#" |
362 | 32..36 'self': &Self | 362 | 32..36 'self': &Self |
363 | 91..110 '{ ...d(); }': () | 363 | 91..110 '{ ...d(); }': () |
364 | 97..98 'S': S | 364 | 97..98 'S': S |
365 | 97..107 'S.method()': u32 | 365 | 97..107 'S.method()': u32 |
366 | "### | 366 | "#]], |
367 | ); | 367 | ); |
368 | } | 368 | } |
369 | 369 | ||
370 | #[test] | 370 | #[test] |
371 | fn infer_trait_method_generic_more_params() { | 371 | fn infer_trait_method_generic_more_params() { |
372 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 372 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
373 | assert_snapshot!( | 373 | check_infer( |
374 | infer(r#" | 374 | r#" |
375 | trait Trait<T1, T2, T3> { | 375 | trait Trait<T1, T2, T3> { |
376 | fn method1(&self) -> (T1, T2, T3); | 376 | fn method1(&self) -> (T1, T2, T3); |
377 | fn method2(&self) -> (T3, T2, T1); | 377 | fn method2(&self) -> (T3, T2, T1); |
378 | } | 378 | } |
379 | struct S1; | 379 | struct S1; |
380 | impl Trait<u8, u16, u32> for S1 {} | 380 | impl Trait<u8, u16, u32> for S1 {} |
381 | struct S2; | 381 | struct S2; |
382 | impl<T> Trait<i8, i16, T> for S2 {} | 382 | impl<T> Trait<i8, i16, T> for S2 {} |
383 | fn test() { | 383 | fn test() { |
384 | S1.method1(); // u8, u16, u32 | 384 | S1.method1(); // u8, u16, u32 |
385 | S1.method2(); // u32, u16, u8 | 385 | S1.method2(); // u32, u16, u8 |
386 | S2.method1(); // i8, i16, {unknown} | 386 | S2.method1(); // i8, i16, {unknown} |
387 | S2.method2(); // {unknown}, i16, i8 | 387 | S2.method2(); // {unknown}, i16, i8 |
388 | } | 388 | } |
389 | "#), | 389 | "#, |
390 | @r###" | 390 | expect![[r#" |
391 | 42..46 'self': &Self | 391 | 42..46 'self': &Self |
392 | 81..85 'self': &Self | 392 | 81..85 'self': &Self |
393 | 209..360 '{ ..., i8 }': () | 393 | 209..360 '{ ..., i8 }': () |
394 | 215..217 'S1': S1 | 394 | 215..217 'S1': S1 |
395 | 215..227 'S1.method1()': (u8, u16, u32) | 395 | 215..227 'S1.method1()': (u8, u16, u32) |
396 | 249..251 'S1': S1 | 396 | 249..251 'S1': S1 |
397 | 249..261 'S1.method2()': (u32, u16, u8) | 397 | 249..261 'S1.method2()': (u32, u16, u8) |
398 | 283..285 'S2': S2 | 398 | 283..285 'S2': S2 |
399 | 283..295 'S2.method1()': (i8, i16, {unknown}) | 399 | 283..295 'S2.method1()': (i8, i16, {unknown}) |
400 | 323..325 'S2': S2 | 400 | 323..325 'S2': S2 |
401 | 323..335 'S2.method2()': ({unknown}, i16, i8) | 401 | 323..335 'S2.method2()': ({unknown}, i16, i8) |
402 | "### | 402 | "#]], |
403 | ); | 403 | ); |
404 | } | 404 | } |
405 | 405 | ||
406 | #[test] | 406 | #[test] |
407 | fn infer_trait_method_generic_2() { | 407 | fn infer_trait_method_generic_2() { |
408 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 408 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
409 | assert_snapshot!( | 409 | check_infer( |
410 | infer(r#" | 410 | r#" |
411 | trait Trait<T> { | 411 | trait Trait<T> { |
412 | fn method(&self) -> T; | 412 | fn method(&self) -> T; |
413 | } | 413 | } |
414 | struct S<T>(T); | 414 | struct S<T>(T); |
415 | impl<U> Trait<U> for S<U> {} | 415 | impl<U> Trait<U> for S<U> {} |
416 | fn test() { | 416 | fn test() { |
417 | S(1u32).method(); | 417 | S(1u32).method(); |
418 | } | 418 | } |
419 | "#), | 419 | "#, |
420 | @r###" | 420 | expect![[r#" |
421 | 32..36 'self': &Self | 421 | 32..36 'self': &Self |
422 | 101..126 '{ ...d(); }': () | 422 | 101..126 '{ ...d(); }': () |
423 | 107..108 'S': S<u32>(u32) -> S<u32> | 423 | 107..108 'S': S<u32>(u32) -> S<u32> |
424 | 107..114 'S(1u32)': S<u32> | 424 | 107..114 'S(1u32)': S<u32> |
425 | 107..123 'S(1u32...thod()': u32 | 425 | 107..123 'S(1u32...thod()': u32 |
426 | 109..113 '1u32': u32 | 426 | 109..113 '1u32': u32 |
427 | "### | 427 | "#]], |
428 | ); | 428 | ); |
429 | } | 429 | } |
430 | 430 | ||
431 | #[test] | 431 | #[test] |
432 | fn infer_trait_assoc_method() { | 432 | fn infer_trait_assoc_method() { |
433 | assert_snapshot!( | 433 | check_infer( |
434 | infer(r#" | 434 | r#" |
435 | trait Default { | 435 | trait Default { |
436 | fn default() -> Self; | 436 | fn default() -> Self; |
437 | } | 437 | } |
438 | struct S; | 438 | struct S; |
439 | impl Default for S {} | 439 | impl Default for S {} |
440 | fn test() { | 440 | fn test() { |
441 | let s1: S = Default::default(); | 441 | let s1: S = Default::default(); |
442 | let s2 = S::default(); | 442 | let s2 = S::default(); |
443 | let s3 = <S as Default>::default(); | 443 | let s3 = <S as Default>::default(); |
444 | } | 444 | } |
445 | "#), | 445 | "#, |
446 | @r###" | 446 | expect![[r#" |
447 | 86..192 '{ ...t(); }': () | 447 | 86..192 '{ ...t(); }': () |
448 | 96..98 's1': S | 448 | 96..98 's1': S |
449 | 104..120 'Defaul...efault': fn default<S>() -> S | 449 | 104..120 'Defaul...efault': fn default<S>() -> S |
450 | 104..122 'Defaul...ault()': S | 450 | 104..122 'Defaul...ault()': S |
451 | 132..134 's2': S | 451 | 132..134 's2': S |
452 | 137..147 'S::default': fn default<S>() -> S | 452 | 137..147 'S::default': fn default<S>() -> S |
453 | 137..149 'S::default()': S | 453 | 137..149 'S::default()': S |
454 | 159..161 's3': S | 454 | 159..161 's3': S |
455 | 164..187 '<S as ...efault': fn default<S>() -> S | 455 | 164..187 '<S as ...efault': fn default<S>() -> S |
456 | 164..189 '<S as ...ault()': S | 456 | 164..189 '<S as ...ault()': S |
457 | "### | 457 | "#]], |
458 | ); | 458 | ); |
459 | } | 459 | } |
460 | 460 | ||
461 | #[test] | 461 | #[test] |
462 | fn infer_trait_assoc_method_generics_1() { | 462 | fn infer_trait_assoc_method_generics_1() { |
463 | assert_snapshot!( | 463 | check_infer( |
464 | infer(r#" | 464 | r#" |
465 | trait Trait<T> { | 465 | trait Trait<T> { |
466 | fn make() -> T; | 466 | fn make() -> T; |
467 | } | 467 | } |
468 | struct S; | 468 | struct S; |
469 | impl Trait<u32> for S {} | 469 | impl Trait<u32> for S {} |
470 | struct G<T>; | 470 | struct G<T>; |
471 | impl<T> Trait<T> for G<T> {} | 471 | impl<T> Trait<T> for G<T> {} |
472 | fn test() { | 472 | fn test() { |
473 | let a = S::make(); | 473 | let a = S::make(); |
474 | let b = G::<u64>::make(); | 474 | let b = G::<u64>::make(); |
475 | let c: f64 = G::make(); | 475 | let c: f64 = G::make(); |
476 | } | 476 | } |
477 | "#), | 477 | "#, |
478 | @r###" | 478 | expect![[r#" |
479 | 126..210 '{ ...e(); }': () | 479 | 126..210 '{ ...e(); }': () |
480 | 136..137 'a': u32 | 480 | 136..137 'a': u32 |
481 | 140..147 'S::make': fn make<S, u32>() -> u32 | 481 | 140..147 'S::make': fn make<S, u32>() -> u32 |
482 | 140..149 'S::make()': u32 | 482 | 140..149 'S::make()': u32 |
483 | 159..160 'b': u64 | 483 | 159..160 'b': u64 |
484 | 163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64 | 484 | 163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64 |
485 | 163..179 'G::<u6...make()': u64 | 485 | 163..179 'G::<u6...make()': u64 |
486 | 189..190 'c': f64 | 486 | 189..190 'c': f64 |
487 | 198..205 'G::make': fn make<G<f64>, f64>() -> f64 | 487 | 198..205 'G::make': fn make<G<f64>, f64>() -> f64 |
488 | 198..207 'G::make()': f64 | 488 | 198..207 'G::make()': f64 |
489 | "### | 489 | "#]], |
490 | ); | 490 | ); |
491 | } | 491 | } |
492 | 492 | ||
493 | #[test] | 493 | #[test] |
494 | fn infer_trait_assoc_method_generics_2() { | 494 | fn infer_trait_assoc_method_generics_2() { |
495 | assert_snapshot!( | 495 | check_infer( |
496 | infer(r#" | 496 | r#" |
497 | trait Trait<T> { | 497 | trait Trait<T> { |
498 | fn make<U>() -> (T, U); | 498 | fn make<U>() -> (T, U); |
499 | } | 499 | } |
500 | struct S; | 500 | struct S; |
501 | impl Trait<u32> for S {} | 501 | impl Trait<u32> for S {} |
502 | struct G<T>; | 502 | struct G<T>; |
503 | impl<T> Trait<T> for G<T> {} | 503 | impl<T> Trait<T> for G<T> {} |
504 | fn test() { | 504 | fn test() { |
505 | let a = S::make::<i64>(); | 505 | let a = S::make::<i64>(); |
506 | let b: (_, i64) = S::make(); | 506 | let b: (_, i64) = S::make(); |
507 | let c = G::<u32>::make::<i64>(); | 507 | let c = G::<u32>::make::<i64>(); |
508 | let d: (u32, _) = G::make::<i64>(); | 508 | let d: (u32, _) = G::make::<i64>(); |
509 | let e: (u32, i64) = G::make(); | 509 | let e: (u32, i64) = G::make(); |
510 | } | 510 | } |
511 | "#), | 511 | "#, |
512 | @r###" | 512 | expect![[r#" |
513 | 134..312 '{ ...e(); }': () | 513 | 134..312 '{ ...e(); }': () |
514 | 144..145 'a': (u32, i64) | 514 | 144..145 'a': (u32, i64) |
515 | 148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64) | 515 | 148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64) |
516 | 148..164 'S::mak...i64>()': (u32, i64) | 516 | 148..164 'S::mak...i64>()': (u32, i64) |
517 | 174..175 'b': (u32, i64) | 517 | 174..175 'b': (u32, i64) |
518 | 188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64) | 518 | 188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64) |
519 | 188..197 'S::make()': (u32, i64) | 519 | 188..197 'S::make()': (u32, i64) |
520 | 207..208 'c': (u32, i64) | 520 | 207..208 'c': (u32, i64) |
521 | 211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) | 521 | 211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) |
522 | 211..234 'G::<u3...i64>()': (u32, i64) | 522 | 211..234 'G::<u3...i64>()': (u32, i64) |
523 | 244..245 'd': (u32, i64) | 523 | 244..245 'd': (u32, i64) |
524 | 258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) | 524 | 258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) |
525 | 258..274 'G::mak...i64>()': (u32, i64) | 525 | 258..274 'G::mak...i64>()': (u32, i64) |
526 | 284..285 'e': (u32, i64) | 526 | 284..285 'e': (u32, i64) |
527 | 300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64) | 527 | 300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64) |
528 | 300..309 'G::make()': (u32, i64) | 528 | 300..309 'G::make()': (u32, i64) |
529 | "### | 529 | "#]], |
530 | ); | 530 | ); |
531 | } | 531 | } |
532 | 532 | ||
533 | #[test] | 533 | #[test] |
534 | fn infer_trait_assoc_method_generics_3() { | 534 | fn infer_trait_assoc_method_generics_3() { |
535 | assert_snapshot!( | 535 | check_infer( |
536 | infer(r#" | 536 | r#" |
537 | trait Trait<T> { | 537 | trait Trait<T> { |
538 | fn make() -> (Self, T); | 538 | fn make() -> (Self, T); |
539 | } | 539 | } |
540 | struct S<T>; | 540 | struct S<T>; |
541 | impl Trait<i64> for S<i32> {} | 541 | impl Trait<i64> for S<i32> {} |
542 | fn test() { | 542 | fn test() { |
543 | let a = S::make(); | 543 | let a = S::make(); |
544 | } | 544 | } |
545 | "#), | 545 | "#, |
546 | @r###" | 546 | expect![[r#" |
547 | 100..126 '{ ...e(); }': () | 547 | 100..126 '{ ...e(); }': () |
548 | 110..111 'a': (S<i32>, i64) | 548 | 110..111 'a': (S<i32>, i64) |
549 | 114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64) | 549 | 114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64) |
550 | 114..123 'S::make()': (S<i32>, i64) | 550 | 114..123 'S::make()': (S<i32>, i64) |
551 | "### | 551 | "#]], |
552 | ); | 552 | ); |
553 | } | 553 | } |
554 | 554 | ||
555 | #[test] | 555 | #[test] |
556 | fn infer_trait_assoc_method_generics_4() { | 556 | fn infer_trait_assoc_method_generics_4() { |
557 | assert_snapshot!( | 557 | check_infer( |
558 | infer(r#" | 558 | r#" |
559 | trait Trait<T> { | 559 | trait Trait<T> { |
560 | fn make() -> (Self, T); | 560 | fn make() -> (Self, T); |
561 | } | 561 | } |
562 | struct S<T>; | 562 | struct S<T>; |
563 | impl Trait<i64> for S<u64> {} | 563 | impl Trait<i64> for S<u64> {} |
564 | impl Trait<i32> for S<u32> {} | 564 | impl Trait<i32> for S<u32> {} |
565 | fn test() { | 565 | fn test() { |
566 | let a: (S<u64>, _) = S::make(); | 566 | let a: (S<u64>, _) = S::make(); |
567 | let b: (_, i32) = S::make(); | 567 | let b: (_, i32) = S::make(); |
568 | } | 568 | } |
569 | "#), | 569 | "#, |
570 | @r###" | 570 | expect![[r#" |
571 | 130..202 '{ ...e(); }': () | 571 | 130..202 '{ ...e(); }': () |
572 | 140..141 'a': (S<u64>, i64) | 572 | 140..141 'a': (S<u64>, i64) |
573 | 157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64) | 573 | 157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64) |
574 | 157..166 'S::make()': (S<u64>, i64) | 574 | 157..166 'S::make()': (S<u64>, i64) |
575 | 176..177 'b': (S<u32>, i32) | 575 | 176..177 'b': (S<u32>, i32) |
576 | 190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32) | 576 | 190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32) |
577 | 190..199 'S::make()': (S<u32>, i32) | 577 | 190..199 'S::make()': (S<u32>, i32) |
578 | "### | 578 | "#]], |
579 | ); | 579 | ); |
580 | } | 580 | } |
581 | 581 | ||
582 | #[test] | 582 | #[test] |
583 | fn infer_trait_assoc_method_generics_5() { | 583 | fn infer_trait_assoc_method_generics_5() { |
584 | assert_snapshot!( | 584 | check_infer( |
585 | infer(r#" | 585 | r#" |
586 | trait Trait<T> { | 586 | trait Trait<T> { |
587 | fn make<U>() -> (Self, T, U); | 587 | fn make<U>() -> (Self, T, U); |
588 | } | 588 | } |
589 | struct S<T>; | 589 | struct S<T>; |
590 | impl Trait<i64> for S<u64> {} | 590 | impl Trait<i64> for S<u64> {} |
591 | fn test() { | 591 | fn test() { |
592 | let a = <S as Trait<i64>>::make::<u8>(); | 592 | let a = <S as Trait<i64>>::make::<u8>(); |
593 | let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>(); | 593 | let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>(); |
594 | } | 594 | } |
595 | "#), | 595 | "#, |
596 | @r###" | 596 | expect![[r#" |
597 | 106..210 '{ ...>(); }': () | 597 | 106..210 '{ ...>(); }': () |
598 | 116..117 'a': (S<u64>, i64, u8) | 598 | 116..117 'a': (S<u64>, i64, u8) |
599 | 120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) | 599 | 120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) |
600 | 120..151 '<S as ...<u8>()': (S<u64>, i64, u8) | 600 | 120..151 '<S as ...<u8>()': (S<u64>, i64, u8) |
601 | 161..162 'b': (S<u64>, i64, u8) | 601 | 161..162 'b': (S<u64>, i64, u8) |
602 | 181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) | 602 | 181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) |
603 | 181..207 'Trait:...<u8>()': (S<u64>, i64, u8) | 603 | 181..207 'Trait:...<u8>()': (S<u64>, i64, u8) |
604 | "### | 604 | "#]], |
605 | ); | 605 | ); |
606 | } | 606 | } |
607 | 607 | ||
608 | #[test] | 608 | #[test] |
609 | fn infer_call_trait_method_on_generic_param_1() { | 609 | fn infer_call_trait_method_on_generic_param_1() { |
610 | assert_snapshot!( | 610 | check_infer( |
611 | infer(r#" | 611 | r#" |
612 | trait Trait { | 612 | trait Trait { |
613 | fn method(&self) -> u32; | 613 | fn method(&self) -> u32; |
614 | } | 614 | } |
615 | fn test<T: Trait>(t: T) { | 615 | fn test<T: Trait>(t: T) { |
616 | t.method(); | 616 | t.method(); |
617 | } | 617 | } |
618 | "#), | 618 | "#, |
619 | @r###" | 619 | expect![[r#" |
620 | 29..33 'self': &Self | 620 | 29..33 'self': &Self |
621 | 63..64 't': T | 621 | 63..64 't': T |
622 | 69..88 '{ ...d(); }': () | 622 | 69..88 '{ ...d(); }': () |
623 | 75..76 't': T | 623 | 75..76 't': T |
624 | 75..85 't.method()': u32 | 624 | 75..85 't.method()': u32 |
625 | "### | 625 | "#]], |
626 | ); | 626 | ); |
627 | } | 627 | } |
628 | 628 | ||
629 | #[test] | 629 | #[test] |
630 | fn infer_call_trait_method_on_generic_param_2() { | 630 | fn infer_call_trait_method_on_generic_param_2() { |
631 | assert_snapshot!( | 631 | check_infer( |
632 | infer(r#" | 632 | r#" |
633 | trait Trait<T> { | 633 | trait Trait<T> { |
634 | fn method(&self) -> T; | 634 | fn method(&self) -> T; |
635 | } | 635 | } |
636 | fn test<U, T: Trait<U>>(t: T) { | 636 | fn test<U, T: Trait<U>>(t: T) { |
637 | t.method(); | 637 | t.method(); |
638 | } | 638 | } |
639 | "#), | 639 | "#, |
640 | @r###" | 640 | expect![[r#" |
641 | 32..36 'self': &Self | 641 | 32..36 'self': &Self |
642 | 70..71 't': T | 642 | 70..71 't': T |
643 | 76..95 '{ ...d(); }': () | 643 | 76..95 '{ ...d(); }': () |
644 | 82..83 't': T | 644 | 82..83 't': T |
645 | 82..92 't.method()': U | 645 | 82..92 't.method()': U |
646 | "### | 646 | "#]], |
647 | ); | 647 | ); |
648 | } | 648 | } |
649 | 649 | ||
650 | #[test] | 650 | #[test] |
651 | fn infer_with_multiple_trait_impls() { | 651 | fn infer_with_multiple_trait_impls() { |
652 | assert_snapshot!( | 652 | check_infer( |
653 | infer(r#" | 653 | r#" |
654 | trait Into<T> { | 654 | trait Into<T> { |
655 | fn into(self) -> T; | 655 | fn into(self) -> T; |
656 | } | 656 | } |
657 | struct S; | 657 | struct S; |
658 | impl Into<u32> for S {} | 658 | impl Into<u32> for S {} |
659 | impl Into<u64> for S {} | 659 | impl Into<u64> for S {} |
660 | fn test() { | 660 | fn test() { |
661 | let x: u32 = S.into(); | 661 | let x: u32 = S.into(); |
662 | let y: u64 = S.into(); | 662 | let y: u64 = S.into(); |
663 | let z = Into::<u64>::into(S); | 663 | let z = Into::<u64>::into(S); |
664 | } | 664 | } |
665 | "#), | 665 | "#, |
666 | @r###" | 666 | expect![[r#" |
667 | 28..32 'self': Self | 667 | 28..32 'self': Self |
668 | 110..201 '{ ...(S); }': () | 668 | 110..201 '{ ...(S); }': () |
669 | 120..121 'x': u32 | 669 | 120..121 'x': u32 |
670 | 129..130 'S': S | 670 | 129..130 'S': S |
671 | 129..137 'S.into()': u32 | 671 | 129..137 'S.into()': u32 |
672 | 147..148 'y': u64 | 672 | 147..148 'y': u64 |
673 | 156..157 'S': S | 673 | 156..157 'S': S |
674 | 156..164 'S.into()': u64 | 674 | 156..164 'S.into()': u64 |
675 | 174..175 'z': u64 | 675 | 174..175 'z': u64 |
676 | 178..195 'Into::...::into': fn into<S, u64>(S) -> u64 | 676 | 178..195 'Into::...::into': fn into<S, u64>(S) -> u64 |
677 | 178..198 'Into::...nto(S)': u64 | 677 | 178..198 'Into::...nto(S)': u64 |
678 | 196..197 'S': S | 678 | 196..197 'S': S |
679 | "### | 679 | "#]], |
680 | ); | 680 | ); |
681 | } | 681 | } |
682 | 682 | ||
@@ -1023,31 +1023,31 @@ fn test() { (S {}).method(); } | |||
1023 | 1023 | ||
1024 | #[test] | 1024 | #[test] |
1025 | fn dyn_trait_super_trait_not_in_scope() { | 1025 | fn dyn_trait_super_trait_not_in_scope() { |
1026 | assert_snapshot!( | 1026 | check_infer( |
1027 | infer(r#" | 1027 | r#" |
1028 | mod m { | 1028 | mod m { |
1029 | pub trait SuperTrait { | 1029 | pub trait SuperTrait { |
1030 | fn foo(&self) -> u32 { 0 } | 1030 | fn foo(&self) -> u32 { 0 } |
1031 | } | 1031 | } |
1032 | } | 1032 | } |
1033 | trait Trait: m::SuperTrait {} | 1033 | trait Trait: m::SuperTrait {} |
1034 | 1034 | ||
1035 | struct S; | 1035 | struct S; |
1036 | impl m::SuperTrait for S {} | 1036 | impl m::SuperTrait for S {} |
1037 | impl Trait for S {} | 1037 | impl Trait for S {} |
1038 | 1038 | ||
1039 | fn test(d: &dyn Trait) { | 1039 | fn test(d: &dyn Trait) { |
1040 | d.foo(); | 1040 | d.foo(); |
1041 | } | 1041 | } |
1042 | "#), | 1042 | "#, |
1043 | @r###" | 1043 | expect![[r#" |
1044 | 51..55 'self': &Self | 1044 | 51..55 'self': &Self |
1045 | 64..69 '{ 0 }': u32 | 1045 | 64..69 '{ 0 }': u32 |
1046 | 66..67 '0': u32 | 1046 | 66..67 '0': u32 |
1047 | 176..177 'd': &dyn Trait | 1047 | 176..177 'd': &dyn Trait |
1048 | 191..207 '{ ...o(); }': () | 1048 | 191..207 '{ ...o(); }': () |
1049 | 197..198 'd': &dyn Trait | 1049 | 197..198 'd': &dyn Trait |
1050 | 197..204 'd.foo()': u32 | 1050 | 197..204 'd.foo()': u32 |
1051 | "### | 1051 | "#]], |
1052 | ); | 1052 | ); |
1053 | } | 1053 | } |
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs index 64d421d40..49538b572 100644 --- a/crates/ra_hir_ty/src/tests/never_type.rs +++ b/crates/ra_hir_ty/src/tests/never_type.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use insta::assert_snapshot; | 1 | use expect::expect; |
2 | 2 | ||
3 | use super::{check_types, infer_with_mismatches}; | 3 | use super::{check_infer_with_mismatches, check_types}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn infer_never1() { | 6 | fn infer_never1() { |
@@ -240,173 +240,170 @@ fn test(a: i32) { | |||
240 | 240 | ||
241 | #[test] | 241 | #[test] |
242 | fn diverging_expression_1() { | 242 | fn diverging_expression_1() { |
243 | let t = infer_with_mismatches( | 243 | check_infer_with_mismatches( |
244 | r#" | 244 | r" |
245 | //- /main.rs | 245 | //- /main.rs |
246 | fn test1() { | 246 | fn test1() { |
247 | let x: u32 = return; | 247 | let x: u32 = return; |
248 | } | 248 | } |
249 | fn test2() { | 249 | fn test2() { |
250 | let x: u32 = { return; }; | 250 | let x: u32 = { return; }; |
251 | } | 251 | } |
252 | fn test3() { | 252 | fn test3() { |
253 | let x: u32 = loop {}; | 253 | let x: u32 = loop {}; |
254 | } | 254 | } |
255 | fn test4() { | 255 | fn test4() { |
256 | let x: u32 = { loop {} }; | 256 | let x: u32 = { loop {} }; |
257 | } | 257 | } |
258 | fn test5() { | 258 | fn test5() { |
259 | let x: u32 = { if true { loop {}; } else { loop {}; } }; | 259 | let x: u32 = { if true { loop {}; } else { loop {}; } }; |
260 | } | 260 | } |
261 | fn test6() { | 261 | fn test6() { |
262 | let x: u32 = { let y: u32 = { loop {}; }; }; | 262 | let x: u32 = { let y: u32 = { loop {}; }; }; |
263 | } | 263 | } |
264 | "#, | 264 | ", |
265 | true, | 265 | expect![[r" |
266 | 11..39 '{ ...urn; }': () | ||
267 | 21..22 'x': u32 | ||
268 | 30..36 'return': ! | ||
269 | 51..84 '{ ...; }; }': () | ||
270 | 61..62 'x': u32 | ||
271 | 70..81 '{ return; }': u32 | ||
272 | 72..78 'return': ! | ||
273 | 96..125 '{ ... {}; }': () | ||
274 | 106..107 'x': u32 | ||
275 | 115..122 'loop {}': ! | ||
276 | 120..122 '{}': () | ||
277 | 137..170 '{ ...} }; }': () | ||
278 | 147..148 'x': u32 | ||
279 | 156..167 '{ loop {} }': u32 | ||
280 | 158..165 'loop {}': ! | ||
281 | 163..165 '{}': () | ||
282 | 182..246 '{ ...} }; }': () | ||
283 | 192..193 'x': u32 | ||
284 | 201..243 '{ if t...}; } }': u32 | ||
285 | 203..241 'if tru... {}; }': u32 | ||
286 | 206..210 'true': bool | ||
287 | 211..223 '{ loop {}; }': u32 | ||
288 | 213..220 'loop {}': ! | ||
289 | 218..220 '{}': () | ||
290 | 229..241 '{ loop {}; }': u32 | ||
291 | 231..238 'loop {}': ! | ||
292 | 236..238 '{}': () | ||
293 | 258..310 '{ ...; }; }': () | ||
294 | 268..269 'x': u32 | ||
295 | 277..307 '{ let ...; }; }': u32 | ||
296 | 283..284 'y': u32 | ||
297 | 292..304 '{ loop {}; }': u32 | ||
298 | 294..301 'loop {}': ! | ||
299 | 299..301 '{}': () | ||
300 | "]], | ||
266 | ); | 301 | ); |
267 | assert_snapshot!(t, @r###" | ||
268 | 11..39 '{ ...urn; }': () | ||
269 | 21..22 'x': u32 | ||
270 | 30..36 'return': ! | ||
271 | 51..84 '{ ...; }; }': () | ||
272 | 61..62 'x': u32 | ||
273 | 70..81 '{ return; }': u32 | ||
274 | 72..78 'return': ! | ||
275 | 96..125 '{ ... {}; }': () | ||
276 | 106..107 'x': u32 | ||
277 | 115..122 'loop {}': ! | ||
278 | 120..122 '{}': () | ||
279 | 137..170 '{ ...} }; }': () | ||
280 | 147..148 'x': u32 | ||
281 | 156..167 '{ loop {} }': u32 | ||
282 | 158..165 'loop {}': ! | ||
283 | 163..165 '{}': () | ||
284 | 182..246 '{ ...} }; }': () | ||
285 | 192..193 'x': u32 | ||
286 | 201..243 '{ if t...}; } }': u32 | ||
287 | 203..241 'if tru... {}; }': u32 | ||
288 | 206..210 'true': bool | ||
289 | 211..223 '{ loop {}; }': u32 | ||
290 | 213..220 'loop {}': ! | ||
291 | 218..220 '{}': () | ||
292 | 229..241 '{ loop {}; }': u32 | ||
293 | 231..238 'loop {}': ! | ||
294 | 236..238 '{}': () | ||
295 | 258..310 '{ ...; }; }': () | ||
296 | 268..269 'x': u32 | ||
297 | 277..307 '{ let ...; }; }': u32 | ||
298 | 283..284 'y': u32 | ||
299 | 292..304 '{ loop {}; }': u32 | ||
300 | 294..301 'loop {}': ! | ||
301 | 299..301 '{}': () | ||
302 | "###); | ||
303 | } | 302 | } |
304 | 303 | ||
305 | #[test] | 304 | #[test] |
306 | fn diverging_expression_2() { | 305 | fn diverging_expression_2() { |
307 | let t = infer_with_mismatches( | 306 | check_infer_with_mismatches( |
308 | r#" | 307 | r#" |
309 | //- /main.rs | 308 | //- /main.rs |
310 | fn test1() { | 309 | fn test1() { |
311 | // should give type mismatch | 310 | // should give type mismatch |
312 | let x: u32 = { loop {}; "foo" }; | 311 | let x: u32 = { loop {}; "foo" }; |
313 | } | 312 | } |
314 | "#, | 313 | "#, |
315 | true, | 314 | expect![[r#" |
315 | 11..84 '{ ..." }; }': () | ||
316 | 54..55 'x': u32 | ||
317 | 63..81 '{ loop...foo" }': &str | ||
318 | 65..72 'loop {}': ! | ||
319 | 70..72 '{}': () | ||
320 | 74..79 '"foo"': &str | ||
321 | 63..81: expected u32, got &str | ||
322 | 74..79: expected u32, got &str | ||
323 | "#]], | ||
316 | ); | 324 | ); |
317 | assert_snapshot!(t, @r###" | ||
318 | 11..84 '{ ..." }; }': () | ||
319 | 54..55 'x': u32 | ||
320 | 63..81 '{ loop...foo" }': &str | ||
321 | 65..72 'loop {}': ! | ||
322 | 70..72 '{}': () | ||
323 | 74..79 '"foo"': &str | ||
324 | 63..81: expected u32, got &str | ||
325 | 74..79: expected u32, got &str | ||
326 | "###); | ||
327 | } | 325 | } |
328 | 326 | ||
329 | #[test] | 327 | #[test] |
330 | fn diverging_expression_3_break() { | 328 | fn diverging_expression_3_break() { |
331 | let t = infer_with_mismatches( | 329 | check_infer_with_mismatches( |
332 | r#" | 330 | r" |
333 | //- /main.rs | 331 | //- /main.rs |
334 | fn test1() { | 332 | fn test1() { |
335 | // should give type mismatch | 333 | // should give type mismatch |
336 | let x: u32 = { loop { break; } }; | 334 | let x: u32 = { loop { break; } }; |
337 | } | 335 | } |
338 | fn test2() { | 336 | fn test2() { |
339 | // should give type mismatch | 337 | // should give type mismatch |
340 | let x: u32 = { for a in b { break; }; }; | 338 | let x: u32 = { for a in b { break; }; }; |
341 | // should give type mismatch as well | 339 | // should give type mismatch as well |
342 | let x: u32 = { for a in b {}; }; | 340 | let x: u32 = { for a in b {}; }; |
343 | // should give type mismatch as well | 341 | // should give type mismatch as well |
344 | let x: u32 = { for a in b { return; }; }; | 342 | let x: u32 = { for a in b { return; }; }; |
345 | } | 343 | } |
346 | fn test3() { | 344 | fn test3() { |
347 | // should give type mismatch | 345 | // should give type mismatch |
348 | let x: u32 = { while true { break; }; }; | 346 | let x: u32 = { while true { break; }; }; |
349 | // should give type mismatch as well -- there's an implicit break, even if it's never hit | 347 | // should give type mismatch as well -- there's an implicit break, even if it's never hit |
350 | let x: u32 = { while true {}; }; | 348 | let x: u32 = { while true {}; }; |
351 | // should give type mismatch as well | 349 | // should give type mismatch as well |
352 | let x: u32 = { while true { return; }; }; | 350 | let x: u32 = { while true { return; }; }; |
353 | } | 351 | } |
354 | "#, | 352 | ", |
355 | true, | 353 | expect![[r" |
354 | 11..85 '{ ...} }; }': () | ||
355 | 54..55 'x': u32 | ||
356 | 63..82 '{ loop...k; } }': () | ||
357 | 65..80 'loop { break; }': () | ||
358 | 70..80 '{ break; }': () | ||
359 | 72..77 'break': ! | ||
360 | 63..82: expected u32, got () | ||
361 | 65..80: expected u32, got () | ||
362 | 97..343 '{ ...; }; }': () | ||
363 | 140..141 'x': u32 | ||
364 | 149..175 '{ for ...; }; }': () | ||
365 | 151..172 'for a ...eak; }': () | ||
366 | 155..156 'a': {unknown} | ||
367 | 160..161 'b': {unknown} | ||
368 | 162..172 '{ break; }': () | ||
369 | 164..169 'break': ! | ||
370 | 226..227 'x': u32 | ||
371 | 235..253 '{ for ... {}; }': () | ||
372 | 237..250 'for a in b {}': () | ||
373 | 241..242 'a': {unknown} | ||
374 | 246..247 'b': {unknown} | ||
375 | 248..250 '{}': () | ||
376 | 304..305 'x': u32 | ||
377 | 313..340 '{ for ...; }; }': () | ||
378 | 315..337 'for a ...urn; }': () | ||
379 | 319..320 'a': {unknown} | ||
380 | 324..325 'b': {unknown} | ||
381 | 326..337 '{ return; }': () | ||
382 | 328..334 'return': ! | ||
383 | 149..175: expected u32, got () | ||
384 | 235..253: expected u32, got () | ||
385 | 313..340: expected u32, got () | ||
386 | 355..654 '{ ...; }; }': () | ||
387 | 398..399 'x': u32 | ||
388 | 407..433 '{ whil...; }; }': () | ||
389 | 409..430 'while ...eak; }': () | ||
390 | 415..419 'true': bool | ||
391 | 420..430 '{ break; }': () | ||
392 | 422..427 'break': ! | ||
393 | 537..538 'x': u32 | ||
394 | 546..564 '{ whil... {}; }': () | ||
395 | 548..561 'while true {}': () | ||
396 | 554..558 'true': bool | ||
397 | 559..561 '{}': () | ||
398 | 615..616 'x': u32 | ||
399 | 624..651 '{ whil...; }; }': () | ||
400 | 626..648 'while ...urn; }': () | ||
401 | 632..636 'true': bool | ||
402 | 637..648 '{ return; }': () | ||
403 | 639..645 'return': ! | ||
404 | 407..433: expected u32, got () | ||
405 | 546..564: expected u32, got () | ||
406 | 624..651: expected u32, got () | ||
407 | "]], | ||
356 | ); | 408 | ); |
357 | assert_snapshot!(t, @r###" | ||
358 | 11..85 '{ ...} }; }': () | ||
359 | 54..55 'x': u32 | ||
360 | 63..82 '{ loop...k; } }': () | ||
361 | 65..80 'loop { break; }': () | ||
362 | 70..80 '{ break; }': () | ||
363 | 72..77 'break': ! | ||
364 | 63..82: expected u32, got () | ||
365 | 65..80: expected u32, got () | ||
366 | 97..343 '{ ...; }; }': () | ||
367 | 140..141 'x': u32 | ||
368 | 149..175 '{ for ...; }; }': () | ||
369 | 151..172 'for a ...eak; }': () | ||
370 | 155..156 'a': {unknown} | ||
371 | 160..161 'b': {unknown} | ||
372 | 162..172 '{ break; }': () | ||
373 | 164..169 'break': ! | ||
374 | 226..227 'x': u32 | ||
375 | 235..253 '{ for ... {}; }': () | ||
376 | 237..250 'for a in b {}': () | ||
377 | 241..242 'a': {unknown} | ||
378 | 246..247 'b': {unknown} | ||
379 | 248..250 '{}': () | ||
380 | 304..305 'x': u32 | ||
381 | 313..340 '{ for ...; }; }': () | ||
382 | 315..337 'for a ...urn; }': () | ||
383 | 319..320 'a': {unknown} | ||
384 | 324..325 'b': {unknown} | ||
385 | 326..337 '{ return; }': () | ||
386 | 328..334 'return': ! | ||
387 | 149..175: expected u32, got () | ||
388 | 235..253: expected u32, got () | ||
389 | 313..340: expected u32, got () | ||
390 | 355..654 '{ ...; }; }': () | ||
391 | 398..399 'x': u32 | ||
392 | 407..433 '{ whil...; }; }': () | ||
393 | 409..430 'while ...eak; }': () | ||
394 | 415..419 'true': bool | ||
395 | 420..430 '{ break; }': () | ||
396 | 422..427 'break': ! | ||
397 | 537..538 'x': u32 | ||
398 | 546..564 '{ whil... {}; }': () | ||
399 | 548..561 'while true {}': () | ||
400 | 554..558 'true': bool | ||
401 | 559..561 '{}': () | ||
402 | 615..616 'x': u32 | ||
403 | 624..651 '{ whil...; }; }': () | ||
404 | 626..648 'while ...urn; }': () | ||
405 | 632..636 'true': bool | ||
406 | 637..648 '{ return; }': () | ||
407 | 639..645 'return': ! | ||
408 | 407..433: expected u32, got () | ||
409 | 546..564: expected u32, got () | ||
410 | 624..651: expected u32, got () | ||
411 | "###); | ||
412 | } | 409 | } |
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index f937426bd..39fabf7eb 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs | |||
@@ -1,561 +1,561 @@ | |||
1 | use insta::assert_snapshot; | 1 | use expect::expect; |
2 | use test_utils::mark; | 2 | use test_utils::mark; |
3 | 3 | ||
4 | use super::{infer, infer_with_mismatches}; | 4 | use super::{check_infer, check_infer_with_mismatches}; |
5 | 5 | ||
6 | #[test] | 6 | #[test] |
7 | fn infer_pattern() { | 7 | fn infer_pattern() { |
8 | assert_snapshot!( | 8 | check_infer( |
9 | infer(r#" | 9 | r#" |
10 | fn test(x: &i32) { | 10 | fn test(x: &i32) { |
11 | let y = x; | 11 | let y = x; |
12 | let &z = x; | 12 | let &z = x; |
13 | let a = z; | 13 | let a = z; |
14 | let (c, d) = (1, "hello"); | 14 | let (c, d) = (1, "hello"); |
15 | 15 | ||
16 | for (e, f) in some_iter { | 16 | for (e, f) in some_iter { |
17 | let g = e; | 17 | let g = e; |
18 | } | 18 | } |
19 | 19 | ||
20 | if let [val] = opt { | 20 | if let [val] = opt { |
21 | let h = val; | 21 | let h = val; |
22 | } | 22 | } |
23 | 23 | ||
24 | let lambda = |a: u64, b, c: i32| { a + b; c }; | 24 | let lambda = |a: u64, b, c: i32| { a + b; c }; |
25 | 25 | ||
26 | let ref ref_to_x = x; | 26 | let ref ref_to_x = x; |
27 | let mut mut_x = x; | 27 | let mut mut_x = x; |
28 | let ref mut mut_ref_to_x = x; | 28 | let ref mut mut_ref_to_x = x; |
29 | let k = mut_ref_to_x; | 29 | let k = mut_ref_to_x; |
30 | } | 30 | } |
31 | "#), | 31 | "#, |
32 | @r###" | 32 | expect![[r#" |
33 | 8..9 'x': &i32 | 33 | 8..9 'x': &i32 |
34 | 17..368 '{ ...o_x; }': () | 34 | 17..368 '{ ...o_x; }': () |
35 | 27..28 'y': &i32 | 35 | 27..28 'y': &i32 |
36 | 31..32 'x': &i32 | 36 | 31..32 'x': &i32 |
37 | 42..44 '&z': &i32 | 37 | 42..44 '&z': &i32 |
38 | 43..44 'z': i32 | 38 | 43..44 'z': i32 |
39 | 47..48 'x': &i32 | 39 | 47..48 'x': &i32 |
40 | 58..59 'a': i32 | 40 | 58..59 'a': i32 |
41 | 62..63 'z': i32 | 41 | 62..63 'z': i32 |
42 | 73..79 '(c, d)': (i32, &str) | 42 | 73..79 '(c, d)': (i32, &str) |
43 | 74..75 'c': i32 | 43 | 74..75 'c': i32 |
44 | 77..78 'd': &str | 44 | 77..78 'd': &str |
45 | 82..94 '(1, "hello")': (i32, &str) | 45 | 82..94 '(1, "hello")': (i32, &str) |
46 | 83..84 '1': i32 | 46 | 83..84 '1': i32 |
47 | 86..93 '"hello"': &str | 47 | 86..93 '"hello"': &str |
48 | 101..151 'for (e... }': () | 48 | 101..151 'for (e... }': () |
49 | 105..111 '(e, f)': ({unknown}, {unknown}) | 49 | 105..111 '(e, f)': ({unknown}, {unknown}) |
50 | 106..107 'e': {unknown} | 50 | 106..107 'e': {unknown} |
51 | 109..110 'f': {unknown} | 51 | 109..110 'f': {unknown} |
52 | 115..124 'some_iter': {unknown} | 52 | 115..124 'some_iter': {unknown} |
53 | 125..151 '{ ... }': () | 53 | 125..151 '{ ... }': () |
54 | 139..140 'g': {unknown} | 54 | 139..140 'g': {unknown} |
55 | 143..144 'e': {unknown} | 55 | 143..144 'e': {unknown} |
56 | 157..204 'if let... }': () | 56 | 157..204 'if let... }': () |
57 | 164..169 '[val]': [{unknown}] | 57 | 164..169 '[val]': [{unknown}] |
58 | 165..168 'val': {unknown} | 58 | 165..168 'val': {unknown} |
59 | 172..175 'opt': [{unknown}] | 59 | 172..175 'opt': [{unknown}] |
60 | 176..204 '{ ... }': () | 60 | 176..204 '{ ... }': () |
61 | 190..191 'h': {unknown} | 61 | 190..191 'h': {unknown} |
62 | 194..197 'val': {unknown} | 62 | 194..197 'val': {unknown} |
63 | 214..220 'lambda': |u64, u64, i32| -> i32 | 63 | 214..220 'lambda': |u64, u64, i32| -> i32 |
64 | 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32 | 64 | 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32 |
65 | 224..225 'a': u64 | 65 | 224..225 'a': u64 |
66 | 232..233 'b': u64 | 66 | 232..233 'b': u64 |
67 | 235..236 'c': i32 | 67 | 235..236 'c': i32 |
68 | 243..255 '{ a + b; c }': i32 | 68 | 243..255 '{ a + b; c }': i32 |
69 | 245..246 'a': u64 | 69 | 245..246 'a': u64 |
70 | 245..250 'a + b': u64 | 70 | 245..250 'a + b': u64 |
71 | 249..250 'b': u64 | 71 | 249..250 'b': u64 |
72 | 252..253 'c': i32 | 72 | 252..253 'c': i32 |
73 | 266..278 'ref ref_to_x': &&i32 | 73 | 266..278 'ref ref_to_x': &&i32 |
74 | 281..282 'x': &i32 | 74 | 281..282 'x': &i32 |
75 | 292..301 'mut mut_x': &i32 | 75 | 292..301 'mut mut_x': &i32 |
76 | 304..305 'x': &i32 | 76 | 304..305 'x': &i32 |
77 | 315..335 'ref mu...f_to_x': &mut &i32 | 77 | 315..335 'ref mu...f_to_x': &mut &i32 |
78 | 338..339 'x': &i32 | 78 | 338..339 'x': &i32 |
79 | 349..350 'k': &mut &i32 | 79 | 349..350 'k': &mut &i32 |
80 | 353..365 'mut_ref_to_x': &mut &i32 | 80 | 353..365 'mut_ref_to_x': &mut &i32 |
81 | "### | 81 | "#]], |
82 | ); | 82 | ); |
83 | } | 83 | } |
84 | 84 | ||
85 | #[test] | 85 | #[test] |
86 | fn infer_literal_pattern() { | 86 | fn infer_literal_pattern() { |
87 | assert_snapshot!( | 87 | check_infer_with_mismatches( |
88 | infer_with_mismatches(r#" | 88 | r#" |
89 | fn any<T>() -> T { loop {} } | 89 | fn any<T>() -> T { loop {} } |
90 | fn test(x: &i32) { |