diff options
Diffstat (limited to 'crates/hir_ty/src')
-rw-r--r-- | crates/hir_ty/src/chalk_db.rs | 8 | ||||
-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 | 15 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/unsafe_check.rs | 6 | ||||
-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 | 45 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/coerce.rs | 12 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/expr.rs | 49 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/pat.rs | 9 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/unify.rs | 7 | ||||
-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 | 157 | ||||
-rw-r--r-- | crates/hir_ty/src/traits.rs | 2 |
20 files changed, 538 insertions, 133 deletions
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs index b108fd559..4e042bf42 100644 --- a/crates/hir_ty/src/chalk_db.rs +++ b/crates/hir_ty/src/chalk_db.rs | |||
@@ -383,7 +383,7 @@ pub(crate) fn associated_ty_data_query( | |||
383 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` | 383 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` |
384 | let type_alias_data = db.type_alias_data(type_alias); | 384 | let type_alias_data = db.type_alias_data(type_alias); |
385 | let generic_params = generics(db.upcast(), type_alias.into()); | 385 | let generic_params = generics(db.upcast(), type_alias.into()); |
386 | let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); | 386 | // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); |
387 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); | 387 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); |
388 | let ctx = crate::TyLoweringContext::new(db, &resolver) | 388 | let ctx = crate::TyLoweringContext::new(db, &resolver) |
389 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); | 389 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); |
@@ -396,8 +396,10 @@ pub(crate) fn associated_ty_data_query( | |||
396 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) | 396 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) |
397 | .collect(); | 397 | .collect(); |
398 | 398 | ||
399 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | 399 | // FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed. |
400 | let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; | 400 | // (rust-analyzer#9052) |
401 | // let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | ||
402 | let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses: vec![] }; | ||
401 | let datum = AssociatedTyDatum { | 403 | let datum = AssociatedTyDatum { |
402 | trait_id: to_chalk_trait_id(trait_), | 404 | trait_id: to_chalk_trait_id(trait_), |
403 | id, | 405 | id, |
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 53c4ee9da..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 | ||
@@ -181,7 +182,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
181 | for (id, expr) in body.exprs.iter() { | 182 | for (id, expr) in body.exprs.iter() { |
182 | if let Expr::MethodCall { receiver, .. } = expr { | 183 | if let Expr::MethodCall { receiver, .. } = expr { |
183 | let function_id = match self.infer.method_resolution(id) { | 184 | let function_id = match self.infer.method_resolution(id) { |
184 | Some(id) => id, | 185 | Some((id, _)) => id, |
185 | None => continue, | 186 | None => continue, |
186 | }; | 187 | }; |
187 | 188 | ||
@@ -239,15 +240,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
239 | return; | 240 | return; |
240 | } | 241 | } |
241 | 242 | ||
242 | // FIXME: note that we erase information about substs here. This | 243 | let (callee, subst) = match self.infer.method_resolution(call_id) { |
243 | // is not right, but, luckily, doesn't matter as we care only | 244 | Some(it) => it, |
244 | // about the number of params | ||
245 | let callee = match self.infer.method_resolution(call_id) { | ||
246 | Some(callee) => callee, | ||
247 | None => return, | 245 | None => return, |
248 | }; | 246 | }; |
249 | let sig = | 247 | let sig = db.callable_item_signature(callee.into()).substitute(&Interner, &subst); |
250 | db.callable_item_signature(callee.into()).into_value_and_skipped_binders().0; | ||
251 | 248 | ||
252 | (sig, args) | 249 | (sig, args) |
253 | } | 250 | } |
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index ed97dc0e3..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> { |
@@ -105,7 +105,7 @@ fn walk_unsafe( | |||
105 | Expr::MethodCall { .. } => { | 105 | Expr::MethodCall { .. } => { |
106 | if infer | 106 | if infer |
107 | .method_resolution(current) | 107 | .method_resolution(current) |
108 | .map(|func| db.function_data(func).is_unsafe()) | 108 | .map(|(func, _)| db.function_data(func).is_unsafe()) |
109 | .unwrap_or(false) | 109 | .unwrap_or(false) |
110 | { | 110 | { |
111 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | 111 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); |
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 f1cebbdb9..7a4268819 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -28,17 +28,18 @@ 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, TyBuilder, | 41 | lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution, |
41 | TyExt, TyKind, | 42 | TyBuilder, TyExt, TyKind, |
42 | }; | 43 | }; |
43 | 44 | ||
44 | // This lint has a false positive here. See the link below for details. | 45 | // This lint has a false positive here. See the link below for details. |
@@ -132,7 +133,7 @@ impl Default for InternedStandardTypes { | |||
132 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | 133 | #[derive(Clone, PartialEq, Eq, Debug, Default)] |
133 | pub struct InferenceResult { | 134 | pub struct InferenceResult { |
134 | /// For each method call expr, records the function it resolves to. | 135 | /// For each method call expr, records the function it resolves to. |
135 | method_resolutions: FxHashMap<ExprId, FunctionId>, | 136 | method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>, |
136 | /// For each field access expr, records the field it resolves to. | 137 | /// For each field access expr, records the field it resolves to. |
137 | field_resolutions: FxHashMap<ExprId, FieldId>, | 138 | field_resolutions: FxHashMap<ExprId, FieldId>, |
138 | /// For each struct literal or pattern, records the variant it resolves to. | 139 | /// For each struct literal or pattern, records the variant it resolves to. |
@@ -152,8 +153,8 @@ pub struct InferenceResult { | |||
152 | } | 153 | } |
153 | 154 | ||
154 | impl InferenceResult { | 155 | impl InferenceResult { |
155 | pub fn method_resolution(&self, expr: ExprId) -> Option<FunctionId> { | 156 | pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> { |
156 | self.method_resolutions.get(&expr).copied() | 157 | self.method_resolutions.get(&expr).cloned() |
157 | } | 158 | } |
158 | pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { | 159 | pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { |
159 | self.field_resolutions.get(&expr).copied() | 160 | self.field_resolutions.get(&expr).copied() |
@@ -284,14 +285,17 @@ impl<'a> InferenceContext<'a> { | |||
284 | self.table.propagate_diverging_flag(); | 285 | self.table.propagate_diverging_flag(); |
285 | let mut result = std::mem::take(&mut self.result); | 286 | let mut result = std::mem::take(&mut self.result); |
286 | for ty in result.type_of_expr.values_mut() { | 287 | for ty in result.type_of_expr.values_mut() { |
287 | *ty = self.table.resolve_ty_completely(ty.clone()); | 288 | *ty = self.table.resolve_completely(ty.clone()); |
288 | } | 289 | } |
289 | for ty in result.type_of_pat.values_mut() { | 290 | for ty in result.type_of_pat.values_mut() { |
290 | *ty = self.table.resolve_ty_completely(ty.clone()); | 291 | *ty = self.table.resolve_completely(ty.clone()); |
291 | } | 292 | } |
292 | for mismatch in result.type_mismatches.values_mut() { | 293 | for mismatch in result.type_mismatches.values_mut() { |
293 | mismatch.expected = self.table.resolve_ty_completely(mismatch.expected.clone()); | 294 | mismatch.expected = self.table.resolve_completely(mismatch.expected.clone()); |
294 | mismatch.actual = self.table.resolve_ty_completely(mismatch.actual.clone()); | 295 | mismatch.actual = self.table.resolve_completely(mismatch.actual.clone()); |
296 | } | ||
297 | for (_, subst) in result.method_resolutions.values_mut() { | ||
298 | *subst = self.table.resolve_completely(subst.clone()); | ||
295 | } | 299 | } |
296 | result | 300 | result |
297 | } | 301 | } |
@@ -300,8 +304,8 @@ impl<'a> InferenceContext<'a> { | |||
300 | self.result.type_of_expr.insert(expr, ty); | 304 | self.result.type_of_expr.insert(expr, ty); |
301 | } | 305 | } |
302 | 306 | ||
303 | fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId) { | 307 | fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) { |
304 | self.result.method_resolutions.insert(expr, func); | 308 | self.result.method_resolutions.insert(expr, (func, subst)); |
305 | } | 309 | } |
306 | 310 | ||
307 | fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) { | 311 | fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) { |
@@ -554,7 +558,13 @@ impl<'a> InferenceContext<'a> { | |||
554 | 558 | ||
555 | self.infer_pat(*pat, &ty, BindingMode::default()); | 559 | self.infer_pat(*pat, &ty, BindingMode::default()); |
556 | } | 560 | } |
557 | 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 | ||
558 | self.return_ty = return_ty; | 568 | self.return_ty = return_ty; |
559 | } | 569 | } |
560 | 570 | ||
@@ -575,9 +585,14 @@ impl<'a> InferenceContext<'a> { | |||
575 | } | 585 | } |
576 | 586 | ||
577 | 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 | ||
578 | let path = path![core::ops::Try]; | 589 | let path = path![core::ops::Try]; |
579 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 590 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
580 | 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])) | ||
581 | } | 596 | } |
582 | 597 | ||
583 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { | 598 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { |
@@ -790,11 +805,11 @@ impl std::ops::BitOrAssign for Diverges { | |||
790 | 805 | ||
791 | mod diagnostics { | 806 | mod diagnostics { |
792 | use hir_def::{expr::ExprId, DefWithBodyId}; | 807 | use hir_def::{expr::ExprId, DefWithBodyId}; |
793 | use hir_expand::diagnostics::DiagnosticSink; | ||
794 | 808 | ||
795 | use crate::{ | 809 | use crate::{ |
796 | db::HirDatabase, | 810 | db::HirDatabase, |
797 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, | 811 | diagnostics::{BreakOutsideOfLoop, NoSuchField}, |
812 | diagnostics_sink::DiagnosticSink, | ||
798 | }; | 813 | }; |
799 | 814 | ||
800 | #[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 08c05c67c..41ef45326 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 |
@@ -120,7 +119,7 @@ impl<'a> InferenceContext<'a> { | |||
120 | } | 119 | } |
121 | 120 | ||
122 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 121 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
123 | self.db.check_canceled(); | 122 | self.db.unwind_if_cancelled(); |
124 | 123 | ||
125 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 124 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
126 | let ty = match &body[tgt_expr] { | 125 | let ty = match &body[tgt_expr] { |
@@ -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); |
@@ -891,17 +890,21 @@ impl<'a> InferenceContext<'a> { | |||
891 | method_name, | 890 | method_name, |
892 | ) | 891 | ) |
893 | }); | 892 | }); |
894 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { | 893 | let (derefed_receiver_ty, method_ty, substs) = match resolved { |
895 | Some((ty, func)) => { | 894 | Some((ty, func)) => { |
896 | let ty = canonicalized_receiver.decanonicalize_ty(ty); | 895 | let ty = canonicalized_receiver.decanonicalize_ty(ty); |
897 | self.write_method_resolution(tgt_expr, func); | 896 | let generics = generics(self.db.upcast(), func.into()); |
898 | (ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into()))) | 897 | let substs = self.substs_for_method_call(generics, generic_args, &ty); |
898 | self.write_method_resolution(tgt_expr, func, substs.clone()); | ||
899 | (ty, self.db.value_ty(func.into()), substs) | ||
899 | } | 900 | } |
900 | None => (receiver_ty, Binders::empty(&Interner, self.err_ty()), None), | 901 | None => ( |
902 | receiver_ty, | ||
903 | Binders::empty(&Interner, self.err_ty()), | ||
904 | Substitution::empty(&Interner), | ||
905 | ), | ||
901 | }; | 906 | }; |
902 | let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); | ||
903 | let method_ty = method_ty.substitute(&Interner, &substs); | 907 | let method_ty = method_ty.substitute(&Interner, &substs); |
904 | let method_ty = self.insert_type_vars(method_ty); | ||
905 | self.register_obligations_for_call(&method_ty); | 908 | self.register_obligations_for_call(&method_ty); |
906 | let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { | 909 | let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { |
907 | Some(sig) => { | 910 | Some(sig) => { |
@@ -950,23 +953,21 @@ impl<'a> InferenceContext<'a> { | |||
950 | 953 | ||
951 | fn substs_for_method_call( | 954 | fn substs_for_method_call( |
952 | &mut self, | 955 | &mut self, |
953 | def_generics: Option<Generics>, | 956 | def_generics: Generics, |
954 | generic_args: Option<&GenericArgs>, | 957 | generic_args: Option<&GenericArgs>, |
955 | receiver_ty: &Ty, | 958 | receiver_ty: &Ty, |
956 | ) -> Substitution { | 959 | ) -> Substitution { |
957 | let (parent_params, self_params, type_params, impl_trait_params) = | 960 | let (parent_params, self_params, type_params, impl_trait_params) = |
958 | def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split()); | 961 | def_generics.provenance_split(); |
959 | assert_eq!(self_params, 0); // method shouldn't have another Self param | 962 | assert_eq!(self_params, 0); // method shouldn't have another Self param |
960 | let total_len = parent_params + type_params + impl_trait_params; | 963 | let total_len = parent_params + type_params + impl_trait_params; |
961 | let mut substs = Vec::with_capacity(total_len); | 964 | let mut substs = Vec::with_capacity(total_len); |
962 | // Parent arguments are unknown, except for the receiver type | 965 | // Parent arguments are unknown, except for the receiver type |
963 | if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { | 966 | for (_id, param) in def_generics.iter_parent() { |
964 | for (_id, param) in parent_generics { | 967 | if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf { |
965 | if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf { | 968 | substs.push(receiver_ty.clone()); |
966 | substs.push(receiver_ty.clone()); | 969 | } else { |
967 | } else { | 970 | substs.push(self.table.new_type_var()); |
968 | substs.push(self.err_ty()); | ||
969 | } | ||
970 | } | 971 | } |
971 | } | 972 | } |
972 | // handle provided type arguments | 973 | // handle provided type arguments |
@@ -989,7 +990,7 @@ impl<'a> InferenceContext<'a> { | |||
989 | }; | 990 | }; |
990 | let supplied_params = substs.len(); | 991 | let supplied_params = substs.len(); |
991 | for _ in supplied_params..total_len { | 992 | for _ in supplied_params..total_len { |
992 | substs.push(self.err_ty()); | 993 | substs.push(self.table.new_type_var()); |
993 | } | 994 | } |
994 | assert_eq!(substs.len(), total_len); | 995 | assert_eq!(substs.len(), total_len); |
995 | Substitution::from_iter(&Interner, substs) | 996 | Substitution::from_iter(&Interner, substs) |
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/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index f8233cac3..ea5684229 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -295,8 +295,11 @@ impl<'a> InferenceTable<'a> { | |||
295 | .expect("fold failed unexpectedly") | 295 | .expect("fold failed unexpectedly") |
296 | } | 296 | } |
297 | 297 | ||
298 | pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { | 298 | pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T::Result |
299 | self.resolve_with_fallback(ty, |_, _, d, _| d) | 299 | where |
300 | T: HasInterner<Interner = Interner> + Fold<Interner>, | ||
301 | { | ||
302 | self.resolve_with_fallback(t, |_, _, d, _| d) | ||
300 | } | 303 | } |
301 | 304 | ||
302 | /// Unify two types and register new trait goals that arise from that. | 305 | /// Unify two types and register new trait goals that arise from that. |
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..49add4ab9 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -161,6 +161,58 @@ mod result { | |||
161 | } | 161 | } |
162 | 162 | ||
163 | #[test] | 163 | #[test] |
164 | fn infer_try_trait_v2() { | ||
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 | mod ops { | ||
176 | mod try_trait { | ||
177 | pub trait Try: FromResidual { | ||
178 | type Output; | ||
179 | type Residual; | ||
180 | } | ||
181 | pub trait FromResidual<R = <Self as Try>::Residual> {} | ||
182 | } | ||
183 | |||
184 | pub use self::try_trait::FromResidual; | ||
185 | pub use self::try_trait::Try; | ||
186 | } | ||
187 | |||
188 | mov convert { | ||
189 | pub trait From<T> {} | ||
190 | impl<T> From<T> for T {} | ||
191 | } | ||
192 | |||
193 | #[prelude_import] use result::*; | ||
194 | mod result { | ||
195 | use crate::convert::From; | ||
196 | use crate::ops::{Try, FromResidual}; | ||
197 | |||
198 | pub enum Infallible {} | ||
199 | pub enum Result<O, E> { | ||
200 | Ok(O), | ||
201 | Err(E) | ||
202 | } | ||
203 | |||
204 | impl<O, E> Try for Result<O, E> { | ||
205 | type Output = O; | ||
206 | type Error = Result<Infallible, E>; | ||
207 | } | ||
208 | |||
209 | impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {} | ||
210 | } | ||
211 | "#, | ||
212 | ); | ||
213 | } | ||
214 | |||
215 | #[test] | ||
164 | fn infer_for_loop() { | 216 | fn infer_for_loop() { |
165 | check_types( | 217 | check_types( |
166 | r#" | 218 | r#" |
@@ -3041,7 +3093,7 @@ fn infer_fn_trait_arg() { | |||
3041 | 3093 | ||
3042 | #[test] | 3094 | #[test] |
3043 | fn infer_box_fn_arg() { | 3095 | fn infer_box_fn_arg() { |
3044 | // The type mismatch is a bug | 3096 | // The type mismatch is because we don't define Unsize and CoerceUnsized |
3045 | check_infer_with_mismatches( | 3097 | check_infer_with_mismatches( |
3046 | r#" | 3098 | r#" |
3047 | //- /lib.rs deps:std | 3099 | //- /lib.rs deps:std |
@@ -3101,7 +3153,7 @@ fn foo() { | |||
3101 | 555..557 'ps': {unknown} | 3153 | 555..557 'ps': {unknown} |
3102 | 559..561 '{}': () | 3154 | 559..561 '{}': () |
3103 | 568..569 'f': Box<dyn FnOnce(&Option<i32>)> | 3155 | 568..569 'f': Box<dyn FnOnce(&Option<i32>)> |
3104 | 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> | 3156 | 568..573 'f(&s)': () |
3105 | 570..572 '&s': &Option<i32> | 3157 | 570..572 '&s': &Option<i32> |
3106 | 571..572 's': Option<i32> | 3158 | 571..572 's': Option<i32> |
3107 | 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()> | 3159 | 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()> |
@@ -3571,3 +3623,104 @@ fn main() { | |||
3571 | "#]], | 3623 | "#]], |
3572 | ) | 3624 | ) |
3573 | } | 3625 | } |
3626 | |||
3627 | #[test] | ||
3628 | fn fn_returning_unit() { | ||
3629 | check_infer_with_mismatches( | ||
3630 | r#" | ||
3631 | #[lang = "fn_once"] | ||
3632 | trait FnOnce<Args> { | ||
3633 | type Output; | ||
3634 | } | ||
3635 | |||
3636 | fn test<F: FnOnce()>(f: F) { | ||
3637 | let _: () = f(); | ||
3638 | }"#, | ||
3639 | expect![[r#" | ||
3640 | 82..83 'f': F | ||
3641 | 88..112 '{ ...f(); }': () | ||
3642 | 98..99 '_': () | ||
3643 | 106..107 'f': F | ||
3644 | 106..109 'f()': () | ||
3645 | "#]], | ||
3646 | ); | ||
3647 | } | ||
3648 | |||
3649 | #[test] | ||
3650 | fn trait_in_scope_of_trait_impl() { | ||
3651 | check_infer( | ||
3652 | r#" | ||
3653 | mod foo { | ||
3654 | pub trait Foo { | ||
3655 | fn foo(self); | ||
3656 | fn bar(self) -> usize { 0 } | ||
3657 | } | ||
3658 | } | ||
3659 | impl foo::Foo for u32 { | ||
3660 | fn foo(self) { | ||
3661 | let _x = self.bar(); | ||
3662 | } | ||
3663 | } | ||
3664 | "#, | ||
3665 | expect![[r#" | ||
3666 | 45..49 'self': Self | ||
3667 | 67..71 'self': Self | ||
3668 | 82..87 '{ 0 }': usize | ||
3669 | 84..85 '0': usize | ||
3670 | 131..135 'self': u32 | ||
3671 | 137..173 '{ ... }': () | ||
3672 | 151..153 '_x': usize | ||
3673 | 156..160 'self': u32 | ||
3674 | 156..166 'self.bar()': usize | ||
3675 | "#]], | ||
3676 | ); | ||
3677 | } | ||
3678 | |||
3679 | #[test] | ||
3680 | fn infer_async_ret_type() { | ||
3681 | check_types( | ||
3682 | r#" | ||
3683 | //- /main.rs crate:main deps:core | ||
3684 | |||
3685 | enum Result<T, E> { | ||
3686 | Ok(T), | ||
3687 | Err(E), | ||
3688 | } | ||
3689 | |||
3690 | use Result::*; | ||
3691 | |||
3692 | |||
3693 | struct Fooey; | ||
3694 | |||
3695 | impl Fooey { | ||
3696 | fn collect<B: Convert>(self) -> B { | ||
3697 | B::new() | ||
3698 | } | ||
3699 | } | ||
3700 | |||
3701 | trait Convert { | ||
3702 | fn new() -> Self; | ||
3703 | } | ||
3704 | impl Convert for u32 { | ||
3705 | fn new() -> Self { | ||
3706 | 0 | ||
3707 | } | ||
3708 | } | ||
3709 | |||
3710 | async fn get_accounts() -> Result<u32, ()> { | ||
3711 | let ret = Fooey.collect(); | ||
3712 | // ^ u32 | ||
3713 | Ok(ret) | ||
3714 | } | ||
3715 | |||
3716 | //- /core.rs crate:core | ||
3717 | #[prelude_import] use future::*; | ||
3718 | mod future { | ||
3719 | #[lang = "future_trait"] | ||
3720 | trait Future { | ||
3721 | type Output; | ||
3722 | } | ||
3723 | } | ||
3724 | "#, | ||
3725 | ); | ||
3726 | } | ||
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs index 294cb531c..f589b314b 100644 --- a/crates/hir_ty/src/traits.rs +++ b/crates/hir_ty/src/traits.rs | |||
@@ -112,7 +112,7 @@ fn solve( | |||
112 | let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); | 112 | let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); |
113 | 113 | ||
114 | let should_continue = || { | 114 | let should_continue = || { |
115 | context.db.check_canceled(); | 115 | db.unwind_if_cancelled(); |
116 | let remaining = fuel.get(); | 116 | let remaining = fuel.get(); |
117 | fuel.set(remaining - 1); | 117 | fuel.set(remaining - 1); |
118 | if remaining == 0 { | 118 | if remaining == 0 { |