Skip to content

Commit 469e5ec

Browse files
committed
Merge branch 'main' of https://github.com/rochala/dotty into illegal-access-extension-error-message
2 parents 689a69e + 6ae7291 commit 469e5ec

File tree

103 files changed

+816
-251
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+816
-251
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeIdiomatic.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ trait BCodeIdiomatic {
5252
case "15" => asm.Opcodes.V15
5353
case "16" => asm.Opcodes.V16
5454
case "17" => asm.Opcodes.V17
55+
case "18" => asm.Opcodes.V18
5556
}
5657

5758
lazy val majorVersion: Int = (classfileVersion & 0xFF)

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ScalaSettings extends SettingGroup with AllScalaSettings
1616
object ScalaSettings:
1717
// Keep synchronized with `classfileVersion` in `BCodeIdiomatic`
1818
private val minTargetVersion = 8
19-
private val maxTargetVersion = 17
19+
private val maxTargetVersion = 18
2020

2121
def supportedTargetVersions: List[String] =
2222
(minTargetVersion to maxTargetVersion).toList.map(_.toString)

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,11 +1764,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
17641764
case _ => false
17651765

17661766
/** Does type `tp1` have a member with name `name` whose normalized type is a subtype of
1767-
* the normalized type of the refinement `tp2`?
1767+
* the normalized type of the refinement of `tp2`?
17681768
* Normalization is as follows: If `tp2` contains a skolem to its refinement type,
17691769
* rebase both itself and the member info of `tp` on a freshly created skolem type.
17701770
*/
1771-
protected def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean =
1771+
def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType): Boolean =
17721772
trace(i"hasMatchingMember($tp1 . $name :? ${tp2.refinedInfo}), mbr: ${tp1.member(name).info}", subtyping) {
17731773

17741774
def qualifies(m: SingleDenotation): Boolean =
@@ -2750,6 +2750,9 @@ object TypeComparer {
27502750
def matchesType(tp1: Type, tp2: Type, relaxed: Boolean)(using Context): Boolean =
27512751
comparing(_.matchesType(tp1, tp2, relaxed))
27522752

2753+
def hasMatchingMember(name: Name, tp1: Type, tp2: RefinedType)(using Context): Boolean =
2754+
comparing(_.hasMatchingMember(name, tp1, tp2))
2755+
27532756
def matchingMethodParams(tp1: MethodType, tp2: MethodType)(using Context): Boolean =
27542757
comparing(_.matchingMethodParams(tp1, tp2))
27552758

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,9 +556,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
556556
case TypeBoundsTree(lo, hi, alias) =>
557557
if (lo eq hi) && alias.isEmpty then optText(lo)(" = " ~ _)
558558
else optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _) ~ optText(alias)(" = " ~ _)
559-
case Bind(name, body) =>
559+
case bind @ Bind(name, body) =>
560560
keywordText("given ").provided(tree.symbol.isOneOf(GivenOrImplicit) && !homogenizedView) ~ // Used for scala.quoted.Type in quote patterns (not pickled)
561-
changePrec(InfixPrec) { toText(name) ~ " @ " ~ toText(body) }
561+
changePrec(InfixPrec) { nameIdText(bind) ~ " @ " ~ toText(body) }
562562
case Alternative(trees) =>
563563
changePrec(OrPrec) { toText(trees, " | ") }
564564
case UnApply(fun, implicits, patterns) =>

compiler/src/dotty/tools/dotc/transform/Dependencies.scala

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,18 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co
179179
if enclClass.isContainedIn(thisClass) then thisClass
180180
else enclClass) // unknown this reference, play it safe and assume the narrowest possible owner
181181

