diff options
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/diagnostics.rs | 15 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 31 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check.rs | 4 | ||||
-rw-r--r-- | crates/hir_ty/src/lower.rs | 6 | ||||
-rw-r--r-- | crates/hir_ty/src/tests.rs | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/macros.rs | 31 |
6 files changed, 68 insertions, 21 deletions
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 14e18f5a1..c67a289f2 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -186,9 +186,10 @@ impl Diagnostic for MissingMatchArms { | |||
186 | } | 186 | } |
187 | } | 187 | } |
188 | 188 | ||
189 | // Diagnostic: missing-ok-in-tail-expr | 189 | // Diagnostic: missing-ok-or-some-in-tail-expr |
190 | // | 190 | // |
191 | // This diagnostic is triggered if block that should return `Result` returns a value not wrapped in `Ok`. | 191 | // This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`, |
192 | // or if a block that should return `Option` returns a value not wrapped in `Some`. | ||
192 | // | 193 | // |
193 | // Example: | 194 | // Example: |
194 | // | 195 | // |
@@ -198,17 +199,19 @@ impl Diagnostic for MissingMatchArms { | |||
198 | // } | 199 | // } |
199 | // ``` | 200 | // ``` |
200 | #[derive(Debug)] | 201 | #[derive(Debug)] |
201 | pub struct MissingOkInTailExpr { | 202 | pub struct MissingOkOrSomeInTailExpr { |
202 | pub file: HirFileId, | 203 | pub file: HirFileId, |
203 | pub expr: AstPtr<ast::Expr>, | 204 | pub expr: AstPtr<ast::Expr>, |
205 | // `Some` or `Ok` depending on whether the return type is Result or Option | ||
206 | pub required: String, | ||
204 | } | 207 | } |
205 | 208 | ||
206 | impl Diagnostic for MissingOkInTailExpr { | 209 | impl Diagnostic for MissingOkOrSomeInTailExpr { |
207 | fn code(&self) -> DiagnosticCode { | 210 | fn code(&self) -> DiagnosticCode { |
208 | DiagnosticCode("missing-ok-in-tail-expr") | 211 | DiagnosticCode("missing-ok-or-some-in-tail-expr") |
209 | } | 212 | } |
210 | fn message(&self) -> String { | 213 | fn message(&self) -> String { |
211 | "wrap return expression in Ok".to_string() | 214 | format!("wrap return expression in {}", self.required) |
212 | } | 215 | } |
213 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | 216 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
214 | InFile { file_id: self.file, value: self.expr.clone().into() } | 217 | InFile { file_id: self.file, value: self.expr.clone().into() } |
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index b4e453411..107417c27 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -11,8 +11,8 @@ use crate::{ | |||
11 | db::HirDatabase, | 11 | db::HirDatabase, |
12 | diagnostics::{ | 12 | diagnostics::{ |
13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | 13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, |
14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, | 14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, |
15 | RemoveThisSemicolon, | 15 | MissingPatFields, RemoveThisSemicolon, |
16 | }, | 16 | }, |
17 | utils::variant_data, | 17 | utils::variant_data, |
18 | ApplicationTy, InferenceResult, Ty, TypeCtor, | 18 | ApplicationTy, InferenceResult, Ty, TypeCtor, |
@@ -306,27 +306,40 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
306 | }; | 306 | }; |
307 | 307 | ||
308 | let core_result_path = path![core::result::Result]; | 308 | let core_result_path = path![core::result::Result]; |
309 | let core_option_path = path![core::option::Option]; | ||
309 | 310 | ||
310 | let resolver = self.owner.resolver(db.upcast()); | 311 | let resolver = self.owner.resolver(db.upcast()); |
311 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { | 312 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { |
312 | Some(it) => it, | 313 | Some(it) => it, |
313 | _ => return, | 314 | _ => return, |
314 | }; | 315 | }; |
316 | let core_option_enum = match resolver.resolve_known_enum(db.upcast(), &core_option_path) { | ||
317 | Some(it) => it, | ||
318 | _ => return, | ||
319 | }; | ||
315 | 320 | ||
316 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); | 321 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); |
317 | let params = match &mismatch.expected { | 322 | let core_option_ctor = TypeCtor::Adt(AdtId::EnumId(core_option_enum)); |
323 | |||
324 | let (params, required) = match &mismatch.expected { | ||
318 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { | 325 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { |
319 | parameters | 326 | (parameters, "Ok".to_string()) |
327 | } | ||
328 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_option_ctor => { | ||
329 | (parameters, "Some".to_string()) | ||
320 | } | 330 | } |
321 | _ => return, | 331 | _ => return, |
322 | }; | 332 | }; |
323 | 333 | ||
324 | if params.len() == 2 && params[0] == mismatch.actual { | 334 | if params.len() > 0 && params[0] == mismatch.actual { |
325 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | 335 | let (_, source_map) = db.body_with_source_map(self.owner.into()); |
326 | 336 | ||
327 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 337 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
328 | self.sink | 338 | self.sink.push(MissingOkOrSomeInTailExpr { |
329 | .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value }); | 339 | file: source_ptr.file_id, |
340 | expr: source_ptr.value, | ||
341 | required, | ||
342 | }); | ||
330 | } | 343 | } |
331 | } | 344 | } |
332 | } | 345 | } |
@@ -366,7 +379,7 @@ pub fn record_literal_missing_fields( | |||
366 | id: ExprId, | 379 | id: ExprId, |
367 | expr: &Expr, | 380 | expr: &Expr, |
368 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { | 381 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { |
369 | let (fields, exhausitve) = match expr { | 382 | let (fields, exhaustive) = match expr { |
370 | Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), | 383 | Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), |
371 | _ => return None, | 384 | _ => return None, |
372 | }; | 385 | }; |
@@ -387,7 +400,7 @@ pub fn record_literal_missing_fields( | |||
387 | if missed_fields.is_empty() { | 400 | if missed_fields.is_empty() { |
388 | return None; | 401 | return None; |
389 | } | 402 | } |
390 | Some((variant_def, missed_fields, exhausitve)) | 403 | Some((variant_def, missed_fields, exhaustive)) |
391 | } | 404 | } |
392 | 405 | ||
393 | pub fn record_pattern_missing_fields( | 406 | pub fn record_pattern_missing_fields( |
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 62c329731..61c47eec8 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -14,7 +14,7 @@ | |||
14 | //! The algorithm implemented here is a modified version of the one described in | 14 | //! The algorithm implemented here is a modified version of the one described in |
15 | //! <http://moscova.inria.fr/~maranget/papers/warn/index.html>. | 15 | //! <http://moscova.inria.fr/~maranget/papers/warn/index.html>. |
16 | //! However, to save future implementors from reading the original paper, we | 16 | //! However, to save future implementors from reading the original paper, we |
17 | //! summarise the algorithm here to hopefully save time and be a little clearer | 17 | //! summarize the algorithm here to hopefully save time and be a little clearer |
18 | //! (without being so rigorous). | 18 | //! (without being so rigorous). |
19 | //! | 19 | //! |
20 | //! The core of the algorithm revolves about a "usefulness" check. In particular, we | 20 | //! The core of the algorithm revolves about a "usefulness" check. In particular, we |
@@ -132,7 +132,7 @@ | |||
132 | //! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). | 132 | //! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns). |
133 | //! That means we're going to check the components from left-to-right, so the algorithm | 133 | //! That means we're going to check the components from left-to-right, so the algorithm |
134 | //! operates principally on the first component of the matrix and new pattern-stack `p`. | 134 | //! operates principally on the first component of the matrix and new pattern-stack `p`. |
135 | //! This algorithm is realised in the `is_useful` function. | 135 | //! This algorithm is realized in the `is_useful` function. |
136 | //! | 136 | //! |
137 | //! Base case (`n = 0`, i.e., an empty tuple pattern): | 137 | //! Base case (`n = 0`, i.e., an empty tuple pattern): |
138 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then | 138 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 222f61a11..9594cce8b 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -491,16 +491,16 @@ impl Ty { | |||
491 | fn from_hir_path_inner( | 491 | fn from_hir_path_inner( |
492 | ctx: &TyLoweringContext<'_>, | 492 | ctx: &TyLoweringContext<'_>, |
493 | segment: PathSegment<'_>, | 493 | segment: PathSegment<'_>, |
494 | typable: TyDefId, | 494 | typeable: TyDefId, |
495 | infer_args: bool, | 495 | infer_args: bool, |
496 | ) -> Ty { | 496 | ) -> Ty { |
497 | let generic_def = match typable { | 497 | let generic_def = match typeable { |
498 | TyDefId::BuiltinType(_) => None, | 498 | TyDefId::BuiltinType(_) => None, |
499 | TyDefId::AdtId(it) => Some(it.into()), | 499 | TyDefId::AdtId(it) => Some(it.into()), |
500 | TyDefId::TypeAliasId(it) => Some(it.into()), | 500 | TyDefId::TypeAliasId(it) => Some(it.into()), |
501 | }; | 501 | }; |
502 | let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); | 502 | let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); |
503 | ctx.db.ty(typable).subst(&substs) | 503 | ctx.db.ty(typeable).subst(&substs) |
504 | } | 504 | } |
505 | 505 | ||
506 | /// Collect generic arguments from a path into a `Substs`. See also | 506 | /// Collect generic arguments from a path into a `Substs`. See also |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 0a400cb70..3b1675f0b 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -314,7 +314,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
314 | " | 314 | " |
315 | //- /lib.rs | 315 | //- /lib.rs |
316 | fn foo() -> i32 { | 316 | fn foo() -> i32 { |
317 | <|>1 + 1 | 317 | $01 + 1 |
318 | } | 318 | } |
319 | ", | 319 | ", |
320 | ); | 320 | ); |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 1953da7be..c64f0b5b5 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -371,6 +371,37 @@ expand!(); | |||
371 | } | 371 | } |
372 | 372 | ||
373 | #[test] | 373 | #[test] |
374 | fn infer_macro_with_dollar_crate_in_def_site() { | ||
375 | check_types( | ||
376 | r#" | ||
377 | //- /main.rs crate:main deps:foo | ||
378 | use foo::expand; | ||
379 | |||
380 | macro_rules! list { | ||
381 | ($($tt:tt)*) => { $($tt)* } | ||
382 | } | ||
383 | |||
384 | fn test() { | ||
385 | let r = expand!(); | ||
386 | r; | ||
387 | //^ u128 | ||
388 | } | ||
389 | |||
390 | //- /lib.rs crate:foo | ||
391 | #[macro_export] | ||
392 | macro_rules! expand { | ||
393 | () => { list!($crate::m!()) }; | ||
394 | } | ||
395 | |||
396 | #[macro_export] | ||
397 | macro_rules! m { | ||
398 | () => { 0u128 }; | ||
399 | } | ||
400 | "#, | ||
401 | ); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
374 | fn infer_type_value_non_legacy_macro_use_as() { | 405 | fn infer_type_value_non_legacy_macro_use_as() { |
375 | check_infer( | 406 | check_infer( |
376 | r#" | 407 | r#" |