@@ -6,6 +6,7 @@ import SymDenotations.{ SymDenotation, ClassDenotation, NoDenotation, NotDefined
6
6
import Contexts .{Context , ContextBase }
7
7
import Names .{Name , PreName }
8
8
import Names .TypeName
9
+ import StdNames ._
9
10
import Symbols .NoSymbol
10
11
import Symbols ._
11
12
import Types ._
@@ -247,6 +248,25 @@ object Denotations {
247
248
else asSingleDenotation
248
249
}
249
250
251
+ /** Handle merge conflict by throwing a `MergeError` exception */
252
+ private def mergeConflict (tp1 : Type , tp2 : Type )(implicit ctx : Context ): Type = {
253
+ def showType (tp : Type ) = tp match {
254
+ case ClassInfo (_, cls, _, _, _) => cls.showLocated
255
+ case bounds : TypeBounds => i " type bounds $bounds"
256
+ case _ => tp.show
257
+ }
258
+ if (true ) throw new MergeError (s " cannot merge ${showType(tp1)} with ${showType(tp2)}" , tp1, tp2)
259
+ else throw new Error (s " cannot merge ${showType(tp1)} with ${showType(tp2)}" ) // flip condition for debugging
260
+ }
261
+
262
+ /** Merge two lists of names. If names in corresponding positions match, keep them,
263
+ * otherwise generate new synthetic names.
264
+ */
265
+ def mergeNames [N <: Name ](names1 : List [N ], names2 : List [N ], syntheticName : Int => N ): List [N ] = {
266
+ for ((name1, name2, idx) <- (names1, names2, 0 until names1.length).zipped)
267
+ yield if (name1 == name2) name1 else syntheticName(idx)
268
+ }.toList
269
+
250
270
/** Form a denotation by conjoining with denotation `that`.
251
271
*
252
272
* NoDenotations are dropped. MultiDenotations are handled by merging
@@ -277,6 +297,50 @@ object Denotations {
277
297
*/
278
298
def & (that : Denotation , pre : Type , safeIntersection : Boolean = false )(implicit ctx : Context ): Denotation = {
279
299
300
+ /** Normally, `tp1 & tp2`. Special cases for matching methods and classes, with
301
+ * the possibility of raising a merge error.
302
+ */
303
+ def infoMeet (tp1 : Type , tp2 : Type ): Type = {
304
+ if (tp1 eq tp2) tp1
305
+ else tp1 match {
306
+ case tp1 : TypeBounds =>
307
+ tp2 match {
308
+ case tp2 : TypeBounds => if (safeIntersection) tp1 safe_& tp2 else tp1 & tp2
309
+ case tp2 : ClassInfo if tp1 contains tp2 => tp2
310
+ case _ => mergeConflict(tp1, tp2)
311
+ }
312
+ case tp1 : ClassInfo =>
313
+ tp2 match {
314
+ case tp2 : ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix)
315
+ case tp2 : TypeBounds if tp2 contains tp1 => tp1
316
+ case _ => mergeConflict(tp1, tp2)
317
+ }
318
+ case tp1 @ MethodType (names1, formals1) if isTerm =>
319
+ tp2 match {
320
+ case tp2 @ MethodType (names2, formals2) if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
321
+ tp1.isImplicit == tp2.isImplicit =>
322
+ tp1.derivedMethodType(
323
+ mergeNames(names1, names2, nme.syntheticParamName),
324
+ formals1,
325
+ infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1)))
326
+ case _ =>
327
+ mergeConflict(tp1, tp2)
328
+ }
329
+ case tp1 : PolyType if isTerm =>
330
+ tp2 match {
331
+ case tp2 : PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) =>
332
+ tp1.derivedPolyType(
333
+ mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
334
+ tp1.paramBounds,
335
+ infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1)))
336
+ case _ : MethodicType =>
337
+ mergeConflict(tp1, tp2)
338
+ }
339
+ case _ =>
340
+ tp1 & tp2
341
+ }
342
+ }
343
+
280
344
/** Try to merge denot1 and denot2 without adding a new signature. */
281
345
def mergeDenot (denot1 : Denotation , denot2 : SingleDenotation ): Denotation = denot1 match {
282
346
case denot1 @ MultiDenotation (denot11, denot12) =>
@@ -289,96 +353,95 @@ object Denotations {
289
353
}
290
354
case denot1 : SingleDenotation =>
291
355
if (denot1 eq denot2) denot1
292
- else if (denot1.matches(denot2)) {
293
- val info1 = denot1.info
294
- val info2 = denot2.info
295
- val sym1 = denot1.symbol
296
- val sym2 = denot2.symbol
297
-
298
- val sym2Accessible = sym2.isAccessibleFrom(pre)
299
-
300
- /** Does `sym1` come before `sym2` in the linearization of `pre`? */
301
- def precedes (sym1 : Symbol , sym2 : Symbol ) = {
302
- def precedesIn (bcs : List [ClassSymbol ]): Boolean = bcs match {
303
- case bc :: bcs1 => (sym1 eq bc) || ! (sym2 eq bc) && precedesIn(bcs1)
304
- case Nil => true
305
- }
306
- (sym1 ne sym2) &&
307
- (sym1.derivesFrom(sym2) ||
308
- ! sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses))
309
- }
356
+ else if (denot1.matches(denot2)) mergeSingleDenot(denot1, denot2)
357
+ else NoDenotation
358
+ }
310
359
311
- /** Similar to SymDenotation#accessBoundary, but without the special cases. */
312
- def accessBoundary (sym : Symbol ) =
313
- if (sym.is(Private )) sym.owner
314
- else sym.privateWithin.orElse(
315
- if (sym.is(Protected )) sym.owner.enclosingPackageClass
316
- else defn.RootClass
317
- )
318
-
319
- /** Establish a partial order "preference" order between symbols.
320
- * Give preference to `sym1` over `sym2` if one of the following
321
- * conditions holds, in decreasing order of weight:
322
- * 1. sym1 is concrete and sym2 is abstract
323
- * 2. The owner of sym1 comes before the owner of sym2 in the linearization
324
- * of the type of the prefix `pre`.
325
- * 3. The access boundary of sym2 is properly contained in the access
326
- * boundary of sym1. For protected access, we count the enclosing
327
- * package as access boundary.
328
- * 4. sym1 a method but sym2 is not.
329
- * The aim of these criteria is to give some disambiguation on access which
330
- * - does not depend on textual order or other arbitrary choices
331
- * - minimizes raising of doubleDef errors
332
- */
333
- def preferSym (sym1 : Symbol , sym2 : Symbol ) =
334
- sym1.eq(sym2) ||
335
- sym1.isAsConcrete(sym2) &&
336
- (! sym2.isAsConcrete(sym1) ||
337
- precedes(sym1.owner, sym2.owner) ||
338
- accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) ||
339
- sym1.is(Method ) && ! sym2.is(Method )) ||
340
- sym1.info.isErroneous
341
-
342
- /** Sym preference provided types also override */
343
- def prefer (sym1 : Symbol , sym2 : Symbol , info1 : Type , info2 : Type ) =
344
- preferSym(sym1, sym2) && info1.overrides(info2)
345
-
346
- def handleDoubleDef =
347
- if (preferSym(sym1, sym2)) denot1
348
- else if (preferSym(sym2, sym1)) denot2
349
- else doubleDefError(denot1, denot2, pre)
350
-
351
- if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2
352
- else {
353
- val sym1Accessible = sym1.isAccessibleFrom(pre)
354
- if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
355
- else if (sym1Accessible && sym2.exists && ! sym2Accessible) denot1
356
- else if (sym2Accessible && sym1.exists && ! sym1Accessible) denot2
357
- else if (isDoubleDef(sym1, sym2)) handleDoubleDef
358
- else {
359
- val sym =
360
- if (! sym1.exists) sym2
361
- else if (! sym2.exists) sym1
362
- else if (preferSym(sym2, sym1)) sym2
363
- else sym1
364
- val jointInfo =
365
- try
366
- if (safeIntersection)
367
- info1 safe_& info2
368
- else
369
- info1 & info2
370
- catch {
371
- case ex : MergeError =>
372
- if (pre.widen.classSymbol.is(Scala2x ) || ctx.scala2Mode)
373
- info1 // follow Scala2 linearization -
374
- // compare with way merge is performed in SymDenotation#computeMembersNamed
375
- else
376
- throw new MergeError (s " ${ex.getMessage} as members of type ${pre.show}" , ex.tp1, ex.tp2)
377
- }
378
- new JointRefDenotation (sym, jointInfo, denot1.validFor & denot2.validFor)
360
+ /** Try to merge single-denotations. */
361
+ def mergeSingleDenot (denot1 : SingleDenotation , denot2 : SingleDenotation ): SingleDenotation = {
362
+ val info1 = denot1.info
363
+ val info2 = denot2.info
364
+ val sym1 = denot1.symbol
365
+ val sym2 = denot2.symbol
366
+
367
+ val sym2Accessible = sym2.isAccessibleFrom(pre)
368
+
369
+ /** Does `sym1` come before `sym2` in the linearization of `pre`? */
370
+ def precedes (sym1 : Symbol , sym2 : Symbol ) = {
371
+ def precedesIn (bcs : List [ClassSymbol ]): Boolean = bcs match {
372
+ case bc :: bcs1 => (sym1 eq bc) || ! (sym2 eq bc) && precedesIn(bcs1)
373
+ case Nil => true
374
+ }
375
+ (sym1 ne sym2) &&
376
+ (sym1.derivesFrom(sym2) ||
377
+ ! sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses))
378
+ }
379
+
380
+ /** Similar to SymDenotation#accessBoundary, but without the special cases. */
381
+ def accessBoundary (sym : Symbol ) =
382
+ if (sym.is(Private )) sym.owner
383
+ else sym.privateWithin.orElse(
384
+ if (sym.is(Protected )) sym.owner.enclosingPackageClass
385
+ else defn.RootClass )
386
+
387
+ /** Establish a partial order "preference" order between symbols.
388
+ * Give preference to `sym1` over `sym2` if one of the following
389
+ * conditions holds, in decreasing order of weight:
390
+ * 1. sym1 is concrete and sym2 is abstract
391
+ * 2. The owner of sym1 comes before the owner of sym2 in the linearization
392
+ * of the type of the prefix `pre`.
393
+ * 3. The access boundary of sym2 is properly contained in the access
394
+ * boundary of sym1. For protected access, we count the enclosing
395
+ * package as access boundary.
396
+ * 4. sym1 a method but sym2 is not.
397
+ * The aim of these criteria is to give some disambiguation on access which
398
+ * - does not depend on textual order or other arbitrary choices
399
+ * - minimizes raising of doubleDef errors
400
+ */
401
+ def preferSym (sym1 : Symbol , sym2 : Symbol ) =
402
+ sym1.eq(sym2) ||
403
+ sym1.isAsConcrete(sym2) &&
404
+ (! sym2.isAsConcrete(sym1) ||
405
+ precedes(sym1.owner, sym2.owner) ||
406
+ accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) ||
407
+ sym1.is(Method ) && ! sym2.is(Method )) ||
408
+ sym1.info.isErroneous
409
+
410
+ /** Sym preference provided types also override */
411
+ def prefer (sym1 : Symbol , sym2 : Symbol , info1 : Type , info2 : Type ) =
412
+ preferSym(sym1, sym2) && info1.overrides(info2)
413
+
414
+ def handleDoubleDef =
415
+ if (preferSym(sym1, sym2)) denot1
416
+ else if (preferSym(sym2, sym1)) denot2
417
+ else doubleDefError(denot1, denot2, pre)
418
+
419
+ if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2
420
+ else {
421
+ val sym1Accessible = sym1.isAccessibleFrom(pre)
422
+ if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
423
+ else if (sym1Accessible && sym2.exists && ! sym2Accessible) denot1
424
+ else if (sym2Accessible && sym1.exists && ! sym1Accessible) denot2
425
+ else if (isDoubleDef(sym1, sym2)) handleDoubleDef
426
+ else {
427
+ val sym =
428
+ if (! sym1.exists) sym2
429
+ else if (! sym2.exists) sym1
430
+ else if (preferSym(sym2, sym1)) sym2
431
+ else sym1
432
+ val jointInfo =
433
+ try infoMeet(info1, info2)
434
+ catch {
435
+ case ex : MergeError =>
436
+ if (pre.widen.classSymbol.is(Scala2x ) || ctx.scala2Mode)
437
+ info1 // follow Scala2 linearization -
438
+ // compare with way merge is performed in SymDenotation#computeMembersNamed
439
+ else
440
+ throw new MergeError (s " ${ex.getMessage} as members of type ${pre.show}" , ex.tp1, ex.tp2)
379
441
}
380
- }
381
- } else NoDenotation
442
+ new JointRefDenotation (sym, jointInfo, denot1.validFor & denot2.validFor)
443
+ }
444
+ }
382
445
}
383
446
384
447
if (this eq that) this
@@ -399,6 +462,46 @@ object Denotations {
399
462
*/
400
463
def | (that : Denotation , pre : Type )(implicit ctx : Context ): Denotation = {
401
464
465
+ /** Normally, `tp1 | tp2`. Special cases for matching methods and classes, with
466
+ * the possibility of raising a merge error.
467
+ */
468
+ def infoJoin (tp1 : Type , tp2 : Type ): Type = tp1 match {
469
+ case tp1 : TypeBounds =>
470
+ tp2 match {
471
+ case tp2 : TypeBounds => tp1 | tp2
472
+ case tp2 : ClassInfo if tp1 contains tp2 => tp1
473
+ case _ => mergeConflict(tp1, tp2)
474
+ }
475
+ case tp1 : ClassInfo =>
476
+ tp2 match {
477
+ case tp2 : ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix | tp2.prefix)
478
+ case tp2 : TypeBounds if tp2 contains tp1 => tp2
479
+ case _ => mergeConflict(tp1, tp2)
480
+ }
481
+ case tp1 @ MethodType (names1, formals1) =>
482
+ tp2 match {
483
+ case tp2 @ MethodType (names2, formals2)
484
+ if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) &&
485
+ tp1.isImplicit == tp2.isImplicit =>
486
+ tp1.derivedMethodType(
487
+ mergeNames(names1, names2, nme.syntheticParamName),
488
+ formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1))
489
+ case _ =>
490
+ mergeConflict(tp1, tp2)
491
+ }
492
+ case tp1 : PolyType =>
493
+ tp2 match {
494
+ case tp2 : PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) =>
495
+ tp1.derivedPolyType(
496
+ mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
497
+ tp1.paramBounds, tp1.resultType | tp2.resultType.subst(tp2, tp1))
498
+ case _ =>
499
+ mergeConflict(tp1, tp2)
500
+ }
501
+ case _ =>
502
+ tp1 | tp2
503
+ }
504
+
402
505
def unionDenot (denot1 : SingleDenotation , denot2 : SingleDenotation ): Denotation =
403
506
if (denot1.matches(denot2)) {
404
507
val sym1 = denot1.symbol
@@ -428,7 +531,8 @@ object Denotations {
428
531
}
429
532
lubSym(sym1.allOverriddenSymbols, NoSymbol )
430
533
}
431
- new JointRefDenotation (jointSym, info1 | info2, denot1.validFor & denot2.validFor)
534
+ new JointRefDenotation (
535
+ jointSym, infoJoin(info1, info2), denot1.validFor & denot2.validFor)
432
536
}
433
537
}
434
538
else NoDenotation
@@ -1134,5 +1238,4 @@ object Denotations {
1134
1238
util.Stats .record(" not defined here" )
1135
1239
override def getMessage () = msg
1136
1240
}
1137
- }
1138
-
1241
+ }
0 commit comments