Replace Projection variant in GenericPredicate with AliasEq

This commit is contained in:
Lukas Wirth 2021-03-19 02:07:15 +01:00
parent 86878443b1
commit 8996b1a235
10 changed files with 223 additions and 133 deletions

View File

@ -56,9 +56,9 @@ use hir_ty::{
primitive::UintTy, primitive::UintTy,
to_assoc_type_id, to_assoc_type_id,
traits::{FnTrait, Solution, SolutionVariables}, traits::{FnTrait, Solution, SolutionVariables},
AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex,
InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substitution, GenericPredicate, InEnvironment, Interner, Obligation, ProjectionTy, Scalar, Substitution, Ty,
Ty, TyDefId, TyKind, TyVariableKind, TyDefId, TyKind, TyVariableKind,
}; };
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
@ -1786,17 +1786,17 @@ impl Type {
.push(self.ty.value.clone()) .push(self.ty.value.clone())
.fill(args.iter().map(|t| t.ty.value.clone())) .fill(args.iter().map(|t| t.ty.value.clone()))
.build(); .build();
let predicate = ProjectionPredicate {
projection_ty: ProjectionTy {
associated_ty_id: to_assoc_type_id(alias.id),
substitution: subst,
},
ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner),
};
let goal = Canonical { let goal = Canonical {
value: InEnvironment::new( value: InEnvironment::new(
self.ty.environment.clone(), self.ty.environment.clone(),
Obligation::Projection(predicate), Obligation::AliasEq(AliasEq {
alias: AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(alias.id),
substitution: subst,
}),
ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
.intern(&Interner),
}),
), ),
kinds: Arc::new([TyVariableKind::General]), kinds: Arc::new([TyVariableKind::General]),
}; };

View File

@ -15,7 +15,8 @@ use crate::{
to_assoc_type_id, to_chalk_trait_id, to_assoc_type_id, to_chalk_trait_id,
traits::{InEnvironment, Solution}, traits::{InEnvironment, Solution},
utils::generics, utils::generics,
BoundVar, Canonical, DebruijnIndex, Interner, Obligation, Substitution, TraitRef, Ty, TyKind, AliasEq, AliasTy, BoundVar, Canonical, DebruijnIndex, Interner, Obligation, ProjectionTy,
Substitution, TraitRef, Ty, TyKind,
}; };
const AUTODEREF_RECURSION_LIMIT: usize = 10; const AUTODEREF_RECURSION_LIMIT: usize = 10;
@ -82,16 +83,16 @@ fn deref_by_trait(
} }
// Now do the assoc type projection // Now do the assoc type projection
let projection = super::traits::ProjectionPredicate { let projection = AliasEq {
ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())) alias: AliasTy::Projection(ProjectionTy {
.intern(&Interner),
projection_ty: super::ProjectionTy {
associated_ty_id: to_assoc_type_id(target), associated_ty_id: to_assoc_type_id(target),
substitution: parameters, substitution: parameters,
}, }),
ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len()))
.intern(&Interner),
}; };
let obligation = super::Obligation::Projection(projection); let obligation = super::Obligation::AliasEq(projection);
let in_env = InEnvironment { value: obligation, environment: ty.environment }; let in_env = InEnvironment { value: obligation, environment: ty.environment };

View File

