Skip to content

Commit 219519c

Browse files
committed
support calls on opaque types :<
1 parent cf224ea commit 219519c

File tree

24 files changed

+454
-139
lines changed

24 files changed

+454
-139
lines changed

compiler/rustc_hir_analysis/src/autoderef.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
6868
return None;
6969
}
7070

71-
if self.state.cur_ty.is_ty_var() {
71+
if let &ty::Infer(ty::TyVar(vid)) = self.state.cur_ty.kind()
72+
&& !self.infcx.has_opaques_with_sub_unified_hidden_type(vid)
73+
{
7274
return None;
7375
}
7476

@@ -160,7 +162,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
160162
self.param_env,
161163
ty::Binder::dummy(trait_ref),
162164
);
163-
if !self.infcx.next_trait_solver() && !self.infcx.predicate_may_hold(&obligation) {
165+
if !self.infcx.predicate_may_hold_opaque_types_jank(&obligation) {
164166
debug!("overloaded_deref_ty: cannot match obligation");
165167
return None;
166168
}

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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,15 @@ 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+
if !self.has_opaques_with_sub_unified_hidden_type(vid) {
305+
self.type_must_be_known_at_this_point(autoderef.span(), adjusted_ty);
306+
return None;
307+
}
308+
}
309+
300310
ty::Error(_) => {
301311
return None;
302312
}
@@ -367,35 +377,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
367377
Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
368378
});
369379

370-
if let Some(ok) = self.lookup_method_for_operator(
380+
let Some(ok) = self.lookup_method_for_operator(
371381
self.misc(call_expr.span),
372382
method_name,
373383
trait_def_id,
374384
adjusted_ty,
375385
opt_input_type,
376-
) {
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-
}
386+
) else {
387+
continue;
388+
};
389+
let method = self.register_infer_ok_obligations(ok);
390+
let mut autoref = None;
391+
if borrow {
392+
// Check for &self vs &mut self in the method signature. Since this is either
393+
// the Fn or FnMut trait, it should be one of those.
394+
let ty::Ref(_, _, mutbl) = *method.sig.inputs()[0].kind() else {
395+
bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut")
396+
};
396397

397-
return Some((autoref, method));
398+
// For initial two-phase borrow
399+
// deployment, conservatively omit
400+
// overloaded function call ops.
401+
let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::No);
402+
403+
autoref = Some(Adjustment {
404+
kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
405+
target: method.sig.inputs()[0],
406+
});
398407
}
408+
409+
return Some((autoref, method));
399410
}
400411

401412
None

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_hir_typeck/src/method/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
360360
);
361361

