@@ -412,6 +412,58 @@ class Namer { typer: Typer =>
412
412
def isEnumConstant (vd : ValDef )(using Context ): Boolean =
413
413
vd.mods.isAllOf(JavaEnumValue )
414
414
415
+ /** Ensure that the first type in a list of parent types Ps points to a non-trait class.
416
+ * If that's not already the case, add one. The added class type CT is determined as follows.
417
+ * First, let C be the unique class such that
418
+ * - there is a parent P_i such that P_i derives from C, and
419
+ * - for every class D: If some parent P_j, j <= i derives from D, then C derives from D.
420
+ * Then, let CT be the smallest type which
421
+ * - has C as its class symbol, and
422
+ * - for all parents P_i: If P_i derives from C then P_i <:< CT.
423
+ *
424
+ * Tweak: It could be that at the point where the method is called, some superclass
425
+ * is still missing its parents. Parents are set to Nil when completion starts and are
426
+ * set to the actual parents later. If a superclass completes a subclass in one
427
+ * of its parents, the parents of the superclass or some intervening class might
428
+ * not yet be set. This situation can be detected by asking for the baseType of Any -
429
+ * if that type does not exist, one of the base classes of this class misses its parents.
430
+ * If this situation arises, the computation of the superclass might be imprecise.
431
+ * For instance, in i12722.scala, the superclass of `IPersonalCoinOps` is computed
432
+ * as `Object`, where `JsObject` would be correct. The problem cannot be solved locally,
433
+ * but we detect the situaton and mark the superclass with a `@ProvisionalSuperClass`
434
+ * annotation in this case. When typechecking the class, we then run ensureFirstIsClass
435
+ * again and possibly improve the computed super class.
436
+ * An alternatiev fix would compute superclasses at typer instead at completion. But
437
+ * that breaks too many invariants. For instance, we rely on correct @Child annotations
438
+ * after completion, and these in turn need the superclass.
439
+ */
440
+ def ensureFirstIsClass (cls : ClassSymbol , parents : List [Type ])(using Context ): List [Type ] =
441
+
442
+ def realClassParent (sym : Symbol ): ClassSymbol =
443
+ if ! sym.isClass then defn.ObjectClass
444
+ else if ! sym.is(Trait ) then sym.asClass
445
+ else sym.info.parents match
446
+ case parentRef :: _ => realClassParent(parentRef.typeSymbol)
447
+ case nil => defn.ObjectClass
448
+
449
+ def improve (candidate : ClassSymbol , parent : Type ): ClassSymbol =
450
+ val pcls = realClassParent(parent.classSymbol)
451
+ if (pcls derivesFrom candidate) pcls else candidate
452
+
453
+ parents match
454
+ case p :: _ if p.classSymbol.isRealClass => parents
455
+ case _ =>
456
+ val pcls = parents.foldLeft(defn.ObjectClass )(improve)
457
+ typr.println(i " ensure first is class $parents%, % --> ${parents map (_ baseType pcls)}%, % " )
458
+ val bases = parents.map(_.baseType(pcls))
459
+ var first = TypeComparer .glb(defn.ObjectType :: bases)
460
+ val isProvisional = parents.exists(! _.baseType(defn.AnyClass ).exists)
461
+ if isProvisional then
462
+ typr.println(i " provisional superclass $first for $cls" )
463
+ first = AnnotatedType (first, Annotation (defn.ProvisionalSuperClassAnnot ))
464
+ checkFeasibleParent(first, cls.srcPos, em " in inferred superclass $first" ) :: parents
465
+ end ensureFirstIsClass
466
+
415
467
/** Add child annotation for `child` to annotations of `cls`. The annotation
416
468
* is added at the correct insertion point, so that Child annotations appear
417
469
* in reverse order of their start positions.
@@ -1260,37 +1312,6 @@ class Namer { typer: Typer =>
1260
1312
}
1261
1313
}
1262
1314
1263
- /** Ensure that the first type in a list of parent types Ps points to a non-trait class.
1264
- * If that's not already the case, add one. The added class type CT is determined as follows.
1265
- * First, let C be the unique class such that
1266
- * - there is a parent P_i such that P_i derives from C, and
1267
- * - for every class D: If some parent P_j, j <= i derives from D, then C derives from D.
1268
- * Then, let CT be the smallest type which
1269
- * - has C as its class symbol, and
1270
- * - for all parents P_i: If P_i derives from C then P_i <:< CT.
1271
- */
1272
- def ensureFirstIsClass (parents : List [Type ]): List [Type ] =
1273
-
1274
- def realClassParent (sym : Symbol ): ClassSymbol =
1275
- if ! sym.isClass then defn.ObjectClass
1276
- else if ! sym.is(Trait ) then sym.asClass
1277
- else sym.info.parents match
1278
- case parentRef :: _ => realClassParent(parentRef.typeSymbol)
1279
- case nil => defn.ObjectClass
1280
-
1281
- def improve (candidate : ClassSymbol , parent : Type ): ClassSymbol =
1282
- val pcls = realClassParent(parent.classSymbol)
1283
- if (pcls derivesFrom candidate) pcls else candidate
1284
-
1285
- parents match
1286
- case p :: _ if p.classSymbol.isRealClass => parents
1287
- case _ =>
1288
- val pcls = parents.foldLeft(defn.ObjectClass )(improve)
1289
- typr.println(i " ensure first is class $parents%, % --> ${parents map (_ baseType pcls)}%, % " )
1290
- val first = TypeComparer .glb(defn.ObjectType :: parents.map(_.baseType(pcls)))
1291
- checkFeasibleParent(first, cls.srcPos, em " in inferred superclass $first" ) :: parents
1292
- end ensureFirstIsClass
1293
-
1294
1315
/** If `parents` contains references to traits that have supertraits with implicit parameters
1295
1316
* add those supertraits in linearization order unless they are already covered by other
1296
1317
* parent types. For instance, in
@@ -1333,7 +1354,7 @@ class Namer { typer: Typer =>
1333
1354
val parentTypes = defn.adjustForTuple(cls, cls.typeParams,
1334
1355
defn.adjustForBoxedUnit(cls,
1335
1356
addUsingTraits(
1336
- ensureFirstIsClass(parents.map(checkedParentType(_)))
1357
+ ensureFirstIsClass(cls, parents.map(checkedParentType(_)))
1337
1358
)
1338
1359
)
1339
1360
)
0 commit comments