Skip to content

Commit

Permalink
Change result type of by-name closures
Browse files Browse the repository at this point in the history
Make it the formal type rather than the actual one. This avoids messing up
capture annotations.
  • Loading branch information
odersky committed Feb 1, 2022
1 parent 4cc8ff0 commit ac14dcd
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 18 deletions.
9 changes: 3 additions & 6 deletions compiler/src/dotty/tools/dotc/transform/ElimByName.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class ElimByName extends MiniPhase, InfoTransformer:
sym.is(Method) || exprBecomesFunction(sym)

def byNameClosure(arg: Tree, argType: Type)(using Context): Tree =
log(i"creating by name closure for $argType")
val meth = newAnonFun(ctx.owner, MethodType(Nil, argType), coord = arg.span)
Closure(meth,
_ => arg.changeOwnerAfter(ctx.owner, meth, thisPhase),
Expand Down Expand Up @@ -135,12 +136,8 @@ class ElimByName extends MiniPhase, InfoTransformer:
if isByNameRef(qual) && (isPureExpr(qual) || qual.symbol.isAllOf(InlineParam)) =>
qual
case _ =>
if isByNameRef(arg) || arg.symbol.name.is(SuperArgName)
then arg
else
var argType = arg.tpe.widenIfUnstable
if argType.isBottomType then argType = formalResult
byNameClosure(arg, argType)
if isByNameRef(arg) || arg.symbol.name.is(SuperArgName) then arg
else byNameClosure(arg, formalResult)
case _ =>
arg

Expand Down
18 changes: 9 additions & 9 deletions tests/neg-custom-args/captures/byname.check
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
-- Warning: tests/neg-custom-args/captures/byname.scala:14:18 ----------------------------------------------------------
14 | def h(x: {cap1} -> I) = x // warning
-- Warning: tests/neg-custom-args/captures/byname.scala:17:18 ----------------------------------------------------------
17 | def h(x: {cap1} -> I) = x // warning
| ^
| Style: by-name `->` should immediately follow closing `}` of capture set
| to avoid confusion with function type.
| That is, `{c}-> T` instead of `{c} -> T`.
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:7:5 -----------------------------------------
7 | h(f()) // error
| ^^^
| Found: {cap2} (x$0: Int) -> Int
| Required: Int -> Int
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:10:6 ----------------------------------------
10 | h(f2()) // error
| ^^^^
| Found: {cap1} (x$0: Int) -> Int
| Required: {cap2} Int -> Int

longer explanation available when compiling with `-explain`
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:16:5 ----------------------------------------
16 | h(g()) // error
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:19:5 ----------------------------------------
19 | h(g()) // error
| ^^^
| Found: {cap2} () ?-> I
| Required: {cap1} () ?-> I
Expand Down
5 changes: 4 additions & 1 deletion tests/neg-custom-args/captures/byname.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
def test(cap1: Cap, cap2: Cap) =
def f() = if cap1 == cap1 then g else g
def g(x: Int) = if cap2 == cap2 then 1 else x
def g2(x: Int) = if cap1 == cap1 then 1 else x
def f2() = if cap1 == cap1 then g2 else g2
def h(ff: => {cap2} Int -> Int) = ff
h(f()) // error
h(f()) // ok
h(f2()) // error

class I

Expand Down
7 changes: 5 additions & 2 deletions tests/pos-custom-args/captures/lazylists-exceptions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,17 @@ extension [A](xs: {*} LazyList[A])

def concat(ys: {*} LazyList[A]): {xs, ys} LazyList[A] =
if xs.isEmpty then ys
else LazyCons(xs.head, () => xs.tail.concat(ys))
else lazyCons(xs.head, xs.tail.concat(ys))
end extension

def lazyCons[A](x: A, xs1: => {*} LazyList[A]): {xs1} LazyList[A] =
LazyCons(x, () => xs1)

class Ex1 extends Exception
class Ex2 extends Exception

def test(using cap1: CanThrow[Ex1], cap2: CanThrow[Ex2]) =
val xs = LazyCons(1, () => LazyNil)
val xs = lazyCons(1, LazyNil)

def f(x: Int): Int throws Ex1 =
if x < 0 then throw Ex1()
Expand Down

0 comments on commit ac14dcd

Please sign in to comment.