@@ -212,6 +212,107 @@ object Applications {
212212 overwriteType(app.tpe)
213213 // ExtMethodApply always has wildcard type in order not to prompt any further adaptations
214214 // such as eta expansion before the method is fully applied.
215+ }
216+
217+ /** Find reference to default parameter getter for parameter #n in current
218+ * parameter list, or NoType if none was found
219+ */
220+ def findDefaultGetter (fn : Tree , n : Int , testOnly : Boolean )(using Context ): Tree = {
221+ if fn.symbol.isTerm then
222+ val meth = fn.symbol.asTerm
223+ val receiver : Tree = methPart(fn) match {
224+ case Select (receiver, _) => receiver
225+ case mr => mr.tpe.normalizedPrefix match {
226+ case mr : TermRef => ref(mr)
227+ case mr =>
228+ if testOnly then
229+ // In this case it is safe to skolemize now; we will produce a stable prefix for the actual call.
230+ ref(mr.narrow)
231+ else
232+ EmptyTree
233+ }
234+ }
235+ val getterPrefix =
236+ if (meth.is(Synthetic ) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name
237+ def getterName = DefaultGetterName (getterPrefix, n + numArgs(fn))
238+ if ! meth.hasDefaultParams then
239+ EmptyTree
240+ else if (receiver.isEmpty) {
241+ def findGetter (cx : Context ): Tree =
242+ if (cx eq NoContext ) EmptyTree
243+ else if (cx.scope != cx.outer.scope &&
244+ cx.denotNamed(meth.name).hasAltWith(_.symbol == meth)) {
245+ val denot = cx.denotNamed(getterName)
246+ if (denot.exists) ref(TermRef (cx.owner.thisType, getterName, denot))
247+ else findGetter(cx.outer)
248+ }
249+ else findGetter(cx.outer)
250+ findGetter(ctx)
251+ }
252+ else {
253+ def selectGetter (qual : Tree ): Tree = {
254+ val getterDenot = qual.tpe.member(getterName)
255+ if (getterDenot.exists) qual.select(TermRef (qual.tpe, getterName, getterDenot))
256+ else EmptyTree
257+ }
258+ if (! meth.isClassConstructor)
259+ selectGetter(receiver)
260+ else {
261+ // default getters for class constructors are found in the companion object
262+ val cls = meth.owner
263+ val companion = cls.companionModule
264+ if (companion.isTerm) {
265+ val prefix = receiver.tpe.baseType(cls).normalizedPrefix
266+ if (prefix.exists) selectGetter(ref(TermRef (prefix, companion.asTerm)))
267+ else EmptyTree
268+ }
269+ else EmptyTree
270+ }
271+ }
272+ else EmptyTree // structural applies don't have symbols or defaults
273+ }// .showing(i"find getter $fn, $n = $result")
274+ end findDefaultGetter
275+
276+ /** Splice new method reference `meth` into existing application `app` */
277+ private def spliceMeth (meth : Tree , app : Tree )(using Context ): Tree = app match {
278+ case Apply (fn, args) =>
279+ spliceMeth(meth, fn).appliedToArgs(args)
280+ case TypeApply (fn, targs) =>
281+ // Note: It is important that the type arguments `targs` are passed in new trees
282+ // instead of being spliced in literally. Otherwise, a type argument to a default
283+ // method could be constructed as the definition site of the type variable for
284+ // that default constructor. This would interpolate type variables too early,
285+ // causing lots of tests (among them tasty_unpickleScala2) to fail.
286+ //
287+ // The test case is in i1757.scala. Here we have a variable `s` and a method `cpy`
288+ // defined like this:
289+ //
290+ // var s
291+ // def cpy[X](b: List[Int] = b): B[X] = new B[X](b)
292+ //
293+ // The call `s.cpy()` then gets expanded to
294+ //
295+ // { val $1$: B[Int] = this.s
296+ // $1$.cpy[X']($1$.cpy$default$1[X']
297+ // }
298+ //
299+ // A type variable gets interpolated if it does not appear in the type
300+ // of the current tree and the current tree contains the variable's "definition".
301+ // Previously, the polymorphic function tree to which the variable was first added
302+ // was taken as the variable's definition. But that fails here because that
303+ // tree was `s.cpy` but got transformed into `$1$.cpy`. We now take the type argument
304+ // [X'] of the variable as its definition tree, which is more robust. But then
305+ // it's crucial that the type tree is not copied directly as argument to
306+ // `cpy$default$1`. If it was, the variable `X'` would already be interpolated
307+ // when typing the default argument, which is too early.
308+ spliceMeth(meth, fn).appliedToTypes(targs.tpes)
309+ case _ => meth
310+ }
311+
312+ def defaultArgument (fn : Tree , n : Int , testOnly : Boolean )(using Context ): Tree =
313+ val getter = findDefaultGetter(fn, n, testOnly)
314+ if getter.isEmpty then getter
315+ else spliceMeth(getter.withSpan(fn.span), fn)
215316}
216317
217318trait Applications extends Compatibility {
@@ -412,98 +513,6 @@ trait Applications extends Compatibility {
412513 handlePositional(methodType.paramNames, args)
413514 }
414515
415- /** Splice new method reference into existing application */
416- def spliceMeth (meth : Tree , app : Tree ): Tree = app match {
417- case Apply (fn, args) =>
418- spliceMeth(meth, fn).appliedToTermArgs(args)
419- case TypeApply (fn, targs) =>
420- // Note: It is important that the type arguments `targs` are passed in new trees
421- // instead of being spliced in literally. Otherwise, a type argument to a default
422- // method could be constructed as the definition site of the type variable for
423- // that default constructor. This would interpolate type variables too early,
424- // causing lots of tests (among them tasty_unpickleScala2) to fail.
425- //
426- // The test case is in i1757.scala. Here we have a variable `s` and a method `cpy`
427- // defined like this:
428- //
429- // var s
430- // def cpy[X](b: List[Int] = b): B[X] = new B[X](b)
431- //
432- // The call `s.cpy()` then gets expanded to
433- //
434- // { val $1$: B[Int] = this.s
435- // $1$.cpy[X']($1$.cpy$default$1[X']
436- // }
437- //
438- // A type variable gets interpolated if it does not appear in the type
439- // of the current tree and the current tree contains the variable's "definition".
440- // Previously, the polymorphic function tree to which the variable was first added
441- // was taken as the variable's definition. But that fails here because that
442- // tree was `s.cpy` but got transformed into `$1$.cpy`. We now take the type argument
443- // [X'] of the variable as its definition tree, which is more robust. But then
444- // it's crucial that the type tree is not copied directly as argument to
445- // `cpy$default$1`. If it was, the variable `X'` would already be interpolated
446- // when typing the default argument, which is too early.
447- spliceMeth(meth, fn).appliedToTypes(targs.tpes)
448- case _ => meth
449- }
450-
451- /** Find reference to default parameter getter for parameter #n in current
452- * parameter list, or NoType if none was found
453- */
454- def findDefaultGetter (n : Int )(using Context ): Tree = {
455- val meth = methRef.symbol.asTerm
456- val receiver : Tree = methPart(normalizedFun) match {
457- case Select (receiver, _) => receiver
458- case mr => mr.tpe.normalizedPrefix match {
459- case mr : TermRef => ref(mr)
460- case mr =>
461- if (this .isInstanceOf [TestApplication [? ]])
462- // In this case it is safe to skolemize now; we will produce a stable prefix for the actual call.
463- ref(mr.narrow)
464- else
465- EmptyTree
466- }
467- }
468- val getterPrefix =
469- if (meth.is(Synthetic ) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name
470- def getterName = DefaultGetterName (getterPrefix, n)
471- if (! meth.hasDefaultParams)
472- EmptyTree
473- else if (receiver.isEmpty) {
474- def findGetter (cx : Context ): Tree =
475- if (cx eq NoContext ) EmptyTree
476- else if (cx.scope != cx.outer.scope &&
477- cx.denotNamed(meth.name).hasAltWith(_.symbol == meth)) {
478- val denot = cx.denotNamed(getterName)
479- if (denot.exists) ref(TermRef (cx.owner.thisType, getterName, denot))
480- else findGetter(cx.outer)
481- }
482- else findGetter(cx.outer)
483- findGetter(ctx)
484- }
485- else {
486- def selectGetter (qual : Tree ): Tree = {
487- val getterDenot = qual.tpe.member(getterName)
488- if (getterDenot.exists) qual.select(TermRef (qual.tpe, getterName, getterDenot))
489- else EmptyTree
490- }
491- if (! meth.isClassConstructor)
492- selectGetter(receiver)
493- else {
494- // default getters for class constructors are found in the companion object
495- val cls = meth.owner
496- val companion = cls.companionModule
497- if (companion.isTerm) {
498- val prefix = receiver.tpe.baseType(cls).normalizedPrefix
499- if (prefix.exists) selectGetter(ref(TermRef (prefix, companion.asTerm)))
500- else EmptyTree
501- }
502- else EmptyTree
503- }
504- }
505- }
506-
507516 /** Is `sym` a constructor of a Java-defined annotation? */
508517 def isJavaAnnotConstr (sym : Symbol ): Boolean =
509518 sym.is(JavaDefined ) && sym.isConstructor && sym.owner.derivesFrom(defn.AnnotationClass )
@@ -554,18 +563,7 @@ trait Applications extends Compatibility {
554563 else
555564 EmptyTree
556565 }
557- else {
558- val getter =
559- if (sym.exists) // `sym` doesn't exist for structural calls
560- findDefaultGetter(n + numArgs(normalizedFun))
561- else
562- EmptyTree
563-
564- if (! getter.isEmpty)
565- spliceMeth(getter.withSpan(normalizedFun.span), normalizedFun)
566- else
567- EmptyTree
568- }
566+ else defaultArgument(normalizedFun, n, this .isInstanceOf [TestApplication [? ]])
569567
570568 def implicitArg = implicitArgTree(formal, appPos.span)
571569
0 commit comments