@ -18,9 +18,9 @@ use hir_expand::name::Name;
use crate::{ use crate::{
db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive,
to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasTy, CallableDefId, to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy,
CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation, OpaqueTy, CallableDefId, CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation,
ProjectionTy, Scalar, Substitution, TraitRef, Ty, TyKind, OpaqueTy, ProjectionTy, Scalar, Substitution, TraitRef, Ty, TyKind,
}; };
pub struct HirFormatter<'a> { pub struct HirFormatter<'a> {
@ -268,6 +268,16 @@ impl HirDisplay for ProjectionTy {
} }
} }
impl HirDisplay for OpaqueTy {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
if f.should_truncate() {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
self.substitution[0].hir_fmt(f)
}
}
impl HirDisplay for Ty { impl HirDisplay for Ty {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
if f.should_truncate() { if f.should_truncate() {
@ -700,12 +710,12 @@ fn write_bounds_like_dyn_trait(
} }
} }
} }
GenericPredicate::Projection(projection_pred) if is_fn_trait => { GenericPredicate::AliasEq(alias_eq) if is_fn_trait => {
is_fn_trait = false; is_fn_trait = false;
write!(f, " -> ")?; write!(f, " -> ")?;
projection_pred.ty.hir_fmt(f)?; alias_eq.ty.hir_fmt(f)?;
} }
GenericPredicate::Projection(projection_pred) => { GenericPredicate::AliasEq(AliasEq { ty, alias }) => {
// in types in actual Rust, these will always come // in types in actual Rust, these will always come
// after the corresponding Implemented predicate // after the corresponding Implemented predicate
if angle_open { if angle_open {
@ -714,11 +724,12 @@ fn write_bounds_like_dyn_trait(
write!(f, "<")?; write!(f, "<")?;
angle_open = true; angle_open = true;
} }
let type_alias = f.db.type_alias_data(from_assoc_type_id( if let AliasTy::Projection(proj) = alias {
projection_pred.projection_ty.associated_ty_id, let type_alias =
)); f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
write!(f, "{} = ", type_alias.name)?; write!(f, "{} = ", type_alias.name)?;
projection_pred.ty.hir_fmt(f)?; }
ty.hir_fmt(f)?;
} }
GenericPredicate::Error => { GenericPredicate::Error => {
if angle_open { if angle_open {
@ -775,20 +786,20 @@ impl HirDisplay for GenericPredicate {
match self { match self {
GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
GenericPredicate::Projection(projection_pred) => { GenericPredicate::AliasEq(AliasEq {
alias: AliasTy::Projection(projection_ty),
ty,
}) => {
write!(f, "<")?; write!(f, "<")?;
projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
write!( write!(
f, f,
">::{} = ", ">::{} = ",
f.db.type_alias_data(from_assoc_type_id( f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
projection_pred.projection_ty.associated_ty_id
))
.name,
)?; )?;
projection_pred.ty.hir_fmt(f)?; ty.hir_fmt(f)?;
} }
GenericPredicate::Error => write!(f, "{{error}}")?, GenericPredicate::AliasEq(_) | GenericPredicate::Error => write!(f, "{{error}}")?,
} }
Ok(()) Ok(())
} }
@ -815,11 +826,14 @@ impl HirDisplay for Obligation {
tr.hir_fmt(f)?; tr.hir_fmt(f)?;
write!(f, ")") write!(f, ")")
} }
Obligation::Projection(proj) => { Obligation::AliasEq(AliasEq { alias, ty }) => {
write!(f, "Normalize(")?; write!(f, "Normalize(")?;
proj.projection_ty.hir_fmt(f)?; match alias {
AliasTy::Projection(projection_ty) => projection_ty.hir_fmt(f)?,
AliasTy::Opaque(opaque) => opaque.hir_fmt(f)?,
}
write!(f, " => ")?; write!(f, " => ")?;
proj.ty.hir_fmt(f)?; ty.hir_fmt(f)?;
write!(f, ")") write!(f, ")")
} }
} }

View File

@ -37,12 +37,12 @@ use stdx::impl_from;
use syntax::SmolStr; use syntax::SmolStr;
use super::{ use super::{
traits::{Guidance, Obligation, ProjectionPredicate, Solution}, traits::{Guidance, Obligation, Solution},
InEnvironment, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TypeWalk, InEnvironment, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TypeWalk,
}; };
use crate::{ use crate::{
db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
to_assoc_type_id, to_chalk_trait_id, AliasTy, Interner, TyKind, to_assoc_type_id, to_chalk_trait_id, AliasEq, AliasTy, Interner, TyKind,
}; };
pub(crate) use unify::unify; pub(crate) use unify::unify;
@ -396,15 +396,15 @@ impl<'a> InferenceContext<'a> {
.build(); .build();
let trait_ref = let trait_ref =
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() }; TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() };
let projection = ProjectionPredicate { let alias_eq = AliasEq {
ty: ty.clone(), alias: AliasTy::Projection(ProjectionTy {
projection_ty: ProjectionTy {
associated_ty_id: to_assoc_type_id(res_assoc_ty), associated_ty_id: to_assoc_type_id(res_assoc_ty),
substitution: substs, substitution: substs,
}, }),
ty: ty.clone(),
}; };
self.obligations.push(Obligation::Trait(trait_ref)); self.obligations.push(Obligation::Trait(trait_ref));
self.obligations.push(Obligation::Projection(projection)); self.obligations.push(Obligation::AliasEq(alias_eq));
self.resolve_ty_as_possible(ty) self.resolve_ty_as_possible(ty)
} }
None => self.err_ty(), None => self.err_ty(),
@ -429,8 +429,8 @@ impl<'a> InferenceContext<'a> {
fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
let var = self.table.new_type_var(); let var = self.table.new_type_var();
let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() }; let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
let obligation = Obligation::Projection(predicate); let obligation = Obligation::AliasEq(alias_eq);
self.obligations.push(obligation); self.obligations.push(obligation);
var var
} }

