about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-08-12 17:55:29 +0000
committerGitHub <noreply@github.com>2021-08-12 17:55:29 +0000
commitbaf149437452f6aec9f873bb312723bf62cb3a74 (patch)
treeaa9f703c7982944aed7d7393bb0db0f653686b2d
parentc619cb12d7f7c1cf65d44007b144b4c9bcafc7c5 (diff)
parent6c366ade0087db292b9a1eee71b6a20653a4d0e9 (diff)
Merge #9807
9807: Implicit `Sized` bounds r=iDawer a=iDawer

This should close #8984 

`hir_ty`:
- Type parameters, associated types and `impl Trait` are `Sized` by deafault except `Self` in a trait.
- Implicit `Sized` bound is added to end of predicate list. It does not check if such bound is present already. Also it does not track the bound is implicit.
- Allowed ambiguous unsize coercion if Chalk returns definite guidance.
- Allowed ambiguous autoderef if Chalk returns definite guidance.

`hir_def`:
- `ItemTree` pretty printing shows `?Sized` bounds.

`HirDisplay`:
- `impl Trait` with weird bounds rendered correctly.
- `Sized`/`?Sized` bounds are not shown if they are default.

### Perf
`./target/rust-analyzer-baseline_8a843113 -q analysis-stats --memory-usage .`
```
Database loaded:     1.63s, 287minstr, 91mb
  crates: 38, mods: 741, decls: 15914, fns: 11835
Item Collection:     26.80s, 73ginstr, 338mb
  exprs: 318994, ??ty: 398 (0%), ?ty: 435 (0%), !ty: 174
Inference:           50.28s, 116ginstr, 516mb
Total:               77.08s, 189ginstr, 855mb
```

`./target/rust-analyzer-sized-fixed_ambig_coercion-de074fe6 -q analysis-stats --memory-usage .`
```
Database loaded:     1.63s, 287minstr, 91mb
  crates: 38, mods: 741, decls: 15914, fns: 11835
Item Collection:     26.95s, 73ginstr, 338mb
  exprs: 318994, ??ty: 398 (0%), ?ty: 435 (0%), !ty: 166
Inference:           96.39s, 234ginstr, 543mb
Total:               123.33s, 307ginstr, 881mb
```


Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com>
-rw-r--r--crates/hir/src/display.rs7
-rw-r--r--crates/hir_def/src/generics.rs4
-rw-r--r--crates/hir_def/src/item_tree/lower.rs4
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs9
-rw-r--r--crates/hir_def/src/item_tree/tests.rs8
-rw-r--r--crates/hir_def/src/type_ref.rs27
-rw-r--r--crates/hir_ty/src/autoderef.rs19
-rw-r--r--crates/hir_ty/src/chalk_db.rs17
-rw-r--r--crates/hir_ty/src/display.rs145
-rw-r--r--crates/hir_ty/src/infer/coerce.rs12
-rw-r--r--crates/hir_ty/src/lower.rs130
-rw-r--r--crates/hir_ty/src/tests/coercion.rs19
-rw-r--r--crates/hir_ty/src/tests/display_source_code.rs111
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs27
-rw-r--r--crates/hir_ty/src/tests/regression.rs3
-rw-r--r--crates/hir_ty/src/tests/traits.rs91
-rw-r--r--crates/hir_ty/src/utils.rs6
-rw-r--r--crates/ide/src/hover.rs28
-rw-r--r--crates/ide/src/inlay_hints.rs48
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs9
20 files changed, 620 insertions, 104 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 72f0d9b5f79..dff4372738b 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -7,7 +7,7 @@ use hir_def::{
 };
 use hir_ty::display::{
     write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
-    HirFormatter,
+    HirFormatter, SizedByDefault,
 };
 use hir_ty::Interner;
 use syntax::ast::{self, NameOwner};
