Skip to content

Fix #2675: Properly handle undetermined type variables in unapply #3889

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 13 commits into from
Feb 1, 2018
3 changes: 0 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,6 @@ object Flags {
/** A method that has default params */
final val DefaultParameterized = termFlag(27, "<defaultparam>")

/** A type that is defined by a type bind */
final val BindDefinedType = typeFlag(27, "<bind-defined>")

/** Symbol is inlined */
final val Inline = commonFlag(29, "inline")

Expand Down
24 changes: 7 additions & 17 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1077,23 +1077,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
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 }
else {
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 }
}
}

Expand Down
19 changes: 4 additions & 15 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,6 @@ class TreePickler(pickler: TastyPickler) {
pickleConstant(value)
case tpe: NamedType =>
val sym = tpe.symbol
def pickleDirectRef() = {
writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
pickleSymRef(sym)
}
def pickleExternalRef(sym: Symbol) = {
def pickleCore() = {
pickleNameAndSig(sym.name, tpe.signature)
Expand All @@ -188,17 +184,10 @@ class TreePickler(pickler: TastyPickler) {
writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg)
pickleName(sym.fullName)
}
else if (tpe.prefix == NoPrefix)
if (sym is Flags.BindDefinedType) {
registerDef(sym)
writeByte(BIND)
withLength {
pickleName(sym.name)
pickleType(sym.info)
pickleDirectRef()
}
}
else pickleDirectRef()
else if (tpe.prefix == NoPrefix) {
writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
pickleSymRef(sym)
}
else if (isLocallyDefined(sym)) {
writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol)
pickleSymRef(sym); pickleType(tpe.prefix)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ class TreeUnpickler(reader: TastyReader,
case SUPERtype =>
SuperType(readType(), readType())
case BIND =>
val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType(),
val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, EmptyFlags, readType(),
coord = coordAt(start))
registerSym(start, sym)
if (currentAddr != end) readType()
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,7 @@ class Typer extends Namer
// with an expected type in typedTyped. The type symbol is eliminated once
// the enclosing pattern has been typechecked; see `indexPattern` in `typedCase`.
val wildcardSym = ctx.newPatternBoundSymbol(tpnme.WILDCARD, tree1.tpe, tree.pos)
untpd.Bind(name, tree1).withType(wildcardSym.typeRef)
untpd.Bind(tpnme.WILDCARD, tree1).withType(wildcardSym.typeRef)
}
else tree1
}
Expand Down
59 changes: 59 additions & 0 deletions tests/pickling/i0290-type-bind.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
object foo{
val x = List(1,2,3)
x match {
case t: List[tt] => t.head.asInstanceOf[tt]
}
}

object bar {

class C[T <: Seq[_]]

val x: AnyRef = new C

x match {
case x: C[u] =>
def x: u = x
val s: Seq[_] = x
}
}

object foo2{{
val x = List(1,2,3)
x match {
case t: List[tt] => t.head.asInstanceOf[tt]
}
}}

object bar2 {{

class C[T <: Seq[_]]

val x: AnyRef = new C

x match {
case x: C[u] =>
def x: u = x
val s: Seq[_] = x
}
}}

object foo3{ val x0 = {
val x = List(1,2,3)
x match {
case t: List[tt] => t.head.asInstanceOf[tt]
}
}}

object bar3 { def f0 = {

class C[T <: Seq[_]]

val x: AnyRef = new C

x match {
case x: C[u] =>
def x: u = x
Copy link
Member

Choose a reason for hiding this comment

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

Is the self-recursive call intended here?

Copy link
Contributor Author

@odersky odersky Jan 23, 2018

Choose a reason for hiding this comment

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

I assume so, it was an old test in pos. The new test in pickling adds more variations that exercise forward binds in pickling.

val s: Seq[_] = x
}
}}