View File

@ -7,8 +7,8 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
use super::{InferenceContext, Obligation}; use super::{InferenceContext, Obligation};
use crate::{ use crate::{
BoundVar, Canonical, DebruijnIndex, FnPointer, GenericPredicate, InEnvironment, InferenceVar, AliasEq, AliasTy, BoundVar, Canonical, DebruijnIndex, FnPointer, GenericPredicate,
Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk,
}; };
impl<'a> InferenceContext<'a> { impl<'a> InferenceContext<'a> {
@ -93,8 +93,8 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
Obligation::Trait(tr) => { Obligation::Trait(tr) => {
Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST)) Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST))
} }
Obligation::Projection(pr) => { Obligation::AliasEq(alias_eq) => {
Obligation::Projection(self.do_canonicalize(pr, DebruijnIndex::INNERMOST)) Obligation::AliasEq(self.do_canonicalize(alias_eq, DebruijnIndex::INNERMOST))
} }
}; };
self.into_canonicalized(InEnvironment { self.into_canonicalized(InEnvironment {
@ -394,14 +394,25 @@ impl InferenceTable {
{ {
self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1) self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1)
} }
(GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2)) (
if proj1.projection_ty.associated_ty_id == proj2.projection_ty.associated_ty_id => GenericPredicate::AliasEq(AliasEq { alias: alias1, ty: ty1 }),
{ GenericPredicate::AliasEq(AliasEq { alias: alias2, ty: ty2 }),
self.unify_substs( ) => {
&proj1.projection_ty.substitution, let (substitution1, substitution2) = match (alias1, alias2) {
&proj2.projection_ty.substitution, (AliasTy::Projection(projection_ty1), AliasTy::Projection(projection_ty2))
depth + 1, if projection_ty1.associated_ty_id == projection_ty2.associated_ty_id =>
) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1) {
(&projection_ty1.substitution, &projection_ty2.substitution)
}
(AliasTy::Opaque(opaque1), AliasTy::Opaque(opaque2))
if opaque1.opaque_ty_id == opaque2.opaque_ty_id =>
{
(&opaque1.substitution, &opaque2.substitution)
}
_ => return false,
};
self.unify_substs(&substitution1, &substitution2, depth + 1)
&& self.unify_inner(&ty1, &ty2, depth + 1)
} }
_ => false, _ => false,
} }

View File

