diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index a5dd020676..2e5c424410 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -6,7 +6,7 @@ use std::{ }; use chalk_ir::{ - cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, + cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyKind, TyVariableKind, }; use hir_def::{ expr::{ @@ -34,8 +34,8 @@ use crate::{ primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, utils::{generics, Generics}, - AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, - Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, + Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnPointer, FnSig, FnSubst, + Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, }; use super::{ @@ -1038,14 +1038,38 @@ impl<'a> InferenceContext<'a> { self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone())); let ret_ty = match method_ty.callable_sig(self.db) { - Some(sig) => sig.ret().clone(), + Some(sig) => { + let p_left = &sig.params()[0]; + if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. }) { + if let &TyKind::Ref(mtbl, _, _) = p_left.kind(Interner) { + self.write_expr_adj( + lhs, + vec![Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(mtbl)), + target: p_left.clone(), + }], + ); + } + } + let p_right = &sig.params()[1]; + if matches!(op, BinaryOp::CmpOp(..)) { + if let &TyKind::Ref(mtbl, _, _) = p_right.kind(Interner) { + self.write_expr_adj( + rhs, + vec![Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(mtbl)), + target: p_right.clone(), + }], + ); + } + } + sig.ret().clone() + } None => self.err_ty(), }; let ret_ty = self.normalize_associated_types_in(ret_ty); - // FIXME: record autoref adjustments - // use knowledge of built-in binary ops, which can sometimes help inference if let Some(builtin_rhs) = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()) { self.unify(&builtin_rhs, &rhs_ty); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 7bcf89ff59..ba5d9c2412 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -94,11 +94,12 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour types.insert(file_range, expected.trim_start_matches("type: ").to_string()); } else if expected.starts_with("expected") { mismatches.insert(file_range, expected); - } else if expected.starts_with("adjustments: ") { + } else if expected.starts_with("adjustments:") { adjustments.insert( file_range, expected - .trim_start_matches("adjustments: ") + .trim_start_matches("adjustments:") + .trim() .split(',') .map(|it| it.trim().to_string()) .filter(|it| !it.is_empty()) @@ -176,17 +177,17 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour assert_eq!(actual, expected); } if let Some(expected) = adjustments.remove(&range) { - if let Some(adjustments) = inference_result.expr_adjustments.get(&expr) { - assert_eq!( - expected, - adjustments - .iter() - .map(|Adjustment { kind, .. }| format!("{kind:?}")) - .collect::>() - ); - } else { - panic!("expected {expected:?} adjustments, found none"); - } + let adjustments = inference_result + .expr_adjustments + .get(&expr) + .map_or_else(Default::default, |it| &**it); + assert_eq!( + expected, + adjustments + .iter() + .map(|Adjustment { kind, .. }| format!("{kind:?}")) + .collect::>() + ); } } diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index 7e3aecc2ae..3e110abaf4 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -807,3 +807,37 @@ fn main() { "#, ); } + +#[test] +fn adjust_comparison_arguments() { + check_no_mismatches( + r" +//- minicore: eq +struct Struct; +impl core::cmp::PartialEq for Struct { + fn eq(&self, other: &Self) -> bool { true } +} +fn test() { + Struct == Struct; + // ^^^^^^ adjustments: Borrow(Ref(Not)) + // ^^^^^^ adjustments: Borrow(Ref(Not)) +}", + ); +} + +#[test] +fn adjust_assign_lhs() { + check_no_mismatches( + r" +//- minicore: add +struct Struct; +impl core::ops::AddAssign for Struct { + fn add_assign(&mut self, other: Self) {} +} +fn test() { + Struct += Struct; + // ^^^^^^ adjustments: Borrow(Ref(Mut)) + // ^^^^^^ adjustments: +}", + ); +} diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 9ec3f7f29a..368c8aaa93 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -24,7 +24,7 @@ mod chaining; mod param_name; mod binding_mode; mod bind_pat; -mod discrimant; +mod discriminant; #[derive(Clone, Debug, PartialEq, Eq)] pub struct InlayHintsConfig { @@ -376,7 +376,7 @@ fn hints( _ => None, }, ast::Variant(v) => { - discrimant::hints(hints, famous_defs, config, file_id, &v) + discriminant::hints(hints, famous_defs, config, file_id, &v) }, // FIXME: fn-ptr type, dyn fn type, and trait object type elisions ast::Type(_) => None, diff --git a/crates/ide/src/inlay_hints/discrimant.rs b/crates/ide/src/inlay_hints/discriminant.rs similarity index 100% rename from crates/ide/src/inlay_hints/discrimant.rs rename to crates/ide/src/inlay_hints/discriminant.rs diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 750b64fea6..3ca63fcab9 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -382,6 +382,12 @@ pub mod ops { type Output; fn add(self, rhs: Rhs) -> Self::Output; } + + #[lang = "add_assign"] + #[const_trait] + pub trait AddAssign { + fn add_assign(&mut self, rhs: Rhs); + } // endregion:add // region:generator