diff options
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/diagnostics.rs | 12 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/decl_check.rs | 6 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 3 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/unsafe_check.rs | 4 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics_sink.rs | 109 | ||||
-rw-r--r-- | crates/hir_ty/src/display.rs | 13 | ||||
-rw-r--r-- | crates/hir_ty/src/infer.rs | 20 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/coerce.rs | 12 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/expr.rs | 13 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/pat.rs | 9 | ||||
-rw-r--r-- | crates/hir_ty/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/hir_ty/src/lower.rs | 5 | ||||
-rw-r--r-- | crates/hir_ty/src/tests.rs | 45 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/coercion.rs | 101 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/incremental.rs | 51 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/macros.rs | 18 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/traits.rs | 142 |
17 files changed, 474 insertions, 90 deletions
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 84fc8ce14..7598e2193 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -8,12 +8,14 @@ use std::{any::Any, fmt}; | |||
8 | 8 | ||
9 | use base_db::CrateId; | 9 | use base_db::CrateId; |
10 | use hir_def::{DefWithBodyId, ModuleDefId}; | 10 | use hir_def::{DefWithBodyId, ModuleDefId}; |
11 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; | ||
12 | use hir_expand::{name::Name, HirFileId, InFile}; | 11 | use hir_expand::{name::Name, HirFileId, InFile}; |
13 | use stdx::format_to; | 12 | use stdx::format_to; |
14 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | 13 | use syntax::{ast, AstPtr, SyntaxNodePtr}; |
15 | 14 | ||
16 | use crate::db::HirDatabase; | 15 | use crate::{ |
16 | db::HirDatabase, | ||
17 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink}, | ||
18 | }; | ||
17 | 19 | ||
18 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; | 20 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; |
19 | 21 | ||
@@ -446,15 +448,13 @@ impl Diagnostic for ReplaceFilterMapNextWithFindMap { | |||
446 | mod tests { | 448 | mod tests { |
447 | use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | 449 | use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; |
448 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; | 450 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; |
449 | use hir_expand::{ | 451 | use hir_expand::db::AstDatabase; |
450 | db::AstDatabase, | ||
451 | diagnostics::{Diagnostic, DiagnosticSinkBuilder}, | ||
452 | }; | ||
453 | use rustc_hash::FxHashMap; | 452 | use rustc_hash::FxHashMap; |
454 | use syntax::{TextRange, TextSize}; | 453 | use syntax::{TextRange, TextSize}; |
455 | 454 | ||
456 | use crate::{ | 455 | use crate::{ |
457 | diagnostics::{validate_body, validate_module_item}, | 456 | diagnostics::{validate_body, validate_module_item}, |
457 | diagnostics_sink::{Diagnostic, DiagnosticSinkBuilder}, | ||
458 | test_db::TestDB, | 458 | test_db::TestDB, |
459 | }; | 459 | }; |
460 | 460 | ||
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index 075dc4131..ef982cbcd 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -19,10 +19,7 @@ use hir_def::{ | |||
19 | src::HasSource, | 19 | src::HasSource, |
20 | AdtId, AttrDefId, ConstId, EnumId, FunctionId, Lookup, ModuleDefId, StaticId, StructId, | 20 | AdtId, AttrDefId, ConstId, EnumId, FunctionId, Lookup, ModuleDefId, StaticId, StructId, |
21 | }; | 21 | }; |
22 | use hir_expand::{ | 22 | use hir_expand::name::{AsName, Name}; |
23 | diagnostics::DiagnosticSink, | ||
24 | name::{AsName, Name}, | ||
25 | }; | ||
26 | use stdx::{always, never}; | 23 | use stdx::{always, never}; |
27 | use syntax::{ | 24 | use syntax::{ |
28 | ast::{self, NameOwner}, | 25 | ast::{self, NameOwner}, |
@@ -32,6 +29,7 @@ use syntax::{ | |||
32 | use crate::{ | 29 | use crate::{ |
33 | db::HirDatabase, | 30 | db::HirDatabase, |
34 | diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, | 31 | diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, |
32 | diagnostics_sink::DiagnosticSink, | ||
35 | }; | 33 | }; |
36 | 34 | ||
37 | mod allow { | 35 | mod allow { |
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index d1f113e7f..86f82e3fa 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId}; | 7 | use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId}; |
8 | use hir_expand::{diagnostics::DiagnosticSink, name}; | 8 | use hir_expand::name; |
9 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
10 | use syntax::{ast, AstPtr}; | 10 | use syntax::{ast, AstPtr}; |
11 | 11 | ||
@@ -16,6 +16,7 @@ use crate::{ | |||
16 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | 16 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, |
17 | MissingPatFields, RemoveThisSemicolon, | 17 | MissingPatFields, RemoveThisSemicolon, |
18 | }, | 18 | }, |
19 | diagnostics_sink::DiagnosticSink, | ||
19 | AdtId, InferenceResult, Interner, TyExt, TyKind, | 20 | AdtId, InferenceResult, Interner, TyExt, TyKind, |
20 | }; | 21 | }; |
21 | 22 | ||
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index 5d13bddea..c3c483425 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -9,10 +9,10 @@ use hir_def::{ | |||
9 | resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, | 9 | resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, |
10 | DefWithBodyId, | 10 | DefWithBodyId, |
11 | }; | 11 | }; |
12 | use hir_expand::diagnostics::DiagnosticSink; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyExt, TyKind, | 14 | db::HirDatabase, diagnostics::MissingUnsafe, diagnostics_sink::DiagnosticSink, InferenceResult, |
15 | Interner, TyExt, TyKind, | ||
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | 18 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { |
diff --git a/crates/hir_ty/src/diagnostics_sink.rs b/crates/hir_ty/src/diagnostics_sink.rs new file mode 100644 index 000000000..084fa8b06 --- /dev/null +++ b/crates/hir_ty/src/diagnostics_sink.rs | |||
@@ -0,0 +1,109 @@ | |||
1 | //! Semantic errors and warnings. | ||
2 | //! | ||
3 | //! The `Diagnostic` trait defines a trait object which can represent any | ||
4 | //! diagnostic. | ||
5 | //! | ||
6 | //! `DiagnosticSink` struct is used as an emitter for diagnostic. When creating | ||
7 | //! a `DiagnosticSink`, you supply a callback which can react to a `dyn | ||
8 | //! Diagnostic` or to any concrete diagnostic (downcasting is used internally). | ||
9 | //! | ||
10 | //! Because diagnostics store file offsets, it's a bad idea to store them | ||
11 | //! directly in salsa. For this reason, every hir subsytem defines it's own | ||
12 | //! strongly-typed closed set of diagnostics which use hir ids internally, are | ||
13 | //! stored in salsa and do *not* implement the `Diagnostic` trait. Instead, a | ||
14 | //! subsystem provides a separate, non-query-based API which can walk all stored | ||
15 | //! values and transform them into instances of `Diagnostic`. | ||
16 | |||
17 | use std::{any::Any, fmt}; | ||
18 | |||
19 | use hir_expand::InFile; | ||
20 | use syntax::SyntaxNodePtr; | ||
21 | |||
22 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
23 | pub struct DiagnosticCode(pub &'static str); | ||
24 | |||
25 | impl DiagnosticCode { | ||
26 | pub fn as_str(&self) -> &str { | ||
27 | self.0 | ||
28 | } | ||
29 | } | ||
30 | |||
31 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | ||
32 | fn code(&self) -> DiagnosticCode; | ||
33 | fn message(&self) -> String; | ||
34 | /// Source element that triggered the diagnostics. | ||
35 | /// | ||
36 | /// Note that this should reflect "semantics", rather than specific span we | ||
37 | /// want to highlight. When rendering the diagnostics into an error message, | ||
38 | /// the IDE will fetch the `SyntaxNode` and will narrow the span | ||
39 | /// appropriately. | ||
40 | fn display_source(&self) -> InFile<SyntaxNodePtr>; | ||
41 | fn as_any(&self) -> &(dyn Any + Send + 'static); | ||
42 | fn is_experimental(&self) -> bool { | ||
43 | false | ||
44 | } | ||
45 | } | ||
46 | |||
47 | pub struct DiagnosticSink<'a> { | ||
48 | callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, | ||
49 | filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>, | ||
50 | default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>, | ||
51 | } | ||
52 | |||
53 | impl<'a> DiagnosticSink<'a> { | ||
54 | pub fn push(&mut self, d: impl Diagnostic) { | ||
55 | let d: &dyn Diagnostic = &d; | ||
56 | self._push(d); | ||
57 | } | ||
58 | |||
59 | fn _push(&mut self, d: &dyn Diagnostic) { | ||
60 | for filter in &mut self.filters { | ||
61 | if !filter(d) { | ||
62 | return; | ||
63 | } | ||
64 | } | ||
65 | for cb in &mut self.callbacks { | ||
66 | match cb(d) { | ||
67 | Ok(()) => return, | ||
68 | Err(()) => (), | ||
69 | } | ||
70 | } | ||
71 | (self.default_callback)(d) | ||
72 | } | ||
73 | } | ||
74 | |||
75 | pub struct DiagnosticSinkBuilder<'a> { | ||
76 | callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, | ||
77 | filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>, | ||
78 | } | ||
79 | |||
80 | impl<'a> DiagnosticSinkBuilder<'a> { | ||
81 | pub fn new() -> Self { | ||
82 | Self { callbacks: Vec::new(), filters: Vec::new() } | ||
83 | } | ||
84 | |||
85 | pub fn filter<F: FnMut(&dyn Diagnostic) -> bool + 'a>(mut self, cb: F) -> Self { | ||
86 | self.filters.push(Box::new(cb)); | ||
87 | self | ||
88 | } | ||
89 | |||
90 | pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self { | ||
91 | let cb = move |diag: &dyn Diagnostic| match diag.as_any().downcast_ref::<D>() { | ||
92 | Some(d) => { | ||
93 | cb(d); | ||
94 | Ok(()) | ||
95 | } | ||
96 | None => Err(()), | ||
97 | }; | ||
98 | self.callbacks.push(Box::new(cb)); | ||
99 | self | ||
100 | } | ||
101 | |||
102 | pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> { | ||
103 | DiagnosticSink { | ||
104 | callbacks: self.callbacks, | ||
105 | filters: self.filters, | ||
106 | default_callback: Box::new(default_callback), | ||
107 | } | ||
108 | } | ||
109 | } | ||
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 7bbd1a1f7..44f843bf3 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -13,6 +13,7 @@ use hir_def::{ | |||
13 | db::DefDatabase, | 13 | db::DefDatabase, |
14 | find_path, | 14 | find_path, |
15 | generics::TypeParamProvenance, | 15 | generics::TypeParamProvenance, |
16 | intern::{Internable, Interned}, | ||
16 | item_scope::ItemInNs, | 17 | item_scope::ItemInNs, |
17 | path::{Path, PathKind}, | 18 | path::{Path, PathKind}, |
18 | type_ref::{TypeBound, TypeRef}, | 19 | type_ref::{TypeBound, TypeRef}, |
@@ -256,6 +257,12 @@ impl<T: HirDisplay> HirDisplay for &'_ T { | |||
256 | } | 257 | } |
257 | } | 258 | } |
258 | 259 | ||
260 | impl<T: HirDisplay + Internable> HirDisplay for Interned<T> { | ||
261 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
262 | HirDisplay::hir_fmt(self.as_ref(), f) | ||
263 | } | ||
264 | } | ||
265 | |||
259 | impl HirDisplay for ProjectionTy { | 266 | impl HirDisplay for ProjectionTy { |
260 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | 267 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { |
261 | if f.should_truncate() { | 268 | if f.should_truncate() { |
@@ -771,8 +778,10 @@ fn write_bounds_like_dyn_trait( | |||
771 | } | 778 | } |
772 | WhereClause::AliasEq(alias_eq) if is_fn_trait => { | 779 | WhereClause::AliasEq(alias_eq) if is_fn_trait => { |
773 | is_fn_trait = false; | 780 | is_fn_trait = false; |
774 | write!(f, " -> ")?; | 781 | if !alias_eq.ty.is_unit() { |
775 | alias_eq.ty.hir_fmt(f)?; | 782 | write!(f, " -> ")?; |
783 | alias_eq.ty.hir_fmt(f)?; | ||
784 | } | ||
776 | } | 785 | } |
777 | WhereClause::AliasEq(AliasEq { ty, alias }) => { | 786 | WhereClause::AliasEq(AliasEq { ty, alias }) => { |
778 | // in types in actual Rust, these will always come | 787 | // in types in actual Rust, these will always come |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index db3c937ff..7a4268819 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -28,13 +28,14 @@ use hir_def::{ | |||
28 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup, | 28 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup, |
29 | TraitId, TypeAliasId, VariantId, | 29 | TraitId, TypeAliasId, VariantId, |
30 | }; | 30 | }; |
31 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | 31 | use hir_expand::name::name; |
32 | use la_arena::ArenaMap; | 32 | use la_arena::ArenaMap; |
33 | use rustc_hash::FxHashMap; | 33 | use rustc_hash::FxHashMap; |
34 | use stdx::impl_from; | 34 | use stdx::impl_from; |
35 | use syntax::SmolStr; | 35 | use syntax::SmolStr; |
36 | 36 | ||
37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; | 37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; |
38 | use crate::diagnostics_sink::DiagnosticSink; | ||
38 | use crate::{ | 39 | use crate::{ |
39 | db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, | 40 | db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, |
40 | lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution, | 41 | lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution, |
@@ -557,7 +558,13 @@ impl<'a> InferenceContext<'a> { | |||
557 | 558 | ||
558 | self.infer_pat(*pat, &ty, BindingMode::default()); | 559 | self.infer_pat(*pat, &ty, BindingMode::default()); |
559 | } | 560 | } |
560 | let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT | 561 | let error_ty = &TypeRef::Error; |
562 | let return_ty = if data.is_async() { | ||
563 | data.async_ret_type.as_deref().unwrap_or(error_ty) | ||
564 | } else { | ||
565 | &*data.ret_type | ||
566 | }; | ||
567 | let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT | ||
561 | self.return_ty = return_ty; | 568 | self.return_ty = return_ty; |
562 | } | 569 | } |
563 | 570 | ||
@@ -578,9 +585,14 @@ impl<'a> InferenceContext<'a> { | |||
578 | } | 585 | } |
579 | 586 | ||
580 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { | 587 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { |
588 | // FIXME resolve via lang_item once try v2 is stable | ||
581 | let path = path![core::ops::Try]; | 589 | let path = path![core::ops::Try]; |
582 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 590 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
583 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) | 591 | let trait_data = self.db.trait_data(trait_); |
592 | trait_data | ||
593 | // FIXME remove once try v2 is stable | ||
594 | .associated_type_by_name(&name![Ok]) | ||
595 | .or_else(|| trait_data.associated_type_by_name(&name![Output])) | ||
584 | } | 596 | } |
585 | 597 | ||
586 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { | 598 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { |
@@ -793,11 +805,11 @@ impl std::ops::BitOrAssign for Diverges { | |||
793 | 805 | ||
794 | mod diagnostics { | 806 | mod diagnostics { |
795 | use hir_def::{expr::ExprId, DefWithBodyId}; | 807 | use hir_def::{expr::ExprId, DefWithBodyId}; |
796 | use hir_expand::diagnostics::DiagnosticSink; | ||
797 | 808 | ||
798 | use crate::{ | 809 | use crate::{ |
799 | db::HirDatabase, | 810 | db::HirDatabase, |
800 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, | 811 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, |
812 | diagnostics_sink::DiagnosticSink, | ||
801 | }; | 813 | }; |
802 | 814 | ||
803 | #[derive(Debug, PartialEq, Eq, Clone)] | 815 | #[derive(Debug, PartialEq, Eq, Clone)] |
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 765a02b1c..03b97e7db 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -76,17 +76,17 @@ impl<'a> InferenceContext<'a> { | |||
76 | // way around first would mean we make the type variable `!`, instead of | 76 | // way around first would mean we make the type variable `!`, instead of |
77 | // just marking it as possibly diverging. | 77 | // just marking it as possibly diverging. |
78 | if self.coerce(&ty2, &ty1) { | 78 | if self.coerce(&ty2, &ty1) { |
79 | ty1.clone() | 79 | ty1 |
80 | } else if self.coerce(&ty1, &ty2) { | 80 | } else if self.coerce(&ty1, &ty2) { |
81 | ty2.clone() | 81 | ty2 |
82 | } else { | 82 | } else { |
83 | if let Some(id) = id { | 83 | if let Some(id) = id { |
84 | self.result | 84 | self.result |
85 | .type_mismatches | 85 | .type_mismatches |
86 | .insert(id.into(), TypeMismatch { expected: ty1.clone(), actual: ty2.clone() }); | 86 | .insert(id.into(), TypeMismatch { expected: ty1.clone(), actual: ty2 }); |
87 | } | 87 | } |
88 | cov_mark::hit!(coerce_merge_fail_fallback); | 88 | cov_mark::hit!(coerce_merge_fail_fallback); |
89 | ty1.clone() | 89 | ty1 |
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 | ||
@@ -183,7 +183,7 @@ impl<'a> InferenceContext<'a> { | |||
183 | // details of coercion errors though, so I think it's useful to leave | 183 | // details of coercion errors though, so I think it's useful to leave |
184 | // the structure like it is. | 184 | // the structure like it is. |
185 | 185 | ||
186 | let canonicalized = self.canonicalize(from_ty.clone()); | 186 | let canonicalized = self.canonicalize(from_ty); |
187 | let autoderef = autoderef::autoderef( | 187 | let autoderef = autoderef::autoderef( |
188 | self.db, | 188 | self.db, |
189 | self.resolver.krate(), | 189 | self.resolver.krate(), |
@@ -389,7 +389,7 @@ impl<'a> InferenceContext<'a> { | |||
389 | // The CoerceUnsized trait should have two generic params: Self and T. | 389 | // The CoerceUnsized trait should have two generic params: Self and T. |
390 | return Err(TypeError); | 390 | return Err(TypeError); |
391 | } | 391 | } |
392 | b.push(coerce_from.clone()).push(to_ty.clone()).build() | 392 | b.push(coerce_from).push(to_ty.clone()).build() |
393 | }; | 393 | }; |
394 | 394 | ||
395 | let goal: InEnvironment<DomainGoal> = | 395 | let goal: InEnvironment<DomainGoal> = |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index eab8fac91..97507305c 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -44,7 +44,7 @@ impl<'a> InferenceContext<'a> { | |||
44 | if !could_unify { | 44 | if !could_unify { |
45 | self.result.type_mismatches.insert( | 45 | self.result.type_mismatches.insert( |
46 | tgt_expr.into(), | 46 | tgt_expr.into(), |
47 | TypeMismatch { expected: expected_ty.clone(), actual: ty.clone() }, | 47 | TypeMismatch { expected: expected_ty, actual: ty.clone() }, |
48 | ); | 48 | ); |
49 | } | 49 | } |
50 | } | 50 | } |
@@ -57,15 +57,14 @@ impl<'a> InferenceContext<'a> { | |||
57 | let ty = self.infer_expr_inner(expr, &expected); | 57 | let ty = self.infer_expr_inner(expr, &expected); |
58 | let ty = if let Some(target) = expected.only_has_type(&mut self.table) { | 58 | let ty = if let Some(target) = expected.only_has_type(&mut self.table) { |
59 | if !self.coerce(&ty, &target) { | 59 | if !self.coerce(&ty, &target) { |
60 | self.result.type_mismatches.insert( | 60 | self.result |
61 | expr.into(), | 61 | .type_mismatches |
62 | TypeMismatch { expected: target.clone(), actual: ty.clone() }, | 62 | .insert(expr.into(), TypeMismatch { expected: target, actual: ty.clone() }); |
63 | ); | ||
64 | // Return actual type when type mismatch. | 63 | // Return actual type when type mismatch. |
65 | // This is needed for diagnostic when return type mismatch. | 64 | // This is needed for diagnostic when return type mismatch. |
66 | ty | 65 | ty |
67 | } else { | 66 | } else { |
68 | target.clone() | 67 | target |
69 | } | 68 | } |
70 | } else { | 69 | } else { |
71 | ty | 70 | ty |
@@ -805,7 +804,7 @@ impl<'a> InferenceContext<'a> { | |||
805 | None => self.table.new_float_var(), | 804 | None => self.table.new_float_var(), |
806 | }, | 805 | }, |
807 | }, | 806 | }, |
808 | Expr::MacroStmts { tail } => self.infer_expr(*tail, expected), | 807 | Expr::MacroStmts { tail } => self.infer_expr_inner(*tail, expected), |
809 | }; | 808 | }; |
810 | // use a new type variable if we got unknown here | 809 | // use a new type variable if we got unknown here |
811 | let ty = self.insert_type_vars_shallow(ty); | 810 | let ty = self.insert_type_vars_shallow(ty); |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 9c8e3b6ae..83e0a7a9e 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -196,7 +196,7 @@ impl<'a> InferenceContext<'a> { | |||
196 | let inner_ty = if let Some(subpat) = subpat { | 196 | let inner_ty = if let Some(subpat) = subpat { |
197 | self.infer_pat(*subpat, &expected, default_bm) | 197 | self.infer_pat(*subpat, &expected, default_bm) |
198 | } else { | 198 | } else { |
199 | expected.clone() | 199 | expected |
200 | }; | 200 | }; |
201 | let inner_ty = self.insert_type_vars_shallow(inner_ty); | 201 | let inner_ty = self.insert_type_vars_shallow(inner_ty); |
202 | 202 | ||
@@ -266,10 +266,9 @@ impl<'a> InferenceContext<'a> { | |||
266 | // use a new type variable if we got error type here | 266 | // use a new type variable if we got error type here |
267 | let ty = self.insert_type_vars_shallow(ty); | 267 | let ty = self.insert_type_vars_shallow(ty); |
268 | if !self.unify(&ty, &expected) { | 268 | if !self.unify(&ty, &expected) { |
269 | self.result.type_mismatches.insert( | 269 | self.result |
270 | pat.into(), | 270 | .type_mismatches |
271 | TypeMismatch { expected: expected.clone(), actual: ty.clone() }, | 271 | .insert(pat.into(), TypeMismatch { expected: expected, actual: ty.clone() }); |
272 | ); | ||
273 | } | 272 | } |
274 | self.write_pat_ty(pat, ty.clone()); | 273 | self.write_pat_ty(pat, ty.clone()); |
275 | ty | 274 | ty |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index ef021978a..50e0d6333 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -21,6 +21,7 @@ mod utils; | |||
21 | mod walk; | 21 | mod walk; |
22 | pub mod db; | 22 | pub mod db; |
23 | pub mod diagnostics; | 23 | pub mod diagnostics; |
24 | pub mod diagnostics_sink; | ||
24 | pub mod display; | 25 | pub mod display; |
25 | pub mod method_resolution; | 26 | pub mod method_resolution; |
26 | pub mod primitive; | 27 | pub mod primitive; |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8a375b973..c83933c73 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -10,6 +10,7 @@ use std::{iter, sync::Arc}; | |||
10 | 10 | ||
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; | 12 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; |
13 | use hir_def::intern::Interned; | ||
13 | use hir_def::{ | 14 | use hir_def::{ |
14 | adt::StructKind, | 15 | adt::StructKind, |
15 | body::{Expander, LowerCtx}, | 16 | body::{Expander, LowerCtx}, |
@@ -843,7 +844,7 @@ impl<'a> TyLoweringContext<'a> { | |||
843 | }) | 844 | }) |
844 | } | 845 | } |
845 | 846 | ||
846 | fn lower_impl_trait(&self, bounds: &[TypeBound]) -> ReturnTypeImplTrait { | 847 | fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>]) -> ReturnTypeImplTrait { |
847 | cov_mark::hit!(lower_rpit); | 848 | cov_mark::hit!(lower_rpit); |
848 | let self_ty = | 849 | let self_ty = |
849 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); | 850 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); |
@@ -1025,7 +1026,7 @@ pub(crate) fn trait_environment_query( | |||
1025 | }; | 1026 | }; |
1026 | if let Some(AssocContainerId::TraitId(trait_id)) = container { | 1027 | if let Some(AssocContainerId::TraitId(trait_id)) = container { |
1027 | // add `Self: Trait<T1, T2, ...>` to the environment in trait | 1028 | // add `Self: Trait<T1, T2, ...>` to the environment in trait |
1028 | // function default implementations (and hypothetical code | 1029 | // function default implementations (and speculative code |
1029 | // inside consts or type aliases) | 1030 | // inside consts or type aliases) |
1030 | cov_mark::hit!(trait_self_implements_self); | 1031 | cov_mark::hit!(trait_self_implements_self); |
1031 | let substs = TyBuilder::type_params_subst(db, trait_id); | 1032 | let substs = TyBuilder::type_params_subst(db, trait_id); |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index cc819373c..9d726b024 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -7,6 +7,7 @@ mod traits; | |||
7 | mod method_resolution; | 7 | mod method_resolution; |
8 | mod macros; | 8 | mod macros; |
9 | mod display_source_code; | 9 | mod display_source_code; |
10 | mod incremental; | ||
10 | 11 | ||
11 | use std::{env, sync::Arc}; | 12 | use std::{env, sync::Arc}; |
12 | 13 | ||
@@ -317,50 +318,6 @@ fn ellipsize(mut text: String, max_len: usize) -> String { | |||
317 | text | 318 | text |
318 | } | 319 | } |
319 | 320 | ||
320 | #[test] | ||
321 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | ||
322 | let (mut db, pos) = TestDB::with_position( | ||
323 | " | ||
324 | //- /lib.rs | ||
325 | fn foo() -> i32 { | ||
326 | $01 + 1 | ||
327 | } | ||
328 | ", | ||
329 | ); | ||
330 | { | ||
331 | let events = db.log_executed(|| { | ||
332 | let module = db.module_for_file(pos.file_id); | ||
333 | let crate_def_map = module.def_map(&db); | ||
334 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
335 | db.infer(def); | ||
336 | }); | ||
337 | }); | ||
338 | assert!(format!("{:?}", events).contains("infer")) | ||
339 | } | ||
340 | |||
341 | let new_text = " | ||
342 | fn foo() -> i32 { | ||
343 | 1 | ||
344 | + | ||
345 | 1 | ||
346 | } | ||
347 | " | ||
348 | .to_string(); | ||
349 | |||
350 | db.set_file_text(pos.file_id, Arc::new(new_text)); | ||
351 | |||
352 | { | ||
353 | let events = db.log_executed(|| { | ||
354 | let module = db.module_for_file(pos.file_id); | ||
355 | let crate_def_map = module.def_map(&db); | ||
356 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
357 | db.infer(def); | ||
358 | }); | ||
359 | }); | ||
360 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | ||
361 | } | ||
362 | } | ||
363 | |||
364 | fn check_infer(ra_fixture: &str, expect: Expect) { | 321 | fn check_infer(ra_fixture: &str, expect: Expect) { |
365 | let mut actual = infer(ra_fixture); | 322 | let mut actual = infer(ra_fixture); |
366 | actual.push('\n'); | 323 | actual.push('\n'); |
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index bb568ea37..6dac7e103 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -832,11 +832,9 @@ fn coerce_unsize_super_trait_cycle() { | |||
832 | ); | 832 | ); |
833 | } | 833 | } |
834 | 834 | ||
835 | #[ignore] | ||
836 | #[test] | 835 | #[test] |
837 | fn coerce_unsize_generic() { | 836 | fn coerce_unsize_generic() { |
838 | // FIXME: Implement this | 837 | // FIXME: fix the type mismatches here |
839 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions | ||
840 | check_infer_with_mismatches( | 838 | check_infer_with_mismatches( |
841 | r#" | 839 | r#" |
842 | #[lang = "unsize"] | 840 | #[lang = "unsize"] |
@@ -854,8 +852,58 @@ fn coerce_unsize_generic() { | |||
854 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | 852 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); |
855 | } | 853 | } |
856 | "#, | 854 | "#, |
857 | expect![[r" | 855 | expect![[r#" |
858 | "]], | 856 | 209..317 '{ ... }); }': () |
857 | 219..220 '_': &Foo<[usize]> | ||
858 | 238..259 '&Foo {..., 3] }': &Foo<[usize]> | ||
859 | 239..259 'Foo { ..., 3] }': Foo<[usize]> | ||
860 | 248..257 '[1, 2, 3]': [usize; 3] | ||
861 | 249..250 '1': usize | ||
862 | 252..253 '2': usize | ||
863 | 255..256 '3': usize | ||
864 | 269..270 '_': &Bar<[usize]> | ||
865 | 288..314 '&Bar(F... 3] })': &Bar<[i32; 3]> | ||
866 | 289..292 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]> | ||
867 | 289..314 'Bar(Fo... 3] })': Bar<[i32; 3]> | ||
868 | 293..313 'Foo { ..., 3] }': Foo<[i32; 3]> | ||
869 | 302..311 '[1, 2, 3]': [i32; 3] | ||
870 | 303..304 '1': i32 | ||
871 | 306..307 '2': i32 | ||
872 | 309..310 '3': i32 | ||
873 | 248..257: expected [usize], got [usize; 3] | ||
874 | 288..314: expected &Bar<[usize]>, got &Bar<[i32; 3]> | ||
875 | "#]], | ||
876 | ); | ||
877 | } | ||
878 | |||
879 | #[test] | ||
880 | fn coerce_unsize_apit() { | ||
881 | // FIXME: #8984 | ||
882 | check_infer_with_mismatches( | ||
883 | r#" | ||
884 | #[lang = "sized"] | ||
885 | pub trait Sized {} | ||
886 | #[lang = "unsize"] | ||
887 | pub trait Unsize<T> {} | ||
888 | #[lang = "coerce_unsized"] | ||
889 | pub trait CoerceUnsized<T> {} | ||
890 | |||
891 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
892 | |||
893 | trait Foo {} | ||
894 | |||
895 | fn test(f: impl Foo) { | ||
896 | let _: &dyn Foo = &f; | ||
897 | } | ||
898 | "#, | ||
899 | expect![[r#" | ||
900 | 210..211 'f': impl Foo | ||
901 | 223..252 '{ ... &f; }': () | ||
902 | 233..234 '_': &dyn Foo | ||
903 | 247..249 '&f': &impl Foo | ||
904 | 248..249 'f': impl Foo | ||
905 | 247..249: expected &dyn Foo, got &impl Foo | ||
906 | "#]], | ||
859 | ); | 907 | ); |
860 | } | 908 | } |
861 | 909 | ||
@@ -912,3 +960,46 @@ fn test() -> i32 { | |||
912 | "#, | 960 | "#, |
913 | ) | 961 | ) |
914 | } | 962 | } |
963 | |||
964 | #[test] | ||
965 | fn panic_macro() { | ||
966 | check_infer_with_mismatches( | ||
967 | r#" | ||
968 | mod panic { | ||
969 | #[macro_export] | ||
970 | pub macro panic_2015 { | ||
971 | () => ( | ||
972 | $crate::panicking::panic() | ||
973 | ), | ||
974 | } | ||
975 | } | ||
976 | |||
977 | mod panicking { | ||
978 | pub fn panic() -> ! { loop {} } | ||
979 | } | ||
980 | |||
981 | #[rustc_builtin_macro = "core_panic"] | ||
982 | macro_rules! panic { | ||
983 | // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` | ||
984 | // depending on the edition of the caller. | ||
985 | ($($arg:tt)*) => { | ||
986 | /* compiler built-in */ | ||
987 | }; | ||
988 | } | ||
989 | |||
990 | fn main() { | ||
991 | panic!() | ||
992 | } | ||
993 | "#, | ||
994 | expect![[r#" | ||
995 | 174..185 '{ loop {} }': ! | ||
996 | 176..183 'loop {}': ! | ||
997 | 181..183 '{}': () | ||
998 | !0..24 '$crate...:panic': fn panic() -> ! | ||
999 | !0..26 '$crate...anic()': ! | ||
1000 | !0..26 '$crate...anic()': ! | ||
1001 | !0..28 '$crate...015!()': ! | ||
1002 | 454..470 '{ ...c!() }': () | ||
1003 | "#]], | ||
1004 | ); | ||
1005 | } | ||
diff --git a/crates/hir_ty/src/tests/incremental.rs b/crates/hir_ty/src/tests/incremental.rs new file mode 100644 index 000000000..3e08e83e8 --- /dev/null +++ b/crates/hir_ty/src/tests/incremental.rs | |||
@@ -0,0 +1,51 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use base_db::{fixture::WithFixture, SourceDatabaseExt}; | ||
4 | |||
5 | use crate::{db::HirDatabase, test_db::TestDB}; | ||
6 | |||
7 | use super::visit_module; | ||
8 | |||
9 | #[test] | ||
10 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | ||
11 | let (mut db, pos) = TestDB::with_position( | ||
12 | " | ||
13 | //- /lib.rs | ||
14 | fn foo() -> i32 { | ||
15 | $01 + 1 | ||
16 | } | ||
17 | ", | ||
18 | ); | ||
19 | { | ||
20 | let events = db.log_executed(|| { | ||
21 | let module = db.module_for_file(pos.file_id); | ||
22 | let crate_def_map = module.def_map(&db); | ||
23 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
24 | db.infer(def); | ||
25 | }); | ||
26 | }); | ||
27 | assert!(format!("{:?}", events).contains("infer")) | ||
28 | } | ||
29 | |||
30 | let new_text = " | ||
31 | fn foo() -> i32 { | ||
32 | 1 | ||
33 | + | ||
34 | 1 | ||
35 | } | ||
36 | " | ||
37 | .to_string(); | ||
38 | |||
39 | db.set_file_text(pos.file_id, Arc::new(new_text)); | ||
40 | |||
41 | { | ||
42 | let events = db.log_executed(|| { | ||
43 | let module = db.module_for_file(pos.file_id); | ||
44 | let crate_def_map = module.def_map(&db); | ||
45 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
46 | db.infer(def); | ||
47 | }); | ||
48 | }); | ||
49 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | ||
50 | } | ||
51 | } | ||
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 6588aa46c..7647bb08b 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -752,6 +752,24 @@ fn bar() -> u32 {0} | |||
752 | } | 752 | } |
753 | 753 | ||
754 | #[test] | 754 | #[test] |
755 | fn infer_builtin_macros_include_expression() { | ||
756 | check_types( | ||
757 | r#" | ||
758 | //- /main.rs | ||
759 | #[rustc_builtin_macro] | ||
760 | macro_rules! include {() => {}} | ||
761 | fn main() { | ||
762 | let i = include!("bla.rs"); | ||
763 | i; | ||
764 | //^ i32 | ||
765 | } | ||
766 | //- /bla.rs | ||
767 | 0 | ||
768 | "#, | ||
769 | ) | ||
770 | } | ||
771 | |||
772 | #[test] | ||
755 | fn infer_builtin_macros_include_child_mod() { | 773 | fn infer_builtin_macros_include_child_mod() { |
756 | check_types( | 774 | check_types( |
757 | r#" | 775 | r#" |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index a5a2df54c..7c0ff2170 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -161,6 +161,43 @@ mod result { | |||
161 | } | 161 | } |
162 | 162 | ||
163 | #[test] | 163 | #[test] |
164 | fn infer_tryv2() { | ||
165 | check_types( | ||
166 | r#" | ||
167 | //- /main.rs crate:main deps:core | ||
168 | fn test() { | ||
169 | let r: Result<i32, u64> = Result::Ok(1); | ||
170 | let v = r?; | ||
171 | v; | ||
172 | } //^ i32 | ||
173 | |||
174 | //- /core.rs crate:core | ||
175 | #[prelude_import] use ops::*; | ||
176 | mod ops { | ||
177 | trait Try { | ||
178 | type Output; | ||
179 | type Residual; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | #[prelude_import] use result::*; | ||
184 | mod result { | ||
185 | enum Infallible {} | ||
186 | enum Result<O, E> { | ||
187 | Ok(O), | ||
188 | Err(E) | ||
189 | } | ||
190 | |||
191 | impl<O, E> crate::ops::Try for Result<O, E> { | ||
192 | type Output = O; | ||
193 | type Error = Result<Infallible, E>; | ||
194 | } | ||
195 | } | ||
196 | "#, | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
164 | fn infer_for_loop() { | 201 | fn infer_for_loop() { |
165 | check_types( | 202 | check_types( |
166 | r#" | 203 | r#" |
@@ -3041,7 +3078,7 @@ fn infer_fn_trait_arg() { | |||
3041 | 3078 | ||
3042 | #[test] | 3079 | #[test] |
3043 | fn infer_box_fn_arg() { | 3080 | fn infer_box_fn_arg() { |
3044 | // The type mismatch is a bug | 3081 | // The type mismatch is because we don't define Unsize and CoerceUnsized |
3045 | check_infer_with_mismatches( | 3082 | check_infer_with_mismatches( |
3046 | r#" | 3083 | r#" |
3047 | //- /lib.rs deps:std | 3084 | //- /lib.rs deps:std |
@@ -3101,7 +3138,7 @@ fn foo() { | |||
3101 | 555..557 'ps': {unknown} | 3138 | 555..557 'ps': {unknown} |
3102 | 559..561 '{}': () | 3139 | 559..561 '{}': () |
3103 | 568..569 'f': Box<dyn FnOnce(&Option<i32>)> | 3140 | 568..569 'f': Box<dyn FnOnce(&Option<i32>)> |
3104 | 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> | 3141 | 568..573 'f(&s)': () |
3105 | 570..572 '&s': &Option<i32> | 3142 | 570..572 '&s': &Option<i32> |
3106 | 571..572 's': Option<i32> | 3143 | 571..572 's': Option<i32> |
3107 | 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()> | 3144 | 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()> |
@@ -3571,3 +3608,104 @@ fn main() { | |||
3571 | "#]], | 3608 | "#]], |
3572 | ) | 3609 | ) |
3573 | } | 3610 | } |
3611 | |||
3612 | #[test] | ||
3613 | fn fn_returning_unit() { | ||
3614 | check_infer_with_mismatches( | ||
3615 | r#" | ||
3616 | #[lang = "fn_once"] | ||
3617 | trait FnOnce<Args> { | ||
3618 | type Output; | ||
3619 | } | ||
3620 | |||
3621 | fn test<F: FnOnce()>(f: F) { | ||
3622 | let _: () = f(); | ||
3623 | }"#, | ||
3624 | expect![[r#" | ||
3625 | 82..83 'f': F | ||
3626 | 88..112 '{ ...f(); }': () | ||
3627 | 98..99 '_': () | ||
3628 | 106..107 'f': F | ||
3629 | 106..109 'f()': () | ||
3630 | "#]], | ||
3631 | ); | ||
3632 | } | ||
3633 | |||
3634 | #[test] | ||
3635 | fn trait_in_scope_of_trait_impl() { | ||
3636 | check_infer( | ||
3637 | r#" | ||
3638 | mod foo { | ||
3639 | pub trait Foo { | ||
3640 | fn foo(self); | ||
3641 | fn bar(self) -> usize { 0 } | ||
3642 | } | ||
3643 | } | ||
3644 | impl foo::Foo for u32 { | ||
3645 | fn foo(self) { | ||
3646 | let _x = self.bar(); | ||
3647 | } | ||
3648 | } | ||
3649 | "#, | ||
3650 | expect![[r#" | ||
3651 | 45..49 'self': Self | ||
3652 | 67..71 'self': Self | ||
3653 | 82..87 '{ 0 }': usize | ||
3654 | 84..85 '0': usize | ||
3655 | 131..135 'self': u32 | ||
3656 | 137..173 '{ ... }': () | ||
3657 | 151..153 '_x': usize | ||
3658 | 156..160 'self': u32 | ||
3659 | 156..166 'self.bar()': usize | ||
3660 | "#]], | ||
3661 | ); | ||
3662 | } | ||
3663 | |||
3664 | #[test] | ||
3665 | fn infer_async_ret_type() { | ||
3666 | check_types( | ||
3667 | r#" | ||
3668 | //- /main.rs crate:main deps:core | ||
3669 | |||
3670 | enum Result<T, E> { | ||
3671 | Ok(T), | ||
3672 | Err(E), | ||
3673 | } | ||
3674 | |||
3675 | use Result::*; | ||
3676 | |||
3677 | |||
3678 | struct Fooey; | ||
3679 | |||
3680 | impl Fooey { | ||
3681 | fn collect<B: Convert>(self) -> B { | ||
3682 | B::new() | ||
3683 | } | ||
3684 | } | ||
3685 | |||
3686 | trait Convert { | ||
3687 | fn new() -> Self; | ||
3688 | } | ||
3689 | impl Convert for u32 { | ||
3690 | fn new() -> Self { | ||
3691 | 0 | ||
3692 | } | ||
3693 | } | ||
3694 | |||
3695 | async fn get_accounts() -> Result<u32, ()> { | ||
3696 | let ret = Fooey.collect(); | ||
3697 | // ^ u32 | ||
3698 | Ok(ret) | ||
3699 | } | ||
3700 | |||
3701 | //- /core.rs crate:core | ||
3702 | #[prelude_import] use future::*; | ||
3703 | mod future { | ||
3704 | #[lang = "future_trait"] | ||
3705 | trait Future { | ||
3706 | type Output; | ||
3707 | } | ||
3708 | } | ||
3709 | "#, | ||
3710 | ); | ||
3711 | } | ||