@@ -212,6 +212,107 @@ object Applications {
212
212
overwriteType(app.tpe)
213
213
// ExtMethodApply always has wildcard type in order not to prompt any further adaptations
214
214
// 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)
215
316
}
216
317
217
318
trait Applications extends Compatibility {
@@ -412,98 +513,6 @@ trait Applications extends Compatibility {
412
513
handlePositional(methodType.paramNames, args)
413
514
}
414
515
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
-
507
516
/** Is `sym` a constructor of a Java-defined annotation? */
508
517
def isJavaAnnotConstr (sym : Symbol ): Boolean =
509
518
sym.is(JavaDefined ) && sym.isConstructor && sym.owner.derivesFrom(defn.AnnotationClass )
@@ -554,18 +563,7 @@ trait Applications extends Compatibility {
554
563
else
555
564
EmptyTree
556
565
}
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 [? ]])
569
567
570
568
def implicitArg = implicitArgTree(formal, appPos.span)
571
569
0 commit comments