Skip to content

Commit 1168967

Browse files
authored
Merge pull request #14762 from dotty-staging/fix-13900
Fix hasKnownMembers
2 parents a2974d9 + 7f7d83f commit 1168967

File tree

3 files changed

+35
-23
lines changed

3 files changed

+35
-23
lines changed

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

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -157,28 +157,35 @@ object ProtoTypes {
157157
abstract case class SelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)
158158
extends CachedProxyType with ProtoType with ValueTypeOrProto {
159159

160-
/** Is the set of members of this type unknown? This is the case if:
161-
* 1. The type has Nothing or Wildcard as a prefix or underlying type
162-
* 2. The type has an uninstantiated TypeVar as a prefix or underlying type,
163-
* or as an upper bound of a prefix or underlying type.
160+
/** Is the set of members of this type unknown, in the sense that we
161+
* cannot compute a non-trivial upper approximation? This is the case if:
162+
* 1. The type has Nothing or Wildcard as a prefix or underlying type
163+
* 2. The type is an abstract type with a lower bound that has a unknown
164+
* members and an upper bound that is both provisional and has unknown members.
165+
* 3. The type is an uninstiated type var with a lower that has unknown members.
166+
* 4. Type proxies have unknown members if their super types do
164167
*/
165-
private def hasUnknownMembers(tp: Type)(using Context): Boolean = tp match {
166-
case tp: TypeVar => !tp.isInstantiated
168+
private def hasUnknownMembers(tp: Type)(using Context): Boolean = tp match
167169
case tp: WildcardType => true
168170
case NoType => true
169171
case tp: TypeRef =>
170172
val sym = tp.symbol
171-
sym == defn.NothingClass ||
172-
!sym.isStatic && {
173-
hasUnknownMembers(tp.prefix) || {
174-
val bound = tp.info.hiBound
175-
bound.isProvisional && hasUnknownMembers(bound)
176-
}
177-
}
173+
sym == defn.NothingClass
174+
|| !sym.isClass
175+
&& !sym.isStatic
176+
&& {
177+
hasUnknownMembers(tp.prefix)
178+
|| { val bound = tp.info.hiBound
179+
bound.isProvisional && hasUnknownMembers(bound)
180+
} && hasUnknownMembers(tp.info.loBound)
181+
}
182+
case tp: TypeVar if !tp.isInstantiated =>
183+
hasUnknownMembers(TypeComparer.bounds(tp.origin).lo)
178184
case tp: AppliedType => hasUnknownMembers(tp.tycon) || hasUnknownMembers(tp.superType)
179185
case tp: TypeProxy => hasUnknownMembers(tp.superType)
186+
// It woukd make sense to also include And/OrTypes, but that leads to
187+
// infinite recursions, as observed for instance for t2399.scala.
180188
case _ => false
181-
}
182189

183190
override def isMatchedBy(tp1: Type, keepConstraint: Boolean)(using Context): Boolean =
184191
name == nme.WILDCARD || hasUnknownMembers(tp1) ||

tests/neg/i13900.scala

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/pos/i13900.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import compiletime.ops.int.Max
2+
import scala.annotation.targetName
3+
opaque type Inlined[T] = T
4+
object Inlined:
5+
extension [T](inlined: Inlined[T]) def value: T = inlined
6+
inline given fromValue[T <: Singleton]: Conversion[T, Inlined[T]] =
7+
value => value
8+
@targetName("fromValueWide")
9+
given fromValue[Wide]: Conversion[Wide, Inlined[Wide]] = value => value
10+
11+
def forced[T](value: Any): Inlined[T] = value.asInstanceOf[T]
12+
extension [T <: Int](lhs: Inlined[T])
13+
def max[R <: Int](rhs: Inlined[R]) =
14+
forced[Max[T, R]](lhs.value max rhs.value)

0 commit comments

Comments
 (0)