aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorPhil Ellison <[email protected]>2019-08-11 15:00:37 +0100
committerAleksey Kladov <[email protected]>2019-08-25 10:55:56 +0100
commita40e390860987a23f9b899abc5947f1525d3709c (patch)
tree39aa52a99ce47d439ab92d0519681d4524240820 /crates
parent62c2002e2b21b3a74a4e2205ccc40fa93f722b34 (diff)
Check type rather than just name in ok-wrapping diagnostic. Add test for handling generic functions (which currently fails)
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/expr/validation.rs46
-rw-r--r--crates/ra_hir/src/name.rs2
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs37
3 files changed, 77 insertions, 8 deletions
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index ca7db61bc..339a7b848 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -6,10 +6,13 @@ use ra_syntax::ast::{AstNode, RecordLit};
6use super::{Expr, ExprId, RecordLitField}; 6use super::{Expr, ExprId, RecordLitField};
7use crate::{ 7use crate::{
8 adt::AdtDef, 8 adt::AdtDef,
9 code_model::Enum,
9 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, 10 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
10 expr::AstPtr, 11 expr::AstPtr,
12 name,
13 path::{PathKind, PathSegment},
11 ty::{InferenceResult, Ty, TypeCtor}, 14 ty::{InferenceResult, Ty, TypeCtor},
12 Function, HasSource, HirDatabase, Name, Path, 15 Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution
13}; 16};
14use ra_syntax::ast; 17use ra_syntax::ast;
15 18
@@ -106,18 +109,45 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
106 Some(m) => m, 109 Some(m) => m,
107 None => return, 110 None => return,
108 }; 111 };
109 let ret = match &mismatch.expected { 112
110 Ty::Apply(t) => t, 113 let std_result_path = Path {
111 _ => return, 114 kind: PathKind::Abs,
115 segments: vec![
116 PathSegment { name: name::STD, args_and_bindings: None },
117 PathSegment { name: name::RESULT_MOD, args_and_bindings: None },
118 PathSegment { name: name::RESULT_TYPE, args_and_bindings: None },
119 ]
112 }; 120 };
113 let ret_enum = match ret.ctor { 121
114 TypeCtor::Adt(AdtDef::Enum(e)) => e, 122 let resolver = self.func.resolver(db);
123 let std_result_enum = match resolver.resolve_path_segments(db, &std_result_path).into_fully_resolved() {
124 PerNs { types: Some(Resolution::Def(ModuleDef::Enum(e))), .. } => e,
115 _ => return, 125 _ => return,
116 }; 126 };
117 let enum_name = ret_enum.name(db); 127
118 if enum_name.is_none() || enum_name.unwrap().to_string() != "Result" { 128 let std_result_type = std_result_enum.ty(db);
129
130 fn enum_from_type(ty: &Ty) -> Option<Enum> {
131 match ty {
132 Ty::Apply(t) => {
133 match t.ctor {
134 TypeCtor::Adt(AdtDef::Enum(e)) => Some(e),
135 _ => None,
136 }
137 }
138 _ => None
139 }
140 }
141
142 if enum_from_type(&mismatch.expected) != enum_from_type(&std_result_type) {
119 return; 143 return;
120 } 144 }
145
146 let ret = match &mismatch.expected {
147 Ty::Apply(t) => t,
148 _ => return,
149 };
150
121 let params = &ret.parameters; 151 let params = &ret.parameters;
122 if params.len() == 2 && &params[0] == &mismatch.actual { 152 if params.len() == 2 && &params[0] == &mismatch.actual {
123 let source_map = self.func.body_source_map(db); 153 let source_map = self.func.body_source_map(db);
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 6d14eea8e..9c4822d91 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -120,6 +120,8 @@ pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")
120pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); 120pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok"));
121pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); 121pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future"));
122pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); 122pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future"));
123pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result"));
124pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result"));
123pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); 125pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output"));
124 126
125fn resolve_name(text: &SmolStr) -> SmolStr { 127fn resolve_name(text: &SmolStr) -> SmolStr {
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 5e25991c6..57454719c 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -282,6 +282,43 @@ fn div(x: i32, y: i32) -> Result<i32, String> {
282 } 282 }
283 283
284 #[test] 284 #[test]
285 fn test_wrap_return_type_handles_generic_functions() {
286 let before = r#"
287 //- /main.rs
288 use std::{default::Default, result::Result::{self, Ok, Err}};
289
290 fn div<T: Default, i32>(x: i32) -> Result<T, i32> {
291 if x == 0 {
292 return Err(7);
293 }
294 T::default()
295 }
296
297 //- /std/lib.rs
298 pub mod result {
299 pub enum Result<T, E> { Ok(T), Err(E) }
300 }
301 pub mod default {
302 pub trait Default {
303 fn default() -> Self;
304 }
305 }
306 "#;
307// The formatting here is a bit odd due to how the parse_fixture function works in test_utils -
308// it strips empty lines and leading whitespace. The important part of this test is that the final
309// `x / y` expr is now wrapped in `Ok(..)`
310 let after = r#"use std::{default::Default, result::Result::{self, Ok, Err}};
311fn div<T: Default>(x: i32) -> Result<T, i32> {
312 if x == 0 {
313 return Err(7);
314 }
315 Ok(T::default())
316}
317"#;
318 check_apply_diagnostic_fix_for_target_file("/main.rs", before, after);
319 }
320
321 #[test]
285 fn test_wrap_return_type_handles_type_aliases() { 322 fn test_wrap_return_type_handles_type_aliases() {
286 let before = r#" 323 let before = r#"
287 //- /main.rs 324 //- /main.rs