]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_ty/src/display.rs
re-added FIXME
[rust.git] / crates / hir_ty / src / display.rs
index 3f7455959d763779e5311901c95805111f643c8f..2ee4f5cf41bf351508ab8bf3143c1bd1f4bde481 100644 (file)
@@ -4,6 +4,7 @@
 
 use std::fmt::{self, Debug};
 
+use base_db::CrateId;
 use chalk_ir::BoundVar;
 use hir_def::{
     body,
     intern::{Internable, Interned},
     item_scope::ItemInNs,
     path::{Path, PathKind},
-    type_ref::{TypeBound, TypeRef},
+    type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
-    AssocContainerId, Lookup, ModuleId, TraitId,
+    HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use itertools::Itertools;
+use syntax::SmolStr;
 
 use crate::{
     const_from_placeholder_idx,
@@ -149,6 +151,12 @@ pub fn write_joined<T: HirDisplay>(
                 write!(self, "{}", sep)?;
             }
             first = false;
+
+            // Abbreviate multiple omitted types with a single ellipsis.
+            if self.should_truncate() {
+                return write!(self, "{}", TYPE_HINT_TRUNCATION);
+            }
+
             e.hir_fmt(self)?;
         }
         Ok(())
@@ -166,10 +174,9 @@ pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError>
     }
 
     pub fn should_truncate(&self) -> bool {
-        if let Some(max_size) = self.max_size {
-            self.curr_size >= max_size
-        } else {
-            false
+        match self.max_size {
+            Some(max_size) => self.curr_size >= max_size,
+            None => false,
         }
     }
 
@@ -273,11 +280,11 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
 
         let trait_ = f.db.trait_data(self.trait_(f.db));
         write!(f, "<")?;
-        self.self_type_parameter(&Interner).hir_fmt(f)?;
+        self.self_type_parameter(Interner).hir_fmt(f)?;
         write!(f, " as {}", trait_.name)?;
-        if self.substitution.len(&Interner) > 1 {
+        if self.substitution.len(Interner) > 1 {
             write!(f, "<")?;
-            f.write_joined(&self.substitution.as_slice(&Interner)[1..], ", ")?;
+            f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
             write!(f, ">")?;
         }
         write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
@@ -291,7 +298,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
 
-        self.substitution.at(&Interner, 0).hir_fmt(f)
+        self.substitution.at(Interner, 0).hir_fmt(f)
     }
 }
 
@@ -334,7 +341,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
 
-        match self.kind(&Interner) {
+        match self.kind(Interner) {
             TyKind::Never => write!(f, "!")?,
             TyKind::Str => write!(f, "str")?,
             TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
@@ -355,7 +362,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 write!(f, "]")?;
             }
             TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
-                if matches!(self.kind(&Interner), TyKind::Raw(..)) {
+                if matches!(self.kind(Interner), TyKind::Raw(..)) {
                     write!(
                         f,
                         "*{}",
@@ -376,10 +383,20 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 }
 
                 // FIXME: all this just to decide whether to use parentheses...
-                let datas;
-                let predicates: Vec<_> = match t.kind(&Interner) {
+                let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
+                    bounds.iter().any(|bound| {
+                        if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
+                            let trait_ = trait_ref.hir_trait_id();
+                            fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
+                        } else {
+                            false
+                        }
+                    })
+                };
+                let (preds_to_print, has_impl_fn_pred) = 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()
+                        let bounds = dyn_ty.bounds.skip_binders().interned();
+                        (bounds.len(), contains_impl_fn(bounds))
                     }
                     TyKind::Alias(AliasTy::Opaque(OpaqueTy {
                         opaque_ty_id,
@@ -389,33 +406,54 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         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 =
+                            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.substitute(&Interner, parameters);
-                            bounds.into_value_and_skipped_binders().0
+                            let bounds = data.substitute(Interner, parameters);
+                            let mut len = bounds.skip_binders().len();
+
+                            // Don't count Sized but count when it absent
+                            // (i.e. when explicit ?Sized bound is set).
+                            let default_sized = SizedByDefault::Sized {
+                                anchor: func.lookup(f.db.upcast()).module(f.db.upcast()).krate(),
+                            };
+                            let sized_bounds = bounds
+                                .skip_binders()
+                                .iter()
+                                .filter(|b| {
+                                    matches!(
+                                        b.skip_binders(),
+                                        WhereClause::Implemented(trait_ref)
+                                            if default_sized.is_sized_trait(
+                                                trait_ref.hir_trait_id(),
+                                                f.db.upcast(),
+                                            ),
+                                    )
+                                })
+                                .count();
+                            match sized_bounds {
+                                0 => len += 1,
+                                _ => {
+                                    len = len.saturating_sub(sized_bounds);
+                                }
+                            }
+
+                            (len, contains_impl_fn(bounds.skip_binders()))
                         } else {
-                            Vec::new()
+                            (0, false)
                         }
                     }
-                    _ => Vec::new(),
+                    _ => (0, false),
                 };
 
-                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 t.hir_fmt(f);
-                    }
+                if has_impl_fn_pred && preds_to_print <= 2 {
+                    return t.hir_fmt(f);
                 }
 
