Skip to content

Commit bbe2f6c

Browse files
committed
also try to normalize opaque types in alias-relate
with this, alias-relate treats all aliases the same way and it can be used for structural normalization.
1 parent 0a5b998 commit bbe2f6c

File tree

5 files changed

+27
-98
lines changed

5 files changed

+27
-98
lines changed

compiler/rustc_hir_typeck/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ fn typeck_with_fallback<'tcx>(
304304

305305
let typeck_results = fcx.resolve_type_vars_in_body(body);
306306

307+
let _ = fcx.infcx.take_opaque_types();
308+
307309
// Consistency check our TypeckResults instance can hold all ItemLocalIds
308310
// it will need to hold.
309311
assert_eq!(typeck_results.hir_owner, id.owner);

compiler/rustc_hir_typeck/src/writeback.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
562562

563563
#[instrument(skip(self), level = "debug")]
564564
fn visit_opaque_types(&mut self) {
565-
let opaque_types = self.fcx.infcx.take_opaque_types();
565+
// We clone the opaques instead of stealing them here as they are still used for
566+
// normalization in the next generation trait solver.
567+
let opaque_types = self.fcx.infcx.clone_opaque_types();
566568
for (opaque_type_key, decl) in opaque_types {
567569
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
568570
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);

compiler/rustc_infer/src/infer/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,12 @@ impl<'tcx> InferCtxt<'tcx> {
13251325
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
13261326
}
13271327

1328+
#[instrument(level = "debug", skip(self), ret)]
1329+
pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
1330+
debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
1331+
self.inner.borrow().opaque_type_storage.opaque_types.clone()
1332+
}
1333+
13281334
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
13291335
self.resolve_vars_if_possible(t).to_string()
13301336
}

compiler/rustc_trait_selection/src/solve/alias_relate.rs

+14-72
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,22 @@
33
//! of our more general approach to "lazy normalization".
44
//!
55
//! This is done by first normalizing both sides of the goal, ending up in
6-
//! either a concrete type, rigid projection, opaque, or an infer variable.
6+
//! either a concrete type, rigid alias, or an infer variable.
77
//! These are related further according to the rules below:
88
//!
9-
//! (1.) If we end up with a rigid projection and a rigid projection, then we
10-
//! relate those projections structurally.
9+
//! (1.) If we end up with two rigid aliases, then we relate them structurally.
1110
//!
12-
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
13-
//! have its hidden type defined to be that rigid projection.
14-
//!
15-
//! (3.) If we end up with an opaque and an opaque, then we assemble two
16-
//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
17-
//! versa.
18-
//!
19-
//! (4.) If we end up with an infer var and an opaque or rigid projection, then
11+
//! (2.) If we end up with an infer var and a rigid alias, then
2012
//! we assign the alias to the infer var.
2113
//!
22-
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
23-
//! define the hidden type of the opaque to be the rigid type.
24-
//!
25-
//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
14+
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
2615
//! relate them structurally.
16+
//!
17+
//! Subtle: when relating an opaque to another type, we emit a
18+
//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
19+
//! This nested goal starts out as ambiguous and does not actually define the opaque.
20+
//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
21+
//! `NormalizesTo` goal, at which point the opaque is actually defined.
2722
2823
use super::{EvalCtxt, GoalSource};
2924
use rustc_infer::infer::DefineOpaqueTypes;
@@ -59,31 +54,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
5954
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
6055
}
6156

