Skip to content

Commit

Permalink
Do expected type widening only in final classes
Browse files Browse the repository at this point in the history
Alex found a counter-example why this is required. See map5 in
neg-customargs/captures/lazylists2.scala
  • Loading branch information
odersky committed Oct 5, 2021
1 parent facd751 commit 5f407b3
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 10 deletions.
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/CheckCaptures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ class CheckCaptures extends Recheck:
override def recheckRHS(tree: Tree, pt: Type, sym: Symbol)(using Context): Type =
val pt1 = pt match
case CapturingType(core, refs, _)
if sym.owner.isClass && refs.elems.contains(sym.owner.thisType) =>
if sym.owner.isClass && !sym.owner.isExtensibleClass
&& refs.elems.contains(sym.owner.thisType) =>
val paramCaptures =
sym.paramSymss.flatten.foldLeft(CaptureSet.empty) { (cs, p) =>
val pcs = p.info.captureSet
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/lazylists1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object LazyNil extends LazyList[Nothing]:

extension [A](xs: {*} LazyList[A])
def map[B](f: {*} A => B): {xs, f} LazyList[B] =
class Mapped extends LazyList[B]:
final class Mapped extends LazyList[B]:
this: ({xs, f} Mapped) =>

def isEmpty = false
Expand Down
11 changes: 9 additions & 2 deletions tests/neg-custom-args/captures/lazylists2.check
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

longer explanation available when compiling with `-explain`
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:18:4 ------------------------------------
18 | class Mapped extends LazyList[B]: // error
18 | final class Mapped extends LazyList[B]: // error
| ^
| Found: {f, xs} LazyList[B]
| Required: {f} LazyList[B]
Expand All @@ -18,7 +18,7 @@ longer explanation available when compiling with `-explain`

longer explanation available when compiling with `-explain`
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:27:4 ------------------------------------
27 | class Mapped extends LazyList[B]: // error
27 | final class Mapped extends LazyList[B]: // error
| ^
| Found: {f, xs} LazyList[B]
| Required: {xs} LazyList[B]
Expand All @@ -36,3 +36,10 @@ longer explanation available when compiling with `-explain`
| Required: {xs} LazyList[B]

longer explanation available when compiling with `-explain`
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:59:48 -----------------------------------
59 | def tail: {this} LazyList[B] = xs.tail.map(f) // error
| ^^^^^^^^^^^^^^
| Found: {f} LazyList[B]
| Required: {Mapped.this} LazyList[B]

longer explanation available when compiling with `-explain`
20 changes: 16 additions & 4 deletions tests/neg-custom-args/captures/lazylists2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object LazyNil extends LazyList[Nothing]:

extension [A](xs: {*} LazyList[A])
def map[B](f: {*} A => B): {f} LazyList[B] =
class Mapped extends LazyList[B]: // error
final class Mapped extends LazyList[B]: // error
this: ({xs, f} Mapped) =>

def isEmpty = false
Expand All @@ -24,7 +24,7 @@ extension [A](xs: {*} LazyList[A])
new Mapped

def map2[B](f: {*} A => B): {xs} LazyList[B] =
class Mapped extends LazyList[B]: // error
final class Mapped extends LazyList[B]: // error
this: ({xs, f} Mapped) =>

def isEmpty = false
Expand All @@ -33,7 +33,7 @@ extension [A](xs: {*} LazyList[A])
new Mapped

def map3[B](f: {*} A => B): {xs} LazyList[B] =
class Mapped extends LazyList[B]:
final class Mapped extends LazyList[B]:
this: ({xs} Mapped) =>

def isEmpty = false
Expand All @@ -42,11 +42,23 @@ extension [A](xs: {*} LazyList[A])
new Mapped

def map4[B](f: {*} A => B): {xs} LazyList[B] =
class Mapped extends LazyList[B]:
final class Mapped extends LazyList[B]:
this: ({xs, f} Mapped) =>

def isEmpty = false
def head: B = f(xs.head)
def tail: {xs, f} LazyList[B] = xs.tail.map(f) // error
new Mapped

def map5[B](f: {*} A => B): LazyList[B] =
class Mapped extends LazyList[B]:
this: ({xs, f} Mapped) =>

def isEmpty = false
def head: B = f(xs.head)
def tail: {this} LazyList[B] = xs.tail.map(f) // error
class Mapped2 extends Mapped:
this: Mapped =>
new Mapped2


2 changes: 1 addition & 1 deletion tests/pos-custom-args/captures/lazylists.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object LazyNil extends LazyList[Nothing]:

extension [A](xs: {*} LazyList[A])
def map[B](f: {*} A => B): {xs, f} LazyList[B] =
class Mapped extends LazyList[B]:
final class Mapped extends LazyList[B]:
this: ({xs, f} Mapped) =>

def isEmpty = false
Expand Down
2 changes: 1 addition & 1 deletion tests/pos-custom-args/captures/lazylists1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object LazyNil extends LazyList[Nothing]:
def head = ???
def tail = ???

class LazyCons[+T](val x: T, val xs: {*} () => {*} LazyList[T]) extends LazyList[T]:
final class LazyCons[+T](val x: T, val xs: {*} () => {*} LazyList[T]) extends LazyList[T]:
this: ({*} LazyList[T]) =>

def isEmpty = false
Expand Down

0 comments on commit 5f407b3

Please sign in to comment.