Skip to content

Commit b21b10e

Browse files
committed
i hate this :<
1 parent 4c0e9b9 commit b21b10e

24 files changed

+231
-127
lines changed

Diff for: compiler/rustc_hir_typeck/src/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1589,7 +1589,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15891589
) -> Ty<'tcx> {
15901590
let rcvr_t = self.check_expr(rcvr);
15911591
// no need to check for bot/err -- callee does that
1592-
let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
1592+
let rcvr_t = self.try_structurally_resolve_type(rcvr.span, rcvr_t);
15931593

15941594
let method = match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args)
15951595
{

Diff for: compiler/rustc_hir_typeck/src/method/confirm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
190190
assert_eq!(n, pick.autoderefs);
191191

192192
let mut adjustments = self.adjust_steps(&autoderef);
193-
let mut target = self.structurally_resolve_type(autoderef.span(), ty);
193+
let mut target = self.try_structurally_resolve_type(autoderef.span(), ty);
194194

195195
match pick.autoref_or_ptr_adjustment {
196196
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {

Diff for: compiler/rustc_hir_typeck/src/method/probe.rs

+188-85
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ use rustc_hir::HirId;
1010
use rustc_hir::def::DefKind;
1111
use rustc_hir_analysis::autoderef::{self, Autoderef};
1212
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
13-
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
14-
use rustc_infer::traits::ObligationCauseCode;
13+
use rustc_infer::infer::{self, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt};
14+
use rustc_infer::traits::solve::Goal;
15+
use rustc_infer::traits::{ObligationCauseCode, PredicateObligation};
1516
use rustc_middle::middle::stability;
1617
use rustc_middle::query::Providers;
1718
use rustc_middle::ty::elaborate::supertrait_def_ids;
1819
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
1920
use rustc_middle::ty::{
2021
self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind,
21-
ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast,
22+
ParamEnvAnd, PredicateKind, Ty, TyCtxt, TypeVisitableExt, Upcast,
2223
};
2324
use rustc_middle::{bug, span_bug};
2425
use rustc_session::lint;
@@ -29,6 +30,9 @@ use rustc_span::edit_distance::{
2930
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
3031
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
3132
use rustc_trait_selection::infer::InferCtxtExt as _;
33+
use rustc_trait_selection::solve::inspect::{
34+
InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor,
35+
};
3236
use rustc_trait_selection::traits::query::CanonicalTyGoal;
3337
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
3438
use rustc_trait_selection::traits::query::method_autoderef::{
@@ -442,7 +446,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
442446
// If we encountered an `_` type or an error type during autoderef, this is
443447
// ambiguous.
444448
if let Some(bad_ty) = &steps.opt_bad_ty {
445-
if is_suggestion.0 {
449+
// Ended up encountering a type variable when doing autoderef,
450+
// but it may not be a type variable after processing obligations
451+
// in our local `FnCtxt`, so don't call `structurally_resolve_type`.
452+
let ty = &bad_ty.ty;
453+
let ty = self
454+
.probe_instantiate_query_response(span, &orig_values, ty)
455+
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
456+
if bad_ty.is_opaque_type
457+
|| final_ty_is_opaque(
458+
&self.infcx,
459+
&self.fulfillment_cx.borrow().pending_obligations(),
460+
ty.value,
461+
)
462+
{
463+
// FIXME(-Znext-solver): This isn't really what we want :<
464+
assert!(self.tcx.next_trait_solver_globally());
465+
} else if is_suggestion.0 {
446466
// Ambiguity was encountered during a suggestion. There's really
447467
// not much use in suggesting methods in this case.
448468
return Err(MethodError::NoMatch(NoMatchData {
@@ -468,13 +488,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
468488
},
469489
);
470490
} else {
471-
// Ended up encountering a type variable when doing autoderef,
472-
// but it may not be a type variable after processing obligations
473-
// in our local `FnCtxt`, so don't call `structurally_resolve_type`.
474-
let ty = &bad_ty.ty;
475-
let ty = self
476-
.probe_instantiate_query_response(span, &orig_values, ty)
477-
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
478491
let ty = self.resolve_vars_if_possible(ty.value);
479492
let guar = match *ty.kind() {
480493
ty::Infer(ty::TyVar(_)) => {
@@ -582,60 +595,77 @@ fn method_autoderef_steps<'tcx>(
582595
let mut reached_raw_pointer = false;
583596
let arbitrary_self_types_enabled =
584597
tcx.features().arbitrary_self_types() || tcx.features().arbitrary_self_types_pointers();
585-
let (mut steps, reached_recursion_limit): (Vec<_>, bool) = if arbitrary_self_types_enabled {
586-
let reachable_via_deref =
587-
autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false));
588-
589-
let mut autoderef_via_receiver =
590-
Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
591-
.include_raw_pointers()
592-
.use_receiver_trait()
593-
.silence_errors();
594-
let steps = autoderef_via_receiver
595-
.by_ref()
596-
.zip(reachable_via_deref)
597-
.map(|((ty, d), reachable_via_deref)| {
598-
let step = CandidateStep {
599-
self_ty: infcx
600-
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
601-
autoderefs: d,
602-
from_unsafe_deref: reached_raw_pointer,
603-
unsize: false,
604-
reachable_via_deref,
605-
};
606-
if ty.is_raw_ptr() {
607-
// all the subsequent steps will be from_unsafe_deref
608-
reached_raw_pointer = true;
609-
}
610-
step
611-
})
612-
.collect();
613-
(steps, autoderef_via_receiver.reached_recursion_limit())
614-
} else {
615-
let steps = autoderef_via_deref
616-
.by_ref()
617-
.map(|(ty, d)| {
618-
let step = CandidateStep {
619-
self_ty: infcx
620-
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
621-
autoderefs: d,
622-
from_unsafe_deref: reached_raw_pointer,
623-
unsize: false,
624-
reachable_via_deref: true,
625-
};
626-
if ty.is_raw_ptr() {
627-
// all the subsequent steps will be from_unsafe_deref
628-
reached_raw_pointer = true;
629-
}
630-
step
631-
})
632-
.collect();
633-
(steps, autoderef_via_deref.reached_recursion_limit())
634-
};
635-
let final_ty = autoderef_via_deref.final_ty(true);
598+
let (mut steps, final_ty, reached_recursion_limit, obligations): (Vec<_>, _, _, _) =
599+
if arbitrary_self_types_enabled {
600+
let reachable_via_deref =
601+
autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false));
602+
603+
let mut autoderef_via_receiver =
604+
Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
605+
.include_raw_pointers()
606+
.use_receiver_trait()
607+
.silence_errors();
608+
let steps = autoderef_via_receiver
609+
.by_ref()
610+
.zip(reachable_via_deref)
611+
.map(|((ty, d), reachable_via_deref)| {
612+
let step = CandidateStep {
613+
self_ty: infcx
614+
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
615+
autoderefs: d,
616+
from_unsafe_deref: reached_raw_pointer,
617+
unsize: false,
618+
reachable_via_deref,
619+
};
620+
if ty.is_raw_ptr() {
621+
// all the subsequent steps will be from_unsafe_deref
622+
reached_raw_pointer = true;
623+
}
624+
step
625+
})
626+
.collect();
627+
(
628+
steps,
629+
// FIXME(arbitrary_self_types): This is sus.
630+
autoderef_via_deref.final_ty(true),
631+
autoderef_via_receiver.reached_recursion_limit(),
632+
autoderef_via_receiver.into_obligations(),
633+
)
634+
} else {
635+
let steps = autoderef_via_deref
636+
.by_ref()
637+
.map(|(ty, d)| {
638+
let step = CandidateStep {
639+
self_ty: infcx
640+
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
641+
autoderefs: d,
642+
from_unsafe_deref: reached_raw_pointer,
643+
unsize: false,
644+
reachable_via_deref: true,
645+
};
646+
if ty.is_raw_ptr() {
647+
// all the subsequent steps will be from_unsafe_deref
648+
reached_raw_pointer = true;
649+
}
650+
step
651+
})
652+
.collect();
653+
(
654+
steps,
655+
autoderef_via_deref.final_ty(true),
656+
autoderef_via_deref.reached_recursion_limit(),
657+
autoderef_via_deref.into_obligations(),
658+
)
659+
};
636660
let opt_bad_ty = match final_ty.kind() {
637-
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
661+
ty::Infer(ty::TyVar(_)) => Some(MethodAutoderefBadTy {
638662
reached_raw_pointer,
663+
is_opaque_type: final_ty_is_opaque(infcx, &obligations, final_ty),
664+
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
665+
}),
666+
ty::Error(_) => Some(MethodAutoderefBadTy {
667+
reached_raw_pointer,
668+
is_opaque_type: false,
639669
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
640670
}),
641671
ty::Array(elem_ty, _) => {
@@ -668,6 +698,71 @@ fn method_autoderef_steps<'tcx>(
668698
}
669699
}
670700

701+
/// Returns `true` in case the final type is the hidden type of an opaque.
702+
#[instrument(level = "debug", skip(infcx), ret)]
703+
fn final_ty_is_opaque<'tcx>(
704+
infcx: &InferCtxt<'tcx>,
705+
obligations: &[PredicateObligation<'tcx>],
706+
final_ty: Ty<'tcx>,
707+
) -> bool {
708+
// nyaaaa~
709+
if infcx.next_trait_solver() {
710+
for obligation in obligations {
711+
let mut visitor = FinalTyIsOpaque { final_ty, is_opaque_ty: false };
712+
let goal = Goal::new(infcx.tcx, obligation.param_env, obligation.predicate);
713+
infcx.visit_proof_tree(goal, &mut visitor);
714+
if visitor.is_opaque_ty {
715+
return true;
716+
}
717+
}
718+
719+
let opaque_types = infcx.clone_opaque_types();
720+
for (_, hidden_ty) in &opaque_types {
721+
if infcx.shallow_resolve(hidden_ty.ty) == final_ty {
722+
return true;
723+
}
724+
}
725+
}
726+
727+
false
728+
}
729+
730+
struct FinalTyIsOpaque<'tcx> {
731+
final_ty: Ty<'tcx>,
732+
is_opaque_ty: bool,
733+
}
734+
735+
impl<'tcx> ProofTreeVisitor<'tcx> for FinalTyIsOpaque<'tcx> {
736+
fn span(&self) -> Span {
737+
DUMMY_SP
738+
}
739+
740+
fn config(&self) -> InspectConfig {
741+
// Using an intentionally low depth to avoid potential hangs
742+
// due to exponentially growing proof trees.
743+
InspectConfig { max_depth: 5 }
744+
}
745+
746+
fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
747+
let infcx = inspect_goal.infcx();
748+
let goal = inspect_goal.goal();
749+
if let PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) =
750+
goal.predicate.kind().skip_binder()
751+
{
752+
debug!(?alias, ?term, "visiting normalizes-to goal");
753+
if term.as_type().is_some_and(|ty| ty == self.final_ty)
754+
&& alias.kind(infcx.tcx) == ty::AliasTermKind::OpaqueTy
755+
{
756+
self.is_opaque_ty = true;
757+
}
758+
}
759+
760+
if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
761+
candidate.visit_nested_in_probe(self)
762+
}
763+
}
764+
}
765+
671766
impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
672767
fn new(
673768
fcx: &'a FnCtxt<'a, 'tcx>,
@@ -1881,31 +1976,39 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18811976
(xform_self_ty, xform_ret_ty) =
18821977
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
18831978
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
1884-
match self_ty.kind() {
1885-
// HACK: opaque types will match anything for which their bounds hold.
1886-
// Thus we need to prevent them from trying to match the `&_` autoref
1887-
// candidates that get created for `&self` trait methods.
1888-
ty::Alias(ty::Opaque, alias_ty)
1889-
if !self.next_trait_solver()
1890-
&& self.infcx.can_define_opaque_ty(alias_ty.def_id)
1891-
&& !xform_self_ty.is_ty_var() =>
1892-
{
1893-
return ProbeResult::NoMatch;
1894-
}
1895-
_ => match ocx.relate(
1896-
cause,
1897-
self.param_env,
1898-
self.variance(),
1899-
self_ty,
1900-
xform_self_ty,
1901-
) {
1902-
Ok(()) => {}
1903-
Err(err) => {
1904-
debug!("--> cannot relate self-types {:?}", err);
1979+
1980+
// HACK: opaque types will match anything for which their bounds hold.
1981+
// Thus we need to prevent them from trying to match the `&_` autoref
1982+
// candidates that get created for `&self` trait methods.
1983+
if self.mode == Mode::MethodCall {
1984+
match self_ty.kind() {
1985+
ty::Infer(ty::TyVar(_)) => {
1986+
assert!(self.infcx.next_trait_solver());
1987+
if !xform_self_ty.is_ty_var() {
1988+
return ProbeResult::NoMatch;
1989+
}
1990+
}
1991+
ty::Alias(ty::Opaque, alias_ty)
1992+
if !self.infcx.next_trait_solver()
1993+
&& self.infcx.can_define_opaque_ty(alias_ty.def_id)
1994+
&& !xform_self_ty.is_ty_var() =>
1995+
{
1996+
assert!(!self.infcx.next_trait_solver());
19051997
return ProbeResult::NoMatch;
19061998
}
1907-
},
1999+
_ => {}
2000+
}
2001+
}
2002+
2003+
match ocx.relate(cause, self.param_env, self.variance(), self_ty, xform_self_ty)
2004+
{
2005+
Ok(()) => {}
2006+
Err(err) => {
2007+
debug!("--> cannot relate self-types {:?}", err);
2008+
return ProbeResult::NoMatch;
2009+
}
19082010
}
2011+
19092012
let obligation = traits::Obligation::new(
19102013
self.tcx,
19112014
cause.clone(),

Diff for: compiler/rustc_middle/src/traits/query.rs

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ pub struct MethodAutoderefStepsResult<'tcx> {
178178
#[derive(Debug, HashStable)]
179179
pub struct MethodAutoderefBadTy<'tcx> {
180180
pub reached_raw_pointer: bool,
181+
pub is_opaque_type: bool,
181182
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
182183
}
183184

Diff for: tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | needs_foo(|x| {
55
| ^
66
...
77
LL | x.to_string();
8-
| - type must be known at this point
8+
| --------- type must be known at this point
99
|
1010
help: consider giving this closure parameter an explicit type
1111
|

Diff for: tests/ui/impl-trait/call_method_ambiguous.next.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let mut iter = foo(n - 1, m);
55
| ^^^^^^^^
66
LL |
77
LL | assert_eq!(iter.get(), 1);
8-
| ---- type must be known at this point
8+
| --- type must be known at this point
99
|
1010
help: consider giving `iter` an explicit type
1111
|

Diff for: tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let x = my_foo();
55
| ^
66
LL |
77
LL | x.my_debug();
8-
| - type must be known at this point
8+
| -------- type must be known at this point
99
|
1010
help: consider giving `x` an explicit type
1111
|

Diff for: tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let x = my_foo();
55
| ^
66
LL |
77
LL | x.my_debug();
8-
| - type must be known at this point
8+
| -------- type must be known at this point
99
|
1010
help: consider giving `x` an explicit type
1111
|

0 commit comments

Comments
 (0)