182+
def setLogicOwner(local: Symbol) =
183+
val encClass = local.owner.enclosingClass
184+
val preferEncClass =
185+
encClass.isStatic
186+
// non-static classes can capture owners, so should be avoided
187+
&& (encClass.isProperlyContainedIn(local.topLevelClass)
188+
// can be false for symbols which are defined in some weird combination of supercalls.
189+
|| encClass.is(ModuleClass, butNot = Package)
190+
// needed to not cause deadlocks in classloader. see t5375.scala
191+
)
192+
logicOwner(sym) = if preferEncClass then encClass else local.enclosingPackageClass
193+
182194
tree match
183195
case tree: Ident =>
184196
if isLocal(sym) then
@@ -194,7 +206,7 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co
194206
case tree: This =>
195207
narrowTo(tree.symbol.asClass)
196208
case tree: MemberDef if isExpr(sym) && sym.owner.isTerm =>
197-
logicOwner(sym) = sym.enclosingPackageClass
209+
setLogicOwner(sym)
198210
// this will make methods in supercall constructors of top-level classes owned
199211
// by the enclosing package, which means they will be static.
200212
// On the other hand, all other methods will be indirectly owned by their
@@ -205,8 +217,8 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co
205217
// the class itself. This is done so that the constructor inherits
206218
// the free variables of the class.
207219
symSet(called, sym) += sym.owner
208-
case tree: TypeDef =>
209-
if sym.owner.isTerm then logicOwner(sym) = sym.topLevelClass.owner
220+
case tree: TypeDef if sym.owner.isTerm =>
221+
setLogicOwner(sym)
210222
case _ =>
211223
end process
212224

compiler/src/dotty/tools/dotc/transform/LambdaLift.scala

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,7 @@ object LambdaLift:
9494
private def liftLocals()(using Context): Unit = {
9595
for ((local, lOwner) <- deps.logicalOwner) {
9696
val (newOwner, maybeStatic) =
97-
if (lOwner is Package) {
98-
val encClass = local.enclosingClass
99-
val topClass = local.topLevelClass
100-
val preferEncClass =
101-
encClass.isStatic &&
102-
// non-static classes can capture owners, so should be avoided
103-
(encClass.isProperlyContainedIn(topClass) ||
104-
// can be false for symbols which are defined in some weird combination of supercalls.
105-
encClass.is(ModuleClass, butNot = Package)
106-
// needed to not cause deadlocks in classloader. see t5375.scala
107-
)
108-
if (preferEncClass) (encClass, EmptyFlags)
109-
else (topClass, JavaStatic)
110-
}
97+
if lOwner is Package then (local.topLevelClass, JavaStatic)
11198
else (lOwner, EmptyFlags)
11299
// Drop Module because class is no longer a singleton in the lifted context.
113100
var initFlags = local.flags &~ Module | Private | Lifted | maybeStatic

compiler/src/dotty/tools/dotc/transform/MegaPhase.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -418,12 +418,16 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
418418
}
419419
}
420420

421-
if (tree.source != ctx.source && tree.source.exists)
422-
transformTree(tree, start)(using ctx.withSource(tree.source))
423-
else if (tree.isInstanceOf[NameTree])
424-
transformNamed(tree, start, ctx)
425-
else
426-
transformUnnamed(tree, start, ctx)
421+
// try
422+
if (tree.source != ctx.source && tree.source.exists)
423+
transformTree(tree, start)(using ctx.withSource(tree.source))
424+
else if (tree.isInstanceOf[NameTree])
425+
transformNamed(tree, start, ctx)
426+
else
427+
transformUnnamed(tree, start, ctx)
428+
// catch case ex: AssertionError =>
429+
// println(i"error while transforming $tree")
430+
// throw ex
427431
}
428432

