aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src')
-rw-r--r--crates/hir_ty/src/chalk_db.rs8
-rw-r--r--crates/hir_ty/src/diagnostics.rs12
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs6
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs15
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs6
-rw-r--r--crates/hir_ty/src/diagnostics_sink.rs109
-rw-r--r--crates/hir_ty/src/display.rs13
-rw-r--r--crates/hir_ty/src/infer.rs45
-rw-r--r--crates/hir_ty/src/infer/coerce.rs12
-rw-r--r--crates/hir_ty/src/infer/expr.rs49
-rw-r--r--crates/hir_ty/src/infer/pat.rs9
-rw-r--r--crates/hir_ty/src/infer/unify.rs7
-rw-r--r--crates/hir_ty/src/lib.rs1
-rw-r--r--crates/hir_ty/src/lower.rs5
-rw-r--r--crates/hir_ty/src/tests.rs45
-rw-r--r--crates/hir_ty/src/tests/coercion.rs101
-rw-r--r--crates/hir_ty/src/tests/incremental.rs51
-rw-r--r--crates/hir_ty/src/tests/macros.rs18
-rw-r--r--crates/hir_ty/src/tests/traits.rs157
-rw-r--r--crates/hir_ty/src/traits.rs2
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
9use base_db::CrateId; 9use base_db::CrateId;
10use hir_def::{DefWithBodyId, ModuleDefId}; 10use hir_def::{DefWithBodyId, ModuleDefId};
11use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
12use hir_expand::{name::Name, HirFileId, InFile}; 11use hir_expand::{name::Name, HirFileId, InFile};
13use stdx::format_to; 12use stdx::format_to;
14use syntax::{ast, AstPtr, SyntaxNodePtr}; 13use syntax::{ast, AstPtr, SyntaxNodePtr};
15 14
16use crate::db::HirDatabase; 15use crate::{
16 db::HirDatabase,
17 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink},
18};
17 19
18pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; 20pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields};
19 21
@@ -446,15 +448,13 @@ impl Diagnostic for ReplaceFilterMapNextWithFindMap {
446mod tests { 448mod 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};
22use hir_expand::{ 22use hir_expand::name::{AsName, Name};
23 diagnostics::DiagnosticSink,
24 name::{AsName, Name},
25};
26use stdx::{always, never}; 23use stdx::{always, never};
27use syntax::{ 24use syntax::{
28 ast::{self, NameOwner}, 25 ast::{self, NameOwner},
@@ -32,6 +29,7 @@ use syntax::{
32use crate::{ 29use 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
37mod allow { 35mod 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 @@
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId}; 7use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId};
8use hir_expand::{diagnostics::DiagnosticSink, name}; 8use hir_expand::name;
9use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
10use syntax::{ast, AstPtr}; 10use 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};
12use hir_expand::diagnostics::DiagnosticSink;
13 12
14use crate::{ 13use 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
18pub(super) struct UnsafeValidator<'a, 'b: 'a> { 18pub(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
17use std::{any::Any, fmt};
18
19use hir_expand::InFile;
20use syntax::SyntaxNodePtr;
21
22#[derive(Copy, Clone, Debug, PartialEq)]
23pub struct DiagnosticCode(pub &'static str);
24
25impl DiagnosticCode {
26 pub fn as_str(&self) -> &str {
27 self.0
28 }
29}
30
31pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
32 fn code(&self) -> DiagnosticCode;
33 fn message(&self) -> String;
34 /// Source element that triggered the diagnostics.
35 ///
36 /// Note that this should reflect "semantics", rather than specific span we
37 /// want to highlight. When rendering the diagnostics into an error message,
38 /// the IDE will fetch the `SyntaxNode` and will narrow the span
39 /// appropriately.
40 fn display_source(&self) -> InFile<SyntaxNodePtr>;
41 fn as_any(&self) -> &(dyn Any + Send + 'static);
42 fn is_experimental(&self) -> bool {
43 false
44 }
45}
46
47pub struct DiagnosticSink<'a> {
48 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
49 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
50 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
51}
52
53impl<'a> DiagnosticSink<'a> {
54 pub fn push(&mut self, d: impl Diagnostic) {
55 let d: &dyn Diagnostic = &d;
56 self._push(d);
57 }
58
59 fn _push(&mut self, d: &dyn Diagnostic) {
60 for filter in &mut self.filters {
61 if !filter(d) {
62 return;
63 }
64 }
65 for cb in &mut self.callbacks {
66 match cb(d) {
67 Ok(()) => return,
68 Err(()) => (),
69 }
70 }
71 (self.default_callback)(d)
72 }
73}
74
75pub struct DiagnosticSinkBuilder<'a> {
76 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
77 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
78}
79
80impl<'a> DiagnosticSinkBuilder<'a> {
81 pub fn new() -> Self {
82 Self { callbacks: Vec::new(), filters: Vec::new() }
83 }
84
85 pub fn filter<F: FnMut(&dyn Diagnostic) -> bool + 'a>(mut self, cb: F) -> Self {
86 self.filters.push(Box::new(cb));
87 self
88 }
89
90 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self {
91 let cb = move |diag: &dyn Diagnostic| match diag.as_any().downcast_ref::<D>() {
92 Some(d) => {
93 cb(d);
94 Ok(())
95 }
96 None => Err(()),
97 };
98 self.callbacks.push(Box::new(cb));
99 self
100 }
101
102 pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> {
103 DiagnosticSink {
104 callbacks: self.callbacks,
105 filters: self.filters,
106 default_callback: Box::new(default_callback),
107 }
108 }
109}
diff --git a/crates/hir_ty/src/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
260impl<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
259impl HirDisplay for ProjectionTy { 266impl 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};
31use hir_expand::{diagnostics::DiagnosticSink, name::name}; 31use hir_expand::name::name;
32use la_arena::ArenaMap; 32use la_arena::ArenaMap;
33use rustc_hash::FxHashMap; 33use rustc_hash::FxHashMap;
34use stdx::impl_from; 34use stdx::impl_from;
35use syntax::SmolStr; 35use syntax::SmolStr;
36 36
37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; 37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
38use crate::diagnostics_sink::DiagnosticSink;
38use crate::{ 39use 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)]
133pub struct InferenceResult { 134pub 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
154impl InferenceResult { 155impl 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
791mod diagnostics { 806mod 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;
21mod walk; 21mod walk;
22pub mod db; 22pub mod db;
23pub mod diagnostics; 23pub mod diagnostics;
24pub mod diagnostics_sink;
24pub mod display; 25pub mod display;
25pub mod method_resolution; 26pub mod method_resolution;
26pub mod primitive; 27pub 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
11use base_db::CrateId; 11use base_db::CrateId;
12use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; 12use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
13use hir_def::intern::Interned;
13use hir_def::{ 14use 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;
7mod method_resolution; 7mod method_resolution;
8mod macros; 8mod macros;
9mod display_source_code; 9mod display_source_code;
10mod incremental;
10 11
11use std::{env, sync::Arc}; 12use 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]
321fn 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
364fn check_infer(ra_fixture: &str, expect: Expect) { 321fn 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]
837fn coerce_unsize_generic() { 836fn 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]
880fn coerce_unsize_apit() {
881 // FIXME: #8984
882 check_infer_with_mismatches(
883 r#"
884#[lang = "sized"]
885pub trait Sized {}
886#[lang = "unsize"]
887pub trait Unsize<T> {}
888#[lang = "coerce_unsized"]
889pub trait CoerceUnsized<T> {}
890
891impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
892
893trait Foo {}
894
895fn 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]
965fn panic_macro() {
966 check_infer_with_mismatches(
967 r#"
968mod panic {
969 #[macro_export]
970 pub macro panic_2015 {
971 () => (
972 $crate::panicking::panic()
973 ),
974 }
975}
976
977mod panicking {
978 pub fn panic() -> ! { loop {} }
979}
980
981#[rustc_builtin_macro = "core_panic"]
982macro_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
990fn 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 @@
1use std::sync::Arc;
2
3use base_db::{fixture::WithFixture, SourceDatabaseExt};
4
5use crate::{db::HirDatabase, test_db::TestDB};
6
7use super::visit_module;
8
9#[test]
10fn 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]
755fn infer_builtin_macros_include_expression() {
756 check_types(
757 r#"
758//- /main.rs
759#[rustc_builtin_macro]
760macro_rules! include {() => {}}
761fn main() {
762 let i = include!("bla.rs");
763 i;
764 //^ i32
765}
766//- /bla.rs
7670
768 "#,
769 )
770}
771
772#[test]
755fn infer_builtin_macros_include_child_mod() { 773fn 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]
164fn infer_try_trait_v2() {
165 check_types(
166 r#"
167//- /main.rs crate:main deps:core
168fn test() {
169 let r: Result<i32, u64> = Result::Ok(1);
170 let v = r?;
171 v;
172} //^ i32
173
174//- /core.rs crate:core
175mod 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
188mov convert {
189 pub trait From<T> {}
190 impl<T> From<T> for T {}
191}
192
193#[prelude_import] use result::*;
194mod 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]
164fn infer_for_loop() { 216fn 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]
3043fn infer_box_fn_arg() { 3095fn 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]
3628fn fn_returning_unit() {
3629 check_infer_with_mismatches(
3630 r#"
3631#[lang = "fn_once"]
3632trait FnOnce<Args> {
3633 type Output;
3634}
3635
3636fn 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]
3650fn trait_in_scope_of_trait_impl() {
3651 check_infer(
3652 r#"
3653mod foo {
3654 pub trait Foo {
3655 fn foo(self);
3656 fn bar(self) -> usize { 0 }
3657 }
3658}
3659impl 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]
3680fn infer_async_ret_type() {
3681 check_types(
3682 r#"
3683//- /main.rs crate:main deps:core
3684
3685enum Result<T, E> {
3686 Ok(T),
3687 Err(E),
3688}
3689
3690use Result::*;
3691
3692
3693struct Fooey;
3694
3695impl Fooey {
3696 fn collect<B: Convert>(self) -> B {
3697 B::new()
3698 }
3699}
3700
3701trait Convert {
3702 fn new() -> Self;
3703}
3704impl Convert for u32 {
3705 fn new() -> Self {
3706 0
3707 }
3708}
3709
3710async 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::*;
3718mod 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 {