about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-01-02 23:16:09 +0100
committerLukas Wirth <lukastw97@gmail.com>2023-01-02 23:16:09 +0100
commitf51111aacbbfbbf680efc115f8feb1e815309853 (patch)
tree55120e88f25f40865b7484e296bd30759bd0d0dc
parent17cc78f169538538a10e11251562e0fde8ed4958 (diff)
downloadrust-f51111aacbbfbbf680efc115f8feb1e815309853.tar.gz
rust-f51111aacbbfbbf680efc115f8feb1e815309853.zip
Write down adjustments introduced by binary operators
-rw-r--r--crates/hir-ty/src/infer/expr.rs36
-rw-r--r--crates/hir-ty/src/tests.rs27
-rw-r--r--crates/hir-ty/src/tests/coercion.rs34
-rw-r--r--crates/test-utils/src/minicore.rs6
4 files changed, 84 insertions, 19 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index a5dd0206764..2e5c4244109 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 7bcf89ff59c..ba5d9c24126 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::<Vec<_>>()
-                    );
-                } 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::<Vec<_>>()
+                );
             }
         }
 
diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs
index 7e3aecc2ae0..3e110abaf4b 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/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 750b64fea6f..3ca63fcab90 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<Rhs = Self> {
+        fn add_assign(&mut self, rhs: Rhs);
+    }
     // endregion:add
 
     // region:generator