Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a4a0e7e

Browse files
committed
i hate this :>
1 parent 73c0ae6 commit a4a0e7e

23 files changed

+231
-126
lines changed

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15881588
) -> Ty<'tcx> {
15891589
let rcvr_t = self.check_expr(rcvr);
15901590
// no need to check for bot/err -- callee does that
1591-
let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
1591+
let rcvr_t = self.try_structurally_resolve_type(rcvr.span, rcvr_t);
15921592

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

compiler/rustc_hir_typeck/src/method/confirm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
185185
assert_eq!(n, pick.autoderefs);
186186

187187
let mut adjustments = self.adjust_steps(&autoderef);
188-
let mut target = self.structurally_resolve_type(autoderef.span(), ty);
188+
let mut target = self.try_structurally_resolve_type(autoderef.span(), ty);
189189

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

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 189 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ 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::fast_reject::{TreatParams, simplify_type};
1819
use rustc_middle::ty::{
1920
self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind,
20-
ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast,
21+
ParamEnvAnd, PredicateKind, Ty, TyCtxt, TypeVisitableExt, Upcast,
2122
};
2223
use rustc_middle::{bug, span_bug};
2324
use rustc_session::lint;
@@ -28,6 +29,9 @@ use rustc_span::edit_distance::{
2829
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
2930
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
3031
use rustc_trait_selection::infer::InferCtxtExt as _;
32+
use rustc_trait_selection::solve::inspect::{
33+
InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor,
34+
};
3135
use rustc_trait_selection::traits::query::CanonicalTyGoal;
3236
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
3337
use rustc_trait_selection::traits::query::method_autoderef::{
@@ -438,7 +442,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
438442
// If we encountered an `_` type or an error type during autoderef, this is
439443
// ambiguous.
440444
if let Some(bad_ty) = &steps.opt_bad_ty {
441-
if is_suggestion.0 {
445+
// Ended up encountering a type variable when doing autoderef,
446+
// but it may not be a type variable after processing obligations
447+
// in our local `FnCtxt`, so don't call `structurally_resolve_type`.
448+
let ty = &bad_ty.ty;
449+
let ty = self
450+
.probe_instantiate_query_response(span, &orig_values, ty)
451+
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
452+
if bad_ty.is_opaque_type
453+
|| final_ty_is_opaque(
454+
&self.infcx,
455+
&self.fulfillment_cx.borrow().pending_obligations(),
456+
ty.value,
457+
)
458+
{
459+
// FIXME(-Znext-solver): This isn't really what we want :<
460+
assert!(self.tcx.next_trait_solver_globally());
461+
} else if is_suggestion.0 {
442462
// Ambiguity was encountered during a suggestion. There's really
443463
// not much use in suggesting methods in this case.
444464
return Err(MethodError::NoMatch(NoMatchData {
@@ -464,13 +484,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
464484
},
465485
);
466486
} else {
467-
// Ended up encountering a type variable when doing autoderef,
468-
// but it may not be a type variable after processing obligations
469-
// in our local `FnCtxt`, so don't call `structurally_resolve_type`.
470-
let ty = &bad_ty.ty;
471-
let ty = self
472-
.probe_instantiate_query_response(span, &orig_values, ty)
473-
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
474487
let ty = self.resolve_vars_if_possible(ty.value);
475488
let guar = match *ty.kind() {
476489
ty::Infer(ty::TyVar(_)) => {
@@ -578,60 +591,78 @@ fn method_autoderef_steps<'tcx>(
578591
let mut reached_raw_pointer = false;
579592
let arbitrary_self_types_enabled =
580593
tcx.features().arbitrary_self_types() || tcx.features().arbitrary_self_types_pointers();
581-
let (mut steps, reached_recursion_limit): (Vec<_>, bool) = if arbitrary_self_types_enabled {
582-
let reachable_via_deref =
583-
autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false));
584-
585-
let mut autoderef_via_receiver =
586-
Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
587-
.include_raw_pointers()
588-
.use_receiver_trait()
589-
.silence_errors();
590-
let steps = autoderef_via_receiver
591-
.by_ref()
592-
.zip(reachable_via_deref)
593-
.map(|((ty, d), reachable_via_deref)| {
594-
let step = CandidateStep {
595-
self_ty: infcx
596-
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
597-
autoderefs: d,
598-
from_unsafe_deref: reached_raw_pointer,
599-
unsize: false,
600-
reachable_via_deref,
601-
};
602-
if ty.is_unsafe_ptr() {
603-
// all the subsequent steps will be from_unsafe_deref
604-
reached_raw_pointer = true;
605-
}
606-
step
607-
})
608-
.collect();
609-
(steps, autoderef_via_receiver.reached_recursion_limit())
610-
} else {
611-
let steps = autoderef_via_deref
612-
.by_ref()
613-
.map(|(ty, d)| {
614-
let step = CandidateStep {
615-
self_ty: infcx
616-
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
617-
autoderefs: d,
618-
from_unsafe_deref: reached_raw_pointer,
619-
unsize: false,
620-
reachable_via_deref: true,
621-
};
622-
if ty.is_unsafe_ptr() {
623-
// all the subsequent steps will be from_unsafe_deref
624-
reached_raw_pointer = true;
625-
}
626-
step
627-
})
628-
.collect();
629-
(steps, autoderef_via_deref.reached_recursion_limit())
630-
};
631-
let final_ty = autoderef_via_deref.final_ty(true);
594+
let (mut steps, final_ty, reached_recursion_limit, obligations) =
595+
if arbitrary_self_types_enabled {
596+
let reachable_via_deref =
597+
autoderef_via_deref.by_ref().map(|_| true).chain(std::iter::repeat(false));
598+
599+
let mut autoderef_via_receiver =
600+
Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
601+
.include_raw_pointers()
602+
.use_receiver_trait()
603+
.silence_errors();
604+
let steps: Vec<_> = autoderef_via_receiver
605+
.by_ref()
606+
.zip(reachable_via_deref)
607+
.map(|((ty, d), reachable_via_deref)| {
608+
let step = CandidateStep {
609+
self_ty: infcx
610+
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
611+
autoderefs: d,
612+
from_unsafe_deref: reached_raw_pointer,
613+
unsize: false,
614+
reachable_via_deref,
615+
};
616+
if ty.is_unsafe_ptr() {
617+
// all the subsequent steps will be from_unsafe_deref
618+
reached_raw_pointer = true;
619+
}
620+
step
621+
})
622+
.collect();
623+
(
624+
steps,
625+
// FIXME(arbitrary_self_types): Why do we look at the final type of
626+
// the `deref` chain here?
627+
autoderef_via_deref.final_ty(true),
628+
autoderef_via_receiver.reached_recursion_limit(),
629+
autoderef_via_receiver.into_obligations(),
630+
)
631+
} else {
632+
let steps = autoderef_via_deref
633+
.by_ref()
634+
.map(|(ty, d)| {
635+
let step = CandidateStep {
636+
self_ty: infcx
637+
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
638+
autoderefs: d,
639+
from_unsafe_deref: reached_raw_pointer,
640+
unsize: false,
641+
reachable_via_deref: true,
642+
};
643+
if ty.is_unsafe_ptr() {
644+
// all the subsequent steps will be from_unsafe_deref
645+
reached_raw_pointer = true;
646+
}
647+
step
648+
})
649+
.collect();
650+
(
651+
steps,
652+
autoderef_via_deref.final_ty(true),
653+
autoderef_via_deref.reached_recursion_limit(),
654+
autoderef_via_deref.into_obligations(),
655+
)
656+
};
632657
let opt_bad_ty = match final_ty.kind() {
633-
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
658+
ty::Infer(ty::TyVar(_)) => Some(MethodAutoderefBadTy {
634659
reached_raw_pointer,
660+
is_opaque_type: final_ty_is_opaque(infcx, &obligations, final_ty),
661+
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
662+
}),
663+
ty::Error(_) => Some(MethodAutoderefBadTy {
664+
reached_raw_pointer,
665+
is_opaque_type: false,
635666
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
636667
}),
637668
ty::Array(elem_ty, _) => {
@@ -664,6 +695,71 @@ fn method_autoderef_steps<'tcx>(
664695
}
665696
}
666697

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

compiler/rustc_middle/src/traits/query.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ pub struct MethodAutoderefStepsResult<'tcx> {
175175
#[derive(Debug, HashStable)]
176176
pub struct MethodAutoderefBadTy<'tcx> {
177177
pub reached_raw_pointer: bool,
178+
pub is_opaque_type: bool,
178179
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
179180
}
180181

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

Lines changed: 1 addition & 1 deletion
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
|

tests/ui/impl-trait/call_method_ambiguous.next.stderr

Lines changed: 1 addition & 1 deletion
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
|

tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr

Lines changed: 1 addition & 1 deletion
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
|

tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr

Lines changed: 1 addition & 1 deletion
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)