Skip to content

Commit 493f654

Browse files
smartertgodzik
authored andcommitted
Don't approximate a type using Nothing as prefix
Approximate range(Nothing, hi) to Nothing & hi instead of Nothing. This avoids creating TypeRefs with a Nothing prefix which manifest themselves down the line with an error like: Cannot resolve reference to type path.type.AbsMember. The classfile defining the type might be missing from the classpath. val z1 = transition(di).ext(1) // error ^ Due to a MissingType thrown from TypeErasure#sigName. This change required tweaking Type#findMember to handle WildcardTypes instead of returning NoDenotation. This was only required for two tests (tests/pos/i7414.scala and tests/pos/i13842.scala) where `wildApprox` ends up creating a TermRef whose underlying type is a WildcardType, because of a type parameter being substituted by a wildcard, which seems legitimate when we're using `wildApprox`. The presentation compiler also had a special case for Nothing appearing in completion which had to be adapted. Fixes scala#23530 [Cherry-picked 9f4179a]
1 parent 705b7aa commit 493f654

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,8 @@ object Types extends TypeUtils {
792792
goOr(tp)
793793
case tp: JavaArrayType =>
794794
defn.ObjectType.findMember(name, pre, required, excluded)
795+
case tp: WildcardType =>
796+
go(tp.bounds)
795797
case err: ErrorType =>
796798
newErrorSymbol(pre.classSymbol.orElse(defn.RootClass), name, err.msg)
797799
case _ =>
@@ -6052,9 +6054,24 @@ object Types extends TypeUtils {
60526054
abstract class ApproximatingTypeMap(using Context) extends TypeMap { thisMap =>
60536055

60546056
protected def range(lo: Type, hi: Type): Type =
6055-
if (variance > 0) hi
6056-
else if (variance < 0) lo
6057-
else if (lo `eq` hi) lo
6057+
if variance > 0 then hi
6058+
else if variance < 0 then
6059+
if (lo eq defn.NothingType) && hi.hasSimpleKind then
6060+
// Approximate by Nothing & hi instead of just Nothing, in case the
6061+
// approximated type is used as the prefix of another type (this would
6062+
// lead to a type with a `NoDenotation` denot and a possible
6063+
// MissingType in `TypeErasure#sigName`).
6064+
//
6065+
// Note that we cannot simply check for a `Nothing` prefix in
6066+
// `derivedSelect`, because the substitution might be done lazily (for
6067+
// example if Nothing is the type of a parameter being depended on in
6068+
// a MethodType)
6069+
//
6070+
// Test case in tests/pos/i23530.scala
6071+
AndType(lo, hi)
6072+
else
6073+
lo
6074+
else if lo `eq` hi then lo
60586075
else Range(lower(lo), upper(hi))
60596076

60606077
protected def emptyRange = range(defn.NothingType, defn.AnyType)

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ import dotty.tools.dotc.core.Names
1717
import dotty.tools.dotc.core.Names.Name
1818
import dotty.tools.dotc.core.Names.NameOrdering
1919
import dotty.tools.dotc.core.StdNames
20-
import dotty.tools.dotc.core.Symbols.NoSymbol
21-
import dotty.tools.dotc.core.Symbols.Symbol
20+
import dotty.tools.dotc.core.Symbols.*
2221
import dotty.tools.dotc.core.Types.*
2322
import dotty.tools.dotc.core.Types.Type
2423
import dotty.tools.dotc.printing.RefinedPrinter
@@ -254,7 +253,6 @@ class ShortenedTypePrinter(
254253
end hoverSymbol
255254

256255
def isImportedByDefault(sym: Symbol): Boolean =
257-
import dotty.tools.dotc.core.Symbols.defn
258256
lazy val effectiveOwner = sym.effectiveOwner
259257
sym.isType && (effectiveOwner == defn.ScalaPackageClass || effectiveOwner == defn.ScalaPredefModuleClass)
260258

@@ -496,9 +494,9 @@ class ShortenedTypePrinter(
496494
val info = nameToInfo
497495
.get(param.name)
498496
.flatMap { info =>
499-
// In some cases, paramInfo becomes Nothing (e.g. CompletionOverrideSuite#cake)
497+
// In some cases, paramInfo becomes `... & Nothing` (e.g. CompletionOverrideSuite#cake)
500498
// which is meaningless, in that case, fallback to param.info
501-
if info.isNothingType then None
499+
if info <:< defn.NothingType then None
502500
else Some(info)
503501
}
504502
.getOrElse(param.info)

tests/pos/i23530.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
trait TestContainer:
2+
trait TestPath:
3+
type AbsMember
4+
5+
extension (path: TestPath)
6+
infix def ext(color: path.AbsMember): Unit = ???
7+
infix def ext(other: Int): Unit = ???
8+
9+
object Repro:
10+
val dc2: TestContainer = ???
11+
import dc2.TestPath
12+
13+
def transition(path: TestPath)(using DummyImplicit): TestPath = ???
14+
15+
def test: Unit =
16+
val di: TestPath = ???
17+
// error
18+
val z1 = transition(di).ext(1)

0 commit comments

Comments
 (0)