Skip to content

Commit b52748e

Browse files
committed
Improve "...is not stable" error message
Give some context why an immutable path is required, and explain what an immutable path is.
1 parent f58e245 commit b52748e

File tree

6 files changed

+27
-14
lines changed

6 files changed

+27
-14
lines changed

compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] {
9191
ExpectedTopLevelDefID,
9292
AnonymousFunctionMissingParamTypeID,
9393
SuperCallsNotAllowedInlineableID,
94-
UNUSED1, // not used anymore, but left so that error numbers stay the same
94+
NotAPathID,
9595
WildcardOnTypeArgumentNotAllowedOnNewID,
9696
FunctionTypeNeedsNonEmptyParameterListID,
9797
WrongNumberOfParametersID,

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1701,10 +1701,19 @@ object messages {
17011701
case class SuperCallsNotAllowedInlineable(symbol: Symbol)(implicit ctx: Context)
17021702
extends Message(SuperCallsNotAllowedInlineableID) {
17031703
val kind: String = "Syntax"
1704-
val msg: String = s"Super call not allowed in inlineable $symbol"
1704+
val msg: String = em"Super call not allowed in inlineable $symbol"
17051705
val explanation: String = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called."
17061706
}
17071707

1708+
case class NotAPath(tp: Type, usage: String)(using Context) extends Message(NotAPathID):
1709+
val kind: String = "Type"
1710+
val msg: String = em"$tp is not a valid $usage, since it is not an immutable path"
1711+
val explanation: String =
1712+
i"""An immutable path is
1713+
| - a reference to an immutable value, or
1714+
| - a reference to `this`, or
1715+
| - a selection of an immutable path with an immutable value."""
1716+
17081717
case class WrongNumberOfParameters(expected: Int)(implicit ctx: Context)
17091718
extends Message(WrongNumberOfParametersID) {
17101719
val kind: String = "Syntax"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
239239

240240
tag.tpe match
241241
case tp: TermRef =>
242-
checkStable(tp, pos)
242+
checkStable(tp, pos, "type witness")
243243
Some(ref(getQuoteTypeTags.getTagRef(tp)))
244244
case _: SearchFailureType =>
245245
levelError(sym, tp, pos,

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,8 @@ trait Checking {
652652
Checking.checkNonCyclicInherited(joint, parents, decls, posd)
653653

654654
/** Check that type `tp` is stable. */
655-
def checkStable(tp: Type, pos: SourcePosition)(implicit ctx: Context): Unit =
656-
if (!tp.isStable) ctx.error(ex"$tp is not stable", pos)
655+
def checkStable(tp: Type, pos: SourcePosition, kind: String)(implicit ctx: Context): Unit =
656+
if !tp.isStable then ctx.error(NotAPath(tp, kind), pos)
657657

658658
/** Check that all type members of `tp` have realizable bounds */
659659
def checkRealizableBounds(cls: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = {
@@ -712,7 +712,7 @@ trait Checking {
712712

713713
/** Check that `path` is a legal prefix for an import or export clause */
714714
def checkLegalImportPath(path: Tree)(implicit ctx: Context): Unit = {
715-
checkStable(path.tpe, path.sourcePos)
715+
checkStable(path.tpe, path.sourcePos, "import prefix")
716716
if (!ctx.isAfterTyper) Checking.checkRealizable(path.tpe, path.posd)
717717
}
718718

@@ -726,7 +726,7 @@ trait Checking {
726726
tp.underlyingClassRef(refinementOK = false) match {
727727
case tref: TypeRef =>
728728
if (traitReq && !tref.symbol.is(Trait)) ctx.error(TraitIsExpected(tref.symbol), pos)
729-
if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos)
729+
if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos, "class prefix")
730730
tp
731731
case _ =>
732732
ctx.error(ex"$tp is not a class type", pos)
@@ -1194,7 +1194,7 @@ trait NoChecking extends ReChecking {
11941194
import tpd._
11951195
override def checkNonCyclic(sym: Symbol, info: TypeBounds, reportErrors: Boolean)(implicit ctx: Context): Type = info
11961196
override def checkNonCyclicInherited(joint: Type, parents: List[Type], decls: Scope, posd: Positioned)(implicit ctx: Context): Unit = ()
1197-
override def checkStable(tp: Type, pos: SourcePosition)(implicit ctx: Context): Unit = ()
1197+
override def checkStable(tp: Type, pos: SourcePosition, kind: String)(implicit ctx: Context): Unit = ()
11981198
override def checkClassType(tp: Type, pos: SourcePosition, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp
11991199
override def checkImplicitConversionDefOK(sym: Symbol)(implicit ctx: Context): Unit = ()
12001200
override def checkImplicitConversionUseOK(sym: Symbol, posd: Positioned)(implicit ctx: Context): Unit = ()

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ class Typer extends Namer
491491
case _ => app
492492
}
493493
case qual =>
494-
if (tree.name.isTypeName) checkStable(qual.tpe, qual.sourcePos)
494+
if (tree.name.isTypeName) checkStable(qual.tpe, qual.sourcePos, "type prefix")
495495
val select = assignType(cpy.Select(tree)(qual, tree.name), qual)
496496

497497
val select1 = toNotNullTermRef(select, pt)
@@ -1429,7 +1429,7 @@ class Typer extends Namer
14291429

14301430
def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = {
14311431
val ref1 = typedExpr(tree.ref)
1432-
checkStable(ref1.tpe, tree.sourcePos)
1432+
checkStable(ref1.tpe, tree.sourcePos, "singleton type")
14331433
assignType(cpy.SingletonTypeTree(tree)(ref1), ref1)
14341434
}
14351435

tests/neg/i8569.check

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
-- Error: tests/neg/i8569.scala:8:2 ------------------------------------------------------------------------------------
1+
-- [E083] Type Error: tests/neg/i8569.scala:8:2 ------------------------------------------------------------------------
22
8 | outer.Inner(2) // error
33
| ^^^^^
4-
| (Test.outer : => Outer) is not a valid path
5-
-- Error: tests/neg/i8569.scala:9:6 ------------------------------------------------------------------------------------
4+
| (Test.outer : => Outer) is not a valid type prefix, since it is not an immutable path
5+
6+
longer explanation available when compiling with `-explain`
7+
-- [E083] Type Error: tests/neg/i8569.scala:9:6 ------------------------------------------------------------------------
68
9 | new outer.Inner(2) // error
79
| ^^^^^
8-
| (Test.outer : => Outer) is not a valid path
10+
| (Test.outer : => Outer) is not a valid type prefix, since it is not an immutable path
11+
12+
longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)