Skip to content

Commit 58e084e

Browse files
committed
alternative using select error addendum
1 parent ca14396 commit 58e084e

File tree

6 files changed

+67
-55
lines changed

6 files changed

+67
-55
lines changed

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -151,31 +151,9 @@ object DesugarEnums {
151151
valueOfDef :: Nil
152152
}
153153

154-
/** This generates the same public API as `enumScaffolding`, but stubs implementations to fail at compiletime and
155-
* not generate bytecode
156-
*/
157-
private def enumScaffoldingStubbed(using Context): List[Tree] = {
158-
val rawEnumClassRef = rawRef(enumClass.typeRef)
159-
extension (tpe: NamedType) def ofRawEnum = AppliedTypeTree(ref(tpe), rawEnumClassRef)
160-
161-
def stub(description: String) = Apply(ref(defn.Compiletime_error), Literal(Constant(
162-
i"Although $enumClass is an enum, it has non-singleton cases, which prevents it from having a $description")))
163-
164-
val valuesDef = DefDef(nme.values, Nil, Nil, defn.ArrayType.ofRawEnum, stub(i"${nme.values} array"))
165-
.withFlags(Synthetic | Inline)
166-
167-
val valueOfDef = DefDef(nme.valueOf, Nil, List(param(nme.nameDollar, defn.StringType) :: Nil),
168-
TypeTree(), stub(i"${nme.valueOf} lookup method"))
169-
.withFlags(Synthetic | Inline)
170-
171-
valuesDef ::
172-
valueOfDef :: Nil
173-
}
174-
175154
private def enumLookupMethods(constraints: EnumConstraints)(using Context): List[Tree] =
176155
def scaffolding: List[Tree] =
177-
if constraints.isEnumeration then enumScaffolding(constraints.enumCases.map(_._2))
178-
else enumScaffoldingStubbed
156+
if constraints.isEnumeration then enumScaffolding(constraints.enumCases.map(_._2)) else Nil
179157
def valueCtor: List[Tree] = if constraints.requiresCreator then enumValueCreator :: Nil else Nil
180158
def fromOrdinal: Tree =
181159
def throwArg(ordinal: Tree) =

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ package typer
44

55
import ast._
66
import core._
7-
import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._
7+
import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._, Names._
88
import Implicits._, Flags._, Constants.Constant
99
import util.Spans._
1010
import util.SrcPos
1111
import config.Feature
1212
import java.util.regex.Matcher.quoteReplacement
1313
import reporting._
14+
import transform.SymUtils._
15+
import StdNames._
1416

1517
object ErrorReporting {
1618

@@ -145,7 +147,7 @@ object ErrorReporting {
145147
else ""
146148

147149
def selectErrorAddendum
148-
(tree: untpd.RefTree, qual1: Tree, qualType: Type, suggestImports: Type => String)
150+
(tree: untpd.RefTree, qual1: Tree, qualType: Type, name: Name, suggestImports: Type => String)
149151
(using Context): String =
150152
val attempts: List[Tree] = qual1.getAttachment(Typer.HiddenSearchFailure) match
151153
case Some(failures) =>
@@ -171,6 +173,13 @@ object ErrorReporting {
171173
|or drop any spaces behind the operator."""
172174
else if qualType.isBottomType then
173175
""
176+
else if ((name eq nme.values) || (name eq nme.valueOf)) && qualType.classSymbol.companionClass.isEnumClass then
177+
val kind = if name eq nme.values then i"${nme.values} array" else i"${nme.valueOf} lookup method"
178+
// an assumption is made here that the values and valueOf methods were not generated
179+
// because the enum defines non-singleton cases
180+
i""".
181+
|Although ${qualType.classSymbol.companionClass} is an enum, it has non-singleton cases,
182+
|which prevents it from having a $kind."""
174183
else
175184
val add = suggestImports(
176185
ViewProto(qualType.widen,

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ trait TypeAssigner {
163163
errorType(ex"$qualType does not have a constructor", tree.srcPos)
164164
else {
165165
val kind = if (name.isTypeName) "type" else "value"
166-
def addendum = err.selectErrorAddendum(tree, qual1, qualType, importSuggestionAddendum)
166+
def addendum = err.selectErrorAddendum(tree, qual1, qualType, name, importSuggestionAddendum)
167167
errorType(NotAMember(qualType, name, kind, addendum), tree.srcPos)
168168
}
169169
}
@@ -520,4 +520,3 @@ trait TypeAssigner {
520520

521521

522522
object TypeAssigner extends TypeAssigner
523-

tests/neg/enum-values.check

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,44 @@
1-
-- Error: tests/neg/enum-values.scala:19:45 ----------------------------------------------------------------------------
2-
19 | val tags: Array[Tag[?]] = Tag.values // error
1+
-- [E008] Not Found Error: tests/neg/enum-values.scala:28:45 -----------------------------------------------------------
2+
28 | val tags: Array[Tag[?]] = Tag.values // error
33
| ^^^^^^^^^^
4-
| Although class Tag is an enum, it has non-singleton cases, which prevents it from having a values array
5-
-- Error: tests/neg/enum-values.scala:20:50 ----------------------------------------------------------------------------
6-
20 | val listlikes: Array[ListLike[?]] = ListLike.values // error
4+
| value values is not a member of object example.Tag.
5+
| Although class Tag is an enum, it has non-singleton cases,
6+
| which prevents it from having a values array.
7+
-- [E008] Not Found Error: tests/neg/enum-values.scala:29:50 -----------------------------------------------------------
8+
29 | val listlikes: Array[ListLike[?]] = ListLike.values // error
79
| ^^^^^^^^^^^^^^^
8-
| Although class ListLike is an enum, it has non-singleton cases, which prevents it from having a values array
9-
-- Error: tests/neg/enum-values.scala:21:52 ----------------------------------------------------------------------------
10-
21 | val typeCtorsK: Array[TypeCtorsK[?]] = TypeCtorsK.values // error
10+
| value values is not a member of object example.ListLike.
11+
| Although class ListLike is an enum, it has non-singleton cases,
12+
| which prevents it from having a values array.
13+
-- [E008] Not Found Error: tests/neg/enum-values.scala:30:52 -----------------------------------------------------------
14+
30 | val typeCtorsK: Array[TypeCtorsK[?]] = TypeCtorsK.values // error
1115
| ^^^^^^^^^^^^^^^^^
12-
| Although class TypeCtorsK is an enum, it has non-singleton cases, which prevents it from having a values array
13-
-- Error: tests/neg/enum-values.scala:23:13 ----------------------------------------------------------------------------
14-
23 | Tag.valueOf("Int") // error
16+
| value values is not a member of object example.TypeCtorsK.
17+
| Although class TypeCtorsK is an enum, it has non-singleton cases,
18+
| which prevents it from having a values array.
19+
-- [E008] Not Found Error: tests/neg/enum-values.scala:32:6 ------------------------------------------------------------
20+
32 | Tag.valueOf("Int") // error
21+
| ^^^^^^^^^^^
22+
| value valueOf is not a member of object example.Tag.
23+
| Although class Tag is an enum, it has non-singleton cases,
24+
| which prevents it from having a valueOf lookup method.
25+
-- [E008] Not Found Error: tests/neg/enum-values.scala:33:11 -----------------------------------------------------------
26+
33 | ListLike.valueOf("EmptyListLike") // error
27+
| ^^^^^^^^^^^^^^^^
28+
| value valueOf is not a member of object example.ListLike.
29+
| Although class ListLike is an enum, it has non-singleton cases,
30+
| which prevents it from having a valueOf lookup method.
31+
-- [E008] Not Found Error: tests/neg/enum-values.scala:34:13 -----------------------------------------------------------
32+
34 | TypeCtorsK.valueOf("Option") // error
1533
| ^^^^^^^^^^^^^^^^^^
16-
|Although class Tag is an enum, it has non-singleton cases, which prevents it from having a valueOf lookup method
17-
-- Error: tests/neg/enum-values.scala:24:18 ----------------------------------------------------------------------------
18-
24 | ListLike.valueOf("EmptyListLike") // error
19-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20-
|Although class ListLike is an enum, it has non-singleton cases, which prevents it from having a valueOf lookup method
21-
-- Error: tests/neg/enum-values.scala:25:20 ----------------------------------------------------------------------------
22-
25 | TypeCtorsK.valueOf("Option") // error
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24-
|Although class TypeCtorsK is an enum, it has non-singleton cases, which prevents it from having a valueOf lookup method
34+
| value valueOf is not a member of object example.TypeCtorsK.
35+
| Although class TypeCtorsK is an enum, it has non-singleton cases,
36+
| which prevents it from having a valueOf lookup method.
37+
-- [E008] Not Found Error: tests/neg/enum-values.scala:36:12 -----------------------------------------------------------
38+
36 | NotAnEnum.values // error
39+
| ^^^^^^^^^^^^^^^^
40+
| value values is not a member of object example.NotAnEnum
41+
-- [E008] Not Found Error: tests/neg/enum-values.scala:37:12 -----------------------------------------------------------
42+
37 | NotAnEnum.valueOf("Foo") // error
43+
| ^^^^^^^^^^^^^^^^^
44+
| value valueOf is not a member of object example.NotAnEnum

tests/neg/enum-values.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
package example
2+
13
enum Tag[T]:
24
case Int extends Tag[Int]
35
case String extends Tag[String]
@@ -6,15 +8,22 @@ enum Tag[T]:
68
enum ListLike[+T]:
79
case Cons[T](head: T, tail: ListLike[T]) extends ListLike[T]
810
case EmptyListLike
11+
object ListLike:
12+
def valuef(s: String): ListLike[?] = ??? // this will usually trigger a "- did you mean ListLike.valuef" addendum
13+
14+
object Extensions:
15+
extension (TagModule: Tag.type) // this will usually trigger an import suggestions addendum
16+
def values: Array[Tag[?]] = ???
917

1018
enum TypeCtorsK[F[_]]:
1119
case List extends TypeCtorsK[List]
1220
case Option extends TypeCtorsK[Option]
1321
case Const[T]() extends TypeCtorsK[[U] =>> T]
1422

23+
object NotAnEnum // object without a companion class
24+
1525
def Test: Unit =
1626
import Tag._, ListLike._, TypeCtorsK._
17-
import reflect.Selectable.reflectiveSelectable
1827

1928
val tags: Array[Tag[?]] = Tag.values // error
2029
val listlikes: Array[ListLike[?]] = ListLike.values // error
@@ -23,3 +32,6 @@ def Test: Unit =
2332
Tag.valueOf("Int") // error
2433
ListLike.valueOf("EmptyListLike") // error
2534
TypeCtorsK.valueOf("Option") // error
35+
36+
NotAnEnum.values // error
37+
NotAnEnum.valueOf("Foo") // error

tests/semanticdb/metac.expect

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ Schema => SemanticDB v4
641641
Uri => Enums.scala
642642
Text => empty
643643
Language => Scala
644-
Symbols => 187 entries
644+
Symbols => 181 entries
645645
Occurrences => 203 entries
646646

647647
Symbols:
@@ -720,9 +720,6 @@ _empty_/Enums.Maybe.Just.unapply().[A] => typeparam A
720720
_empty_/Enums.Maybe.None. => case val static enum method None
721721
_empty_/Enums.Maybe.fromOrdinal(). => method fromOrdinal
722722
_empty_/Enums.Maybe.fromOrdinal().(ordinal) => param ordinal
723-
_empty_/Enums.Maybe.valueOf(). => macro valueOf
724-
_empty_/Enums.Maybe.valueOf().($name) => param $name
725-
_empty_/Enums.Maybe.values(). => macro values
726723
_empty_/Enums.Planet# => abstract sealed enum class Planet
727724
_empty_/Enums.Planet#G. => final val method G
728725
_empty_/Enums.Planet#`<init>`(). => primary ctor <init>
@@ -822,9 +819,6 @@ _empty_/Enums.`<:<`.fromOrdinal(). => method fromOrdinal
822819
_empty_/Enums.`<:<`.fromOrdinal().(ordinal) => param ordinal
823820
_empty_/Enums.`<:<`.given_T(). => final implicit method given_T
824821
_empty_/Enums.`<:<`.given_T().[T] => typeparam T
825-
_empty_/Enums.`<:<`.valueOf(). => macro valueOf
826-
_empty_/Enums.`<:<`.valueOf().($name) => param $name
827-
_empty_/Enums.`<:<`.values(). => macro values
828822
_empty_/Enums.extension_unwrap(). => method extension_unwrap
829823
_empty_/Enums.extension_unwrap().(ev) => implicit param ev
830824
_empty_/Enums.extension_unwrap().(opt) => param opt

0 commit comments

Comments
 (0)