@@ -93,7 +93,7 @@ impl HirDisplay for Function {
         } else {
             match &*data.ret_type {
                 TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
-                    TypeBound::Path(path) => {
+                    TypeBound::Path(path, _) => {
                         path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
                             [0]
                         .type_ref
@@ -239,7 +239,8 @@ impl HirDisplay for TypeParam {
         let predicates =
             bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect::<Vec<_>>();
         if !(predicates.is_empty() || f.omit_verbose_types()) {
-            write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
+            let default_sized = SizedByDefault::Sized { anchor: self.module(f.db).krate().id };
+            write_bounds_like_dyn_trait_with_prefix(":", &predicates, default_sized, f)?;
         }
         Ok(())
     }
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 096ac796850..40104833db3 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -338,10 +338,6 @@ impl GenericParams {
         hrtb_lifetimes: Option<&Box<[Name]>>,
         target: Either<TypeRef, LifetimeRef>,
     ) {
-        if bound.question_mark_token().is_some() {
-            // FIXME: remove this bound
-            return;
-        }
         let bound = TypeBound::from_ast(lower_ctx, bound);
         let predicate = match (target, bound) {
             (Either::Left(type_ref), bound) => match hrtb_lifetimes {
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 44bd2fa9e57..2f9e33b6adc 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -10,7 +10,7 @@ use syntax::{
 
 use crate::{
     generics::{GenericParams, TypeParamData, TypeParamProvenance},
-    type_ref::{LifetimeRef, TraitRef},
+    type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
 };
 
 use super::*;
@@ -369,7 +369,7 @@ impl<'a> Ctx<'a> {
         let (ret_type, async_ret_type) = if func.async_token().is_some() {
             let async_ret_type = ret_type.clone();
             let future_impl = desugar_future_path(ret_type);
-            let ty_bound = Interned::new(TypeBound::Path(future_impl));
+            let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
             (TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type))
         } else {
             (ret_type, None)
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 603c594f2aa..24cc2408de2 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -8,6 +8,7 @@ use crate::{
     attr::RawAttrs,
     generics::{WherePredicate, WherePredicateTypeTarget},
     path::GenericArg,
+    type_ref::TraitBoundModifier,
     visibility::RawVisibility,
 };
 
@@ -543,7 +544,13 @@ impl<'a> Printer<'a> {
             }
 
             match bound.as_ref() {
-                TypeBound::Path(path) => self.print_path(path),
+                TypeBound::Path(path, modifier) => {
+                    match modifier {
+                        TraitBoundModifier::None => (),
+                        TraitBoundModifier::Maybe => w!(self, "?"),
+                    }
+                    self.print_path(path)
+                }
                 TypeBound::ForLifetime(lifetimes, path) => {
                     w!(self, "for<{}> ", lifetimes.iter().format(", "));
                     self.print_path(path);
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index cbaa6d086db..a153e17b17a 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -304,7 +304,7 @@ struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {
     field: &'a &'b T,
 }
 
-struct Tuple<T: Copy>(T);
+struct Tuple<T: Copy, U: ?Sized>(T, U);
 
 impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> {
     fn f<G: 'a>(arg: impl Copy) -> impl Copy {}
@@ -325,11 +325,13 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
                 pub(self) field: &'a &'b T,
             }
 
-            pub(self) struct Tuple<T>(
+            pub(self) struct Tuple<T, U>(
                 pub(self) 0: T,
+                pub(self) 1: U,
             )
             where
-                T: Copy;
+                T: Copy,
+                U: ?Sized;
 
             impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K>
             where
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 1d35f02ca1d..9f33fd26e84 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -118,12 +118,20 @@ impl LifetimeRef {
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum TypeBound {
-    Path(Path),
+    Path(Path, TraitBoundModifier),
     ForLifetime(Box<[Name]>, Path),
     Lifetime(LifetimeRef),
     Error,
 }
 
+/// A modifier on a bound, currently this is only used for `?Sized`, where the
+/// modifier is `Maybe`.
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum TraitBoundModifier {
+    None,
+    Maybe,
+}
+
 impl TypeRef {
     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
     pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
@@ -233,7 +241,7 @@ impl TypeRef {
                 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
                     for bound in bounds {
                         match bound.as_ref() {
-                            TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
+                            TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
                                 go_path(path, f)
                             }
                             TypeBound::Lifetime(_) | TypeBound::Error => (),
@@ -265,7 +273,7 @@ impl TypeRef {
                         }
                         for bound in &binding.bounds {
                             match bound.as_ref() {
-                                TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => {
+                                TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
                                     go_path(path, f)
                                 }
                                 TypeBound::Lifetime(_) | TypeBound::Error => (),
@@ -295,7 +303,13 @@ impl TypeBound {
 
         match node.kind() {
             ast::TypeBoundKind::PathType(path_type) => {
-                lower_path_type(path_type).map(TypeBound::Path).unwrap_or(TypeBound::Error)
+                let m = match node.question_mark_token() {
+                    Some(_) => TraitBoundModifier::Maybe,
+                    None => TraitBoundModifier::None,
+                };
+                lower_path_type(path_type)
+                    .map(|p| TypeBound::Path(p, m))
+                    .unwrap_or(TypeBound::Error)
             }
             ast::TypeBoundKind::ForType(for_type) => {
                 let lt_refs = match for_type.generic_param_list() {
@@ -320,9 +334,10 @@ impl TypeBound {
         }
     }
 
-    pub fn as_path(&self) -> Option<&Path> {
+    pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> {
         match self {
-            TypeBound::Path(p) | TypeBound::ForLifetime(_, p) => Some(p),
+            TypeBound::Path(p, m) => Some((p, m)),
+            TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
             TypeBound::Lifetime(_) | TypeBound::Error => None,
         }
     }
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index 267d08d69a6..0be337fc2df 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -14,8 +14,8 @@ use log::{info, warn};
 
 use crate::{
     db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
-    DebruijnIndex, Environment, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution,
-    Ty, TyBuilder, TyKind,
+    ConstrainedSubst, DebruijnIndex, Environment, Guidance, InEnvironment, Interner,
+    ProjectionTyExt, Solution, Substitution, Ty, TyBuilder, TyKind,
 };
 
 const AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
@@ -187,7 +187,8 @@ fn deref_by_trait(
     let solution = db.trait_solve(krate, canonical)?;
 
     match &solution {
-        Solution::Unique(vars) => {
+        Solution::Unique(Canonical { value: ConstrainedSubst { subst, .. }, binders })
+        | Solution::Ambig(Guidance::Definite(Canonical { value: subst, binders })) => {
             // FIXME: vars may contain solutions for any inference variables
             // that happened to be inside ty. To correctly handle these, we
             // would have to pass the solution up to the inference context, but
@@ -203,8 +204,8 @@ fn deref_by_trait(
             // assumptions will be broken. We would need to properly introduce
             // new variables in that case
 
-            for i in 1..vars.binders.len(&Interner) {
-                if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
+            for i in 1..binders.len(&Interner) {
+                if subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
                     != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
                 {
                     warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
@@ -214,13 +215,11 @@ fn deref_by_trait(
             // FIXME: we remove lifetime variables here since they can confuse
             // the method resolution code later
             Some(fixup_lifetime_variables(Canonical {
-                value: vars
-                    .value
-                    .subst
-                    .at(&Interner, vars.value.subst.len(&Interner) - 1)
+                value: subst
+                    .at(&Interner, subst.len(&Interner) - 1)
                     .assert_ty_ref(&Interner)
                     .clone(),
-                binders: vars.binders.clone(),
+                binders: binders.clone(),
             }))
         }
         Solution::Ambig(_) => {
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index a55b99de042..333d934ed37 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -412,13 +412,28 @@ pub(crate) fn associated_ty_data_query(
         .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
     let self_ty =
         TyKind::BoundVar(BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)).intern(&Interner);
-    let bounds = type_alias_data
+    let mut bounds: Vec<_> = type_alias_data
         .bounds
         .iter()
         .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false))
         .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
         .collect();
 
+    if !ctx.unsized_types.borrow().contains(&self_ty) {
+        let sized_trait = resolver
+            .krate()
+            .and_then(|krate| db.lang_item(krate, "sized".into()))
+            .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
+        let sized_bound = sized_trait.into_iter().map(|sized_trait| {
+            let trait_bound =
+                rust_ir::TraitBound { trait_id: sized_trait, args_no_self: Default::default() };
+            let inline_bound = rust_ir::InlineBound::TraitBound(trait_bound);
+            chalk_ir::Binders::empty(&Interner, inline_bound)
+        });
+        bounds.extend(sized_bound);
+        bounds.shrink_to_fit();
+    }
+
     // FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed.
     //        (rust-analyzer#9052)
     // let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 3f7455959d7..91c705afb78 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -4,6 +4,7 @@
 
 use std::fmt::{self, Debug};
 
+use base_db::CrateId;
 use chalk_ir::BoundVar;
 use hir_def::{
     body,
@@ -13,9 +14,9 @@ use hir_def::{
     intern::{Internable, Interned},
     item_scope::ItemInNs,
     path::{Path, PathKind},
-    type_ref::{TypeBound, TypeRef},
+    type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
-    AssocContainerId, Lookup, ModuleId, TraitId,
+    AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use itertools::Itertools;
@@ -376,10 +377,20 @@ impl HirDisplay for Ty {
                 }
 
                 // 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 +400,54 @@ impl HirDisplay for Ty {
                         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 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, ")")?;
@@ -582,7 +614,13 @@ impl HirDisplay for Ty {
                             .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 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(..) => {
@@ -641,7 +679,13 @@ impl HirDisplay for Ty {
                                     _ => 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 +694,7 @@ impl HirDisplay for Ty {
                 write_bounds_like_dyn_trait_with_prefix(
                     "dyn",
                     dyn_ty.bounds.skip_binders().interned(),
+                    SizedByDefault::NotSized,
                     f,
                 )?;
             }
@@ -664,7 +709,13 @@ impl HirDisplay for Ty {
                             .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 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 +764,37 @@ 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, "sized".into()).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 +802,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 +814,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_);
                 }
@@ -808,6 +890,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(())
 }
 
@@ -1026,7 +1115,13 @@ impl HirDisplay for TypeRef {
 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(", "))?;
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index d2e999a730f..0f5859c433f 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -17,8 +17,8 @@ use crate::{
         Adjust, Adjustment, AutoBorrow, InferOk, InferResult, InferenceContext, OverloadedDeref,
         PointerCast, TypeError, TypeMismatch,
     },
-    static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, InEnvironment, Interner, Solution,
-    Substitution, Ty, TyBuilder, TyExt, TyKind,
+    static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner,
+    Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
 };
 
 pub(crate) type CoerceResult = Result<InferOk<(Vec<Adjustment>, Ty)>, TypeError>;
@@ -541,7 +541,7 @@ impl<'a> InferenceContext<'a> {
             _ => return Err(TypeError),
         };
 
-        let trait_ref = {
+        let coerce_unsized_tref = {
             let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
             if b.remaining() != 2 {
                 // The CoerceUnsized trait should have two generic params: Self and T.
@@ -551,7 +551,7 @@ impl<'a> InferenceContext<'a> {
         };
 
         let goal: InEnvironment<DomainGoal> =
-            InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
+            InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(&Interner));
 
         let canonicalized = self.canonicalize(goal);
 
@@ -575,7 +575,9 @@ impl<'a> InferenceContext<'a> {
                     },
                 );
             }
-            // FIXME: should we accept ambiguous results here?
+            Solution::Ambig(Guidance::Definite(subst)) => {
+                canonicalized.apply_solution(&mut self.table, subst)
+            }
             _ => return Err(TypeError),
         };
         let unsize =
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 5ba66fda8f8..8cac285cb19 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -18,13 +18,14 @@ use hir_def::{
     generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
     path::{GenericArg, Path, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
-    type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef},
+    type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
     AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
     GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
     TypeAliasId, TypeParamId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
 use la_arena::ArenaMap;
+use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use stdx::impl_from;
 use syntax::ast;
@@ -65,6 +66,8 @@ pub struct TyLoweringContext<'a> {
     /// Splitting this up would be a possible fix.
     opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
     expander: RefCell<Option<Expander>>,
+    /// Tracks types with explicit `?Sized` bounds.
+    pub(crate) unsized_types: RefCell<FxHashSet<Ty>>,
 }
 
 impl<'a> TyLoweringContext<'a> {
@@ -83,6 +86,7 @@ impl<'a> TyLoweringContext<'a> {
             type_param_mode,
             opaque_type_data,
             expander: RefCell::new(None),
+            unsized_types: RefCell::default(),
         }
     }
 
@@ -93,17 +97,20 @@ impl<'a> TyLoweringContext<'a> {
     ) -> T {
         let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
         let expander = self.expander.replace(None);
+        let unsized_types = self.unsized_types.replace(Default::default());
         let new_ctx = Self {
             in_binders: debruijn,
             impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
             opaque_type_data: RefCell::new(opaque_ty_data_vec),
             expander: RefCell::new(expander),
+            unsized_types: RefCell::new(unsized_types),
             ..*self
         };
         let result = f(&new_ctx);
         self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
         self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
         self.expander.replace(new_ctx.expander.into_inner());
+        self.unsized_types.replace(new_ctx.unsized_types.into_inner());
         result
     }
 
@@ -219,6 +226,10 @@ impl<'a> TyLoweringContext<'a> {
                     ImplTraitLoweringMode::Opaque => {
                         let idx = self.impl_trait_counter.get();
                         self.impl_trait_counter.set(idx + 1);
+                        let func = match self.resolver.generic_def() {
+                            Some(GenericDefId::FunctionId(f)) => f,
+                            _ => panic!("opaque impl trait lowering in non-function"),
+                        };
 
                         assert!(idx as usize == self.opaque_type_data.borrow().len());
                         // this dance is to make sure the data is in the right
@@ -238,14 +249,10 @@ impl<'a> TyLoweringContext<'a> {
                         // away instead of two.
                         let actual_opaque_type_data = self
                             .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
-                                ctx.lower_impl_trait(bounds)
+                                ctx.lower_impl_trait(bounds, func)
                             });
                         self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
 
-                        let func = match self.resolver.generic_def() {
-                            Some(GenericDefId::FunctionId(f)) => f,
-                            _ => panic!("opaque impl trait lowering in non-function"),
-                        };
                         let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
                         let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
                         let generics = generics(self.db.upcast(), func.into());
@@ -776,10 +783,27 @@ impl<'a> TyLoweringContext<'a> {
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
         let mut bindings = None;
         let trait_ref = match bound {
-            TypeBound::Path(path) => {
+            TypeBound::Path(path, TraitBoundModifier::None) => {
                 bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
                 bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
+            TypeBound::Path(path, TraitBoundModifier::Maybe) => {
+                let sized_trait = self
+                    .resolver
+                    .krate()
+                    .and_then(|krate| self.db.lang_item(krate, "sized".into()))
+                    .and_then(|lang_item| lang_item.as_trait());
+                // Don't lower associated type bindings as the only possible relaxed trait bound
+                // `?Sized` has no of them.
+                // If we got another trait here ignore the bound completely.
+                let trait_id = self
+                    .lower_trait_ref_from_path(path, Some(self_ty.clone()))
+                    .map(|trait_ref| trait_ref.hir_trait_id());
+                if trait_id == sized_trait {
+                    self.unsized_types.borrow_mut().insert(self_ty);
+                }
+                None
+            }
             TypeBound::ForLifetime(_, path) => {
                 // FIXME Don't silently drop the hrtb lifetimes here
                 bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
@@ -802,8 +826,12 @@ impl<'a> TyLoweringContext<'a> {
         trait_ref: TraitRef,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
         let last_segment = match bound {
-            TypeBound::Path(path) | TypeBound::ForLifetime(_, path) => path.segments().last(),
-            TypeBound::Error | TypeBound::Lifetime(_) => None,
+            TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
+                path.segments().last()
+            }
+            TypeBound::Path(_, TraitBoundModifier::Maybe)
+            | TypeBound::Error
+            | TypeBound::Lifetime(_) => None,
         };
         last_segment
             .into_iter()
@@ -843,13 +871,39 @@ impl<'a> TyLoweringContext<'a> {
             })
     }
 
-    fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>]) -> ReturnTypeImplTrait {
+    fn lower_impl_trait(
+        &self,
+        bounds: &[Interned<TypeBound>],
+        func: FunctionId,
+    ) -> ReturnTypeImplTrait {
         cov_mark::hit!(lower_rpit);
         let self_ty =
             TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner);
         let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-            bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect()
+            let mut predicates: Vec<_> = bounds
+                .iter()
+                .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
+                .collect();
+
+            if !ctx.unsized_types.borrow().contains(&self_ty) {
+                let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
+                let sized_trait = ctx
+                    .db
+                    .lang_item(krate, "sized".into())
+                    .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
+                let sized_clause = sized_trait.map(|trait_id| {
+                    let clause = WhereClause::Implemented(TraitRef {
+                        trait_id,
+                        substitution: Substitution::from1(&Interner, self_ty.clone()),
+                    });
+                    crate::wrap_empty_binders(clause)
+                });
+                predicates.extend(sized_clause.into_iter());
+                predicates.shrink_to_fit();
+            }
+            predicates
         });
+
         ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
     }
 }
@@ -1008,7 +1062,7 @@ pub(crate) fn trait_environment_query(
                 traits_in_scope
                     .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
             }
-            let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
+            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
             clauses.push(program_clause.into_from_env_clause(&Interner));
         }
     }
@@ -1035,6 +1089,15 @@ pub(crate) fn trait_environment_query(
         clauses.push(program_clause.into_from_env_clause(&Interner));
     }
 
+    let subst = generics(db.upcast(), def).type_params_subst(db);
+    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+    let implicitly_sized_clauses =
+        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| {
+            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
+            program_clause.into_from_env_clause(&Interner)
+        });
+    clauses.extend(implicitly_sized_clauses);
+
     let krate = def.module(db.upcast()).krate();
 
     let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses);
@@ -1051,10 +1114,49 @@ pub(crate) fn generic_predicates_query(
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let generics = generics(db.upcast(), def);
-    resolver
+
+    let mut predicates = resolver
         .where_predicates_in_scope()
         .flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
-        .collect()
+        .collect::<Vec<_>>();
+
+    let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
+    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
+    let implicitly_sized_predicates =
+        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
+            .map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
+    predicates.extend(implicitly_sized_predicates);
+    predicates.into()
+}
+
+/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
+/// Exception is Self of a trait def.
+fn implicitly_sized_clauses<'a>(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+    explicitly_unsized_tys: &'a FxHashSet<Ty>,
+    substitution: &'a Substitution,
+    resolver: &Resolver,
+) -> impl Iterator<Item = WhereClause> + 'a {
+    let is_trait_def = matches!(def, GenericDefId::TraitId(..));
+    let generic_args = &substitution.as_slice(&Interner)[is_trait_def as usize..];
+    let sized_trait = resolver
+        .krate()
+        .and_then(|krate| db.lang_item(krate, "sized".into()))
+        .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
+
+    sized_trait.into_iter().flat_map(move |sized_trait| {
+        let implicitly_sized_tys = generic_args
+            .iter()
+            .filter_map(|generic_arg| generic_arg.ty(&Interner))
+            .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty));
+        implicitly_sized_tys.map(move |self_ty| {
+            WhereClause::Implemented(TraitRef {
+                trait_id: sized_trait,
+                substitution: Substitution::from1(&Interner, self_ty.clone()),
+            })
+        })
+    })
 }
 
 /// Resolve the default type params from generics
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 8db1592c916..4e761a6b474 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -398,15 +398,15 @@ fn test() {
 
 #[test]
 fn coerce_unsize_apit() {
-    // FIXME: #8984
     check(
         r#"
 //- minicore: coerce_unsized
 trait Foo {}
 
-fn test(f: impl Foo) {
+fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
     let _: &dyn Foo = &f;
-                    //^^ expected &dyn Foo, got &impl Foo
+    let _: &dyn Foo = g;
+                    //^ expected &dyn Foo, got &impl Foo + ?Sized
 }
         "#,
     );
@@ -559,3 +559,16 @@ fn test() {
         "#,
     );
 }
+
+#[test]
+fn coerce_type_var() {
+    check_types(
+        r#"
+//- minicore: from, coerce_unsized
+fn test() {
+    let x = ();
+    let _: &() = &x.into();
+}               //^^^^^^^^ ()
+"#,
+    )
+}
diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs
index a484dc3a03b..240942e488d 100644
--- a/crates/hir_ty/src/tests/display_source_code.rs
+++ b/crates/hir_ty/src/tests/display_source_code.rs
@@ -44,13 +44,13 @@ fn main() {
 fn render_raw_ptr_impl_ty() {
     check_types_source_code(
         r#"
-trait Sized {}
+//- minicore: sized
 trait Unpin {}
 fn foo() -> *const (impl Unpin + Sized) { loop {} }
 fn main() {
     let foo = foo();
     foo;
-} //^^^ *const (impl Unpin + Sized)
+} //^^^ *const impl Unpin
 "#,
     );
 }
@@ -67,3 +67,110 @@ fn foo(foo: &dyn for<'a> Foo<'a>) {}
 "#,
     );
 }
+
+#[test]
+fn sized_bounds_apit() {
+    check_types_source_code(
+        r#"
+//- minicore: sized
+trait Foo {}
+trait Bar<T> {}
+struct S<T>;
+fn test(
+    a: impl Foo,
+    b: impl Foo + Sized,
+    c: &(impl Foo + ?Sized),
+    d: S<impl Foo>,
+    ref_any: &impl ?Sized,
+    empty: impl,
+) {
+    a;
+  //^ impl Foo
+    b;
+  //^ impl Foo
+    c;
+  //^ &impl Foo + ?Sized
+    d;
+  //^ S<impl Foo>
+    ref_any;
+  //^^^^^^^ &impl ?Sized
+    empty;
+} //^^^^^ impl Sized
+"#,
+    );
+}
+
+#[test]
+fn sized_bounds_rpit() {
+    check_types_source_code(
+        r#"
+//- minicore: sized
+trait Foo {}
+fn foo1() -> impl Foo { loop {} }
+fn foo2() -> impl Foo + Sized { loop {} }
+fn foo3() -> impl Foo + ?Sized { loop {} }
+fn test() {
+    let foo = foo1();
+    foo;
+  //^^^ impl Foo
+    let foo = foo2();
+    foo;
+  //^^^ impl Foo
+    let foo = foo3();
+    foo;
+} //^^^ impl Foo + ?Sized
+"#,
+    );
+}
+
+#[test]
+fn parenthesize_ptr_rpit_sized_bounds() {
+    check_types_source_code(
+        r#"
+//- minicore: sized
+trait Foo {}
+fn foo1() -> *const impl Foo { loop {} }
+fn foo2() -> *const (impl Foo + Sized) { loop {} }
+fn foo3() -> *const (impl Sized + Foo) { loop {} }
+fn foo4() -> *const (impl Foo + ?Sized) { loop {} }
+fn foo5() -> *const (impl ?Sized + Foo) { loop {} }
+fn test() {
+    let foo = foo1();
+    foo;
+  //^^^ *const impl Foo
+    let foo = foo2();
+    foo;
+  //^^^ *const impl Foo
+    let foo = foo3();
+    foo;
+  //^^^ *const impl Foo
+    let foo = foo4();
+    foo;
+  //^^^ *const (impl Foo + ?Sized)
+    let foo = foo5();
+    foo;
+} //^^^ *const (impl Foo + ?Sized)
+"#,
+    );
+}
+
+#[test]
+fn sized_bounds_impl_traits_in_fn_signature() {
+    check_types_source_code(
+        r#"
+//- minicore: sized
+trait Foo {}
+fn test(
+    a: fn(impl Foo) -> impl Foo,
+    b: fn(impl Foo + Sized) -> impl Foo + Sized,
+    c: fn(&(impl Foo + ?Sized)) -> &(impl Foo + ?Sized),
+) {
+    a;
+  //^ fn(impl Foo) -> impl Foo
+    b;
+  //^ fn(impl Foo) -> impl Foo
+    c;
+} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
+"#,
+    );
+}
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 90eee77422e..0c502273099 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -922,6 +922,7 @@ fn test() { foo.call(); }
 fn super_trait_impl_return_trait_method_resolution() {
     check_infer(
         r#"
+        //- minicore: sized
         trait Base {
             fn foo(self) -> usize;
         }
@@ -1312,3 +1313,29 @@ impl<'a, T> IntoIterator for &'a [T] {
     "#,
     );
 }
+
+#[test]
+fn sized_blanket_impl() {
+    check_infer(
+        r#"
+//- minicore: sized
+trait Foo { fn foo() -> u8; }
+impl<T: Sized> Foo for T {}
+fn f<S: Sized, T, U: ?Sized>() {
+    u32::foo;
+    S::foo;
+    T::foo;
+    U::foo;
+    <[u32]>::foo;
+}
+"#,
+        expect![[r#"
+            89..160 '{     ...foo; }': ()
+            95..103 'u32::foo': fn foo<u32>() -> u8
+            109..115 'S::foo': fn foo<S>() -> u8
+            121..127 'T::foo': fn foo<T>() -> u8
+            133..139 'U::foo': {unknown}
+            145..157 '<[u32]>::foo': {unknown}
+        "#]],
+    );
+}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 58bbaa1c80e..2574dfca320 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -944,7 +944,7 @@ fn lifetime_from_chalk_during_deref() {
         r#"
 //- minicore: deref
 struct Box<T: ?Sized> {}
-impl<T> core::ops::Deref for Box<T> {
+impl<T: ?Sized> core::ops::Deref for Box<T> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -1063,6 +1063,7 @@ fn cfg_tail() {
 fn impl_trait_in_option_9530() {
     check_types(
         r#"
+//- minicore: sized
 struct Option<T>;
 impl<T> Option<T> {
     fn unwrap(self) -> T { loop {} }
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index d5d0173ec11..de1b0e9f298 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -43,7 +43,7 @@ fn test() {
 fn infer_desugar_async() {
     check_types(
         r#"
-//- minicore: future
+//- minicore: future, sized
 async fn foo() -> u64 { 128 }
 
 fn test() {
@@ -147,7 +147,7 @@ mod ops {
     pub use self::try_trait::Try;
 }
 
-mov convert {
+mod convert {
     pub trait From<T> {}
     impl<T> From<T> for T {}
 }
@@ -567,8 +567,8 @@ fn deref_trait() {
     check_types(
         r#"
 //- minicore: deref
-struct Arc<T>;
-impl<T> core::ops::Deref for Arc<T> {
+struct Arc<T: ?Sized>;
+impl<T: ?Sized> core::ops::Deref for Arc<T> {
     type Target = T;
 }
 
@@ -589,9 +589,9 @@ fn deref_trait_with_inference_var() {
     check_types(
         r#"
 //- minicore: deref
-struct Arc<T>;
-fn new_arc<T>() -> Arc<T> { Arc }
-impl<T> core::ops::Deref for Arc<T> {
+struct Arc<T: ?Sized>;
+fn new_arc<T: ?Sized>() -> Arc<T> { Arc }
+impl<T: ?Sized> core::ops::Deref for Arc<T> {
     type Target = T;
 }
 
@@ -631,7 +631,7 @@ fn deref_trait_with_question_mark_size() {
     check_types(
         r#"
 //- minicore: deref
-struct Arc<T>;
+struct Arc<T: ?Sized>;
 impl<T: ?Sized> core::ops::Deref for Arc<T> {
     type Target = T;
 }
@@ -649,6 +649,25 @@ fn test(s: Arc<S>) {
 }
 
 #[test]
+fn deref_trait_with_implicit_sized_requirement_on_inference_var() {
+    check_types(
+        r#"
+//- minicore: deref
+struct Foo<T>;
+impl<T> core::ops::Deref for Foo<T> {
+    type Target = ();
+}
+fn test() {
+    let foo = Foo;
+    *foo;
+  //^^^^ ()
+    let _: Foo<u8> = foo;
+}
+"#,
+    )
+}
+
+#[test]
 fn obligation_from_function_clause() {
     check_types(
         r#"
@@ -845,6 +864,7 @@ fn test<T: ApplyL>(t: T) {
 fn argument_impl_trait() {
     check_infer_with_mismatches(
         r#"
+//- minicore: sized
 trait Trait<T> {
     fn foo(&self) -> T;
     fn foo2(&self) -> i64;
@@ -902,6 +922,7 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
 fn argument_impl_trait_type_args_1() {
     check_infer_with_mismatches(
         r#"
+//- minicore: sized
 trait Trait {}
 trait Foo {
     // this function has an implicit Self param, an explicit type param,
@@ -967,6 +988,7 @@ fn test() {
 fn argument_impl_trait_type_args_2() {
     check_infer_with_mismatches(
         r#"
+//- minicore: sized
 trait Trait {}
 struct S;
 impl Trait for S {}
@@ -1008,6 +1030,7 @@ fn test() {
 fn argument_impl_trait_to_fn_pointer() {
     check_infer_with_mismatches(
         r#"
+//- minicore: sized
 trait Trait {}
 fn foo(x: impl Trait) { loop {} }
 struct S;
@@ -1032,6 +1055,7 @@ fn test() {
 fn impl_trait() {
     check_infer(
         r#"
+//- minicore: sized
 trait Trait<T> {
     fn foo(&self) -> T;
     fn foo2(&self) -> i64;
@@ -1082,6 +1106,7 @@ fn simple_return_pos_impl_trait() {
     cov_mark::check!(lower_rpit);
     check_infer(
         r#"
+//- minicore: sized
 trait Trait<T> {
     fn foo(&self) -> T;
 }
@@ -1110,6 +1135,7 @@ fn test() {
 fn more_return_pos_impl_trait() {
     check_infer(
         r#"
+//- minicore: sized
 trait Iterator {
     type Item;
     fn next(&mut self) -> Self::Item;
@@ -1168,6 +1194,7 @@ fn test() {
 fn dyn_trait() {
     check_infer(
         r#"
+//- minicore: sized
 trait Trait<T> {
     fn foo(&self) -> T;
     fn foo2(&self) -> i64;
@@ -1217,6 +1244,7 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
 fn dyn_trait_in_impl() {
     check_infer(
         r#"
+//- minicore: sized
 trait Trait<T, U> {
     fn foo(&self) -> (T, U);
 }
@@ -1252,6 +1280,7 @@ fn test(s: S<u32, i32>) {
 fn dyn_trait_bare() {
     check_infer(
         r#"
+//- minicore: sized
 trait Trait {
     fn foo(&self) -> u64;
 }
@@ -1290,6 +1319,7 @@ fn test(x: Trait, y: &Trait) -> u64 {
 fn weird_bounds() {
     check_infer(
         r#"
+//- minicore: sized
 trait Trait {}
 fn test(
     a: impl Trait + 'lifetime,
@@ -1302,11 +1332,11 @@ fn test(
 "#,
         expect![[r#"
             28..29 'a': impl Trait
-            59..60 'b': impl
+            59..60 'b': impl Sized
             82..83 'c': impl Trait
-            103..104 'd': impl
-            128..129 'e': impl
-            148..149 'f': impl Trait
+            103..104 'd': impl Sized
+            128..129 'e': impl ?Sized
+            148..149 'f': impl Trait + ?Sized
             173..175 '{}': ()
         "#]],
     );
@@ -1331,6 +1361,7 @@ fn test(x: (impl Trait + UnknownTrait)) {
 fn assoc_type_bindings() {
     check_infer(
         r#"
+//- minicore: sized
 trait Trait {
     type Type;
 }
@@ -1495,6 +1526,7 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
 fn super_trait_impl_trait_method_resolution() {
     check_infer(
         r#"
+//- minicore: sized
 mod foo {
     trait SuperTrait {
         fn foo(&self) -> u32 {}
@@ -2299,6 +2331,7 @@ impl TokenStream for Rustc {
 fn unify_impl_trait() {
     check_infer_with_mismatches(
         r#"
+//- minicore: sized
 trait Trait<T> {}
 
 fn foo(x: impl Trait<u32>) { loop {} }
@@ -2417,8 +2450,8 @@ fn dyn_trait_through_chalk() {
     check_types(
         r#"
 //- minicore: deref
-struct Box<T> {}
-impl<T> core::ops::Deref for Box<T> {
+struct Box<T: ?Sized> {}
+impl<T: ?Sized> core::ops::Deref for Box<T> {
     type Target = T;
 }
 trait Trait {
@@ -3515,3 +3548,33 @@ fn test() {
 "#,
     );
 }
+
+#[test]
+fn associated_type_sized_bounds() {
+    check_infer(
+        r#"
+//- minicore: sized
+struct Yes;
+trait IsSized { const IS_SIZED: Yes; }
+impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
+
+trait Foo {
+    type Explicit: Sized;
+    type Implicit;
+    type Relaxed: ?Sized;
+}
+fn f<F: Foo>() {
+    F::Explicit::IS_SIZED;
+    F::Implicit::IS_SIZED;
+    F::Relaxed::IS_SIZED;
+}
+"#,
+        expect![[r#"
+            104..107 'Yes': Yes
+            212..295 '{     ...ZED; }': ()
+            218..239 'F::Exp..._SIZED': Yes
+            245..266 'F::Imp..._SIZED': Yes
+            272..292 'F::Rel..._SIZED': {unknown}
+        "#]],
+    );
+}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 076b2c8cba3..14b8a726a8f 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -13,7 +13,7 @@ use hir_def::{
     intern::Interned,
     path::Path,
     resolver::{HasResolver, TypeNs},
-    type_ref::TypeRef,
+    type_ref::{TraitBoundModifier, TypeRef},
     AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
 };
 use hir_expand::name::{name, Name};
@@ -58,6 +58,10 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
             },
             WherePredicate::Lifetime { .. } => None,
         })
+        .filter_map(|(path, bound_modifier)| match bound_modifier {
+            TraitBoundModifier::None => Some(path),
+            TraitBoundModifier::Maybe => None,
+        })
         .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
             Some(TypeNs::TraitId(t)) => Some(t),
             _ => None,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index da023419ccf..f11eaaa546d 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1226,7 +1226,9 @@ fn main() {
     #[test]
     fn hover_for_param_with_multiple_traits() {
         check(
-            r#"trait Deref {
+            r#"
+            //- minicore: sized
+            trait Deref {
                 type Target: ?Sized;
             }
             trait DerefMut {
@@ -3417,17 +3419,17 @@ fn foo() {
     fn hover_type_param() {
         check(
             r#"
+//- minicore: sized
 struct Foo<T>(T);
 trait Copy {}
 trait Clone {}
-trait Sized {}
 impl<T: Copy + Clone> Foo<T$0> where T: Sized {}
 "#,
             expect![[r#"
                 *T*
 
                 ```rust
-                T: Copy + Clone + Sized
+                T: Copy + Clone
                 ```
             "#]],
         );
@@ -3461,6 +3463,26 @@ impl<T: 'static> Foo<T$0> {}
     }
 
     #[test]
+    fn hover_type_param_not_sized() {
+        check(
+            r#"
+//- minicore: sized
+struct Foo<T>(T);
+trait Copy {}
+trait Clone {}
+impl<T: Copy + Clone> Foo<T$0> where T: ?Sized {}
+"#,
+            expect![[r#"
+                *T*
+
+                ```rust
+                T: Copy + Clone + ?Sized
+                ```
+            "#]],
+        );
+    }
+
+    #[test]
     fn hover_const_param() {
         check(
             r#"
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 3dc1bbf7dca..e3d63cc949e 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -924,9 +924,53 @@ fn main() {
     let foo = foo5();
      // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
     let foo = foo6();
-     // ^^^ impl Fn(f64, f64) -> u32 + Sized
+     // ^^^ impl Fn(f64, f64) -> u32
+    let foo = foo7();
+     // ^^^ *const impl Fn(f64, f64) -> u32
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn fn_hints_ptr_rpit_fn_parentheses() {
+        check_types(
+            r#"
+//- minicore: fn, sized
+trait Trait {}
+
+fn foo1() -> *const impl Fn() { loop {} }
+fn foo2() -> *const (impl Fn() + Sized) { loop {} }
+fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
+fn foo4() -> *const (impl Sized + Fn()) { loop {} }
+fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
+fn foo6() -> *const (impl Fn() + Trait) { loop {} }
+fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
+fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
+fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
+fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
+
+fn main() {
+    let foo = foo1();
+    //  ^^^ *const impl Fn()
+    let foo = foo2();
+    //  ^^^ *const impl Fn()
+    let foo = foo3();
+    //  ^^^ *const (impl Fn() + ?Sized)
+    let foo = foo4();
+    //  ^^^ *const impl Fn()
+    let foo = foo5();
+    //  ^^^ *const (impl Fn() + ?Sized)
+    let foo = foo6();
+    //  ^^^ *const (impl Fn() + Trait)
     let foo = foo7();
-     // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
+    //  ^^^ *const (impl Fn() + Trait)
+    let foo = foo8();
+    //  ^^^ *const (impl Fn() + Trait + ?Sized)
+    let foo = foo9();
+    //  ^^^ *const (impl Fn() -> u8 + ?Sized)
+    let foo = foo10();
+    //  ^^^ *const impl Fn()
 }
 "#,
         )
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 7b8514efe52..63503392cbd 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -937,7 +937,8 @@ fn bar(worble: ()) ${0:-> ()} {
     fn add_function_with_impl_trait_arg() {
         check_assist(
             generate_function,
-            r"
+            r#"
+//- minicore: sized
 trait Foo {}
 fn foo() -> impl Foo {
     todo!()
@@ -945,8 +946,8 @@ fn foo() -> impl Foo {
 fn baz() {
     $0bar(foo())
 }
-",
-            r"
+"#,
+            r#"
 trait Foo {}
 fn foo() -> impl Foo {
     todo!()
@@ -958,7 +959,7 @@ fn baz() {
 fn bar(foo: impl Foo) ${0:-> ()} {
     todo!()
 }
-",
+"#,
         )
     }