Skip to content

Commit dda2a0e

Browse files
committed
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`
2 parents 49c0861 + afb7472 commit dda2a0e

File tree

8 files changed

+78
-76
lines changed

8 files changed

+78
-76
lines changed

Diff for: compiler/rustc_infer/src/infer/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ mod lub;
6464
pub mod nll_relate;
6565
pub mod opaque_types;
6666
pub mod outlives;
67+
mod projection;
6768
pub mod region_constraints;
6869
pub mod resolve;
6970
mod sub;

Diff for: compiler/rustc_infer/src/infer/projection.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use rustc_middle::traits::ObligationCause;
2+
use rustc_middle::ty::{self, ToPredicate, Ty};
3+
4+
use crate::traits::{Obligation, PredicateObligation};
5+
6+
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
7+
use super::InferCtxt;
8+
9+
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10+
/// Instead of normalizing an associated type projection,
11+
/// this function generates an inference variable and registers
12+
/// an obligation that this inference variable must be the result
13+
/// of the given projection. This allows us to proceed with projections
14+
/// while they cannot be resolved yet due to missing information or
15+
/// simply due to the lack of access to the trait resolution machinery.
16+
pub fn infer_projection(
17+
&self,
18+
param_env: ty::ParamEnv<'tcx>,
19+
projection_ty: ty::ProjectionTy<'tcx>,
20+
cause: ObligationCause<'tcx>,
21+
recursion_depth: usize,
22+
obligations: &mut Vec<PredicateObligation<'tcx>>,
23+
) -> Ty<'tcx> {
24+
let def_id = projection_ty.item_def_id;
25+
let ty_var = self.next_ty_var(TypeVariableOrigin {
26+
kind: TypeVariableOriginKind::NormalizeProjectionType,
27+
span: self.tcx.def_span(def_id),
28+
});
29+
let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
30+
let obligation = Obligation::with_depth(
31+
cause,
32+
recursion_depth,
33+
param_env,
34+
projection.to_predicate(self.tcx),
35+
);
36+
obligations.push(obligation);
37+
ty_var
38+
}
39+
}

Diff for: compiler/rustc_trait_selection/src/opaque_types.rs

+31-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::infer::InferCtxtExt as _;
21
use crate::traits::{self, ObligationCause, PredicateObligation};
32
use rustc_data_structures::fx::FxHashMap;
43
use rustc_data_structures::sync::Lrc;
@@ -863,7 +862,6 @@ struct Instantiator<'a, 'tcx> {
863862
}
864863

865864
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
866-
#[instrument(level = "debug", skip(self))]
867865
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
868866
let tcx = self.infcx.tcx;
869867
value.fold_with(&mut BottomUpFolder {
@@ -954,6 +952,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
954952
})
955953
}
956954

955+
#[instrument(skip(self), level = "debug")]
957956
fn fold_opaque_ty(
958957
&mut self,
959958
ty: Ty<'tcx>,
@@ -964,25 +963,18 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
964963
let tcx = infcx.tcx;
965964
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
966965

967-
debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs);
968-
969966
// Use the same type variable if the exact same opaque type appears more
970967
// than once in the return type (e.g., if it's passed to a type alias).
971968
if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
972-
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
969+
debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
973970
return opaque_defn.concrete_ty;
974971
}
972+
975973
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
976974
kind: TypeVariableOriginKind::TypeInference,
977975
span: self.value_span,
978976
});
979977

980-
// Make sure that we are in fact defining the *entire* type
981-
// (e.g., `type Foo<T: Bound> = impl Bar;` needs to be
982-
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
983-
debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,);
984-
debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),);
985-
986978
// Ideally, we'd get the span where *this specific `ty` came
987979
// from*, but right now we just use the span from the overall
988980
// value being folded. In simple cases like `-> impl Foo`,
@@ -999,43 +991,40 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
999991
infcx.opaque_types_vars.insert(ty_var, ty);
1000992
}
1001993

1002-
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
1003-
self.compute_opaque_type_obligations(opaque_type_key);
1004-
1005-
ty_var
1006-
}
1007-
1008-
fn compute_opaque_type_obligations(&mut self, opaque_type_key: OpaqueTypeKey<'tcx>) {
1009-
let infcx = self.infcx;
1010-
let tcx = infcx.tcx;
1011-
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
994+
debug!("generated new type inference var {:?}", ty_var.kind());
1012995

1013996
let item_bounds = tcx.explicit_item_bounds(def_id);
1014-
debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
1015-
let bounds: Vec<_> =
1016-
item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
1017-
1018-
let param_env = tcx.param_env(def_id);
1019-
let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in(
1020-
ObligationCause::misc(self.value_span, self.body_id),
1021-
param_env,
1022-
bounds,
1023-
);
1024-
self.obligations.extend(obligations);
1025997

1026-
debug!("instantiate_opaque_types: bounds={:?}", bounds);
998+
self.obligations.reserve(item_bounds.len());
999+
for (predicate, _) in item_bounds {
1000+
debug!(?predicate);
1001+
let predicate = predicate.subst(tcx, substs);
1002+
debug!(?predicate);
1003+
1004+
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
1005+
let predicate = predicate.fold_with(&mut BottomUpFolder {
1006+
tcx,
1007+
ty_op: |ty| match ty.kind() {
1008+
ty::Projection(projection_ty) => infcx.infer_projection(
1009+
self.param_env,
1010+
*projection_ty,
1011+
ObligationCause::misc(self.value_span, self.body_id),
1012+
0,
1013+
&mut self.obligations,
1014+
),
1015+
_ => ty,
1016+
},
1017+
lt_op: |lt| lt,
1018+
ct_op: |ct| ct,
1019+
});
1020+
debug!(?predicate);
10271021

1028-
for predicate in &bounds {
10291022
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
10301023
if projection.ty.references_error() {
10311024
// No point on adding these obligations since there's a type error involved.
1032-
return;
1025+
return tcx.ty_error();
10331026
}
10341027
}
1035-
}
1036-
1037-
self.obligations.reserve(bounds.len());
1038-
for predicate in bounds {
10391028
// Change the predicate to refer to the type variable,
10401029
// which will be the concrete type instead of the opaque type.
10411030
// This also instantiates nested instances of `impl Trait`.
@@ -1045,9 +1034,11 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
10451034
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
10461035

10471036
// Require that the predicate holds for the concrete type.
1048-
debug!("instantiate_opaque_types: predicate={:?}", predicate);
1037+
debug!(?predicate);
10491038
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
10501039
}
1040+
1041+
ty_var
10511042
}
10521043
}
10531044

Diff for: compiler/rustc_trait_selection/src/traits/project.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -810,17 +810,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>(
810810
// and a deferred predicate to resolve this when more type
811811
// information is available.
812812

813-
let tcx = selcx.infcx().tcx;
814-
let def_id = projection_ty.item_def_id;
815-
let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin {
816-
kind: TypeVariableOriginKind::NormalizeProjectionType,
817-
span: tcx.def_span(def_id),
818-
});
819-
let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
820-
let obligation =
821-
Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate(tcx));
822-
obligations.push(obligation);
823-
ty_var
813+
selcx.infcx().infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
824814
})
825815
}
826816

Diff for: src/test/ui/async-await/issues/issue-65159.rs

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ async fn copy() -> Result<()>
66
//~^ ERROR this enum takes 2 generic arguments
77
{
88
Ok(())
9-
//~^ ERROR type annotations needed
109
}
1110

1211
fn main() { }

Diff for: src/test/ui/async-await/issues/issue-65159.stderr

+2-9
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ help: add missing generic argument
1616
LL | async fn copy() -> Result<(), E>
1717
| +++
1818

19-
error[E0282]: type annotations needed
20-
--> $DIR/issue-65159.rs:8:5
21-
|
22-
LL | Ok(())
23-
| ^^ cannot infer type for type parameter `E` declared on the enum `Result`
24-
25-
error: aborting due to 2 previous errors
19+
error: aborting due to previous error
2620

27-
Some errors have detailed explanations: E0107, E0282.
28-
For more information about an error, try `rustc --explain E0107`.
21+
For more information about this error, try `rustc --explain E0107`.

Diff for: src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
1717
//~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
1818
//~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
1919
LockedMarket(generator.lock().unwrap().buy())
20-
//~^ ERROR cannot return value referencing temporary value
2120
}
2221

2322
struct LockedMarket<T>(T);

Diff for: src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr

+4-14
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
77
| expected 0 lifetime arguments
88
|
99
note: struct defined here, with 0 lifetime parameters
10-
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
10+
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
1111
|
1212
LL | struct LockedMarket<T>(T);
1313
| ^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
1919
| ^^^^^^^^^^^^ expected 1 generic argument
2020
|
2121
note: struct defined here, with 1 generic parameter: `T`
22-
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8
22+
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
2323
|
2424
LL | struct LockedMarket<T>(T);
2525
| ^^^^^^^^^^^^ -
@@ -28,16 +28,6 @@ help: add missing generic argument
2828
LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
2929
| +++
3030

31-
error[E0515]: cannot return value referencing temporary value
32-
--> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5
33-
|
34-
LL | LockedMarket(generator.lock().unwrap().buy())
35-
| ^^^^^^^^^^^^^-------------------------^^^^^^^
36-
| | |
37-
| | temporary value created here
38-
| returns a value referencing data owned by the current function
39-
40-
error: aborting due to 3 previous errors
31+
error: aborting due to 2 previous errors
4132

42-
Some errors have detailed explanations: E0107, E0515.
43-
For more information about an error, try `rustc --explain E0107`.
33+
For more information about this error, try `rustc --explain E0107`.

0 commit comments

Comments
 (0)