@@ -594,12 +594,61 @@ object RefChecks {
594
594
checkNoAbstractDecls(bc.asClass.superClass)
595
595
}
596
596
597
+ // Check that every term member of this concrete class has a symbol that matches the member's type
598
+ // Member types are computed by intersecting the types of all members that have the same name
599
+ // and signature. But a member selection will pick one particular implementation, according to
600
+ // the rules of overriding and linearization. This method checks that the implementation has indeed
601
+ // a type that subsumes the full member type.
602
+ def checkMemberTypesOK () = {
603
+
604
+ // First compute all member names we need to check in `membersToCheck`.
605
+ // We do not check
606
+ // - types
607
+ // - synthetic members or bridges
608
+ // - members in other concrete classes, since these have been checked before
609
+ // (this is done for efficiency)
610
+ // - members in a prefix of inherited parents that all come from Java or Scala2
611
+ // (this is done to avoid false negatives since Scala2's rules for checking are different)
612
+ val membersToCheck = mutable.Set [Name ]()
613
+ val seenClasses = mutable.Set [Symbol ]()
614
+ def addDecls (cls : Symbol ): Unit =
615
+ if (! seenClasses.contains(cls)) {
616
+ seenClasses.+= (cls)
617
+ for (mbr <- cls.info.decls)
618
+ if (mbr.isTerm && ! mbr.is(Synthetic | Bridge ) && mbr.memberCanMatchInheritedSymbols &&
619
+ ! membersToCheck.contains(mbr.name))
620
+ membersToCheck.+= (mbr.name)
621
+ cls.info.parents.map(_.classSymbol)
622
+ .filter(_.is(AbstractOrTrait ))
623
+ .dropWhile(_.is(JavaDefined | Scala2x ))
624
+ .foreach(addDecls)
625
+ }
626
+ addDecls(clazz)
627
+
628
+ // For each member, check that the type of its symbol, as seen from `self`
629
+ // can override the info of this member
630
+ for (name <- membersToCheck) {
631
+ for (mbrd <- self.member(name).alternatives) {
632
+ val mbr = mbrd.symbol
633
+ val mbrType = mbr.info.asSeenFrom(self, mbr.owner)
634
+ if (! mbrType.overrides(mbrd.info, matchLoosely = true ))
635
+ ctx.errorOrMigrationWarning(
636
+ em """ ${mbr.showLocated} is not a legal implementation of ` $name' in $clazz
637
+ | its type $mbrType
638
+ | does not conform to ${mbrd.info}""" ,
639
+ (if (mbr.owner == clazz) mbr else clazz).pos)
640
+ }
641
+ }
642
+ }
643
+
597
644
checkNoAbstractMembers()
598
645
if (abstractErrors.isEmpty)
599
646
checkNoAbstractDecls(clazz)
600
647
601
648
if (abstractErrors.nonEmpty)
602
649
ctx.error(abstractErrorMessage, clazz.pos)
650
+
651
+ checkMemberTypesOK()
603
652
} else if (clazz.is(Trait ) && ! (clazz derivesFrom defn.AnyValClass )) {
604
653
// For non-AnyVal classes, prevent abstract methods in interfaces that override
605
654
// final members in Object; see #4431
0 commit comments