always emit AliasRelate
goals when relating aliases
Add `StructurallyRelateAliases` to allow instantiating infer vars with rigid aliases. Change `instantiate_query_response` to be infallible in the new solver. This requires canonicalization to not hide any information used by the query, so weaken universe compression. It also modifies `term_is_fully_unconstrained` to allow region inference variables in a higher universe.
This commit is contained in:
parent
eeeb9b4d31
commit
1b3164f5c9
21 changed files with 417 additions and 272 deletions
|
@ -302,7 +302,23 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
let Trace { at, trace, a_is_expected } = self;
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
|
||||
fields
|
||||
.equate(a_is_expected)
|
||||
.equate(StructurallyRelateAliases::No, a_is_expected)
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
||||
/// Equates `a` and `b` while structurally relating aliases. This should only
|
||||
/// be used inside of the next generation trait solver when relating rigid aliases.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn eq_structurally_relating_aliases<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
debug_assert!(at.infcx.next_trait_solver());
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::No);
|
||||
fields
|
||||
.equate(StructurallyRelateAliases::Yes, a_is_expected)
|
||||
.relate(a, b)
|
||||
.map(move |_| InferOk { value: (), obligations: fields.obligations })
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ use self::region_constraints::{
|
|||
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
|
||||
};
|
||||
pub use self::relate::combine::CombineFields;
|
||||
pub use self::relate::StructurallyRelateAliases;
|
||||
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
|
||||
pub mod at;
|
||||
|
|
|
@ -26,6 +26,7 @@ use super::equate::Equate;
|
|||
use super::glb::Glb;
|
||||
use super::lub::Lub;
|
||||
use super::sub::Sub;
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::infer::canonical::OriginalQueryValues;
|
||||
|
@ -116,8 +117,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
(_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => {
|
||||
relation.register_type_relate_obligation(a, b);
|
||||
Ok(a)
|
||||
match relation.structurally_relate_aliases() {
|
||||
StructurallyRelateAliases::Yes => {
|
||||
ty::relate::structurally_relate_tys(relation, a, b)
|
||||
}
|
||||
StructurallyRelateAliases::No => {
|
||||
relation.register_type_relate_obligation(a, b);
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All other cases of inference are errors
|
||||
|
@ -240,19 +248,26 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
||||
if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
|
||||
{
|
||||
let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) };
|
||||
match relation.structurally_relate_aliases() {
|
||||
StructurallyRelateAliases::No => {
|
||||
let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) };
|
||||
|
||||
relation.register_predicates([if self.next_trait_solver() {
|
||||
ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
)
|
||||
} else {
|
||||
ty::PredicateKind::ConstEquate(a, b)
|
||||
}]);
|
||||
relation.register_predicates([if self.next_trait_solver() {
|
||||
ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
)
|
||||
} else {
|
||||
ty::PredicateKind::ConstEquate(a, b)
|
||||
}]);
|
||||
|
||||
Ok(b)
|
||||
Ok(b)
|
||||
}
|
||||
StructurallyRelateAliases::Yes => {
|
||||
ty::relate::structurally_relate_consts(relation, a, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ty::relate::structurally_relate_consts(relation, a, b),
|
||||
}
|
||||
|
@ -303,8 +318,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'tcx> {
|
||||
Equate::new(self, a_is_expected)
|
||||
pub fn equate<'a>(
|
||||
&'a mut self,
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
a_is_expected: bool,
|
||||
) -> Equate<'a, 'infcx, 'tcx> {
|
||||
Equate::new(self, structurally_relate_aliases, a_is_expected)
|
||||
}
|
||||
|
||||
pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'tcx> {
|
||||
|
@ -335,6 +354,11 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
|||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx>;
|
||||
|
||||
/// Whether aliases should be related structurally. This is pretty much
|
||||
/// always `No` unless you're equating in some specific locations of the
|
||||
/// new solver. See the comments in these use-cases for more details.
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
|
||||
|
||||
/// Register obligations that must hold in order for this relation to hold
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::combine::{CombineFields, ObligationEmittingRelation};
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::{DefineOpaqueTypes, SubregionOrigin};
|
||||
use crate::traits::PredicateObligations;
|
||||
|
||||
|
@ -13,15 +14,17 @@ use rustc_span::Span;
|
|||
/// Ensures `a` is made equal to `b`. Returns `a` on success.
|
||||
pub struct Equate<'combine, 'infcx, 'tcx> {
|
||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
a_is_expected: bool,
|
||||
}
|
||||
|
||||
impl<'combine, 'infcx, 'tcx> Equate<'combine, 'infcx, 'tcx> {
|
||||
pub fn new(
|
||||
fields: &'combine mut CombineFields<'infcx, 'tcx>,
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
a_is_expected: bool,
|
||||
) -> Equate<'combine, 'infcx, 'tcx> {
|
||||
Equate { fields, a_is_expected }
|
||||
Equate { fields, structurally_relate_aliases, a_is_expected }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +102,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
|
||||
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
|
||||
) if a_def_id == b_def_id => {
|
||||
self.fields.infcx.super_combine_tys(self, a, b)?;
|
||||
infcx.super_combine_tys(self, a, b)?;
|
||||
}
|
||||
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
|
||||
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
||||
|
@ -120,7 +123,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
);
|
||||
}
|
||||
_ => {
|
||||
self.fields.infcx.super_combine_tys(self, a, b)?;
|
||||
infcx.super_combine_tys(self, a, b)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +183,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
self.fields.trace.span()
|
||||
}
|
||||
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
|
||||
self.structurally_relate_aliases
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.fields.param_env
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::mem;
|
||||
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue};
|
||||
use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin};
|
||||
use rustc_data_structures::sso::SsoHashMap;
|
||||
|
@ -45,8 +46,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// region/type inference variables.
|
||||
//
|
||||
// We then relate `generalized_ty <: source_ty`,adding constraints like `'x: '?2` and `?1 <: ?3`.
|
||||
let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } =
|
||||
self.generalize(relation.span(), target_vid, instantiation_variance, source_ty)?;
|
||||
let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self
|
||||
.generalize(
|
||||
relation.span(),
|
||||
relation.structurally_relate_aliases(),
|
||||
target_vid,
|
||||
instantiation_variance,
|
||||
source_ty,
|
||||
)?;
|
||||
|
||||
// Constrain `b_vid` to the generalized type `generalized_ty`.
|
||||
if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
|
||||
|
@ -178,8 +185,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
) -> RelateResult<'tcx, ()> {
|
||||
// FIXME(generic_const_exprs): Occurs check failures for unevaluated
|
||||
// constants and generic expressions are not yet handled correctly.
|
||||
let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } =
|
||||
self.generalize(relation.span(), target_vid, ty::Variance::Invariant, source_ct)?;
|
||||
let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self
|
||||
.generalize(
|
||||
relation.span(),
|
||||
relation.structurally_relate_aliases(),
|
||||
target_vid,
|
||||
ty::Variance::Invariant,
|
||||
source_ct,
|
||||
)?;
|
||||
|
||||
debug_assert!(!generalized_ct.is_ct_infer());
|
||||
if has_unconstrained_ty_var {
|
||||
|
@ -217,6 +230,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
fn generalize<T: Into<Term<'tcx>> + Relate<'tcx>>(
|
||||
&self,
|
||||
span: Span,
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
target_vid: impl Into<ty::TermVid>,
|
||||
ambient_variance: ty::Variance,
|
||||
source_term: T,
|
||||
|
@ -237,6 +251,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
let mut generalizer = Generalizer {
|
||||
infcx: self,
|
||||
span,
|
||||
structurally_relate_aliases,
|
||||
root_vid,
|
||||
for_universe,
|
||||
ambient_variance,
|
||||
|
@ -270,6 +285,10 @@ struct Generalizer<'me, 'tcx> {
|
|||
|
||||
span: Span,
|
||||
|
||||
/// Whether aliases should be related structurally. If not, we have to
|
||||
/// be careful when generalizing aliases.
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
|
||||
/// The vid of the type variable that is in the process of being
|
||||
/// instantiated. If we find this within the value we are folding,
|
||||
/// that means we would have created a cyclic value.
|
||||
|
@ -314,13 +333,30 @@ impl<'tcx> Generalizer<'_, 'tcx> {
|
|||
/// to normalize the alias after all.
|
||||
///
|
||||
/// We handle this by lazily equating the alias and generalizing
|
||||
/// it to an inference variable.
|
||||
/// it to an inference variable. In the new solver, we always
|
||||
/// generalize to an infer var unless the alias contains escaping
|
||||
/// bound variables.
|
||||
///
|
||||
/// This is incomplete and will hopefully soon get fixed by #119106.
|
||||
/// Correctly handling aliases with escaping bound variables is
|
||||
/// difficult and currently incomplete in two opposite ways:
|
||||
/// - if we get an occurs check failure in the alias, replace it with a new infer var.
|
||||
/// This causes us to later emit an alias-relate goal and is incomplete in case the
|
||||
/// alias normalizes to type containing one of the bound variables.
|
||||
/// - if the alias contains an inference variable not nameable by `for_universe`, we
|
||||
/// continue generalizing the alias. This ends up pulling down the universe of the
|
||||
/// inference variable and is incomplete in case the alias would normalize to a type
|
||||
/// which does not mention that inference variable.
|
||||
fn generalize_alias_ty(
|
||||
&mut self,
|
||||
alias: ty::AliasTy<'tcx>,
|
||||
) -> Result<Ty<'tcx>, TypeError<'tcx>> {
|
||||
if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() {
|
||||
return Ok(self.infcx.next_ty_var_in_universe(
|
||||
TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: self.span },
|
||||
self.for_universe,
|
||||
));
|
||||
}
|
||||
|
||||
let is_nested_alias = mem::replace(&mut self.in_alias, true);
|
||||
let result = match self.relate(alias, alias) {
|
||||
Ok(alias) => Ok(alias.to_ty(self.tcx())),
|
||||
|
@ -490,7 +526,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
ty::Alias(_, data) => self.generalize_alias_ty(data),
|
||||
ty::Alias(_, data) => match self.structurally_relate_aliases {
|
||||
StructurallyRelateAliases::No => self.generalize_alias_ty(data),
|
||||
StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
|
||||
},
|
||||
|
||||
_ => relate::structurally_relate_tys(self, t, t),
|
||||
}?;
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_span::Span;
|
|||
|
||||
use super::combine::{CombineFields, ObligationEmittingRelation};
|
||||
use super::lattice::{self, LatticeDir};
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
|
||||
use crate::traits::{ObligationCause, PredicateObligations};
|
||||
|
||||
|
@ -45,7 +46,9 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
|
||||
ty::Invariant => {
|
||||
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
|
||||
}
|
||||
ty::Covariant => self.relate(a, b),
|
||||
// FIXME(#41044) -- not correct, need test
|
||||
ty::Bivariant => Ok(a),
|
||||
|
@ -139,6 +142,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
self.fields.trace.span()
|
||||
}
|
||||
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
|
||||
StructurallyRelateAliases::No
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.fields.param_env
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use super::combine::{CombineFields, ObligationEmittingRelation};
|
||||
use super::lattice::{self, LatticeDir};
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
|
||||
use crate::traits::{ObligationCause, PredicateObligations};
|
||||
|
||||
|
@ -45,7 +46,9 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
|
||||
ty::Invariant => {
|
||||
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
|
||||
}
|
||||
ty::Covariant => self.relate(a, b),
|
||||
// FIXME(#41044) -- not correct, need test
|
||||
ty::Bivariant => Ok(a),
|
||||
|
@ -139,6 +142,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
self.fields.trace.span()
|
||||
}
|
||||
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
|
||||
StructurallyRelateAliases::No
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.fields.param_env
|
||||
}
|
||||
|
|
|
@ -9,3 +9,15 @@ mod higher_ranked;
|
|||
mod lattice;
|
||||
mod lub;
|
||||
mod sub;
|
||||
|
||||
/// Whether aliases should be related structurally or not. Used
|
||||
/// to adjust the behavior of generalization and combine.
|
||||
///
|
||||
/// This should always be `No` unless in a few special-cases when
|
||||
/// instantiating canonical responses and in the new solver. Each
|
||||
/// such case should have a comment explaining why it is used.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum StructurallyRelateAliases {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::combine::CombineFields;
|
||||
use super::StructurallyRelateAliases;
|
||||
use crate::infer::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
|
||||
|
@ -64,7 +65,9 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
match variance {
|
||||
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
|
||||
ty::Invariant => {
|
||||
self.fields.equate(StructurallyRelateAliases::No, self.a_is_expected).relate(a, b)
|
||||
}
|
||||
ty::Covariant => self.relate(a, b),
|
||||
ty::Bivariant => Ok(a),
|
||||
ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)),
|
||||
|
@ -204,6 +207,10 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
self.fields.trace.span()
|
||||
}
|
||||
|
||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
|
||||
StructurallyRelateAliases::No
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.fields.param_env
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue