From 689a868a1f6f20b49ea904ca7cda14636b7768b3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Dec 2021 15:17:16 +0000 Subject: [PATCH 1/3] Remove some noise from opaque type errors around associated types --- .../rustc_infer/src/infer/opaque_types.rs | 14 +++++ .../type-alias-impl-trait/bound_reduction2.rs | 4 -- .../bound_reduction2.stderr | 56 +------------------ 3 files changed, 17 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index c2ef0b41e27bf..eab5e5a5fb4e9 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -551,6 +551,20 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicate = predicate.subst(tcx, substs); debug!(?predicate); + // Replace all other mentions of the same opaque type with the hidden type, + // as the bounds must hold on the hidden type after all. + let predicate = predicate.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| match *ty.kind() { + ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { + ty_var + } + _ => 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, 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 579067340e85c..cee8186dd8f8c 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -15,9 +15,5 @@ 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 a77c0000f12e1..03e696fe89803 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,34 +1,8 @@ -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:1 + --> $DIR/bound_reduction2.rs:16:46 | LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | note: used non-generic type `::Assoc` for generic parameter --> $DIR/bound_reduction2.rs:9:10 @@ -36,35 +10,11 @@ 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 6 previous errors +error: aborting due to 2 previous errors From 5c4600227329a273c0c6c844e4a10ce650ead601 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Dec 2021 15:26:01 +0000 Subject: [PATCH 2/3] Eagerly instantiate opaque types --- compiler/rustc_infer/src/infer/opaque_types.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index eab5e5a5fb4e9..d5e65705b2885 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -551,14 +551,16 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicate = predicate.subst(tcx, substs); debug!(?predicate); - // Replace all other mentions of the same opaque type with the hidden type, - // as the bounds must hold on the hidden type after all. 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, @@ -589,10 +591,6 @@ 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); From bdeeb07bf6400622074f04ca2523dac1512ab662 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Dec 2021 20:24:28 +0000 Subject: [PATCH 3/3] Prove obligations to termination instead of ignoring ambiguities. Sometimes an obligation depends on a later one, so we can't just process them in order like it was done previously. This is not a problem in our test suite, but there may be ICEs out there and it will definitely be a problem with lazy TAIT. --- .../src/traits/query/type_op/mod.rs | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) 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 12ca3faeb3797..d662f61e2cf4d 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,7 +4,9 @@ use crate::infer::canonical::{ use crate::infer::{InferCtxt, InferOk}; use crate::traits::query::Fallible; use crate::traits::ObligationCause; -use rustc_infer::infer::canonical::Canonical; +use rustc_infer::infer::canonical::{Canonical, Certainty}; +use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::PredicateObligations; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use std::fmt; @@ -17,7 +19,6 @@ 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::*; @@ -80,9 +81,14 @@ 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>>)> { + ) -> Fallible<( + Self::QueryResponse, + Option>>, + PredicateObligations<'tcx>, + Certainty, + )> { if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { - return Ok((result, None)); + return Ok((result, None, vec![], Certainty::Proven)); } // FIXME(#33684) -- We need to use @@ -104,20 +110,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { output_query_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. - 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))) + Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty)) } } @@ -129,9 +122,39 @@ where fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { let mut region_constraints = QueryRegionConstraints::default(); - let (output, canonicalized_query) = + let (output, canonicalized_query, mut obligations, _) = 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 =