allow method calls on opaques

This commit is contained in:
lcnr
2025-09-23 17:33:24 +02:00
parent 6b379b560d
commit 148fd9ad3c
28 changed files with 357 additions and 171 deletions

View File

@@ -13,7 +13,7 @@ use rustc_hir::def::DefKind;
use rustc_hir_analysis::autoderef::{self, Autoderef};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::traits::{ObligationCauseCode, query};
use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query};
use rustc_middle::middle::stability;
use rustc_middle::ty::elaborate::supertrait_def_ids;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
@@ -30,6 +30,7 @@ use rustc_span::edit_distance::{
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::solve::Goal;
use rustc_trait_selection::traits::query::CanonicalMethodAutoderefStepsGoal;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::query::method_autoderef::{
@@ -417,6 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
self_ty: self
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
self_ty_is_opaque: false,
autoderefs: 0,
from_unsafe_deref: false,
unsize: false,
@@ -590,6 +592,17 @@ pub(crate) fn method_autoderef_steps<'tcx>(
}
}
// We accept not-yet-defined opaque types in the autoderef
// chain to support recursive calls. We do error if the final
// infer var is not an opaque.
let self_ty_is_opaque = |ty: Ty<'_>| {
if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
infcx.has_opaques_with_sub_unified_hidden_type(vid)
} else {
false
}
};
// If arbitrary self types is not enabled, we follow the chain of
// `Deref<Target=T>`. If arbitrary self types is enabled, we instead
// follow the chain of `Receiver<Target=T>`, but we also record whether
@@ -623,6 +636,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
let step = CandidateStep {
self_ty: infcx
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
self_ty_is_opaque: self_ty_is_opaque(ty),
autoderefs: d,
from_unsafe_deref: reached_raw_pointer,
unsize: false,
@@ -643,6 +657,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
let step = CandidateStep {
self_ty: infcx
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
self_ty_is_opaque: self_ty_is_opaque(ty),
autoderefs: d,
from_unsafe_deref: reached_raw_pointer,
unsize: false,
@@ -659,7 +674,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
};
let final_ty = autoderef_via_deref.final_ty();
let opt_bad_ty = match final_ty.kind() {
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy {
reached_raw_pointer,
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
}),
ty::Error(_) => Some(MethodAutoderefBadTy {
reached_raw_pointer,
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
}),
@@ -670,6 +689,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
inference_vars,
Ty::new_slice(infcx.tcx, *elem_ty),
),
self_ty_is_opaque: false,
autoderefs,
// this could be from an unsafe deref if we had
// a *mut/const [T; N]
@@ -1234,7 +1254,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
!step.self_ty.value.references_error() && !step.from_unsafe_deref
})
.find_map(|step| {
let InferOk { value: self_ty, obligations: _ } = self
let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self
.fcx
.probe_instantiate_query_response(
self.span,
@@ -1245,7 +1265,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
});
let by_value_pick = self.pick_by_value_method(step, self_ty, pick_diag_hints);
let by_value_pick = self.pick_by_value_method(
step,
self_ty,
&instantiate_self_ty_obligations,
pick_diag_hints,
);
// Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
if let Some(by_value_pick) = by_value_pick {
@@ -1256,6 +1281,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
by_value_pick,
step,
self_ty,
&instantiate_self_ty_obligations,
mutbl,
track_unstable_candidates,
) {
@@ -1270,6 +1296,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let autoref_pick = self.pick_autorefd_method(
step,
self_ty,
&instantiate_self_ty_obligations,
hir::Mutability::Not,
pick_diag_hints,
None,
@@ -1283,6 +1310,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
autoref_pick,
step,
self_ty,
&instantiate_self_ty_obligations,
hir::Mutability::Mut,
track_unstable_candidates,
) {
@@ -1319,12 +1347,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.pick_autorefd_method(
step,
self_ty,
&instantiate_self_ty_obligations,
hir::Mutability::Mut,
pick_diag_hints,
None,
)
.or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
.or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
.or_else(|| {
self.pick_const_ptr_method(
step,
self_ty,
&instantiate_self_ty_obligations,
pick_diag_hints,
)
})
.or_else(|| {
self.pick_reborrow_pin_method(
step,
self_ty,
&instantiate_self_ty_obligations,
pick_diag_hints,
)
})
})
}
@@ -1348,6 +1391,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
possible_shadower: &Pick<'tcx>,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
mutbl: hir::Mutability,
track_unstable_candidates: bool,
) -> Result<(), MethodError<'tcx>> {
@@ -1412,6 +1456,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let potentially_shadowed_pick = self.pick_autorefd_method(
step,
self_ty,
instantiate_self_ty_obligations,
mutbl,
&mut pick_diag_hints,
Some(&pick_constraints),
@@ -1438,13 +1483,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
) -> Option<PickResult<'tcx>> {
if step.unsize {
return None;
}
self.pick_method(self_ty, pick_diag_hints, None).map(|r| {
self.pick_method(self_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
@@ -1481,6 +1527,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
mutbl: hir::Mutability,
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
pick_constraints: Option<&PickConstraintsForShadowed>,
@@ -1497,7 +1544,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let region = tcx.lifetimes.re_erased;
let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
self.pick_method(autoref_ty, pick_diag_hints, pick_constraints).map(|r| {
self.pick_method(
autoref_ty,
instantiate_self_ty_obligations,
pick_diag_hints,
pick_constraints,
)
.map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref_or_ptr_adjustment =
@@ -1513,6 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
) -> Option<PickResult<'tcx>> {
if !self.tcx.features().pin_ergonomics() {
@@ -1534,14 +1588,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let region = self.tcx.lifetimes.re_erased;
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
self.pick_method(autopin_ty, pick_diag_hints, None).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref_or_ptr_adjustment =
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
pick
})
})
self.pick_method(autopin_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref_or_ptr_adjustment =
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
pick
})
},
)
}
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
@@ -1551,6 +1607,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
&self,
step: &CandidateStep<'tcx>,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
) -> Option<PickResult<'tcx>> {
// Don't convert an unsized reference to ptr
@@ -1563,18 +1620,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
};
let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
pick
})
})
self.pick_method(const_ptr_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
pick
})
},
)
}
fn pick_method(
&self,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
pick_constraints: Option<&PickConstraintsForShadowed>,
) -> Option<PickResult<'tcx>> {
@@ -1584,8 +1644,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
{
debug!("searching {} candidates", kind);
let res =
self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints);
let res = self.consider_candidates(
self_ty,
instantiate_self_ty_obligations,
candidates,
pick_diag_hints,
pick_constraints,
);
if let Some(pick) = res {
return Some(pick);
}
@@ -1594,6 +1659,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if self.private_candidate.get().is_none() {
if let Some(Ok(pick)) = self.consider_candidates(
self_ty,
instantiate_self_ty_obligations,
&self.private_candidates,
&mut PickDiagHints {
unstable_candidates: None,
@@ -1610,6 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn consider_candidates(
&self,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
candidates: &[Candidate<'tcx>],
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
pick_constraints: Option<&PickConstraintsForShadowed>,
@@ -1626,6 +1693,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
probe,
self.consider_probe(
self_ty,
instantiate_self_ty_obligations,
probe,
&mut pick_diag_hints.unsatisfied_predicates,
),
@@ -1810,10 +1878,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
#[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
#[instrument(level = "debug", skip(self, possibly_unsatisfied_predicates), ret)]
fn consider_probe(
&self,
self_ty: Ty<'tcx>,
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
probe: &Candidate<'tcx>,
possibly_unsatisfied_predicates: &mut Vec<(
ty::Predicate<'tcx>,
@@ -1821,8 +1890,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
Option<ObligationCause<'tcx>>,
)>,
) -> ProbeResult {
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
self.probe(|snapshot| {
let outer_universe = self.universe();
@@ -1830,6 +1897,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let cause = &self.misc(self.span);
let ocx = ObligationCtxt::new_with_diagnostics(self);
// Subtle: we're not *really* instantiating the current self type while
// probing, but instead fully recompute the autoderef steps once we've got
// a final `Pick`. We can't nicely handle these obligations outside of a probe.
//
// We simply handle them for each candidate here for now. That's kinda scuffed
// and ideally we just put them into the `FnCtxt` right away. We need to consider
// them to deal with defining uses in `method_autoderef_steps`.
if self.next_trait_solver() {
ocx.register_obligations(instantiate_self_ty_obligations.iter().cloned());
let errors = ocx.select_where_possible();
if !errors.is_empty() {
unreachable!("unexpected autoderef error {errors:?}");
}
}
let mut trait_predicate = None;
let (mut xform_self_ty, mut xform_ret_ty);
@@ -2072,6 +2154,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
if self.infcx.next_trait_solver() {
if self.should_reject_candidate_due_to_opaque_treated_as_rigid(trait_predicate) {
result = ProbeResult::NoMatch;
}
}
// Previously, method probe used `evaluate_predicate` to determine if a predicate
// was impossible to satisfy. This did a leak check, so we must also do a leak
// check here to prevent backwards-incompatible ambiguity being introduced. See
@@ -2085,6 +2173,71 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
})
}
/// Trait candidates for not-yet-defined opaque types are a somewhat hacky.
///
/// We want to only accept trait methods if they were hold even if the
/// opaque types were rigid. To handle this, we both check that for trait
/// candidates the goal were to hold even when treating opaques as rigid,
/// see [OpaqueTypesJank](rustc_trait_selection::solve::OpaqueTypesJank).
///
/// We also check that all opaque types encountered as self types in the
/// autoderef chain don't get constrained when applying the candidate.
/// Importantly, this also handles calling methods taking `&self` on
/// `impl Trait` to reject the "by-self" candidate.
///
/// This needs to happen at the end of `consider_probe` as we need to take
/// all the constraints from that into account.
#[instrument(level = "debug", skip(self), ret)]
fn should_reject_candidate_due_to_opaque_treated_as_rigid(
&self,
trait_predicate: Option<ty::Predicate<'tcx>>,
) -> bool {
// Check whether the trait candidate would not be applicable if the
// opaque type were rigid.
if let Some(predicate) = trait_predicate {
let goal = Goal { param_env: self.param_env, predicate };
if !self.infcx.goal_may_hold_opaque_types_jank(goal) {
return true;
}
}
// Check whether any opaque types in the autoderef chain have been
// constrained.
for step in self.steps {
if step.self_ty_is_opaque {
debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque");
let constrained_opaque = self.probe(|_| {
// If we fail to instantiate the self type of this
// step, this part of the deref-chain is no longer
// reachable. In this case we don't care about opaque
// types there.
let Ok(ok) = self.fcx.probe_instantiate_query_response(
self.span,
self.orig_steps_var_values,
&step.self_ty,
) else {
debug!("failed to instantiate self_ty");
return false;
};
let ocx = ObligationCtxt::new(self);
let self_ty = ocx.register_infer_ok_obligations(ok);
if !ocx.select_where_possible().is_empty() {
debug!("failed to prove instantiate self_ty obligations");
return false;
}
!self.resolve_vars_if_possible(self_ty).is_ty_var()
});
if constrained_opaque {
debug!("opaque type has been constrained");
return true;
}
}
}
false
}
/// Sometimes we get in a situation where we have multiple probes that are all impls of the
/// same trait, but we don't know which impl to use. In this case, since in all cases the
/// external interface of the method can be determined from the trait, it's ok not to decide.

View File

@@ -85,11 +85,32 @@ impl<'tcx> InferCtxt<'tcx> {
where
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
// While we ignore region constraints and pending obligations,
// we do return constrained opaque types to avoid unconstrained
// inference variables in the response. This is still slightly
// insufficient as ambiguous `Projection` obligations have the
// same issue.
//
// FIXME(-Znext-solver): We could alternatively extend the `var_values`
// each time we call `make_query_response_ignoring_pending_obligations`
// and equate inference variables created inside of the query this way.
// This is what we do for `CanonicalState` and is probably a bit nicer.
let opaque_types = if self.next_trait_solver() {
self.inner
.borrow_mut()
.opaque_type_storage
.iter_opaque_types()
.map(|(k, v)| (k, v.ty))
.collect()
} else {
vec![]
};
self.canonicalize_response(QueryResponse {
var_values: inference_vars,
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Proven, // Ambiguities are OK!
opaque_types: vec![],
opaque_types,
value: answer,
})
}

View File

@@ -154,6 +154,7 @@ impl<'tcx> FromIterator<DropckConstraint<'tcx>> for DropckConstraint<'tcx> {
#[derive(Debug, HashStable)]
pub struct CandidateStep<'tcx> {
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
pub self_ty_is_opaque: bool,
pub autoderefs: usize,
/// `true` if the type results from a dereference of a raw pointer.
/// when assembling candidates, we include these steps, but not when

View File

@@ -194,7 +194,7 @@ where
D: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "debug", skip(self))]
#[instrument(level = "debug", skip(self), ret)]
fn evaluate_root_goal(
&self,
goal: Goal<I, I::Predicate>,
@@ -206,6 +206,7 @@ where
})
}
#[instrument(level = "debug", skip(self), ret)]
fn root_goal_may_hold_opaque_types_jank(
&self,
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,

View File

@@ -381,6 +381,7 @@ where
}
/// The result of evaluating a goal.
#[derive_where(Debug; I: Interner)]
pub struct GoalEvaluation<I: Interner> {
/// The goal we've evaluated. This is the input goal, but potentially with its
/// inference variables resolved. This never applies any inference constraints

View File

@@ -1,6 +1,6 @@
use rustc_infer::traits::solve::Goal;
use rustc_macros::extension;
use rustc_middle::span_bug;
use rustc_middle::{span_bug, ty};
use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
use crate::infer::InferCtxt;
@@ -22,7 +22,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// for more details.
fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool {
if self.next_trait_solver() {
<&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(Goal::new(
self.goal_may_hold_opaque_types_jank(Goal::new(
self.tcx,
obligation.param_env,
obligation.predicate,
@@ -32,6 +32,13 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
/// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
/// for more details.
fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> bool {
assert!(self.next_trait_solver());
<&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(goal)
}
/// Evaluates whether the predicate can be satisfied in the given
/// `ParamEnv`, and returns `false` if not certain. However, this is
/// not entirely accurate if inference variables are involved.

View File

@@ -1,17 +0,0 @@
error[E0282]: type annotations needed
--> $DIR/call_method_ambiguous.rs:26:13
|
LL | let mut iter = foo(n - 1, m);
| ^^^^^^^^
LL |
LL | assert_eq!(iter.get(), 1);
| --- type must be known at this point
|
help: consider giving `iter` an explicit type
|
LL | let mut iter: /* Type */ = foo(n - 1, m);
| ++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View File

@@ -1,6 +1,6 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] run-pass
//@ run-pass
trait Get {
fn get(&mut self) -> u32;
@@ -24,7 +24,6 @@ where
fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> {
if n > 0 {
let mut iter = foo(n - 1, m);
//[next]~^ ERROR type annotations needed
assert_eq!(iter.get(), 1);
}
m

View File

@@ -1,17 +0,0 @@
error[E0282]: type annotations needed
--> $DIR/call_method_on_inherent_impl.rs:18:13
|
LL | let x = my_foo();
| ^
LL |
LL | x.my_debug();
| -------- type must be known at this point
|
help: consider giving `x` an explicit type
|
LL | let x: /* Type */ = my_foo();
| ++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View File

@@ -1,6 +1,6 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] check-pass
//@ check-pass
trait MyDebug {
fn my_debug(&self);
@@ -16,7 +16,6 @@ where
fn my_foo() -> impl std::fmt::Debug {
if false {
let x = my_foo();
//[next]~^ ERROR type annotations needed
x.my_debug();
}
()

View File

@@ -1,5 +1,5 @@
error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:16:11
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:15:11
|
LL | x.my_debug();
| ^^^^^^^^ method not found in `&impl Debug`

View File

@@ -1,17 +1,15 @@
error[E0282]: type annotations needed for `&_`
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13
error[E0599]: no method named `my_debug` found for reference `&_` in the current scope
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:15:11
|
LL | let x = &my_foo();
| ^
LL |
LL | x.my_debug();
| -------- type must be known at this point
| ^^^^^^^^ method not found in `&_`
|
help: consider giving `x` an explicit type, where the placeholders `_` are specified
= help: items from traits can only be used if the trait is implemented and in scope
help: trait `MyDebug` which provides `my_debug` is implemented but not in scope; perhaps you want to import it
|
LL + use MyDebug;
|
LL | let x: &_ = &my_foo();
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.
For more information about this error, try `rustc --explain E0599`.

View File

@@ -12,9 +12,8 @@ impl MyDebug for &() {
fn my_foo() -> impl std::fmt::Debug {
if false {
let x = &my_foo();
//[next]~^ ERROR: type annotations needed
x.my_debug();
//[current]~^ ERROR: no method named `my_debug`
//~^ ERROR: no method named `my_debug`
}
()
}

View File

@@ -1,5 +1,5 @@
error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope
--> $DIR/call_method_on_inherent_impl_ref.rs:19:11
--> $DIR/call_method_on_inherent_impl_ref-err.rs:18:11
|
LL | fn my_debug(&self);
| -------- the method is available for `&impl Debug` here
@@ -9,7 +9,7 @@ LL | x.my_debug();
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
--> $DIR/call_method_on_inherent_impl_ref.rs:4:1
--> $DIR/call_method_on_inherent_impl_ref-err.rs:4:1
|
LL | trait MyDebug {
| ^^^^^^^^^^^^^

View File

@@ -0,0 +1,19 @@
error[E0599]: no method named `my_debug` found for type `_` in the current scope
--> $DIR/call_method_on_inherent_impl_ref-err.rs:18:11
|
LL | fn my_debug(&self);
| -------- the method is available for `&_` here
...
LL | x.my_debug();
| ^^^^^^^^ method not found in `_`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
--> $DIR/call_method_on_inherent_impl_ref-err.rs:4:1
|
LL | trait MyDebug {
| ^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.

View File

@@ -0,0 +1,24 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
trait MyDebug {
fn my_debug(&self);
}
impl<T> MyDebug for &T
where
T: std::fmt::Debug,
{
fn my_debug(&self) {}
}
fn my_foo() -> impl std::fmt::Debug {
if false {
let x = my_foo();
x.my_debug();
//~^ ERROR no method named `my_debug` found
}
()
}
fn main() {}

View File

@@ -1,5 +1,6 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ check-pass
trait MyDebug {
fn my_debug(&self);
@@ -12,20 +13,9 @@ where
fn my_debug(&self) {}
}
fn my_foo() -> impl std::fmt::Debug {
if false {
let x = my_foo();
//[next]~^ ERROR type annotations needed
x.my_debug();
//[current]~^ ERROR no method named `my_debug` found
}
()
}
fn my_bar() -> impl std::fmt::Debug {
if false {
let x = &my_bar();
//[next]~^ ERROR type annotations needed
x.my_debug();
}
()

View File

@@ -1,31 +0,0 @@
error[E0282]: type annotations needed
--> $DIR/call_method_on_inherent_impl_ref.rs:17:13
|
LL | let x = my_foo();
| ^
LL |
LL | x.my_debug();
| -------- type must be known at this point
|
help: consider giving `x` an explicit type
|
LL | let x: /* Type */ = my_foo();
| ++++++++++++
error[E0282]: type annotations needed for `&_`
--> $DIR/call_method_on_inherent_impl_ref.rs:27:13
|
LL | let x = &my_bar();
| ^
LL |
LL | x.my_debug();
| -------- type must be known at this point
|
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
LL | let x: &_ = &my_bar();
| ++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0282`.

View File

@@ -1,9 +0,0 @@
error[E0282]: type annotations needed
--> $DIR/method-resolution4.rs:13:20
|
LL | foo(false).next().unwrap();
| ^^^^ cannot infer type
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View File

@@ -6,12 +6,11 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] check-pass
//@ check-pass
fn foo(b: bool) -> impl Iterator<Item = ()> {
if b {
foo(false).next().unwrap();
//[next]~^ ERROR type annotations needed
}
std::iter::empty()
}

View File

@@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/method-resolution5-deref-no-constrain.rs:20:5
|
LL | fn via_deref() -> impl Deref<Target = Foo> {
| --- expected `&Foo` because of return type
...
LL | Box::new(Foo)
| ^^^^^^^^^^^^^ expected `&Foo`, found `Box<Foo>`
|
= note: expected reference `&Foo`
found struct `Box<Foo>`
help: consider borrowing here
|
LL | &Box::new(Foo)
| +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@@ -0,0 +1,23 @@
//! The recursive method call yields the opaque type. We want
//! to use the impl candidate for `Foo` here without constraining
//! the opaque to `&Foo`.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[next] check-pass
use std::ops::Deref;
struct Foo;
impl Foo {
fn method(&self) {}
}
fn via_deref() -> impl Deref<Target = Foo> {
// Currently errors on stable, but should not
if false {
via_deref().method();
}
Box::new(Foo)
//[current]~^ ERROR mismatched types
}
fn main() {}

View File

@@ -0,0 +1,30 @@
//! The recursive method call yields the opaque type. We want
//! to use the trait candidate for `impl Foo` here while not
//! applying it for the `impl Deref`.
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ check-pass
use std::ops::Deref;
trait Foo {
fn method(&self) {}
}
impl Foo for u32 {}
fn via_deref() -> impl Deref<Target = impl Foo> {
if false {
via_deref().method();
}
Box::new(1u32)
}
fn via_deref_nested() -> Box<impl Deref<Target = impl Foo>> {
if false {
via_deref_nested().method();
}
Box::new(Box::new(1u32))
}
fn main() {}

View File

@@ -1,9 +0,0 @@
error[E0282]: type annotations needed
--> $DIR/recursive-bound-eval.rs:20:28
|
LL | move || recursive_fn().parse()
| ^^^^^ cannot infer type
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View File

@@ -1,10 +1,9 @@
//! Test that we can evaluate nested obligations when invoking methods on recursive calls on
//! an RPIT.
//@revisions: next current
//@ revisions: next current
//@[next] compile-flags: -Znext-solver
//@[current] check-pass
//@ check-pass
pub trait Parser<E> {
fn parse(&self) -> E;
@@ -18,7 +17,6 @@ impl<E, T: Fn() -> E> Parser<E> for T {
pub fn recursive_fn<E>() -> impl Parser<E> {
move || recursive_fn().parse()
//[next]~^ ERROR: type annotations needed
}
fn main() {}

View File

@@ -1,17 +0,0 @@
error[E0282]: type annotations needed
--> $DIR/recursive-coroutine-boxed.rs:11:23
|
LL | let mut gen = Box::pin(foo());
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
LL |
LL | let mut r = gen.as_mut().resume(());
| ------ type must be known at this point
|
help: consider specifying the generic argument
|
LL | let mut gen = Box::<T>::pin(foo());
| +++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View File

@@ -1,7 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[current] check-pass
//@[next] compile-flags: -Znext-solver
//@ check-pass
#![feature(coroutines, coroutine_trait)]
use std::ops::{Coroutine, CoroutineState};
@@ -9,7 +9,6 @@ use std::ops::{Coroutine, CoroutineState};
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
#[coroutine] || {
let mut gen = Box::pin(foo());
//[next]~^ ERROR type annotations needed
let mut r = gen.as_mut().resume(());
while let CoroutineState::Yielded(v) = r {
yield v;

View File

@@ -2,7 +2,13 @@ error[E0282]: type annotations needed
--> $DIR/method_resolution_trait_method_from_opaque.rs:28:18
|
LL | self.bar.next().unwrap();
| ^^^^ cannot infer type
| ^^^^
|
help: try using a fully qualified path to specify the expected types
|
LL - self.bar.next().unwrap();
LL + <_ as Iterator>::next(&mut self.bar).unwrap();
|
error: aborting due to 1 previous error