diff options
Diffstat (limited to 'crates/hir_ty')
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" | |||
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.47", default-features = false } | 20 | chalk-solve = { version = "0.59", default-features = false } |
21 | chalk-ir = "0.47" | 21 | chalk-ir = "0.59" |
22 | chalk-recursive = "0.47" | 22 | chalk-recursive = "0.59" |
23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 24 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 25 | stdx = { 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)] |
252 | pub struct BreakOutsideOfLoop { | 252 | pub 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)] |
276 | pub struct MissingUnsafe { | 276 | pub 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)] |
300 | pub struct MismatchedArgCount { | 300 | pub 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)] | ||
349 | pub enum IdentType { | ||
350 | Argument, | ||
351 | Constant, | ||
352 | Enum, | ||
353 | Field, | ||
354 | Function, | ||
355 | StaticVariable, | ||
356 | Structure, | ||
357 | Variable, | ||
358 | Variant, | ||
359 | } | ||
360 | |||
361 | impl 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)] |
352 | pub struct IncorrectCase { | 383 | pub 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)] | ||
424 | pub 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 | |||
430 | impl 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)] |
390 | mod tests { | 446 | mod 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" | ||
688 | struct S { s: Box<u32> } | ||
689 | fn 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" | ||
700 | struct S { s: u32 } | ||
701 | fn 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 | }; |
26 | use stdx::{always, never}; | ||
26 | use syntax::{ | 27 | use 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 | ||
32 | use crate::{ | 33 | use 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 | ||
37 | mod allow { | 38 | mod 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 | ||
43 | pub(super) struct DeclValidator<'a, 'b: 'a> { | 44 | pub(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(¶m_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(), ¶m_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 | ||
699 | fn 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 | |||
707 | fn 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)] |
716 | mod tests { | 675 | mod 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. |
9 | pub(crate) fn to_camel_case(ident: &str) -> Option<String> { | 9 | pub(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 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{expr::Statement, path::path, resolver::HasResolver, AdtId, DefWithBodyId}; | 5 | use hir_def::{ |
6 | use hir_expand::diagnostics::DiagnosticSink; | 6 | expr::Statement, path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, |
7 | }; | ||
8 | use hir_expand::{diagnostics::DiagnosticSink, name}; | ||
7 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstPtr}; | 10 | use 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 | ||
21 | pub(crate) use hir_def::{ | 23 | pub(crate) use hir_def::{ |
@@ -24,6 +26,8 @@ pub(crate) use hir_def::{ | |||
24 | LocalFieldId, VariantId, | 26 | LocalFieldId, VariantId, |
25 | }; | 27 | }; |
26 | 28 | ||
29 | use super::ReplaceFilterMapNextWithFindMap; | ||
30 | |||
27 | pub(super) struct ExprValidator<'a, 'b: 'a> { | 31 | pub(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::{ | |||
227 | use la_arena::Idx; | 227 | use la_arena::Idx; |
228 | use smallvec::{smallvec, SmallVec}; | 228 | use smallvec::{smallvec, SmallVec}; |
229 | 229 | ||
230 | use crate::{db::HirDatabase, ApplicationTy, InferenceResult, Ty, TypeCtor}; | 230 | use 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#" | ||
1500 | fn 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#" | ||
1530 | fn 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 | }; |
12 | use hir_expand::diagnostics::DiagnosticSink; | 12 | use hir_expand::diagnostics::DiagnosticSink; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Ty}; |
15 | db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDefId, ApplicationTy, | ||
16 | InferenceResult, Ty, TypeCtor, | ||
17 | }; | ||
18 | 15 | ||
19 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | 16 | pub(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 @@ | |||
3 | use std::{borrow::Cow, fmt}; | 3 | use std::{borrow::Cow, fmt}; |
4 | 4 | ||
5 | use crate::{ | 5 | use 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 | }; |
9 | use arrayvec::ArrayVec; | 10 | use arrayvec::ArrayVec; |
11 | use chalk_ir::Mutability; | ||
10 | use hir_def::{ | 12 | use 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 | ||
237 | impl HirDisplay for ApplicationTy { | 239 | impl 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 | |||
263 | impl 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(¶meters.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(¶meters.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 | ¶meters.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(¶meters); |
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 | |||
510 | impl 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 | |||
534 | impl 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 | ||
597 | impl HirDisplay for FnSig { | 590 | impl 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 | ||
619 | fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> { | 612 | fn 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 | ||
630 | pub fn write_bounds_like_dyn_trait( | 623 | pub 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 | |||
637 | fn 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; | |||
18 | use std::ops::Index; | 18 | use std::ops::Index; |
19 | use std::sync::Arc; | 19 | use std::sync::Arc; |
20 | 20 | ||
21 | use chalk_ir::Mutability; | ||
21 | use hir_def::{ | 22 | use 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; | |||
36 | use syntax::SmolStr; | 37 | use syntax::SmolStr; |
37 | 38 | ||
38 | use super::{ | 39 | use 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 | }; |
43 | use crate::{ | 43 | use crate::{ |
44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, | 44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, AliasTy, |
45 | }; | 45 | }; |
46 | 46 | ||
47 | pub(crate) use unify::unify; | 47 | pub(crate) use unify::unify; |
48 | 48 | ||
49 | macro_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 | |||
58 | mod unify; | 49 | mod unify; |
59 | mod path; | 50 | mod path; |
60 | mod expr; | 51 | mod 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)] |
667 | pub enum InferTy { | 658 | pub 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 | ||
674 | impl InferTy { | 662 | impl 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 | ||
7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; | 7 | use chalk_ir::{Mutability, TyVariableKind}; |
8 | use hir_def::lang_item::LangItemTarget; | ||
8 | use test_utils::mark; | 9 | use test_utils::mark; |
9 | 10 | ||
10 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; | 11 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty}; |
11 | 12 | ||
12 | use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; | 13 | use super::{InEnvironment, InferenceContext}; |
13 | 14 | ||
14 | impl<'a> InferenceContext<'a> { | 15 | impl<'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 @@ | |||
3 | use std::iter::{repeat, repeat_with}; | 3 | use std::iter::{repeat, repeat_with}; |
4 | use std::{mem, sync::Arc}; | 4 | use std::{mem, sync::Arc}; |
5 | 5 | ||
6 | use chalk_ir::{Mutability, TyVariableKind}; | ||
6 | use hir_def::{ | 7 | use 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; | |||
15 | use test_utils::mark; | 15 | use test_utils::mark; |
16 | 16 | ||
17 | use crate::{ | 17 | use 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 | ||
25 | use super::{ | 28 | use 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(¶meters) |
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(¶meters) |
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 @@ | |||
3 | use std::iter::repeat; | 3 | use std::iter::repeat; |
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use chalk_ir::Mutability; | ||
6 | use hir_def::{ | 7 | use 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 | }; |
12 | use hir_expand::name::Name; | 12 | use hir_expand::name::Name; |
13 | use test_utils::mark; | 13 | use test_utils::mark; |
14 | 14 | ||
15 | use super::{BindingMode, Expectation, InferenceContext}; | 15 | use super::{BindingMode, Expectation, InferenceContext}; |
16 | use crate::{utils::variant_data, Substs, Ty, TypeCtor}; | 16 | use crate::{lower::lower_to_chalk_mutability, utils::variant_data, Substs, Ty}; |
17 | 17 | ||
18 | impl<'a> InferenceContext<'a> { | 18 | impl<'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 | ||
3 | use std::borrow::Cow; | 3 | use std::borrow::Cow; |
4 | 4 | ||
5 | use chalk_ir::{FloatTy, IntTy, TyVariableKind}; | ||
5 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | 6 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; |
6 | 7 | ||
7 | use test_utils::mark; | 8 | use test_utils::mark; |
8 | 9 | ||
9 | use super::{InferenceContext, Obligation}; | 10 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 11 | use 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 | ||
15 | impl<'a> InferenceContext<'a> { | 16 | impl<'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)] |
37 | pub(super) struct Canonicalized<T> { | 38 | pub(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 | ||
42 | impl<'a, 'b> Canonicalizer<'a, 'b> | 43 | impl<'a, 'b> Canonicalizer<'a, 'b> { |
43 | where | 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]; |
< |