@@ -35,6 +35,7 @@ import dotty.tools.runner.ScalaClassLoader.*
3535import org .jline .reader ._
3636
3737import scala .annotation .tailrec
38+ import scala .collection .mutable
3839import scala .collection .JavaConverters ._
3940import scala .util .Using
4041
@@ -55,12 +56,15 @@ import scala.util.Using
5556 * @param objectIndex the index of the next wrapper
5657 * @param valIndex the index of next value binding for free expressions
5758 * @param imports a map from object index to the list of user defined imports
59+ * @param invalidObjectIndexes the set of object indexes that failed to initialize
5860 * @param context the latest compiler context
5961 */
6062case class State (objectIndex : Int ,
6163 valIndex : Int ,
6264 imports : Map [Int , List [tpd.Import ]],
63- context : Context )
65+ invalidObjectIndexes : Set [Int ],
66+ context : Context ):
67+ def validObjectIndexes = (1 to objectIndex).filterNot(invalidObjectIndexes.contains(_))
6468
6569/** Main REPL instance, orchestrating input, compilation and presentation */
6670class ReplDriver (settings : Array [String ],
@@ -94,7 +98,7 @@ class ReplDriver(settings: Array[String],
9498 }
9599
96100 /** the initial, empty state of the REPL session */
97- final def initialState : State = State (0 , 0 , Map .empty, rootCtx)
101+ final def initialState : State = State (0 , 0 , Map .empty, Set .empty, rootCtx)
98102
99103 /** Reset state of repl to the initial state
100104 *
@@ -237,7 +241,7 @@ class ReplDriver(settings: Array[String],
237241 completions.map(_.label).distinct.map(makeCandidate)
238242 }
239243 .getOrElse(Nil )
240- end completions
244+ end completions
241245
242246 private def interpret (res : ParseResult )(implicit state : State ): State = {
243247 res match {
@@ -353,14 +357,33 @@ class ReplDriver(settings: Array[String],
353357 val typeAliases =
354358 info.bounds.hi.typeMembers.filter(_.symbol.info.isTypeAlias)
355359
356- val formattedMembers =
357- typeAliases.map(rendering.renderTypeAlias) ++
358- defs.map(rendering.renderMethod) ++
359- vals.flatMap(rendering.renderVal)
360-
361- val diagnostics = if formattedMembers.isEmpty then rendering.forceModule(symbol) else formattedMembers
362-
363- (state.copy(valIndex = state.valIndex - vals.count(resAndUnit)), diagnostics)
360+ // The wrapper object may fail to initialize if the rhs of a ValDef throws.
361+ // In that case, don't attempt to render any subsequent vals, and mark this
362+ // wrapper object index as invalid.
363+ var failedInit = false
364+ val renderedVals =
365+ val buf = mutable.ListBuffer [Diagnostic ]()
366+ for d <- vals do if ! failedInit then rendering.renderVal(d) match
367+ case Right (Some (v)) =>
368+ buf += v
369+ case Left (e) =>
370+ buf += rendering.renderError(e, d)
371+ failedInit = true
372+ case _ =>
373+ buf.toList
374+
375+ if failedInit then
376+ // We limit the returned diagnostics here to `renderedVals`, which will contain the rendered error
377+ // for the val which failed to initialize. Since any other defs, aliases, imports, etc. from this
378+ // input line will be inaccessible, we avoid rendering those so as not to confuse the user.
379+ (state.copy(invalidObjectIndexes = state.invalidObjectIndexes + state.objectIndex), renderedVals)
380+ else
381+ val formattedMembers =
382+ typeAliases.map(rendering.renderTypeAlias)
383+ ++ defs.map(rendering.renderMethod)
384+ ++ renderedVals
385+ val diagnostics = if formattedMembers.isEmpty then rendering.forceModule(symbol) else formattedMembers
386+ (state.copy(valIndex = state.valIndex - vals.count(resAndUnit)), diagnostics)
364387 }
365388 else (state, Seq .empty)
366389
@@ -378,8 +401,10 @@ class ReplDriver(settings: Array[String],
378401 tree.symbol.info.memberClasses
379402 .find(_.symbol.name == newestWrapper.moduleClassName)
380403 .map { wrapperModule =>
381- val formattedTypeDefs = typeDefs(wrapperModule.symbol)
382404 val (newState, formattedMembers) = extractAndFormatMembers(wrapperModule.symbol)
405+ val formattedTypeDefs = // don't render type defs if wrapper initialization failed
406+ if newState.invalidObjectIndexes.contains(state.objectIndex) then Seq .empty
407+ else typeDefs(wrapperModule.symbol)
383408 val highlighted = (formattedTypeDefs ++ formattedMembers)
384409 .map(d => new Diagnostic (d.msg.mapMsg(SyntaxHighlighting .highlight), d.pos, d.level))
385410 (newState, highlighted)
@@ -420,7 +445,7 @@ class ReplDriver(settings: Array[String],
420445
421446 case Imports =>
422447 for {
423- objectIndex <- 1 to state.objectIndex
448+ objectIndex <- state.validObjectIndexes
424449 imp <- state.imports.getOrElse(objectIndex, Nil )
425450 } out.println(imp.show(using state.context))
426451 state
0 commit comments