From 2c15597687546f825d5595e9c2be48703a35fe6f Mon Sep 17 00:00:00 2001 From: bitgaoshu Date: Sat, 10 Dec 2022 14:08:12 +0800 Subject: [PATCH] fix: #12247 fully qualified call required to determine trait method type --- crates/hir-expand/src/name.rs | 2 ++ crates/hir-ty/src/infer.rs | 11 ++++++ crates/hir-ty/src/infer/expr.rs | 8 +++++ crates/hir-ty/src/tests/regression.rs | 51 +++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 259fe1327f88..d7068c707eb1 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -266,11 +266,13 @@ pub mod known { IntoIter, Try, Ok, + Err, Future, IntoFuture, Result, Option, Output, + Residual, Target, Box, RangeFrom, diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 112eb5bd84cd..225f342b3325 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -928,6 +928,17 @@ impl<'a> InferenceContext<'a> { .or_else(|| trait_data.associated_type_by_name(&name![Output])) } + fn resolve_ops_try_err(&self) -> Option { + // FIXME resolve via lang_item once try v2 is stable + let path = path![core::ops::Try]; + let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; + let trait_data = self.db.trait_data(trait_); + trait_data + // FIXME remove once try v2 is stable + .associated_type_by_name(&name![Err]) + .or_else(|| trait_data.associated_type_by_name(&name![Residual])) + } + fn resolve_ops_neg_output(&self) -> Option { let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?; self.db.trait_data(trait_).associated_type_by_name(&name![Output]) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index b1f4de826077..8687d203fe7b 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -567,6 +567,14 @@ impl<'a> InferenceContext<'a> { } Expr::Try { expr } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); + let actual_ret = inner_ty.clone(); + let residual = self.resolve_ops_try_err(); + let expect_err = self.resolve_associated_type(self.return_ty.clone(), residual); + let actual_err = self.resolve_associated_type(actual_ret, residual); + match self.table.coerce(&actual_err, &expect_err) { + Err(_) => (), + Ok(_) => (), + } self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()) } Expr::Cast { expr, type_ref } => { diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 4e46397459d5..15f75cf7b444 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -944,6 +944,57 @@ fn clone_iter(s: Iter) { ) } +#[test] +fn issue_12247() { + check_types( + r#" +//- minicore: result, try +fn aa() -> Result { + let a : Result = Err(E1); + let b = a.mapE()?; + //^ i32 +} +struct E1; +struct E2; +struct E3; + +impl From for E2 { + fn from(value: E1) -> Self { + E2 + } +} + +impl From for E3 { + fn from(value: E1) -> Self { + E3 + } +} +trait MapErr { + fn mapE(self) -> Result; +} + +impl MapErr for Result +where + ET: Into, +{ + fn mapE(self) -> Result { + self.map_err(|e| e.into()) + } +} + +impl MapErr for Result +where + ET: Into, +{ + fn mapE(self) -> Result { + self.map_err(|e| e.into()) + } +} + "#, + ) +} + + #[test] fn issue_8686() { check_infer(