62-
(Some(alias), None) => {
57+
(Some(_), None) => {
6358
if rhs.is_infer() {
6459
self.relate(param_env, lhs, variance, rhs)?;
6560
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
66-
} else if alias.is_opaque(tcx) {
67-
// FIXME: This doesn't account for variance.
68-
self.define_opaque(param_env, alias, rhs)
6961
} else {
7062
Err(NoSolution)
7163
}
7264
}
73-
(None, Some(alias)) => {
65+
(None, Some(_)) => {
7466
if lhs.is_infer() {
7567
self.relate(param_env, lhs, variance, rhs)?;
7668
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
77-
} else if alias.is_opaque(tcx) {
78-
// FIXME: This doesn't account for variance.
79-
self.define_opaque(param_env, alias, lhs)
8069
} else {
8170
Err(NoSolution)
8271
}
8372
}
8473

8574
(Some(alias_lhs), Some(alias_rhs)) => {
86-
self.relate_rigid_alias_or_opaque(param_env, alias_lhs, variance, alias_rhs)
75+
self.relate(param_env, alias_lhs, variance, alias_rhs)?;
76+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
8777
}
8878
}
8979
}
@@ -118,52 +108,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
118108
}
119109
}
120110
}
121-
122-
fn define_opaque(
123-
&mut self,
124-
param_env: ty::ParamEnv<'tcx>,
125-
opaque: ty::AliasTy<'tcx>,
126-
term: ty::Term<'tcx>,
127-
) -> QueryResult<'tcx> {
128-
self.add_goal(
129-
GoalSource::Misc,
130-
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }),
131-
);
132-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
133-
}
134-
135-
fn relate_rigid_alias_or_opaque(
136-
&mut self,
137-
param_env: ty::ParamEnv<'tcx>,
138-
lhs: ty::AliasTy<'tcx>,
139-
variance: ty::Variance,
140-
rhs: ty::AliasTy<'tcx>,
141-
) -> QueryResult<'tcx> {
142-
let tcx = self.tcx();
143-
let mut candidates = vec![];
144-
if lhs.is_opaque(tcx) {
145-
candidates.extend(
146-
self.probe_misc_candidate("define-lhs-opaque")
147-
.enter(|ecx| ecx.define_opaque(param_env, lhs, rhs.to_ty(tcx).into())),
148-
);
149-
}
150-
151-
if rhs.is_opaque(tcx) {
152-
candidates.extend(
153-
self.probe_misc_candidate("define-rhs-opaque")
154-
.enter(|ecx| ecx.define_opaque(param_env, rhs, lhs.to_ty(tcx).into())),
155-
);
156-
}
157-
158-
candidates.extend(self.probe_misc_candidate("args-relate").enter(|ecx| {
159-
ecx.relate(param_env, lhs, variance, rhs)?;
160-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
161-
}));
162-
163-
if let Some(result) = self.try_merge_responses(&candidates) {
164-
Ok(result)
165-
} else {
166-
self.flounder(&candidates)
167-
}
168-
}
169111
}

compiler/rustc_trait_selection/src/solve/mod.rs

+2-25
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ use rustc_middle::traits::solve::{
2222
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
2323
QueryResult, Response,
2424
};
25-
use rustc_middle::traits::Reveal;
26-
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
25+
use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
2726
use rustc_middle::ty::{
2827
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
2928
};
@@ -292,32 +291,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
292291
return None;
293292
}
294293

295-
let ty::Alias(kind, alias) = *ty.kind() else {
294+
let ty::Alias(_, alias) = *ty.kind() else {
296295
return Some(ty);
297296
};
298297

299-
// We do no always define opaque types eagerly to allow non-defining uses
300-
// in the defining scope. However, if we can unify this opaque to an existing
301-
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
302-
// through.
303-
if let DefineOpaqueTypes::No = define_opaque_types
304-
&& let Reveal::UserFacing = param_env.reveal()
305-
&& let ty::Opaque = kind
306-
&& let Some(def_id) = alias.def_id.as_local()
307-
&& self.can_define_opaque_ty(def_id)
308-
{
309-
if self
310-
.unify_existing_opaque_tys(
311-
param_env,
312-
OpaqueTypeKey { def_id, args: alias.args },
313-
self.next_ty_infer(),
314-
)
315-
.is_empty()
316-
{
317-
return Some(ty);
318-
}
319-
}
320-
321298
match self.commit_if_ok(|this| {
322299
let normalized_ty = this.next_ty_infer();
323300
let normalizes_to_goal = Goal::new(

0 commit comments

Comments
 (0)