-                if predicates.len() > 1 {
+                if preds_to_print > 1 {
                     write!(f, "(")?;
                     t.hir_fmt(f)?;
                     write!(f, ")")?;
@@ -424,13 +462,13 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 }
             }
             TyKind::Tuple(_, substs) => {
-                if substs.len(&Interner) == 1 {
+                if substs.len(Interner) == 1 {
                     write!(f, "(")?;
-                    substs.at(&Interner, 0).hir_fmt(f)?;
+                    substs.at(Interner, 0).hir_fmt(f)?;
                     write!(f, ",)")?;
                 } else {
                     write!(f, "(")?;
-                    f.write_joined(&*substs.as_slice(&Interner), ", ")?;
+                    f.write_joined(&*substs.as_slice(Interner), ", ")?;
                     write!(f, ")")?;
                 }
             }
@@ -440,7 +478,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
             }
             TyKind::FnDef(def, parameters) => {
                 let def = from_chalk(f.db, *def);
-                let sig = f.db.callable_item_signature(def).substitute(&Interner, parameters);
+                let sig = f.db.callable_item_signature(def).substitute(Interner, parameters);
                 match def {
                     CallableDefId::FunctionId(ff) => {
                         write!(f, "fn {}", f.db.function_data(ff).name)?
@@ -450,7 +488,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(&Interner) > 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();
@@ -458,7 +496,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.as_slice(&Interner)[..total_len], ", ")?;
+                        f.write_joined(&parameters.as_slice(Interner)[..total_len], ", ")?;
                         write!(f, ">")?;
                     }
                 }
@@ -496,7 +534,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     }
                 }
 
-                if parameters.len(&Interner) > 0 {
+                if parameters.len(Interner) > 0 {
                     let parameters_to_write = if f.display_target.is_source_code()
                         || f.omit_verbose_types()
                     {
@@ -505,39 +543,57 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                             .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
                             .filter(|defaults| !defaults.is_empty())
                         {
-                            None => parameters.as_slice(&Interner),
+                            None => parameters.as_slice(Interner),
                             Some(default_parameters) => {
                                 let mut default_from = 0;
-                                for (i, parameter) in parameters.iter(&Interner).enumerate() {
+                                for (i, parameter) in parameters.iter(Interner).enumerate() {
                                     match (
-                                        parameter.assert_ty_ref(&Interner).kind(&Interner),
+                                        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().substitute(
-                                                    &Interner,
-                                                    &subst_prefix(parameters, i),
-                                                );
-                                            if parameter.assert_ty_ref(&Interner) != &actual_default
+                                            let actual_default = default_parameter
+                                                .clone()
+                                                .substitute(Interner, &subst_prefix(parameters, i));
+                                            if parameter.assert_ty_ref(Interner) != &actual_default
                                             {
                                                 default_from = i + 1;
                                             }
                                         }
                                     }
                                 }
-                                &parameters.as_slice(&Interner)[0..default_from]
+                                &parameters.as_slice(Interner)[0..default_from]
                             }
                         }
                     } else {
-                        parameters.as_slice(&Interner)
+                        parameters.as_slice(Interner)
                     };
                     if !parameters_to_write.is_empty() {
                         write!(f, "<")?;
-                        f.write_joined(parameters_to_write, ", ")?;
+
+                        if f.display_target.is_source_code() {
+                            let mut first = true;
+                            for generic_arg in parameters_to_write {
+                                if !first {
+                                    write!(f, ", ")?;
+                                }
+                                first = false;
+
+                                if generic_arg.ty(Interner).map(|ty| ty.kind(Interner))
+                                    == Some(&TyKind::Error)
+                                {
+                                    write!(f, "_")?;
+                                } else {
+                                    generic_arg.hir_fmt(f)?;
+                                }
+                            }
+                        } else {
+                            f.write_joined(parameters_to_write, ", ")?;
+                        }
+
                         write!(f, ">")?;
                     }
                 }
@@ -545,7 +601,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
             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,
+                    ItemContainerId::TraitId(it) => it,
                     _ => panic!("not an associated type"),
                 };
                 let trait_ = f.db.trait_data(trait_);
@@ -554,9 +610,9 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 // 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(&Interner) > 0 {
+                    if parameters.len(Interner) > 0 {
                         write!(f, "<")?;
-                        f.write_joined(&*parameters.as_slice(&Interner), ", ")?;
+                        f.write_joined(&*parameters.as_slice(Interner), ", ")?;
                         write!(f, ">")?;
                     }
                 } else {
@@ -581,13 +637,19 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        let bounds = data.substitute(&Interner, &parameters);
-                        write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
+                        let bounds = data.substitute(Interner, &parameters);
+                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
+                        write_bounds_like_dyn_trait_with_prefix(
+                            "impl",
+                            bounds.skip_binders(),
+                            SizedByDefault::Sized { anchor: krate },
+                            f,
+                        )?;
                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
                     }
                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                         write!(f, "impl Future<Output = ")?;
-                        parameters.at(&Interner, 0).hir_fmt(f)?;
+                        parameters.at(Interner, 0).hir_fmt(f)?;
                         write!(f, ">")?;
                     }
                 }
@@ -598,11 +660,11 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         DisplaySourceCodeError::Closure,
                     ));
                 }
-                let sig = substs.at(&Interner, 0).assert_ty_ref(&Interner).callable_sig(f.db);
+                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, "||")?;
-                    } else if f.omit_verbose_types() {
+                    } else if f.should_truncate() {
                         write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
                     } else {
                         write!(f, "|")?;
@@ -628,20 +690,26 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         let substs = generics.type_params_subst(f.db);
                         let bounds =
                             f.db.generic_predicates(id.parent)
-                                .into_iter()
-                                .map(|pred| pred.clone().substitute(&Interner, &substs))
+                                .iter()
+                                .map(|pred| pred.clone().substitute(Interner, &substs))
                                 .filter(|wc| match &wc.skip_binders() {
                                     WhereClause::Implemented(tr) => {
-                                        &tr.self_type_parameter(&Interner) == self
+                                        &tr.self_type_parameter(Interner) == self
                                     }
                                     WhereClause::AliasEq(AliasEq {
                                         alias: AliasTy::Projection(proj),
                                         ty: _,
-                                    }) => &proj.self_type_parameter(&Interner) == self,
+                                    }) => &proj.self_type_parameter(Interner) == self,
                                     _ => false,
                                 })
                                 .collect::<Vec<_>>();
-                        write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
+                        let krate = id.parent.module(f.db.upcast()).krate();
+                        write_bounds_like_dyn_trait_with_prefix(
+                            "impl",
+                            &bounds,
+                            SizedByDefault::Sized { anchor: krate },
+                            f,
+                        )?;
                     }
                 }
             }