@ -45,7 +45,7 @@ pub use lower::{
associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
TyDefId, TyLoweringContext, ValueTyDefId, TyDefId, TyLoweringContext, ValueTyDefId,
}; };
pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; pub use traits::{AliasEq, InEnvironment, Obligation, TraitEnvironment};
pub use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind}; pub use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind};
@ -72,6 +72,20 @@ pub struct OpaqueTy {
pub substitution: Substitution, pub substitution: Substitution,
} }
impl TypeWalk for OpaqueTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
/// A "projection" type corresponds to an (unnormalized) /// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known. /// trait and all its parameters are fully known.
@ -133,6 +147,25 @@ pub enum AliasTy {
Opaque(OpaqueTy), Opaque(OpaqueTy),
} }
impl TypeWalk for AliasTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
AliasTy::Projection(it) => it.walk(f),
AliasTy::Opaque(it) => it.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self {
AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
}
}
}
/// A type. /// A type.
/// ///
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
@ -535,7 +568,7 @@ pub enum GenericPredicate {
/// The given trait needs to be implemented for its type parameters. /// The given trait needs to be implemented for its type parameters.
Implemented(TraitRef), Implemented(TraitRef),
/// An associated type bindings like in `Iterator<Item = T>`. /// An associated type bindings like in `Iterator<Item = T>`.
Projection(ProjectionPredicate), AliasEq(AliasEq),
/// We couldn't resolve the trait reference. (If some type parameters can't /// We couldn't resolve the trait reference. (If some type parameters can't
/// be resolved, they will just be Unknown). /// be resolved, they will just be Unknown).
Error, Error,
@ -553,8 +586,10 @@ impl GenericPredicate {
pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> { pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
match self { match self {
GenericPredicate::Implemented(tr) => Some(tr.clone()), GenericPredicate::Implemented(tr) => Some(tr.clone()),
GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)), GenericPredicate::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => {
GenericPredicate::Error => None, Some(proj.trait_ref(db))
}
GenericPredicate::AliasEq(_) | GenericPredicate::Error => None,
} }
} }
} }
@ -563,7 +598,7 @@ impl TypeWalk for GenericPredicate {
fn walk(&self, f: &mut impl FnMut(&Ty)) { fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self { match self {
GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
GenericPredicate::Projection(projection_pred) => projection_pred.walk(f), GenericPredicate::AliasEq(alias_eq) => alias_eq.walk(f),
GenericPredicate::Error => {} GenericPredicate::Error => {}
} }
} }
@ -575,9 +610,7 @@ impl TypeWalk for GenericPredicate {
) { ) {
match self { match self {
GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders), GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
GenericPredicate::Projection(projection_pred) => { GenericPredicate::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
projection_pred.walk_mut_binders(f, binders)
}
GenericPredicate::Error => {} GenericPredicate::Error => {}
} }
} }

View File

