Skip to content

Commit 085e237

Browse files
committed
Handle paths of length > 1 for realizability checking
1 parent ee287ab commit 085e237

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,31 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
301301
}
302302
}
303303

304+
/** Is this type a path with some part that is initialized on use? */
305+
def isLateInitialized(tp: Type): Boolean = tp.dealias match {
306+
case tp: TermRef =>
307+
tp.symbol.isLateInitialized || isLateInitialized(tp.prefix)
308+
case _: SingletonType | NoPrefix =>
309+
false
310+
case tp: TypeRef =>
311+
true
312+
case tp: TypeProxy =>
313+
isLateInitialized(tp.underlying)
314+
case tp: AndOrType =>
315+
isLateInitialized(tp.tp1) || isLateInitialized(tp.tp2)
316+
case _ =>
317+
true
318+
}
319+
304320
/** The realizability status of given type `tp`*/
305321
def realizability(tp: Type): Realizability = tp.dealias match {
306322
case tp: TermRef =>
307-
if (tp.symbol.isRealizable) Realizable
323+
if (tp.symbol.isRealizable)
324+
if (tp.symbol.isLateInitialized || // we already checked realizability of info in that case
325+
!isLateInitialized(tp.prefix)) // symbol was definitely constructed in that case
326+
Realizable
327+
else
328+
realizability(tp.info)
308329
else if (!tp.symbol.isStable) NotStable
309330
else if (!tp.symbol.isEffectivelyFinal) new NotFinal(tp.symbol)
310331
else new ProblemInUnderlying(tp.info, realizability(tp.info))
@@ -335,6 +356,18 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
335356
}
336357
}
337358

359+
/* Might need at some point in the future
360+
def memberRealizability(tp: Type)(implicit ctx: Context) = {
361+
println(i"check member rel of $tp")
362+
def isUnrealizable(fld: SingleDenotation) =
363+
!fld.symbol.is(Lazy) && realizability(fld.info) != Realizable
364+
tp.fields.find(isUnrealizable) match {
365+
case Some(fld) => new HasProblemField(fld)
366+
case _ => Realizable
367+
}
368+
}
369+
*/
370+
338371
private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = {
339372
val lazyInfo = new LazyType { // needed so we do not force `formal`.
340373
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
@@ -567,9 +600,14 @@ object TypeOps {
567600
class NotFinal(sym: Symbol)(implicit ctx: Context)
568601
extends Realizability(i" refers to nonfinal $sym")
569602

570-
class HasProblemBounds(mbr: SingleDenotation)(implicit ctx: Context)
571-
extends Realizability(i" has a member $mbr with possibly conflicting bounds ${mbr.info.bounds.lo} <: ... <: ${mbr.info.bounds.hi}")
603+
class HasProblemBounds(typ: SingleDenotation)(implicit ctx: Context)
604+
extends Realizability(i" has a member $typ with possibly conflicting bounds ${typ.info.bounds.lo} <: ... <: ${typ.info.bounds.hi}")
572605

606+
/* Might need at some point in the future
607+
class HasProblemField(fld: SingleDenotation)(implicit ctx: Context)
608+
extends Realizability(i" has a member $fld which is uneligible as a path since ${fld.symbol.name}${ctx.realizability(fld.info)}")
609+
*/
610+
573611
class ProblemInUnderlying(tp: Type, problem: Realizability)(implicit ctx: Context)
574612
extends Realizability(i"s underlying type ${tp}${problem.msg}")
575613
}

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class tests extends CompilerTest {
156156
@Test def neg_i705 = compileFile(negDir, "i705-inner-value-class", xerrors = 7)
157157
@Test def neg_i866 = compileFile(negDir, "i866", xerrors = 2)
158158
@Test def neg_i974 = compileFile(negDir, "i974", xerrors = 2)
159-
@Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 11)
159+
@Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 14)
160160
@Test def neg_i1050a = compileFile(negDir, "i1050a", xerrors = 2)
161161
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
162162
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)

tests/neg/i1050.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,30 @@ object Import {
109109
object V { // error: cannot be instantiated
110110
type Y >: Any <: Nothing // error: only classes can have declared but undefined members
111111
}
112+
object Tiark5 {
113+
trait A { type L <: Nothing }
114+
trait B { type L >: Any }
115+
def f(x: => A & B)(y: Any):Nothing = (y:x.L) // error: underlying conflicting bounds
116+
f(???)("boom!")
117+
}
118+
object Tiark5Inherited {
119+
trait A { type L <: Nothing }
120+
trait B { type L >: Any }
121+
trait A2 extends A
122+
trait B2 extends B
123+
def f(x: => A2 & B2)(y: Any):Nothing = (y:x.L) // error: underlying conflicting bounds
124+
f(???)("boom!")
125+
}
126+
object Tiark6 {
127+
trait B { type L >: Any }
128+
trait A { type L <: Nothing }
129+
trait U {
130+
trait X {
131+
val q: A & B = ???
132+
}
133+
final lazy val p: X = ???
134+
def brand(x: Any): p.q.L = x // error: conflicting bounds
135+
}
136+
val v = new U {}
137+
v.brand("boom!"): Nothing
138+
}

0 commit comments

Comments
 (0)