Skip to content

Commit cc9a9f2

Browse files
Auto merge of #145993 - lcnr:allow-calling-opaques, r=<try>
`-Znext-solver` allow `ExprKind::Call` for not-yet defined opaques
2 parents d1ed52b + efde093 commit cc9a9f2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+971
-182
lines changed

compiler/rustc_hir_analysis/src/autoderef.rs

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

71-
if self.state.cur_ty.is_ty_var() {
71+
// We want to support method and function calls for `impl Deref<Target = ..>`.
72+
//
73+
// To do so we don't eagerly bail if the current type is the hidden type of an
74+
// opaque type and instead return `None` in `fn overloaded_deref_ty` if the
75+
// opaque does not have a `Deref` item-bound.
76+
if let &ty::Infer(ty::TyVar(vid)) = self.state.cur_ty.kind()
77+
&& !self.infcx.has_opaques_with_sub_unified_hidden_type(vid)
78+
{
7279
return None;
7380
}
7481

@@ -160,7 +167,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
160167
self.param_env,
161168
ty::Binder::dummy(trait_ref),
162169
);
163-
if !self.infcx.next_trait_solver() && !self.infcx.predicate_may_hold(&obligation) {
170+
// We detect whether the self type implements `Deref` before trying to
171+
// structurally normalize. We use `predicate_may_hold_opaque_types_jank`
172+
// to support not-yet-defined opaque types. It will succeed for `impl Deref`
173+
// but fail for `impl OtherTrait`.
174+
if !self.infcx.predicate_may_hold_opaque_types_jank(&obligation) {
164175
debug!("overloaded_deref_ty: cannot match obligation");
165176
return None;
166177
}

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use tracing::{debug, instrument};
2525
use super::method::MethodCallee;
2626
use super::method::probe::ProbeScope;
2727
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
28+
use crate::method::TreatNotYetDefinedOpaques;
2829
use crate::{errors, fluent_generated};
2930

3031
/// Checks that it is legal to call methods of the trait corresponding
@@ -78,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7879
_ => self.check_expr(callee_expr),
7980
};
8081

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

8384
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
8485
let mut result = None;
@@ -200,7 +201,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
200201
arg_exprs: &'tcx [hir::Expr<'tcx>],
201202
autoderef: &Autoderef<'a, 'tcx>,
202203
) -> Option<CallStep<'tcx>> {
203-
let adjusted_ty = self.structurally_resolve_type(autoderef.span(), autoderef.final_ty());
204+
let adjusted_ty =
205+
self.try_structurally_resolve_type(autoderef.span(), autoderef.final_ty());
204206

205207
// If the callee is a function pointer or a closure, then we're all set.
206208
match *adjusted_ty.kind() {
@@ -297,6 +299,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
297299
return None;
298300
}
299301

302+
ty::Infer(ty::TyVar(vid)) => {
303+
// If we end up with an inference variable which is not the hidden type of
304+
// an opaque, emit an error.
305+
if !self.has_opaques_with_sub_unified_hidden_type(vid) {
306+
self.type_must_be_known_at_this_point(autoderef.span(), adjusted_ty);
307+
return None;
308+
}
309+
}
310+
300311
ty::Error(_) => {
301312
return None;
302313
}
@@ -367,35 +378,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
367378
Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
368379
});
369380

370-
if let Some(ok) = self.lookup_method_for_operator(
381+
// We use `TreatNotYetDefinedOpaques::AsRigid` here so that if the `adjusted_ty`
382+
// is `Box<impl FnOnce()>` we choose `FnOnce` instead of `Fn`.
383+
let Some(ok) = self.lookup_method_for_operator(
371384
self.misc(call_expr.span),
372385
method_name,
373386
trait_def_id,
374387
adjusted_ty,
375388
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-
}
389+
TreatNotYetDefinedOpaques::AsRigid,
390+
) else {
391+
continue;
392+
};
393+
let method = self.register_infer_ok_obligations(ok);
394+
let mut autoref = None;
395+
if borrow {
396+
// Check for &self vs &mut self in the method signature. Since this is either
397+
// the Fn or FnMut trait, it should be one of those.
398+
let ty::Ref(_, _, mutbl) = *method.sig.inputs()[0].kind() else {
399+
bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut")
400+
};
396401

397-
return Some((autoref, method));
402+
// For initial two-phase borrow
403+
// deployment, conservatively omit
404+
// overloaded function call ops.
405+
let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::No);
406+
407+
autoref = Some(Adjustment {
408+
kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)),
409+
target: method.sig.inputs()[0],
410+
});
398411
}
412+
413+
return Some((autoref, method));
399414
}
400415

401416
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: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
317317
)?;
318318
Ok(pick)
319319
}
320+
}
321+
322+
/// Used by [FnCtxt::lookup_method_for_operator] with `-Znext-solver`.
323+
///
324+
/// With `AsRigid` we error on `impl Opaque: NotInItemBounds` while
325+
/// `AsInfer` just treats it as ambiguous and succeeds. This is necessary
326+
/// as we want [FnCtxt::check_expr_call] to treat not-yet-defined opaque
327+
/// types as rigid to support `impl Deref<Target = impl FnOnce()>` and
328+
/// `Box<impl FnOnce()>`. This is not necessary for other operators and
329+
/// we want to actually treat not-yet-defined opaques as infer vars whenever
330+
/// possible.
331+
#[derive(Debug)]
332+
pub(super) enum TreatNotYetDefinedOpaques {
333+
AsInfer,
334+
AsRigid,
335+
}
320336

