@@ -35,6 +35,7 @@ import dotty.tools.runner.ScalaClassLoader.*
35
35
import org .jline .reader ._
36
36
37
37
import scala .annotation .tailrec
38
+ import scala .collection .mutable
38
39
import scala .collection .JavaConverters ._
39
40
import scala .util .Using
40
41
@@ -55,12 +56,15 @@ import scala.util.Using
55
56
* @param objectIndex the index of the next wrapper
56
57
* @param valIndex the index of next value binding for free expressions
57
58
* @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
58
60
* @param context the latest compiler context
59
61
*/
60
62
case class State (objectIndex : Int ,
61
63
valIndex : Int ,
62
64
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(_))
64
68
65
69
/** Main REPL instance, orchestrating input, compilation and presentation */
66
70
class ReplDriver (settings : Array [String ],
@@ -94,7 +98,7 @@ class ReplDriver(settings: Array[String],
94
98
}
95
99
96
100
/** 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)
98
102
99
103
/** Reset state of repl to the initial state
100
104
*
@@ -237,7 +241,7 @@ class ReplDriver(settings: Array[String],
237
241
completions.map(_.label).distinct.map(makeCandidate)
238
242
}
239
243
.getOrElse(Nil )
240
- end completions
244
+ end completions
241
245
242
246
private def interpret (res : ParseResult )(implicit state : State ): State = {
243
247
res match {
@@ -353,14 +357,33 @@ class ReplDriver(settings: Array[String],
353
357
val typeAliases =
354
358
info.bounds.hi.typeMembers.filter(_.symbol.info.isTypeAlias)
355
359
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)
364
387
}
365
388
else (state, Seq .empty)
366
389
@@ -378,8 +401,10 @@ class ReplDriver(settings: Array[String],
378
401
tree.symbol.info.memberClasses
379
402
.find(_.symbol.name == newestWrapper.moduleClassName)
380
403
.map { wrapperModule =>
381
- val formattedTypeDefs = typeDefs(wrapperModule.symbol)
382
404
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)
383
408
val highlighted = (formattedTypeDefs ++ formattedMembers)
384
409
.map(d => new Diagnostic (d.msg.mapMsg(SyntaxHighlighting .highlight), d.pos, d.level))
385
410
(newState, highlighted)
@@ -420,7 +445,7 @@ class ReplDriver(settings: Array[String],
420
445
421
446
case Imports =>
422
447
for {
423
- objectIndex <- 1 to state.objectIndex
448
+ objectIndex <- state.validObjectIndexes
424
449
imp <- state.imports.getOrElse(objectIndex, Nil )
425
450
} out.println(imp.show(using state.context))
426
451
state
0 commit comments