Skip to content

Fix #1515: Don't narrow gadt bounds when frozen #1598

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 1 commit into from
Oct 14, 2016
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
43 changes: 22 additions & 21 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -965,28 +965,29 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* Test that the resulting bounds are still satisfiable.
*/
private def narrowGADTBounds(tr: NamedType, bound: Type, isUpper: Boolean): Boolean =
ctx.mode.is(Mode.GADTflexible) && {
val tparam = tr.symbol
typr.println(i"narrow gadt bound of $tparam: ${tparam.info} from ${if (isUpper) "above" else "below"} to $bound ${bound.isRef(tparam)}")
if (bound.isRef(tparam)) false
else bound match {
case bound: TypeRef
if bound.symbol.is(BindDefinedType) && ctx.gadt.bounds.contains(bound.symbol) &&
!tr.symbol.is(BindDefinedType) =>
// Avoid having pattern-bound types in gadt bounds,
// as these might be eliminated once the pattern is typechecked.
// Pattern-bound type symbols should be narrowed first, only if that fails
// should symbols in the environment be constrained.
narrowGADTBounds(bound, tr, !isUpper)
case _ =>
val oldBounds = ctx.gadt.bounds(tparam)
val newBounds =
if (isUpper) TypeBounds(oldBounds.lo, oldBounds.hi & bound)
else TypeBounds(oldBounds.lo | bound, oldBounds.hi)
isSubType(newBounds.lo, newBounds.hi) &&
{ ctx.gadt.setBounds(tparam, newBounds); true }
ctx.mode.is(Mode.GADTflexible) && !frozenConstraint && {
val tparam = tr.symbol
typr.println(i"narrow gadt bound of $tparam: ${tparam.info} from ${if (isUpper) "above" else "below"} to $bound ${bound.isRef(tparam)}")
if (bound.isRef(tparam)) false
else bound match {
case bound: TypeRef
if bound.symbol.is(BindDefinedType) &&
ctx.gadt.bounds.contains(bound.symbol) &&
!tr.symbol.is(BindDefinedType) =>
// Avoid having pattern-bound types in gadt bounds,
// as these might be eliminated once the pattern is typechecked.
// Pattern-bound type symbols should be narrowed first, only if that fails
// should symbols in the environment be constrained.
narrowGADTBounds(bound, tr, !isUpper)
case _ =>
val oldBounds = ctx.gadt.bounds(tparam)
val newBounds =
if (isUpper) TypeBounds(oldBounds.lo, oldBounds.hi & bound)
else TypeBounds(oldBounds.lo | bound, oldBounds.hi)
isSubType(newBounds.lo, newBounds.hi) &&
{ ctx.gadt.setBounds(tparam, newBounds); true }
}
}
}

// Tests around `matches`

Expand Down
16 changes: 16 additions & 0 deletions tests/pos/i1515.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
sealed trait Trait[T]

final case class Case[T](e: T) extends Trait[T]

object Demo {
def main(args: Array[String]): Unit = {

def f[H](t: Trait[H]): Unit =
t match {
case Case(e) => println(Some(e))
}

f(Case(1))

}
}