Skip to content

Commit f5ed330

Browse files
compiler-errorslcnr
authored andcommitted
Incompletely allow overloaded call from opaque when self type bottoms out in infer
1 parent dfa06a2 commit f5ed330

File tree

2 files changed

+144
-42
lines changed

2 files changed

+144
-42
lines changed

compiler/rustc_hir_typeck/src/callee.rs

+127-42
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_middle::ty::adjustment::{
1414
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
1515
use rustc_middle::{bug, span_bug};
1616
use rustc_span::def_id::LocalDefId;
17-
use rustc_span::{Ident, Span, sym};
17+
use rustc_span::{Ident, Span, Symbol, sym};
1818
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
1919
use rustc_trait_selection::infer::InferCtxtExt as _;
2020
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -66,7 +66,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6666
arg_exprs: &'tcx [hir::Expr<'tcx>],
6767
expected: Expectation<'tcx>,
6868
) -> Ty<'tcx> {
69-
let original_callee_ty = match &callee_expr.kind {
69+
let expr_ty = match &callee_expr.kind {
7070
hir::ExprKind::Path(hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)) => self
7171
.check_expr_with_expectation_and_args(
7272
callee_expr,
@@ -76,8 +76,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7676
_ => self.check_expr(callee_expr),
7777
};
7878

79-
let expr_ty = self.structurally_resolve_type(call_expr.span, original_callee_ty);
80-
8179
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
8280
let mut result = None;
8381
while result.is_none() && autoderef.next().is_some() {
@@ -87,14 +85,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8785

8886
let output = match result {
8987
None => {
88+
// First report an ambiguity error if possible.
89+
let expr_ty = self.structurally_resolve_type(call_expr.span, expr_ty);
90+
9091
// this will report an error since original_callee_ty is not a fn
91-
self.confirm_builtin_call(
92-
call_expr,
93-
callee_expr,
94-
original_callee_ty,
95-
arg_exprs,
96-
expected,
97-
)
92+
self.confirm_builtin_call(call_expr, callee_expr, expr_ty, arg_exprs, expected)
9893
}
9994

10095
Some(CallStep::Builtin(callee_ty)) => {
@@ -129,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
129124
autoderef: &Autoderef<'a, 'tcx>,
130125
) -> Option<CallStep<'tcx>> {
131126
let adjusted_ty =
132-
self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
127+
self.try_structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
133128

134129
// If the callee is a bare function or a closure, then we're all set.
135130
match *adjusted_ty.kind() {
@@ -226,6 +221,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
226221
return None;
227222
}
228223

224+
// We only want to confirm a call step here if the infer var
225+
// originated from the defining use of an opaque.
226+
ty::Infer(ty::TyVar(vid))
227+
if let Some(alias_ty) = self.find_sup_as_registered_opaque(vid) =>
228+
{
229+
return self
230+
.try_overloaded_call_traits_for_alias(call_expr, alias_ty, arg_exprs)
231+
.map(|(autoref, method)| {
232+
let mut adjustments = self.adjust_steps(autoderef);
233+
adjustments.extend(autoref);
234+
self.apply_adjustments(callee_expr, adjustments);
235+
CallStep::Overloaded(method)
236+
});
237+
}
238+
239+
ty::Infer(_) => {
240+
return None;
241+
}
242+
229243
ty::Error(_) => {
230244
return None;
231245
}
@@ -290,40 +304,111 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
290304

291305
// Try the options that are least restrictive on the caller first.
292306
for (opt_trait_def_id, method_name, borrow) in call_trait_choices {
293-
let Some(trait_def_id) = opt_trait_def_id else { continue };
307+
if let Some(confirmed) = self.try_overloaded_call_trait(
308+
call_expr,
309+
adjusted_ty,
310+
opt_arg_exprs,
311+
opt_trait_def_id,
312+
method_name,
313+
borrow,
314+
) {
315+
return Some(confirmed);
316+
}
317+
}
318+
319+
None
320+
}
294321

295-
let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
296-
Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
322+
fn try_overloaded_call_trait(
323+
&self,
324+
call_expr: &hir::Expr<'_>,
325+
call_ty: Ty<'tcx>,
326+
opt_arg_exprs: Option<&'tcx [hir::Expr<'tcx>]>,
327+
opt_trait_def_id: Option<DefId>,
328+
method_name: Symbol,
329+
borrow: bool,
330+
) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
331+
let Some(trait_def_id) = opt_trait_def_id else {
332+
return None;
333+
};
334+
335+
let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
336+
Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
337+
});
338+
339+
let Some(ok) = self.lookup_method_in_trait(
340+
self.misc(call_expr.span),
341+
Ident::with_dummy_span(method_name),
342+
trait_def_id,
343+
call_ty,
344+
opt_input_type,
345+
) else {
346+
return None;
347+
};
348+
let method = self.register_infer_ok_obligations(ok);
349+
let mut autoref = None;
350+
if borrow {
351+
// Check for &self vs &mut self in the method signature. Since this is either
352+
// the Fn or FnMut trait, it should be one of those.
353+
let ty::Ref(_, _, mutbl) = method.sig.inputs()[0].kind() else {
354+
bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut")
355+
};
356+
357+
// For initial two-phase borrow
358+
// deployment, conservatively omit
359+
// overloaded function call ops.
360+
let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::No);
361+
362+
autoref = Some(Adjustment {
363+
kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
364+
target: method.sig.inputs()[0],
297365
});
366+
}
298367

