Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ use hir_ty::{
primitive::UintTy,
to_assoc_type_id,
traits::{FnTrait, Solution, SolutionVariables},
AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate,
InEnvironment, Interner, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substitution,
Ty, TyDefId, TyKind, TyVariableKind,
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex,
GenericPredicate, InEnvironment, Interner, Obligation, ProjectionTy, Scalar, Substitution, Ty,
TyDefId, TyKind, TyVariableKind,
};
use itertools::Itertools;
use rustc_hash::FxHashSet;
Expand Down Expand Up @@ -1786,17 +1786,17 @@ impl Type {
.push(self.ty.value.clone())
.fill(args.iter().map(|t| t.ty.value.clone()))
.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 {
value: InEnvironment::new(
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]),
};
Expand Down
15 changes: 8 additions & 7 deletions crates/hir_ty/src/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use crate::{
to_assoc_type_id, to_chalk_trait_id,
traits::{InEnvironment, Solution},
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;
Expand Down Expand Up @@ -82,16 +83,16 @@ fn deref_by_trait(
}

// Now do the assoc type projection
let projection = super::traits::ProjectionPredicate {
ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len()))
.intern(&Interner),
projection_ty: super::ProjectionTy {
let projection = AliasEq {
alias: AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(target),
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 };

Expand Down
58 changes: 36 additions & 22 deletions crates/hir_ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ use hir_expand::name::Name;

use crate::{
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,
CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation, OpaqueTy,
ProjectionTy, Scalar, Substitution, TraitRef, Ty, TyKind,
to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy,
CallableDefId, CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation,
OpaqueTy, ProjectionTy, Scalar, Substitution, TraitRef, Ty, TyKind,
};

pub struct HirFormatter<'a> {
Expand Down Expand Up @@ -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 {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
if f.should_truncate() {
Expand Down Expand Up @@ -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;
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
// after the corresponding Implemented predicate
if angle_open {
Expand All @@ -714,11 +724,12 @@ fn write_bounds_like_dyn_trait(
write!(f, "<")?;
angle_open = true;
}
let type_alias = f.db.type_alias_data(from_assoc_type_id(
projection_pred.projection_ty.associated_ty_id,
));
write!(f, "{} = ", type_alias.name)?;
projection_pred.ty.hir_fmt(f)?;
if let AliasTy::Projection(proj) = alias {
let type_alias =
f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
write!(f, "{} = ", type_alias.name)?;
}
ty.hir_fmt(f)?;
}
GenericPredicate::Error => {
if angle_open {
Expand Down Expand Up @@ -775,20 +786,20 @@ impl HirDisplay for GenericPredicate {

match self {
GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
GenericPredicate::Projection(projection_pred) => {
GenericPredicate::AliasEq(AliasEq {
alias: AliasTy::Projection(projection_ty),
ty,
}) => {
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!(
f,
">::{} = ",
f.db.type_alias_data(from_assoc_type_id(
projection_pred.projection_ty.associated_ty_id
))
.name,
f.db.type_alias_data(from_assoc_type_id(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(())
}
Expand All @@ -815,11 +826,14 @@ impl HirDisplay for Obligation {
tr.hir_fmt(f)?;
write!(f, ")")
}
Obligation::Projection(proj) => {
Obligation::AliasEq(AliasEq { alias, ty }) => {
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, " => ")?;
proj.ty.hir_fmt(f)?;
ty.hir_fmt(f)?;
write!(f, ")")
}
}
Expand Down
18 changes: 9 additions & 9 deletions crates/hir_ty/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ use stdx::impl_from;
use syntax::SmolStr;

use super::{
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
traits::{Guidance, Obligation, Solution},
InEnvironment, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TypeWalk,
};
use crate::{
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;
Expand Down Expand Up @@ -396,15 +396,15 @@ impl<'a> InferenceContext<'a> {
.build();
let trait_ref =
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() };
let projection = ProjectionPredicate {
ty: ty.clone(),
projection_ty: ProjectionTy {
let alias_eq = AliasEq {
alias: AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(res_assoc_ty),
substitution: substs,
},
}),
ty: ty.clone(),
};
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)
}
None => self.err_ty(),
Expand All @@ -429,8 +429,8 @@ impl<'a> InferenceContext<'a> {

fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
let var = self.table.new_type_var();
let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() };
let obligation = Obligation::Projection(predicate);
let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
let obligation = Obligation::AliasEq(alias_eq);
self.obligations.push(obligation);
var
}
Expand Down
35 changes: 23 additions & 12 deletions crates/hir_ty/src/infer/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};

use super::{InferenceContext, Obligation};
use crate::{
BoundVar, Canonical, DebruijnIndex, FnPointer, GenericPredicate, InEnvironment, InferenceVar,
Interner, Scalar, Substitution, Ty, TyKind, TypeWalk,
AliasEq, AliasTy, BoundVar, Canonical, DebruijnIndex, FnPointer, GenericPredicate,
InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk,
};

impl<'a> InferenceContext<'a> {
Expand Down Expand Up @@ -93,8 +93,8 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
Obligation::Trait(tr) => {
Obligation::Trait(self.do_canonicalize(tr, DebruijnIndex::INNERMOST))
}
Obligation::Projection(pr) => {
Obligation::Projection(self.do_canonicalize(pr, DebruijnIndex::INNERMOST))
Obligation::AliasEq(alias_eq) => {
Obligation::AliasEq(self.do_canonicalize(alias_eq, DebruijnIndex::INNERMOST))
}
};
self.into_canonicalized(InEnvironment {
Expand Down Expand Up @@ -394,14 +394,25 @@ impl InferenceTable {
{
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 =>
{
self.unify_substs(
&proj1.projection_ty.substitution,
&proj2.projection_ty.substitution,
depth + 1,
) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1)
(
GenericPredicate::AliasEq(AliasEq { alias: alias1, ty: ty1 }),
GenericPredicate::AliasEq(AliasEq { alias: alias2, ty: ty2 }),
) => {
let (substitution1, substitution2) = match (alias1, alias2) {
(AliasTy::Projection(projection_ty1), AliasTy::Projection(projection_ty2))
if projection_ty1.associated_ty_id == projection_ty2.associated_ty_id =>
{
(&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,
}
Expand Down
49 changes: 41 additions & 8 deletions crates/hir_ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub use lower::{
associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
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};

Expand All @@ -72,6 +72,20 @@ pub struct OpaqueTy {
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)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known.
Expand Down Expand Up @@ -133,6 +147,25 @@ pub enum AliasTy {
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.
///
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
Expand Down Expand Up @@ -535,7 +568,7 @@ pub enum GenericPredicate {
/// The given trait needs to be implemented for its type parameters.
Implemented(TraitRef),
/// 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
/// be resolved, they will just be Unknown).
Error,
Expand All @@ -553,8 +586,10 @@ impl GenericPredicate {
pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
match self {
GenericPredicate::Implemented(tr) => Some(tr.clone()),
GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)),
GenericPredicate::Error => None,
GenericPredicate::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => {
Some(proj.trait_ref(db))
}
GenericPredicate::AliasEq(_) | GenericPredicate::Error => None,
}
}
}
Expand All @@ -563,7 +598,7 @@ impl TypeWalk for GenericPredicate {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
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 => {}
}
}
Expand All @@ -575,9 +610,7 @@ impl TypeWalk for GenericPredicate {
) {
match self {
GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
GenericPredicate::Projection(projection_pred) => {
projection_pred.walk_mut_binders(f, binders)
}
GenericPredicate::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
GenericPredicate::Error => {}
}
}
Expand Down
Loading