@@ -20,19 +20,19 @@ import config.Printers.recheckr
20
20
import util .Property
21
21
import StdNames .nme
22
22
import reporting .trace
23
+ import annotation .constructorOnly
23
24
24
25
object Recheck :
26
+ import tpd .Tree
25
27
26
- /** A flag used to indicate that a ParamAccessor has been temporily made not-private
28
+ /** A flag used to indicate that a ParamAccessor has been temporarily made not-private
27
29
* Only used at the start of the Recheck phase, reset at its end.
28
30
* The flag repurposes the Scala2ModuleVar flag. No confusion is possible since
29
31
* Scala2ModuleVar cannot be also ParamAccessors.
30
32
*/
31
33
val ResetPrivate = Scala2ModuleVar
32
34
val ResetPrivateParamAccessor = ResetPrivate | ParamAccessor
33
35
34
- import tpd .Tree
35
-
36
36
/** Attachment key for rechecked types of TypeTrees */
37
37
val RecheckedType = Property .Key [Type ]
38
38
@@ -83,6 +83,10 @@ object Recheck:
83
83
84
84
def hasRememberedType : Boolean = tree.hasAttachment(RecheckedType )
85
85
86
+ /** A base class that runs a simplified typer pass over an already re-typed program. The pass
87
+ * does not transform trees but returns instead the re-typed type of each tree as it is
88
+ * traversed. The Recheck phase must be directly preceded by a phase of type PreRecheck.
89
+ */
86
90
abstract class Recheck extends Phase , SymTransformer :
87
91
thisPhase =>
88
92
@@ -91,7 +95,6 @@ abstract class Recheck extends Phase, SymTransformer:
91
95
92
96
def preRecheckPhase = this .prev.asInstanceOf [PreRecheck ]
93
97
94
- override def isEnabled (using Context ) = ctx.settings.Yrecheck .value
95
98
override def changesBaseTypes : Boolean = true
96
99
97
100
override def isCheckable = false
@@ -109,25 +112,36 @@ abstract class Recheck extends Phase, SymTransformer:
109
112
110
113
def newRechecker ()(using Context ): Rechecker
111
114
112
- class Rechecker (ictx : Context ):
115
+ /** The typechecker pass */
116
+ class Rechecker (@ constructorOnly ictx : Context ):
113
117
private val ta = ictx.typeAssigner
114
- private val keepTypes = inContext(ictx) {
118
+
119
+ /** If true, remember types of all tree nodes in attachments so that they
120
+ * can be retrieved with `knownType`
121
+ */
122
+ private val keepAllTypes = inContext(ictx) {
115
123
ictx.settings.Xprint .value.containsPhase(thisPhase)
116
124
}
117
125
118
- def constFold (tree : Tree , tp : Type )(using Context ): Type =
126
+ /** Should type of `tree` be kept in an attachment so that it can be retrieved with
127
+ * `knownType`? By default true only is `keepAllTypes` hold, but can be overridden.
128
+ */
129
+ def keepType (tree : Tree ): Boolean = keepAllTypes
130
+
131
+ /** Constant-folded rechecked type `tp` of tree `tree` */
132
+ private def constFold (tree : Tree , tp : Type )(using Context ): Type =
119
133
val tree1 = tree.withType(tp)
120
134
val tree2 = ConstFold (tree1)
121
135
if tree2 ne tree1 then tree2.tpe else tp
122
136
123
137
def recheckIdent (tree : Ident )(using Context ): Type =
124
138
tree.tpe
125
139
126
- /** Keep the symbol of the `select` but re-infer its type */
127
140
def recheckSelect (tree : Select )(using Context ): Type =
128
141
val Select (qual, name) = tree
129
142
recheckSelection(tree, recheck(qual).widenIfUnstable, name)
130
143
144
+ /** Keep the symbol of the `select` but re-infer its type */
131
145
def recheckSelection (tree : Select , qualType : Type , name : Name )(using Context ) =
132
146
if name.is(OuterSelectName ) then tree.tpe
133
147
else
@@ -169,16 +183,17 @@ abstract class Recheck extends Phase, SymTransformer:
169
183
recheckStats(impl.body)
170
184
sym.typeRef
171
185
172
- // Need to remap Object to FromJavaObject since it got lost in ElimRepeated
186
+ /** Assuming `formals` are parameters of a Java-defined method, remap Object
187
+ * to FromJavaObject since it got lost in ElimRepeated
188
+ */
173
189
private def mapJavaArgs (formals : List [Type ])(using Context ): List [Type ] =
174
190
val tm = new TypeMap :
175
191
def apply (t : Type ) = t match
176
192
case t : TypeRef if t.symbol == defn.ObjectClass => defn.FromJavaObjectType
177
193
case _ => mapOver(t)
178
194
formals.mapConserve(tm)
179
195
180
- /** Hook for method type instantiation
181
- */
196
+ /** Hook for method type instantiation */
182
197
protected def instantiate (mt : MethodType , argTypes : List [Type ], sym : Symbol )(using Context ): Type =
183
198
mt.instantiate(argTypes)
184
199
@@ -256,13 +271,21 @@ abstract class Recheck extends Phase, SymTransformer:
256
271
recheck(tree.body, pt)
257
272
258
273
def recheckReturn (tree : Return )(using Context ): Type =
259
- val rawType = recheck(tree.expr)
274
+ // Avoid local pattern defined symbols in returns from matchResult blocks
275
+ // that are inserted by the PatternMatcher transform.
276
+ // For regular symbols in the case branch, we already avoid them by the rule
277
+ // for blocks since a case branch is of the form `return[MatchResultN] { ... }`
278
+ // For source-level returns from methods, there's nothing to avoid, since the
279
+ // result type of a method with a return must be given explicitly.
260
280
def avoidMap = new TypeOps .AvoidMap :
261
281
def toAvoid (tp : NamedType ) =
262
- tp.symbol.is(Case ) && tp.symbol.owner.isContainedIn(ctx.owner)
282
+ tp.symbol.is(Case ) && tp.symbol.owner.isContainedIn(ctx.owner)
283
+
284
+ val rawType = recheck(tree.expr)
263
285
val ownType = avoidMap(rawType)
264
286
checkConforms(ownType, tree.from.symbol.returnProto, tree)
265
287
defn.NothingType
288
+ end recheckReturn
266
289
267
290
def recheckWhileDo (tree : WhileDo )(using Context ): Type =
268
291
recheck(tree.cond, defn.BooleanType )
@@ -285,7 +308,7 @@ abstract class Recheck extends Phase, SymTransformer:
285
308
seqLitType(tree, TypeComparer .lub(declaredElemType :: elemTypes))
286
309
287
310
def recheckTypeTree (tree : TypeTree )(using Context ): Type =
288
- knownType(tree)
311
+ knownType(tree) // allows to install new types at Setup
289
312
290
313
def recheckAnnotated (tree : Annotated )(using Context ): Type =
291
314
tree.tpe match
@@ -326,10 +349,13 @@ abstract class Recheck extends Phase, SymTransformer:
326
349
case tree : ValOrDefDef =>
327
350
if tree.isEmpty then NoType
328
351
else
329
- if sym.isUpdatedAfter(preRecheckPhase) then sym.ensureCompleted()
330
- else recheckDef(tree, sym)
352
+ if sym.isUpdatedAfter(preRecheckPhase) then
353
+ sym.ensureCompleted() // in this case the symbol's completer should recheck the right hand side
354
+ else
355
+ recheckDef(tree, sym)
331
356
sym.termRef
332
357
case tree : TypeDef =>
358
+ // TODO: Should we allow for completers as for ValDefs or DefDefs?
333
359
tree.rhs match
334
360
case impl : Template =>
335
361
recheckClassDef(tree, impl, sym.asClass)(using ctx.localContext(tree, sym))
@@ -364,11 +390,15 @@ abstract class Recheck extends Phase, SymTransformer:
364
390
case tree => recheckUnnamed(tree, pt)
365
391
end recheckStart
366
392
393
+ /** Finish rechecking a tree node: check rechecked type against expected type
394
+ * and remember rechecked type in a tree attachment if required.
395
+ * @param tpe the recheched type of `tree`
396
+ * @param tree the rechecked tree
397
+ * @param pt the expected type
398
+ */
367
399
def recheckFinish (tpe : Type , tree : Tree , pt : Type )(using Context ): Type =
368
400
checkConforms(tpe, pt, tree)
369
- if keepTypes
370
- || tree.isInstanceOf [Try ] // type needs tp be checked for * escapes
371
- then tree.rememberType(tpe)
401
+ if keepType(tree) then tree.rememberType(tpe)
372
402
tpe
373
403
374
404
def recheck (tree : Tree , pt : Type = WildcardType )(using Context ): Type =
@@ -379,8 +409,12 @@ abstract class Recheck extends Phase, SymTransformer:
379
409
throw ex
380
410
}
381
411
412
+ /** If true, print info for some successful checkConforms operations (failing ones give
413
+ * an error message in any case).
414
+ */
382
415
private val debugSuccesses = false
383
416
417
+ /** Check that widened types of `tpe` and `pt` are compatible. */
384
418
def checkConforms (tpe : Type , pt : Type , tree : Tree )(using Context ): Unit = tree match
385
419
case _ : DefTree | EmptyTree | _ : TypeTree | _ : Closure =>
386
420
// Don't report closure nodes, since their span is a point; wait instead
@@ -408,6 +442,7 @@ abstract class Recheck extends Phase, SymTransformer:
408
442
409
443
end Rechecker
410
444
445
+ /** Show tree with rechecked types instead of the types stored in the `.tpe` field */
411
446
override def show (tree : untpd.Tree )(using Context ): String =
412
447
val addRecheckedTypes = new TreeMap :
413
448
override def transform (tree : Tree )(using Context ): Tree =
@@ -420,12 +455,14 @@ abstract class Recheck extends Phase, SymTransformer:
420
455
}
421
456
end Recheck
422
457
458
+ /** A class that can be used to test basic rechecking without any customaization */
423
459
object TestRecheck :
424
- class Pre extends PreRecheck , IdentityDenotTransformer
460
+ class Pre extends PreRecheck , IdentityDenotTransformer :
461
+ override def isEnabled (using Context ) = ctx.settings.YrecheckTest .value
425
462
426
463
class TestRecheck extends Recheck :
427
464
def phaseName : String = " recheck"
428
- // override def isEnabled(using Context) = ctx.settings.YrefineTypes .value
465
+ override def isEnabled (using Context ) = ctx.settings.YrecheckTest .value
429
466
def newRechecker ()(using Context ): Rechecker = Rechecker (ctx)
430
467
431
468
0 commit comments