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.
This commit is contained in:
parent
0a5b998c57
commit
bbe2f6c0b2
5 changed files with 27 additions and 98 deletions
|
@ -304,6 +304,8 @@ fn typeck_with_fallback<'tcx>(
|
||||||
|
|
||||||
let typeck_results = fcx.resolve_type_vars_in_body(body);
|
let typeck_results = fcx.resolve_type_vars_in_body(body);
|
||||||
|
|
||||||
|
let _ = fcx.infcx.take_opaque_types();
|
||||||
|
|
||||||
// Consistency check our TypeckResults instance can hold all ItemLocalIds
|
// Consistency check our TypeckResults instance can hold all ItemLocalIds
|
||||||
// it will need to hold.
|
// it will need to hold.
|
||||||
assert_eq!(typeck_results.hir_owner, id.owner);
|
assert_eq!(typeck_results.hir_owner, id.owner);
|
||||||
|
|
|
@ -562,7 +562,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn visit_opaque_types(&mut self) {
|
fn visit_opaque_types(&mut self) {
|
||||||
let opaque_types = self.fcx.infcx.take_opaque_types();
|
// We clone the opaques instead of stealing them here as they are still used for
|
||||||
|
// normalization in the next generation trait solver.
|
||||||
|
let opaque_types = self.fcx.infcx.clone_opaque_types();
|
||||||
for (opaque_type_key, decl) in opaque_types {
|
for (opaque_type_key, decl) in opaque_types {
|
||||||
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
|
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
|
||||||
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
|
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
|
||||||
|
|
|
@ -1325,6 +1325,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
|
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
|
pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
|
||||||
|
debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
|
||||||
|
self.inner.borrow().opaque_type_storage.opaque_types.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
|
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
|
||||||
self.resolve_vars_if_possible(t).to_string()
|
self.resolve_vars_if_possible(t).to_string()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,27 +3,22 @@
|
||||||
//! of our more general approach to "lazy normalization".
|
//! of our more general approach to "lazy normalization".
|
||||||
//!
|
//!
|
||||||
//! This is done by first normalizing both sides of the goal, ending up in
|
//! This is done by first normalizing both sides of the goal, ending up in
|
||||||
//! either a concrete type, rigid projection, opaque, or an infer variable.
|
//! either a concrete type, rigid alias, or an infer variable.
|
||||||
//! These are related further according to the rules below:
|
//! These are related further according to the rules below:
|
||||||
//!
|
//!
|
||||||
//! (1.) If we end up with a rigid projection and a rigid projection, then we
|
//! (1.) If we end up with two rigid aliases, then we relate them structurally.
|
||||||
//! relate those projections structurally.
|
|
||||||
//!
|
//!
|
||||||
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
|
//! (2.) If we end up with an infer var and a rigid alias, then
|
||||||
//! have its hidden type defined to be that rigid projection.
|
|
||||||
//!
|
|
||||||
//! (3.) If we end up with an opaque and an opaque, then we assemble two
|
|
||||||
//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
|
|
||||||
//! versa.
|
|
||||||
//!
|
|
||||||
//! (4.) If we end up with an infer var and an opaque or rigid projection, then
|
|
||||||
//! we assign the alias to the infer var.
|
//! we assign the alias to the infer var.
|
||||||
//!
|
//!
|
||||||
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
|
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
|
||||||
//! define the hidden type of the opaque to be the rigid type.
|
|
||||||
//!
|
|
||||||
//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
|
|
||||||
//! relate them structurally.
|
//! relate them structurally.
|
||||||
|
//!
|
||||||
|
//! Subtle: when relating an opaque to another type, we emit a
|
||||||
|
//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
|
||||||
|
//! This nested goal starts out as ambiguous and does not actually define the opaque.
|
||||||
|
//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
|
||||||
|
//! `NormalizesTo` goal, at which point the opaque is actually defined.
|
||||||
|
|
||||||
use super::{EvalCtxt, GoalSource};
|
use super::{EvalCtxt, GoalSource};
|
||||||
use rustc_infer::infer::DefineOpaqueTypes;
|
use rustc_infer::infer::DefineOpaqueTypes;
|
||||||
|
@ -59,31 +54,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
}
|
}
|
||||||
|
|
||||||
(Some(alias), None) => {
|
(Some(_), None) => {
|
||||||
if rhs.is_infer() {
|
if rhs.is_infer() {
|
||||||
self.relate(param_env, lhs, variance, rhs)?;
|
self.relate(param_env, lhs, variance, rhs)?;
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
} else if alias.is_opaque(tcx) {
|
|
||||||
// FIXME: This doesn't account for variance.
|
|
||||||
self.define_opaque(param_env, alias, rhs)
|
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, Some(alias)) => {
|
(None, Some(_)) => {
|
||||||
if lhs.is_infer() {
|
if lhs.is_infer() {
|
||||||
self.relate(param_env, lhs, variance, rhs)?;
|
self.relate(param_env, lhs, variance, rhs)?;
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
} else if alias.is_opaque(tcx) {
|
|
||||||
// FIXME: This doesn't account for variance.
|
|
||||||
self.define_opaque(param_env, alias, lhs)
|
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(Some(alias_lhs), Some(alias_rhs)) => {
|
(Some(alias_lhs), Some(alias_rhs)) => {
|
||||||
self.relate_rigid_alias_or_opaque(param_env, alias_lhs, variance, alias_rhs)
|
self.relate(param_env, alias_lhs, variance, alias_rhs)?;
|
||||||
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,52 +108,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_opaque(
|
|
||||||
&mut self,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
opaque: ty::AliasTy<'tcx>,
|
|
||||||
term: ty::Term<'tcx>,
|
|
||||||
) -> QueryResult<'tcx> {
|
|
||||||
self.add_goal(
|
|
||||||
GoalSource::Misc,
|
|
||||||
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }),
|
|
||||||
);
|
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relate_rigid_alias_or_opaque(
|
|
||||||
&mut self,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
lhs: ty::AliasTy<'tcx>,
|
|
||||||
variance: ty::Variance,
|
|
||||||
rhs: ty::AliasTy<'tcx>,
|
|
||||||
) -> QueryResult<'tcx> {
|
|
||||||
let tcx = self.tcx();
|
|
||||||
let mut candidates = vec![];
|
|
||||||
if lhs.is_opaque(tcx) {
|
|
||||||
candidates.extend(
|
|
||||||
self.probe_misc_candidate("define-lhs-opaque")
|
|
||||||
.enter(|ecx| ecx.define_opaque(param_env, lhs, rhs.to_ty(tcx).into())),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if rhs.is_opaque(tcx) {
|
|
||||||
candidates.extend(
|
|
||||||
self.probe_misc_candidate("define-rhs-opaque")
|
|
||||||
.enter(|ecx| ecx.define_opaque(param_env, rhs, lhs.to_ty(tcx).into())),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
candidates.extend(self.probe_misc_candidate("args-relate").enter(|ecx| {
|
|
||||||
ecx.relate(param_env, lhs, variance, rhs)?;
|
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
||||||
}));
|
|
||||||
|
|
||||||
if let Some(result) = self.try_merge_responses(&candidates) {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
self.flounder(&candidates)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,7 @@ use rustc_middle::traits::solve::{
|
||||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
||||||
QueryResult, Response,
|
QueryResult, Response,
|
||||||
};
|
};
|
||||||
use rustc_middle::traits::Reveal;
|
use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
|
||||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||||
};
|
};
|
||||||
|
@ -292,32 +291,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty::Alias(kind, alias) = *ty.kind() else {
|
let ty::Alias(_, alias) = *ty.kind() else {
|
||||||
return Some(ty);
|
return Some(ty);
|
||||||
};
|
};
|
||||||
|
|
||||||
// We do no always define opaque types eagerly to allow non-defining uses
|
|
||||||
// in the defining scope. However, if we can unify this opaque to an existing
|
|
||||||
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
|
|
||||||
// through.
|
|
||||||
if let DefineOpaqueTypes::No = define_opaque_types
|
|
||||||
&& let Reveal::UserFacing = param_env.reveal()
|
|
||||||
&& let ty::Opaque = kind
|
|
||||||
&& let Some(def_id) = alias.def_id.as_local()
|
|
||||||
&& self.can_define_opaque_ty(def_id)
|
|
||||||
{
|
|
||||||
if self
|
|
||||||
.unify_existing_opaque_tys(
|
|
||||||
param_env,
|
|
||||||
OpaqueTypeKey { def_id, args: alias.args },
|
|
||||||
self.next_ty_infer(),
|
|
||||||
)
|
|
||||||
.is_empty()
|
|
||||||
{
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.commit_if_ok(|this| {
|
match self.commit_if_ok(|this| {
|
||||||
let normalized_ty = this.next_ty_infer();
|
let normalized_ty = this.next_ty_infer();
|
||||||
let normalizes_to_goal = Goal::new(
|
let normalizes_to_goal = Goal::new(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue