Skip to content

Fix to wildapprox #1953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ object Implicits {
case mt: MethodType =>
mt.isImplicit ||
mt.paramTypes.length != 1 ||
!(argType relaxed_<:< wildApprox(mt.paramTypes.head)(ctx.fresh.setExploreTyperState))
!(argType relaxed_<:< wildApprox(mt.paramTypes.head, null, Set.empty)(ctx.fresh.setExploreTyperState))
case rtp =>
discardForView(wildApprox(rtp), argType)
discardForView(wildApprox(rtp, null, Set.empty), argType)
}
case tpw: TermRef =>
false // can't discard overloaded refs
Expand Down Expand Up @@ -649,7 +649,7 @@ trait Implicits { self: Typer =>
}

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

/** Search failures; overridden in ExplainedImplicitSearch */
protected def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]): SearchFailure = NoImplicitMatches
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ class Namer { typer: Typer =>
ctx.defContext(sym).denotNamed(original)
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
case params :: paramss1 =>
if (idx < params.length) wildApprox(params(idx))
if (idx < params.length) wildApprox(params(idx), null, Set.empty)
else paramProto(paramss1, idx - params.length)
case nil =>
WildcardType
Expand Down
89 changes: 53 additions & 36 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -437,65 +437,82 @@ object ProtoTypes {
/** Approximate occurrences of parameter types and uninstantiated typevars
* by wildcard types.
*/
final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match {
final def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[PolyParam])(implicit ctx: Context): Type = tp match {
case tp: NamedType => // default case, inlined for speed
if (tp.symbol.isStatic) tp
else tp.derivedSelect(wildApprox(tp.prefix, theMap))
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen))
case tp: RefinedType => // default case, inlined for speed
tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
tp.derivedRefinedType(
wildApprox(tp.parent, theMap, seen),
tp.refinedName,
wildApprox(tp.refinedInfo, theMap, seen))
case tp: TypeAlias => // default case, inlined for speed
tp.derivedTypeAlias(wildApprox(tp.alias, theMap))
tp.derivedTypeAlias(wildApprox(tp.alias, theMap, seen))
case tp @ PolyParam(poly, pnum) =>
def unconstrainedApprox = WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)
if (ctx.mode.is(Mode.TypevarsMissContext))
unconstrainedApprox
else
ctx.typerState.constraint.entry(tp) match {
case bounds: TypeBounds => wildApprox(WildcardType(bounds))
case NoType => unconstrainedApprox
case inst => wildApprox(inst)
}
def wildApproxBounds(bounds: TypeBounds) =
if (bounds.lo.isInstanceOf[NamedType] && bounds.hi.isInstanceOf[NamedType])
WildcardType(wildApprox(bounds, theMap, seen).bounds)
else if (seen.contains(tp)) WildcardType
else WildcardType(wildApprox(bounds, theMap, seen + tp).bounds)
def unconstrainedApprox = wildApproxBounds(poly.paramBounds(pnum))
def approxPoly =
if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox
else
ctx.typerState.constraint.entry(tp) match {
case bounds: TypeBounds => wildApproxBounds(bounds)
case NoType => unconstrainedApprox
case inst => wildApprox(inst, theMap, seen)
}
approxPoly
case MethodParam(mt, pnum) =>
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum), theMap, seen)))
case tp: TypeVar =>
wildApprox(tp.underlying)
wildApprox(tp.underlying, theMap, seen)
case tp @ HKApply(tycon, args) =>
wildApprox(tycon) match {
wildApprox(tycon, theMap, seen) match {
case _: WildcardType => WildcardType // this ensures we get a * type
case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_)))
case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_, theMap, seen)))
}
case tp: AndType =>
val tp1a = wildApprox(tp.tp1)
val tp2a = wildApprox(tp.tp2)
def wildBounds(tp: Type) =
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
else
tp.derivedAndType(tp1a, tp2a)
def approxAnd = {
val tp1a = wildApprox(tp.tp1, theMap, seen)
val tp2a = wildApprox(tp.tp2, theMap, seen)
def wildBounds(tp: Type) =
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
else
tp.derivedAndType(tp1a, tp2a)
}
approxAnd
case tp: OrType =>
val tp1a = wildApprox(tp.tp1)
val tp2a = wildApprox(tp.tp2)
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
WildcardType(tp1a.bounds | tp2a.bounds)
else
tp.derivedOrType(tp1a, tp2a)
def approxOr = {
val tp1a = wildApprox(tp.tp1, theMap, seen)
val tp2a = wildApprox(tp.tp2, theMap, seen)
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
WildcardType(tp1a.bounds | tp2a.bounds)
else
tp.derivedOrType(tp1a, tp2a)
}
approxOr
case tp: LazyRef =>
WildcardType
case tp: SelectionProto =>
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto), NoViewsAllowed)
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen), NoViewsAllowed)
case tp: ViewProto =>
tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType))
tp.derivedViewProto(
wildApprox(tp.argType, theMap, seen),
wildApprox(tp.resultType, theMap, seen))
case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
tp
case _ =>
(if (theMap != null) theMap else new WildApproxMap).mapOver(tp)
(if (theMap != null) theMap else new WildApproxMap(seen)).mapOver(tp)
}

@sharable object AssignProto extends UncachedGroundType with MatchAlways

private[ProtoTypes] class WildApproxMap(implicit ctx: Context) extends TypeMap {
def apply(tp: Type) = wildApprox(tp, this)
private[ProtoTypes] class WildApproxMap(val seen: Set[PolyParam])(implicit ctx: Context) extends TypeMap {
def apply(tp: Type) = wildApprox(tp, this, seen)
}

/** Dummy tree to be used as an argument of a FunProto or ViewProto type */
Expand Down
1 change: 1 addition & 0 deletions tests/pos/f-bounded-case-class.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
case class Test[X <: List[Y], Y <: List[X]](x: X, y: Y)
1 change: 1 addition & 0 deletions tests/run/t10170.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
100
7 changes: 7 additions & 0 deletions tests/run/t10170.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
object Test {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A check-file corresponding to this test is missing.

def main(args: Array[String]) = println(f)

def f = {
val a = 100; ({ val a = 0; (c: Int) => c })(a)
}
}