362362
// Now we want to know if this can be matched
363-
if !self.predicate_may_hold(&obligation) {
363+
if !self.predicate_may_hold_opaque_types_jank(&obligation) {
364364
debug!("--> Cannot match obligation");
365365
// Cannot be matched, no such method resolution is possible.
366366
return None;

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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,60 @@ impl<'tcx> InferCtxt<'tcx> {
10041004
self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect()
10051005
}
10061006

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

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

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use crate::delegate::SolverDelegate;
2323
use crate::solve::inspect::ProbeKind;
2424
use crate::solve::{
2525
BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
26-
MaybeCause, NoSolution, ParamEnvSource, QueryResult, has_no_inference_or_external_constraints,
26+
MaybeCause, NoSolution, OpaqueTypesJank, ParamEnvSource, QueryResult,
27+
has_no_inference_or_external_constraints,
2728
};
2829

2930
enum AliasBoundKind {
@@ -474,7 +475,7 @@ where
474475
//
475476
// cc trait-system-refactor-initiative#105
476477
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
477-
let certainty = Certainty::Maybe(cause);
478+
let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood };
478479
self.probe_trait_candidate(source)
479480
.enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
480481
}
@@ -974,11 +975,12 @@ where
974975
candidates: &mut Vec<Candidate<I>>,
975976
) {
976977
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;
978+
let opaque_types = self.opaques_with_sub_unified_hidden_type(self_ty);
979+
if opaque_types.is_empty() {
980+
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
981+
}
982+
983+
for &alias_ty in &opaque_types {
982984
debug!("self ty is sub unified with {alias_ty:?}");
983985

984986
struct ReplaceOpaque<I: Interner> {
@@ -1028,10 +1030,11 @@ where
10281030
}
10291031
}
10301032

1031-
// We also need to consider blanket impls for not-yet-defined opaque types.
1033+
// If the self type is sub unified with any opaque type, we also look at blanket
1034+
// impls for it.
10321035
//
10331036
// 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() {
1037+
if assemble_from.should_assemble_impl_candidates() {
10351038
let cx = self.cx();
10361039
cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
10371040
// For every `default impl`, there's always a non-default `impl`
@@ -1062,7 +1065,15 @@ where
10621065
}
10631066

10641067
if candidates.is_empty() {
1065-
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
1068+
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
1069+
let certainty = Certainty::Maybe {
1070+
cause: MaybeCause::Ambiguity,
1071+
opaque_types_jank: OpaqueTypesJank::ErrorIfRigidSelfTy,
1072+
};
1073+
candidates
1074+
.extend(self.probe_trait_candidate(source).enter(|this| {
1075+
this.evaluate_added_goals_and_make_canonical_response(certainty)
1076+
}));
10661077
}
10671078
}
10681079

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_index::IndexVec;
1515
use rustc_type_ir::data_structures::HashSet;
1616
use rustc_type_ir::inherent::*;
1717
use rustc_type_ir::relate::solver_relating::RelateExt;
18+
use rustc_type_ir::solve::OpaqueTypesJank;
1819
use rustc_type_ir::{
1920
self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
2021
TypeFoldable,
@@ -141,8 +142,10 @@ where
141142
}
142143
};
143144

144-
if let Certainty::Maybe(cause @ MaybeCause::Overflow { keep_constraints: false, .. }) =
145-
certainty
145+
if let Certainty::Maybe {
146+
cause: cause @ MaybeCause::Overflow { keep_constraints: false, .. },
147+
opaque_types_jank,
148+
} = certainty
146149
{
147150
// If we have overflow, it's probable that we're substituting a type
148151
// into itself infinitely and any partial substitutions in the query
@@ -155,7 +158,7 @@ where
155158
//
156159
// Changing this to retain some constraints in the future
157160
// won't be a breaking change, so this is good enough for now.
158-
return Ok(self.make_ambiguous_response_no_constraints(cause));
161+
return Ok(self.make_ambiguous_response_no_constraints(cause, opaque_types_jank));
159162
}
160163

161164
let external_constraints =
@@ -199,10 +202,13 @@ where
199202
.count();
200203
if num_non_region_vars > self.cx().recursion_limit() {
201204
debug!(?num_non_region_vars, "too many inference variables -> overflow");
202-
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow {
203-
suggest_increasing_limit: true,
204-
keep_constraints: false,
205-
}));
205+
return Ok(self.make_ambiguous_response_no_constraints(
206+
MaybeCause::Overflow {
207+
suggest_increasing_limit: true,
208+
keep_constraints: false,
209+
},
210+
OpaqueTypesJank::AllGood,
211+
));
206212
}
207213
}
208214
}
@@ -216,13 +222,14 @@ where
216222
/// ambiguity but return constrained variables to guide inference.
217223
pub(in crate::solve) fn make_ambiguous_response_no_constraints(
218224
&self,
219-
maybe_cause: MaybeCause,
225+
cause: MaybeCause,
226+
opaque_types_jank: OpaqueTypesJank,
220227
) -> CanonicalResponse<I> {
221228
response_no_constraints_raw(
222229
self.cx(),
223230
self.max_input_universe,
224231
self.variables,
225-
Certainty::Maybe(maybe_cause),
232+
Certainty::Maybe { cause, opaque_types_jank },
226233
)
227234
}
228235

0 commit comments

Comments
 (0)