@ -33,8 +33,8 @@ use crate::{
all_super_trait_refs, associated_type_by_name_including_super_traits, generics, all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
variant_data, variant_data,
}, },
AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig, GenericPredicate, AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig,
ImplTraitId, OpaqueTy, PolyFnSig, ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, GenericPredicate, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, ReturnTypeImplTrait,
ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk, ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk,
}; };
@ -750,9 +750,9 @@ impl<'a> TyLoweringContext<'a> {
); );
if let Some(type_ref) = &binding.type_ref { if let Some(type_ref) = &binding.type_ref {
let ty = self.lower_ty(type_ref); let ty = self.lower_ty(type_ref);
let projection_predicate = let alias_eq =
ProjectionPredicate { projection_ty: projection_ty.clone(), ty }; AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
preds.push(GenericPredicate::Projection(projection_predicate)); preds.push(GenericPredicate::AliasEq(alias_eq));
} }
for bound in &binding.bounds { for bound in &binding.bounds {
preds.extend(self.lower_type_bound( preds.extend(self.lower_type_bound(

View File

@ -8,10 +8,9 @@ use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
use hir_def::{lang_item::LangItemTarget, TraitId}; use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context; use stdx::panic_context;
use crate::{db::HirDatabase, DebruijnIndex, Substitution}; use crate::{
db::HirDatabase, AliasTy, Canonical, DebruijnIndex, GenericPredicate, HirDisplay, Substitution,
use super::{ TraitRef, Ty, TyKind, TypeWalk,
Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TyKind, TypeWalk,
}; };
use self::chalk::{from_chalk, Interner, ToChalk}; use self::chalk::{from_chalk, Interner, ToChalk};
@ -93,31 +92,32 @@ pub enum Obligation {
/// Prove that a certain type implements a trait (the type is the `Self` type /// Prove that a certain type implements a trait (the type is the `Self` type
/// parameter to the `TraitRef`). /// parameter to the `TraitRef`).
Trait(TraitRef), Trait(TraitRef),
Projection(ProjectionPredicate), AliasEq(AliasEq),
} }
impl Obligation { impl Obligation {
pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> {
match predicate { match predicate {
GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)),
GenericPredicate::Projection(projection_pred) => { GenericPredicate::AliasEq(alias_eq) => Some(Obligation::AliasEq(alias_eq)),
Some(Obligation::Projection(projection_pred))
}
GenericPredicate::Error => None, GenericPredicate::Error => None,
} }
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ProjectionPredicate { pub struct AliasEq {
pub projection_ty: ProjectionTy, pub alias: AliasTy,
pub ty: Ty, pub ty: Ty,
} }
impl TypeWalk for ProjectionPredicate { impl TypeWalk for AliasEq {
fn walk(&self, f: &mut impl FnMut(&Ty)) { fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.projection_ty.walk(f);
self.ty.walk(f); self.ty.walk(f);
match &self.alias {
AliasTy::Projection(projection_ty) => projection_ty.walk(f),
AliasTy::Opaque(opaque) => opaque.walk(f),
}
} }
fn walk_mut_binders( fn walk_mut_binders(
@ -125,8 +125,11 @@ impl TypeWalk for ProjectionPredicate {
f: &mut impl FnMut(&mut Ty, DebruijnIndex), f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex, binders: DebruijnIndex,
) { ) {
self.projection_ty.walk_mut_binders(f, binders);
self.ty.walk_mut_binders(f, binders); self.ty.walk_mut_binders(f, binders);
match &mut self.alias {
AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
}
} }
} }
@ -138,12 +141,14 @@ pub(crate) fn trait_solve_query(
) -> Option<Solution> { ) -> Option<Solution> {
let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value { let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value {
Obligation::Trait(it) => db.trait_data(it.hir_trait_id()).name.to_string(), Obligation::Trait(it) => db.trait_data(it.hir_trait_id()).name.to_string(),
Obligation::Projection(_) => "projection".to_string(), Obligation::AliasEq(_) => "alias_eq".to_string(),
}); });
log::info!("trait_solve_query({})", goal.value.value.display(db)); log::info!("trait_solve_query({})", goal.value.value.display(db));
if let Obligation::Projection(pred) = &goal.value.value { if let Obligation::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), .. }) =
if let TyKind::BoundVar(_) = &pred.projection_ty.substitution[0].interned(&Interner) { &goal.value.value
{
if let TyKind::BoundVar(_) = &projection_ty.substitution[0].interned(&Interner) {
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
return Some(Solution::Ambig(Guidance::Unknown)); return Some(Solution::Ambig(Guidance::Unknown));
} }

View File

@ -21,8 +21,8 @@ use crate::{
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
to_assoc_type_id, to_chalk_trait_id, to_assoc_type_id, to_chalk_trait_id,
utils::generics, utils::generics,
BoundVar, CallableDefId, CallableSig, DebruijnIndex, FnDefId, GenericPredicate, AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, DebruijnIndex, FnDefId,
ProjectionPredicate, ProjectionTy, Substitution, TraitRef, Ty, TyKind, GenericPredicate, ProjectionTy, Substitution, TraitRef, Ty, TyKind,
}; };
use mapping::{ use mapping::{
convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
@ -229,18 +229,18 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
.intern(&Interner), .intern(&Interner),
), ),
}); });
let proj_bound = GenericPredicate::Projection(ProjectionPredicate { let proj_bound = GenericPredicate::AliasEq(AliasEq {
// The parameter of the opaque type. alias: AliasTy::Projection(ProjectionTy {
ty: TyKind::BoundVar(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 })
.intern(&Interner),
projection_ty: ProjectionTy {
associated_ty_id: to_assoc_type_id(future_output), associated_ty_id: to_assoc_type_id(future_output),
// Self type as the first parameter. // Self type as the first parameter.
substitution: Substitution::single( substitution: Substitution::single(
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
.intern(&Interner), .intern(&Interner),
), ),
}, }),
// The parameter of the opaque type.
ty: TyKind::BoundVar(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 })
.intern(&Interner),
}); });
let bound = OpaqueTyDatumBound { let bound = OpaqueTyDatumBound {
bounds: make_binders( bounds: make_binders(

View File

@ -14,8 +14,8 @@ use crate::{
from_assoc_type_id, from_assoc_type_id,
primitive::UintTy, primitive::UintTy,
traits::{Canonical, Obligation}, traits::{Canonical, Obligation},
AliasTy, CallableDefId, FnPointer, GenericPredicate, InEnvironment, OpaqueTy, AliasTy, CallableDefId, FnPointer, GenericPredicate, InEnvironment, OpaqueTy, ProjectionTy,
ProjectionPredicate, ProjectionTy, Scalar, Substitution, TraitRef, Ty, Scalar, Substitution, TraitRef, Ty,
}; };
use super::interner::*; use super::interner::*;
@ -314,12 +314,10 @@ impl ToChalk for GenericPredicate {
let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner);
make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0)
} }
GenericPredicate::Projection(projection_pred) => { GenericPredicate::AliasEq(alias_eq) => make_binders(
let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db).shifted_in(&Interner)),
let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); 0,
let alias = chalk_ir::AliasTy::Projection(projection); ),
make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
}
GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
} }
} }
@ -338,16 +336,8 @@ impl ToChalk for GenericPredicate {
chalk_ir::WhereClause::Implemented(tr) => { chalk_ir::WhereClause::Implemented(tr) => {
GenericPredicate::Implemented(from_chalk(db, tr)) GenericPredicate::Implemented(from_chalk(db, tr))
} }
chalk_ir::WhereClause::AliasEq(projection_eq) => { chalk_ir::WhereClause::AliasEq(alias_eq) => {
let projection_ty = from_chalk( GenericPredicate::AliasEq(from_chalk(db, alias_eq))
db,
match projection_eq.alias {
chalk_ir::AliasTy::Projection(p) => p,
_ => unimplemented!(),
},
);
let ty = from_chalk(db, projection_eq.ty);
GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty })
} }
chalk_ir::WhereClause::LifetimeOutlives(_) => { chalk_ir::WhereClause::LifetimeOutlives(_) => {
@ -383,19 +373,55 @@ impl ToChalk for ProjectionTy {
} }
} }
} }
impl ToChalk for OpaqueTy {
type Chalk = chalk_ir::OpaqueTy<Interner>;
impl ToChalk for ProjectionPredicate { fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
type Chalk = chalk_ir::AliasEq<Interner>; chalk_ir::OpaqueTy {
opaque_ty_id: self.opaque_ty_id,
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { substitution: self.substitution.to_chalk(db),
chalk_ir::AliasEq {
alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)),
ty: self.ty.to_chalk(db),
} }
} }
fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
unimplemented!() OpaqueTy {
opaque_ty_id: chalk.opaque_ty_id,
substitution: from_chalk(db, chalk.substitution),
}
}
}
impl ToChalk for AliasTy {
type Chalk = chalk_ir::AliasTy<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
match self {
AliasTy::Projection(projection_ty) => {
chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
}
AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
}
}
fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
match chalk {
chalk_ir::AliasTy::Projection(projection_ty) => {
AliasTy::Projection(from_chalk(db, projection_ty))
}
chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
}
}
}
impl ToChalk for AliasEq {
type Chalk = chalk_ir::AliasEq<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
}
fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
} }
} }
@ -405,7 +431,7 @@ impl ToChalk for Obligation {
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
match self { match self {
Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner),
Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), Obligation::AliasEq(alias_eq) => alias_eq.to_chalk(db).cast(&Interner),
} }
} }
@ -527,29 +553,29 @@ pub(super) fn generic_predicate_to_inline_bound(
let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
Some(rust_ir::InlineBound::TraitBound(trait_bound)) Some(rust_ir::InlineBound::TraitBound(trait_bound))
} }
GenericPredicate::Projection(proj) => { GenericPredicate::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
if &proj.projection_ty.substitution[0] != self_ty { if &projection_ty.substitution[0] != self_ty {
return None; return None;
} }
let trait_ = match from_assoc_type_id(proj.projection_ty.associated_ty_id) let trait_ = match from_assoc_type_id(projection_ty.associated_ty_id)
.lookup(db.upcast()) .lookup(db.upcast())
.container .container
{ {
AssocContainerId::TraitId(t) => t, AssocContainerId::TraitId(t) => t,
_ => panic!("associated type not in trait"), _ => panic!("associated type not in trait"),
}; };
let args_no_self = proj.projection_ty.substitution[1..] let args_no_self = projection_ty.substitution[1..]
.iter() .iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner)) .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.collect(); .collect();
let alias_eq_bound = rust_ir::AliasEqBound { let alias_eq_bound = rust_ir::AliasEqBound {
value: proj.ty.clone().to_chalk(db), value: ty.clone().to_chalk(db),
trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
associated_ty_id: proj.projection_ty.associated_ty_id, associated_ty_id: projection_ty.associated_ty_id,
parameters: Vec::new(), // FIXME we don't support generic associated types yet parameters: Vec::new(), // FIXME we don't support generic associated types yet
}; };
Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound))
} }
GenericPredicate::Error => None, _ => None,
} }
} }