mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-19 19:17:31 +00:00
Auto merge of #89045 - oli-obk:lazy_normalization_in_opaque_types, r=nikomatsakis
Register normalization obligations instead of immediately normalizing in opaque type instantiation For lazy TAIT we will need to instantiate opaque types from within `rustc_infer`, which cannot invoke normalization methods (they are in `rustc_trait_resolution`). So before we move the logic over to `rustc_infer`, we need make sure no normalization happens anymore. This PR resolves that by just registering normalization obligations and continuing. This PR is best reviewed commit by commit I also included f7ad36e which is just an independent cleanup that touches the same code and reduces diagnostics noise a bit r? `@nikomatsakis` cc `@spastorino`
This commit is contained in:
commit
dda2a0eca4
@ -64,6 +64,7 @@ mod lub;
|
|||||||
pub mod nll_relate;
|
pub mod nll_relate;
|
||||||
pub mod opaque_types;
|
pub mod opaque_types;
|
||||||
pub mod outlives;
|
pub mod outlives;
|
||||||
|
mod projection;
|
||||||
pub mod region_constraints;
|
pub mod region_constraints;
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
mod sub;
|
mod sub;
|
||||||
|
39
compiler/rustc_infer/src/infer/projection.rs
Normal file
39
compiler/rustc_infer/src/infer/projection.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use rustc_middle::traits::ObligationCause;
|
||||||
|
use rustc_middle::ty::{self, ToPredicate, Ty};
|
||||||
|
|
||||||
|
use crate::traits::{Obligation, PredicateObligation};
|
||||||
|
|
||||||
|
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
use super::InferCtxt;
|
||||||
|
|
||||||
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
/// Instead of normalizing an associated type projection,
|
||||||
|
/// this function generates an inference variable and registers
|
||||||
|
/// an obligation that this inference variable must be the result
|
||||||
|
/// of the given projection. This allows us to proceed with projections
|
||||||
|
/// while they cannot be resolved yet due to missing information or
|
||||||
|
/// simply due to the lack of access to the trait resolution machinery.
|
||||||
|
pub fn infer_projection(
|
||||||
|
&self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
projection_ty: ty::ProjectionTy<'tcx>,
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
recursion_depth: usize,
|
||||||
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
let def_id = projection_ty.item_def_id;
|
||||||
|
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
||||||
|
span: self.tcx.def_span(def_id),
|
||||||
|
});
|
||||||
|
let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
|
||||||
|
let obligation = Obligation::with_depth(
|
||||||
|
cause,
|
||||||
|
recursion_depth,
|
||||||
|
param_env,
|
||||||
|
projection.to_predicate(self.tcx),
|
||||||
|
);
|
||||||
|
obligations.push(obligation);
|
||||||
|
ty_var
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
use crate::infer::InferCtxtExt as _;
|
|
||||||
use crate::traits::{self, ObligationCause, PredicateObligation};
|
use crate::traits::{self, ObligationCause, PredicateObligation};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
@ -863,7 +862,6 @@ struct Instantiator<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||||
#[instrument(level = "debug", skip(self))]
|
|
||||||
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
|
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
value.fold_with(&mut BottomUpFolder {
|
value.fold_with(&mut BottomUpFolder {
|
||||||
@ -954,6 +952,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn fold_opaque_ty(
|
fn fold_opaque_ty(
|
||||||
&mut self,
|
&mut self,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
@ -964,25 +963,18 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
|
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
|
||||||
|
|
||||||
debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs);
|
|
||||||
|
|
||||||
// Use the same type variable if the exact same opaque type appears more
|
// Use the same type variable if the exact same opaque type appears more
|
||||||
// than once in the return type (e.g., if it's passed to a type alias).
|
// than once in the return type (e.g., if it's passed to a type alias).
|
||||||
if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
|
if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
|
||||||
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
|
debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
|
||||||
return opaque_defn.concrete_ty;
|
return opaque_defn.concrete_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
|
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::TypeInference,
|
kind: TypeVariableOriginKind::TypeInference,
|
||||||
span: self.value_span,
|
span: self.value_span,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure that we are in fact defining the *entire* type
|
|
||||||
// (e.g., `type Foo<T: Bound> = impl Bar;` needs to be
|
|
||||||
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
|
|
||||||
debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,);
|
|
||||||
debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),);
|
|
||||||
|
|
||||||
// Ideally, we'd get the span where *this specific `ty` came
|
// Ideally, we'd get the span where *this specific `ty` came
|
||||||
// from*, but right now we just use the span from the overall
|
// from*, but right now we just use the span from the overall
|
||||||
// value being folded. In simple cases like `-> impl Foo`,
|
// value being folded. In simple cases like `-> impl Foo`,
|
||||||
@ -999,43 +991,40 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||||||
infcx.opaque_types_vars.insert(ty_var, ty);
|
infcx.opaque_types_vars.insert(ty_var, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
|
debug!("generated new type inference var {:?}", ty_var.kind());
|
||||||
self.compute_opaque_type_obligations(opaque_type_key);
|
|
||||||
|
|
||||||
ty_var
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_opaque_type_obligations(&mut self, opaque_type_key: OpaqueTypeKey<'tcx>) {
|
|
||||||
let infcx = self.infcx;
|
|
||||||
let tcx = infcx.tcx;
|
|
||||||
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
|
|
||||||
|
|
||||||
let item_bounds = tcx.explicit_item_bounds(def_id);
|
let item_bounds = tcx.explicit_item_bounds(def_id);
|
||||||
debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
|
|
||||||
let bounds: Vec<_> =
|
|
||||||
item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
|
|
||||||
|
|
||||||
let param_env = tcx.param_env(def_id);
|
self.obligations.reserve(item_bounds.len());
|
||||||
let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in(
|
for (predicate, _) in item_bounds {
|
||||||
|
debug!(?predicate);
|
||||||
|
let predicate = predicate.subst(tcx, substs);
|
||||||
|
debug!(?predicate);
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
ty_op: |ty| match ty.kind() {
|
||||||
|
ty::Projection(projection_ty) => infcx.infer_projection(
|
||||||
|
self.param_env,
|
||||||
|
*projection_ty,
|
||||||
ObligationCause::misc(self.value_span, self.body_id),
|
ObligationCause::misc(self.value_span, self.body_id),
|
||||||
param_env,
|
0,
|
||||||
bounds,
|
&mut self.obligations,
|
||||||
);
|
),
|
||||||
self.obligations.extend(obligations);
|
_ => ty,
|
||||||
|
},
|
||||||
|
lt_op: |lt| lt,
|
||||||
|
ct_op: |ct| ct,
|
||||||
|
});
|
||||||
|
debug!(?predicate);
|
||||||
|
|
||||||
debug!("instantiate_opaque_types: bounds={:?}", bounds);
|
|
||||||
|
|
||||||
for predicate in &bounds {
|
|
||||||
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
|
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
|
||||||
if projection.ty.references_error() {
|
if projection.ty.references_error() {
|
||||||
// No point on adding these obligations since there's a type error involved.
|
// No point on adding these obligations since there's a type error involved.
|
||||||
return;
|
return tcx.ty_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.obligations.reserve(bounds.len());
|
|
||||||
for predicate in bounds {
|
|
||||||
// Change the predicate to refer to the type variable,
|
// Change the predicate to refer to the type variable,
|
||||||
// which will be the concrete type instead of the opaque type.
|
// which will be the concrete type instead of the opaque type.
|
||||||
// This also instantiates nested instances of `impl Trait`.
|
// This also instantiates nested instances of `impl Trait`.
|
||||||
@ -1045,9 +1034,11 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||||||
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
|
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
|
||||||
|
|
||||||
// Require that the predicate holds for the concrete type.
|
// Require that the predicate holds for the concrete type.
|
||||||
debug!("instantiate_opaque_types: predicate={:?}", predicate);
|
debug!(?predicate);
|
||||||
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
|
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty_var
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,17 +810,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
// and a deferred predicate to resolve this when more type
|
// and a deferred predicate to resolve this when more type
|
||||||
// information is available.
|
// information is available.
|
||||||
|
|
||||||
let tcx = selcx.infcx().tcx;
|
selcx.infcx().infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
|
||||||
let def_id = projection_ty.item_def_id;
|
|
||||||
let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin {
|
|
||||||
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
|
||||||
span: tcx.def_span(def_id),
|
|
||||||
});
|
|
||||||
let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
|
|
||||||
let obligation =
|
|
||||||
Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate(tcx));
|
|
||||||
obligations.push(obligation);
|
|
||||||
ty_var
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ async fn copy() -> Result<()>
|
|||||||
//~^ ERROR this enum takes 2 generic arguments
|
//~^ ERROR this enum takes 2 generic arguments
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
//~^ ERROR type annotations needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
@ -16,13 +16,6 @@ help: add missing generic argument
|
|||||||
LL | async fn copy() -> Result<(), E>
|
LL | async fn copy() -> Result<(), E>
|
||||||
| +++
|
| +++
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error: aborting due to previous error
|
||||||
--> $DIR/issue-65159.rs:8:5
|
|
||||||
|
|
|
||||||
LL | Ok(())
|
|
||||||
| ^^ cannot infer type for type parameter `E` declared on the enum `Result`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0107`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0107, E0282.
|
|
||||||
For more information about an error, try `rustc --explain E0107`.
|
|
||||||
|
@ -17,7 +17,6 @@ async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
|
|||||||
//~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
|
//~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
|
||||||
//~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
|
//~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
|
||||||
LockedMarket(generator.lock().unwrap().buy())
|
LockedMarket(generator.lock().unwrap().buy())
|
||||||
//~^ ERROR cannot return value referencing temporary value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LockedMarket<T>(T);
|
struct LockedMarket<T>(T);
|
||||||
|
@ -7,7 +7,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
|
|||||||
| expected 0 lifetime arguments
|
| expected 0 lifetime arguments
|
||||||
|
|
|
|
||||||
note: struct defined here, with 0 lifetime parameters
|
note: struct defined here, with 0 lifetime parameters
|
||||||
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
|
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
|
||||||
|
|
|
|
||||||
LL | struct LockedMarket<T>(T);
|
LL | struct LockedMarket<T>(T);
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
@ -19,7 +19,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
|
|||||||
| ^^^^^^^^^^^^ expected 1 generic argument
|
| ^^^^^^^^^^^^ expected 1 generic argument
|
||||||
|
|
|
|
||||||
note: struct defined here, with 1 generic parameter: `T`
|
note: struct defined here, with 1 generic parameter: `T`
|
||||||
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
|
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
|
||||||
|
|
|
|
||||||
LL | struct LockedMarket<T>(T);
|
LL | struct LockedMarket<T>(T);
|
||||||
| ^^^^^^^^^^^^ -
|
| ^^^^^^^^^^^^ -
|
||||||
@ -28,16 +28,6 @@ help: add missing generic argument
|
|||||||
LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
|
LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
|
||||||
| +++
|
| +++
|
||||||
|
|
||||||
error[E0515]: cannot return value referencing temporary value
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5
|
|
||||||
|
|
|
||||||
LL | LockedMarket(generator.lock().unwrap().buy())
|
|
||||||
| ^^^^^^^^^^^^^-------------------------^^^^^^^
|
|
||||||
| | |
|
|
||||||
| | temporary value created here
|
|
||||||
| returns a value referencing data owned by the current function
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
For more information about this error, try `rustc --explain E0107`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0107, E0515.
|
|
||||||
For more information about an error, try `rustc --explain E0107`.
|
|
||||||
|
Loading…
Reference in New Issue
Block a user