Skip to content

Commit f784625

Browse files
authored
bugfix: Fix enumeration issues when Value is imported (#23124)
This is still not a perfect fix, since we add the full prefix, but that's the current status quo. Making prefixes shorter is something we need to work on separately.
1 parent c3642c0 commit f784625

File tree

4 files changed

+96
-11
lines changed

4 files changed

+96
-11
lines changed

presentation-compiler/src/main/dotty/tools/pc/IndexedContext.scala

+27-7
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ sealed trait IndexedContext:
2323
given ctx: Context
2424
def scopeSymbols: List[Symbol]
2525
def rename(sym: Symbol): Option[String]
26-
def findSymbol(name: Name): Option[List[Symbol]]
26+
def findSymbol(name: Name, fromPrefix: Option[Type] = None): Option[List[Symbol]]
2727
def findSymbolInLocalScope(name: String): Option[List[Symbol]]
2828

29-
final def lookupSym(sym: Symbol): Result =
29+
final def lookupSym(sym: Symbol, fromPrefix: Option[Type] = None): Result =
3030
def all(symbol: Symbol): Set[Symbol] = Set(symbol, symbol.companionModule, symbol.companionClass, symbol.companion).filter(_ != NoSymbol)
3131
val isRelated = all(sym) ++ all(sym.dealiasType)
32-
findSymbol(sym.name) match
32+
findSymbol(sym.name, fromPrefix) match
3333
case Some(symbols) if symbols.exists(isRelated) => Result.InScope
3434
case Some(symbols) if symbols.exists(isTermAliasOf(_, sym)) => Result.InScope
3535
case Some(symbols) if symbols.map(_.dealiasType).exists(isRelated) => Result.InScope
@@ -81,7 +81,7 @@ object IndexedContext:
8181

8282
case object Empty extends IndexedContext:
8383
given ctx: Context = NoContext
84-
def findSymbol(name: Name): Option[List[Symbol]] = None
84+
def findSymbol(name: Name, fromPrefix: Option[Type]): Option[List[Symbol]] = None
8585
def findSymbolInLocalScope(name: String): Option[List[Symbol]] = None
8686
def scopeSymbols: List[Symbol] = List.empty
8787
def rename(sym: Symbol): Option[String] = None
@@ -111,11 +111,31 @@ object IndexedContext:
111111

112112
override def findSymbolInLocalScope(name: String): Option[List[Symbol]] =
113113
names.get(name).map(_.map(_.symbol).toList).filter(_.nonEmpty)
114-
def findSymbol(name: Name): Option[List[Symbol]] =
114+
def findSymbol(name: Name, fromPrefix: Option[Type]): Option[List[Symbol]] =
115115
names
116116
.get(name.show)
117-
.map(_.map(_.symbol).toList)
118-
.orElse(defaultScopes(name))
117+
.map { denots =>
118+
def skipThisType(tp: Type): Type = tp match
119+
case ThisType(prefix) => skipThisType(prefix)
120+
case _ => tp
121+
122+
val filteredDenots = fromPrefix match
123+
case Some(prefix) =>
124+
val target = skipThisType(prefix)
125+
denots.filter { denot =>
126+
denot.prefix == NoPrefix ||
127+
(denot.prefix match
128+
case tref: TermRef =>
129+
tref.termSymbol.info <:< target
130+
case otherPrefix =>
131+
otherPrefix <:< target
132+
)
133+
}
134+
case None => denots
135+
136+
filteredDenots.map(_.symbol).toList
137+
}
138+
.orElse(defaultScopes(name)).filter(_.nonEmpty)
119139

120140
def scopeSymbols: List[Symbol] =
121141
names.values.flatten.map(_.symbol).toList

presentation-compiler/src/main/dotty/tools/pc/InferredTypeProvider.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ final class InferredTypeProvider(
9494
tpe match
9595
case tref: TypeRef =>
9696
indexedCtx.lookupSym(
97-
tref.currentSymbol
97+
tref.currentSymbol,
98+
Some(tref.prefix)
9899
) == IndexedContext.Result.InScope
99100
case AppliedType(tycon, args) =>
100101
isInScope(tycon) && args.forall(isInScope)
@@ -136,7 +137,6 @@ final class InferredTypeProvider(
136137
findNamePos(sourceText, vl, keywordOffset).endPos.toLsp
137138
adjustOpt.foreach(adjust => endPos.setEnd(adjust.adjustedEndPos))
138139
val spaceBefore = name.isOperatorName
139-
140140
new TextEdit(
141141
endPos,
142142
printTypeAscription(optDealias(tpt.typeOpt), spaceBefore) + {

presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,13 @@ class ShortenedTypePrinter(
174174
res.toPrefixText
175175
}
176176

177-
178177
override def toTextPrefixOf(tp: NamedType): Text = controlled {
179178
val maybeRenamedPrefix: Option[Text] = findRename(tp)
180179
def trimmedPrefix: Text =
181180
if !tp.designator.isInstanceOf[Symbol] && tp.typeSymbol == NoSymbol then
182181
super.toTextPrefixOf(tp)
183182
else
184-
indexedCtx.lookupSym(tp.symbol) match
183+
indexedCtx.lookupSym(tp.symbol, Some(tp.prefix)) match
185184
case _ if indexedCtx.rename(tp.symbol).isDefined => Text()
186185
// symbol is missing and is accessible statically, we can import it and add proper prefix
187186
case Result.Missing if isAccessibleStatically(tp.symbol) =>

presentation-compiler/test/dotty/tools/pc/tests/edit/InsertInferredTypeSuite.scala

+66
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,72 @@ class InsertInferredTypeSuite extends BaseCodeActionSuite:
990990
|""".stripMargin
991991
)
992992

993+
@Test def `enums` =
994+
checkEdit(
995+
"""|object EnumerationValue:
996+
| object Day extends Enumeration {
997+
| type Day = Value
998+
| val Weekday, Weekend = Value
999+
| }
1000+
| object Bool extends Enumeration {
1001+
| type Bool = Value
1002+
| val True, False = Value
1003+
| }
1004+
| import Bool._
1005+
| def day(d: Day.Value): Unit = ???
1006+
| val <<d>> =
1007+
| if (true) Day.Weekday
1008+
| else Day.Weekend
1009+
|""".stripMargin,
1010+
"""|object EnumerationValue:
1011+
| object Day extends Enumeration {
1012+
| type Day = Value
1013+
| val Weekday, Weekend = Value
1014+
| }
1015+
| object Bool extends Enumeration {
1016+
| type Bool = Value
1017+
| val True, False = Value
1018+
| }
1019+
| import Bool._
1020+
| def day(d: Day.Value): Unit = ???
1021+
| val d: EnumerationValue.Day.Value =
1022+
| if (true) Day.Weekday
1023+
| else Day.Weekend
1024+
|""".stripMargin
1025+
)
1026+
1027+
@Test def `enums2` =
1028+
checkEdit(
1029+
"""|object EnumerationValue:
1030+
| object Day extends Enumeration {
1031+
| type Day = Value
1032+
| val Weekday, Weekend = Value
1033+
| }
1034+
| object Bool extends Enumeration {
1035+
| type Bool = Value
1036+
| val True, False = Value
1037+
| }
1038+
| import Bool._
1039+
| val <<b>> =
1040+
| if (true) True
1041+
| else False
1042+
|""".stripMargin,
1043+
"""|object EnumerationValue:
1044+
| object Day extends Enumeration {
1045+
| type Day = Value
1046+
| val Weekday, Weekend = Value
1047+
| }
1048+
| object Bool extends Enumeration {
1049+
| type Bool = Value
1050+
| val True, False = Value
1051+
| }
1052+
| import Bool._
1053+
| val b: Value =
1054+
| if (true) True
1055+
| else False
1056+
|""".stripMargin
1057+
)
1058+
9931059
def checkEdit(
9941060
original: String,
9951061
expected: String

0 commit comments

Comments
 (0)