Skip to content

Commit 102a7d6

Browse files
committed
support calls on opaque types :<
1 parent cf224ea commit 102a7d6

File tree

11 files changed

+292
-85
lines changed

11 files changed

+292
-85
lines changed

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 123 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::ty::adjustment::{
1515
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
1616
use rustc_middle::{bug, span_bug};
1717
use rustc_span::def_id::LocalDefId;
18-
use rustc_span::{Span, sym};
18+
use rustc_span::{Span, Symbol, sym};
1919
use rustc_target::spec::{AbiMap, AbiMapping};
2020
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
2121
use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -78,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7878
_ => self.check_expr(callee_expr),
7979
};
8080

81-
let expr_ty = self.structurally_resolve_type(call_expr.span, original_callee_ty);
81+
let expr_ty = self.try_structurally_resolve_type(call_expr.span, original_callee_ty);
8282

8383
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
8484
let mut result = None;
@@ -200,7 +200,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
200200
arg_exprs: &'tcx [hir::Expr<'tcx>],
201201
autoderef: &Autoderef<'a, 'tcx>,
202202
) -> Option<CallStep<'tcx>> {
203-
let adjusted_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty());
203+
let adjusted_ty =
204+
self.try_structurally_resolve_type(autoderef.span(), autoderef.final_ty());
204205

205206
// If the callee is a function pointer or a closure, then we're all set.
206207
match *adjusted_ty.kind() {
@@ -297,6 +298,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
297298
return None;
298299
}
299300

301+
ty::Infer(ty::TyVar(vid)) => {
302+
// If we end up with an inference variable which is not the hidden type of
303+
// an opaque, emit an error.
304+
let opaque_types = self.opaques_with_sub_unified_hidden_type(vid);
305+
if opaque_types.is_empty() {
306+
self.type_must_be_known_at_this_point(autoderef.span(), adjusted_ty);
307+
return None;
308+
} else {
309+
return self
310+
.try_overloaded_call_traits_for_alias(
311+
call_expr,
312+
adjusted_ty,
313+
opaque_types,
314+
arg_exprs,
315+
)
316+
.map(|(autoref, method)| {
317+
let mut adjustments = self.adjust_steps(autoderef);
318+
adjustments.extend(autoref);
319+
self.apply_adjustments(callee_expr, adjustments);
320+
CallStep::Overloaded(method)
321+
});
322+
}
323+
}
324+
300325
ty::Error(_) => {
301326
return None;
302327
}
@@ -363,38 +388,104 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
363388
for (opt_trait_def_id, method_name, borrow) in call_trait_choices {
364389
let Some(trait_def_id) = opt_trait_def_id else { continue };
365390

366-
let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
367-
Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
368-
});
369-
370-
if let Some(ok) = self.lookup_method_for_operator(
371-
self.misc(call_expr.span),
372-
method_name,
373-
trait_def_id,
391+
if let Some(result) = self.try_overloaded_call_trait(
392+
call_expr,
374393
adjusted_ty,
375-
opt_input_type,
394+
opt_arg_exprs,
395+
trait_def_id,
396+
method_name,
397+
borrow,
376398
) {
377-
let method = self.register_infer_ok_obligations(ok);
378-
let mut autoref = None;
379-
if borrow {
380-
// Check for &self vs &mut self in the method signature. Since this is either
381-
// the Fn or FnMut trait, it should be one of those.
382-
let ty::Ref(_, _, mutbl) = method.sig.inputs()[0].kind() else {
383-
bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut")
384-
};
385-
386-
// For initial two-phase borrow
387-
// deployment, conservatively omit
388-
// overloaded function call ops.
389-
let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::No);
390-
391-
autoref = Some(Adjustment {
392-
kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
393-
target: method.sig.inputs()[0],
394-
});
395-
}
399+
return Some(result);
400+
}
401+
}
402+
403+
None
404+
}
405+
406+
fn try_overloaded_call_trait(
407+
&self,
408+
call_expr: &hir::Expr<'_>,
409+
call_ty: Ty<'tcx>,
410+
opt_arg_exprs: Option<&'tcx [hir::Expr<'tcx>]>,
411+
trait_def_id: DefId,
412+
method_name: Symbol,
413+
borrow: bool,
414+
) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
415+
let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
416+
Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
417+
});
418+
419+
let Some(ok) = self.lookup_method_for_operator(
420+
self.misc(call_expr.span),
421+
method_name,
422+
trait_def_id,
423+
call_ty,
424+
opt_input_type,
425+
) else {
426+
return None;
427+
};
428+
let method = self.register_infer_ok_obligations(ok);
429+
let mut autoref = None;
430+
if borrow {
431+
// Check for &self vs &mut self in the method signature. Since this is either
432+
// the Fn or FnMut trait, it should be one of those.
433+
let ty::Ref(_, _, mutbl) = *method.sig.inputs()[0].kind() else {
434+
bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut")
435+
};
436+
437+
// For initial two-phase borrow
438+
// deployment, conservatively omit
439+
// overloaded function call ops.
440+
let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::No);
441+
442+
autoref = Some(Adjustment {
443+
kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
444+
target: method.sig.inputs()[0],
445+
});
446+
}
396447

