aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty')
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/autoderef.rs11
-rw-r--r--crates/hir_ty/src/diagnostics.rs177
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs279
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check/case_conv.rs34
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs96
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs37
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs16
-rw-r--r--crates/hir_ty/src/display.rs237
-rw-r--r--crates/hir_ty/src/infer.rs48
-rw-r--r--crates/hir_ty/src/infer/coerce.rs87
-rw-r--r--crates/hir_ty/src/infer/expr.rs280
-rw-r--r--crates/hir_ty/src/infer/pat.rs34
-rw-r--r--crates/hir_ty/src/infer/unify.rs200
-rw-r--r--crates/hir_ty/src/lib.rs608
-rw-r--r--crates/hir_ty/src/lower.rs138
-rw-r--r--crates/hir_ty/src/method_resolution.rs186
-rw-r--r--crates/hir_ty/src/op.rs50
-rw-r--r--crates/hir_ty/src/primitive.rs160
-rw-r--r--crates/hir_ty/src/test_db.rs6
-rw-r--r--crates/hir_ty/src/tests.rs14
-rw-r--r--crates/hir_ty/src/tests/macros.rs23
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs67
-rw-r--r--crates/hir_ty/src/tests/simple.rs155
-rw-r--r--crates/hir_ty/src/tests/traits.rs60
-rw-r--r--crates/hir_ty/src/traits.rs2
-rw-r--r--crates/hir_ty/src/traits/chalk.rs32
-rw-r--r--crates/hir_ty/src/traits/chalk/interner.rs5
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs332
29 files changed, 1787 insertions, 1593 deletions
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 98434b741..d1302d749 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = { version = "0.47", default-features = false } 20chalk-solve = { version = "0.59", default-features = false }
21chalk-ir = "0.47" 21chalk-ir = "0.59"
22chalk-recursive = "0.47" 22chalk-recursive = "0.59"
23la-arena = { version = "0.2.0", path = "../../lib/arena" } 23la-arena = { version = "0.2.0", path = "../../lib/arena" }
24 24
25stdx = { path = "../stdx", version = "0.0.0" } 25stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index ece68183e..be1fd1f13 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -81,7 +81,7 @@ fn deref_by_trait(
81 81
82 // Now do the assoc type projection 82 // Now do the assoc type projection
83 let projection = super::traits::ProjectionPredicate { 83 let projection = super::traits::ProjectionPredicate {
84 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())), 84 ty: Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())),
85 projection_ty: super::ProjectionTy { associated_ty: target, parameters }, 85 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
86 }; 86 };
87 87
@@ -89,8 +89,10 @@ fn deref_by_trait(
89 89
90 let in_env = InEnvironment { value: obligation, environment: ty.environment }; 90 let in_env = InEnvironment { value: obligation, environment: ty.environment };
91 91
92 let canonical = 92 let canonical = Canonical::new(
93 Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General))); 93 in_env,
94 ty.value.kinds.iter().copied().chain(Some(chalk_ir::TyVariableKind::General)),
95 );
94 96
95 let solution = db.trait_solve(krate, canonical)?; 97 let solution = db.trait_solve(krate, canonical)?;
96 98
@@ -112,7 +114,8 @@ fn deref_by_trait(
112 // new variables in that case 114 // new variables in that case
113 115
114 for i in 1..vars.0.kinds.len() { 116 for i in 1..vars.0.kinds.len() {
115 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 117 if vars.0.value[i - 1]
118 != Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
116 { 119 {
117 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); 120 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
118 return None; 121 return None;
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index c67a289f2..6bca7aa0d 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -247,7 +247,7 @@ impl Diagnostic for RemoveThisSemicolon {
247 247
248// Diagnostic: break-outside-of-loop 248// Diagnostic: break-outside-of-loop
249// 249//
250// This diagnostic is triggered if `break` keyword is used outside of a loop. 250// This diagnostic is triggered if the `break` keyword is used outside of a loop.
251#[derive(Debug)] 251#[derive(Debug)]
252pub struct BreakOutsideOfLoop { 252pub struct BreakOutsideOfLoop {
253 pub file: HirFileId, 253 pub file: HirFileId,
@@ -271,7 +271,7 @@ impl Diagnostic for BreakOutsideOfLoop {
271 271
272// Diagnostic: missing-unsafe 272// Diagnostic: missing-unsafe
273// 273//
274// This diagnostic is triggered if operation marked as `unsafe` is used outside of `unsafe` function or block. 274// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
275#[derive(Debug)] 275#[derive(Debug)]
276pub struct MissingUnsafe { 276pub struct MissingUnsafe {
277 pub file: HirFileId, 277 pub file: HirFileId,
@@ -295,7 +295,7 @@ impl Diagnostic for MissingUnsafe {
295 295
296// Diagnostic: mismatched-arg-count 296// Diagnostic: mismatched-arg-count
297// 297//
298// This diagnostic is triggered if function is invoked with an incorrect amount of arguments. 298// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
299#[derive(Debug)] 299#[derive(Debug)]
300pub struct MismatchedArgCount { 300pub struct MismatchedArgCount {
301 pub file: HirFileId, 301 pub file: HirFileId,
@@ -345,15 +345,46 @@ impl fmt::Display for CaseType {
345 } 345 }
346} 346}
347 347
348#[derive(Debug)]
349pub enum IdentType {
350 Argument,
351 Constant,
352 Enum,
353 Field,
354 Function,
355 StaticVariable,
356 Structure,
357 Variable,
358 Variant,
359}
360
361impl fmt::Display for IdentType {
362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363 let repr = match self {
364 IdentType::Argument => "Argument",
365 IdentType::Constant => "Constant",
366 IdentType::Enum => "Enum",
367 IdentType::Field => "Field",
368 IdentType::Function => "Function",
369 IdentType::StaticVariable => "Static variable",
370 IdentType::Structure => "Structure",
371 IdentType::Variable => "Variable",
372 IdentType::Variant => "Variant",
373 };
374
375 write!(f, "{}", repr)
376 }
377}
378
348// Diagnostic: incorrect-ident-case 379// Diagnostic: incorrect-ident-case
349// 380//
350// This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. 381// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
351#[derive(Debug)] 382#[derive(Debug)]
352pub struct IncorrectCase { 383pub struct IncorrectCase {
353 pub file: HirFileId, 384 pub file: HirFileId,
354 pub ident: AstPtr<ast::Name>, 385 pub ident: AstPtr<ast::Name>,
355 pub expected_case: CaseType, 386 pub expected_case: CaseType,
356 pub ident_type: String, 387 pub ident_type: IdentType,
357 pub ident_text: String, 388 pub ident_text: String,
358 pub suggested_text: String, 389 pub suggested_text: String,
359} 390}
@@ -386,6 +417,31 @@ impl Diagnostic for IncorrectCase {
386 } 417 }
387} 418}
388 419
420// Diagnostic: replace-filter-map-next-with-find-map
421//
422// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
423#[derive(Debug)]
424pub struct ReplaceFilterMapNextWithFindMap {
425 pub file: HirFileId,
426 /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
427 pub next_expr: AstPtr<ast::Expr>,
428}
429
430impl Diagnostic for ReplaceFilterMapNextWithFindMap {
431 fn code(&self) -> DiagnosticCode {
432 DiagnosticCode("replace-filter-map-next-with-find-map")
433 }
434 fn message(&self) -> String {
435 "replace filter_map(..).next() with find_map(..)".to_string()
436 }
437 fn display_source(&self) -> InFile<SyntaxNodePtr> {
438 InFile { file_id: self.file, value: self.next_expr.clone().into() }
439 }
440 fn as_any(&self) -> &(dyn Any + Send + 'static) {
441 self
442 }
443}
444
389#[cfg(test)] 445#[cfg(test)]
390mod tests { 446mod tests {
391 use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; 447 use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
@@ -409,7 +465,7 @@ mod tests {
409 let crate_def_map = self.crate_def_map(krate); 465 let crate_def_map = self.crate_def_map(krate);
410 466
411 let mut fns = Vec::new(); 467 let mut fns = Vec::new();
412 for (module_id, _) in crate_def_map.modules.iter() { 468 for (module_id, _) in crate_def_map.modules() {
413 for decl in crate_def_map[module_id].scope.declarations() { 469 for decl in crate_def_map[module_id].scope.declarations() {
414 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); 470 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
415 validate_module_item(self, krate, decl, &mut sink); 471 validate_module_item(self, krate, decl, &mut sink);
@@ -455,7 +511,7 @@ mod tests {
455 // FIXME: macros... 511 // FIXME: macros...
456 let file_id = src.file_id.original_file(&db); 512 let file_id = src.file_id.original_file(&db);
457 let range = src.value.to_node(&root).text_range(); 513 let range = src.value.to_node(&root).text_range();
458 let message = d.message().to_owned(); 514 let message = d.message();
459 actual.entry(file_id).or_default().push((range, message)); 515 actual.entry(file_id).or_default().push((range, message));
460 }); 516 });
461 517
@@ -626,6 +682,30 @@ fn baz(s: S) -> i32 {
626 } 682 }
627 683
628 #[test] 684 #[test]
685 fn missing_record_pat_field_box() {
686 check_diagnostics(
687 r"
688struct S { s: Box<u32> }
689fn x(a: S) {
690 let S { box s } = a;
691}
692",
693 )
694 }
695
696 #[test]
697 fn missing_record_pat_field_ref() {
698 check_diagnostics(
699 r"
700struct S { s: u32 }
701fn x(a: S) {
702 let S { ref s } = a;
703}
704",
705 )
706 }
707
708 #[test]
629 fn break_outside_of_loop() { 709 fn break_outside_of_loop() {
630 check_diagnostics( 710 check_diagnostics(
631 r#" 711 r#"
@@ -644,4 +724,87 @@ fn foo() { break; }
644 "#, 724 "#,
645 ); 725 );
646 } 726 }
727
728 // Register the required standard library types to make the tests work
729 fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
730 let prefix = r#"
731 //- /main.rs crate:main deps:core
732 use core::iter::Iterator;
733 use core::option::Option::{self, Some, None};
734 "#;
735 let suffix = r#"
736 //- /core/lib.rs crate:core
737 pub mod option {
738 pub enum Option<T> { Some(T), None }
739 }
740 pub mod iter {
741 pub trait Iterator {
742 type Item;
743 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
744 fn next(&mut self) -> Option<Self::Item>;
745 }
746 pub struct FilterMap {}
747 impl Iterator for FilterMap {
748 type Item = i32;
749 fn next(&mut self) -> i32 { 7 }
750 }
751 }
752 "#;
753 format!("{}{}{}", prefix, body, suffix)
754 }
755
756 #[test]
757 fn replace_filter_map_next_with_find_map2() {
758 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
759 r#"
760 fn foo() {
761 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
762 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
763 }
764 "#,
765 ));
766 }
767
768 #[test]
769 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
770 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
771 r#"
772 fn foo() {
773 let m = [1, 2, 3]
774 .iter()
775 .filter_map(|x| if *x == 2 { Some (4) } else { None })
776 .len();
777 }
778 "#,
779 ));
780 }
781
782 #[test]
783 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
784 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
785 r#"
786 fn foo() {
787 let m = [1, 2, 3]
788 .iter()
789 .filter_map(|x| if *x == 2 { Some (4) } else { None })
790 .map(|x| x + 2)
791 .len();
792 }
793 "#,
794 ));
795 }
796
797 #[test]
798 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
799 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
800 r#"
801 fn foo() {
802 let m = [1, 2, 3]
803 .iter()
804 .filter_map(|x| if *x == 2 { Some (4) } else { None });
805 let n = m.next();
806 }
807 "#,
808 ));
809 }
647} 810}
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index eaeb6899f..6773ddea3 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -23,6 +23,7 @@ use hir_expand::{
23 diagnostics::DiagnosticSink, 23 diagnostics::DiagnosticSink,
24 name::{AsName, Name}, 24 name::{AsName, Name},
25}; 25};
26use stdx::{always, never};
26use syntax::{ 27use syntax::{
27 ast::{self, NameOwner}, 28 ast::{self, NameOwner},
28 AstNode, AstPtr, 29 AstNode, AstPtr,
@@ -31,7 +32,7 @@ use test_utils::mark;
31 32
32use crate::{ 33use crate::{
33 db::HirDatabase, 34 db::HirDatabase,
34 diagnostics::{decl_check::case_conv::*, CaseType, IncorrectCase}, 35 diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase},
35}; 36};
36 37
37mod allow { 38mod allow {
@@ -40,7 +41,7 @@ mod allow {
40 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; 41 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
41} 42}
42 43
43pub(super) struct DeclValidator<'a, 'b: 'a> { 44pub(super) struct DeclValidator<'a, 'b> {
44 db: &'a dyn HirDatabase, 45 db: &'a dyn HirDatabase,
45 krate: CrateId, 46 krate: CrateId,
46 sink: &'a mut DiagnosticSink<'b>, 47 sink: &'a mut DiagnosticSink<'b>,
@@ -77,7 +78,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
77 AdtId::StructId(struct_id) => self.validate_struct(struct_id), 78 AdtId::StructId(struct_id) => self.validate_struct(struct_id),
78 AdtId::EnumId(enum_id) => self.validate_enum(enum_id), 79 AdtId::EnumId(enum_id) => self.validate_enum(enum_id),
79 AdtId::UnionId(_) => { 80 AdtId::UnionId(_) => {
80 // Unions aren't yet supported by this validator. 81 // FIXME: Unions aren't yet supported by this validator.
81 } 82 }
82 } 83 }
83 } 84 }
@@ -111,63 +112,50 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
111 112
112 // Check the function name. 113 // Check the function name.
113 let function_name = data.name.to_string(); 114 let function_name = data.name.to_string();
114 let fn_name_replacement = if let Some(new_name) = to_lower_snake_case(&function_name) { 115 let fn_name_replacement = to_lower_snake_case(&function_name).map(|new_name| Replacement {
115 let replacement = Replacement { 116 current_name: data.name.clone(),
116 current_name: data.name.clone(), 117 suggested_text: new_name,
117 suggested_text: new_name, 118 expected_case: CaseType::LowerSnakeCase,
118 expected_case: CaseType::LowerSnakeCase, 119 });
119 };
120 Some(replacement)
121 } else {
122 None
123 };
124 120
125 // Check the param names. 121 // Check the param names.
126 let mut fn_param_replacements = Vec::new(); 122 let fn_param_replacements = body
127 123 .params
128 for pat_id in body.params.iter().cloned() { 124 .iter()
129 let pat = &body[pat_id]; 125 .filter_map(|&id| match &body[id] {
130 126 Pat::Bind { name, .. } => Some(name),
131 let param_name = match pat { 127 _ => None,
132 Pat::Bind { name, .. } => name, 128 })
133 _ => continue, 129 .filter_map(|param_name| {
134 }; 130 Some(Replacement {
135
136 let name = param_name.to_string();
137 if let Some(new_name) = to_lower_snake_case(&name) {
138 let replacement = Replacement {
139 current_name: param_name.clone(), 131 current_name: param_name.clone(),
140 suggested_text: new_name, 132 suggested_text: to_lower_snake_case(&param_name.to_string())?,
141 expected_case: CaseType::LowerSnakeCase, 133 expected_case: CaseType::LowerSnakeCase,
142 }; 134 })
143 fn_param_replacements.push(replacement); 135 })
144 } 136 .collect();
145 }
146 137
147 // Check the patterns inside the function body. 138 // Check the patterns inside the function body.
148 let mut pats_replacements = Vec::new(); 139 let pats_replacements = body
149 140 .pats
150 for (pat_idx, pat) in body.pats.iter() { 141 .iter()
151 if body.params.contains(&pat_idx) { 142 // We aren't interested in function parameters, we've processed them above.
152 // We aren't interested in function parameters, we've processed them above. 143 .filter(|(pat_idx, _)| !body.params.contains(&pat_idx))
153 continue; 144 .filter_map(|(id, pat)| match pat {
154 } 145 Pat::Bind { name, .. } => Some((id, name)),
155 146 _ => None,
156 let bind_name = match pat { 147 })
157 Pat::Bind { name, .. } => name, 148 .filter_map(|(id, bind_name)| {
158 _ => continue, 149 Some((
159 }; 150 id,
160 151 Replacement {
161 let name = bind_name.to_string(); 152 current_name: bind_name.clone(),
162 if let Some(new_name) = to_lower_snake_case(&name) { 153 suggested_text: to_lower_snake_case(&bind_name.to_string())?,
163 let replacement = Replacement { 154 expected_case: CaseType::LowerSnakeCase,
164 current_name: bind_name.clone(), 155 },
165 suggested_text: new_name, 156 ))
166 expected_case: CaseType::LowerSnakeCase, 157 })
167 }; 158 .collect();
168 pats_replacements.push((pat_idx, replacement));
169 }
170 }
171 159
172 // If there is at least one element to spawn a warning on, go to the source map and generate a warning. 160 // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
173 self.create_incorrect_case_diagnostic_for_func( 161 self.create_incorrect_case_diagnostic_for_func(
@@ -199,8 +187,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
199 let ast_ptr = match fn_src.value.name() { 187 let ast_ptr = match fn_src.value.name() {
200 Some(name) => name, 188 Some(name) => name,
201 None => { 189 None => {
202 // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic. 190 never!(
203 log::error!(
204 "Replacement ({:?}) was generated for a function without a name: {:?}", 191 "Replacement ({:?}) was generated for a function without a name: {:?}",
205 replacement, 192 replacement,
206 fn_src 193 fn_src
@@ -211,7 +198,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
211 198
212 let diagnostic = IncorrectCase { 199 let diagnostic = IncorrectCase {
213 file: fn_src.file_id, 200 file: fn_src.file_id,
214 ident_type: "Function".to_string(), 201 ident_type: IdentType::Function,
215 ident: AstPtr::new(&ast_ptr).into(), 202 ident: AstPtr::new(&ast_ptr).into(),
216 expected_case: replacement.expected_case, 203 expected_case: replacement.expected_case,
217 ident_text: replacement.current_name.to_string(), 204 ident_text: replacement.current_name.to_string(),
@@ -225,12 +212,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
225 let fn_params_list = match fn_src.value.param_list() { 212 let fn_params_list = match fn_src.value.param_list() {
226 Some(params) => params, 213 Some(params) => params,
227 None => { 214 None => {
228 if !fn_param_replacements.is_empty() { 215 always!(
229 log::error!( 216 fn_param_replacements.is_empty(),
230 "Replacements ({:?}) were generated for a function parameters which had no parameters list: {:?}", 217 "Replacements ({:?}) were generated for a function parameters which had no parameters list: {:?}",
231 fn_param_replacements, fn_src 218 fn_param_replacements,
232 ); 219 fn_src
233 } 220 );
234 return; 221 return;
235 } 222 }
236 }; 223 };
@@ -240,23 +227,25 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
240 // actual params list, but just some of them (ones that named correctly) are skipped. 227 // actual params list, but just some of them (ones that named correctly) are skipped.
241 let ast_ptr: ast::Name = loop { 228 let ast_ptr: ast::Name = loop {
242 match fn_params_iter.next() { 229 match fn_params_iter.next() {
243 Some(element) 230 Some(element) => {
244 if pat_equals_to_name(element.pat(), &param_to_rename.current_name) => 231 if let Some(ast::Pat::IdentPat(pat)) = element.pat() {
245 { 232 if pat.to_string() == param_to_rename.current_name.to_string() {
246 if let ast::Pat::IdentPat(pat) = element.pat().unwrap() { 233 if let Some(name) = pat.name() {
247 break pat.name().unwrap(); 234 break name;
248 } else { 235 }
249 // This is critical. If we consider this parameter the expected one, 236 // This is critical. If we consider this parameter the expected one,
250 // it **must** have a name. 237 // it **must** have a name.
251 panic!( 238 never!(
252 "Pattern {:?} equals to expected replacement {:?}, but has no name", 239 "Pattern {:?} equals to expected replacement {:?}, but has no name",
253 element, param_to_rename 240 element,
254 ); 241 param_to_rename
242 );
243 return;
244 }
255 } 245 }
256 } 246 }
257 Some(_) => {}
258 None => { 247 None => {
259 log::error!( 248 never!(
260 "Replacement ({:?}) was generated for a function parameter which was not found: {:?}", 249 "Replacement ({:?}) was generated for a function parameter which was not found: {:?}",
261 param_to_rename, fn_src 250 param_to_rename, fn_src
262 ); 251 );
@@ -267,7 +256,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
267 256
268 let diagnostic = IncorrectCase { 257 let diagnostic = IncorrectCase {
269 file: fn_src.file_id, 258 file: fn_src.file_id,
270 ident_type: "Argument".to_string(), 259 ident_type: IdentType::Argument,
271 ident: AstPtr::new(&ast_ptr).into(), 260 ident: AstPtr::new(&ast_ptr).into(),
272 expected_case: param_to_rename.expected_case, 261 expected_case: param_to_rename.expected_case,
273 ident_text: param_to_rename.current_name.to_string(), 262 ident_text: param_to_rename.current_name.to_string(),
@@ -309,8 +298,8 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
309 // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, 298 // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
310 // because e.g. match arms are patterns as well. 299 // because e.g. match arms are patterns as well.
311 // In other words, we check that it's a named variable binding. 300 // In other words, we check that it's a named variable binding.
312 let is_binding = ast::LetStmt::cast(parent.clone()).is_some() 301 let is_binding = ast::LetStmt::can_cast(parent.kind())
313 || (ast::MatchArm::cast(parent).is_some() 302 || (ast::MatchArm::can_cast(parent.kind())
314 && ident_pat.at_token().is_some()); 303 && ident_pat.at_token().is_some());
315 if !is_binding { 304 if !is_binding {
316 // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. 305 // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
@@ -319,7 +308,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
319 308
320 let diagnostic = IncorrectCase { 309 let diagnostic = IncorrectCase {
321 file: source_ptr.file_id, 310 file: source_ptr.file_id,
322 ident_type: "Variable".to_string(), 311 ident_type: IdentType::Variable,
323 ident: AstPtr::new(&name_ast).into(), 312 ident: AstPtr::new(&name_ast).into(),
324 expected_case: replacement.expected_case, 313 expected_case: replacement.expected_case,
325 ident_text: replacement.current_name.to_string(), 314 ident_text: replacement.current_name.to_string(),
@@ -341,17 +330,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
341 330
342 // Check the structure name. 331 // Check the structure name.
343 let struct_name = data.name.to_string(); 332 let struct_name = data.name.to_string();
344 let struct_name_replacement = if let Some(new_name) = to_camel_case(&struct_name) { 333 let struct_name_replacement = if !non_camel_case_allowed {
345 let replacement = Replacement { 334 to_camel_case(&struct_name).map(|new_name| Replacement {
346 current_name: data.name.clone(), 335 current_name: data.name.clone(),
347 suggested_text: new_name, 336 suggested_text: new_name,
348 expected_case: CaseType::UpperCamelCase, 337 expected_case: CaseType::UpperCamelCase,
349 }; 338 })
350 if non_camel_case_allowed {
351 None
352 } else {
353 Some(replacement)
354 }
355 } else { 339 } else {
356 None 340 None
357 }; 341 };
@@ -403,8 +387,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
403 let ast_ptr = match struct_src.value.name() { 387 let ast_ptr = match struct_src.value.name() {
404 Some(name) => name, 388 Some(name) => name,
405 None => { 389 None => {
406 // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic. 390 never!(
407 log::error!(
408 "Replacement ({:?}) was generated for a structure without a name: {:?}", 391 "Replacement ({:?}) was generated for a structure without a name: {:?}",
409 replacement, 392 replacement,
410 struct_src 393 struct_src
@@ -415,7 +398,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
415 398
416 let diagnostic = IncorrectCase { 399 let diagnostic = IncorrectCase {
417 file: struct_src.file_id, 400 file: struct_src.file_id,
418 ident_type: "Structure".to_string(), 401 ident_type: IdentType::Structure,
419 ident: AstPtr::new(&ast_ptr).into(), 402 ident: AstPtr::new(&ast_ptr).into(),
420 expected_case: replacement.expected_case, 403 expected_case: replacement.expected_case,
421 ident_text: replacement.current_name.to_string(), 404 ident_text: replacement.current_name.to_string(),
@@ -428,12 +411,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
428 let struct_fields_list = match struct_src.value.field_list() { 411 let struct_fields_list = match struct_src.value.field_list() {
429 Some(ast::FieldList::RecordFieldList(fields)) => fields, 412 Some(ast::FieldList::RecordFieldList(fields)) => fields,
430 _ => { 413 _ => {
431 if !struct_fields_replacements.is_empty() { 414 always!(
432 log::error!( 415 struct_fields_replacements.is_empty(),
433 "Replacements ({:?}) were generated for a structure fields which had no fields list: {:?}", 416 "Replacements ({:?}) were generated for a structure fields which had no fields list: {:?}",
434 struct_fields_replacements, struct_src 417 struct_fields_replacements,
435 ); 418 struct_src
436 } 419 );
437 return; 420 return;
438 } 421 }
439 }; 422 };
@@ -442,13 +425,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
442 // We assume that parameters in replacement are in the same order as in the 425 // We assume that parameters in replacement are in the same order as in the
443 // actual params list, but just some of them (ones that named correctly) are skipped. 426 // actual params list, but just some of them (ones that named correctly) are skipped.
444 let ast_ptr = loop { 427 let ast_ptr = loop {
445 match struct_fields_iter.next() { 428 match struct_fields_iter.next().and_then(|field| field.name()) {
446 Some(element) if names_equal(element.name(), &field_to_rename.current_name) => { 429 Some(field_name) => {
447 break element.name().unwrap() 430 if field_name.as_name() == field_to_rename.current_name {
431 break field_name;
432 }
448 } 433 }
449 Some(_) => {}
450 None => { 434 None => {
451 log::error!( 435 never!(
452 "Replacement ({:?}) was generated for a structure field which was not found: {:?}", 436 "Replacement ({:?}) was generated for a structure field which was not found: {:?}",
453 field_to_rename, struct_src 437 field_to_rename, struct_src
454 ); 438 );
@@ -459,7 +443,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
459 443
460 let diagnostic = IncorrectCase { 444 let diagnostic = IncorrectCase {
461 file: struct_src.file_id, 445 file: struct_src.file_id,
462 ident_type: "Field".to_string(), 446 ident_type: IdentType::Field,
463 ident: AstPtr::new(&ast_ptr).into(), 447 ident: AstPtr::new(&ast_ptr).into(),
464 expected_case: field_to_rename.expected_case, 448 expected_case: field_to_rename.expected_case,
465 ident_text: field_to_rename.current_name.to_string(), 449 ident_text: field_to_rename.current_name.to_string(),
@@ -480,31 +464,24 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
480 464
481 // Check the enum name. 465 // Check the enum name.
482 let enum_name = data.name.to_string(); 466 let enum_name = data.name.to_string();
483 let enum_name_replacement = if let Some(new_name) = to_camel_case(&enum_name) { 467 let enum_name_replacement = to_camel_case(&enum_name).map(|new_name| Replacement {
484 let replacement = Replacement { 468 current_name: data.name.clone(),
485 current_name: data.name.clone(), 469 suggested_text: new_name,
486 suggested_text: new_name, 470 expected_case: CaseType::UpperCamelCase,
487 expected_case: CaseType::UpperCamelCase, 471 });
488 };
489 Some(replacement)
490 } else {
491 None
492 };
493 472
494 // Check the field names. 473 // Check the field names.
495 let mut enum_fields_replacements = Vec::new(); 474 let enum_fields_replacements = data
496 475 .variants
497 for (_, variant) in data.variants.iter() { 476 .iter()
498 let variant_name = variant.name.to_string(); 477 .filter_map(|(_, variant)| {
499 if let Some(new_name) = to_camel_case(&variant_name) { 478 Some(Replacement {
500 let replacement = Replacement {
501 current_name: variant.name.clone(), 479 current_name: variant.name.clone(),
502 suggested_text: new_name, 480 suggested_text: to_camel_case(&variant.name.to_string())?,
503 expected_case: CaseType::UpperCamelCase, 481 expected_case: CaseType::UpperCamelCase,
504 }; 482 })
505 enum_fields_replacements.push(replacement); 483 })
506 } 484 .collect();
507 }
508 485
509 // If there is at least one element to spawn a warning on, go to the source map and generate a warning. 486 // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
510 self.create_incorrect_case_diagnostic_for_enum( 487 self.create_incorrect_case_diagnostic_for_enum(
@@ -534,8 +511,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
534 let ast_ptr = match enum_src.value.name() { 511 let ast_ptr = match enum_src.value.name() {
535 Some(name) => name, 512 Some(name) => name,
536 None => { 513 None => {
537 // We don't want rust-analyzer to panic over this, but it is definitely some kind of error in the logic. 514 never!(
538 log::error!(
539 "Replacement ({:?}) was generated for a enum without a name: {:?}", 515 "Replacement ({:?}) was generated for a enum without a name: {:?}",
540 replacement, 516 replacement,
541 enum_src 517 enum_src
@@ -546,7 +522,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
546 522
547 let diagnostic = IncorrectCase { 523 let diagnostic = IncorrectCase {
548 file: enum_src.file_id, 524 file: enum_src.file_id,
549 ident_type: "Enum".to_string(), 525 ident_type: IdentType::Enum,
550 ident: AstPtr::new(&ast_ptr).into(), 526 ident: AstPtr::new(&ast_ptr).into(),
551 expected_case: replacement.expected_case, 527 expected_case: replacement.expected_case,
552 ident_text: replacement.current_name.to_string(), 528 ident_text: replacement.current_name.to_string(),
@@ -559,12 +535,12 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
559 let enum_variants_list = match enum_src.value.variant_list() { 535 let enum_variants_list = match enum_src.value.variant_list() {
560 Some(variants) => variants, 536 Some(variants) => variants,
561 _ => { 537 _ => {
562 if !enum_variants_replacements.is_empty() { 538 always!(
563 log::error!( 539 enum_variants_replacements.is_empty(),
564 "Replacements ({:?}) were generated for a enum variants which had no fields list: {:?}", 540 "Replacements ({:?}) were generated for a enum variants which had no fields list: {:?}",
565 enum_variants_replacements, enum_src 541 enum_variants_replacements,
566 ); 542 enum_src
567 } 543 );
568 return; 544 return;
569 } 545 }
570 }; 546 };
@@ -573,15 +549,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
573 // We assume that parameters in replacement are in the same order as in the 549 // We assume that parameters in replacement are in the same order as in the
574 // actual params list, but just some of them (ones that named correctly) are skipped. 550 // actual params list, but just some of them (ones that named correctly) are skipped.
575 let ast_ptr = loop { 551 let ast_ptr = loop {
576 match enum_variants_iter.next() { 552 match enum_variants_iter.next().and_then(|v| v.name()) {
577 Some(variant) 553 Some(variant_name) => {
578 if names_equal(variant.name(), &variant_to_rename.current_name) => 554 if variant_name.as_name() == variant_to_rename.current_name {
579 { 555 break variant_name;
580 break variant.name().unwrap() 556 }
581 } 557 }
582 Some(_) => {}
583 None => { 558 None => {
584 log::error!( 559 never!(
585 "Replacement ({:?}) was generated for a enum variant which was not found: {:?}", 560 "Replacement ({:?}) was generated for a enum variant which was not found: {:?}",
586 variant_to_rename, enum_src 561 variant_to_rename, enum_src
587 ); 562 );
@@ -592,7 +567,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
592 567
593 let diagnostic = IncorrectCase { 568 let diagnostic = IncorrectCase {
594 file: enum_src.file_id, 569 file: enum_src.file_id,
595 ident_type: "Variant".to_string(), 570 ident_type: IdentType::Variant,
596 ident: AstPtr::new(&ast_ptr).into(), 571 ident: AstPtr::new(&ast_ptr).into(),
597 expected_case: variant_to_rename.expected_case, 572 expected_case: variant_to_rename.expected_case,
598 ident_text: variant_to_rename.current_name.to_string(), 573 ident_text: variant_to_rename.current_name.to_string(),
@@ -637,7 +612,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
637 612
638 let diagnostic = IncorrectCase { 613 let diagnostic = IncorrectCase {
639 file: const_src.file_id, 614 file: const_src.file_id,
640 ident_type: "Constant".to_string(), 615 ident_type: IdentType::Constant,
641 ident: AstPtr::new(&ast_ptr).into(), 616 ident: AstPtr::new(&ast_ptr).into(),
642 expected_case: replacement.expected_case, 617 expected_case: replacement.expected_case,
643 ident_text: replacement.current_name.to_string(), 618 ident_text: replacement.current_name.to_string(),
@@ -685,7 +660,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
685 660
686 let diagnostic = IncorrectCase { 661 let diagnostic = IncorrectCase {
687 file: static_src.file_id, 662 file: static_src.file_id,
688 ident_type: "Static variable".to_string(), 663 ident_type: IdentType::StaticVariable,
689 ident: AstPtr::new(&ast_ptr).into(), 664 ident: AstPtr::new(&ast_ptr).into(),
690 expected_case: replacement.expected_case, 665 expected_case: replacement.expected_case,
691 ident_text: replacement.current_name.to_string(), 666 ident_text: replacement.current_name.to_string(),
@@ -696,22 +671,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
696 } 671 }
697} 672}
698 673
699fn names_equal(left: Option<ast::Name>, right: &Name) -> bool {
700 if let Some(left) = left {
701 &left.as_name() == right
702 } else {
703 false
704 }
705}
706
707fn pat_equals_to_name(pat: Option<ast::Pat>, name: &Name) -> bool {
708 if let Some(ast::Pat::IdentPat(ident)) = pat {
709 ident.to_string() == name.to_string()
710 } else {
711 false
712 }
713}
714
715#[cfg(test)] 674#[cfg(test)]
716mod tests { 675mod tests {
717 use test_utils::mark; 676 use test_utils::mark;
diff --git a/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs b/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
index 14e4d92f0..3ab36caf2 100644
--- a/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
@@ -5,7 +5,7 @@
5// from file /compiler/rustc_lint/src/nonstandard_style.rs 5// from file /compiler/rustc_lint/src/nonstandard_style.rs
6 6
7/// Converts an identifier to an UpperCamelCase form. 7/// Converts an identifier to an UpperCamelCase form.
8/// Returns `None` if the string is already is UpperCamelCase. 8/// Returns `None` if the string is already in UpperCamelCase.
9pub(crate) fn to_camel_case(ident: &str) -> Option<String> { 9pub(crate) fn to_camel_case(ident: &str) -> Option<String> {
10 if is_camel_case(ident) { 10 if is_camel_case(ident) {
11 return None; 11 return None;
@@ -17,7 +17,7 @@ pub(crate) fn to_camel_case(ident: &str) -> Option<String> {
17 .split('_') 17 .split('_')
18 .filter(|component| !component.is_empty()) 18 .filter(|component| !component.is_empty())
19 .map(|component| { 19 .map(|component| {
20 let mut camel_cased_component = String::new(); 20 let mut camel_cased_component = String::with_capacity(component.len());
21 21
22 let mut new_word = true; 22 let mut new_word = true;
23 let mut prev_is_lower_case = true; 23 let mut prev_is_lower_case = true;
@@ -30,9 +30,9 @@ pub(crate) fn to_camel_case(ident: &str) -> Option<String> {
30 } 30 }
31 31
32 if new_word { 32 if new_word {
33 camel_cased_component.push_str(&c.to_uppercase().to_string()); 33 camel_cased_component.extend(c.to_uppercase());
34 } else { 34 } else {
35 camel_cased_component.push_str(&c.to_lowercase().to_string()); 35 camel_cased_component.extend(c.to_lowercase());
36 } 36 }
37 37
38 prev_is_lower_case = c.is_lowercase(); 38 prev_is_lower_case = c.is_lowercase();
@@ -41,16 +41,16 @@ pub(crate) fn to_camel_case(ident: &str) -> Option<String> {
41 41
42 camel_cased_component 42 camel_cased_component
43 }) 43 })
44 .fold((String::new(), None), |(acc, prev): (String, Option<String>), next| { 44 .fold((String::new(), None), |(acc, prev): (_, Option<String>), next| {
45 // separate two components with an underscore if their boundary cannot 45 // separate two components with an underscore if their boundary cannot
46 // be distinguished using a uppercase/lowercase case distinction 46 // be distinguished using a uppercase/lowercase case distinction
47 let join = if let Some(prev) = prev { 47 let join = prev
48 let l = prev.chars().last().unwrap(); 48 .and_then(|prev| {
49 let f = next.chars().next().unwrap(); 49 let f = next.chars().next()?;
50 !char_has_case(l) && !char_has_case(f) 50 let l = prev.chars().last()?;
51 } else { 51 Some(!char_has_case(l) && !char_has_case(f))
52 false 52 })
53 }; 53 .unwrap_or(false);
54 (acc + if join { "_" } else { "" } + &next, Some(next)) 54 (acc + if join { "_" } else { "" } + &next, Some(next))
55 }) 55 })
56 .0; 56 .0;
@@ -92,14 +92,12 @@ fn is_camel_case(name: &str) -> bool {
92 let mut fst = None; 92 let mut fst = None;
93 // start with a non-lowercase letter rather than non-uppercase 93 // start with a non-lowercase letter rather than non-uppercase
94 // ones (some scripts don't have a concept of upper/lowercase) 94 // ones (some scripts don't have a concept of upper/lowercase)
95 !name.chars().next().unwrap().is_lowercase() 95 name.chars().next().map_or(true, |c| !c.is_lowercase())
96 && !name.contains("__") 96 && !name.contains("__")
97 && !name.chars().any(|snd| { 97 && !name.chars().any(|snd| {
98 let ret = match (fst, snd) { 98 let ret = match fst {
99 (None, _) => false, 99 None => false,
100 (Some(fst), snd) => { 100 Some(fst) => char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_',
101 char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_'
102 }
103 }; 101 };
104 fst = Some(snd); 102 fst = Some(snd);
105 103
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 107417c27..66a88e2b6 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -2,8 +2,10 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{expr::Statement, path::path, resolver::HasResolver, AdtId, DefWithBodyId}; 5use hir_def::{
6use hir_expand::diagnostics::DiagnosticSink; 6 expr::Statement, path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId,
7};
8use hir_expand::{diagnostics::DiagnosticSink, name};
7use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
8use syntax::{ast, AstPtr}; 10use syntax::{ast, AstPtr};
9 11
@@ -15,7 +17,7 @@ use crate::{
15 MissingPatFields, RemoveThisSemicolon, 17 MissingPatFields, RemoveThisSemicolon,
16 }, 18 },
17 utils::variant_data, 19 utils::variant_data,
18 ApplicationTy, InferenceResult, Ty, TypeCtor, 20 InferenceResult, Ty,
19}; 21};
20 22
21pub(crate) use hir_def::{ 23pub(crate) use hir_def::{
@@ -24,6 +26,8 @@ pub(crate) use hir_def::{
24 LocalFieldId, VariantId, 26 LocalFieldId, VariantId,
25}; 27};
26 28
29use super::ReplaceFilterMapNextWithFindMap;
30
27pub(super) struct ExprValidator<'a, 'b: 'a> { 31pub(super) struct ExprValidator<'a, 'b: 'a> {
28 owner: DefWithBodyId, 32 owner: DefWithBodyId,
29 infer: Arc<InferenceResult>, 33 infer: Arc<InferenceResult>,
@@ -40,6 +44,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
40 } 44 }
41 45
42 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { 46 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
47 self.check_for_filter_map_next(db);
48
43 let body = db.body(self.owner.into()); 49 let body = db.body(self.owner.into());
44 50
45 for (id, expr) in body.exprs.iter() { 51 for (id, expr) in body.exprs.iter() {
@@ -150,20 +156,76 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
150 } 156 }
151 } 157 }
152 158
153 fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> { 159 fn check_for_filter_map_next(&mut self, db: &dyn HirDatabase) {
160 // Find the FunctionIds for Iterator::filter_map and Iterator::next
161 let iterator_path = path![core::iter::Iterator];
162 let resolver = self.owner.resolver(db.upcast());
163 let iterator_trait_id = match resolver.resolve_known_trait(db.upcast(), &iterator_path) {
164 Some(id) => id,
165 None => return,
166 };
167 let iterator_trait_items = &db.trait_data(iterator_trait_id).items;
168 let filter_map_function_id =
169 match iterator_trait_items.iter().find(|item| item.0 == name![filter_map]) {
170 Some((_, AssocItemId::FunctionId(id))) => id,
171 _ => return,
172 };
173 let next_function_id = match iterator_trait_items.iter().find(|item| item.0 == name![next])
174 {
175 Some((_, AssocItemId::FunctionId(id))) => id,
176 _ => return,
177 };
178
179 // Search function body for instances of .filter_map(..).next()
180 let body = db.body(self.owner.into());
181 let mut prev = None;
182 for (id, expr) in body.exprs.iter() {
183 if let Expr::MethodCall { receiver, .. } = expr {
184 let function_id = match self.infer.method_resolution(id) {
185 Some(id) => id,
186 None => continue,
187 };
188
189 if function_id == *filter_map_function_id {
190 prev = Some(id);
191 continue;
192 }
193
194 if function_id == *next_function_id {
195 if let Some(filter_map_id) = prev {
196 if *receiver == filter_map_id {
197 let (_, source_map) = db.body_with_source_map(self.owner.into());
198 if let Ok(next_source_ptr) = source_map.expr_syntax(id) {
199 self.sink.push(ReplaceFilterMapNextWithFindMap {
200 file: next_source_ptr.file_id,
201 next_expr: next_source_ptr.value,
202 });
203 }
204 }
205 }
206 }
207 }
208 prev = None;
209 }
210 }
211
212 fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) {
154 // Check that the number of arguments matches the number of parameters. 213 // Check that the number of arguments matches the number of parameters.
155 214
156 // FIXME: Due to shortcomings in the current type system implementation, only emit this 215 // FIXME: Due to shortcomings in the current type system implementation, only emit this
157 // diagnostic if there are no type mismatches in the containing function. 216 // diagnostic if there are no type mismatches in the containing function.
158 if self.infer.type_mismatches.iter().next().is_some() { 217 if self.infer.type_mismatches.iter().next().is_some() {
159 return None; 218 return;
160 } 219 }
161 220
162 let is_method_call = matches!(expr, Expr::MethodCall { .. }); 221 let is_method_call = matches!(expr, Expr::MethodCall { .. });
163 let (sig, args) = match expr { 222 let (sig, args) = match expr {
164 Expr::Call { callee, args } => { 223 Expr::Call { callee, args } => {
165 let callee = &self.infer.type_of_expr[*callee]; 224 let callee = &self.infer.type_of_expr[*callee];
166 let sig = callee.callable_sig(db)?; 225 let sig = match callee.callable_sig(db) {
226 Some(sig) => sig,
227 None => return,
228 };
167 (sig, args.clone()) 229 (sig, args.clone())
168 } 230 }
169 Expr::MethodCall { receiver, args, .. } => { 231 Expr::MethodCall { receiver, args, .. } => {
@@ -175,22 +237,25 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
175 // if the receiver is of unknown type, it's very likely we 237 // if the receiver is of unknown type, it's very likely we
176 // don't know enough to correctly resolve the method call. 238 // don't know enough to correctly resolve the method call.
177 // This is kind of a band-aid for #6975. 239 // This is kind of a band-aid for #6975.
178 return None; 240 return;
179 } 241 }
180 242
181 // FIXME: note that we erase information about substs here. This 243 // FIXME: note that we erase information about substs here. This
182 // is not right, but, luckily, doesn't matter as we care only 244 // is not right, but, luckily, doesn't matter as we care only
183 // about the number of params 245 // about the number of params
184 let callee = self.infer.method_resolution(call_id)?; 246 let callee = match self.infer.method_resolution(call_id) {
247 Some(callee) => callee,
248 None => return,
249 };
185 let sig = db.callable_item_signature(callee.into()).value; 250 let sig = db.callable_item_signature(callee.into()).value;
186 251
187 (sig, args) 252 (sig, args)
188 } 253 }
189 _ => return None, 254 _ => return,
190 }; 255 };
191 256
192 if sig.is_varargs { 257 if sig.is_varargs {
193 return None; 258 return;
194 } 259 }
195 260
196 let params = sig.params(); 261 let params = sig.params();
@@ -213,8 +278,6 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
213 }); 278 });
214 } 279 }
215 } 280 }
216
217 None
218 } 281 }
219 282
220 fn validate_match( 283 fn validate_match(
@@ -318,14 +381,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
318 _ => return, 381 _ => return,
319 }; 382 };
320 383
321 let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); 384 let (params, required) = match mismatch.expected {
322 let core_option_ctor = TypeCtor::Adt(AdtId::EnumId(core_option_enum)); 385 Ty::Adt(AdtId::EnumId(enum_id), ref parameters) if enum_id == core_result_enum => {
323
324 let (params, required) = match &mismatch.expected {
325 Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => {
326 (parameters, "Ok".to_string()) 386 (parameters, "Ok".to_string())
327 } 387 }
328 Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_option_ctor => { 388 Ty::Adt(AdtId::EnumId(enum_id), ref parameters) if enum_id == core_option_enum => {
329 (parameters, "Some".to_string()) 389 (parameters, "Some".to_string())
330 } 390 }
331 _ => return, 391 _ => return,
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index fbe760c39..86fee0050 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -227,7 +227,7 @@ use hir_def::{
227use la_arena::Idx; 227use la_arena::Idx;
228use smallvec::{smallvec, SmallVec}; 228use smallvec::{smallvec, SmallVec};
229 229
230use crate::{db::HirDatabase, ApplicationTy, InferenceResult, Ty, TypeCtor}; 230use crate::{db::HirDatabase, InferenceResult, Ty};
231 231
232#[derive(Debug, Clone, Copy)] 232#[derive(Debug, Clone, Copy)]
233/// Either a pattern from the source code being analyzed, represented as 233/// Either a pattern from the source code being analyzed, represented as
@@ -627,14 +627,12 @@ pub(super) fn is_useful(
627 // - `!` type 627 // - `!` type
628 // In those cases, no match arm is useful. 628 // In those cases, no match arm is useful.
629 match cx.infer[cx.match_expr].strip_references() { 629 match cx.infer[cx.match_expr].strip_references() {
630 Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) => { 630 Ty::Adt(AdtId::EnumId(enum_id), ..) => {
631 if cx.db.enum_data(*enum_id).variants.is_empty() { 631 if cx.db.enum_data(*enum_id).variants.is_empty() {
632 return Ok(Usefulness::NotUseful); 632 return Ok(Usefulness::NotUseful);
633 } 633 }
634 } 634 }
635 Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) => { 635 Ty::Never => return Ok(Usefulness::NotUseful),
636 return Ok(Usefulness::NotUseful);
637 }
638 _ => (), 636 _ => (),
639 } 637 }
640 638
@@ -1495,6 +1493,20 @@ fn main(f: Foo) {
1495 ); 1493 );
1496 } 1494 }
1497 1495
1496 #[test]
1497 fn internal_or() {
1498 check_diagnostics(
1499 r#"
1500fn main() {
1501 enum Either { A(bool), B }
1502 match Either::B {
1503 //^^^^^^^^^ Missing match arm
1504 Either::A(true | false) => (),
1505 }
1506}
1507"#,
1508 );
1509 }
1498 mod false_negatives { 1510 mod false_negatives {
1499 //! The implementation of match checking here is a work in progress. As we roll this out, we 1511 //! The implementation of match checking here is a work in progress. As we roll this out, we
1500 //! prefer false negatives to false positives (ideally there would be no false positives). This 1512 //! prefer false negatives to false positives (ideally there would be no false positives). This
@@ -1521,20 +1533,5 @@ fn main() {
1521"#, 1533"#,
1522 ); 1534 );
1523 } 1535 }
1524
1525 #[test]
1526 fn internal_or() {
1527 // We do not currently handle patterns with internal `or`s.
1528 check_diagnostics(
1529 r#"
1530fn main() {
1531 enum Either { A(bool), B }
1532 match Either::B {
1533 Either::A(true | false) => (),
1534 }
1535}
1536"#,
1537 );
1538 }
1539 } 1536 }
1540} 1537}
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index 6dc862826..e77a20fea 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -11,10 +11,7 @@ use hir_def::{
11}; 11};
12use hir_expand::diagnostics::DiagnosticSink; 12use hir_expand::diagnostics::DiagnosticSink;
13 13
14use crate::{ 14use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Ty};
15 db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDefId, ApplicationTy,
16 InferenceResult, Ty, TypeCtor,
17};
18 15
19pub(super) struct UnsafeValidator<'a, 'b: 'a> { 16pub(super) struct UnsafeValidator<'a, 'b: 'a> {
20 owner: DefWithBodyId, 17 owner: DefWithBodyId,
@@ -87,13 +84,8 @@ fn walk_unsafe(
87) { 84) {
88 let expr = &body.exprs[current]; 85 let expr = &body.exprs[current];
89 match expr { 86 match expr {
90 Expr::Call { callee, .. } => { 87 &Expr::Call { callee, .. } => {
91 let ty = &infer[*callee]; 88 if let Some(func) = infer[callee].as_fn_def() {
92 if let &Ty::Apply(ApplicationTy {
93 ctor: TypeCtor::FnDef(CallableDefId::FunctionId(func)),
94 ..
95 }) = ty
96 {
97 if db.function_data(func).is_unsafe { 89 if db.function_data(func).is_unsafe {
98 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 90 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
99 } 91 }
@@ -118,7 +110,7 @@ fn walk_unsafe(
118 } 110 }
119 } 111 }
120 Expr::UnaryOp { expr, op: UnaryOp::Deref } => { 112 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
121 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] { 113 if let Ty::Raw(..) = &infer[*expr] {
122 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 114 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
123 } 115 }
124 } 116 }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index d2f1b4014..d4a8b48e6 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -3,10 +3,12 @@
3use std::{borrow::Cow, fmt}; 3use std::{borrow::Cow, fmt};
4 4
5use crate::{ 5use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, 6 db::HirDatabase, primitive, utils::generics, AliasTy, CallableDefId, CallableSig,
7 Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 GenericPredicate, Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs,
8 TraitRef, Ty,
8}; 9};
9use arrayvec::ArrayVec; 10use arrayvec::ArrayVec;
11use chalk_ir::Mutability;
10use hir_def::{ 12use hir_def::{
11 db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, 13 db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId,
12 AssocContainerId, HasModule, Lookup, ModuleId, TraitId, 14 AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
@@ -234,39 +236,79 @@ impl HirDisplay for &Ty {
234 } 236 }
235} 237}
236 238
237impl HirDisplay for ApplicationTy { 239impl HirDisplay for ProjectionTy {
240 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
241 if f.should_truncate() {
242 return write!(f, "{}", TYPE_HINT_TRUNCATION);
243 }
244
245 let trait_ = f.db.trait_data(self.trait_(f.db));
246 let first_parameter = self.parameters[0].into_displayable(
247 f.db,
248 f.max_size,
249 f.omit_verbose_types,
250 f.display_target,
251 );
252 write!(f, "<{} as {}", first_parameter, trait_.name)?;
253 if self.parameters.len() > 1 {
254 write!(f, "<")?;
255 f.write_joined(&self.parameters[1..], ", ")?;
256 write!(f, ">")?;
257 }
258 write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?;
259 Ok(())
260 }
261}
262
263impl HirDisplay for Ty {
238 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 264 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
239 if f.should_truncate() { 265 if f.should_truncate() {
240 return write!(f, "{}", TYPE_HINT_TRUNCATION); 266 return write!(f, "{}", TYPE_HINT_TRUNCATION);
241 } 267 }
242 268
243 match self.ctor { 269 match self {
244 TypeCtor::Bool => write!(f, "bool")?, 270 Ty::Never => write!(f, "!")?,
245 TypeCtor::Char => write!(f, "char")?, 271 Ty::Str => write!(f, "str")?,
246 TypeCtor::Int(t) => write!(f, "{}", t)?, 272 Ty::Scalar(Scalar::Bool) => write!(f, "bool")?,
247 TypeCtor::Float(t) => write!(f, "{}", t)?, 273 Ty::Scalar(Scalar::Char) => write!(f, "char")?,
248 TypeCtor::Str => write!(f, "str")?, 274 &Ty::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
249 TypeCtor::Slice => { 275 &Ty::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
250 let t = self.parameters.as_single(); 276 &Ty::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
277 Ty::Slice(parameters) => {
278 let t = parameters.as_single();
251 write!(f, "[")?; 279 write!(f, "[")?;
252 t.hir_fmt(f)?; 280 t.hir_fmt(f)?;
253 write!(f, "]")?; 281 write!(f, "]")?;
254 } 282 }
255 TypeCtor::Array => { 283 Ty::Array(parameters) => {
256 let t = self.parameters.as_single(); 284 let t = parameters.as_single();
257 write!(f, "[")?; 285 write!(f, "[")?;
258 t.hir_fmt(f)?; 286 t.hir_fmt(f)?;
259 write!(f, "; _]")?; 287 write!(f, "; _]")?;
260 } 288 }
261 TypeCtor::RawPtr(m) | TypeCtor::Ref(m) => { 289 Ty::Raw(m, parameters) | Ty::Ref(m, parameters) => {
262 let t = self.parameters.as_single(); 290 let t = parameters.as_single();
263 let ty_display = 291 let ty_display =
264 t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); 292 t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
265 293
266 if matches!(self.ctor, TypeCtor::RawPtr(_)) { 294 if matches!(self, Ty::Raw(..)) {
267 write!(f, "*{}", m.as_keyword_for_ptr())?; 295 write!(
296 f,
297 "*{}",
298 match m {
299 Mutability::Not => "const ",
300 Mutability::Mut => "mut ",
301 }
302 )?;
268 } else { 303 } else {
269 write!(f, "&{}", m.as_keyword_for_ref())?; 304 write!(
305 f,
306 "&{}",
307 match m {
308 Mutability::Not => "",
309 Mutability::Mut => "mut ",
310 }
311 )?;
270 } 312 }
271 313
272 let datas; 314 let datas;
@@ -274,10 +316,10 @@ impl HirDisplay for ApplicationTy {
274 Ty::Dyn(predicates) if predicates.len() > 1 => { 316 Ty::Dyn(predicates) if predicates.len() > 1 => {
275 Cow::Borrowed(predicates.as_ref()) 317 Cow::Borrowed(predicates.as_ref())
276 } 318 }
277 &Ty::Opaque(OpaqueTy { 319 &Ty::Alias(AliasTy::Opaque(OpaqueTy {
278 opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx), 320 opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx),
279 ref parameters, 321 ref parameters,
280 }) => { 322 })) => {
281 datas = 323 datas =
282 f.db.return_type_impl_traits(func).expect("impl trait id without data"); 324 f.db.return_type_impl_traits(func).expect("impl trait id without data");
283 let data = (*datas) 325 let data = (*datas)
@@ -304,25 +346,24 @@ impl HirDisplay for ApplicationTy {
304 write!(f, "{}", ty_display)?; 346 write!(f, "{}", ty_display)?;
305 } 347 }
306 } 348 }
307 TypeCtor::Never => write!(f, "!")?, 349 Ty::Tuple(_, substs) => {
308 TypeCtor::Tuple { .. } => { 350 if substs.len() == 1 {
309 let ts = &self.parameters;
310 if ts.len() == 1 {
311 write!(f, "(")?; 351 write!(f, "(")?;
312 ts[0].hir_fmt(f)?; 352 substs[0].hir_fmt(f)?;
313 write!(f, ",)")?; 353 write!(f, ",)")?;
314 } else { 354 } else {
315 write!(f, "(")?; 355 write!(f, "(")?;
316 f.write_joined(&*ts.0, ", ")?; 356 f.write_joined(&*substs.0, ", ")?;
317 write!(f, ")")?; 357 write!(f, ")")?;
318 } 358 }
319 } 359 }
320 TypeCtor::FnPtr { is_varargs, .. } => { 360 Ty::Function(fn_ptr) => {
321 let sig = FnSig::from_fn_ptr_substs(&self.parameters, is_varargs); 361 let sig = CallableSig::from_fn_ptr(fn_ptr);
322 sig.hir_fmt(f)?; 362 sig.hir_fmt(f)?;
323 } 363 }
324 TypeCtor::FnDef(def) => { 364 Ty::FnDef(def, parameters) => {
325 let sig = f.db.callable_item_signature(def).subst(&self.parameters); 365 let def = *def;
366 let sig = f.db.callable_item_signature(def).subst(parameters);
326 match def { 367 match def {
327 CallableDefId::FunctionId(ff) => { 368 CallableDefId::FunctionId(ff) => {
328 write!(f, "fn {}", f.db.function_data(ff).name)? 369 write!(f, "fn {}", f.db.function_data(ff).name)?
@@ -332,7 +373,7 @@ impl HirDisplay for ApplicationTy {
332 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? 373 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
333 } 374 }
334 }; 375 };
335 if self.parameters.len() > 0 { 376 if parameters.len() > 0 {
336 let generics = generics(f.db.upcast(), def.into()); 377 let generics = generics(f.db.upcast(), def.into());
337 let (parent_params, self_param, type_params, _impl_trait_params) = 378 let (parent_params, self_param, type_params, _impl_trait_params) =
338 generics.provenance_split(); 379 generics.provenance_split();
@@ -340,7 +381,7 @@ impl HirDisplay for ApplicationTy {
340 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? 381 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
341 if total_len > 0 { 382 if total_len > 0 {
342 write!(f, "<")?; 383 write!(f, "<")?;
343 f.write_joined(&self.parameters.0[..total_len], ", ")?; 384 f.write_joined(&parameters.0[..total_len], ", ")?;
344 write!(f, ">")?; 385 write!(f, ">")?;
345 } 386 }
346 } 387 }
@@ -359,10 +400,10 @@ impl HirDisplay for ApplicationTy {
359 write!(f, " -> {}", ret_display)?; 400 write!(f, " -> {}", ret_display)?;
360 } 401 }
361 } 402 }
362 TypeCtor::Adt(def_id) => { 403 Ty::Adt(def_id, parameters) => {
363 match f.display_target { 404 match f.display_target {
364 DisplayTarget::Diagnostics | DisplayTarget::Test => { 405 DisplayTarget::Diagnostics | DisplayTarget::Test => {
365 let name = match def_id { 406 let name = match *def_id {
366 AdtId::StructId(it) => f.db.struct_data(it).name.clone(), 407 AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
367 AdtId::UnionId(it) => f.db.union_data(it).name.clone(), 408 AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
368 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), 409 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
@@ -372,7 +413,7 @@ impl HirDisplay for ApplicationTy {
372 DisplayTarget::SourceCode { module_id } => { 413 DisplayTarget::SourceCode { module_id } => {
373 if let Some(path) = find_path::find_path( 414 if let Some(path) = find_path::find_path(
374 f.db.upcast(), 415 f.db.upcast(),
375 ItemInNs::Types(def_id.into()), 416 ItemInNs::Types((*def_id).into()),
376 module_id, 417 module_id,
377 ) { 418 ) {
378 write!(f, "{}", path)?; 419 write!(f, "{}", path)?;
@@ -384,19 +425,18 @@ impl HirDisplay for ApplicationTy {
384 } 425 }
385 } 426 }
386 427
387 if self.parameters.len() > 0 { 428 if parameters.len() > 0 {
388 let parameters_to_write = 429 let parameters_to_write =
389 if f.display_target.is_source_code() || f.omit_verbose_types() { 430 if f.display_target.is_source_code() || f.omit_verbose_types() {
390 match self 431 match self
391 .ctor
392 .as_generic_def() 432 .as_generic_def()
393 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 433 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
394 .filter(|defaults| !defaults.is_empty()) 434 .filter(|defaults| !defaults.is_empty())
395 { 435 {
396 None => self.parameters.0.as_ref(), 436 None => parameters.0.as_ref(),
397 Some(default_parameters) => { 437 Some(default_parameters) => {
398 let mut default_from = 0; 438 let mut default_from = 0;
399 for (i, parameter) in self.parameters.iter().enumerate() { 439 for (i, parameter) in parameters.iter().enumerate() {
400 match (parameter, default_parameters.get(i)) { 440 match (parameter, default_parameters.get(i)) {
401 (&Ty::Unknown, _) | (_, None) => { 441 (&Ty::Unknown, _) | (_, None) => {
402 default_from = i + 1; 442 default_from = i + 1;
@@ -404,18 +444,18 @@ impl HirDisplay for ApplicationTy {
404 (_, Some(default_parameter)) => { 444 (_, Some(default_parameter)) => {
405 let actual_default = default_parameter 445 let actual_default = default_parameter
406 .clone() 446 .clone()
407 .subst(&self.parameters.prefix(i)); 447 .subst(&parameters.prefix(i));
408 if parameter != &actual_default { 448 if parameter != &actual_default {
409 default_from = i + 1; 449 default_from = i + 1;
410 } 450 }
411 } 451 }
412 } 452 }
413 } 453 }
414 &self.parameters.0[0..default_from] 454 &parameters.0[0..default_from]
415 } 455 }
416 } 456 }
417 } else { 457 } else {
418 self.parameters.0.as_ref() 458 parameters.0.as_ref()
419 }; 459 };
420 if !parameters_to_write.is_empty() { 460 if !parameters_to_write.is_empty() {
421 write!(f, "<")?; 461 write!(f, "<")?;
@@ -424,62 +464,54 @@ impl HirDisplay for ApplicationTy {
424 } 464 }
425 } 465 }
426 } 466 }
427 TypeCtor::AssociatedType(type_alias) => { 467 Ty::AssociatedType(type_alias, parameters) => {
428 let trait_ = match type_alias.lookup(f.db.upcast()).container { 468 let trait_ = match type_alias.lookup(f.db.upcast()).container {
429 AssocContainerId::TraitId(it) => it, 469 AssocContainerId::TraitId(it) => it,
430 _ => panic!("not an associated type"), 470 _ => panic!("not an associated type"),
431 }; 471 };
432 let trait_ = f.db.trait_data(trait_); 472 let trait_ = f.db.trait_data(trait_);
433 let type_alias_data = f.db.type_alias_data(type_alias); 473 let type_alias_data = f.db.type_alias_data(*type_alias);
434 474
435 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types) 475 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
436 if f.display_target.is_test() { 476 if f.display_target.is_test() {
437 write!(f, "{}::{}", trait_.name, type_alias_data.name)?; 477 write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
438 if self.parameters.len() > 0 { 478 if parameters.len() > 0 {
439 write!(f, "<")?; 479 write!(f, "<")?;
440 f.write_joined(&*self.parameters.0, ", ")?; 480 f.write_joined(&*parameters.0, ", ")?;
441 write!(f, ">")?; 481 write!(f, ">")?;
442 } 482 }
443 } else { 483 } else {
444 let projection_ty = ProjectionTy { 484 let projection_ty =
445 associated_ty: type_alias, 485 ProjectionTy { associated_ty: *type_alias, parameters: parameters.clone() };
446 parameters: self.parameters.clone(),
447 };
448 486
449 projection_ty.hir_fmt(f)?; 487 projection_ty.hir_fmt(f)?;
450 } 488 }
451 } 489 }
452 TypeCtor::ForeignType(type_alias) => { 490 Ty::ForeignType(type_alias) => {
453 let type_alias = f.db.type_alias_data(type_alias); 491 let type_alias = f.db.type_alias_data(*type_alias);
454 write!(f, "{}", type_alias.name)?; 492 write!(f, "{}", type_alias.name)?;
455 if self.parameters.len() > 0 {
456 write!(f, "<")?;
457 f.write_joined(&*self.parameters.0, ", ")?;
458 write!(f, ">")?;
459 }
460 } 493 }
461 TypeCtor::OpaqueType(opaque_ty_id) => { 494 Ty::OpaqueType(opaque_ty_id, parameters) => {
462 match opaque_ty_id { 495 match opaque_ty_id {
463 OpaqueTyId::ReturnTypeImplTrait(func, idx) => { 496 &OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
464 let datas = 497 let datas =
465 f.db.return_type_impl_traits(func).expect("impl trait id without data"); 498 f.db.return_type_impl_traits(func).expect("impl trait id without data");
466 let data = (*datas) 499 let data = (*datas)
467 .as_ref() 500 .as_ref()
468 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 501 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
469 let bounds = data.subst(&self.parameters); 502 let bounds = data.subst(&parameters);
470 write!(f, "impl ")?; 503 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
471 write_bounds_like_dyn_trait(&bounds.value, f)?;
472 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution 504 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
473 } 505 }
474 OpaqueTyId::AsyncBlockTypeImplTrait(..) => { 506 OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
475 write!(f, "impl Future<Output = ")?; 507 write!(f, "impl Future<Output = ")?;
476 self.parameters[0].hir_fmt(f)?; 508 parameters[0].hir_fmt(f)?;
477 write!(f, ">")?; 509 write!(f, ">")?;
478 } 510 }
479 } 511 }
480 } 512 }
481 TypeCtor::Closure { .. } => { 513 Ty::Closure(.., substs) => {
482 let sig = self.parameters[0].callable_sig(f.db); 514 let sig = substs[0].callable_sig(f.db);
483 if let Some(sig) = sig { 515 if let Some(sig) = sig {
484 if sig.params().is_empty() { 516 if sig.params().is_empty() {
485 write!(f, "||")?; 517 write!(f, "||")?;
@@ -502,44 +534,6 @@ impl HirDisplay for ApplicationTy {
502 write!(f, "{{closure}}")?; 534 write!(f, "{{closure}}")?;
503 } 535 }
504 } 536 }
505 }
506 Ok(())
507 }
508}
509
510impl HirDisplay for ProjectionTy {
511 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
512 if f.should_truncate() {
513 return write!(f, "{}", TYPE_HINT_TRUNCATION);
514 }
515
516 let trait_ = f.db.trait_data(self.trait_(f.db));
517 let first_parameter = self.parameters[0].into_displayable(
518 f.db,
519 f.max_size,
520 f.omit_verbose_types,
521 f.display_target,
522 );
523 write!(f, "<{} as {}", first_parameter, trait_.name)?;
524 if self.parameters.len() > 1 {
525 write!(f, "<")?;
526 f.write_joined(&self.parameters[1..], ", ")?;
527 write!(f, ">")?;
528 }
529 write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?;
530 Ok(())
531 }
532}
533
534impl HirDisplay for Ty {
535 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
536 if f.should_truncate() {
537 return write!(f, "{}", TYPE_HINT_TRUNCATION);
538 }
539
540 match self {
541 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
542 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?,
543 Ty::Placeholder(id) => { 537 Ty::Placeholder(id) => {
544 let generics = generics(f.db.upcast(), id.parent); 538 let generics = generics(f.db.upcast(), id.parent);
545 let param_data = &generics.params.types[id.local_id]; 539 let param_data = &generics.params.types[id.local_id];
@@ -548,22 +542,22 @@ impl HirDisplay for Ty {
548 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? 542 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
549 } 543 }
550 TypeParamProvenance::ArgumentImplTrait => { 544 TypeParamProvenance::ArgumentImplTrait => {
551 write!(f, "impl ")?;
552 let bounds = f.db.generic_predicates_for_param(*id); 545 let bounds = f.db.generic_predicates_for_param(*id);
553 let substs = Substs::type_params_for_generics(&generics); 546 let substs = Substs::type_params_for_generics(&generics);
554 write_bounds_like_dyn_trait( 547 write_bounds_like_dyn_trait_with_prefix(
548 "impl",
555 &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(), 549 &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
556 f, 550 f,
557 )?; 551 )?;
558 } 552 }
559 } 553 }
560 } 554 }
561 Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, 555 Ty::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
562 Ty::Dyn(predicates) => { 556 Ty::Dyn(predicates) => {
563 write!(f, "dyn ")?; 557 write_bounds_like_dyn_trait_with_prefix("dyn", predicates, f)?;
564 write_bounds_like_dyn_trait(predicates, f)?;
565 } 558 }
566 Ty::Opaque(opaque_ty) => { 559 Ty::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
560 Ty::Alias(AliasTy::Opaque(opaque_ty)) => {
567 match opaque_ty.opaque_ty_id { 561 match opaque_ty.opaque_ty_id {
568 OpaqueTyId::ReturnTypeImplTrait(func, idx) => { 562 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
569 let datas = 563 let datas =
@@ -572,8 +566,7 @@ impl HirDisplay for Ty {
572 .as_ref() 566 .as_ref()
573 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 567 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
574 let bounds = data.subst(&opaque_ty.parameters); 568 let bounds = data.subst(&opaque_ty.parameters);
575 write!(f, "impl ")?; 569 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
576 write_bounds_like_dyn_trait(&bounds.value, f)?;
577 } 570 }
578 OpaqueTyId::AsyncBlockTypeImplTrait(..) => { 571 OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
579 write!(f, "{{async block}}")?; 572 write!(f, "{{async block}}")?;
@@ -588,13 +581,13 @@ impl HirDisplay for Ty {
588 } 581 }
589 write!(f, "{{unknown}}")?; 582 write!(f, "{{unknown}}")?;
590 } 583 }
591 Ty::Infer(..) => write!(f, "_")?, 584 Ty::InferenceVar(..) => write!(f, "_")?,
592 } 585 }
593 Ok(()) 586 Ok(())
594 } 587 }
595} 588}
596 589
597impl HirDisplay for FnSig { 590impl HirDisplay for CallableSig {
598 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 591 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
599 write!(f, "fn(")?; 592 write!(f, "fn(")?;
600 f.write_joined(self.params(), ", ")?; 593 f.write_joined(self.params(), ", ")?;
@@ -617,7 +610,7 @@ impl HirDisplay for FnSig {
617} 610}
618 611
619fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> { 612fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
620 let krate = trait_.lookup(db).container.module(db).krate; 613 let krate = trait_.lookup(db).container.module(db).krate();
621 let fn_traits = [ 614 let fn_traits = [
622 db.lang_item(krate, "fn".into()), 615 db.lang_item(krate, "fn".into()),
623 db.lang_item(krate, "fn_mut".into()), 616 db.lang_item(krate, "fn_mut".into()),
@@ -627,7 +620,21 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = Trai
627 ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait()) 620 ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
628} 621}
629 622
630pub fn write_bounds_like_dyn_trait( 623pub fn write_bounds_like_dyn_trait_with_prefix(
624 prefix: &str,
625 predicates: &[GenericPredicate],
626 f: &mut HirFormatter,
627) -> Result<(), HirDisplayError> {
628 write!(f, "{}", prefix)?;
629 if !predicates.is_empty() {
630 write!(f, " ")?;
631 write_bounds_like_dyn_trait(predicates, f)
632 } else {
633 Ok(())
634 }
635}
636
637fn write_bounds_like_dyn_trait(
631 predicates: &[GenericPredicate], 638 predicates: &[GenericPredicate],
632 f: &mut HirFormatter, 639 f: &mut HirFormatter,
633) -> Result<(), HirDisplayError> { 640) -> Result<(), HirDisplayError> {
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index d08867c70..4d771a91e 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -18,6 +18,7 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use chalk_ir::Mutability;
21use hir_def::{ 22use hir_def::{
22 body::Body, 23 body::Body,
23 data::{ConstData, FunctionData, StaticData}, 24 data::{ConstData, FunctionData, StaticData},
@@ -25,7 +26,7 @@ use hir_def::{
25 lang_item::LangItemTarget, 26 lang_item::LangItemTarget,
26 path::{path, Path}, 27 path::{path, Path},
27 resolver::{HasResolver, Resolver, TypeNs}, 28 resolver::{HasResolver, Resolver, TypeNs},
28 type_ref::{Mutability, TypeRef}, 29 type_ref::TypeRef,
29 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId, 30 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId,
30 TypeAliasId, VariantId, 31 TypeAliasId, VariantId,
31}; 32};
@@ -36,25 +37,15 @@ use stdx::impl_from;
36use syntax::SmolStr; 37use syntax::SmolStr;
37 38
38use super::{ 39use super::{
39 primitive::{FloatTy, IntTy},
40 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 40 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
41 InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 41 InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeWalk,
42}; 42};
43use crate::{ 43use crate::{
44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, AliasTy,
45}; 45};
46 46
47pub(crate) use unify::unify; 47pub(crate) use unify::unify;
48 48
49macro_rules! ty_app {
50 ($ctor:pat, $param:pat) => {
51 crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param })
52 };
53 ($ctor:pat) => {
54 ty_app!($ctor, _)
55 };
56}
57
58mod unify; 49mod unify;
59mod path; 50mod path;
60mod expr; 51mod expr;
@@ -97,7 +88,7 @@ impl BindingMode {
97 fn convert(annotation: BindingAnnotation) -> BindingMode { 88 fn convert(annotation: BindingAnnotation) -> BindingMode {
98 match annotation { 89 match annotation {
99 BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move, 90 BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
100 BindingAnnotation::Ref => BindingMode::Ref(Mutability::Shared), 91 BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
101 BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut), 92 BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
102 } 93 }
103 } 94 }
@@ -405,7 +396,7 @@ impl<'a> InferenceContext<'a> {
405 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 396 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
406 let ty = self.resolve_ty_as_possible(ty); 397 let ty = self.resolve_ty_as_possible(ty);
407 ty.fold(&mut |ty| match ty { 398 ty.fold(&mut |ty| match ty {
408 Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), 399 Ty::Alias(AliasTy::Projection(proj_ty)) => self.normalize_projection_ty(proj_ty),
409 _ => ty, 400 _ => ty,
410 }) 401 })
411 } 402 }
@@ -461,7 +452,7 @@ impl<'a> InferenceContext<'a> {
461 (ty, variant) 452 (ty, variant)
462 } 453 }
463 Some(1) => { 454 Some(1) => {
464 let segment = path.mod_path().segments.last().unwrap(); 455 let segment = path.mod_path().segments().last().unwrap();
465 // this could be an enum variant or associated type 456 // this could be an enum variant or associated type
466 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { 457 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
467 let enum_data = self.db.enum_data(enum_id); 458 let enum_data = self.db.enum_data(enum_id);
@@ -664,30 +655,17 @@ impl<'a> InferenceContext<'a> {
664/// two are used for inference of literal values (e.g. `100` could be one of 655/// two are used for inference of literal values (e.g. `100` could be one of
665/// several integer types). 656/// several integer types).
666#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 657#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
667pub enum InferTy { 658pub struct InferenceVar {
668 TypeVar(unify::TypeVarId), 659 index: u32,
669 IntVar(unify::TypeVarId),
670 FloatVar(unify::TypeVarId),
671 MaybeNeverTypeVar(unify::TypeVarId),
672} 660}
673 661
674impl InferTy { 662impl InferenceVar {
675 fn to_inner(self) -> unify::TypeVarId { 663 fn to_inner(self) -> unify::TypeVarId {
676 match self { 664 unify::TypeVarId(self.index)
677 InferTy::TypeVar(ty)
678 | InferTy::IntVar(ty)
679 | InferTy::FloatVar(ty)
680 | InferTy::MaybeNeverTypeVar(ty) => ty,
681 }
682 } 665 }
683 666
684 fn fallback_value(self) -> Ty { 667 fn from_inner(unify::TypeVarId(index): unify::TypeVarId) -> Self {
685 match self { 668 InferenceVar { index }
686 InferTy::TypeVar(..) => Ty::Unknown,
687 InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(IntTy::i32())),
688 InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(FloatTy::f64())),
689 InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never),
690 }
691 } 669 }
692} 670}
693 671
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 32c7c57cd..cf0a3add4 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -4,12 +4,13 @@
4//! 4//!
5//! See: https://doc.rust-lang.org/nomicon/coercions.html 5//! See: https://doc.rust-lang.org/nomicon/coercions.html
6 6
7use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; 7use chalk_ir::{Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget;
8use test_utils::mark; 9use test_utils::mark;
9 10
10use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; 11use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty};
11 12
12use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; 13use super::{InEnvironment, InferenceContext};
13 14
14impl<'a> InferenceContext<'a> { 15impl<'a> InferenceContext<'a> {
15 /// Unify two types, but may coerce the first one to the second one 16 /// Unify two types, but may coerce the first one to the second one
@@ -33,7 +34,7 @@ impl<'a> InferenceContext<'a> {
33 } else if self.coerce(ty2, ty1) { 34 } else if self.coerce(ty2, ty1) {
34 ty1.clone() 35 ty1.clone()
35 } else { 36 } else {
36 if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) { 37 if let (Ty::FnDef(..), Ty::FnDef(..)) = (ty1, ty2) {
37 mark::hit!(coerce_fn_reification); 38 mark::hit!(coerce_fn_reification);
38 // Special case: two function types. Try to coerce both to 39 // Special case: two function types. Try to coerce both to
39 // pointers to have a chance at getting a match. See 40 // pointers to have a chance at getting a match. See
@@ -53,12 +54,11 @@ impl<'a> InferenceContext<'a> {
53 fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { 54 fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool {
54 match (&from_ty, to_ty) { 55 match (&from_ty, to_ty) {
55 // Never type will make type variable to fallback to Never Type instead of Unknown. 56 // Never type will make type variable to fallback to Never Type instead of Unknown.
56 (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => { 57 (Ty::Never, Ty::InferenceVar(tv, TyVariableKind::General)) => {
57 let var = self.table.new_maybe_never_type_var(); 58 self.table.type_variable_table.set_diverging(*tv, true);
58 self.table.var_unification_table.union_value(*tv, TypeVarValue::Known(var));
59 return true; 59 return true;
60 } 60 }
61 (ty_app!(TypeCtor::Never), _) => return true, 61 (Ty::Never, _) => return true,
62 62
63 // Trivial cases, this should go after `never` check to 63 // Trivial cases, this should go after `never` check to
64 // avoid infer result type to be never 64 // avoid infer result type to be never
@@ -71,38 +71,33 @@ impl<'a> InferenceContext<'a> {
71 71
72 // Pointer weakening and function to pointer 72 // Pointer weakening and function to pointer
73 match (&mut from_ty, to_ty) { 73 match (&mut from_ty, to_ty) {
74 // `*mut T`, `&mut T, `&T`` -> `*const T` 74 // `*mut T` -> `*const T`
75 // `&mut T` -> `&T` 75 // `&mut T` -> `&T`
76 // `&mut T` -> `*mut T` 76 (Ty::Raw(m1, ..), Ty::Raw(m2 @ Mutability::Not, ..))
77 (ty_app!(c1@TypeCtor::RawPtr(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared))) 77 | (Ty::Ref(m1, ..), Ty::Ref(m2 @ Mutability::Not, ..)) => {
78 | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared))) 78 *m1 = *m2;
79 | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::Ref(Mutability::Shared))) 79 }
80 | (ty_app!(c1@TypeCtor::Ref(Mutability::Mut)), ty_app!(c2@TypeCtor::RawPtr(_))) => { 80 // `&T` -> `*const T`
81 *c1 = *c2; 81 // `&mut T` -> `*mut T`/`*const T`
82 (Ty::Ref(.., substs), &Ty::Raw(m2 @ Mutability::Not, ..))
83 | (Ty::Ref(Mutability::Mut, substs), &Ty::Raw(m2, ..)) => {
84 from_ty = Ty::Raw(m2, substs.clone());
82 } 85 }
83 86
84 // Illegal mutablity conversion 87 // Illegal mutability conversion
85 ( 88 (Ty::Raw(Mutability::Not, ..), Ty::Raw(Mutability::Mut, ..))
86 ty_app!(TypeCtor::RawPtr(Mutability::Shared)), 89 | (Ty::Ref(Mutability::Not, ..), Ty::Ref(Mutability::Mut, ..)) => return false,
87 ty_app!(TypeCtor::RawPtr(Mutability::Mut)),
88 )
89 | (
90 ty_app!(TypeCtor::Ref(Mutability::Shared)),
91 ty_app!(TypeCtor::Ref(Mutability::Mut)),
92 ) => return false,
93 90
94 // `{function_type}` -> `fn()` 91 // `{function_type}` -> `fn()`
95 (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => { 92 (Ty::FnDef(..), Ty::Function { .. }) => match from_ty.callable_sig(self.db) {
96 match from_ty.callable_sig(self.db) { 93 None => return false,
97 None => return false, 94 Some(sig) => {
98 Some(sig) => { 95 from_ty = Ty::fn_ptr(sig);
99 from_ty = Ty::fn_ptr(sig);
100 }
101 } 96 }
102 } 97 },
103 98
104 (ty_app!(TypeCtor::Closure { .. }, params), ty_app!(TypeCtor::FnPtr { .. })) => { 99 (Ty::Closure(.., substs), Ty::Function { .. }) => {
105 from_ty = params[0].clone(); 100 from_ty = substs[0].clone();
106 } 101 }
107 102
108 _ => {} 103 _ => {}
@@ -115,9 +110,7 @@ impl<'a> InferenceContext<'a> {
115 // Auto Deref if cannot coerce 110 // Auto Deref if cannot coerce
116 match (&from_ty, to_ty) { 111 match (&from_ty, to_ty) {
117 // FIXME: DerefMut 112 // FIXME: DerefMut
118 (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => { 113 (Ty::Ref(_, st1), Ty::Ref(_, st2)) => self.unify_autoderef_behind_ref(&st1[0], &st2[0]),
119 self.unify_autoderef_behind_ref(&st1[0], &st2[0])
120 }
121 114
122 // Otherwise, normal unify 115 // Otherwise, normal unify
123 _ => self.unify(&from_ty, to_ty), 116 _ => self.unify(&from_ty, to_ty),
@@ -178,17 +171,17 @@ impl<'a> InferenceContext<'a> {
178 }, 171 },
179 ) { 172 ) {
180 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); 173 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value);
181 match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) { 174 let from_ty = self.resolve_ty_shallow(&derefed_ty);
182 // Stop when constructor matches. 175 // Stop when constructor matches.
183 (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => { 176 if from_ty.equals_ctor(&to_ty) {
184 // It will not recurse to `coerce`. 177 // It will not recurse to `coerce`.
185 return self.table.unify_substs(st1, st2, 0); 178 return match (from_ty.substs(), to_ty.substs()) {
186 } 179 (Some(st1), Some(st2)) => self.table.unify_substs(st1, st2, 0),
187 _ => { 180 (None, None) => true,
188 if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) { 181 _ => false,
189 return true; 182 };
190 } 183 } else if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) {
191 } 184 return true;
192 } 185 }
193 } 186 }
194 187
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 9bf3b51b0..cf1f1038a 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -3,8 +3,8 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::{mem, sync::Arc}; 4use std::{mem, sync::Arc};
5 5
6use chalk_ir::{Mutability, TyVariableKind};
6use hir_def::{ 7use hir_def::{
7 builtin_type::Signedness,
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
10 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
@@ -15,11 +15,14 @@ use syntax::ast::RangeOp;
15use test_utils::mark; 15use test_utils::mark;
16 16
17use crate::{ 17use crate::{
18 autoderef, method_resolution, op, 18 autoderef,
19 lower::lower_to_chalk_mutability,
20 method_resolution, op,
21 primitive::{self, UintTy},
19 traits::{FnTrait, InEnvironment}, 22 traits::{FnTrait, InEnvironment},
20 utils::{generics, variant_data, Generics}, 23 utils::{generics, variant_data, Generics},
21 ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, OpaqueTyId, 24 Binders, CallableDefId, FnPointer, FnSig, Obligation, OpaqueTyId, Rawness, Scalar, Substs,
22 Rawness, Substs, TraitRef, Ty, TypeCtor, 25 TraitRef, Ty,
23}; 26};
24 27
25use super::{ 28use super::{
@@ -82,10 +85,7 @@ impl<'a> InferenceContext<'a> {
82 arg_tys.push(arg); 85 arg_tys.push(arg);
83 } 86 }
84 let parameters = param_builder.build(); 87 let parameters = param_builder.build();
85 let arg_ty = Ty::Apply(ApplicationTy { 88 let arg_ty = Ty::Tuple(num_args, parameters);
86 ctor: TypeCtor::Tuple { cardinality: num_args as u16 },
87 parameters,
88 });
89 let substs = 89 let substs =
90 Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); 90 Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
91 91
@@ -120,7 +120,7 @@ impl<'a> InferenceContext<'a> {
120 Expr::Missing => Ty::Unknown, 120 Expr::Missing => Ty::Unknown,
121 Expr::If { condition, then_branch, else_branch } => { 121 Expr::If { condition, then_branch, else_branch } => {
122 // if let is desugared to match, so this is always simple if 122 // if let is desugared to match, so this is always simple if
123 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 123 self.infer_expr(*condition, &Expectation::has_type(Ty::Scalar(Scalar::Bool)));
124 124
125 let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); 125 let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
126 let mut both_arms_diverge = Diverges::Always; 126 let mut both_arms_diverge = Diverges::Always;
@@ -137,24 +137,33 @@ impl<'a> InferenceContext<'a> {
137 137
138 self.coerce_merge_branch(&then_ty, &else_ty) 138 self.coerce_merge_branch(&then_ty, &else_ty)
139 } 139 }
140 Expr::Block { statements, tail, label } => match label { 140 Expr::Block { statements, tail, label, id: _ } => {
141 Some(_) => { 141 let old_resolver = mem::replace(
142 let break_ty = self.table.new_type_var(); 142 &mut self.resolver,
143 self.breakables.push(BreakableContext { 143 resolver_for_expr(self.db.upcast(), self.owner, tgt_expr),
144 may_break: false, 144 );
145 break_ty: break_ty.clone(), 145 let ty = match label {
146 label: label.map(|label| self.body[label].name.clone()), 146 Some(_) => {
147 }); 147 let break_ty = self.table.new_type_var();
148 let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty)); 148 self.breakables.push(BreakableContext {
149 let ctxt = self.breakables.pop().expect("breakable stack broken"); 149 may_break: false,
150 if ctxt.may_break { 150 break_ty: break_ty.clone(),
151 ctxt.break_ty 151 label: label.map(|label| self.body[label].name.clone()),
152 } else { 152 });
153 ty 153 let ty =
154 self.infer_block(statements, *tail, &Expectation::has_type(break_ty));
155 let ctxt = self.breakables.pop().expect("breakable stack broken");
156 if ctxt.may_break {
157 ctxt.break_ty
158 } else {
159 ty
160 }
154 } 161 }
155 } 162 None => self.infer_block(statements, *tail, expected),
156 None => self.infer_block(statements, *tail, expected), 163 };
157 }, 164 self.resolver = old_resolver;
165 ty
166 }
158 Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected), 167 Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
159 Expr::TryBlock { body } => { 168 Expr::TryBlock { body } => {
160 let _inner = self.infer_expr(*body, expected); 169 let _inner = self.infer_expr(*body, expected);
@@ -166,7 +175,7 @@ impl<'a> InferenceContext<'a> {
166 // existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType> 175 // existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
167 let inner_ty = self.infer_expr(*body, &Expectation::none()); 176 let inner_ty = self.infer_expr(*body, &Expectation::none());
168 let opaque_ty_id = OpaqueTyId::AsyncBlockTypeImplTrait(self.owner, *body); 177 let opaque_ty_id = OpaqueTyId::AsyncBlockTypeImplTrait(self.owner, *body);
169 Ty::apply_one(TypeCtor::OpaqueType(opaque_ty_id), inner_ty) 178 Ty::OpaqueType(opaque_ty_id, Substs::single(inner_ty))
170 } 179 }
171 Expr::Loop { body, label } => { 180 Expr::Loop { body, label } => {
172 self.breakables.push(BreakableContext { 181 self.breakables.push(BreakableContext {
@@ -184,7 +193,7 @@ impl<'a> InferenceContext<'a> {
184 if ctxt.may_break { 193 if ctxt.may_break {
185 ctxt.break_ty 194 ctxt.break_ty
186 } else { 195 } else {
187 Ty::simple(TypeCtor::Never) 196 Ty::Never
188 } 197 }
189 } 198 }
190 Expr::While { condition, body, label } => { 199 Expr::While { condition, body, label } => {
@@ -194,7 +203,7 @@ impl<'a> InferenceContext<'a> {
194 label: label.map(|label| self.body[label].name.clone()), 203 label: label.map(|label| self.body[label].name.clone()),
195 }); 204 });
196 // while let is desugared to a match loop, so this is always simple while 205 // while let is desugared to a match loop, so this is always simple while
197 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 206 self.infer_expr(*condition, &Expectation::has_type(Ty::Scalar(Scalar::Bool)));
198 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 207 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
199 let _ctxt = self.breakables.pop().expect("breakable stack broken"); 208 let _ctxt = self.breakables.pop().expect("breakable stack broken");
200 // the body may not run, so it diverging doesn't mean we diverge 209 // the body may not run, so it diverging doesn't mean we diverge
@@ -241,12 +250,12 @@ impl<'a> InferenceContext<'a> {
241 None => self.table.new_type_var(), 250 None => self.table.new_type_var(),
242 }; 251 };
243 sig_tys.push(ret_ty.clone()); 252 sig_tys.push(ret_ty.clone());
244 let sig_ty = Ty::apply( 253 let sig_ty = Ty::Function(FnPointer {
245 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false }, 254 num_args: sig_tys.len() - 1,
246 Substs(sig_tys.clone().into()), 255 sig: FnSig { variadic: false },
247 ); 256 substs: Substs(sig_tys.clone().into()),
248 let closure_ty = 257 });
249 Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); 258 let closure_ty = Ty::Closure(self.owner, tgt_expr, Substs::single(sig_ty));
250 259
251 // Eagerly try to relate the closure type with the expected 260 // Eagerly try to relate the closure type with the expected
252 // type, otherwise we often won't have enough information to 261 // type, otherwise we often won't have enough information to
@@ -297,11 +306,8 @@ impl<'a> InferenceContext<'a> {
297 Expr::Match { expr, arms } => { 306 Expr::Match { expr, arms } => {
298 let input_ty = self.infer_expr(*expr, &Expectation::none()); 307 let input_ty = self.infer_expr(*expr, &Expectation::none());
299 308
300 let mut result_ty = if arms.is_empty() { 309 let mut result_ty =
301 Ty::simple(TypeCtor::Never) 310 if arms.is_empty() { Ty::Never } else { self.table.new_type_var() };
302 } else {
303 self.table.new_type_var()
304 };
305 311
306 let matchee_diverges = self.diverges; 312 let matchee_diverges = self.diverges;
307 let mut all_arms_diverge = Diverges::Always; 313 let mut all_arms_diverge = Diverges::Always;
@@ -312,7 +318,7 @@ impl<'a> InferenceContext<'a> {
312 if let Some(guard_expr) = arm.guard { 318 if let Some(guard_expr) = arm.guard {
313 self.infer_expr( 319 self.infer_expr(
314 guard_expr, 320 guard_expr,
315 &Expectation::has_type(Ty::simple(TypeCtor::Bool)), 321 &Expectation::has_type(Ty::Scalar(Scalar::Bool)),
316 ); 322 );
317 } 323 }
318 324
@@ -330,7 +336,7 @@ impl<'a> InferenceContext<'a> {
330 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); 336 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
331 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) 337 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
332 } 338 }
333 Expr::Continue { .. } => Ty::simple(TypeCtor::Never), 339 Expr::Continue { .. } => Ty::Never,
334 Expr::Break { expr, label } => { 340 Expr::Break { expr, label } => {
335 let val_ty = if let Some(expr) = expr { 341 let val_ty = if let Some(expr) = expr {
336 self.infer_expr(*expr, &Expectation::none()) 342 self.infer_expr(*expr, &Expectation::none())
@@ -355,8 +361,7 @@ impl<'a> InferenceContext<'a> {
355 expr: tgt_expr, 361 expr: tgt_expr,
356 }); 362 });
357 } 363 }
358 364 Ty::Never
359 Ty::simple(TypeCtor::Never)
360 } 365 }
361 Expr::Return { expr } => { 366 Expr::Return { expr } => {
362 if let Some(expr) = expr { 367 if let Some(expr) = expr {
@@ -365,14 +370,14 @@ impl<'a> InferenceContext<'a> {
365 let unit = Ty::unit(); 370 let unit = Ty::unit();
366 self.coerce(&unit, &self.return_ty.clone()); 371 self.coerce(&unit, &self.return_ty.clone());
367 } 372 }
368 Ty::simple(TypeCtor::Never) 373 Ty::Never
369 } 374 }
370 Expr::Yield { expr } => { 375 Expr::Yield { expr } => {
371 // FIXME: track yield type for coercion 376 // FIXME: track yield type for coercion
372 if let Some(expr) = expr { 377 if let Some(expr) = expr {
373 self.infer_expr(*expr, &Expectation::none()); 378 self.infer_expr(*expr, &Expectation::none());
374 } 379 }
375 Ty::simple(TypeCtor::Never) 380 Ty::Never
376 } 381 }
377 Expr::RecordLit { path, fields, spread } => { 382 Expr::RecordLit { path, fields, spread } => {
378 let (ty, def_id) = self.resolve_variant(path.as_ref()); 383 let (ty, def_id) = self.resolve_variant(path.as_ref());
@@ -382,7 +387,7 @@ impl<'a> InferenceContext<'a> {
382 387
383 self.unify(&ty, &expected.ty); 388 self.unify(&ty, &expected.ty);
384 389
385 let substs = ty.substs().unwrap_or_else(Substs::empty); 390 let substs = ty.substs().cloned().unwrap_or_else(Substs::empty);
386 let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); 391 let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
387 let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it)); 392 let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it));
388 for (field_idx, field) in fields.iter().enumerate() { 393 for (field_idx, field) in fields.iter().enumerate() {
@@ -421,30 +426,23 @@ impl<'a> InferenceContext<'a> {
421 }, 426 },
422 ) 427 )
423 .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { 428 .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) {
424 Ty::Apply(a_ty) => match a_ty.ctor { 429 Ty::Tuple(_, substs) => {
425 TypeCtor::Tuple { .. } => name 430 name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned())
426 .as_tuple_index() 431 }
427 .and_then(|idx| a_ty.parameters.0.get(idx).cloned()), 432 Ty::Adt(AdtId::StructId(s), parameters) => {
428 TypeCtor::Adt(AdtId::StructId(s)) => { 433 self.db.struct_data(s).variant_data.field(name).map(|local_id| {
429 self.db.struct_data(s).variant_data.field(name).map(|local_id| { 434 let field = FieldId { parent: s.into(), local_id };
430 let field = FieldId { parent: s.into(), local_id }; 435 self.write_field_resolution(tgt_expr, field);
431 self.write_field_resolution(tgt_expr, field); 436 self.db.field_types(s.into())[field.local_id].clone().subst(&parameters)
432 self.db.field_types(s.into())[field.local_id] 437 })
433 .clone() 438 }
434 .subst(&a_ty.parameters) 439 Ty::Adt(AdtId::UnionId(u), parameters) => {
435 }) 440 self.db.union_data(u).variant_data.field(name).map(|local_id| {
436 } 441 let field = FieldId { parent: u.into(), local_id };
437 TypeCtor::Adt(AdtId::UnionId(u)) => { 442 self.write_field_resolution(tgt_expr, field);
438 self.db.union_data(u).variant_data.field(name).map(|local_id| { 443 self.db.field_types(u.into())[field.local_id].clone().subst(&parameters)
439 let field = FieldId { parent: u.into(), local_id }; 444 })
440 self.write_field_resolution(tgt_expr, field); 445 }
441 self.db.field_types(u.into())[field.local_id]
442 .clone()
443 .subst(&a_ty.parameters)
444 })
445 }
446 _ => None,
447 },
448 _ => None, 446 _ => None,
449 }) 447 })
450 .unwrap_or(Ty::Unknown); 448 .unwrap_or(Ty::Unknown);
@@ -466,10 +464,11 @@ impl<'a> InferenceContext<'a> {
466 cast_ty 464 cast_ty
467 } 465 }
468 Expr::Ref { expr, rawness, mutability } => { 466 Expr::Ref { expr, rawness, mutability } => {
467 let mutability = lower_to_chalk_mutability(*mutability);
469 let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = 468 let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) =
470 &expected.ty.as_reference_or_ptr() 469 &expected.ty.as_reference_or_ptr()
471 { 470 {
472 if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { 471 if *exp_mutability == Mutability::Mut && mutability == Mutability::Not {
473 // FIXME: throw type error - expected mut reference but found shared ref, 472 // FIXME: throw type error - expected mut reference but found shared ref,
474 // which cannot be coerced 473 // which cannot be coerced
475 } 474 }
@@ -482,16 +481,24 @@ impl<'a> InferenceContext<'a> {
482 Expectation::none() 481 Expectation::none()
483 }; 482 };
484 let inner_ty = self.infer_expr_inner(*expr, &expectation); 483 let inner_ty = self.infer_expr_inner(*expr, &expectation);
485 let ty = match rawness { 484 match rawness {
486 Rawness::RawPtr => TypeCtor::RawPtr(*mutability), 485 Rawness::RawPtr => Ty::Raw(mutability, Substs::single(inner_ty)),
487 Rawness::Ref => TypeCtor::Ref(*mutability), 486 Rawness::Ref => Ty::Ref(mutability, Substs::single(inner_ty)),
488 }; 487 }
489 Ty::apply_one(ty, inner_ty)
490 } 488 }
491 Expr::Box { expr } => { 489 Expr::Box { expr } => {
492 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 490 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
493 if let Some(box_) = self.resolve_boxed_box() { 491 if let Some(box_) = self.resolve_boxed_box() {
494 Ty::apply_one(TypeCtor::Adt(box_), inner_ty) 492 let mut sb = Substs::builder(generics(self.db.upcast(), box_.into()).len());
493 sb = sb.push(inner_ty);
494 match self.db.generic_defaults(box_.into()).as_ref() {
495 [_, alloc_ty, ..] if !alloc_ty.value.is_unknown() => {
496 sb = sb.push(alloc_ty.value.clone());
497 }
498 _ => (),
499 }
500 sb = sb.fill(repeat_with(|| self.table.new_type_var()));
501 Ty::Adt(box_, sb.build())
495 } else { 502 } else {
496 Ty::Unknown 503 Ty::Unknown
497 } 504 }
@@ -521,13 +528,11 @@ impl<'a> InferenceContext<'a> {
521 UnaryOp::Neg => { 528 UnaryOp::Neg => {
522 match &inner_ty { 529 match &inner_ty {
523 // Fast path for builtins 530 // Fast path for builtins
524 Ty::Apply(ApplicationTy { 531 Ty::Scalar(Scalar::Int(_))
525 ctor: TypeCtor::Int(IntTy { signedness: Signedness::Signed, .. }), 532 | Ty::Scalar(Scalar::Uint(_))
526 .. 533 | Ty::Scalar(Scalar::Float(_))
527 }) 534 | Ty::InferenceVar(_, TyVariableKind::Integer)
528 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) 535 | Ty::InferenceVar(_, TyVariableKind::Float) => inner_ty,
529 | Ty::Infer(InferTy::IntVar(..))
530 | Ty::Infer(InferTy::FloatVar(..)) => inner_ty,
531 // Otherwise we resolve via the std::ops::Neg trait 536 // Otherwise we resolve via the std::ops::Neg trait
532 _ => self 537 _ => self
533 .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), 538 .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
@@ -536,9 +541,10 @@ impl<'a> InferenceContext<'a> {
536 UnaryOp::Not => { 541 UnaryOp::Not => {
537 match &inner_ty { 542 match &inner_ty {
538 // Fast path for builtins 543 // Fast path for builtins
539 Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }) 544 Ty::Scalar(Scalar::Bool)
540 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. }) 545 | Ty::Scalar(Scalar::Int(_))
541 | Ty::Infer(InferTy::IntVar(..)) => inner_ty, 546 | Ty::Scalar(Scalar::Uint(_))
547 | Ty::InferenceVar(_, TyVariableKind::Integer) => inner_ty,
542 // Otherwise we resolve via the std::ops::Not trait 548 // Otherwise we resolve via the std::ops::Not trait
543 _ => self 549 _ => self
544 .resolve_associated_type(inner_ty, self.resolve_ops_not_output()), 550 .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
@@ -549,7 +555,7 @@ impl<'a> InferenceContext<'a> {
549 Expr::BinaryOp { lhs, rhs, op } => match op { 555 Expr::BinaryOp { lhs, rhs, op } => match op {
550 Some(op) => { 556 Some(op) => {
551 let lhs_expectation = match op { 557 let lhs_expectation = match op {
552 BinaryOp::LogicOp(..) => Expectation::has_type(Ty::simple(TypeCtor::Bool)), 558 BinaryOp::LogicOp(..) => Expectation::has_type(Ty::Scalar(Scalar::Bool)),
553 _ => Expectation::none(), 559 _ => Expectation::none(),
554 }; 560 };
555 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); 561 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation);
@@ -580,31 +586,31 @@ impl<'a> InferenceContext<'a> {
580 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); 586 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
581 match (range_type, lhs_ty, rhs_ty) { 587 match (range_type, lhs_ty, rhs_ty) {
582 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { 588 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
583 Some(adt) => Ty::simple(TypeCtor::Adt(adt)), 589 Some(adt) => Ty::Adt(adt, Substs::empty()),
584 None => Ty::Unknown, 590 None => Ty::Unknown,
585 }, 591 },
586 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { 592 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
587 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), 593 Some(adt) => Ty::Adt(adt, Substs::single(ty)),
588 None => Ty::Unknown, 594 None => Ty::Unknown,
589 }, 595 },
590 (RangeOp::Inclusive, None, Some(ty)) => { 596 (RangeOp::Inclusive, None, Some(ty)) => {
591 match self.resolve_range_to_inclusive() { 597 match self.resolve_range_to_inclusive() {
592 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), 598 Some(adt) => Ty::Adt(adt, Substs::single(ty)),
593 None => Ty::Unknown, 599 None => Ty::Unknown,
594 } 600 }
595 } 601 }
596 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { 602 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
597 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), 603 Some(adt) => Ty::Adt(adt, Substs::single(ty)),
598 None => Ty::Unknown, 604 None => Ty::Unknown,
599 }, 605 },
600 (RangeOp::Inclusive, Some(_), Some(ty)) => { 606 (RangeOp::Inclusive, Some(_), Some(ty)) => {
601 match self.resolve_range_inclusive() { 607 match self.resolve_range_inclusive() {
602 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), 608 Some(adt) => Ty::Adt(adt, Substs::single(ty)),
603 None => Ty::Unknown, 609 None => Ty::Unknown,
604 } 610 }
605 } 611 }
606 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { 612 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
607 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), 613 Some(adt) => Ty::Adt(adt, Substs::single(ty)),
608 None => Ty::Unknown, 614 None => Ty::Unknown,
609 }, 615 },
610 (RangeOp::Inclusive, _, None) => Ty::Unknown, 616 (RangeOp::Inclusive, _, None) => Ty::Unknown,
@@ -638,7 +644,7 @@ impl<'a> InferenceContext<'a> {
638 } 644 }
639 Expr::Tuple { exprs } => { 645 Expr::Tuple { exprs } => {
640 let mut tys = match &expected.ty { 646 let mut tys = match &expected.ty {
641 ty_app!(TypeCtor::Tuple { .. }, st) => st 647 Ty::Tuple(_, substs) => substs
642 .iter() 648 .iter()
643 .cloned() 649 .cloned()
644 .chain(repeat_with(|| self.table.new_type_var())) 650 .chain(repeat_with(|| self.table.new_type_var()))
@@ -651,15 +657,11 @@ impl<'a> InferenceContext<'a> {
651 self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); 657 self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
652 } 658 }
653 659
654 Ty::apply(TypeCtor::Tuple { cardinality: tys.len() as u16 }, Substs(tys.into())) 660 Ty::Tuple(tys.len(), Substs(tys.into()))
655 } 661 }
656 Expr::Array(array) => { 662 Expr::Array(array) => {
657 let elem_ty = match &expected.ty { 663 let elem_ty = match &expected.ty {
658 // FIXME: remove when https://github.com/rust-lang/rust/issues/80501 is fixed 664 Ty::Array(st) | Ty::Slice(st) => st.as_single().clone(),
659 #[allow(unreachable_patterns)]
660 ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => {
661 st.as_single().clone()
662 }
663 _ => self.table.new_type_var(), 665 _ => self.table.new_type_var(),
664 }; 666 };
665 667
@@ -676,30 +678,38 @@ impl<'a> InferenceContext<'a> {
676 ); 678 );
677 self.infer_expr( 679 self.infer_expr(
678 *repeat, 680 *repeat,
679 &Expectation::has_type(Ty::simple(TypeCtor::Int(IntTy::usize()))), 681 &Expectation::has_type(Ty::Scalar(Scalar::Uint(UintTy::Usize))),
680 ); 682 );
681 } 683 }
682 } 684 }
683 685
684 Ty::apply_one(TypeCtor::Array, elem_ty) 686 Ty::Array(Substs::single(elem_ty))
685 } 687 }
686 Expr::Literal(lit) => match lit { 688 Expr::Literal(lit) => match lit {
687 Literal::Bool(..) => Ty::simple(TypeCtor::Bool), 689 Literal::Bool(..) => Ty::Scalar(Scalar::Bool),
688 Literal::String(..) => { 690 Literal::String(..) => Ty::Ref(Mutability::Not, Substs::single(Ty::Str)),
689 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str))
690 }
691 Literal::ByteString(..) => { 691 Literal::ByteString(..) => {
692 let byte_type = Ty::simple(TypeCtor::Int(IntTy::u8())); 692 let byte_type = Ty::Scalar(Scalar::Uint(UintTy::U8));
693 let array_type = Ty::apply_one(TypeCtor::Array, byte_type); 693 let array_type = Ty::Array(Substs::single(byte_type));
694 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) 694 Ty::Ref(Mutability::Not, Substs::single(array_type))
695 } 695 }
696 Literal::Char(..) => Ty::simple(TypeCtor::Char), 696 Literal::Char(..) => Ty::Scalar(Scalar::Char),
697 Literal::Int(_v, ty) => match ty { 697 Literal::Int(_v, ty) => match ty {
698 Some(int_ty) => Ty::simple(TypeCtor::Int((*int_ty).into())), 698 Some(int_ty) => {
699 Ty::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty)))
700 }
701 None => self.table.new_integer_var(),
702 },
703 Literal::Uint(_v, ty) => match ty {
704 Some(int_ty) => {
705 Ty::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty)))
706 }
699 None => self.table.new_integer_var(), 707 None => self.table.new_integer_var(),
700 }, 708 },
701 Literal::Float(_v, ty) => match ty { 709 Literal::Float(_v, ty) => match ty {
702 Some(float_ty) => Ty::simple(TypeCtor::Float((*float_ty).into())), 710 Some(float_ty) => {
711 Ty::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty)))
712 }
703 None => self.table.new_float_var(), 713 None => self.table.new_float_var(),
704 }, 714 },
705 }, 715 },
@@ -755,7 +765,7 @@ impl<'a> InferenceContext<'a> {
755 // `!`). 765 // `!`).
756 if self.diverges.is_always() { 766 if self.diverges.is_always() {
757 // we don't even make an attempt at coercion 767 // we don't even make an attempt at coercion
758 self.table.new_maybe_never_type_var() 768 self.table.new_maybe_never_var()
759 } else { 769 } else {
760 self.coerce(&Ty::unit(), expected.coercion_target()); 770 self.coerce(&Ty::unit(), expected.coercion_target());
761 Ty::unit() 771 Ty::unit()
@@ -812,7 +822,7 @@ impl<'a> InferenceContext<'a> {
812 // Apply autoref so the below unification works correctly 822 // Apply autoref so the below unification works correctly
813 // FIXME: return correct autorefs from lookup_method 823 // FIXME: return correct autorefs from lookup_method
814 let actual_receiver_ty = match expected_receiver_ty.as_reference() { 824 let actual_receiver_ty = match expected_receiver_ty.as_reference() {
815 Some((_, mutability)) => Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty), 825 Some((_, mutability)) => Ty::Ref(mutability, Substs::single(derefed_receiver_ty)),
816 _ => derefed_receiver_ty, 826 _ => derefed_receiver_ty,
817 }; 827 };
818 self.unify(&expected_receiver_ty, &actual_receiver_ty); 828 self.unify(&expected_receiver_ty, &actual_receiver_ty);
@@ -889,30 +899,26 @@ impl<'a> InferenceContext<'a> {
889 } 899 }
890 900
891 fn register_obligations_for_call(&mut self, callable_ty: &Ty) { 901 fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
892 if let Ty::Apply(a_ty) = callable_ty { 902 if let &Ty::FnDef(def, ref parameters) = callable_ty {
893 if let TypeCtor::FnDef(def) = a_ty.ctor { 903 let generic_predicates = self.db.generic_predicates(def.into());
894 let generic_predicates = self.db.generic_predicates(def.into()); 904 for predicate in generic_predicates.iter() {
895 for predicate in generic_predicates.iter() { 905 let predicate = predicate.clone().subst(parameters);
896 let predicate = predicate.clone().subst(&a_ty.parameters); 906 if let Some(obligation) = Obligation::from_predicate(predicate) {
897 if let Some(obligation) = Obligation::from_predicate(predicate) { 907 self.obligations.push(obligation);
898 self.obligations.push(obligation);
899 }
900 } 908 }
901 // add obligation for trait implementation, if this is a trait method 909 }
902 match def { 910 // add obligation for trait implementation, if this is a trait method
903 CallableDefId::FunctionId(f) => { 911 match def {
904 if let AssocContainerId::TraitId(trait_) = 912 CallableDefId::FunctionId(f) => {
905 f.lookup(self.db.upcast()).container 913 if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container
906 { 914 {
907 // construct a TraitDef 915 // construct a TraitDef
908 let substs = a_ty 916 let substs =
909 .parameters 917 parameters.prefix(generics(self.db.upcast(), trait_.into()).len());
910 .prefix(generics(self.db.upcast(), trait_.into()).len()); 918 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
911 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
912 }
913 } 919 }
914 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
915 } 920 }
921 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
916 } 922 }
917 } 923 }
918 } 924 }
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index d974f805b..eb099311c 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -3,17 +3,17 @@
3use std::iter::repeat; 3use std::iter::repeat;
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use chalk_ir::Mutability;
6use hir_def::{ 7use hir_def::{
7 expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, 8 expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
8 path::Path, 9 path::Path,
9 type_ref::Mutability,
10 FieldId, 10 FieldId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use test_utils::mark; 13use test_utils::mark;
14 14
15use super::{BindingMode, Expectation, InferenceContext}; 15use super::{BindingMode, Expectation, InferenceContext};
16use crate::{utils::variant_data, Substs, Ty, TypeCtor}; 16use crate::{lower::lower_to_chalk_mutability, utils::variant_data, Substs, Ty};
17 17
18impl<'a> InferenceContext<'a> { 18impl<'a> InferenceContext<'a> {
19 fn infer_tuple_struct_pat( 19 fn infer_tuple_struct_pat(
@@ -32,7 +32,7 @@ impl<'a> InferenceContext<'a> {
32 } 32 }
33 self.unify(&ty, expected); 33 self.unify(&ty, expected);
34 34
35 let substs = ty.substs().unwrap_or_else(Substs::empty); 35 let substs = ty.substs().cloned().unwrap_or_else(Substs::empty);
36 36
37 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); 37 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
38 let (pre, post) = match ellipsis { 38 let (pre, post) = match ellipsis {
@@ -71,7 +71,7 @@ impl<'a> InferenceContext<'a> {
71 71
72 self.unify(&ty, expected); 72 self.unify(&ty, expected);
73 73
74 let substs = ty.substs().unwrap_or_else(Substs::empty); 74 let substs = ty.substs().cloned().unwrap_or_else(Substs::empty);
75 75
76 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); 76 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
77 for subpat in subpats { 77 for subpat in subpats {
@@ -103,7 +103,7 @@ impl<'a> InferenceContext<'a> {
103 expected = inner; 103 expected = inner;
104 default_bm = match default_bm { 104 default_bm = match default_bm {
105 BindingMode::Move => BindingMode::Ref(mutability), 105 BindingMode::Move => BindingMode::Ref(mutability),
106 BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared), 106 BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not),
107 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability), 107 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
108 } 108 }
109 } 109 }
@@ -138,10 +138,7 @@ impl<'a> InferenceContext<'a> {
138 inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned()); 138 inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned());
139 inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat)); 139 inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat));
140 140
141 Ty::apply( 141 Ty::Tuple(inner_tys.len(), Substs(inner_tys.into()))
142 TypeCtor::Tuple { cardinality: inner_tys.len() as u16 },
143 Substs(inner_tys.into()),
144 )
145 } 142 }
146 Pat::Or(ref pats) => { 143 Pat::Or(ref pats) => {
147 if let Some((first_pat, rest)) = pats.split_first() { 144 if let Some((first_pat, rest)) = pats.split_first() {
@@ -155,9 +152,10 @@ impl<'a> InferenceContext<'a> {
155 } 152 }
156 } 153 }
157 Pat::Ref { pat, mutability } => { 154 Pat::Ref { pat, mutability } => {
155 let mutability = lower_to_chalk_mutability(*mutability);
158 let expectation = match expected.as_reference() { 156 let expectation = match expected.as_reference() {
159 Some((inner_ty, exp_mut)) => { 157 Some((inner_ty, exp_mut)) => {
160 if *mutability != exp_mut { 158 if mutability != exp_mut {
161 // FIXME: emit type error? 159 // FIXME: emit type error?
162 } 160 }
163 inner_ty 161 inner_ty
@@ -165,7 +163,7 @@ impl<'a> InferenceContext<'a> {
165 _ => &Ty::Unknown, 163 _ => &Ty::Unknown,
166 }; 164 };
167 let subty = self.infer_pat(*pat, expectation, default_bm); 165 let subty = self.infer_pat(*pat, expectation, default_bm);
168 Ty::apply_one(TypeCtor::Ref(*mutability), subty) 166 Ty::Ref(mutability, Substs::single(subty))
169 } 167 }
170 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( 168 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
171 p.as_ref(), 169 p.as_ref(),
@@ -198,7 +196,7 @@ impl<'a> InferenceContext<'a> {
198 196
199 let bound_ty = match mode { 197 let bound_ty = match mode {
200 BindingMode::Ref(mutability) => { 198 BindingMode::Ref(mutability) => {
201 Ty::apply_one(TypeCtor::Ref(mutability), inner_ty.clone()) 199 Ty::Ref(mutability, Substs::single(inner_ty.clone()))
202 } 200 }
203 BindingMode::Move => inner_ty.clone(), 201 BindingMode::Move => inner_ty.clone(),
204 }; 202 };
@@ -207,17 +205,17 @@ impl<'a> InferenceContext<'a> {
207 return inner_ty; 205 return inner_ty;
208 } 206 }
209 Pat::Slice { prefix, slice, suffix } => { 207 Pat::Slice { prefix, slice, suffix } => {
210 let (container_ty, elem_ty) = match &expected { 208 let (container_ty, elem_ty): (fn(_) -> _, _) = match &expected {
211 ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()), 209 Ty::Array(st) => (Ty::Array, st.as_single().clone()),
212 ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()), 210 Ty::Slice(st) => (Ty::Slice, st.as_single().clone()),
213 _ => (TypeCtor::Slice, Ty::Unknown), 211 _ => (Ty::Slice, Ty::Unknown),
214 }; 212 };
215 213
216 for pat_id in prefix.iter().chain(suffix) { 214 for pat_id in prefix.iter().chain(suffix) {
217 self.infer_pat(*pat_id, &elem_ty, default_bm); 215 self.infer_pat(*pat_id, &elem_ty, default_bm);
218 } 216 }
219 217
220 let pat_ty = Ty::apply_one(container_ty, elem_ty); 218 let pat_ty = container_ty(Substs::single(elem_ty));
221 if let Some(slice_pat_id) = slice { 219 if let Some(slice_pat_id) = slice {
222 self.infer_pat(*slice_pat_id, &pat_ty, default_bm); 220 self.infer_pat(*slice_pat_id, &pat_ty, default_bm);
223 } 221 }
@@ -239,7 +237,7 @@ impl<'a> InferenceContext<'a> {
239 }; 237 };
240 238
241 let inner_ty = self.infer_pat(*inner, inner_expected, default_bm); 239 let inner_ty = self.infer_pat(*inner, inner_expected, default_bm);
242 Ty::apply_one(TypeCtor::Adt(box_adt), inner_ty) 240 Ty::Adt(box_adt, Substs::single(inner_ty))
243 } 241 }
244 None => Ty::Unknown, 242 None => Ty::Unknown,
245 }, 243 },
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 76984242e..99a89a7f3 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -2,14 +2,15 @@
2 2
3use std::borrow::Cow; 3use std::borrow::Cow;
4 4
5use chalk_ir::{FloatTy, IntTy, TyVariableKind};
5use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
6 7
7use test_utils::mark; 8use test_utils::mark;
8 9
9use super::{InferenceContext, Obligation}; 10use super::{InferenceContext, Obligation};
10use crate::{ 11use crate::{
11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, 12 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferenceVar, Scalar,
12 TyKind, TypeCtor, TypeWalk, 13 Substs, Ty, TypeWalk,
13}; 14};
14 15
15impl<'a> InferenceContext<'a> { 16impl<'a> InferenceContext<'a> {
@@ -26,7 +27,7 @@ where
26 'a: 'b, 27 'a: 'b,
27{ 28{
28 ctx: &'b mut InferenceContext<'a>, 29 ctx: &'b mut InferenceContext<'a>,
29 free_vars: Vec<InferTy>, 30 free_vars: Vec<(InferenceVar, TyVariableKind)>,
30 /// A stack of type variables that is used to detect recursive types (which 31 /// A stack of type variables that is used to detect recursive types (which
31 /// are an error, but we need to protect against them to avoid stack 32 /// are an error, but we need to protect against them to avoid stack
32 /// overflows). 33 /// overflows).
@@ -36,17 +37,14 @@ where
36#[derive(Debug)] 37#[derive(Debug)]
37pub(super) struct Canonicalized<T> { 38pub(super) struct Canonicalized<T> {
38 pub(super) value: Canonical<T>, 39 pub(super) value: Canonical<T>,
39 free_vars: Vec<InferTy>, 40 free_vars: Vec<(InferenceVar, TyVariableKind)>,
40} 41}
41 42
42impl<'a, 'b> Canonicalizer<'a, 'b> 43impl<'a, 'b> Canonicalizer<'a, 'b> {
43where 44 fn add(&mut self, free_var: InferenceVar, kind: TyVariableKind) -> usize {
44 'a: 'b, 45 self.free_vars.iter().position(|&(v, _)| v == free_var).unwrap_or_else(|| {
45{
46 fn add(&mut self, free_var: InferTy) -> usize {
47 self.free_vars.iter().position(|&v| v == free_var).unwrap_or_else(|| {
48 let next_index = self.free_vars.len(); 46 let next_index = self.free_vars.len();
49 self.free_vars.push(free_var); 47 self.free_vars.push((free_var, kind));
50 next_index 48 next_index
51 }) 49 })
52 } 50 }
@@ -54,11 +52,11 @@ where
54 fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T { 52 fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T {
55 t.fold_binders( 53 t.fold_binders(
56 &mut |ty, binders| match ty { 54 &mut |ty, binders| match ty {
57 Ty::Infer(tv) => { 55 Ty::InferenceVar(var, kind) => {
58 let inner = tv.to_inner(); 56 let inner = var.to_inner();
59 if self.var_stack.contains(&inner) { 57 if self.var_stack.contains(&inner) {
60 // recursive type 58 // recursive type
61 return tv.fallback_value(); 59 return self.ctx.table.type_variable_table.fallback_value(var, kind);
62 } 60 }
63 if let Some(known_ty) = 61 if let Some(known_ty) =
64 self.ctx.table.var_unification_table.inlined_probe_value(inner).known() 62 self.ctx.table.var_unification_table.inlined_probe_value(inner).known()
@@ -69,14 +67,8 @@ where
69 result 67 result
70 } else { 68 } else {
71 let root = self.ctx.table.var_unification_table.find(inner); 69 let root = self.ctx.table.var_unification_table.find(inner);
72 let free_var = match tv { 70 let position = self.add(InferenceVar::from_inner(root), kind);
73 InferTy::TypeVar(_) => InferTy::TypeVar(root), 71 Ty::BoundVar(BoundVar::new(binders, position))
74 InferTy::IntVar(_) => InferTy::IntVar(root),
75 InferTy::FloatVar(_) => InferTy::FloatVar(root),
76 InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root),
77 };
78 let position = self.add(free_var);
79 Ty::Bound(BoundVar::new(binders, position))
80 } 72 }
81 } 73 }
82 _ => ty, 74 _ => ty,
@@ -86,19 +78,7 @@ where
86 } 78 }
87 79
88 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 80 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
89 let kinds = self 81 let kinds = self.free_vars.iter().map(|&(_, k)| k).collect();
90 .free_vars
91 .iter()
92 .map(|v| match v {
93 // mapping MaybeNeverTypeVar to the same kind as general ones
94 // should be fine, because as opposed to int or float type vars,
95 // they don't restrict what kind of type can go into them, they
96 // just affect fallback.
97 InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General,
98 InferTy::IntVar(_) => TyKind::Integer,
99 InferTy::FloatVar(_) => TyKind::Float,
100 })
101 .collect();
102 Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars } 82 Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars }
103 } 83 }
104 84
@@ -130,9 +110,10 @@ impl<T> Canonicalized<T> {
130 pub(super) fn decanonicalize_ty(&self, mut ty: Ty) -> Ty { 110 pub(super) fn decanonicalize_ty(&self, mut ty: Ty) -> Ty {
131 ty.walk_mut_binders( 111 ty.walk_mut_binders(
132 &mut |ty, binders| { 112 &mut |ty, binders| {
133 if let &mut Ty::Bound(bound) = ty { 113 if let &mut Ty::BoundVar(bound) = ty {
134 if bound.debruijn >= binders { 114 if bound.debruijn >= binders {
135 *ty = Ty::Infer(self.free_vars[bound.index]); 115 let (v, k) = self.free_vars[bound.index];
116 *ty = Ty::InferenceVar(v, k);
136 } 117 }
137 } 118 }
138 }, 119 },
@@ -152,18 +133,18 @@ impl<T> Canonicalized<T> {
152 .kinds 133 .kinds
153 .iter() 134 .iter()
154 .map(|k| match k { 135 .map(|k| match k {
155 TyKind::General => ctx.table.new_type_var(), 136 TyVariableKind::General => ctx.table.new_type_var(),
156 TyKind::Integer => ctx.table.new_integer_var(), 137 TyVariableKind::Integer => ctx.table.new_integer_var(),
157 TyKind::Float => ctx.table.new_float_var(), 138 TyVariableKind::Float => ctx.table.new_float_var(),
158 }) 139 })
159 .collect(), 140 .collect(),
160 ); 141 );
161 for (i, ty) in solution.value.into_iter().enumerate() { 142 for (i, ty) in solution.value.into_iter().enumerate() {
162 let var = self.free_vars[i]; 143 let (v, k) = self.free_vars[i];
<