Skip to content

Commit 04f2c01

Browse files
committed
implement eager normalization in a fresh context during typeck
1 parent 5d0863b commit 04f2c01

6 files changed

Lines changed: 97 additions & 16 deletions

File tree

compiler/rustc_infer/src/infer/at.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
140140
ty::Contravariant,
141141
actual,
142142
self.cause.span,
143-
// TODO: should normalize
144-
&mut |_alias| self.infcx.next_ty_var(self.cause.span),
143+
&mut |alias| {
144+
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
145+
},
145146
)
146147
.map(|goals| self.goals_to_obligations(goals))
147148
} else {
@@ -175,8 +176,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
175176
ty::Covariant,
176177
actual,
177178
self.cause.span,
178-
// TODO: should normalize
179-
&mut |_alias| self.infcx.next_ty_var(self.cause.span),
179+
&mut |alias| {
180+
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
181+
},
180182
)
181183
.map(|goals| self.goals_to_obligations(goals))
182184
} else {
@@ -229,8 +231,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
229231
ty::Invariant,
230232
actual,
231233
self.cause.span,
232-
// TODO: should normalize
233-
&mut |_alias| self.infcx.next_ty_var(self.cause.span),
234+
&mut |alias| {
235+
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
236+
},
234237
)
235238
.map(|goals| self.goals_to_obligations(goals))
236239
} else {

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::cell::{Cell, RefCell};
2-
use std::fmt;
2+
use std::{fmt, mem};
33

44
pub use at::DefineOpaqueTypes;
55
use free_regions::RegionRelations;
@@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
2121
use rustc_macros::extension;
2222
pub use rustc_macros::{TypeFoldable, TypeVisitable};
2323
use rustc_middle::bug;
24+
use rustc_middle::hooks::TypeErasedInfcx;
2425
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
2526
use rustc_middle::mir::ConstraintCategory;
2627
use rustc_middle::traits::select;
@@ -1498,6 +1499,16 @@ impl<'tcx> InferCtxt<'tcx> {
14981499
}
14991500
}
15001501

1502+
pub fn try_eagerly_normalize_alias<'a>(
1503+
&'a self,
1504+
param_env: ty::ParamEnv<'tcx>,
1505+
span: Span,
1506+
alias: ty::AliasTy<'tcx>,
1507+
) -> Ty<'tcx> {
1508+
let erased = unsafe { mem::transmute::<_, TypeErasedInfcx<'a, 'tcx>>(self) };
1509+
self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias)
1510+
}
1511+
15011512
/// Attach a callback to be invoked on each root obligation evaluated in the new trait solver.
15021513
pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) {
15031514
debug_assert!(

compiler/rustc_infer/src/infer/relate/lattice.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,7 @@ impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
300300
))]);
301301
}
302302

303-
fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
304-
// TODO: this should actually normalize
305-
self.infcx.next_ty_var(self.span())
303+
fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
304+
self.infcx.try_eagerly_normalize_alias(self.param_env(), self.span(), alias)
306305
}
307306
}

compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
900900
rustc_hir_typeck::provide(&mut providers.queries);
901901
ty::provide(&mut providers.queries);
902902
traits::provide(&mut providers.queries);
903-
solve::provide(&mut providers.queries);
903+
solve::provide(providers);
904904
rustc_passes::provide(&mut providers.queries);
905905
rustc_traits::provide(&mut providers.queries);
906906
rustc_ty_utils::provide(&mut providers.queries);

compiler/rustc_middle/src/hooks/mod.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
//! similar to queries, but queries come with a lot of machinery for caching and incremental
44
//! compilation, whereas hooks are just plain function pointers without any of the query magic.
55
6+
use std::marker::PhantomData;
7+
68
use rustc_hir::def_id::{DefId, DefPathHash};
79
use rustc_session::StableCrateId;
810
use rustc_span::def_id::{CrateNum, LocalDefId};
9-
use rustc_span::{ExpnHash, ExpnId};
11+
use rustc_span::{ExpnHash, ExpnId, Span};
1012

11-
use crate::mir;
1213
use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex};
1314
use crate::ty::{Ty, TyCtxt};
15+
use crate::{mir, ty};
1416