429433
def transformSpecificTree[T <: Tree](tree: T, start: Int)(using Context): T =

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ object TypeTestsCasts {
150150
case AndType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)
151151
case OrType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)
152152
case AnnotatedType(t, _) => recur(X, t)
153-
case _: RefinedType => false
153+
case tp2: RefinedType => recur(X, tp2.parent) && TypeComparer.hasMatchingMember(tp2.refinedName, X, tp2)
154154
case _ => true
155155
})
156156

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1876,7 +1876,7 @@ trait Applications extends Compatibility {
18761876
* formal parameter that is a unary function.
18771877
*/
18781878
def normArg(alts: List[TermRef], arg: untpd.Tree, idx: Int): untpd.Tree = arg match
1879-
case Block(Nil, expr) => normArg(alts, expr, idx)
1879+
case Block(Nil, expr) if !expr.isEmpty => normArg(alts, expr, idx)
18801880
case untpd.Function(args: List[untpd.ValDef] @unchecked, body) =>
18811881

18821882
// If ref refers to a method whose parameter at index `idx` is a function type,

compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -306,15 +306,13 @@ class ImplicitSearchError(
306306

307307
private def location(preposition: String) = if (where.isEmpty) "" else s" $preposition $where"
308308

309-
private def defaultAmbiguousImplicitMsg(ambi: AmbiguousImplicits) = {
310-
formatMsg(s"ambiguous implicit arguments: ${ambi.explanation}${location("of")}")(
311-
s"ambiguous implicit arguments of type ${pt.show} found${location("for")}"
309+
private def defaultAmbiguousImplicitMsg(ambi: AmbiguousImplicits) =
310+
formatMsg(s"ambiguous given instances: ${ambi.explanation}${location("of")}")(
311+
s"ambiguous given instances of type ${pt.show} found${location("for")}"
312312
)
313-
}
314313

315-
private def defaultImplicitNotFoundMessage = {
316-
ex"no implicit argument of type $pt was found${location("for")}"
317-
}
314+
private def defaultImplicitNotFoundMessage =
315+
ex"no given instance of type $pt was found${location("for")}"
318316

319317
/** Construct a custom error message given an ambiguous implicit
320318
* candidate `alt` and a user defined message `raw`.

compiler/src/dotty/tools/repl/Rendering.scala

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,25 +129,31 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None) {
129129
infoDiagnostic(d.symbol.showUser, d)
130130

131131
/** Render value definition result */
132-
def renderVal(d: Denotation)(using Context): Option[Diagnostic] =
132+
def renderVal(d: Denotation)(using Context): Either[InvocationTargetException, Option[Diagnostic]] =
133133
val dcl = d.symbol.showUser
134134
def msg(s: String) = infoDiagnostic(s, d)
135135
try
136-
if (d.symbol.is(Flags.Lazy)) Some(msg(dcl))
137-
else valueOf(d.symbol).map(value => msg(s"$dcl = $value"))
138-
catch case e: InvocationTargetException => Some(msg(renderError(e, d)))
136+
Right(
137+
if d.symbol.is(Flags.Lazy) then Some(msg(dcl))
138+
else valueOf(d.symbol).map(value => msg(s"$dcl = $value"))
139+
)
140+
catch case e: InvocationTargetException => Left(e)
139141
end renderVal
140142

141143
/** Force module initialization in the absence of members. */
142144
def forceModule(sym: Symbol)(using Context): Seq[Diagnostic] =
145+
import scala.util.control.NonFatal
143146
def load() =
144147
val objectName = sym.fullName.encode.toString
145148
Class.forName(objectName, true, classLoader())
146149
Nil
147-
try load() catch case e: ExceptionInInitializerError => List(infoDiagnostic(renderError(e, sym.denot), sym.denot))
150+
try load()
151+
catch
152+
case e: ExceptionInInitializerError => List(renderError(e, sym.denot))
153+
case NonFatal(e) => List(renderError(InvocationTargetException(e), sym.denot))
148154

149155
/** Render the stack trace of the underlying exception. */
150-
private def renderError(ite: InvocationTargetException | ExceptionInInitializerError, d: Denotation)(using Context): String =
156+
def renderError(ite: InvocationTargetException | ExceptionInInitializerError, d: Denotation)(using Context): Diagnostic =
151157
import dotty.tools.dotc.util.StackTraceOps._
152158
val cause = ite.getCause match
153159
case e: ExceptionInInitializerError => e.getCause
@@ -159,7 +165,7 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None) {
159165
ste.getClassName.startsWith(REPL_WRAPPER_NAME_PREFIX) // d.symbol.owner.name.show is simple name
160166
&& (ste.getMethodName == nme.STATIC_CONSTRUCTOR.show || ste.getMethodName == nme.CONSTRUCTOR.show)
161167

162-
cause.formatStackTracePrefix(!isWrapperInitialization(_))
168+
infoDiagnostic(cause.formatStackTracePrefix(!isWrapperInitialization(_)), d)
163169
end renderError
164170

165171
private def infoDiagnostic(msg: String, d: Denotation)(using Context): Diagnostic =

compiler/src/dotty/tools/repl/ReplCompiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class ReplCompiler extends Compiler {
6161
val rootCtx = super.rootContext.fresh
6262
.setOwner(defn.EmptyPackageClass)
6363
.withRootImports
64-
(1 to state.objectIndex).foldLeft(rootCtx)((ctx, id) =>
64+
(state.validObjectIndexes).foldLeft(rootCtx)((ctx, id) =>
6565
importPreviousRun(id)(using ctx))
6666
}
6767
}

compiler/src/dotty/tools/repl/ReplDriver.scala

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import dotty.tools.runner.ScalaClassLoader.*
3535
import org.jline.reader._
3636

3737
import scala.annotation.tailrec
38+
import scala.collection.mutable
3839
import scala.collection.JavaConverters._
3940
import 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
*/
6062
case 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 */
6670
class 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

Comments
 (0)