Skip to content

Commit d34256c

Browse files
committed
Handle paths of length > 1 for realizability checking
1 parent 20fc6bd commit d34256c

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
@@ -342,10 +342,31 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
342342
}
343343
}
344344

345+
/** Is this type a path with some part that is initialized on use? */
346+
def isLateInitialized(tp: Type): Boolean = tp.dealias match {
347+
case tp: TermRef =>
348+
tp.symbol.isLateInitialized || isLateInitialized(tp.prefix)
349+
case _: SingletonType | NoPrefix =>
350+
false
351+
case tp: TypeRef =>
352+
true
353+
case tp: TypeProxy =>
354+
isLateInitialized(tp.underlying)
355+
case tp: AndOrType =>
356+
isLateInitialized(tp.tp1) || isLateInitialized(tp.tp2)
357+
case _ =>
358+
true
359+
}
360+
345361
/** The realizability status of given type `tp`*/
346362
def realizability(tp: Type): Realizability = tp.dealias match {
347363
case tp: TermRef =>
348-
if (tp.symbol.isRealizable) Realizable
364+
if (tp.symbol.isRealizable)
365+
if (tp.symbol.isLateInitialized || // we already checked realizability of info in that case
366+
!isLateInitialized(tp.prefix)) // symbol was definitely constructed in that case
367+
Realizable
368+
else
369+
realizability(tp.info)
349370
else if (!tp.symbol.isStable) NotStable
350371
else if (!tp.symbol.isEffectivelyFinal) new NotFinal(tp.symbol)
351372
else new ProblemInUnderlying(tp.info, realizability(tp.info))
@@ -376,6 +397,18 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
376397
}
377398
}
378399

400+
/* Might need at some point in the future
401+
def memberRealizability(tp: Type)(implicit ctx: Context) = {
402+
println(i"check member rel of $tp")
403+
def isUnrealizable(fld: SingleDenotation) =
404+
!fld.symbol.is(Lazy) && realizability(fld.info) != Realizable
405+
tp.fields.find(isUnrealizable) match {
406+
case Some(fld) => new HasProblemField(fld)
407+
case _ => Realizable
408+
}
409+
}
410+
*/
411+
379412
private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = {
380413
val lazyInfo = new LazyType { // needed so we do not force `formal`.
381414
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
@@ -608,9 +641,14 @@ object TypeOps {
608641
class NotFinal(sym: Symbol)(implicit ctx: Context)
609642
extends Realizability(i" refers to nonfinal $sym")
610643

611-
class HasProblemBounds(mbr: SingleDenotation)(implicit ctx: Context)
612-
extends Realizability(i" has a member $mbr with possibly conflicting bounds ${mbr.info.bounds.lo} <: ... <: ${mbr.info.bounds.hi}")
644+
class HasProblemBounds(typ: SingleDenotation)(implicit ctx: Context)
645+
extends Realizability(i" has a member $typ with possibly conflicting bounds ${typ.info.bounds.lo} <: ... <: ${typ.info.bounds.hi}")
613646

647+
/* Might need at some point in the future
648+
class HasProblemField(fld: SingleDenotation)(implicit ctx: Context)
649+
extends Realizability(i" has a member $fld which is uneligible as a path since ${fld.symbol.name}${ctx.realizability(fld.info)}")
650+
*/
651+
614652
class ProblemInUnderlying(tp: Type, problem: Realizability)(implicit ctx: Context)
615653
extends Realizability(i"s underlying type ${tp}${problem.msg}")
616654
}

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class tests extends CompilerTest {
162162
@Test def neg_i803 = compileFile(negDir, "i803", xerrors = 2)
163163
@Test def neg_i866 = compileFile(negDir, "i866", xerrors = 2)
164164
@Test def neg_i974 = compileFile(negDir, "i974", xerrors = 2)
165-
@Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 11)
165+
@Test def neg_i1050 = compileFile(negDir, "i1050", xerrors = 14)
166166
@Test def neg_i1050a = compileFile(negDir, "i1050a", xerrors = 2)
167167
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
168168
@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)