1517
macro_rules! declare_hooks {
1618
($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
@@ -117,6 +119,24 @@ declare_hooks! {
117119
encoder: &mut CacheEncoder<'_, 'tcx>,
118120
query_result_index: &mut EncodedDepNodeIndex
119121
) -> ();
122+
123+
/// Tries to normalize an alias, ignoring any errors.
124+
///
125+
/// Generalization with the new trait solver calls into this,
126+
/// when generalizing outside of the trait solver in `hir_typeck`.
127+
hook try_eagerly_normalize_alias(
128+
type_erased_infcx: TypeErasedInfcx<'_, 'tcx>,
129+
param_env: ty::ParamEnv<'tcx>,
130+
span: Span,
131+
alias: ty::AliasTy<'tcx>
132+
) -> Ty<'tcx>;
133+
}
134+
135+
// `repr(transparent)` so we can transmute a `&'a Infcx<'tcx>` to this struct.
136+
#[repr(transparent)]
137+
pub struct TypeErasedInfcx<'a, 'tcx> {
138+
_infcx: *const (),
139+
phantom: PhantomData<&'a mut &'tcx ()>,
120140
}
121141

122142
#[cold]

compiler/rustc_trait_selection/src/solve.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
use std::mem;
2+
3+
use rustc_infer::infer::InferCtxt;
4+
use rustc_infer::traits::{Obligation, ObligationCause};
5+
use rustc_middle::hooks::TypeErasedInfcx;
16
pub use rustc_next_trait_solver::solve::*;
27

38
mod delegate;
@@ -13,10 +18,13 @@ pub use normalize::{
1318
deeply_normalize, deeply_normalize_with_skipped_universes,
1419
deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
1520
};
16-
use rustc_middle::query::Providers;
17-
use rustc_middle::ty::TyCtxt;
21+
use rustc_middle::ty::{self, Ty, TyCtxt};
22+
use rustc_middle::util::Providers;
23+
use rustc_span::Span;
1824
pub use select::InferCtxtSelectExt;
1925

26+
use crate::traits::ObligationCtxt;
27+
2028
fn evaluate_root_goal_for_proof_tree_raw<'tcx>(
2129
tcx: TyCtxt<'tcx>,
2230
canonical_input: CanonicalInput<TyCtxt<'tcx>>,
@@ -27,6 +35,46 @@ fn evaluate_root_goal_for_proof_tree_raw<'tcx>(
2735
)
2836
}
2937

38+
fn try_eagerly_normalize_alias<'a, 'tcx>(
39+
tcx: TyCtxt<'tcx>,
40+
type_erased_infcx: TypeErasedInfcx<'a, 'tcx>,
41+
param_env: ty::ParamEnv<'tcx>,
42+
span: Span,
43+
alias: ty::AliasTy<'tcx>,
44+
) -> Ty<'tcx> {
45+
let infcx = unsafe {
46+
mem::transmute::<TypeErasedInfcx<'a, 'tcx>, &'a InferCtxt<'tcx>>(type_erased_infcx)
47+
};
48+
49+
let ocx = ObligationCtxt::new(infcx);
50+
51+
let infer_term = infcx.next_ty_var(span);
52+
53+
// Dummy because we ignore the error anyway.
54+
// We do provide a span, because this span is used when registering opaque types.
55+
// For example, if we don't provide a span here, some diagnostics talking about TAIT will refer to a dummy span.
56+
let cause = ObligationCause::dummy_with_span(span);
57+
let obligation = Obligation::new(
58+
tcx,
59+
// we ignore the error anyway
60+
ObligationCause::dummy(),
61+
param_env,
62+
ty::PredicateKind::AliasRelate(
63+
alias.to_ty(tcx).into(),
64+
infer_term.into(),
65+
ty::AliasRelationDirection::Equate,
66+
),
67+
);
68+
69+
ocx.register_obligation(obligation);
70+
71+
// This only tries to eagerly resolve, if it errors we don't care.
72+
let _ = ocx.try_evaluate_obligations();
73+
74+
infcx.resolve_vars_if_possible(infer_term)
75+
}
76+
3077
pub fn provide(providers: &mut Providers) {
31-
*providers = Providers { evaluate_root_goal_for_proof_tree_raw, ..*providers };
78+
providers.hooks.try_eagerly_normalize_alias = try_eagerly_normalize_alias;
79+
providers.queries.evaluate_root_goal_for_proof_tree_raw = evaluate_root_goal_for_proof_tree_raw;
3280
}

0 commit comments

Comments
 (0)