Skip to content

Commit eb4939e

Browse files
committed
Support overloaded deref MIR lowering
1 parent 9564773 commit eb4939e

File tree

18 files changed

+398
-86
lines changed

18 files changed

+398
-86
lines changed

crates/hir-def/src/body/lower.rs

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -609,21 +609,12 @@ impl ExprCollector<'_> {
609609
fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId {
610610
let (try_branch, cf_continue, cf_break, try_from_residual) = 'if_chain: {
611611
if let Some(try_branch) = LangItem::TryTraitBranch.path(self.db, self.krate) {
612-
if let Some(cf_continue) =
613-
LangItem::ControlFlowContinue.path(self.db, self.krate)
614-
{
615-
if let Some(cf_break) =
616-
LangItem::ControlFlowBreak.path(self.db, self.krate)
617-
{
612+
if let Some(cf_continue) = LangItem::ControlFlowContinue.path(self.db, self.krate) {
613+
if let Some(cf_break) = LangItem::ControlFlowBreak.path(self.db, self.krate) {
618614
if let Some(try_from_residual) =
619615
LangItem::TryTraitFromResidual.path(self.db, self.krate)
620616
{
621-
break 'if_chain (
622-
try_branch,
623-
cf_continue,
624-
cf_break,
625-
try_from_residual,
626-
);
617+
break 'if_chain (try_branch, cf_continue, cf_break, try_from_residual);
627618
}
628619
}
629620
}
@@ -634,15 +625,10 @@ impl ExprCollector<'_> {
634625
let operand = self.collect_expr_opt(e.expr());
635626
let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr.clone());
636627
let expr = self.alloc_expr(
637-
Expr::Call {
638-
callee: try_branch,
639-
args: Box::new([operand]),
640-
is_assignee_expr: false,
641-
},
628+
Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false },
642629
syntax_ptr.clone(),
643630
);
644-
let continue_binding =
645-
self.alloc_binding(name![v1], BindingAnnotation::Unannotated);
631+
let continue_binding = self.alloc_binding(name![v1], BindingAnnotation::Unannotated);
646632
let continue_bpat =
647633
self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None });
648634
self.add_definition_to_binding(continue_binding, continue_bpat);
@@ -656,8 +642,7 @@ impl ExprCollector<'_> {
656642
expr: self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone()),
657643
};
658644
let break_binding = self.alloc_binding(name![v1], BindingAnnotation::Unannotated);
659-
let break_bpat =
660-
self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
645+
let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
661646
self.add_definition_to_binding(break_binding, break_bpat);
662647
let break_arm = MatchArm {
663648
pat: self.alloc_pat_desugared(Pat::TupleStruct {
@@ -667,10 +652,8 @@ impl ExprCollector<'_> {
667652
}),
668653
guard: None,
669654
expr: {
670-
let x =
671-
self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone());
672-
let callee =
673-
self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone());
655+
let x = self.alloc_expr(Expr::Path(Path::from(name![v1])), syntax_ptr.clone());
656+
let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone());
674657
let result = self.alloc_expr(
675658
Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false },
676659
syntax_ptr.clone(),
@@ -1030,8 +1013,9 @@ impl ExprCollector<'_> {
10301013
.collect(),
10311014
}
10321015
}
1033-
ast::Pat::LiteralPat(lit) => 'b: {
1034-
if let Some(ast_lit) = lit.literal() {
1016+
// FIXME: rustfmt removes this label if it is a block and not a loop
1017+
ast::Pat::LiteralPat(lit) => 'b: loop {
1018+
break if let Some(ast_lit) = lit.literal() {
10351019
let mut hir_lit: Literal = ast_lit.kind().into();
10361020
if lit.minus_token().is_some() {
10371021
let Some(h) = hir_lit.negate() else {
@@ -1045,8 +1029,8 @@ impl ExprCollector<'_> {
10451029
Pat::Lit(expr_id)
10461030
} else {
10471031
Pat::Missing
1048-
}
1049-
}
1032+
};
1033+
},
10501034
ast::Pat::RestPat(_) => {
10511035
// `RestPat` requires special handling and should not be mapped
10521036
// to a Pat. Here we are using `Pat::Missing` as a fallback for

crates/hir-ty/src/consteval/tests.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,7 @@ fn reference_autoderef() {
166166

167167
#[test]
168168
fn overloaded_deref() {
169-
// FIXME: We should support this.
170-
check_fail(
169+
check_number(
171170
r#"
172171
//- minicore: deref_mut
173172
struct Foo;
@@ -185,9 +184,7 @@ fn overloaded_deref() {
185184
*y + *x
186185
};
187186
"#,
188-
ConstEvalError::MirLowerError(MirLowerError::NotSupported(
189-
"explicit overloaded deref".into(),
190-
)),
187+
10,
191188
);
192189
}
193190

@@ -698,7 +695,7 @@ fn pattern_matching_literal() {
698695
}
699696
const GOAL: i32 = f(-1) + f(1) + f(0) + f(-5);
700697
"#,
701-
211
698+
211,
702699
);
703700
check_number(
704701
r#"
@@ -711,7 +708,7 @@ fn pattern_matching_literal() {
711708
}
712709
const GOAL: u8 = f("foo") + f("bar");
713710
"#,
714-
11
711+
11,
715712
);
716713
}
717714

@@ -1116,6 +1113,22 @@ fn function_traits() {
11161113
"#,
11171114
15,
11181115
);
1116+
check_number(
1117+
r#"
1118+
//- minicore: coerce_unsized, fn
1119+
fn add2(x: u8) -> u8 {
1120+
x + 2
1121+
}
1122+
fn call(f: &dyn Fn(u8) -> u8, x: u8) -> u8 {
1123+
f(x)
1124+
}
1125+
fn call_mut(f: &mut dyn FnMut(u8) -> u8, x: u8) -> u8 {
1126+
f(x)
1127+
}
1128+
const GOAL: u8 = call(&add2, 3) + call_mut(&mut add2, 3);
1129+
"#,
1130+
10,
1131+
);
11191132
check_number(
11201133
r#"
11211134
//- minicore: fn

crates/hir-ty/src/infer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ mod expr;
5757
mod pat;
5858
mod coerce;
5959
mod closure;
60+
mod mutability;
6061

6162
/// The entry point of type inference.
6263
pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
@@ -99,6 +100,8 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
99100

100101
ctx.infer_body();
101102

103+
ctx.infer_mut_body();
104+
102105
Arc::new(ctx.resolve_all())
103106
}
104107

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

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -390,14 +390,28 @@ impl<'a> InferenceContext<'a> {
390390
if let Some(fn_x) = func {
391391
match fn_x {
392392
FnTrait::FnOnce => (),
393-
FnTrait::FnMut => adjustments.push(Adjustment::borrow(
394-
Mutability::Mut,
395-
derefed_callee.clone(),
396-
)),
397-
FnTrait::Fn => adjustments.push(Adjustment::borrow(
398-
Mutability::Not,
399-
derefed_callee.clone(),
400-
)),
393+
FnTrait::FnMut => {
394+
if !matches!(
395+
derefed_callee.kind(Interner),
396+
TyKind::Ref(Mutability::Mut, _, _)
397+
) {
398+
adjustments.push(Adjustment::borrow(
399+
Mutability::Mut,
400+
derefed_callee.clone(),
401+
));
402+
}
403+
}
404+
FnTrait::Fn => {
405+
if !matches!(
406+
derefed_callee.kind(Interner),
407+
TyKind::Ref(Mutability::Not, _, _)
408+
) {
409+
adjustments.push(Adjustment::borrow(
410+
Mutability::Not,
411+
derefed_callee.clone(),
412+
));
413+
}
414+
}
401415
}
402416
let trait_ = fn_x
403417
.get_id(self.db, self.trait_env.krate)
@@ -673,6 +687,23 @@ impl<'a> InferenceContext<'a> {
673687
// FIXME: Note down method resolution her
674688
match op {
675689
UnaryOp::Deref => {
690+
if let Some(deref_trait) = self
691+
.db
692+
.lang_item(self.table.trait_env.krate, LangItem::Deref)
693+
.and_then(|l| l.as_trait())
694+
{
695+
if let Some(deref_fn) =
696+
self.db.trait_data(deref_trait).method_by_name(&name![deref])
697+
{
698+
// FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
699+
// the mutability is not wrong, and will be fixed in `self.infer_mut`).
700+
self.write_method_resolution(
701+
tgt_expr,
702+
deref_fn,
703+
Substitution::empty(Interner),
704+
);
705+
}
706+
}
676707
autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
677708
}
678709
UnaryOp::Neg => {

0 commit comments

Comments
 (0)