@@ -1809,7 +1809,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1809
1809
params.map(genParamDef(_))
1810
1810
}
1811
1811
1812
- if (isAbstractMethod(dd)) {
1812
+ val jsMethodDef = if (isAbstractMethod(dd)) {
1813
1813
val body = if (scalaUsesImplClasses &&
1814
1814
sym.hasAnnotation(JavaDefaultMethodAnnotation )) {
1815
1815
/* For an interface method with @JavaDefaultMethod, make it a
@@ -1899,6 +1899,24 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1899
1899
1900
1900
methodDefWithoutUselessVars
1901
1901
}
1902
+
1903
+ /* #3953 Patch the param defs to have the type advertised by the method's type.
1904
+ * This works around https://github.com/scala/bug/issues/11884, whose fix
1905
+ * upstream is blocked because it is not binary compatible. The fix here
1906
+ * only affects the inside of the js.MethodDef, so it is binary compat.
1907
+ */
1908
+ val paramTypeRewrites = jsParams.zip(sym.tpe.paramTypes.map(toIRType(_))).collect {
1909
+ case (js.ParamDef (name, _, tpe, _), sigType) if tpe != sigType => name.name -> sigType
1910
+ }
1911
+ if (paramTypeRewrites.isEmpty) {
1912
+ // Overwhelmingly common case: all the types match, so there is nothing to do
1913
+ jsMethodDef
1914
+ } else {
1915
+ devWarning(
1916
+ " Working around https://github.com/scala/bug/issues/11884 " +
1917
+ s " for ${sym.fullName} at ${sym.pos}" )
1918
+ patchTypeOfParamDefs(jsMethodDef, paramTypeRewrites.toMap)
1919
+ }
1902
1920
}
1903
1921
}
1904
1922
@@ -1958,6 +1976,42 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1958
1976
newBody)(methodDef.optimizerHints, None )(methodDef.pos)
1959
1977
}
1960
1978
1979
+ /** Patches the type of selected param defs in a [[js.MethodDef ]].
1980
+ *
1981
+ * @param patches
1982
+ * Map from local name to new type. For param defs not in the map, the
1983
+ * type is untouched.
1984
+ */
1985
+ private def patchTypeOfParamDefs (methodDef : js.MethodDef ,
1986
+ patches : Map [LocalName , jstpe.Type ]): js.MethodDef = {
1987
+
1988
+ def newType (name : js.LocalIdent , oldType : jstpe.Type ): jstpe.Type =
1989
+ patches.getOrElse(name.name, oldType)
1990
+
1991
+ val js .MethodDef (flags, methodName, originalName, params, resultType, body) =
1992
+ methodDef
1993
+ val newParams = for {
1994
+ p @ js.ParamDef (name, originalName, ptpe, mutable) <- params
1995
+ } yield {
1996
+ js.ParamDef (name, originalName, newType(name, ptpe), mutable)(p.pos)
1997
+ }
1998
+ val transformer = new ir.Transformers .Transformer {
1999
+ override def transform (tree : js.Tree , isStat : Boolean ): js.Tree = tree match {
2000
+ case tree @ js.VarRef (name) =>
2001
+ js.VarRef (name)(newType(name, tree.tpe))(tree.pos)
2002
+ case js.Closure (arrow, captureParams, params, restParam, body, captureValues) =>
2003
+ js.Closure (arrow, captureParams, params, restParam, body,
2004
+ captureValues.map(transformExpr))(tree.pos)
2005
+ case _ =>
2006
+ super .transform(tree, isStat)
2007
+ }
2008
+ }
2009
+ val newBody = body.map(
2010
+ b => transformer.transform(b, isStat = resultType == jstpe.NoType ))
2011
+ js.MethodDef (flags, methodName, originalName, newParams, resultType,
2012
+ newBody)(methodDef.optimizerHints, None )(methodDef.pos)
2013
+ }
2014
+
1961
2015
/** Generates the JSNativeMemberDef of a JS native method. */
1962
2016
def genJSNativeMemberDef (tree : DefDef ): js.JSNativeMemberDef = {
1963
2017
implicit val pos = tree.pos
0 commit comments