Skip to content

Commit 7b2c3cb

Browse files
committed
Merge pull request scala#3995 from retronym/ticket/8267
SI-8267 Avoid existentials after polymorphic overload resolution
2 parents c1492ac + ee2b7d6 commit 7b2c3cb

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
11001100
adaptConstant(value)
11011101
case OverloadedType(pre, alts) if !mode.inFunMode => // (1)
11021102
inferExprAlternative(tree, pt)
1103-
adapt(tree, mode, pt, original)
1103+
adaptAfterOverloadResolution(tree, mode, pt, original)
11041104
case NullaryMethodType(restpe) => // (2)
11051105
adapt(tree setType restpe, mode, pt, original)
11061106
case TypeRef(_, ByNameParamClass, arg :: Nil) if mode.inExprMode => // (2)
@@ -1133,6 +1133,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
11331133
}
11341134
}
11351135

1136+
// This just exists to help keep track of the spots where we have to adapt a tree after
1137+
// overload resolution. These proved hard to find during the fix for SI-8267.
1138+
def adaptAfterOverloadResolution(tree: Tree, mode: Mode, pt: Type = WildcardType, original: Tree = EmptyTree): Tree = {
1139+
adapt(tree, mode, pt, original)
1140+
}
1141+
11361142
def instantiate(tree: Tree, mode: Mode, pt: Type): Tree = {
11371143
inferExprInstance(tree, context.extractUndetparams(), pt)
11381144
adapt(tree, mode, pt)
@@ -3171,7 +3177,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
31713177
if (sym1 != NoSymbol) sym = sym1
31723178
}
31733179
if (sym == NoSymbol) fun
3174-
else adapt(fun setSymbol sym setType pre.memberType(sym), mode.forFunMode, WildcardType)
3180+
else adaptAfterOverloadResolution(fun setSymbol sym setType pre.memberType(sym), mode.forFunMode)
31753181
} else fun
31763182
}
31773183

@@ -3216,7 +3222,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
32163222
setError(tree)
32173223
else {
32183224
inferMethodAlternative(fun, undetparams, argTpes, pt)
3219-
doTypedApply(tree, adapt(fun, mode.forFunMode, WildcardType), args1, mode, pt)
3225+
doTypedApply(tree, adaptAfterOverloadResolution(fun, mode.forFunMode, WildcardType), args1, mode, pt)
32203226
}
32213227
}
32223228
handleOverloaded
@@ -3799,7 +3805,18 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
37993805
protected def typedTypeApply(tree: Tree, mode: Mode, fun: Tree, args: List[Tree]): Tree = fun.tpe match {
38003806
case OverloadedType(pre, alts) =>
38013807
inferPolyAlternatives(fun, mapList(args)(treeTpe))
3802-
val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree)
3808+
3809+
// SI-8267 `memberType` can introduce existentials *around* a PolyType/MethodType, see AsSeenFromMap#captureThis.
3810+
// If we had selected a non-overloaded symbol, `memberType` would have been called in `makeAccessible`
3811+
// and the resulting existential type would have been skolemized in `adapt` *before* we typechecked
3812+
// the enclosing type-/ value- application.
3813+
//
3814+
// However, if the selection is overloaded, we defer calling `memberType` until we can select a single
3815+
// alternative here. It is therefore necessary to skolemize the existential here.
3816+
//
3817+
val fun1 = adaptAfterOverloadResolution(fun, mode.forFunMode | TAPPmode)
3818+
3819+
val tparams = fun1.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree)
38033820
val args1 = if (sameLength(args, tparams)) {
38043821
//@M: in case TypeApply we can't check the kind-arities of the type arguments,
38053822
// as we don't know which alternative to choose... here we do
@@ -3813,7 +3830,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
38133830
// ...actually this was looping anyway, see bug #278.
38143831
return TypedApplyWrongNumberOfTpeParametersError(fun, fun)
38153832

3816-
typedTypeApply(tree, mode, fun, args1)
3833+
typedTypeApply(tree, mode, fun1, args1)
38173834
case SingleType(_, _) =>
38183835
typedTypeApply(tree, mode, fun setType fun.tpe.widen, args)
38193836
case PolyType(tparams, restpe) if tparams.nonEmpty =>

test/files/pos/t8267.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Bippy { trait Foo[A] }
2+
3+
final class RichBippy[C <: Bippy with Singleton](val c1: C) {
4+
def f: Int = 1
5+
def f[A](x: A)(ev: c1.Foo[A]): Int = 2
6+
7+
def g[A <: Nothing](x: A): Int = 1
8+
def g[A](x: A)(ev: c1.Foo[A]): Int = 2
9+
10+
def h[A](x: A)(ev: c1.Foo[A]): Int = 1
11+
12+
def i(x: Nothing): Int = 1
13+
def i(x: AnyRef)(ev: c1.Foo[x.type]): Int = 2
14+
}
15+
16+
object p {
17+
18+
val c = new Bippy
19+
val d0 = new RichBippy[c.type](c)
20+
def d1 = new RichBippy[c.type](c)
21+
22+
d0.f[Int](5)(null: c.Foo[Int]) // ok
23+
d1.f[Int](5)(null: c.Foo[Int]) // fails
24+
25+
d0.g[Int](5)(null: c.Foo[Int]) // ok
26+
d1.g[Int](5)(null: c.Foo[Int]) // fails
27+
28+
d0.h[Int](5)(null: c.Foo[Int]) // ok
29+
d1.h[Int](5)(null: c.Foo[Int]) // ok
30+
31+
d0.i("")(null) // ok
32+
d1.i("")(null) // ok
33+
}

0 commit comments

Comments
 (0)