397-
return Some((autoref, method));
448+
Some((autoref, method))
449+
}
450+
451+
fn try_overloaded_call_traits_for_alias(
452+
&self,
453+
call_expr: &'tcx hir::Expr<'tcx>,
454+
call_ty: Ty<'tcx>,
455+
opaque_types: Vec<ty::AliasTy<'tcx>>,
456+
arg_exprs: &'tcx [rustc_hir::Expr<'tcx>],
457+
) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
458+
let call_traits = [
459+
(self.tcx.lang_items().fn_trait(), sym::call, true),
460+
(self.tcx.lang_items().fn_mut_trait(), sym::call_mut, true),
461+
(self.tcx.lang_items().fn_once_trait(), sym::call_once, false),
462+
(self.tcx.lang_items().async_fn_trait(), sym::async_call, true),
463+
(self.tcx.lang_items().async_fn_mut_trait(), sym::async_call_mut, true),
464+
(self.tcx.lang_items().async_fn_once_trait(), sym::async_call_once, false),
465+
];
466+
// Test for iteration order.
467+
for (trait_def_id, method_name, borrow) in call_traits {
468+
let Some(trait_def_id) = trait_def_id else { continue };
469+
for clause in opaque_types.iter().flat_map(|alias_ty| {
470+
self.tcx
471+
.item_self_bounds(alias_ty.def_id)
472+
.iter_instantiated(self.tcx, alias_ty.args)
473+
}) {
474+
let Some(poly_trait_ref) = clause.as_trait_clause() else {
475+
continue;
476+
};
477+
if poly_trait_ref.def_id() == trait_def_id {
478+
if let Some(confirmed) = self.try_overloaded_call_trait(
479+
call_expr,
480+
call_ty,
481+
Some(arg_exprs),
482+
trait_def_id,
483+
method_name,
484+
borrow,
485+
) {
486+
return Some(confirmed);
487+
}
488+
}
398489
}
399490
}
400491

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,24 +1469,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14691469
pub(crate) fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
14701470
let ty = self.try_structurally_resolve_type(sp, ty);
14711471

1472-
if !ty.is_ty_var() {
1473-
ty
1474-
} else {
1475-
let e = self.tainted_by_errors().unwrap_or_else(|| {
1476-
self.err_ctxt()
1477-
.emit_inference_failure_err(
1478-
self.body_id,
1479-
sp,
1480-
ty.into(),
1481-
TypeAnnotationNeeded::E0282,
1482-
true,
1483-
)
1484-
.emit()
1485-
});
1486-
let err = Ty::new_error(self.tcx, e);
1487-
self.demand_suptype(sp, err, ty);
1488-
err
1489-
}
1472+
if !ty.is_ty_var() { ty } else { self.type_must_be_known_at_this_point(sp, ty) }
1473+
}
1474+
1475+
#[cold]
1476+
pub(crate) fn type_must_be_known_at_this_point(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
1477+
let guar = self.tainted_by_errors().unwrap_or_else(|| {
1478+
self.err_ctxt()
1479+
.emit_inference_failure_err(
1480+
self.body_id,
1481+
sp,
1482+
ty.into(),
1483+
TypeAnnotationNeeded::E0282,
1484+
true,
1485+
)
1486+
.emit()
1487+
});
1488+
let err = Ty::new_error(self.tcx, guar);
1489+
self.demand_suptype(sp, err, ty);
1490+
err
14901491
}
14911492

14921493
pub(crate) fn structurally_resolve_const(

compiler/rustc_infer/src/infer/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
302302
.map(|(k, h)| (k, h.ty))
303303
.collect()
304304
}
305+
fn opaques_with_sub_unified_hidden_type(&self, ty: ty::TyVid) -> Vec<ty::AliasTy<'tcx>> {
306+
self.opaques_with_sub_unified_hidden_type(ty)
307+
}
305308

