@@ -169,7 +169,7 @@ object RefChecks {
169169 * TODO This still needs to be cleaned up; the current version is a straight port of what was there
170170 * before, but it looks too complicated and method bodies are far too large.
171171 */
172- private def checkAllOverrides (clazz : Symbol )(implicit ctx : Context ): Unit = {
172+ private def checkAllOverrides (clazz : ClassSymbol )(implicit ctx : Context ): Unit = {
173173 val self = clazz.thisType
174174 val upwardsSelf = upwardsThisType(clazz)
175175 var hasErrors = false
@@ -470,33 +470,52 @@ object RefChecks {
470470 }
471471 }
472472
473- def ignoreDeferred (member : SingleDenotation ) =
474- member.isType || {
475- val mbr = member.symbol
476- mbr.isSuperAccessor || // not yet synthesized
477- ShortcutImplicits .isImplicitShortcut(mbr) || // only synthesized when referenced, see Note in ShortcutImplicits
478- mbr.is(JavaDefined ) && hasJavaErasedOverriding(mbr)
479- }
473+ def ignoreDeferred (mbr : Symbol ) =
474+ mbr.isType
475+ || mbr.isSuperAccessor // not yet synthesized
476+ || ShortcutImplicits .isImplicitShortcut(mbr) // only synthesized when referenced, see Note in ShortcutImplicits
477+ || mbr.is(JavaDefined ) && hasJavaErasedOverriding(mbr)
478+
479+ def isImplemented (mbr : Symbol ) =
480+ val mbrType = clazz.thisType.memberInfo(mbr)
481+ def (sym : Symbol ).isConcrete = sym.exists && ! sym.is(Deferred )
482+ clazz.nonPrivateMembersNamed(mbr.name)
483+ .filterWithPredicate(
484+ impl => impl.symbol.isConcrete && mbrType.matchesLoosely(impl.info))
485+ .exists
486+
487+ /** The term symbols in this class and its baseclasses that are
488+ * abstract in this class. We can't use memberNames for that since
489+ * a concrete member might have the same signature as an abstract
490+ * member in a base class, yet might not override it.
491+ */
492+ def missingTermSymbols : List [Symbol ] =
493+ val buf = new mutable.ListBuffer [Symbol ]
494+ for bc <- clazz.baseClasses
495+ sym <- bc.info.decls.toList
496+ if sym.is(DeferredTerm ) && ! isImplemented(sym) && ! ignoreDeferred(sym)
497+ do buf += sym
498+ buf.toList
480499
481500 // 2. Check that only abstract classes have deferred members
482501 def checkNoAbstractMembers (): Unit = {
483502 // Avoid spurious duplicates: first gather any missing members.
484- val missing = clazz.thisType.abstractTermMembers.filterNot(ignoreDeferred)
503+ val missing = missingTermSymbols
485504 // Group missing members by the name of the underlying symbol,
486505 // to consolidate getters and setters.
487- val grouped = missing.groupBy(_.symbol. underlyingSymbol.name)
506+ val grouped = missing.groupBy(_.underlyingSymbol.name)
488507
489508 val missingMethods = grouped.toList flatMap {
490509 case (name, syms) =>
491- val withoutSetters = syms filterNot (_.symbol. isSetter)
510+ val withoutSetters = syms filterNot (_.isSetter)
492511 if (withoutSetters.nonEmpty) withoutSetters else syms
493512 }
494513
495514 def stubImplementations : List [String ] = {
496515 // Grouping missing methods by the declaring class
497- val regrouped = missingMethods.groupBy(_.symbol. owner).toList
498- def membersStrings (members : List [SingleDenotation ]) =
499- members.sortBy(_.symbol. name.toString).map(_.showDcl + " = ???" )
516+ val regrouped = missingMethods.groupBy(_.owner).toList
517+ def membersStrings (members : List [Symbol ]) =
518+ members.sortBy(_.name.toString).map(_.showDcl + " = ???" )
500519
501520 if (regrouped.tail.isEmpty)
502521 membersStrings(regrouped.head._2)
@@ -520,22 +539,21 @@ object RefChecks {
520539 }
521540
522541 for (member <- missing) {
523- val memberSym = member.symbol
524542 def undefined (msg : String ) =
525543 abstractClassError(false , s " ${member.showDcl} is not defined $msg" )
526- val underlying = memberSym .underlyingSymbol
544+ val underlying = member .underlyingSymbol
527545
528546 // Give a specific error message for abstract vars based on why it fails:
529547 // It could be unimplemented, have only one accessor, or be uninitialized.
530548 if (underlying.is(Mutable )) {
531549 val isMultiple = grouped.getOrElse(underlying.name(ctx), Nil ).size > 1
532550
533551 // If both getter and setter are missing, squelch the setter error.
534- if (memberSym .isSetter && isMultiple) ()
552+ if (member .isSetter && isMultiple) ()
535553 else undefined(
536- if (memberSym .isSetter) " \n (Note that an abstract var requires a setter in addition to the getter)"
537- else if (memberSym .isGetter && ! isMultiple) " \n (Note that an abstract var requires a getter in addition to the setter)"
538- else err.abstractVarMessage(memberSym ))
554+ if (member .isSetter) " \n (Note that an abstract var requires a setter in addition to the getter)"
555+ else if (member .isGetter && ! isMultiple) " \n (Note that an abstract var requires a getter in addition to the setter)"
556+ else err.abstractVarMessage(member ))
539557 }
540558 else if (underlying.is(Method )) {
541559 // If there is a concrete method whose name matches the unimplemented
@@ -961,7 +979,7 @@ class RefChecks extends MiniPhase { thisPhase =>
961979 }
962980
963981 override def transformTemplate (tree : Template )(implicit ctx : Context ): Tree = try {
964- val cls = ctx.owner
982+ val cls = ctx.owner.asClass
965983 checkOverloadedRestrictions(cls)
966984 checkParents(cls)
967985 if (cls.is(Trait )) tree.parents.foreach(checkParentPrefix(cls, _))
0 commit comments