Skip to content

Commit c53064f

Browse files
committed
Enforce builtin binop expectations even without lang items
1 parent 461435a commit c53064f

File tree

2 files changed

+16
-102
lines changed

2 files changed

+16
-102
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,10 +1041,6 @@ impl Expectation {
10411041
}
10421042
}
10431043

1044-
fn from_option(ty: Option<Ty>) -> Self {
1045-
ty.map_or(Expectation::None, Expectation::HasType)
1046-
}
1047-
10481044
/// The following explanation is copied straight from rustc:
10491045
/// Provides an expectation for an rvalue expression given an *optional*
10501046
/// hint, which is not required for type safety (the resulting type might

crates/hir-ty/src/infer/expr.rs

Lines changed: 16 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ use chalk_ir::{
1010
};
1111
use hir_def::{
1212
expr::{
13-
ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
14-
UnaryOp,
13+
ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
1514
},
1615
generics::TypeOrConstParamData,
1716
path::{GenericArg, GenericArgs},
@@ -1017,11 +1016,21 @@ impl<'a> InferenceContext<'a> {
10171016
let (trait_, func) = match trait_func {
10181017
Some(it) => it,
10191018
None => {
1020-
let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
1021-
let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
1022-
return self
1023-
.builtin_binary_op_return_ty(op, lhs_ty, rhs_ty)
1024-
.unwrap_or_else(|| self.err_ty());
1019+
// HACK: `rhs_ty` is a general inference variable with no clue at all at this
1020+
// point. Passing `lhs_ty` as both operands just to check if `lhs_ty` is a builtin
1021+
// type applicable to `op`.
1022+
let ret_ty = if self.is_builtin_binop(&lhs_ty, &lhs_ty, op) {
1023+
// Assume both operands are builtin so we can continue inference. No guarantee
1024+
// on the correctness, rustc would complain as necessary lang items don't seem
1025+
// to exist anyway.
1026+
self.enforce_builtin_binop_types(&lhs_ty, &rhs_ty, op)
1027+
} else {
1028+
self.err_ty()
1029+
};
1030+
1031+
self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty));
1032+
1033+
return ret_ty;
10251034
}
10261035
};
10271036

@@ -1475,97 +1484,6 @@ impl<'a> InferenceContext<'a> {
14751484
indices
14761485
}
14771486

1478-
fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option<Ty> {
1479-
let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
1480-
let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
1481-
match op {
1482-
BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => {
1483-
Some(TyKind::Scalar(Scalar::Bool).intern(Interner))
1484-
}
1485-
BinaryOp::Assignment { .. } => Some(TyBuilder::unit()),
1486-
BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
1487-
// all integer combinations are valid here
1488-
if matches!(
1489-
lhs_ty.kind(Interner),
1490-
TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
1491-
| TyKind::InferenceVar(_, TyVariableKind::Integer)
1492-
) && matches!(
1493-
rhs_ty.kind(Interner),
1494-
TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
1495-
| TyKind::InferenceVar(_, TyVariableKind::Integer)
1496-
) {
1497-
Some(lhs_ty)
1498-
} else {
1499-
None
1500-
}
1501-
}
1502-
BinaryOp::ArithOp(_) => match (lhs_ty.kind(Interner), rhs_ty.kind(Interner)) {
1503-
// (int, int) | (uint, uint) | (float, float)
1504-
(TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
1505-
| (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
1506-
| (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => {
1507-
Some(rhs_ty)
1508-
}
1509-
// ({int}, int) | ({int}, uint)
1510-
(
1511-
TyKind::InferenceVar(_, TyVariableKind::Integer),
1512-
TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
1513-
) => Some(rhs_ty),
1514-
// (int, {int}) | (uint, {int})
1515-
(
1516-
TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
1517-
TyKind::InferenceVar(_, TyVariableKind::Integer),
1518-
) => Some(lhs_ty),
1519-
// ({float} | float)
1520-
(
1521-
TyKind::InferenceVar(_, TyVariableKind::Float),
1522-
TyKind::Scalar(Scalar::Float(_)),
1523-
) => Some(rhs_ty),
1524-
// (float, {float})
1525-
(
1526-
TyKind::Scalar(Scalar::Float(_)),
1527-
TyKind::InferenceVar(_, TyVariableKind::Float),
1528-
) => Some(lhs_ty),
1529-
// ({int}, {int}) | ({float}, {float})
1530-
(
1531-
TyKind::InferenceVar(_, TyVariableKind::Integer),
1532-
TyKind::InferenceVar(_, TyVariableKind::Integer),
1533-
)
1534-
| (
1535-
TyKind::InferenceVar(_, TyVariableKind::Float),
1536-
TyKind::InferenceVar(_, TyVariableKind::Float),
1537-
) => Some(rhs_ty),
1538-
_ => None,
1539-
},
1540-
}
1541-
}
1542-
1543-
fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Option<Ty> {
1544-
Some(match op {
1545-
BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
1546-
BinaryOp::Assignment { op: None } => {
1547-
stdx::never!("Simple assignment operator is not binary op.");
1548-
return None;
1549-
}
1550-
BinaryOp::CmpOp(CmpOp::Eq { .. }) => match self
1551-
.resolve_ty_shallow(&lhs_ty)
1552-
.kind(Interner)
1553-
{
1554-
TyKind::Scalar(_) | TyKind::Str => lhs_ty,
1555-
TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
1556-
_ => return None,
1557-
},
1558-
BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => return None,
1559-
BinaryOp::CmpOp(CmpOp::Ord { .. })
1560-
| BinaryOp::Assignment { op: Some(_) }
1561-
| BinaryOp::ArithOp(_) => match self.resolve_ty_shallow(&lhs_ty).kind(Interner) {
1562-
TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
1563-
TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
1564-
_ => return None,
1565-
},
1566-
})
1567-
}
1568-
15691487
/// Dereferences a single level of immutable referencing.
15701488
fn deref_ty_if_possible(&mut self, ty: &Ty) -> Ty {
15711489
let ty = self.resolve_ty_shallow(ty);

0 commit comments

Comments
 (0)