@@ -22,6 +22,7 @@ import StdNames.nme
22
22
import reporting .trace
23
23
import annotation .constructorOnly
24
24
import cc .CaptureSet .IdempotentCaptRefMap
25
+ import dotty .tools .dotc .core .Denotations .SingleDenotation
25
26
26
27
object Recheck :
27
28
import tpd .*
@@ -91,6 +92,18 @@ object Recheck:
91
92
92
93
def hasRememberedType : Boolean = tree.hasAttachment(RecheckedType )
93
94
95
+ extension (tpe : Type )
96
+
97
+ /** Map ExprType => T to () ?=> T (and analogously for pure versions).
98
+ * Even though this phase runs after ElimByName, ExprTypes can still occur
99
+ * as by-name arguments of applied types. See note in doc comment for
100
+ * ElimByName phase. Test case is bynamefun.scala.
101
+ */
102
+ def mapExprType (using Context ): Type = tpe match
103
+ case ExprType (rt) => defn.ByNameFunction (rt)
104
+ case _ => tpe
105
+
106
+
94
107
/** A base class that runs a simplified typer pass over an already re-typed program. The pass
95
108
* does not transform trees but returns instead the re-typed type of each tree as it is
96
109
* traversed. The Recheck phase must be directly preceded by a phase of type PreRecheck.
@@ -152,15 +165,27 @@ abstract class Recheck extends Phase, SymTransformer:
152
165
else AnySelectionProto
153
166
recheckSelection(tree, recheck(qual, proto).widenIfUnstable, name, pt)
154
167
168
+ /** When we select the `apply` of a function with type such as `(=> A) => B`,
169
+ * we need to convert the parameter type `=> A` to `() ?=> A`. See doc comment
170
+ * of `mapExprType`.
171
+ */
172
+ def normalizeByName (mbr : SingleDenotation )(using Context ): SingleDenotation = mbr.info match
173
+ case mt : MethodType if mt.paramInfos.exists(_.isInstanceOf [ExprType ]) =>
174
+ mbr.derivedSingleDenotation(mbr.symbol,
175
+ mt.derivedLambdaType(paramInfos = mt.paramInfos.map(_.mapExprType)))
176
+ case _ =>
177
+ mbr
178
+
155
179
def recheckSelection (tree : Select , qualType : Type , name : Name ,
156
180
sharpen : Denotation => Denotation )(using Context ): Type =
157
181
if name.is(OuterSelectName ) then tree.tpe
158
182
else
159
183
// val pre = ta.maybeSkolemizePrefix(qualType, name)
160
- val mbr = sharpen(
184
+ val mbr = normalizeByName(
185
+ sharpen(
161
186
qualType.findMember(name, qualType,
162
187
excluded = if tree.symbol.is(Private ) then EmptyFlags else Private
163
- )).suchThat(tree.symbol == _)
188
+ )).suchThat(tree.symbol == _))
164
189
constFold(tree, qualType.select(name, mbr))
165
190
// .showing(i"recheck select $qualType . $name : ${mbr.info} = $result")
166
191
@@ -215,15 +240,16 @@ abstract class Recheck extends Phase, SymTransformer:
215
240
mt.instantiate(argTypes)
216
241
217
242
def recheckApply (tree : Apply , pt : Type )(using Context ): Type =
218
- recheck(tree.fun).widen match
243
+ val funtpe = recheck(tree.fun)
244
+ funtpe.widen match
219
245
case fntpe : MethodType =>
220
246
assert(fntpe.paramInfos.hasSameLengthAs(tree.args))
221
247
val formals =
222
248
if tree.symbol.is(JavaDefined ) then mapJavaArgs(fntpe.paramInfos)
223
249
else fntpe.paramInfos
224
250
def recheckArgs (args : List [Tree ], formals : List [Type ], prefs : List [ParamRef ]): List [Type ] = args match
225
251
case arg :: args1 =>
226
- val argType = recheck(arg, formals.head)
252
+ val argType = recheck(arg, formals.head.mapExprType )
227
253
val formals1 =
228
254
if fntpe.isParamDependent
229
255
then formals.tail.map(_.substParam(prefs.head, argType))
@@ -235,6 +261,8 @@ abstract class Recheck extends Phase, SymTransformer:
235
261
val argTypes = recheckArgs(tree.args, formals, fntpe.paramRefs)
236
262
constFold(tree, instantiate(fntpe, argTypes, tree.fun.symbol))
237
263
// .showing(i"typed app $tree : $fntpe with ${tree.args}%, % : $argTypes%, % = $result")
264
+ case tp =>
265
+ assert(false , i " unexpected type of ${tree.fun}: $funtpe" )
238
266
239
267
def recheckTypeApply (tree : TypeApply , pt : Type )(using Context ): Type =
240
268
recheck(tree.fun).widen match
0 commit comments