]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_ty/src/display.rs
Rename TyKind::ForeignType to Foreign
[rust.git] / crates / hir_ty / src / display.rs
index ab51cb0a6ee4b42ac939b7545d43179fb4d3dc80..5ff70c893a2328542c4768124b502659484b34f1 100644 (file)
@@ -1,19 +1,25 @@
 //! FIXME: write short doc here
 
-use std::{borrow::Cow, fmt};
+use std::{array, fmt};
 
-use arrayvec::ArrayVec;
 use chalk_ir::Mutability;
 use hir_def::{
-    db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs,
+    db::DefDatabase,
+    find_path,
+    generics::TypeParamProvenance,
+    item_scope::ItemInNs,
+    path::{Path, PathKind},
+    type_ref::{TypeBound, TypeRef},
+    visibility::Visibility,
     AssocContainerId, Lookup, ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 
 use crate::{
-    db::HirDatabase, primitive, utils::generics, AdtId, AliasTy, CallableDefId, CallableSig,
-    GenericPredicate, Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs,
-    TraitRef, Ty,
+    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, AliasEq, AliasTy,
+    CallableDefId, CallableSig, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, OpaqueTy,
+    ProjectionTy, QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause,
 };
 
 pub struct HirFormatter<'a> {
@@ -183,6 +189,7 @@ fn is_test(&self) -> bool {
 pub enum DisplaySourceCodeError {
     PathNotFound,
     UnknownType,
+    Closure,
 }
 
 pub enum HirDisplayError {
@@ -231,7 +238,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 const TYPE_HINT_TRUNCATION: &str = "…";
 
-impl HirDisplay for &Ty {
+impl<T: HirDisplay> HirDisplay for &'_ T {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         HirDisplay::hir_fmt(*self, f)
     }
@@ -244,55 +251,70 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         }
 
         let trait_ = f.db.trait_data(self.trait_(f.db));
-        let first_parameter = self.parameters[0].into_displayable(
+        let first_parameter = self.self_type_parameter().into_displayable(
             f.db,
             f.max_size,
             f.omit_verbose_types,
             f.display_target,
         );
         write!(f, "<{} as {}", first_parameter, trait_.name)?;
-        if self.parameters.len() > 1 {
+        if self.substitution.len(&Interner) > 1 {
             write!(f, "<")?;
-            f.write_joined(&self.parameters[1..], ", ")?;
+            f.write_joined(&self.substitution.interned()[1..], ", ")?;
             write!(f, ">")?;
         }
-        write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?;
+        write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
         Ok(())
     }
 }
 
+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.at(&Interner, 0).hir_fmt(f)
+    }
+}
+
+impl HirDisplay for GenericArg {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        match self.interned() {
+            crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
+        }
+    }
+}
+
 impl HirDisplay for Ty {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         if f.should_truncate() {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
 
-        match self {
-            Ty::Never => write!(f, "!")?,
-            Ty::Str => write!(f, "str")?,
-            Ty::Scalar(Scalar::Bool) => write!(f, "bool")?,
-            Ty::Scalar(Scalar::Char) => write!(f, "char")?,
-            &Ty::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
-            &Ty::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
-            &Ty::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
-            Ty::Slice(parameters) => {
-                let t = parameters.as_single();
+        match self.kind(&Interner) {
+            TyKind::Never => write!(f, "!")?,
+            TyKind::Str => write!(f, "str")?,
+            TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
+            TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
+            &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
+            &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
+            &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
+            TyKind::Slice(t) => {
                 write!(f, "[")?;
                 t.hir_fmt(f)?;
                 write!(f, "]")?;
             }
-            Ty::Array(parameters) => {
-                let t = parameters.as_single();
+            TyKind::Array(t) => {
                 write!(f, "[")?;
                 t.hir_fmt(f)?;
                 write!(f, "; _]")?;
             }
-            Ty::Raw(m, parameters) | Ty::Ref(m, parameters) => {
-                let t = parameters.as_single();
+            TyKind::Raw(m, t) | TyKind::Ref(m, t) => {
                 let ty_display =
                     t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
 
-                if matches!(self, Ty::Raw(..)) {
+                if matches!(self.kind(&Interner), TyKind::Raw(..)) {
                     write!(
                         f,
                         "*{}",
@@ -312,29 +334,40 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     )?;
                 }
 
+                // FIXME: all this just to decide whether to use parentheses...
                 let datas;
-                let predicates = match t {
-                    Ty::Dyn(predicates) if predicates.len() > 1 => {
-                        Cow::Borrowed(predicates.as_ref())
+                let predicates: Vec<_> = match t.kind(&Interner) {
+                    TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
+                        dyn_ty.bounds.skip_binders().interned().iter().cloned().collect()
                     }
-                    &Ty::Alias(AliasTy::Opaque(OpaqueTy {
-                        opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx),
-                        ref parameters,
+                    &TyKind::Alias(AliasTy::Opaque(OpaqueTy {
+                        opaque_ty_id,
+                        substitution: ref parameters,
                     })) => {
-                        datas =
-                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
-                        let data = (*datas)
-                            .as_ref()
-                            .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        let bounds = data.subst(parameters);
-                        Cow::Owned(bounds.value)
+                        let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty_id.into());
+                        if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
+                            datas =
+                                f.db.return_type_impl_traits(func)
+                                    .expect("impl trait id without data");
+                            let data = (*datas)
+                                .as_ref()
+                                .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
+                            let bounds = data.subst(parameters);
+                            bounds.value
+                        } else {
+                            Vec::new()
+                        }
                     }
-                    _ => Cow::Borrowed(&[][..]),
+                    _ => Vec::new(),
                 };
 
-                if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
-                    let trait_ = trait_ref.trait_;
-                    if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
+                if let Some(WhereClause::Implemented(trait_ref)) =
+                    predicates.get(0).map(|b| b.skip_binders())
+                {
+                    let trait_ = trait_ref.hir_trait_id();
+                    if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
+                        && predicates.len() <= 2
+                    {
                         return write!(f, "{}", ty_display);
                     }
                 }
@@ -347,23 +380,23 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     write!(f, "{}", ty_display)?;
                 }
             }
-            Ty::Tuple(_, substs) => {
-                if substs.len() == 1 {
+            TyKind::Tuple(_, substs) => {
+                if substs.len(&Interner) == 1 {
                     write!(f, "(")?;
-                    substs[0].hir_fmt(f)?;
+                    substs.at(&Interner, 0).hir_fmt(f)?;
                     write!(f, ",)")?;
                 } else {
                     write!(f, "(")?;
-                    f.write_joined(&*substs.0, ", ")?;
+                    f.write_joined(&*substs.interned(), ", ")?;
                     write!(f, ")")?;
                 }
             }
-            Ty::Function(fn_ptr) => {
+            TyKind::Function(fn_ptr) => {
                 let sig = CallableSig::from_fn_ptr(fn_ptr);
                 sig.hir_fmt(f)?;
             }
-            Ty::FnDef(def, parameters) => {
-                let def = *def;
+            TyKind::FnDef(def, parameters) => {
+                let def = from_chalk(f.db, *def);
                 let sig = f.db.callable_item_signature(def).subst(parameters);
                 match def {
                     CallableDefId::FunctionId(ff) => {
@@ -374,7 +407,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
                     }
                 };
-                if parameters.len() > 0 {
+                if parameters.len(&Interner) > 0 {
                     let generics = generics(f.db.upcast(), def.into());
                     let (parent_params, self_param, type_params, _impl_trait_params) =
                         generics.provenance_split();
@@ -382,7 +415,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
                     if total_len > 0 {
                         write!(f, "<")?;
-                        f.write_joined(&parameters.0[..total_len], ", ")?;
+                        f.write_joined(&parameters.interned()[..total_len], ", ")?;
                         write!(f, ">")?;
                     }
                 }
@@ -390,7 +423,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 f.write_joined(sig.params(), ", ")?;
                 write!(f, ")")?;
                 let ret = sig.ret();
-                if *ret != Ty::unit() {
+                if !ret.is_unit() {
                     let ret_display = ret.into_displayable(
                         f.db,
                         f.max_size,
@@ -401,7 +434,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     write!(f, " -> {}", ret_display)?;
                 }
             }
-            Ty::Adt(AdtId(def_id), parameters) => {
+            TyKind::Adt(AdtId(def_id), parameters) => {
                 match f.display_target {
                     DisplayTarget::Diagnostics | DisplayTarget::Test => {
                         let name = match *def_id {
@@ -426,38 +459,43 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     }
                 }
 
-                if parameters.len() > 0 {
-                    let parameters_to_write =
-                        if f.display_target.is_source_code() || f.omit_verbose_types() {
-                            match self
-                                .as_generic_def()
-                                .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
-                                .filter(|defaults| !defaults.is_empty())
-                            {
-                                None => parameters.0.as_ref(),
-                                Some(default_parameters) => {
-                                    let mut default_from = 0;
-                                    for (i, parameter) in parameters.iter().enumerate() {
-                                        match (parameter, default_parameters.get(i)) {
-                                            (&Ty::Unknown, _) | (_, None) => {
+                if parameters.len(&Interner) > 0 {
+                    let parameters_to_write = if f.display_target.is_source_code()
+                        || f.omit_verbose_types()
+                    {
+                        match self
+                            .as_generic_def(f.db)
+                            .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
+                            .filter(|defaults| !defaults.is_empty())
+                        {
+                            None => parameters.interned().as_ref(),
+                            Some(default_parameters) => {
+                                let mut default_from = 0;
+                                for (i, parameter) in parameters.iter(&Interner).enumerate() {
+                                    match (
+                                        parameter.assert_ty_ref(&Interner).kind(&Interner),
+                                        default_parameters.get(i),
+                                    ) {
+                                        (&TyKind::Error, _) | (_, None) => {
+                                            default_from = i + 1;
+                                        }
+                                        (_, Some(default_parameter)) => {
+                                            let actual_default = default_parameter
+                                                .clone()
+                                                .subst(&parameters.prefix(i));
+                                            if parameter.assert_ty_ref(&Interner) != &actual_default
+                                            {
                                                 default_from = i + 1;
                                             }
-                                            (_, Some(default_parameter)) => {
-                                                let actual_default = default_parameter
-                                                    .clone()
-                                                    .subst(&parameters.prefix(i));
-                                                if parameter != &actual_default {
-                                                    default_from = i + 1;
-                                                }
-                                            }
                                         }
                                     }
-                                    &parameters.0[0..default_from]
                                 }
+                                &parameters.interned()[0..default_from]
                             }
-                        } else {
-                            parameters.0.as_ref()
-                        };
+                        }
+                    } else {
+                        parameters.interned().as_ref()
+                    };
                     if !parameters_to_write.is_empty() {
                         write!(f, "<")?;
                         f.write_joined(parameters_to_write, ", ")?;
@@ -465,36 +503,40 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     }
                 }
             }
-            Ty::AssociatedType(type_alias, parameters) => {
+            TyKind::AssociatedType(assoc_type_id, parameters) => {
+                let type_alias = from_assoc_type_id(*assoc_type_id);
                 let trait_ = match type_alias.lookup(f.db.upcast()).container {
                     AssocContainerId::TraitId(it) => it,
                     _ => panic!("not an associated type"),
                 };
                 let trait_ = f.db.trait_data(trait_);
-                let type_alias_data = f.db.type_alias_data(*type_alias);
+                let type_alias_data = f.db.type_alias_data(type_alias);
 
                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
                 if f.display_target.is_test() {
                     write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
-                    if parameters.len() > 0 {
+                    if parameters.len(&Interner) > 0 {
                         write!(f, "<")?;
-                        f.write_joined(&*parameters.0, ", ")?;
+                        f.write_joined(&*parameters.interned(), ", ")?;
                         write!(f, ">")?;
                     }
                 } else {
-                    let projection_ty =
-                        ProjectionTy { associated_ty: *type_alias, parameters: parameters.clone() };
+                    let projection_ty = ProjectionTy {
+                        associated_ty_id: to_assoc_type_id(type_alias),
+                        substitution: parameters.clone(),
+                    };
 
                     projection_ty.hir_fmt(f)?;
                 }
             }
-            Ty::ForeignType(type_alias) => {
-                let type_alias = f.db.type_alias_data(*type_alias);
+            TyKind::Foreign(type_alias) => {
+                let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
                 write!(f, "{}", type_alias.name)?;
             }
-            Ty::OpaqueType(opaque_ty_id, parameters) => {
-                match opaque_ty_id {
-                    &OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
+            TyKind::OpaqueType(opaque_ty_id, parameters) => {
+                let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
+                match impl_trait_id {
+                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
                         let datas =
                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
                         let data = (*datas)
@@ -504,15 +546,20 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
                     }
-                    OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
+                    ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                         write!(f, "impl Future<Output = ")?;
-                        parameters[0].hir_fmt(f)?;
+                        parameters.at(&Interner, 0).hir_fmt(f)?;
                         write!(f, ">")?;
                     }
                 }
             }
-            Ty::Closure(.., substs) => {
-                let sig = substs[0].callable_sig(f.db);
+            TyKind::Closure(.., substs) => {
+                if f.display_target.is_source_code() {
+                    return Err(HirDisplayError::DisplaySourceCodeError(
+                        DisplaySourceCodeError::Closure,
+                    ));
+                }
+                let sig = substs.at(&Interner, 0).assert_ty_ref(&Interner).callable_sig(f.db);
                 if let Some(sig) = sig {
                     if sig.params().is_empty() {
                         write!(f, "||")?;
@@ -535,7 +582,8 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     write!(f, "{{closure}}")?;
                 }
             }
-            Ty::Placeholder(id) => {
+            TyKind::Placeholder(idx) => {
+                let id = from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
                 let param_data = &generics.params.types[id.local_id];
                 match param_data.provenance {
@@ -543,38 +591,52 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
                     }
                     TypeParamProvenance::ArgumentImplTrait => {
-                        let bounds = f.db.generic_predicates_for_param(*id);
-                        let substs = Substs::type_params_for_generics(&generics);
-                        write_bounds_like_dyn_trait_with_prefix(
-                            "impl",
-                            &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
-                            f,
-                        )?;
+                        let substs = generics.type_params_subst(f.db);
+                        let bounds = f
+                            .db
+                            .generic_predicates(id.parent)
+                            .into_iter()
+                            .map(|pred| pred.clone().subst(&substs))
+                            .filter(|wc| match &wc.skip_binders() {
+                                WhereClause::Implemented(tr) => tr.self_type_parameter() == self,
+                                WhereClause::AliasEq(AliasEq {
+                                    alias: AliasTy::Projection(proj),
+                                    ty: _,
+                                }) => proj.self_type_parameter() == self,
+                                _ => false,
+                            })
+                            .collect::<Vec<_>>();
+                        write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
                     }
                 }
             }
-            Ty::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
-            Ty::Dyn(predicates) => {
-                write_bounds_like_dyn_trait_with_prefix("dyn", predicates, f)?;
+            TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
+            TyKind::Dyn(dyn_ty) => {
+                write_bounds_like_dyn_trait_with_prefix(
+                    "dyn",
+                    dyn_ty.bounds.skip_binders().interned(),
+                    f,
+                )?;
             }
-            Ty::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
-            Ty::Alias(AliasTy::Opaque(opaque_ty)) => {
-                match opaque_ty.opaque_ty_id {
-                    OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
+            TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
+            TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
+                let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
+                match impl_trait_id {
+                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
                         let datas =
                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        let bounds = data.subst(&opaque_ty.parameters);
+                        let bounds = data.subst(&opaque_ty.substitution);
                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
                     }
-                    OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
+                    ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                         write!(f, "{{async block}}")?;
                     }
                 };
             }
-            Ty::Unknown => {
+            TyKind::Error => {
                 if f.display_target.is_source_code() {
                     return Err(HirDisplayError::DisplaySourceCodeError(
                         DisplaySourceCodeError::UnknownType,
@@ -582,7 +644,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 }
                 write!(f, "{{unknown}}")?;
             }
-            Ty::InferenceVar(..) => write!(f, "_")?,
+            TyKind::InferenceVar(..) => write!(f, "_")?,
         }
         Ok(())
     }
@@ -601,7 +663,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         }
         write!(f, ")")?;
         let ret = self.ret();
-        if *ret != Ty::unit() {
+        if !ret.is_unit() {
             let ret_display =
                 ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
             write!(f, " -> {}", ret_display)?;
@@ -617,13 +679,12 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = Trai
         db.lang_item(krate, "fn_mut".into()),
         db.lang_item(krate, "fn_once".into()),
     ];
-    // FIXME: Replace ArrayVec when into_iter is a thing on arrays
-    ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
+    array::IntoIter::new(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
 }
 
 pub fn write_bounds_like_dyn_trait_with_prefix(
     prefix: &str,
-    predicates: &[GenericPredicate],
+    predicates: &[QuantifiedWhereClause],
     f: &mut HirFormatter,
 ) -> Result<(), HirDisplayError> {
     write!(f, "{}", prefix)?;
@@ -636,7 +697,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
 }
 
 fn write_bounds_like_dyn_trait(
-    predicates: &[GenericPredicate],
+    predicates: &[QuantifiedWhereClause],
     f: &mut HirFormatter,
 ) -> Result<(), HirDisplayError> {
     // Note: This code is written to produce nice results (i.e.
@@ -649,9 +710,9 @@ fn write_bounds_like_dyn_trait(
     let mut angle_open = false;
     let mut is_fn_trait = false;
     for p in predicates.iter() {
-        match p {
-            GenericPredicate::Implemented(trait_ref) => {
-                let trait_ = trait_ref.trait_;
+        match p.skip_binders() {
+            WhereClause::Implemented(trait_ref) => {
+                let trait_ = trait_ref.hir_trait_id();
                 if !is_fn_trait {
                     is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
                 }
@@ -666,11 +727,13 @@ fn write_bounds_like_dyn_trait(
                 // existential) here, which is the only thing that's
                 // possible in actual Rust, and hence don't print it
                 write!(f, "{}", f.db.trait_data(trait_).name)?;
-                if let [_, params @ ..] = &*trait_ref.substs.0 {
+                if let [_, params @ ..] = &*trait_ref.substitution.interned() {
                     if is_fn_trait {
-                        if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
+                        if let Some(args) =
+                            params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
+                        {
                             write!(f, "(")?;
-                            f.write_joined(&*args.0, ", ")?;
+                            f.write_joined(&*args.interned(), ", ")?;
                             write!(f, ")")?;
                         }
                     } else if !params.is_empty() {
@@ -681,12 +744,12 @@ fn write_bounds_like_dyn_trait(
                     }
                 }
             }
-            GenericPredicate::Projection(projection_pred) if is_fn_trait => {
+            WhereClause::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) => {
+            WhereClause::AliasEq(AliasEq { ty, alias }) => {
                 // in types in actual Rust, these will always come
                 // after the corresponding Implemented predicate
                 if angle_open {
@@ -695,19 +758,12 @@ fn write_bounds_like_dyn_trait(
                     write!(f, "<")?;
                     angle_open = true;
                 }
-                let type_alias = f.db.type_alias_data(projection_pred.projection_ty.associated_ty);
-                write!(f, "{} = ", type_alias.name)?;
-                projection_pred.ty.hir_fmt(f)?;
-            }
-            GenericPredicate::Error => {
-                if angle_open {
-                    // impl Trait<X, {error}>
-                    write!(f, ", ")?;
-                } else if !first {
-                    // impl Trait + {error}
-                    write!(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)?;
                 }
-                p.hir_fmt(f)?;
+                ty.hir_fmt(f)?;
             }
         }
         first = false;
@@ -724,16 +780,16 @@ fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDispl
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
 
-        self.substs[0].hir_fmt(f)?;
+        self.self_type_parameter().hir_fmt(f)?;
         if use_as {
             write!(f, " as ")?;
         } else {
             write!(f, ": ")?;
         }
-        write!(f, "{}", f.db.trait_data(self.trait_).name)?;
-        if self.substs.len() > 1 {
+        write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
+        if self.substitution.len(&Interner) > 1 {
             write!(f, "<")?;
-            f.write_joined(&self.substs[1..], ", ")?;
+            f.write_joined(&self.substitution.interned()[1..], ", ")?;
             write!(f, ">")?;
         }
         Ok(())
@@ -746,31 +802,25 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
     }
 }
 
-impl HirDisplay for &GenericPredicate {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        HirDisplay::hir_fmt(*self, f)
-    }
-}
-
-impl HirDisplay for GenericPredicate {
+impl HirDisplay for WhereClause {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         if f.should_truncate() {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
 
         match self {
-            GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
-            GenericPredicate::Projection(projection_pred) => {
+            WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
+            WhereClause::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(projection_pred.projection_ty.associated_ty).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}}")?,
+            WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
         }
         Ok(())
     }
@@ -789,21 +839,201 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
     }
 }
 
-impl HirDisplay for Obligation {
+impl HirDisplay for DomainGoal {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         match self {
-            Obligation::Trait(tr) => {
-                write!(f, "Implements(")?;
-                tr.hir_fmt(f)?;
+            DomainGoal::Holds(wc) => {
+                write!(f, "Holds(")?;
+                wc.hir_fmt(f)?;
                 write!(f, ")")
             }
-            Obligation::Projection(proj) => {
-                write!(f, "Normalize(")?;
-                proj.projection_ty.hir_fmt(f)?;
-                write!(f, " => ")?;
-                proj.ty.hir_fmt(f)?;
-                write!(f, ")")
+        }
+    }
+}
+
+pub fn write_visibility(
+    module_id: ModuleId,
+    vis: Visibility,
+    f: &mut HirFormatter,
+) -> Result<(), HirDisplayError> {
+    match vis {
+        Visibility::Public => write!(f, "pub "),
+        Visibility::Module(vis_id) => {
+            let def_map = module_id.def_map(f.db.upcast());
+            let root_module_id = def_map.module_id(def_map.root());
+            if vis_id == module_id {
+                // pub(self) or omitted
+                Ok(())
+            } else if root_module_id == vis_id {
+                write!(f, "pub(crate) ")
+            } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
+                write!(f, "pub(super) ")
+            } else {
+                write!(f, "pub(in ...) ")
             }
         }
     }
 }
+
+impl HirDisplay for TypeRef {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        match self {
+            TypeRef::Never => write!(f, "!")?,
+            TypeRef::Placeholder => write!(f, "_")?,
+            TypeRef::Tuple(elems) => {
+                write!(f, "(")?;
+                f.write_joined(elems, ", ")?;
+                if elems.len() == 1 {
+                    write!(f, ",")?;
+                }
+                write!(f, ")")?;
+            }
+            TypeRef::Path(path) => path.hir_fmt(f)?,
+            TypeRef::RawPtr(inner, mutability) => {
+                let mutability = match mutability {
+                    hir_def::type_ref::Mutability::Shared => "*const ",
+                    hir_def::type_ref::Mutability::Mut => "*mut ",
+                };
+                write!(f, "{}", mutability)?;
+                inner.hir_fmt(f)?;
+            }
+            TypeRef::Reference(inner, lifetime, mutability) => {
+                let mutability = match mutability {
+                    hir_def::type_ref::Mutability::Shared => "",
+                    hir_def::type_ref::Mutability::Mut => "mut ",
+                };
+                write!(f, "&")?;
+                if let Some(lifetime) = lifetime {
+                    write!(f, "{} ", lifetime.name)?;
+                }
+                write!(f, "{}", mutability)?;
+                inner.hir_fmt(f)?;
+            }
+            TypeRef::Array(inner) => {
+                write!(f, "[")?;
+                inner.hir_fmt(f)?;
+                // FIXME: Array length?
+                write!(f, "; _]")?;
+            }
+            TypeRef::Slice(inner) => {
+                write!(f, "[")?;
+                inner.hir_fmt(f)?;
+                write!(f, "]")?;
+            }
+            TypeRef::Fn(tys, is_varargs) => {
+                // FIXME: Function pointer qualifiers.
+                write!(f, "fn(")?;
+                f.write_joined(&tys[..tys.len() - 1], ", ")?;
+                if *is_varargs {
+                    write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
+                }
+                write!(f, ")")?;
+                let ret_ty = tys.last().unwrap();
+                match ret_ty {
+                    TypeRef::Tuple(tup) if tup.is_empty() => {}
+                    _ => {
+                        write!(f, " -> ")?;
+                        ret_ty.hir_fmt(f)?;
+                    }
+                }
+            }
+            TypeRef::ImplTrait(bounds) => {
+                write!(f, "impl ")?;
+                f.write_joined(bounds, " + ")?;
+            }
+            TypeRef::DynTrait(bounds) => {
+                write!(f, "dyn ")?;
+                f.write_joined(bounds, " + ")?;
+            }
+            TypeRef::Error => write!(f, "{{error}}")?,
+        }
+        Ok(())
+    }
+}
+
+impl HirDisplay for TypeBound {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        match self {
+            TypeBound::Path(path) => path.hir_fmt(f),
+            TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
+            TypeBound::Error => write!(f, "{{error}}"),
+        }
+    }
+}
+
+impl HirDisplay for Path {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        match (self.type_anchor(), self.kind()) {
+            (Some(anchor), _) => {
+                write!(f, "<")?;
+                anchor.hir_fmt(f)?;
+                write!(f, ">")?;
+            }
+            (_, PathKind::Plain) => {}
+            (_, PathKind::Abs) => write!(f, "::")?,
+            (_, PathKind::Crate) => write!(f, "crate")?,
+            (_, PathKind::Super(0)) => write!(f, "self")?,
+            (_, PathKind::Super(n)) => {
+                write!(f, "super")?;
+                for _ in 0..*n {
+                    write!(f, "::super")?;
+                }
+            }
+            (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
+        }
+
+        for (seg_idx, segment) in self.segments().iter().enumerate() {
+            if seg_idx != 0 {
+                write!(f, "::")?;
+            }
+            write!(f, "{}", segment.name)?;
+            if let Some(generic_args) = segment.args_and_bindings {
+                // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
+                // Do we actually format expressions?
+                write!(f, "<")?;
+                let mut first = true;
+                for arg in &generic_args.args {
+                    if first {
+                        first = false;
+                        if generic_args.has_self_type {
+                            // FIXME: Convert to `<Ty as Trait>` form.
+                            write!(f, "Self = ")?;
+                        }
+                    } else {
+                        write!(f, ", ")?;
+                    }
+                    arg.hir_fmt(f)?;
+                }
+                for binding in &generic_args.bindings {
+                    if first {
+                        first = false;
+                    } else {
+                        write!(f, ", ")?;
+                    }
+                    write!(f, "{}", binding.name)?;
+                    match &binding.type_ref {
+                        Some(ty) => {
+                            write!(f, " = ")?;
+                            ty.hir_fmt(f)?
+                        }
+                        None => {
+                            write!(f, ": ")?;
+                            f.write_joined(&binding.bounds, " + ")?;
+                        }
+                    }
+                }
+                write!(f, ">")?;
+            }
+        }
+        Ok(())
+    }
+}
+
+impl HirDisplay for hir_def::path::GenericArg {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        match self {
+            hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
+            hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
+        }
+    }
+}