aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala38
-rw-r--r--tests/pos/flowops.scala31
2 files changed, 49 insertions, 20 deletions
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 9b1f756b7..22d2407bc 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -156,16 +156,24 @@ object Checking {
tp
}
- def apply(tp: Type) = tp match {
+ private def apply(tp: Type, cycleOK: Boolean, nestedCycleOK: Boolean): Type = {
+ val savedCycleOK = this.cycleOK
+ val savedNestedCycleOK = this.nestedCycleOK
+ this.cycleOK = cycleOK
+ this.nestedCycleOK = nestedCycleOK
+ try apply(tp)
+ finally {
+ this.cycleOK = savedCycleOK
+ this.nestedCycleOK = savedNestedCycleOK
+ }
+ }
+
+ def apply(tp: Type): Type = tp match {
case tp: TermRef =>
this(tp.info)
mapOver(tp)
case tp @ RefinedType(parent, name) =>
- val parent1 = this(parent)
- val saved = cycleOK
- cycleOK = nestedCycleOK
- try tp.derivedRefinedType(parent1, name, this(tp.refinedInfo))
- finally cycleOK = saved
+ tp.derivedRefinedType(this(parent), name, this(tp.refinedInfo, nestedCycleOK, nestedCycleOK))
case tp @ TypeRef(pre, name) =>
try {
// A prefix is interesting if it might contain (transitively) a reference
@@ -182,19 +190,12 @@ object Checking {
case _: RefinedType => true
case _ => false
}
- // If prefix is interesting, check info of typeref recursively, marking the referred symbol
- // with NoCompleter. This provokes a CyclicReference when the symbol
- // is hit again. Without this precaution we could stackoverflow here.
if (isInteresting(pre)) {
- val info = tp.info
- val sym = tp.symbol
- if (sym.infoOrCompleter == SymDenotations.NoCompleter) throw CyclicReference(sym)
- val symInfo = sym.info
- if (sym.exists) sym.info = SymDenotations.NoCompleter
- try checkInfo(info)
- finally if (sym.exists) sym.info = symInfo
+ val pre1 = this(pre, false, false)
+ checkInfo(tp.info)
+ if (pre1 eq pre) tp else tp.newLikeThis(pre1)
}
- tp
+ else tp
} catch {
case ex: CyclicReference =>
ctx.debuglog(i"cycle detected for $tp, $nestedCycleOK, $cycleOK")
@@ -210,9 +211,6 @@ object Checking {
* @pre sym is not yet initialized (i.e. its type is a Completer).
* @return `info` where every legal F-bounded reference is proctected
* by a `LazyRef`, or `ErrorType` if a cycle was detected and reported.
- * Furthermore: Add an #Apply to a fully instantiated type lambda, if none was
- * given before. This is necessary here because sometimes type lambdas are not
- * recognized when they are first formed.
*/
def checkNonCyclic(sym: Symbol, info: Type, reportErrors: Boolean)(implicit ctx: Context): Type = {
val checker = new CheckNonCyclicMap(sym, reportErrors)(ctx.addMode(Mode.CheckCyclic))
diff --git a/tests/pos/flowops.scala b/tests/pos/flowops.scala
new file mode 100644
index 000000000..6aead26be
--- /dev/null
+++ b/tests/pos/flowops.scala
@@ -0,0 +1,31 @@
+object Test {
+ import language.higherKinds
+
+ class NotUsed
+
+ trait FO[+Out, +Mat] { self =>
+ type Repr[+O] <: FO[O, Mat] {
+ type Repr[+OO] = self.Repr[OO]
+ }
+ def map[T](f: Out => T): Repr[T] = ???
+ }
+
+ class Source[+O, +M] extends FO[O, M] {
+ type Repr[+OO] <: Source[OO, M]
+ }
+
+ class Flow[-I, +O, +M] extends FO[O, M] {
+ type Repr[+OO] <: Flow[I, OO, M]
+ }
+
+ implicit class x[O, M, F[o, m] <: FO[o, m]](val f: F[O, M]) extends AnyVal {
+ def xx(i: Int): f.Repr[O] = f.map(identity)
+ }
+
+ type IntFlow[O, M] = Flow[Int, O, M]
+
+ val s1 = new Source[Int, NotUsed].xx(12)
+ val s2: Source[Int, NotUsed] = s1
+ val f1 = x[Int, NotUsed, IntFlow](new Flow[Int, Int, NotUsed]).xx(12)
+ val f2: Flow[Int, Int, NotUsed] = f1
+}