@@ -52,17 +52,18 @@ object Recheck:
52
52
*/
53
53
def updateInfoBetween (prevPhase : DenotTransformer , lastPhase : DenotTransformer , newInfo : Type )(using Context ): Unit =
54
54
if sym.info ne newInfo then
55
+ val flags = sym.flags
55
56
sym.copySymDenotation(
56
57
initFlags =
57
- if sym. flags.isAllOf(ResetPrivateParamAccessor )
58
- then sym. flags &~ ResetPrivate | Private
59
- else sym. flags
58
+ if flags.isAllOf(ResetPrivateParamAccessor )
59
+ then flags &~ ResetPrivate | Private
60
+ else flags
60
61
).installAfter(lastPhase) // reset
61
62
sym.copySymDenotation(
62
63
info = newInfo,
63
64
initFlags =
64
- if newInfo.isInstanceOf [LazyType ] then sym. flags &~ Touched
65
- else sym. flags
65
+ if newInfo.isInstanceOf [LazyType ] then flags &~ Touched
66
+ else flags
66
67
).installAfter(prevPhase)
67
68
68
69
/** Does symbol have a new denotation valid from phase.next that is different
@@ -96,17 +97,44 @@ object Recheck:
96
97
case Some (tpe) => tree.withType(tpe).asInstanceOf [T ]
97
98
case None => tree
98
99
99
- extension (tpe : Type )
100
-
101
- /** Map ExprType => T to () ?=> T (and analogously for pure versions).
102
- * Even though this phase runs after ElimByName, ExprTypes can still occur
103
- * as by-name arguments of applied types. See note in doc comment for
104
- * ElimByName phase. Test case is bynamefun.scala.
105
- */
106
- def mapExprType (using Context ): Type = tpe match
107
- case ExprType (rt) => defn.ByNameFunction (rt)
108
- case _ => tpe
109
100
101
+ /** Map ExprType => T to () ?=> T (and analogously for pure versions).
102
+ * Even though this phase runs after ElimByName, ExprTypes can still occur
103
+ * as by-name arguments of applied types. See note in doc comment for
104
+ * ElimByName phase. Test case is bynamefun.scala.
105
+ */
106
+ private def mapExprType (tp : Type )(using Context ): Type = tp match
107
+ case ExprType (rt) => defn.ByNameFunction (rt)
108
+ case _ => tp
109
+
110
+ /** Normalize `=> A` types to `() ?=> A` types
111
+ * - at the top level
112
+ * - in function and method parameter types
113
+ * - under annotations
114
+ */
115
+ def normalizeByName (tp : Type )(using Context ): Type = tp match
116
+ case tp : ExprType =>
117
+ mapExprType(tp)
118
+ case tp : PolyType =>
119
+ tp.derivedLambdaType(resType = normalizeByName(tp.resType))
120
+ case tp : MethodType =>
121
+ tp.derivedLambdaType(
122
+ paramInfos = tp.paramInfos.mapConserve(mapExprType),
123
+ resType = normalizeByName(tp.resType))
124
+ case tp @ RefinedType (parent, nme.apply, rinfo) if defn.isFunctionType(tp) =>
125
+ tp.derivedRefinedType(parent, nme.apply, normalizeByName(rinfo))
126
+ case tp @ defn.FunctionOf (pformals, restpe, isContextual) =>
127
+ val pformals1 = pformals.mapConserve(mapExprType)
128
+ val restpe1 = normalizeByName(restpe)
129
+ if (pformals1 ne pformals) || (restpe1 ne restpe) then
130
+ defn.FunctionOf (pformals1, restpe1, isContextual)
131
+ else
132
+ tp
133
+ case tp @ AnnotatedType (parent, ann) =>
134
+ tp.derivedAnnotatedType(normalizeByName(parent), ann)
135
+ case _ =>
136
+ tp
137
+ end Recheck
110
138
111
139
/** A base class that runs a simplified typer pass over an already re-typed program. The pass
112
140
* does not transform trees but returns instead the re-typed type of each tree as it is
@@ -183,27 +211,16 @@ abstract class Recheck extends Phase, SymTransformer:
183
211
else AnySelectionProto
184
212
recheckSelection(tree, recheck(qual, proto).widenIfUnstable, name, pt)
185
213
186
- /** When we select the `apply` of a function with type such as `(=> A) => B`,
187
- * we need to convert the parameter type `=> A` to `() ?=> A`. See doc comment
188
- * of `mapExprType`.
189
- */
190
- def normalizeByName (mbr : SingleDenotation )(using Context ): SingleDenotation = mbr.info match
191
- case mt : MethodType if mt.paramInfos.exists(_.isInstanceOf [ExprType ]) =>
192
- mbr.derivedSingleDenotation(mbr.symbol,
193
- mt.derivedLambdaType(paramInfos = mt.paramInfos.map(_.mapExprType)))
194
- case _ =>
195
- mbr
196
-
197
214
def recheckSelection (tree : Select , qualType : Type , name : Name ,
198
215
sharpen : Denotation => Denotation )(using Context ): Type =
199
216
if name.is(OuterSelectName ) then tree.tpe
200
217
else
201
218
// val pre = ta.maybeSkolemizePrefix(qualType, name)
202
- val mbr = normalizeByName(
219
+ val mbr =
203
220
sharpen(
204
221
qualType.findMember(name, qualType,
205
222
excluded = if tree.symbol.is(Private ) then EmptyFlags else Private
206
- )).suchThat(tree.symbol == _))
223
+ )).suchThat(tree.symbol == _)
207
224
val newType = tree.tpe match
208
225
case prevType : NamedType =>
209
226
val prevDenot = prevType.denot
@@ -281,7 +298,7 @@ abstract class Recheck extends Phase, SymTransformer:
281
298
else fntpe.paramInfos
282
299
def recheckArgs (args : List [Tree ], formals : List [Type ], prefs : List [ParamRef ]): List [Type ] = args match
283
300
case arg :: args1 =>
284
- val argType = recheck(arg, formals.head.mapExprType )
301
+ val argType = recheck(arg, normalizeByName( formals.head) )
285
302
val formals1 =
286
303
if fntpe.isParamDependent
287
304
then formals.tail.map(_.substParam(prefs.head, argType))
@@ -313,27 +330,33 @@ abstract class Recheck extends Phase, SymTransformer:
313
330
recheck(tree.rhs, lhsType.widen)
314
331
defn.UnitType
315
332
316
- def recheckBlock (stats : List [Tree ], expr : Tree , pt : Type )(using Context ): Type =
333
+ private def recheckBlock (stats : List [Tree ], expr : Tree )(using Context ): Type =
317
334
recheckStats(stats)
318
335
val exprType = recheck(expr)
336
+ TypeOps .avoid(exprType, localSyms(stats).filterConserve(_.isTerm))
337
+
338
+ def recheckBlock (tree : Block , pt : Type )(using Context ): Type = tree match
339
+ case Block (Nil , expr : Block ) => recheckBlock(expr, pt)
340
+ case Block ((mdef : DefDef ) :: Nil , closure : Closure ) =>
341
+ recheckClosureBlock(mdef, closure.withSpan(tree.span), pt)
342
+ case Block (stats, expr) => recheckBlock(stats, expr)
319
343
// The expected type `pt` is not propagated. Doing so would allow variables in the
320
344
// expected type to contain references to local symbols of the block, so the
321
345
// local symbols could escape that way.
322
- TypeOps .avoid(exprType, localSyms(stats).filterConserve(_.isTerm))
323
346
324
- def recheckBlock ( tree : Block , pt : Type )(using Context ): Type =
325
- recheckBlock(tree.stats, tree.expr, pt )
347
+ def recheckClosureBlock ( mdef : DefDef , expr : Closure , pt : Type )(using Context ): Type =
348
+ recheckBlock(mdef :: Nil , expr )
326
349
327
350
def recheckInlined (tree : Inlined , pt : Type )(using Context ): Type =
328
- recheckBlock(tree.bindings, tree.expansion, pt )(using inlineContext(tree))
351
+ recheckBlock(tree.bindings, tree.expansion)(using inlineContext(tree))
329
352
330
353
def recheckIf (tree : If , pt : Type )(using Context ): Type =
331
354
recheck(tree.cond, defn.BooleanType )
332
355
recheck(tree.thenp, pt) | recheck(tree.elsep, pt)
333
356
334
- def recheckClosure (tree : Closure , pt : Type )(using Context ): Type =
357
+ def recheckClosure (tree : Closure , pt : Type , forceDependent : Boolean = false )(using Context ): Type =
335
358
if tree.tpt.isEmpty then
336
- tree.meth.tpe.widen.toFunctionType(tree.meth.symbol.is(JavaDefined ))
359
+ tree.meth.tpe.widen.toFunctionType(tree.meth.symbol.is(JavaDefined ), alwaysDependent = forceDependent )
337
360
else
338
361
recheck(tree.tpt)
339
362
@@ -534,9 +557,7 @@ abstract class Recheck extends Phase, SymTransformer:
534
557
535
558
/** Check that widened types of `tpe` and `pt` are compatible. */
536
559
def checkConforms (tpe : Type , pt : Type , tree : Tree )(using Context ): Unit = tree match
537
- case _ : DefTree | EmptyTree | _ : TypeTree | _ : Closure =>
538
- // Don't report closure nodes, since their span is a point; wait instead
539
- // for enclosing block to preduce an error
560
+ case _ : DefTree | EmptyTree | _ : TypeTree =>
540
561
case _ =>
541
562
checkConformsExpr(tpe.widenExpr, pt.widenExpr, tree)
542
563
0 commit comments