306309
fn register_hidden_type_in_storage(
307310
&self,

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,45 @@ impl<'tcx> InferCtxt<'tcx> {
10041004
self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect()
10051005
}
10061006

1007+
/// Searches for an opaque type key whose hidden type is related to `ty_vid`.
1008+
///
1009+
/// This only checks for a subtype relation, it does not require equality.
1010+
pub fn opaques_with_sub_unified_hidden_type(&self, ty_vid: TyVid) -> Vec<ty::AliasTy<'tcx>> {
1011+
// Avoid accidentally allowing more code to compile with the old solver.
1012+
if !self.next_trait_solver() {
1013+
return vec![];
1014+
}
1015+
1016+
let opaque_types = self.clone_opaque_types();
1017+
if opaque_types.is_empty() {
1018+
return vec![];
1019+
}
1020+
1021+
let ty_sub_vid = self.sub_unification_table_root_var(ty_vid);
1022+
let inner = &mut *self.inner.borrow_mut();
1023+
// This is iffy, can't call `type_variables()` as we're already
1024+
// borrowing the `opaque_type_storage` here.
1025+
let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log);
1026+
inner
1027+
.opaque_type_storage
1028+
.iter_opaque_types()
1029+
.filter_map(|(key, hidden_ty)| {
1030+
if let ty::Infer(ty::TyVar(hidden_vid)) = *hidden_ty.ty.kind() {
1031+
let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid);
1032+
if opaque_sub_vid == ty_sub_vid {
1033+
return Some(ty::AliasTy::new_from_args(
1034+
self.tcx,
1035+
key.def_id.into(),
1036+
key.args,
1037+
));
1038+
}
1039+
}
1040+
1041+
None
1042+
})
1043+
.collect()
1044+
}
1045+
10071046
#[inline(always)]
10081047
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
10091048
debug_assert!(!self.next_trait_solver());

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -974,11 +974,8 @@ where
974974
candidates: &mut Vec<Candidate<I>>,
975975
) {
976976
let self_ty = goal.predicate.self_ty();
977-
// If the self type is sub unified with any opaque type, we
978-
// also look at blanket impls for it.
979-
let mut assemble_blanket_impls = false;
980-
for alias_ty in self.opaques_with_sub_unified_hidden_type(self_ty) {
981-
assemble_blanket_impls = true;
977+
let opaque_types = self.opaques_with_sub_unified_hidden_type(self_ty);
978+
for &alias_ty in &opaque_types {
982979
debug!("self ty is sub unified with {alias_ty:?}");
983980

984981
struct ReplaceOpaque<I: Interner> {
@@ -1028,10 +1025,11 @@ where
10281025
}
10291026
}
10301027

1031-
// We also need to consider blanket impls for not-yet-defined opaque types.
1028+
// If the self type is sub unified with any opaque type, we also look at blanket
1029+
// impls for it.
10321030
//
10331031
// See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example.
1034-
if assemble_blanket_impls && assemble_from.should_assemble_impl_candidates() {
1032+
if !opaque_types.is_empty() && assemble_from.should_assemble_impl_candidates() {
10351033
let cx = self.cx();
10361034
cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
10371035
// For every `default impl`, there's always a non-default `impl`

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,28 +1184,12 @@ where
11841184
pub(crate) fn opaques_with_sub_unified_hidden_type(
11851185
&self,
11861186
self_ty: I::Ty,
1187-
) -> impl Iterator<Item = ty::AliasTy<I>> + use<'a, D, I> {
1188-
let delegate = self.delegate;
1189-
delegate
1190-
.clone_opaque_types_lookup_table()
1191-
.into_iter()
1192-
.chain(delegate.clone_duplicate_opaque_types())
1193-
.filter_map(move |(key, hidden_ty)| {
1194-
if let ty::Infer(ty::TyVar(self_vid)) = self_ty.kind() {
1195-
if let ty::Infer(ty::TyVar(hidden_vid)) = hidden_ty.kind() {
1196-
if delegate.sub_unification_table_root_var(self_vid)
1197-
== delegate.sub_unification_table_root_var(hidden_vid)
1198-
{
1199-
return Some(ty::AliasTy::new_from_args(
1200-
delegate.cx(),
1201-
key.def_id.into(),
1202-
key.args,
1203-
));
1204-
}
1205-
}
1206-
}
1207-
None
1208-
})
1187+
) -> Vec<ty::AliasTy<I>> {
1188+
if let ty::Infer(ty::TyVar(vid)) = self_ty.kind() {
1189+
self.delegate.opaques_with_sub_unified_hidden_type(vid)
1190+
} else {
1191+
vec![]
1192+
}
12091193
}
12101194
}
12111195

compiler/rustc_type_ir/src/infer_ctxt.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::fold::TypeFoldable;
66
use crate::inherent::*;
77
use crate::relate::RelateResult;
88
use crate::relate::combine::PredicateEmittingRelation;
9-
use crate::{self as ty, Interner};
9+
use crate::{self as ty, Interner, TyVid};
1010

1111
/// The current typing mode of an inference context. We unfortunately have some
1212
/// slightly different typing rules depending on the current context. See the
@@ -271,6 +271,7 @@ pub trait InferCtxtLike: Sized {
271271
&self,
272272
prev_entries: Self::OpaqueTypeStorageEntries,
273273
) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
274+
fn opaques_with_sub_unified_hidden_type(&self, ty: TyVid) -> Vec<ty::AliasTy<Self::Interner>>;
274275

275276
fn register_hidden_type_in_storage(
276277
&self,

0 commit comments

Comments
 (0)