@@ -410,8 +410,8 @@ object Semantic {
410
410
def select (f : Symbol , source : Tree ): Contextual [Result ] =
411
411
value.select(f, source) ++ errors
412
412
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
415
415
416
416
def callConstructor (ctor : Symbol , args : List [ArgInfo ], source : Tree ): Contextual [Result ] =
417
417
value.callConstructor(ctor, args, source) ++ errors
@@ -587,7 +587,7 @@ object Semantic {
587
587
}
588
588
}
589
589
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) {
591
591
def checkArgs = args.flatMap(_.promote)
592
592
593
593
def isSyntheticApply (meth : Symbol ) =
@@ -600,6 +600,24 @@ object Semantic {
600
600
|| (meth eq defn.Object_ne )
601
601
|| (meth eq defn.Any_isInstanceOf )
602
602
603
+ def checkArgsWithParametricity () =
604
+ val methodType = atPhaseBeforeTransforms { meth.info.stripPoly }
605
+ var allArgsPromote = true
606
+ var allParamTypes = methodType.paramInfoss.flatten.map(_.repeatedToSingle)
607
+ val errors = allParamTypes.zip(args).flatMap { (info, arg) =>
608
+ val isTypeParam = info.isInstanceOf [TypeParamRef ]
609
+ val isWithinBounds = info.bounds.lo <:< defn.NothingType && defn.AnyType <:< info.bounds.hi
610
+ def otherParamContains = allParamTypes.exists( param => { param != info && param.typeSymbol != defn.ClassTagClass && info.occursIn(param) } )
611
+ val errors = arg.promote
612
+ allArgsPromote = allArgsPromote && errors.isEmpty
613
+ // A non-hot method argument is allowed if the corresponding parameter type is a
614
+ // type parameter T with Any as its upper bound and Nothing as its lower bound.
615
+ // the other arguments should either correspond to a parameter type that is T
616
+ // or that does not contain T as a component.
617
+ if isTypeParam && ! isWithinBounds && ! otherParamContains then Nil else errors
618
+ }
619
+ (errors, allArgsPromote)
620
+
603
621
// fast track if the current object is already initialized
604
622
if promoted.isCurrentObjectPromoted then Result (Hot , Nil )
605
623
else if isAlwaysSafe(meth) then Result (Hot , Nil )
@@ -610,7 +628,14 @@ object Semantic {
610
628
val klass = meth.owner.companionClass.asClass
611
629
instantiate(klass, klass.primaryConstructor, args, source)
612
630
else
613
- Result (Hot , checkArgs)
631
+ if receiver.typeSymbol.isStaticOwner then
632
+ val (errors, allArgsPromote) = checkArgsWithParametricity()
633
+ if allArgsPromote || errors.nonEmpty then
634
+ Result (Hot , errors)
635
+ else
636
+ Result (Cold , errors)
637
+ else
638
+ Result (Hot , checkArgs)
614
639
615
640
case Cold =>
616
641
val error = CallCold (meth, source, trace.toVector)
@@ -666,7 +691,7 @@ object Semantic {
666
691
}
667
692
668
693
case RefSet (refs) =>
669
- val resList = refs.map(_.call(meth, args, superType, source))
694
+ val resList = refs.map(_.call(meth, args, receiver, superType, source))
670
695
val value2 = resList.map(_.value).join
671
696
val errors = resList.flatMap(_.errors)
672
697
Result (value2, errors)
@@ -946,7 +971,7 @@ object Semantic {
946
971
locally {
947
972
given Trace = trace2
948
973
val args = member.info.paramInfoss.flatten.map(_ => ArgInfo (Hot , EmptyTree ))
949
- val res = warm.call(member, args, superType = NoType , source = member.defTree)
974
+ val res = warm.call(member, args, receiver = NoType , superType = NoType , source = member.defTree)
950
975
buffer ++= res.ensureHot(msg, source).errors
951
976
}
952
977
else
@@ -1126,14 +1151,14 @@ object Semantic {
1126
1151
case Select (supert : Super , _) =>
1127
1152
val SuperType (thisTp, superTp) = supert.tpe
1128
1153
val thisValue2 = resolveThis(thisTp.classSymbol.asClass, thisV, klass, ref)
1129
- Result (thisValue2, errors).call(ref.symbol, args, superTp, expr)
1154
+ Result (thisValue2, errors).call(ref.symbol, args, thisTp, superTp, expr)
1130
1155
1131
1156
case Select (qual, _) =>
1132
1157
val res = eval(qual, thisV, klass) ++ errors
1133
1158
if ref.symbol.isConstructor then
1134
1159
res.callConstructor(ref.symbol, args, source = expr)
1135
1160
else
1136
- res.call(ref.symbol, args, superType = NoType , source = expr)
1161
+ res.call(ref.symbol, args, receiver = qual.tpe, superType = NoType , source = expr)
1137
1162
1138
1163
case id : Ident =>
1139
1164
id.tpe match
@@ -1142,13 +1167,13 @@ object Semantic {
1142
1167
val enclosingClass = id.symbol.owner.enclosingClass.asClass
1143
1168
val thisValue2 = resolveThis(enclosingClass, thisV, klass, id)
1144
1169
// local methods are not a member, but we can reuse the method `call`
1145
- thisValue2.call(id.symbol, args, superType = NoType , expr, needResolve = false )
1170
+ thisValue2.call(id.symbol, args, receiver = NoType , superType = NoType , expr, needResolve = false )
1146
1171
case TermRef (prefix, _) =>
1147
1172
val res = cases(prefix, thisV, klass, id) ++ errors
1148
1173
if id.symbol.isConstructor then
1149
1174
res.callConstructor(id.symbol, args, source = expr)
1150
1175
else
1151
- res.call(id.symbol, args, superType = NoType , source = expr)
1176
+ res.call(id.symbol, args, receiver = prefix, superType = NoType , source = expr)
1152
1177
1153
1178
case Select (qualifier, name) =>
1154
1179
val qualRes = eval(qualifier, thisV, klass)
0 commit comments