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