@@ -20,19 +20,19 @@ import config.Printers.recheckr
2020import util .Property
2121import StdNames .nme
2222import reporting .trace
23+ import annotation .constructorOnly
2324
2425object Recheck :
26+ import tpd .Tree
2527
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
2729 * Only used at the start of the Recheck phase, reset at its end.
2830 * The flag repurposes the Scala2ModuleVar flag. No confusion is possible since
2931 * Scala2ModuleVar cannot be also ParamAccessors.
3032 */
3133 val ResetPrivate = Scala2ModuleVar
3234 val ResetPrivateParamAccessor = ResetPrivate | ParamAccessor
3335
34- import tpd .Tree
35-
3636 /** Attachment key for rechecked types of TypeTrees */
3737 val RecheckedType = Property .Key [Type ]
3838
@@ -83,6 +83,10 @@ object Recheck:
8383
8484 def hasRememberedType : Boolean = tree.hasAttachment(RecheckedType )
8585
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+ */
8690abstract class Recheck extends Phase , SymTransformer :
8791 thisPhase =>
8892
@@ -91,7 +95,6 @@ abstract class Recheck extends Phase, SymTransformer:
9195
9296 def preRecheckPhase = this .prev.asInstanceOf [PreRecheck ]
9397
94- override def isEnabled (using Context ) = ctx.settings.Yrecheck .value
9598 override def changesBaseTypes : Boolean = true
9699
97100 override def isCheckable = false
@@ -109,25 +112,36 @@ abstract class Recheck extends Phase, SymTransformer:
109112
110113 def newRechecker ()(using Context ): Rechecker
111114
112- class Rechecker (ictx : Context ):
115+ /** The typechecker pass */
116+ class Rechecker (@ constructorOnly ictx : Context ):
113117 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) {
115123 ictx.settings.Xprint .value.containsPhase(thisPhase)
116124 }
117125
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 =
119133 val tree1 = tree.withType(tp)
120134 val tree2 = ConstFold (tree1)
121135 if tree2 ne tree1 then tree2.tpe else tp
122136
123137 def recheckIdent (tree : Ident )(using Context ): Type =
124138 tree.tpe
125139
126- /** Keep the symbol of the `select` but re-infer its type */
127140 def recheckSelect (tree : Select )(using Context ): Type =
128141 val Select (qual, name) = tree
129142 recheckSelection(tree, recheck(qual).widenIfUnstable, name)
130143
144+ /** Keep the symbol of the `select` but re-infer its type */
131145 def recheckSelection (tree : Select , qualType : Type , name : Name )(using Context ) =
132146 if name.is(OuterSelectName ) then tree.tpe
133147 else
@@ -169,16 +183,17 @@ abstract class Recheck extends Phase, SymTransformer:
169183 recheckStats(impl.body)
170184 sym.typeRef
171185
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+ */
173189 private def mapJavaArgs (formals : List [Type ])(using Context ): List [Type ] =
174190 val tm = new TypeMap :
175191 def apply (t : Type ) = t match
176192 case t : TypeRef if t.symbol == defn.ObjectClass => defn.FromJavaObjectType
177193 case _ => mapOver(t)
178194 formals.mapConserve(tm)
179195
180- /** Hook for method type instantiation
181- */
196+ /** Hook for method type instantiation */
182197 protected def instantiate (mt : MethodType , argTypes : List [Type ], sym : Symbol )(using Context ): Type =
183198 mt.instantiate(argTypes)
184199
@@ -256,13 +271,21 @@ abstract class Recheck extends Phase, SymTransformer:
256271 recheck(tree.body, pt)
257272
258273 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.
260280 def avoidMap = new TypeOps .AvoidMap :
261281 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)
263285 val ownType = avoidMap(rawType)
264286 checkConforms(ownType, tree.from.symbol.returnProto, tree)
265287 defn.NothingType
288+ end recheckReturn
266289
267290 def recheckWhileDo (tree : WhileDo )(using Context ): Type =
268291 recheck(tree.cond, defn.BooleanType )
@@ -285,7 +308,7 @@ abstract class Recheck extends Phase, SymTransformer:
285308 seqLitType(tree, TypeComparer .lub(declaredElemType :: elemTypes))
286309
287310 def recheckTypeTree (tree : TypeTree )(using Context ): Type =
288- knownType(tree)
311+ knownType(tree) // allows to install new types at Setup
289312
290313 def recheckAnnotated (tree : Annotated )(using Context ): Type =
291314 tree.tpe match
@@ -326,10 +349,13 @@ abstract class Recheck extends Phase, SymTransformer:
326349 case tree : ValOrDefDef =>
327350 if tree.isEmpty then NoType
328351 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)
331356 sym.termRef
332357 case tree : TypeDef =>
358+ // TODO: Should we allow for completers as for ValDefs or DefDefs?
333359 tree.rhs match
334360 case impl : Template =>
335361 recheckClassDef(tree, impl, sym.asClass)(using ctx.localContext(tree, sym))
@@ -364,11 +390,15 @@ abstract class Recheck extends Phase, SymTransformer:
364390 case tree => recheckUnnamed(tree, pt)
365391 end recheckStart
366392
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+ */
367399 def recheckFinish (tpe : Type , tree : Tree , pt : Type )(using Context ): Type =
368400 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)
372402 tpe
373403
374404 def recheck (tree : Tree , pt : Type = WildcardType )(using Context ): Type =
@@ -379,8 +409,12 @@ abstract class Recheck extends Phase, SymTransformer:
379409 throw ex
380410 }
381411
412+ /** If true, print info for some successful checkConforms operations (failing ones give
413+ * an error message in any case).
414+ */
382415 private val debugSuccesses = false
383416
417+ /** Check that widened types of `tpe` and `pt` are compatible. */
384418 def checkConforms (tpe : Type , pt : Type , tree : Tree )(using Context ): Unit = tree match
385419 case _ : DefTree | EmptyTree | _ : TypeTree | _ : Closure =>
386420 // Don't report closure nodes, since their span is a point; wait instead
@@ -408,6 +442,7 @@ abstract class Recheck extends Phase, SymTransformer:
408442
409443 end Rechecker
410444
445+ /** Show tree with rechecked types instead of the types stored in the `.tpe` field */
411446 override def show (tree : untpd.Tree )(using Context ): String =
412447 val addRecheckedTypes = new TreeMap :
413448 override def transform (tree : Tree )(using Context ): Tree =
@@ -420,12 +455,14 @@ abstract class Recheck extends Phase, SymTransformer:
420455 }
421456end Recheck
422457
458+ /** A class that can be used to test basic rechecking without any customaization */
423459object TestRecheck :
424- class Pre extends PreRecheck , IdentityDenotTransformer
460+ class Pre extends PreRecheck , IdentityDenotTransformer :
461+ override def isEnabled (using Context ) = ctx.settings.YrecheckTest .value
425462
426463class TestRecheck extends Recheck :
427464 def phaseName : String = " recheck"
428- // override def isEnabled(using Context) = ctx.settings.YrefineTypes .value
465+ override def isEnabled (using Context ) = ctx.settings.YrecheckTest .value
429466 def newRechecker ()(using Context ): Rechecker = Rechecker (ctx)
430467
431468
0 commit comments