Skip to content

Commit 4095410

Browse files
authored
Merge pull request #1953 from dotty-staging/fix-wildapprox
Fix to wildapprox
2 parents b77c24c + 937cca0 commit 4095410

File tree

6 files changed

+66
-40
lines changed

6 files changed

+66
-40
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ object Implicits {
6969
case mt: MethodType =>
7070
mt.isImplicit ||
7171
mt.paramTypes.length != 1 ||
72-
!(argType relaxed_<:< wildApprox(mt.paramTypes.head)(ctx.fresh.setExploreTyperState))
72+
!(argType relaxed_<:< wildApprox(mt.paramTypes.head, null, Set.empty)(ctx.fresh.setExploreTyperState))
7373
case rtp =>
74-
discardForView(wildApprox(rtp), argType)
74+
discardForView(wildApprox(rtp, null, Set.empty), argType)
7575
}
7676
case tpw: TermRef =>
7777
false // can't discard overloaded refs
@@ -653,7 +653,7 @@ trait Implicits { self: Typer =>
653653
}
654654

655655
/** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
656-
val wildProto = implicitProto(pt, wildApprox(_))
656+
val wildProto = implicitProto(pt, wildApprox(_, null, Set.empty))
657657

658658
/** Search failures; overridden in ExplainedImplicitSearch */
659659
protected def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]): SearchFailure = NoImplicitMatches

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ class Namer { typer: Typer =>
972972
ctx.defContext(sym).denotNamed(original)
973973
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
974974
case params :: paramss1 =>
975-
if (idx < params.length) wildApprox(params(idx))
975+
if (idx < params.length) wildApprox(params(idx), null, Set.empty)
976976
else paramProto(paramss1, idx - params.length)
977977
case nil =>
978978
WildcardType

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

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -437,65 +437,82 @@ object ProtoTypes {
437437
/** Approximate occurrences of parameter types and uninstantiated typevars
438438
* by wildcard types.
439439
*/
440-
final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match {
440+
final def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[PolyParam])(implicit ctx: Context): Type = tp match {
441441
case tp: NamedType => // default case, inlined for speed
442442
if (tp.symbol.isStatic) tp
443-
else tp.derivedSelect(wildApprox(tp.prefix, theMap))
443+
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen))
444444
case tp: RefinedType => // default case, inlined for speed
445-
tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
445+
tp.derivedRefinedType(
446+
wildApprox(tp.parent, theMap, seen),
447+
tp.refinedName,
448+
wildApprox(tp.refinedInfo, theMap, seen))
446449
case tp: TypeAlias => // default case, inlined for speed
447-
tp.derivedTypeAlias(wildApprox(tp.alias, theMap))
450+
tp.derivedTypeAlias(wildApprox(tp.alias, theMap, seen))
448451
case tp @ PolyParam(poly, pnum) =>
449-
def unconstrainedApprox = WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)
450-
if (ctx.mode.is(Mode.TypevarsMissContext))
451-
unconstrainedApprox
452-
else
453-
ctx.typerState.constraint.entry(tp) match {
454-
case bounds: TypeBounds => wildApprox(WildcardType(bounds))
455-
case NoType => unconstrainedApprox
456-
case inst => wildApprox(inst)
457-
}
452+
def wildApproxBounds(bounds: TypeBounds) =
453+
if (bounds.lo.isInstanceOf[NamedType] && bounds.hi.isInstanceOf[NamedType])
454+
WildcardType(wildApprox(bounds, theMap, seen).bounds)
455+
else if (seen.contains(tp)) WildcardType
456+
else WildcardType(wildApprox(bounds, theMap, seen + tp).bounds)
457+
def unconstrainedApprox = wildApproxBounds(poly.paramBounds(pnum))
458+
def approxPoly =
459+
if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox
460+
else
461+
ctx.typerState.constraint.entry(tp) match {
462+
case bounds: TypeBounds => wildApproxBounds(bounds)
463+
case NoType => unconstrainedApprox
464+
case inst => wildApprox(inst, theMap, seen)
465+
}
466+
approxPoly
458467
case MethodParam(mt, pnum) =>
459-
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
468+
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum), theMap, seen)))
460469
case tp: TypeVar =>
461-
wildApprox(tp.underlying)
470+
wildApprox(tp.underlying, theMap, seen)
462471
case tp @ HKApply(tycon, args) =>
463-
wildApprox(tycon) match {
472+
wildApprox(tycon, theMap, seen) match {
464473
case _: WildcardType => WildcardType // this ensures we get a * type
465-
case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_)))
474+
case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_, theMap, seen)))
466475
}
467476
case tp: AndType =>
468-
val tp1a = wildApprox(tp.tp1)
469-
val tp2a = wildApprox(tp.tp2)
470-
def wildBounds(tp: Type) =
471-
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
472-
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
473-
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
474-
else
475-
tp.derivedAndType(tp1a, tp2a)
477+
def approxAnd = {
478+
val tp1a = wildApprox(tp.tp1, theMap, seen)
479+
val tp2a = wildApprox(tp.tp2, theMap, seen)
480+
def wildBounds(tp: Type) =
481+
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
482+
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
483+
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
484+
else
485+
tp.derivedAndType(tp1a, tp2a)
486+
}
487+
approxAnd
476488
case tp: OrType =>
477-
val tp1a = wildApprox(tp.tp1)
478-
val tp2a = wildApprox(tp.tp2)
479-
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
480-
WildcardType(tp1a.bounds | tp2a.bounds)
481-
else
482-
tp.derivedOrType(tp1a, tp2a)
489+
def approxOr = {
490+
val tp1a = wildApprox(tp.tp1, theMap, seen)
491+
val tp2a = wildApprox(tp.tp2, theMap, seen)
492+
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
493+
WildcardType(tp1a.bounds | tp2a.bounds)
494+
else
495+
tp.derivedOrType(tp1a, tp2a)
496+
}
497+
approxOr
483498
case tp: LazyRef =>
484499
WildcardType
485500
case tp: SelectionProto =>
486-
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto), NoViewsAllowed)
501+
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen), NoViewsAllowed)
487502
case tp: ViewProto =>
488-
tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType))
503+
tp.derivedViewProto(
504+
wildApprox(tp.argType, theMap, seen),
505+
wildApprox(tp.resultType, theMap, seen))
489506
case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
490507
tp
491508
case _ =>
492-
(if (theMap != null) theMap else new WildApproxMap).mapOver(tp)
509+
(if (theMap != null) theMap else new WildApproxMap(seen)).mapOver(tp)
493510
}
494511

495512
@sharable object AssignProto extends UncachedGroundType with MatchAlways
496513

497-
private[ProtoTypes] class WildApproxMap(implicit ctx: Context) extends TypeMap {
498-
def apply(tp: Type) = wildApprox(tp, this)
514+
private[ProtoTypes] class WildApproxMap(val seen: Set[PolyParam])(implicit ctx: Context) extends TypeMap {
515+
def apply(tp: Type) = wildApprox(tp, this, seen)
499516
}
500517

501518
/** Dummy tree to be used as an argument of a FunProto or ViewProto type */

tests/pos/f-bounded-case-class.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
case class Test[X <: List[Y], Y <: List[X]](x: X, y: Y)

tests/run/t10170.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
100

tests/run/t10170.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object Test {
2+
def main(args: Array[String]) = println(f)
3+
4+
def f = {
5+
val a = 100; ({ val a = 0; (c: Int) => c })(a)
6+
}
7+
}

0 commit comments

Comments
 (0)