diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 04b1a42e5beef..11153fbe7896b 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -555,22 +555,6 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicate = predicate.subst(tcx, substs); debug!(?predicate); - let predicate = predicate.fold_with(&mut BottomUpFolder { - tcx, - ty_op: |ty| match *ty.kind() { - // Replace all other mentions of the same opaque type with the hidden type, - // as the bounds must hold on the hidden type after all. - ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { - ty_var - } - // Instantiate nested instances of `impl Trait`. - ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty), - _ => ty, - }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }); - // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them. let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, @@ -595,6 +579,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { return tcx.ty_error(); } } + // Change the predicate to refer to the type variable, + // which will be the concrete type instead of the opaque type. + // This also instantiates nested instances of `impl Trait`. + let predicate = self.instantiate_opaque_types_in_map(predicate); let cause = traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index d662f61e2cf4d..12ca3faeb3797 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -4,9 +4,7 @@ use crate::infer::canonical::{ use crate::infer::{InferCtxt, InferOk}; use crate::traits::query::Fallible; use crate::traits::ObligationCause; -use rustc_infer::infer::canonical::{Canonical, Certainty}; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::PredicateObligations; +use rustc_infer::infer::canonical::Canonical; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use std::fmt; @@ -19,6 +17,7 @@ pub mod implied_outlives_bounds; pub mod normalize; pub mod outlives; pub mod prove_predicate; +use self::prove_predicate::ProvePredicate; pub mod subtype; pub use rustc_middle::traits::query::type_op::*; @@ -81,14 +80,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { query_key: ParamEnvAnd<'tcx, Self>, infcx: &InferCtxt<'_, 'tcx>, output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, - ) -> Fallible<( - Self::QueryResponse, - Option>>, - PredicateObligations<'tcx>, - Certainty, - )> { + ) -> Fallible<(Self::QueryResponse, Option>>)> { if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { - return Ok((result, None, vec![], Certainty::Proven)); + return Ok((result, None)); } // FIXME(#33684) -- We need to use @@ -110,7 +104,20 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { output_query_region_constraints, )?; - Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty)) + // Typically, instantiating NLL query results does not + // create obligations. However, in some cases there + // are unresolved type variables, and unify them *can* + // create obligations. In that case, we have to go + // fulfill them. We do this via a (recursive) query. + for obligation in obligations { + let ((), _) = ProvePredicate::fully_perform_into( + obligation.param_env.and(ProvePredicate::new(obligation.predicate)), + infcx, + output_query_region_constraints, + )?; + } + + Ok((value, Some(canonical_self))) } } @@ -122,39 +129,9 @@ where fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { let mut region_constraints = QueryRegionConstraints::default(); - let (output, canonicalized_query, mut obligations, _) = + let (output, canonicalized_query) = Q::fully_perform_into(self, infcx, &mut region_constraints)?; - // Typically, instantiating NLL query results does not - // create obligations. However, in some cases there - // are unresolved type variables, and unify them *can* - // create obligations. In that case, we have to go - // fulfill them. We do this via a (recursive) query. - while !obligations.is_empty() { - trace!("{:#?}", obligations); - let mut progress = false; - for obligation in std::mem::take(&mut obligations) { - let obligation = infcx.resolve_vars_if_possible(obligation); - match ProvePredicate::fully_perform_into( - obligation.param_env.and(ProvePredicate::new(obligation.predicate)), - infcx, - &mut region_constraints, - ) { - Ok(((), _, new, certainty)) => { - obligations.extend(new); - progress = true; - if let Certainty::Ambiguous = certainty { - obligations.push(obligation); - } - } - Err(_) => obligations.push(obligation), - } - } - if !progress { - return Err(NoSolution); - } - } - // Promote the final query-region-constraints into a // (optional) ref-counted vector: let region_constraints = diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs index cee8186dd8f8c..579067340e85c 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -15,5 +15,9 @@ impl Trait for () {} fn foo_desugared(_: T) -> Foo { //~^ ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope + //~| ERROR `T` is part of concrete type but not used in parameter list + //~| ERROR `T` is part of concrete type but not used in parameter list () } diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index 03e696fe89803..a77c0000f12e1 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,8 +1,34 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/bound_reduction2.rs:16:60 + | +LL | fn foo_desugared(_: T) -> Foo { + | ____________________________________________________________^ +LL | | +LL | | +LL | | +... | +LL | | () +LL | | } + | |_^ + +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/bound_reduction2.rs:16:60 + | +LL | fn foo_desugared(_: T) -> Foo { + | ____________________________________________________________^ +LL | | +LL | | +LL | | +... | +LL | | () +LL | | } + | |_^ + error: non-defining opaque type use in defining scope - --> $DIR/bound_reduction2.rs:16:46 + --> $DIR/bound_reduction2.rs:16:1 | LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: used non-generic type `::Assoc` for generic parameter --> $DIR/bound_reduction2.rs:9:10 @@ -10,11 +36,35 @@ note: used non-generic type `::Assoc` for generic parameter LL | type Foo = impl Trait; | ^ +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:16:1 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: used non-generic type `_` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 + | +LL | type Foo = impl Trait; + | ^ + +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:16:1 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: used non-generic type `_` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 + | +LL | type Foo = impl Trait; + | ^ + error: could not find defining uses --> $DIR/bound_reduction2.rs:9:15 | LL | type Foo = impl Trait; | ^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors