@@ -410,8 +410,8 @@ object Semantic {
410410 def select (f : Symbol , source : Tree ): Contextual [Result ] =
411411 value.select(f, source) ++ errors
412412
413- def call (meth : Symbol , args : List [ArgInfo ], superType : Type , source : Tree ): Contextual [Result ] =
414- value.call(meth, args, superType, source) ++ errors
413+ def call (meth : Symbol , args : List [ArgInfo ], receiver : Type , superType : Type , source : Tree ): Contextual [Result ] =
414+ value.call(meth, args, receiver, superType, source) ++ errors
415415
416416 def callConstructor (ctor : Symbol , args : List [ArgInfo ], source : Tree ): Contextual [Result ] =
417417 value.callConstructor(ctor, args, source) ++ errors
@@ -587,7 +587,7 @@ object Semantic {
587587 }
588588 }
589589
590- def call (meth : Symbol , args : List [ArgInfo ], superType : Type , source : Tree , needResolve : Boolean = true ): Contextual [Result ] = log(" call " + meth.show + " , args = " + args, printer, (_ : Result ).show) {
590+ def call (meth : Symbol , args : List [ArgInfo ], receiver : Type , superType : Type , source : Tree , needResolve : Boolean = true ): Contextual [Result ] = log(" call " + meth.show + " , args = " + args, printer, (_ : Result ).show) {
591591 def checkArgs = args.flatMap(_.promote)
592592
593593 def isSyntheticApply (meth : Symbol ) =
@@ -600,6 +600,27 @@ object Semantic {
600600 || (meth eq defn.Object_ne )
601601 || (meth eq defn.Any_isInstanceOf )
602602
603+ def checkArgsWithParametricity () =
604+ val methodType = atPhaseBeforeTransforms { meth.info.stripPoly }
605+ var allArgsPromote = true
606+ val allParamTypes = methodType.paramInfoss.flatten.map(_.repeatedToSingle)
607+ val errors = allParamTypes.zip(args).flatMap { (info, arg) =>
608+ val errors = arg.promote
609+ allArgsPromote = allArgsPromote && errors.isEmpty
610+ info match
611+ case typeParamRef : TypeParamRef =>
612+ val bounds = typeParamRef.underlying.bounds
613+ val isWithinBounds = bounds.lo <:< defn.NothingType && defn.AnyType <:< bounds.hi
614+ def otherParamContains = allParamTypes.exists { param => param != info && param.typeSymbol != defn.ClassTagClass && info.occursIn(param) }
615+ // A non-hot method argument is allowed if the corresponding parameter type is a
616+ // type parameter T with Any as its upper bound and Nothing as its lower bound.
617+ // the other arguments should either correspond to a parameter type that is T
618+ // or that does not contain T as a component.
619+ if isWithinBounds && ! otherParamContains then Nil else errors
620+ case _ => errors
621+ }
622+ (errors, allArgsPromote)
623+
603624 // fast track if the current object is already initialized
604625 if promoted.isCurrentObjectPromoted then Result (Hot , Nil )
605626 else if isAlwaysSafe(meth) then Result (Hot , Nil )
@@ -610,7 +631,14 @@ object Semantic {
610631 val klass = meth.owner.companionClass.asClass
611632 instantiate(klass, klass.primaryConstructor, args, source)
612633 else
613- Result (Hot , checkArgs)
634+ if receiver.typeSymbol.isStaticOwner then
635+ val (errors, allArgsPromote) = checkArgsWithParametricity()
636+ if allArgsPromote || errors.nonEmpty then
637+ Result (Hot , errors)
638+ else
639+ Result (Cold , errors)
640+ else
641+ Result (Hot , checkArgs)
614642
615643 case Cold =>
616644 val error = CallCold (meth, source, trace.toVector)
@@ -666,7 +694,7 @@ object Semantic {
666694 }
667695
668696 case RefSet (refs) =>
669- val resList = refs.map(_.call(meth, args, superType, source))
697+ val resList = refs.map(_.call(meth, args, receiver, superType, source))
670698 val value2 = resList.map(_.value).join
671699 val errors = resList.flatMap(_.errors)
672700 Result (value2, errors)
@@ -946,7 +974,7 @@ object Semantic {
946974 locally {
947975 given Trace = trace2
948976 val args = member.info.paramInfoss.flatten.map(_ => ArgInfo (Hot , EmptyTree ))
949- val res = warm.call(member, args, superType = NoType , source = member.defTree)
977+ val res = warm.call(member, args, receiver = NoType , superType = NoType , source = member.defTree)
950978 buffer ++= res.ensureHot(msg, source).errors
951979 }
952980 else
@@ -1126,14 +1154,14 @@ object Semantic {
11261154 case Select (supert : Super , _) =>
11271155 val SuperType (thisTp, superTp) = supert.tpe
11281156 val thisValue2 = resolveThis(thisTp.classSymbol.asClass, thisV, klass, ref)
1129- Result (thisValue2, errors).call(ref.symbol, args, superTp, expr)
1157+ Result (thisValue2, errors).call(ref.symbol, args, thisTp, superTp, expr)
11301158
11311159 case Select (qual, _) =>
11321160 val res = eval(qual, thisV, klass) ++ errors
11331161 if ref.symbol.isConstructor then
11341162 res.callConstructor(ref.symbol, args, source = expr)
11351163 else
1136- res.call(ref.symbol, args, superType = NoType , source = expr)
1164+ res.call(ref.symbol, args, receiver = qual.tpe, superType = NoType , source = expr)
11371165
11381166 case id : Ident =>
11391167 id.tpe match
@@ -1142,13 +1170,13 @@ object Semantic {
11421170 val enclosingClass = id.symbol.owner.enclosingClass.asClass
11431171 val thisValue2 = resolveThis(enclosingClass, thisV, klass, id)
11441172 // local methods are not a member, but we can reuse the method `call`
1145- thisValue2.call(id.symbol, args, superType = NoType , expr, needResolve = false )
1173+ thisValue2.call(id.symbol, args, receiver = NoType , superType = NoType , expr, needResolve = false )
11461174 case TermRef (prefix, _) =>
11471175 val res = cases(prefix, thisV, klass, id) ++ errors
11481176 if id.symbol.isConstructor then
11491177 res.callConstructor(id.symbol, args, source = expr)
11501178 else
1151- res.call(id.symbol, args, superType = NoType , source = expr)
1179+ res.call(id.symbol, args, receiver = prefix, superType = NoType , source = expr)
11521180
11531181 case Select (qualifier, name) =>
11541182 val qualRes = eval(qualifier, thisV, klass)
0 commit comments