299-
if let Some(ok) = self.lookup_method_in_trait(
300-
self.misc(call_expr.span),
301-
Ident::with_dummy_span(method_name),
302-
trait_def_id,
303-
adjusted_ty,
304-
opt_input_type,
305-
) {
306-
let method = self.register_infer_ok_obligations(ok);
307-
let mut autoref = None;
308-
if borrow {
309-
// Check for &self vs &mut self in the method signature. Since this is either
310-
// the Fn or FnMut trait, it should be one of those.
311-
let ty::Ref(_, _, mutbl) = method.sig.inputs()[0].kind() else {
312-
bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut")
313-
};
314-
315-
// For initial two-phase borrow
316-
// deployment, conservatively omit
317-
// overloaded function call ops.
318-
let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::No);
319-
320-
autoref = Some(Adjustment {
321-
kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
322-
target: method.sig.inputs()[0],
323-
});
324-
}
368+
Some((autoref, method))
369+
}
325370

326-
return Some((autoref, method));
371+
fn try_overloaded_call_traits_for_alias(
372+
&self,
373+
call_expr: &'tcx hir::Expr<'tcx>,
374+
alias_ty: ty::AliasTy<'tcx>,
375+
arg_exprs: &'tcx [rustc_hir::Expr<'tcx>],
376+
) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
377+
let call_ty = alias_ty.to_ty(self.tcx);
378+
379+
let call_traits = [
380+
(self.tcx.lang_items().fn_trait(), sym::call, true),
381+
(self.tcx.lang_items().fn_mut_trait(), sym::call_mut, true),
382+
(self.tcx.lang_items().fn_once_trait(), sym::call_once, false),
383+
(self.tcx.lang_items().async_fn_trait(), sym::async_call, true),
384+
(self.tcx.lang_items().async_fn_mut_trait(), sym::async_call_mut, true),
385+
(self.tcx.lang_items().async_fn_once_trait(), sym::async_call_once, false),
386+
];
387+
// We only want to try a call trait if it shows up in the bounds
388+
// of the opaque. We confirm the first one that shows up in the
389+
// bounds list, which can lead to inference weirdness but doesn't
390+
// matter today.
391+
for clause in
392+
self.tcx.item_self_bounds(alias_ty.def_id).iter_instantiated(self.tcx, alias_ty.args)
393+
{
394+
let Some(poly_trait_ref) = clause.as_trait_clause() else {
395+
continue;
396+
};
397+
398+
if let Some(&(opt_trait_def_id, method_name, borrow)) =
399+
call_traits.iter().find(|(trait_def_id, _, _)| {
400+
trait_def_id.is_some_and(|trait_def_id| trait_def_id == poly_trait_ref.def_id())
401+
})
402+
&& let Some(confirmed) = self.try_overloaded_call_trait(
403+
call_expr,
404+
call_ty,
405+
Some(arg_exprs),
406+
opt_trait_def_id,
407+
method_name,
408+
borrow,
409+
)
410+
{
411+
return Some(confirmed);
327412
}
328413
}
329414

compiler/rustc_infer/src/infer/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,23 @@ impl<'tcx> InferCtxt<'tcx> {
968968
self.inner.borrow().opaque_type_storage.opaque_types.clone()
969969
}
970970

971+
pub fn find_sup_as_registered_opaque(&self, ty_vid: TyVid) -> Option<ty::AliasTy<'tcx>> {
972+
let ty_sub_vid = self.sub_root_var(ty_vid);
973+
let opaques = self.inner.borrow().opaque_type_storage.opaque_types.clone();
974+
opaques
975+
.into_iter()
976+
.find(|(_, hidden_ty)| {
977+
if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.ty.kind()
978+
&& self.sub_root_var(hidden_vid) == ty_sub_vid
979+
{
980+
true
981+
} else {
982+
false
983+
}
984+
})
985+
.map(|(key, _)| ty::AliasTy::new_from_args(self.tcx, key.def_id.to_def_id(), key.args))
986+
}
987+
971988
#[inline(always)]
972989
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
973990
debug_assert!(!self.next_trait_solver());

0 commit comments

Comments
 (0)