337+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
321338
/// `lookup_method_in_trait` is used for overloaded operators.
322339
/// It does a very narrow slice of what the normal probe/confirm path does.
323340
/// In particular, it doesn't really do any probing: it simply constructs
@@ -331,6 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
331348
trait_def_id: DefId,
332349
self_ty: Ty<'tcx>,
333350
opt_rhs_ty: Option<Ty<'tcx>>,
351+
treat_opaques: TreatNotYetDefinedOpaques,
334352
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
335353
// Construct a trait-reference `self_ty : Trait<input_tys>`
336354
let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| match param.kind {
@@ -360,7 +378,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
360378
);
361379

362380
// Now we want to know if this can be matched
363-
if !self.predicate_may_hold(&obligation) {
381+
let matches_trait = match treat_opaques {
382+
TreatNotYetDefinedOpaques::AsInfer => self.predicate_may_hold(&obligation),
383+
TreatNotYetDefinedOpaques::AsRigid => {
384+
self.predicate_may_hold_opaque_types_jank(&obligation)
385+
}
386+
};
387+
388+
if !matches_trait {
364389
debug!("--> Cannot match obligation");
365390
// Cannot be matched, no such method resolution is possible.
366391
return None;

compiler/rustc_hir_typeck/src/op.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use {rustc_ast as ast, rustc_hir as hir};
2121
use super::FnCtxt;
2222
use super::method::MethodCallee;
2323
use crate::Expectation;
24+
use crate::method::TreatNotYetDefinedOpaques;
2425

2526
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2627
/// Checks a `a <op>= b`
@@ -974,8 +975,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
974975
},
975976
);
976977

977-
let method =
978-
self.lookup_method_for_operator(cause.clone(), opname, trait_did, lhs_ty, opt_rhs_ty);
978+
let method = self.lookup_method_for_operator(
979+
cause.clone(),
980+
opname,
981+
trait_did,
982+
lhs_ty,
983+
opt_rhs_ty,
984+
TreatNotYetDefinedOpaques::AsInfer,
985+
);
979986
match method {
980987
Some(ok) => {
981988
let method = self.register_infer_ok_obligations(ok);

compiler/rustc_hir_typeck/src/opaque_types.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -117,21 +117,25 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
117117
)
118118
}
119119
UsageKind::UnconstrainedHiddenType(hidden_type) => {
120-
let infer_var = hidden_type
121-
.ty
122-
.walk()
123-
.filter_map(ty::GenericArg::as_term)
124-
.find(|term| term.is_infer())
125-
.unwrap_or_else(|| hidden_type.ty.into());
126-
self.err_ctxt()
127-
.emit_inference_failure_err(
128-
self.body_id,
129-
hidden_type.span,
130-
infer_var,
131-
TypeAnnotationNeeded::E0282,
132-
false,
133-
)
134-
.emit()
120+
if let Some(guar) = self.tainted_by_errors() {
121+
guar
122+
} else {
123+
let infer_var = hidden_type
124+
.ty
125+
.walk()
126+
.filter_map(ty::GenericArg::as_term)
127+
.find(|term| term.is_infer())
128+
.unwrap_or_else(|| hidden_type.ty.into());
129+
self.err_ctxt()
130+
.emit_inference_failure_err(
131+
self.body_id,
132+
hidden_type.span,
133+
infer_var,
134+
TypeAnnotationNeeded::E0282,
135+
false,
136+
)
137+
.emit()
138+
}
135139
}
136140
UsageKind::HasDefiningUse => continue,
137141
};

compiler/rustc_hir_typeck/src/place_op.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_span::{Span, sym};
1212
use tracing::debug;
1313
use {rustc_ast as ast, rustc_hir as hir};
1414

15-
use crate::method::MethodCallee;
15+
use crate::method::{MethodCallee, TreatNotYetDefinedOpaques};
1616
use crate::{FnCtxt, PlaceOp};
1717

1818
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -210,7 +210,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
210210
return None;
211211
};
212212

213-
self.lookup_method_for_operator(self.misc(span), imm_op, imm_tr, base_ty, opt_rhs_ty)
213+
self.lookup_method_for_operator(
214+
self.misc(span),
215+
imm_op,
216+
imm_tr,
217+
base_ty,
218+
opt_rhs_ty,
219+
TreatNotYetDefinedOpaques::AsInfer,
220+
)
214221
}
215222

216223
fn try_mutable_overloaded_place_op(
@@ -230,7 +237,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
230237
return None;
231238
};
232239

233-
self.lookup_method_for_operator(self.misc(span), mut_op, mut_tr, base_ty, opt_rhs_ty)
240+
self.lookup_method_for_operator(
241+
self.misc(span),
242+
mut_op,
243+
mut_tr,
244+
base_ty,
245+
opt_rhs_ty,
246+
TreatNotYetDefinedOpaques::AsInfer,
247+
)
234248
}
235249

236250
/// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`

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,

0 commit comments

Comments
 (0)