Auto merge of #13882 - Veykril:bin-op-adjust, r=Veykril

Write down adjustments introduced by binary operators
This commit is contained in:
bors 2023-01-02 22:17:11 +00:00
commit e75e2f8368
6 changed files with 86 additions and 21 deletions

View File

@ -6,7 +6,7 @@ use std::{
}; };
use chalk_ir::{ use chalk_ir::{
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyKind, TyVariableKind,
}; };
use hir_def::{ use hir_def::{
expr::{ expr::{
@ -34,8 +34,8 @@ use crate::{
primitive::{self, UintTy}, primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id, static_lifetime, to_chalk_trait_id,
utils::{generics, Generics}, utils::{generics, Generics},
AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnPointer, FnSig, FnSubst,
Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt,
}; };
use super::{ use super::{
@ -1038,14 +1038,38 @@ impl<'a> InferenceContext<'a> {
self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone())); self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()));
let ret_ty = match method_ty.callable_sig(self.db) { 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(), None => self.err_ty(),
}; };
let ret_ty = self.normalize_associated_types_in(ret_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 // 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()) { if let Some(builtin_rhs) = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()) {
self.unify(&builtin_rhs, &rhs_ty); self.unify(&builtin_rhs, &rhs_ty);

View File

@ -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()); types.insert(file_range, expected.trim_start_matches("type: ").to_string());
} else if expected.starts_with("expected") { } else if expected.starts_with("expected") {
mismatches.insert(file_range, expected); mismatches.insert(file_range, expected);
} else if expected.starts_with("adjustments: ") { } else if expected.starts_with("adjustments:") {
adjustments.insert( adjustments.insert(
file_range, file_range,
expected expected
.trim_start_matches("adjustments: ") .trim_start_matches("adjustments:")
.trim()
.split(',') .split(',')
.map(|it| it.trim().to_string()) .map(|it| it.trim().to_string())
.filter(|it| !it.is_empty()) .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); assert_eq!(actual, expected);
} }
if let Some(expected) = adjustments.remove(&range) { if let Some(expected) = adjustments.remove(&range) {
if let Some(adjustments) = inference_result.expr_adjustments.get(&expr) { let adjustments = inference_result
assert_eq!( .expr_adjustments
expected, .get(&expr)
adjustments .map_or_else(Default::default, |it| &**it);
.iter() assert_eq!(
.map(|Adjustment { kind, .. }| format!("{kind:?}")) expected,
.collect::<Vec<_>>() adjustments
); .iter()
} else { .map(|Adjustment { kind, .. }| format!("{kind:?}"))
panic!("expected {expected:?} adjustments, found none"); .collect::<Vec<_>>()
} );
} }
} }

View File

@ -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:
}",
);
}

View File

@ -24,7 +24,7 @@ mod chaining;
mod param_name; mod param_name;
mod binding_mode; mod binding_mode;
mod bind_pat; mod bind_pat;
mod discrimant; mod discriminant;
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct InlayHintsConfig { pub struct InlayHintsConfig {
@ -376,7 +376,7 @@ fn hints(
_ => None, _ => None,
}, },
ast::Variant(v) => { 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 // FIXME: fn-ptr type, dyn fn type, and trait object type elisions
ast::Type(_) => None, ast::Type(_) => None,

View File

@ -382,6 +382,12 @@ pub mod ops {
type Output; type Output;
fn add(self, rhs: Rhs) -> Self::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 // endregion:add
// region:generator // region:generator