@@ -203,10 +203,38 @@ const USRBasedType *USRBasedType::fromType(Type Ty, USRBasedTypeArena &Arena) {
203203 Conformance->getProtocol ()->getDeclaredInterfaceType (), Arena));
204204 }
205205 }
206- Type Superclass = Ty->getSuperclass ();
206+
207+ // You would think that superclass + conformances form a DAG. You are wrong!
208+ // We can achieve a circular supertype hierarcy with
209+ //
210+ // protocol Proto : Class {}
211+ // class Class : Proto {}
212+ //
213+ // USRBasedType is not set up for this. Serialization of code completion
214+ // results from global modules can't handle cycles in the supertype hierarchy
215+ // because it writes the DAG leaf to root(s) and needs to know the type
216+ // offsets. To get consistent results independent of where we start
217+ // constructing USRBasedTypes, ignore superclasses of protocols. If we kept
218+ // track of already visited types, we would get different results depending on
219+ // whether we start constructing the USRBasedType hierarchy from Proto or
220+ // Class.
221+ // Ignoring superclasses of protocols is safe to do because USRBasedType is an
222+ // under-approximation anyway.
223+
224+ // / If `Ty` is a class type and has a superclass, return that. In all other
225+ // / cases, return null.
226+ auto getSuperclass = [](Type Ty) -> Type {
227+ if (isa_and_nonnull<ClassDecl>(Ty->getAnyNominal ())) {
228+ return Ty->getSuperclass ();
229+ } else {
230+ return Type ();
231+ }
232+ };
233+
234+ Type Superclass = getSuperclass (Ty);
207235 while (Superclass) {
208236 Supertypes.push_back (USRBasedType::fromType (Superclass, Arena));
209- Superclass = Superclass-> getSuperclass ();
237+ Superclass = getSuperclass (Superclass );
210238 }
211239
212240 assert (llvm::all_of (Supertypes, [&USR](const USRBasedType *Ty) {
0 commit comments