Repository: intellij-rust/intellij-rust
Issue: Generate constructor looses dyn

<!--
Hello and thank you for the issue!
If you would like to report a bug, we have added some points below that you can fill out.
Feel free to remove all the irrelevant text to request a new feature.
-->

## Environment

* **IntelliJ Rust plugin version:**  0.2.121.3059-201-stable
* **Rust toolchain version:** 1.44.0-nightly (b2e36e6c2 2020-04-22)
* **IDE name and version:** CLion 2020.1
* **Operating system:** Windows 10

## Problem description

When using "generate constructor", each `dyn Trait` gets stripped of dyn (and any further traits).

## Steps to reproduce

<!--
Please include as much of your codebase as needed to reproduce the error.
If the relevant files are large, please provide a link to a public repository or a [Gist](https://gist.github.com/).
-->

```rust
struct Widget {
    test: Box<dyn Display + Send>,
}

impl Widget {
    // notice the invalid type in the generated constructor
    pub fn new(test: Box<Display>) -> Self {
        Widget { test }
    }
}
```

Changed files:
src/main/kotlin/org/rust/lang/core/types/ty/TyAnon.kt
src/main/kotlin/org/rust/lang/core/types/ty/TyProjection.kt
src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt
src/main/kotlin/org/rust/lang/core/types/Kind.kt
src/test/kotlin/org/rust/ide/hints/RsExpressionTypeProviderTest.kt
src/main/kotlin/org/rust/ide/inspections/import/RsImportHelper.kt
src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt
src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt
src/main/kotlin/org/rust/ide/hints/RsTypeHintsPresentationFactory.kt
src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
src/main/kotlin/org/rust/lang/core/types/ty/Ty.kt
src/main/kotlin/org/rust/lang/core/types/ty/TyTraitObject.kt
src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt
src/main/kotlin/org/rust/ide/navigation/goto/RsTypeDeclarationProvider.kt
src/main/kotlin/org/rust/lang/core/types/infer/Declarations.kt
src/main/kotlin/org/rust/ide/refactoring/RsNameSuggestions.kt

diff --git a/src/main/kotlin/org/rust/ide/hints/RsTypeHintsPresentationFactory.kt b/src/main/kotlin/org/rust/ide/hints/RsTypeHintsPresentationFactory.kt
index 5ed94d9eb..e02bf1ef1 100644
--- a/src/main/kotlin/org/rust/ide/hints/RsTypeHintsPresentationFactory.kt
+++ b/src/main/kotlin/org/rust/ide/hints/RsTypeHintsPresentationFactory.kt
@@ -187,7 +187,7 @@ class RsTypeHintsPresentationFactory(private val factory: PresentationFactory, p
         factory.collapsible(
             prefix = text("dyn "),
             collapsed = text(PLACEHOLDER),
-            expanded = { traitItemTypeHint(type.trait, level, true) },
+            expanded = { type.traits.map { traitItemTypeHint(it, level + 1, true) }.join("+") },
             suffix = text(""),
             startWithPlaceholder = checkSize(level, 1)
         )
diff --git a/src/main/kotlin/org/rust/ide/inspections/import/RsImportHelper.kt b/src/main/kotlin/org/rust/ide/inspections/import/RsImportHelper.kt
index 1834996d2..8ed3081a9 100644
--- a/src/main/kotlin/org/rust/ide/inspections/import/RsImportHelper.kt
+++ b/src/main/kotlin/org/rust/ide/inspections/import/RsImportHelper.kt
@@ -116,7 +116,7 @@ object RsImportHelper {
                         }
                     }
                     is TyAnon -> result += ty.traits.map { it.element }
-                    is TyTraitObject -> result += ty.trait.element
+                    is TyTraitObject -> result += ty.traits.map { it.element }
                     is TyProjection -> {
                         result += ty.trait.element
                         result += ty.target
diff --git a/src/main/kotlin/org/rust/ide/navigation/goto/RsTypeDeclarationProvider.kt b/src/main/kotlin/org/rust/ide/navigation/goto/RsTypeDeclarationProvider.kt
index 9fdd396a5..c35f08580 100644
--- a/src/main/kotlin/org/rust/ide/navigation/goto/RsTypeDeclarationProvider.kt
+++ b/src/main/kotlin/org/rust/ide/navigation/goto/RsTypeDeclarationProvider.kt
@@ -38,7 +38,7 @@ class RsTypeDeclarationProvider : TypeDeclarationProvider {
     private tailrec fun Ty.baseTypeDeclaration(): RsElement? {
         return when (this) {
             is TyAdt -> item
-            is TyTraitObject -> trait.element
+            is TyTraitObject -> traits.firstOrNull()?.element
             is TyTypeParameter -> {
                 when (parameter) {
                     is TyTypeParameter.Named -> parameter.parameter
diff --git a/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt b/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
index eccf7576c..a29044382 100644
--- a/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
+++ b/src/main/kotlin/org/rust/ide/presentation/TypeRendering.kt
@@ -5,7 +5,6 @@
 
 package org.rust.ide.presentation
 
-import org.jetbrains.annotations.TestOnly
 import org.rust.lang.core.psi.RsTraitItem
 import org.rust.lang.core.psi.ext.*
 import org.rust.lang.core.types.BoundElement
@@ -124,7 +123,7 @@ private data class TypeRenderer(
                 }
                 append(ty.target.name)
             }
-            is TyTraitObject -> formatTrait(ty.trait, render)
+            is TyTraitObject -> ty.traits.joinToString("+", "dyn ") { formatTrait(it, render) }
             is TyAnon -> ty.traits.joinToString("+", "impl ") { formatTrait(it, render) }
             is TyAdt -> buildString {
                 if (useAliasNames && ty.aliasedBy != null) {
diff --git a/src/main/kotlin/org/rust/ide/refactoring/RsNameSuggestions.kt b/src/main/kotlin/org/rust/ide/refactoring/RsNameSuggestions.kt
index 979cec6e6..72ec20835 100644
--- a/src/main/kotlin/org/rust/ide/refactoring/RsNameSuggestions.kt
+++ b/src/main/kotlin/org/rust/ide/refactoring/RsNameSuggestions.kt
@@ -55,7 +55,7 @@ fun RsExpr.suggestedNames(): SuggestedNames {
         is TyInteger -> names.addName("i")
         is TyTypeParameter -> names.addName(type.name)
         is TyAdt -> names.addName(type.item.name)
-        is TyTraitObject -> names.addName(type.trait.element.name)
+        is TyTraitObject -> type.traits.forEach { names.addName(it.element.name) }
     }
 
     val parent = this.parent
diff --git a/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt b/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
index 3c0ed65f7..d1343975a 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
@@ -306,7 +306,7 @@ class ImplLookup(
         val implsAndTraits = mutableListOf<TraitImplSource>()
         when (ty) {
             is TyTraitObject -> {
-                ty.trait.flattenHierarchy.mapTo(implsAndTraits) { TraitImplSource.Object(it.element) }
+                ty.getTraitBoundsTransitively().mapTo(implsAndTraits) { TraitImplSource.Object(it.element) }
                 findExplicitImpls(ty) { implsAndTraits += TraitImplSource.ExplicitImpl(it); false }
             }
             is TyFunction -> {
@@ -656,7 +656,7 @@ class ImplLookup(
                 addAll(assembleDerivedCandidates(ref))
                 if (ref.selfTy is TyFunction && element in fnTraits) add(SelectionCandidate.Closure)
                 if (ref.selfTy is TyTraitObject) {
-                    ref.selfTy.trait.flattenHierarchy.find { it.element == ref.trait.element }
+                    ref.selfTy.getTraitBoundsTransitively().find { it.element == ref.trait.element }
                         ?.let { add(SelectionCandidate.TraitObject) }
                 }
                 getHardcodedImpls(ref.selfTy).filter { be ->
@@ -761,7 +761,7 @@ class ImplLookup(
             }
             SelectionCandidate.TraitObject -> {
                 val traits = when (ref.selfTy) {
-                    is TyTraitObject -> ref.selfTy.trait.flattenHierarchy
+                    is TyTraitObject -> ref.selfTy.getTraitBoundsTransitively()
                     is TyAnon -> ref.selfTy.getTraitBoundsTransitively()
                     else -> error("unreachable")
                 }
@@ -874,7 +874,7 @@ class ImplLookup(
     private fun lookupAssociatedType(selfTy: Ty, res: Selection, assocType: RsTypeAlias): Ty? {
         return when (selfTy) {
             is TyTypeParameter -> lookupAssocTypeInBounds(getEnvBoundTransitivelyFor(selfTy), res.impl, assocType)
-            is TyTraitObject -> selfTy.trait.assoc[assocType]
+            is TyTraitObject -> lookupAssocTypeInBounds(selfTy.getTraitBoundsTransitively().asSequence(), res.impl, assocType)
             else -> {
                 lookupAssocTypeInSelection(res, assocType)
                     ?: lookupAssocTypeInBounds(getHardcodedImpls(selfTy).asSequence(), res.impl, assocType)
diff --git a/src/main/kotlin/org/rust/lang/core/types/Kind.kt b/src/main/kotlin/org/rust/lang/core/types/Kind.kt
index d40d0f9c4..a6057b997 100644
--- a/src/main/kotlin/org/rust/lang/core/types/Kind.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/Kind.kt
@@ -22,7 +22,11 @@ interface Kind {
     val flags: TypeFlags
 }
 
-fun mergeFlags(kinds: Collection<Kind>): TypeFlags = kinds.fold(0) { a, b -> a or b.flags }
+fun mergeFlags(kinds: Collection<Kind>): TypeFlags =
+    kinds.fold(0) { a, b -> a or b.flags }
 
-fun mergeFlags(element: BoundElement<*>): TypeFlags =
+fun mergeElementFlags(element: BoundElement<*>): TypeFlags =
     mergeFlags(element.subst.kinds) or mergeFlags(element.assoc.values)
+
+fun mergeElementFlags(elements: Collection<BoundElement<*>>): TypeFlags =
+    elements.fold(0) { acc, element -> acc or mergeElementFlags(element) }
\\ No newline at end of file
diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/Declarations.kt b/src/main/kotlin/org/rust/lang/core/types/infer/Declarations.kt
index 1a7ba82f8..c33fcbf57 100644
--- a/src/main/kotlin/org/rust/lang/core/types/infer/Declarations.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/infer/Declarations.kt
@@ -53,7 +53,7 @@ fun inferTypeReferenceType(type: RsTypeReference, defaultTraitObjectRegion: Regi
                         }
                     }
                     target is RsTraitItem -> {
-                        TyTraitObject(boundElement.downcast()!!, defaultTraitObjectRegion ?: ReUnknown)
+                        TyTraitObject(listOfNotNull(boundElement.downcast()), defaultTraitObjectRegion ?: ReUnknown)
                     }
                     target is RsTypeDeclarationElement -> {
                         val ty = target.declaredType
@@ -102,15 +102,11 @@ fun inferTypeReferenceType(type: RsTypeReference, defaultTraitObjectRegion: Regi
 
         is RsTraitType -> {
             val traitBounds = type.polyboundList.mapNotNull { it.bound.traitRef?.resolveToBoundTrait() }
+            if (type.isImpl) return TyAnon(type, traitBounds)
+            if (traitBounds.isEmpty()) return TyUnknown
             val lifetimeBounds = type.polyboundList.mapNotNull { it.bound.lifetime }
-            if (type.isImpl) {
-                TyAnon(type, traitBounds)
-            } else {  // TODO: use all bounds
-                TyTraitObject(
-                    traitBounds.firstOrNull() ?: return TyUnknown,
-                    lifetimeBounds.firstOrNull()?.resolve() ?: defaultTraitObjectRegion ?: ReStatic
-                )
-            }
+            val regionBound = lifetimeBounds.firstOrNull()?.resolve() ?: defaultTraitObjectRegion ?: ReStatic
+            TyTraitObject(traitBounds, regionBound)
         }
 
         else -> TyUnknown
@@ -152,6 +148,6 @@ private fun <T : TypeFoldable<T>> TypeFoldable<T>.substituteWithTraitObjectRegio
             1 -> bounds.single().substitute(subst)
             else -> ReUnknown
         }
-        return TyTraitObject(ty.trait, region)
+        return TyTraitObject(ty.traits, region)
     }
 }).tryEvaluate()
diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt
index ae390bd54..13fc457c3 100644
--- a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt
@@ -478,7 +478,9 @@ class RsInferenceContext(
                 combineTypePairs(ty1.typeArguments.zip(ty2.typeArguments))
                     .and { combineConstPairs(ty1.constArguments.zip(ty2.constArguments)) }
             }
-            ty1 is TyTraitObject && ty2 is TyTraitObject && combineBoundElements(ty1.trait, ty2.trait) -> CoerceResult.Ok
+            ty1 is TyTraitObject && ty2 is TyTraitObject &&
+                // TODO: Use all trait bounds
+                combineBoundElements(ty1.traits.first(), ty2.traits.first()) -> CoerceResult.Ok
             ty1 is TyAnon && ty2 is TyAnon && ty1.definition != null && ty1.definition == ty2.definition -> CoerceResult.Ok
             ty1 is TyNever || ty2 is TyNever -> CoerceResult.Ok
             else -> CoerceResult.TypeMismatch(ty1, ty2)
@@ -849,7 +851,7 @@ class RsInferenceContext(
         is TraitImplSource.Object -> when (val selfTy = callee.selfTy) {
             is TyAnon -> selfTy.getTraitBoundsTransitively()
                 .find { it.element == source.value }?.subst ?: emptySubstitution
-            is TyTraitObject -> selfTy.trait.flattenHierarchy
+            is TyTraitObject -> selfTy.getTraitBoundsTransitively()
                 .find { it.element == source.value }?.subst ?: emptySubstitution
             else -> emptySubstitution
         }
diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt
index 71ac384dc..6173a08b1 100644
--- a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInferenceWalker.kt
@@ -1245,7 +1245,7 @@ class RsTypeInferenceWalker(
                     .find { it.trait.selfTy == expected && it.trait.trait.element in listOf(items.Fn, items.FnMut, items.FnOnce) }
                     ?.let { lookup.asTyFunction(it.trait.trait) }
             }
-            is TyTraitObject -> lookup.asTyFunction(expected.trait)
+            is TyTraitObject -> lookup.asTyFunction(expected.traits.first()) // TODO: Use all trait bounds
             is TyFunction -> expected
             is TyAnon -> {
                 val trait = expected.traits.find { it.element in listOf(items.Fn, items.FnMut, items.FnOnce) }
diff --git a/src/main/kotlin/org/rust/lang/core/types/ty/Ty.kt b/src/main/kotlin/org/rust/lang/core/types/ty/Ty.kt
index 584f9b3ba..b6238a560 100644
--- a/src/main/kotlin/org/rust/lang/core/types/ty/Ty.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/ty/Ty.kt
@@ -135,7 +135,7 @@ private fun pushSubTypes(stack: Deque<Ty>, parentTy: Ty) {
     when (parentTy) {
         is TyAdt ->
             parentTy.typeArguments.asReversed().forEach(stack::push)
-        is TyAnon, is TyProjection ->
+        is TyAnon, is TyTraitObject, is TyProjection ->
             parentTy.typeParameterValues.types.reversed().forEach(stack::push)
         is TyArray ->
             stack.push(parentTy.base)
@@ -145,8 +145,6 @@ private fun pushSubTypes(stack: Deque<Ty>, parentTy: Ty) {
             stack.push(parentTy.referenced)
         is TySlice ->
             stack.push(parentTy.elementType)
-        is TyTraitObject ->
-            parentTy.trait.subst.types.reversed().forEach(stack::push)
         is TyTuple ->
             parentTy.types.asReversed().forEach(stack::push)
         is TyFunction -> {
diff --git a/src/main/kotlin/org/rust/lang/core/types/ty/TyAnon.kt b/src/main/kotlin/org/rust/lang/core/types/ty/TyAnon.kt
index efd78fca6..4a548ca37 100644
--- a/src/main/kotlin/org/rust/lang/core/types/ty/TyAnon.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/ty/TyAnon.kt
@@ -12,7 +12,7 @@ import org.rust.lang.core.psi.ext.isImpl
 import org.rust.lang.core.types.BoundElement
 import org.rust.lang.core.types.infer.TypeFolder
 import org.rust.lang.core.types.infer.TypeVisitor
-import org.rust.lang.core.types.mergeFlags
+import org.rust.lang.core.types.mergeElementFlags
 
 /**
  * Represents "impl Trait".
@@ -20,7 +20,7 @@ import org.rust.lang.core.types.mergeFlags
 data class TyAnon(
     val definition: RsTraitType?,
     val traits: List<BoundElement<RsTraitItem>>
-) : Ty(traits.fold(0) { acc, trait -> acc or mergeFlags(trait) }) {
+) : Ty(mergeElementFlags(traits)) {
 
     init {
         require(definition == null || definition.isImpl) {
diff --git a/src/main/kotlin/org/rust/lang/core/types/ty/TyProjection.kt b/src/main/kotlin/org/rust/lang/core/types/ty/TyProjection.kt
index 03233ad4f..91d840cf3 100644
--- a/src/main/kotlin/org/rust/lang/core/types/ty/TyProjection.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/ty/TyProjection.kt
@@ -15,7 +15,7 @@ import org.rust.lang.core.types.HAS_TY_PROJECTION_MASK
 import org.rust.lang.core.types.TraitRef
 import org.rust.lang.core.types.infer.TypeFolder
 import org.rust.lang.core.types.infer.TypeVisitor
-import org.rust.lang.core.types.mergeFlags
+import org.rust.lang.core.types.mergeElementFlags
 
 /**
  * Represents projection of an associated type.
@@ -39,7 +39,7 @@ data class TyProjection private constructor(
     val type: Ty,
     val trait: BoundElement<RsTraitItem>,
     val target: RsTypeAlias
-): Ty(type.flags or mergeFlags(trait) or HAS_TY_PROJECTION_MASK) {
+): Ty(type.flags or mergeElementFlags(trait) or HAS_TY_PROJECTION_MASK) {
 
     /**
      * Extracts the underlying trait reference from this projection.
diff --git a/src/main/kotlin/org/rust/lang/core/types/ty/TyTraitObject.kt b/src/main/kotlin/org/rust/lang/core/types/ty/TyTraitObject.kt
index 02ec29769..628255b38 100644
--- a/src/main/kotlin/org/rust/lang/core/types/ty/TyTraitObject.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/ty/TyTraitObject.kt
@@ -7,13 +7,15 @@ package org.rust.lang.core.types.ty
 
 import com.intellij.codeInsight.completion.CompletionUtil
 import org.rust.lang.core.psi.RsTraitItem
+import org.rust.lang.core.psi.ext.flattenHierarchy
 import org.rust.lang.core.psi.ext.typeParameters
 import org.rust.lang.core.psi.ext.withDefaultSubst
 import org.rust.lang.core.types.BoundElement
 import org.rust.lang.core.types.Substitution
+import org.rust.lang.core.types.emptySubstitution
 import org.rust.lang.core.types.infer.TypeFolder
 import org.rust.lang.core.types.infer.TypeVisitor
-import org.rust.lang.core.types.mergeFlags
+import org.rust.lang.core.types.mergeElementFlags
 import org.rust.lang.core.types.regions.ReUnknown
 import org.rust.lang.core.types.regions.Region
 
@@ -23,36 +25,45 @@ import org.rust.lang.core.types.regions.Region
  * only the latter are ty.
  */
 class TyTraitObject(
-    val trait: BoundElement<RsTraitItem>,
+    val traits: List<BoundElement<RsTraitItem>>,
     val region: Region = ReUnknown
-) : Ty(mergeFlags(trait) or region.flags) {
+) : Ty(mergeElementFlags(traits) or region.flags) {
+
+    init {
+        require(traits.isNotEmpty()) {
+            "Can't construct TyTraitObject from empty list of trait bounds"
+        }
+    }
 
     val typeArguments: List<Ty>
-        get() = trait.element.typeParameters.map { typeParameterValues[it] ?: TyUnknown }
+        get() = traits.flatMap { it.element.typeParameters }.map { typeParameterValues[it] ?: TyUnknown }
 
     override val typeParameterValues: Substitution
-        get() = trait.subst
+        get() = traits.map { it.subst }.fold(emptySubstitution) { a, b -> a + b }
 
     override fun superFoldWith(folder: TypeFolder): TyTraitObject =
-        TyTraitObject(trait.foldWith(folder), region.foldWith(folder))
+        TyTraitObject(traits.map { it.foldWith(folder) }, region.foldWith(folder))
 
     override fun superVisitWith(visitor: TypeVisitor): Boolean =
-        trait.visitWith(visitor) || region.visitWith(visitor)
+        traits.any { it.visitWith(visitor) } || region.visitWith(visitor)
+
+    fun getTraitBoundsTransitively(): Collection<BoundElement<RsTraitItem>> =
+        traits.flatMap { it.flattenHierarchy }
 
     override fun equals(other: Any?): Boolean = when {
         this === other -> true
         javaClass != other?.javaClass -> false
         other !is TyTraitObject -> false
-        trait != other.trait -> false
+        traits != other.traits -> false
         else -> true
     }
 
-    override fun hashCode(): Int = trait.hashCode()
+    override fun hashCode(): Int = traits.hashCode()
 
     companion object {
         fun valueOf(trait: RsTraitItem): TyTraitObject {
             val item = CompletionUtil.getOriginalOrSelf(trait)
-            return TyTraitObject(item.withDefaultSubst())
+            return TyTraitObject(listOf(item.withDefaultSubst()))
         }
     }
 }
diff --git a/src/test/kotlin/org/rust/ide/hints/RsExpressionTypeProviderTest.kt b/src/test/kotlin/org/rust/ide/hints/RsExpressionTypeProviderTest.kt
index a53a78777..d560b4fe3 100644
--- a/src/test/kotlin/org/rust/ide/hints/RsExpressionTypeProviderTest.kt
+++ b/src/test/kotlin/org/rust/ide/hints/RsExpressionTypeProviderTest.kt
@@ -44,20 +44,20 @@ class RsExpressionTypeProviderTest : RsTestBase() {
             type Item = ();
         }
 
-        fn foo(c: Trait<Item=u32>) {
+        fn foo(c: dyn Trait<Item=u32>) {
             let /*caret*/b = c;
         }
-    """, "Trait<Item=u32>")
+    """, "dyn Trait<Item=u32>")
 
     fun `test associated generic type`() = doTest("""
         trait Trait {
             type Item = ();
         }
 
-        fn foo<T>(c: Trait<Item=T>) {
+        fn foo<T>(c: dyn Trait<Item=T>) {
             let /*caret*/b = c;
         }
-    """, "Trait<Item=T>")
+    """, "dyn Trait<Item=T>")
 
     fun `test aliased type`() = doTest("""
         struct S<T> { t: T }
diff --git a/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt b/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt
index dbeeafd21..e2e3cbe22 100644
--- a/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt
+++ b/src/test/kotlin/org/rust/ide/refactoring/implementMembers/ImplementMembersHandlerTest.kt
@@ -1065,26 +1065,52 @@ class ImplementMembersHandlerTest : RsTestBase() {
         }
     """)
 
+    fun `test trait object type`() = doTest("""
+        struct Foo;
+        trait A {}
+        trait B {}
+        trait Bar {
+            fn bar(&self) -> &dyn A + B;
+        }
+
+        impl Bar for Foo {
+            /*caret*/
+        }
+    """, listOf(ImplementMemberSelection("bar(&self) -> &dyn A + B", true, isSelected = true)), """
+        struct Foo;
+        trait A {}
+        trait B {}
+        trait Bar {
+            fn bar(&self) -> &dyn A + B;
+        }
+
+        impl Bar for Foo {
+            fn bar(&self) -> &dyn A + B {
+                unimplemented!()
+            }
+        }
+    """)
+
     @ProjectDescriptor(WithStdlibRustProjectDescriptor::class)
     fun `test Fn type`() = doTest("""
         struct Foo;
         struct Bar;
         trait Baz {
-            fn baz(&self) -> Box<Fn(i32, i32) -> i32>;
+            fn baz(&self) -> Box<dyn Fn(i32, i32) -> i32>;
         }
 
         impl Baz for Foo {
             /*caret*/
         }
-    """, listOf(ImplementMemberSelection("baz(&self) -> Box<Fn(i32, i32) -> i32>", true, isSelected = true)), """
+    """, listOf(ImplementMemberSelection("baz(&self) -> Box<dyn Fn(i32, i32) -> i32>", true, isSelected = true)), """
         struct Foo;
         struct Bar;
         trait Baz {
-            fn baz(&self) -> Box<Fn(i32, i32) -> i32>;
+            fn baz(&self) -> Box<dyn Fn(i32, i32) -> i32>;
         }
 
         impl Baz for Foo {
-            fn baz(&self) -> Box<Fn(i32, i32) -> i32> {
+            fn baz(&self) -> Box<dyn Fn(i32, i32) -> i32> {
                 unimplemented!()
             }
         }
diff --git a/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt
index 32bbf229f..bb296ea42 100644
--- a/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt
@@ -267,19 +267,19 @@ class RsTypeResolvingTest : RsTypificationTestBase() {
     fun `test generic trait object`() = testType("""
         trait Trait<A> {}
         fn foo(_: &Trait<u8>) { unimplemented!() }
-                  //^ Trait<u8>
+                  //^ dyn Trait<u8>
     """)
 
     fun `test generic 'dyn Trait' trait object`() = testType("""
         trait Trait<A> {}
         fn foo(_: &dyn Trait<u8>) { unimplemented!() }
-                  //^ Trait<u8>
+                  //^ dyn Trait<u8>
     """)
 
     fun `test trait object with bound associated type`() = testType("""
         trait Trait { type Item; }
         fn foo(_: &Trait<Item=u8>) { unimplemented!() }
-                  //^ Trait<Item=u8>
+                  //^ dyn Trait<Item=u8>
     """)
 
     fun `test impl Trait`() = testType("""