diff options
28 files changed, 357 insertions, 171 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3311c141055..e34ee6258b8 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -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. diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5d1b4be9e57..a20cd31113a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -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, }) } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index c1b7c9b9b4e..c5cd7c54e4e 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -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 diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 9b32e487607..85110530ae9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -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>, diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index afb86aaf8ab..a58caeecc33 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index ae731505abf..34e0176d213 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -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. diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr deleted file mode 100644 index 0def594daf1..00000000000 --- a/tests/ui/impl-trait/call_method_ambiguous.next.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs index 6bcafc8ce14..021d6c22f79 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.rs +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -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 diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr deleted file mode 100644 index 7bbf5f5153a..00000000000 --- a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.rs b/tests/ui/impl-trait/call_method_on_inherent_impl.rs index 0e333c3260a..1dd38bc6717 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.rs @@ -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(); } () diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr index 6ecb2b05fc5..e7104664470 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr @@ -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` diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr index 5fb0b8f1d14..de808259d40 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr @@ -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`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs index 7fb2ff3b2bc..0c9909efa1b 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs @@ -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` } () } diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr index fb51bb7b417..71acbd1497d 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.current.stderr @@ -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 { | ^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr new file mode 100644 index 00000000000..523505e9802 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.next.stderr @@ -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`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs new file mode 100644 index 00000000000..0ed09bc76a4 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs @@ -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() {} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-ok.rs index 4e4098b37f9..40739d6a0ce 100644 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref-ok.rs @@ -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(); } () diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr deleted file mode 100644 index 5dea3a715e9..00000000000 --- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/impl-trait/method-resolution4.next.stderr b/tests/ui/impl-trait/method-resolution4.next.stderr deleted file mode 100644 index 47a9aac19ec..00000000000 --- a/tests/ui/impl-trait/method-resolution4.next.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/impl-trait/method-resolution4.rs b/tests/ui/impl-trait/method-resolution4.rs index 90e7850cad5..f90a9309cda 100644 --- a/tests/ui/impl-trait/method-resolution4.rs +++ b/tests/ui/impl-trait/method-resolution4.rs @@ -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() } diff --git a/tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr new file mode 100644 index 00000000000..08578de426a --- /dev/null +++ b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.current.stderr @@ -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`. diff --git a/tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs new file mode 100644 index 00000000000..2c41f62b9fd --- /dev/null +++ b/tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs @@ -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() {} diff --git a/tests/ui/impl-trait/method-resolution5-deref.rs b/tests/ui/impl-trait/method-resolution5-deref.rs new file mode 100644 index 00000000000..6133a8efe24 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution5-deref.rs @@ -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() {} diff --git a/tests/ui/impl-trait/recursive-bound-eval.next.stderr b/tests/ui/impl-trait/recursive-bound-eval.next.stderr deleted file mode 100644 index e94f0a59a1d..00000000000 --- a/tests/ui/impl-trait/recursive-bound-eval.next.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/impl-trait/recursive-bound-eval.rs b/tests/ui/impl-trait/recursive-bound-eval.rs index 7859c8983fc..058b12e5651 100644 --- a/tests/ui/impl-trait/recursive-bound-eval.rs +++ b/tests/ui/impl-trait/recursive-bound-eval.rs @@ -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() {} diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr deleted file mode 100644 index 5ce6eb0fc39..00000000000 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr +++ /dev/null @@ -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`. diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index 306edc3591e..932023d103d 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -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; diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr index 5aae334ccbd..37bde4b18a4 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr @@ -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 |
