Skip to content

Commit 3d03ae4

Browse files
committed
WIP: Preserve bounds in wildApprox for the implicit scope search
This does not work for i553-shuffle.scala because of scala#732
1 parent b2d0288 commit 3d03ae4

File tree

4 files changed

+44
-34
lines changed

4 files changed

+44
-34
lines changed

src/dotty/tools/dotc/core/Types.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,7 @@ object Types {
832832
*
833833
* (*) normalizes means: follow instantiated typevars and aliases.
834834
*/
835-
def lookupRefined(name: Name)(implicit ctx: Context): Type = {
835+
def lookupRefined(name: Name, keepAllBounds: Boolean = false)(implicit ctx: Context): Type = /*ctx.traceIndented(i"lookupRefined($name, $keepAllBounds)", default, show = true)*/ {
836836
def loop(pre: Type, resolved: List[Name]): Type = pre.stripTypeVar match {
837837
case pre: RefinedType =>
838838
object instantiate extends TypeMap {
@@ -861,16 +861,20 @@ object Types {
861861
if (pre.refinedName ne name) loop(pre.parent, pre.refinedName :: resolved)
862862
else if (!pre.refinementRefersToThis) alias
863863
else alias match {
864-
case TypeRef(RefinedThis(`pre`), aliasName) => lookupRefined(aliasName) // (1)
865-
case _ => if (name == tpnme.Apply) betaReduce(alias) else NoType // (2)
864+
case TypeRef(RefinedThis(`pre`), aliasName) =>
865+
lookupRefined(aliasName, keepAllBounds) // (1)
866+
case _ =>
867+
if (name == tpnme.Apply) betaReduce(alias) else NoType // (2)
866868
}
867869
case _ => loop(pre.parent, resolved)
868870
}
869871
case RefinedThis(binder) =>
870-
binder.lookupRefined(name)
872+
binder.lookupRefined(name, keepAllBounds)
871873
case SkolemType(tp) =>
872-
tp.lookupRefined(name)
873-
case pre: WildcardType =>
874+
tp.lookupRefined(name, keepAllBounds)
875+
case WildcardType =>
876+
WildcardType
877+
case pre: WildcardType if !keepAllBounds =>
874878
WildcardType
875879
case pre: TypeRef =>
876880
pre.info match {
@@ -1476,10 +1480,10 @@ object Types {
14761480
ctx.underlyingRecursions -= 1
14771481
}
14781482

1479-
def derivedSelect(prefix: Type)(implicit ctx: Context): Type =
1483+
def derivedSelect(prefix: Type, keepAllBounds: Boolean = false)(implicit ctx: Context): Type =
14801484
if (prefix eq this.prefix) this
14811485
else {
1482-
val res = prefix.lookupRefined(name)
1486+
val res = prefix.lookupRefined(name, keepAllBounds)
14831487
if (res.exists) res else newLikeThis(prefix)
14841488
}
14851489

src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ object Implicits {
9595
}
9696

9797
/** The implicit references coming from the implicit scope of a type.
98-
* @param tp the type determining the implicit scope
98+
* @param tp the expected type used to filter the implicits in the implicit scope
9999
* @param companionRefs the companion objects in the implicit scope.
100100
*/
101101
class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) {
@@ -264,7 +264,7 @@ trait ImplicitRunInfo { self: RunInfo =>
264264
* a type variable, we need the current context, the current
265265
* runinfo context does not do.
266266
*/
267-
def implicitScope(tp: Type, liftingCtx: Context): OfTypeImplicits = {
267+
def implicitScope(boundedTp: Type, wildTp: Type, liftingCtx: Context): OfTypeImplicits = {
268268

269269
val seen: mutable.Set[Type] = mutable.Set()
270270

@@ -332,7 +332,7 @@ trait ImplicitRunInfo { self: RunInfo =>
332332
}
333333
}
334334

335-
def ofTypeImplicits(comps: TermRefSet) = new OfTypeImplicits(tp, comps)(ctx)
335+
def ofTypeImplicits(comps: TermRefSet) = new OfTypeImplicits(wildTp, comps)(ctx)
336336

337337
/** The implicit scope of type `tp`
338338
* @param isLifted Type `tp` is the result of a `liftToClasses` application
@@ -361,7 +361,7 @@ trait ImplicitRunInfo { self: RunInfo =>
361361
}
362362
}
363363

364-
iscope(tp)
364+
iscope(boundedTp)
365365
}
366366

367367
/** A map that counts the number of times an implicit ref was picked */
@@ -463,7 +463,7 @@ trait Implicits { self: Typer =>
463463
case proto => proto
464464
}
465465

466-
/** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
466+
val boundedProto = implicitProto(pt, wildApprox(_, new WildApproxMap(keepAllBounds = true)))
467467
val wildProto = implicitProto(pt, wildApprox(_))
468468

469469
/** Search failures; overridden in ExplainedImplicitSearch */
@@ -569,11 +569,12 @@ trait Implicits { self: Typer =>
569569
case result: SearchSuccess => result
570570
case result: AmbiguousImplicits => result
571571
case result: SearchFailure =>
572-
searchImplicits(implicitScope(wildProto).eligible, contextual = false)
572+
searchImplicits(implicitScope(boundedProto, wildProto).eligible, contextual = false)
573573
}
574574
}
575575

576-
def implicitScope(tp: Type): OfTypeImplicits = ctx.runInfo.implicitScope(tp, ctx)
576+
def implicitScope(boundedTp: Type, wildTp: Type): OfTypeImplicits =
577+
ctx.runInfo.implicitScope(boundedTp, wildTp, ctx)
577578
}
578579

579580
final class ExplainedImplicitSearch(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context)

src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -381,51 +381,57 @@ object ProtoTypes {
381381
/** Approximate occurrences of parameter types and uninstantiated typevars
382382
* by wildcard types.
383383
*/
384-
final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match {
385-
case tp: NamedType => // default case, inlined for speed
384+
final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = /*ctx.traceIndented(i"wildApprox($tp, ${if (theMap != null) theMap.keepAllBounds else false})", default, show = true)*/ { tp match {
385+
case tp: NamedType =>
386386
if (tp.symbol.isStatic) tp
387-
else tp.derivedSelect(wildApprox(tp.prefix, theMap))
387+
else {
388+
val pre = wildApprox(tp.prefix, theMap)
389+
if (theMap != null)
390+
tp.derivedSelect(pre, theMap.keepAllBounds)
391+
else
392+
tp.derivedSelect(pre)
393+
}
388394
case tp: RefinedType => // default case, inlined for speed
389395
tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
390396
case tp: TypeAlias => // default case, inlined for speed
391397
tp.derivedTypeAlias(wildApprox(tp.alias, theMap))
392398
case tp @ PolyParam(poly, pnum) =>
393399
ctx.typerState.constraint.entry(tp) match {
394-
case bounds: TypeBounds => wildApprox(WildcardType(bounds))
395-
case NoType => WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)
396-
case inst => wildApprox(inst)
400+
case bounds: TypeBounds => wildApprox(WildcardType(bounds), theMap)
401+
case NoType => WildcardType(wildApprox(poly.paramBounds(pnum), theMap).bounds)
402+
case inst => wildApprox(inst, theMap)
397403
}
398404
case MethodParam(mt, pnum) =>
399-
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
405+
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum), theMap)))
400406
case tp: TypeVar =>
401-
wildApprox(tp.underlying)
407+
wildApprox(tp.underlying, theMap)
402408
case tp: AndType =>
403-
val tp1a = wildApprox(tp.tp1)
404-
val tp2a = wildApprox(tp.tp2)
409+
val tp1a = wildApprox(tp.tp1, theMap)
410+
val tp2a = wildApprox(tp.tp2, theMap)
405411
def wildBounds(tp: Type) =
406412
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
407413
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
408414
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
409415
else
410416
tp.derivedAndType(tp1a, tp2a)
411417
case tp: OrType =>
412-
val tp1a = wildApprox(tp.tp1)
413-
val tp2a = wildApprox(tp.tp2)
418+
val tp1a = wildApprox(tp.tp1, theMap)
419+
val tp2a = wildApprox(tp.tp2, theMap)
414420
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
415421
WildcardType(tp1a.bounds | tp2a.bounds)
416422
else
417423
tp.derivedOrType(tp1a, tp2a)
418424
case tp: SelectionProto =>
419-
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto), NoViewsAllowed)
425+
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap), NoViewsAllowed)
420426
case tp: ViewProto =>
421-
tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType))
427+
tp.derivedViewProto(wildApprox(tp.argType, theMap), wildApprox(tp.resultType, theMap))
422428
case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
423429
tp
424430
case _ =>
425431
(if (theMap != null) theMap else new WildApproxMap).mapOver(tp)
426-
}
432+
} }
427433

428-
private[ProtoTypes] class WildApproxMap(implicit ctx: Context) extends TypeMap {
434+
private[dotty] class WildApproxMap(val keepAllBounds: Boolean = false)(implicit ctx: Context) extends TypeMap {
429435
def apply(tp: Type) = wildApprox(tp, this)
430436
}
431437

tests/pos/i553-shuffle.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import scala.util.Random
2-
import scala.collection.immutable.List._
32
object Test {
43
def test = {
5-
val rand = new Random
6-
rand.shuffle(List(1,2))//(List.canBuildFrom[Int]) // fails
4+
val rand: Random = new Random
5+
rand.shuffle(List(1,2))// infers implicit argument list (List.canBuildFrom[Int])
76
}
87
}

0 commit comments

Comments
 (0)