@@ -8,7 +8,7 @@ import Symbols.*, Types.*, Contexts.*, Flags.*, Names.*, NameOps.*, NameKinds.*
88import StdNames .* , Denotations .* , Phases .* , SymDenotations .*
99import NameKinds .DefaultGetterName
1010import util .Spans .*
11- import scala .collection .mutable
11+ import scala .collection .{ mutable , immutable }
1212import ast .*
1313import MegaPhase .*
1414import config .Printers .{checks , noPrinter , capt }
@@ -368,6 +368,52 @@ object RefChecks {
368368 && atPhase(typerPhase):
369369 loop(member.info.paramInfoss, other.info.paramInfoss)
370370
371+ /** A map of all occurrences of `into` in a member type.
372+ * Key: number of parameter carrying `into` annotation(s)
373+ * Value: A list of all depths of into annotations, where each
374+ * function arrow increases the depth.
375+ * Example:
376+ * def foo(x: into A, y: => [X] => into (x: X) => into B): C
377+ * produces the map
378+ * (0 -> List(0), 1 -> List(1, 2))
379+ */
380+ type IntoOccurrenceMap = immutable.Map [Int , List [Int ]]
381+
382+ def intoOccurrences (tp : Type ): IntoOccurrenceMap =
383+
384+ def traverseInfo (depth : Int , tp : Type ): List [Int ] = tp match
385+ case AnnotatedType (tp, annot) if annot.symbol == defn.IntoParamAnnot =>
386+ depth :: traverseInfo(depth, tp)
387+ case AppliedType (tycon, arg :: Nil ) if tycon.typeSymbol == defn.RepeatedParamClass =>
388+ traverseInfo(depth, arg)
389+ case defn.FunctionOf (_, resType, _) =>
390+ traverseInfo(depth + 1 , resType)
391+ case RefinedType (parent, rname, mt : MethodOrPoly ) =>
392+ traverseInfo(depth, mt)
393+ case tp : MethodOrPoly =>
394+ traverseInfo(depth + 1 , tp.resType)
395+ case tp : ExprType =>
396+ traverseInfo(depth, tp.resType)
397+ case _ =>
398+ Nil
399+
400+ def traverseParams (n : Int , formals : List [Type ], acc : IntoOccurrenceMap ): IntoOccurrenceMap =
401+ if formals.isEmpty then acc
402+ else
403+ val occs = traverseInfo(0 , formals.head)
404+ traverseParams(n + 1 , formals.tail, if occs.isEmpty then acc else acc + (n -> occs))
405+
406+ def traverse (n : Int , tp : Type , acc : IntoOccurrenceMap ): IntoOccurrenceMap = tp match
407+ case tp : PolyType =>
408+ traverse(n, tp.resType, acc)
409+ case tp : MethodType =>
410+ traverse(n + tp.paramInfos.length, tp.resType, traverseParams(n, tp.paramInfos, acc))
411+ case _ =>
412+ acc
413+
414+ traverse(0 , tp, immutable.Map .empty)
415+ end intoOccurrences
416+
371417 val checker =
372418 if makeOverridingPairsChecker == null then OverridingPairsChecker (clazz, self)
373419 else makeOverridingPairsChecker(clazz, self)
@@ -572,6 +618,8 @@ object RefChecks {
572618 overrideError(i " needs to be declared with @targetName( ${" \" " }${other.targetName}${" \" " }) so that external names match " )
573619 else
574620 overrideError(" cannot have a @targetName annotation since external names would be different" )
621+ else if intoOccurrences(memberTp(self)) != intoOccurrences(otherTp(self)) then
622+ overrideError(" has different occurrences of `into` modifiers" , compareTypes = true )
575623 else if other.is(ParamAccessor ) && ! isInheritedAccessor(member, other) then // (1.12)
576624 report.errorOrMigrationWarning(
577625 em " cannot override val parameter ${other.showLocated}" ,
@@ -1002,9 +1050,9 @@ object RefChecks {
10021050 end checkNoPrivateOverrides
10031051
10041052 def checkVolatile (sym : Symbol )(using Context ): Unit =
1005- if sym.isVolatile && ! sym.is(Mutable ) then
1053+ if sym.isVolatile && ! sym.is(Mutable ) then
10061054 report.warning(VolatileOnVal (), sym.srcPos)
1007-
1055+
10081056 /** Check that unary method definition do not receive parameters.
10091057 * They can only receive inferred parameters such as type parameters and implicit parameters.
10101058 */
0 commit comments