@@ -650,6 +718,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 write_bounds_like_dyn_trait_with_prefix(
                     "dyn",
                     dyn_ty.bounds.skip_binders().interned(),
+                    SizedByDefault::NotSized,
                     f,
                 )?;
             }
@@ -663,8 +732,14 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        let bounds = data.substitute(&Interner, &opaque_ty.substitution);
-                        write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
+                        let bounds = data.substitute(Interner, &opaque_ty.substitution);
+                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
+                        write_bounds_like_dyn_trait_with_prefix(
+                            "impl",
+                            bounds.skip_binders(),
+                            SizedByDefault::Sized { anchor: krate },
+                            f,
+                        )?;
                     }
                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                         write!(f, "{{async block}}")?;
@@ -713,15 +788,38 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = Trai
     utils::fn_traits(db, krate)
 }
 
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum SizedByDefault {
+    NotSized,
+    Sized { anchor: CrateId },
+}
+
+impl SizedByDefault {
+    fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
+        match self {
+            Self::NotSized => false,
+            Self::Sized { anchor } => {
+                let sized_trait = db
+                    .lang_item(anchor, SmolStr::new_inline("sized"))
+                    .and_then(|lang_item| lang_item.as_trait());
+                Some(trait_) == sized_trait
+            }
+        }
+    }
+}
+
 pub fn write_bounds_like_dyn_trait_with_prefix(
     prefix: &str,
     predicates: &[QuantifiedWhereClause],
+    default_sized: SizedByDefault,
     f: &mut HirFormatter,
 ) -> Result<(), HirDisplayError> {
     write!(f, "{}", prefix)?;
-    if !predicates.is_empty() {
+    if !predicates.is_empty()
+        || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
+    {
         write!(f, " ")?;
-        write_bounds_like_dyn_trait(predicates, f)
+        write_bounds_like_dyn_trait(predicates, default_sized, f)
     } else {
         Ok(())
     }
@@ -729,6 +827,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
 
 fn write_bounds_like_dyn_trait(
     predicates: &[QuantifiedWhereClause],
+    default_sized: SizedByDefault,
     f: &mut HirFormatter,
 ) -> Result<(), HirDisplayError> {
     // Note: This code is written to produce nice results (i.e.
@@ -740,10 +839,18 @@ fn write_bounds_like_dyn_trait(
     let mut first = true;
     let mut angle_open = false;
     let mut is_fn_trait = false;
+    let mut is_sized = false;
     for p in predicates.iter() {
         match p.skip_binders() {
             WhereClause::Implemented(trait_ref) => {
                 let trait_ = trait_ref.hir_trait_id();
+                if default_sized.is_sized_trait(trait_, f.db.upcast()) {
+                    is_sized = true;
+                    if matches!(default_sized, SizedByDefault::Sized { .. }) {
+                        // Don't print +Sized, but rather +?Sized if absent.
+                        continue;
+                    }
+                }
                 if !is_fn_trait {
                     is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
                 }
@@ -758,13 +865,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.substitution.as_slice(&Interner) {
+                if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
                     if is_fn_trait {
                         if let Some(args) =
-                            params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
+                            params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
                         {
                             write!(f, "(")?;
-                            f.write_joined(args.as_slice(&Interner), ", ")?;
+                            f.write_joined(args.as_slice(Interner), ", ")?;
                             write!(f, ")")?;
                         }
                     } else if !params.is_empty() {
@@ -808,6 +915,13 @@ fn write_bounds_like_dyn_trait(
     if angle_open {
         write!(f, ">")?;
     }
+    if matches!(default_sized, SizedByDefault::Sized { .. }) {
+        if !is_sized {
+            write!(f, "{}?Sized", if first { "" } else { " + " })?;
+        } else if first {
+            write!(f, "Sized")?;
+        }
+    }
     Ok(())
 }
 
@@ -816,16 +930,16 @@ fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<()
         return write!(f, "{}", TYPE_HINT_TRUNCATION);
     }
 
-    tr.self_type_parameter(&Interner).hir_fmt(f)?;
+    tr.self_type_parameter(Interner).hir_fmt(f)?;
     if use_as {
         write!(f, " as ")?;
     } else {
         write!(f, ": ")?;
     }
     write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
-    if tr.substitution.len(&Interner) > 1 {
+    if tr.substitution.len(Interner) > 1 {
         write!(f, "<")?;
-        f.write_joined(&tr.substitution.as_slice(&Interner)[1..], ", ")?;
+        f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
         write!(f, ">")?;
     }
     Ok(())
@@ -980,20 +1094,33 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 inner.hir_fmt(f)?;
                 write!(f, "]")?;
             }
-            TypeRef::Fn(tys, is_varargs) => {
+            TypeRef::Fn(parameters, is_varargs) => {
                 // FIXME: Function pointer qualifiers.
                 write!(f, "fn(")?;
-                f.write_joined(&tys[..tys.len() - 1], ", ")?;
+                for index in 0..parameters.len() - 1 {
+                    let (param_name, param_type) = &parameters[index];
+                    if let Some(name) = param_name {
+                        write!(f, "{}: ", name)?;
+                    }
+
+                    param_type.hir_fmt(f)?;
+
+                    // Last index contains the return type so we stop writing commas on the second-to-last index
+                    if index != parameters.len() - 2 {
+                        write!(f, ", ")?;
+                    }
+                }
                 if *is_varargs {
-                    write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
+                    write!(f, "{}...", if parameters.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)?;
+                if let Some((_, ret_ty)) = &parameters.last() {
+                    match ret_ty {
+                        TypeRef::Tuple(tup) if tup.is_empty() => {}
+                        _ => {
+                            write!(f, " -> ")?;
+                            ret_ty.hir_fmt(f)?;
+                        }
                     }
                 }
             }
@@ -1026,7 +1153,13 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
 impl HirDisplay for TypeBound {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         match self {
-            TypeBound::Path(path) => path.hir_fmt(f),
+            TypeBound::Path(path, modifier) => {
+                match modifier {
+                    TraitBoundModifier::None => (),
+                    TraitBoundModifier::Maybe => write!(f, "?")?,
+                }
+                path.hir_fmt(f)
+            }
             TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
             TypeBound::ForLifetime(lifetimes, path) => {
                 write!(f, "for<{}> ", lifetimes.iter().format(", "))?;
@@ -1046,26 +1179,51 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 write!(f, ">")?;
             }
             (_, PathKind::Plain) => {}
-            (_, PathKind::Abs) => write!(f, "::")?,
+            (_, PathKind::Abs) => {}
             (_, PathKind::Crate) => write!(f, "crate")?,
             (_, PathKind::Super(0)) => write!(f, "self")?,
             (_, PathKind::Super(n)) => {
-                write!(f, "super")?;
-                for _ in 0..*n {
-                    write!(f, "::super")?;
+                for i in 0..*n {
+                    if i > 0 {
+                        write!(f, "::")?;
+                    }
+                    write!(f, "super")?;
                 }
             }
             (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
         }
 
         for (seg_idx, segment) in self.segments().iter().enumerate() {
-            if seg_idx != 0 {
+            if !matches!(self.kind(), PathKind::Plain) || 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?
+                if generic_args.desugared_from_fn {
+                    // First argument will be a tuple, which already includes the parentheses.
+                    // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
+                    if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
+                        &generic_args.args[0]
+                    {
+                        if v.len() == 1 {
+                            write!(f, "(")?;
+                            v[0].hir_fmt(f)?;
+                            write!(f, ")")?;
+                        } else {
+                            generic_args.args[0].hir_fmt(f)?;
+                        }
+                    }
+                    if let Some(ret) = &generic_args.bindings[0].type_ref {
+                        if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
+                            write!(f, " -> ")?;
+                            ret.hir_fmt(f)?;
+                        }
+                    }
+                    return Ok(());
+                }
+
                 write!(f, "<")?;
                 let mut first = true;
                 for arg in &generic_args.args {