Skip to content

Commit 910762f

Browse files
committed
Treat result of by-name closures as inferred
1 parent 0c3ce57 commit 910762f

File tree

6 files changed

+38
-19
lines changed

6 files changed

+38
-19
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
117117
* where the closure's type is the target type of the expression (FunctionN, unless
118118
* otherwise specified).
119119
*/
120-
def Closure(meth: TermSymbol, rhsFn: List[List[Tree]] => Tree, targs: List[Tree] = Nil, targetType: Type = NoType)(using Context): Block = {
121-
val targetTpt = if (targetType.exists) TypeTree(targetType) else EmptyTree
120+
def Closure(meth: TermSymbol, rhsFn: List[List[Tree]] => Tree, targs: List[Tree] = Nil, targetType: Type = NoType, inferred: Boolean = false)(using Context): Block = {
121+
val targetTpt = if (targetType.exists) TypeTree(targetType, inferred) else EmptyTree
122122
val call =
123123
if (targs.isEmpty) Ident(TermRef(NoPrefix, meth))
124124
else TypeApply(Ident(TermRef(NoPrefix, meth)), targs)
125-
Block(
126-
DefDef(meth, rhsFn) :: Nil,
127-
Closure(Nil, call, targetTpt))
125+
var mdef = DefDef(meth, rhsFn)
126+
if inferred then mdef = cpy.DefDef(mdef)(tpt = TypeTree(mdef.tpt.tpe, inferred))
127+
Block(mdef :: Nil, Closure(Nil, call, targetTpt))
128128
}
129129

130130
/** A closure whose anonymous function has the given method type */

compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ object CheckCaptures:
6868
*/
6969
final class SubstParamsMap(from: BindingType, to: List[Type])(using Context)
7070
extends ApproximatingTypeMap, IdempotentCaptRefMap:
71-
7271
def apply(tp: Type): Type =
7372
tp match
7473
case tp: ParamRef =>

compiler/src/dotty/tools/dotc/transform/ElimByName.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ class ElimByName extends MiniPhase, InfoTransformer:
102102
val meth = newAnonFun(ctx.owner, MethodType(Nil, argType), coord = arg.span)
103103
Closure(meth,
104104
_ => arg.changeOwnerAfter(ctx.owner, meth, thisPhase),
105-
targetType = defn.ByNameFunction(argType)
105+
targetType = defn.ByNameFunction(argType),
106+
inferred = true
106107
).withSpan(arg.span)
107108

108109
private def isByNameRef(tree: Tree)(using Context): Boolean =
Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:10:6 ----------------------------------------
2-
10 | h(f2()) // error
3-
| ^^^^
4-
| Found: (x$0: Int) ->{cap1} Int
5-
| Required: (x$0: Int) ->{cap2} Int
6-
|
7-
| longer explanation available when compiling with `-explain`
81
-- Error: tests/neg-custom-args/captures/byname.scala:19:5 -------------------------------------------------------------
92
19 | h(g()) // error
103
| ^^^
114
| reference (cap2 : Cap^) is not included in the allowed capture set {cap1}
125
| of an enclosing function literal with expected type () ?->{cap1} I
6+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:4:2 -----------------------------------------
7+
4 | def f() = if cap1 == cap1 then g else g // error
8+
| ^
9+
| Found: (x$0: Int) ->{cap2} Int
10+
| Required: (x$0: Int) -> Int
11+
|
12+
| Note that the expected type Int => Int
13+
| is the previously inferred result type of method test
14+
| which is also the type seen in separately compiled sources.
15+
| The new inferred type (x$0: Int) ->{cap2} Int
16+
| must conform to this type.
17+
5 | def g(x: Int) = if cap2 == cap2 then 1 else x
18+
6 | def g2(x: Int) = if cap1 == cap1 then 1 else x
19+
7 | def f2() = if cap1 == cap1 then g2 else g2
20+
8 | def h(ff: => Int ->{cap2} Int) = ff
21+
9 | h(f())
22+
10 | h(f2())
23+
|
24+
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/byname.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
@annotation.capability class Cap
22

33
def test(cap1: Cap, cap2: Cap) =
4-
def f() = if cap1 == cap1 then g else g
4+
def f() = if cap1 == cap1 then g else g // error
55
def g(x: Int) = if cap2 == cap2 then 1 else x
66
def g2(x: Int) = if cap1 == cap1 then 1 else x
77
def f2() = if cap1 == cap1 then g2 else g2
88
def h(ff: => Int ->{cap2} Int) = ff
9-
h(f()) // ok
10-
h(f2()) // error
9+
h(f())
10+
h(f2())
1111

1212
class I
1313

tests/pos/invariant-cc.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ trait IterableFactory[+CC[_]] extends Pure:
55

66
def fill[A](n: Int)(elem: => A): CC[A]^{elem} = ???
77
def fill[A](n1: Int, n2: Int)(elem: => A): CC[(CC[A]^{elem}) @uncheckedVariance]^{elem} =
8-
fill[CC[A]^{elem}](n1)(fill(n2)(elem)) // !!! explicit type argument required under cc
9-
// fill(n1)(fill(n2)(elem)) // !!! does not currently work
8+
fill[CC[A]^{elem}](n1)(fill(n2)(elem))
9+
fill(n1)(fill(n2)(elem))
10+
11+
def fill2[A](n: Int)(elem: () => A): CC[A]^{elem} = ???
12+
def fill2[A](n1: Int, n2: Int)(elem: () => A): CC[(CC[A]^{elem}) @uncheckedVariance]^{elem} =
13+
fill2[CC[A]^{elem}](n1)(() => fill2(n2)(elem))
14+
fill2(n1)(() => fill2(n2)(elem))
15+
16+
1017

1118

0 commit comments

Comments
 (0)