aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/ast/CheckTrees.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala2
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala12
-rw-r--r--tests/neg/blockescapesNeg.scala5
-rw-r--r--tests/new/t2421_delitedsl.scala39
5 files changed, 52 insertions, 7 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala
index 832544706..254f002c1 100644
--- a/src/dotty/tools/dotc/ast/CheckTrees.scala
+++ b/src/dotty/tools/dotc/ast/CheckTrees.scala
@@ -34,6 +34,7 @@ object CheckTrees {
tp namedPartsWith (tp => isLocal(tp.symbol))
def typeLeaks(tp: Type): Boolean = leakingTypes(tp).nonEmpty
def classLeaks(sym: ClassSymbol): Boolean =
+ (ctx.owner is Method) || // can't hoist classes out of method bodies
(sym.info.parents exists typeLeaks) ||
(sym.decls.toList exists (t => typeLeaks(t.info)))
leakingTypes(block.tpe)
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index bd44ccac5..9e34d549a 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -58,7 +58,7 @@ trait Inferencing { this: Checking =>
}
private var toMaximize: Boolean = false
def apply(x: Boolean, tp: Type): Boolean = tp.dealias match {
- case _: WildcardType =>
+ case _: WildcardType | _: ProtoType =>
false
case tvar: TypeVar if !tvar.isInstantiated =>
if (force == ForceDegree.none) false
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 13f65d424..48c263085 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -52,10 +52,14 @@ trait TypeAssigner {
def apply(tp: Type) = tp match {
case tp: TermRef if toAvoid(tp) && variance > 0 =>
apply(tp.info)
- case tp: TypeRef if toAvoid(tp.prefix) =>
+ case tp: TypeRef if (forbidden contains tp.symbol) || toAvoid(tp.prefix) =>
tp.info match {
- case TypeAlias(ref) => apply(ref)
- case _ => mapOver(tp)
+ case TypeAlias(ref) =>
+ apply(ref)
+ case info: ClassInfo =>
+ mapOver(info.instantiatedParents.reduceLeft(AndType(_, _)))
+ case _ =>
+ mapOver(tp)
}
case tp: RefinedType =>
val tp1 @ RefinedType(parent1, _) = mapOver(tp)
@@ -247,7 +251,7 @@ trait TypeAssigner {
tree.withType(defn.UnitType)
def assignType(tree: untpd.Block, stats: List[Tree], expr: Tree)(implicit ctx: Context) =
- tree.withType(avoid(expr.tpe, localSyms(stats)))
+ tree.withType(avoid(expr.tpe, localSyms(stats) filter (_.isTerm)))
def assignType(tree: untpd.If, thenp: Tree, elsep: Tree)(implicit ctx: Context) =
tree.withType(thenp.tpe | elsep.tpe)
diff --git a/tests/neg/blockescapesNeg.scala b/tests/neg/blockescapesNeg.scala
index 028ef5162..7b448ad23 100644
--- a/tests/neg/blockescapesNeg.scala
+++ b/tests/neg/blockescapesNeg.scala
@@ -1,5 +1,6 @@
object blockescapesNeg {
- def m0 = { object Foo { class Bar } ; new Foo.Bar }
+ def m0 = { object Foo { class Bar { val field = 2 }} ; new Foo.Bar }
+ m0.field
class A[T]
def m1 = { val x = 1; new A[x.type]}
-} \ No newline at end of file
+}
diff --git a/tests/new/t2421_delitedsl.scala b/tests/new/t2421_delitedsl.scala
new file mode 100644
index 000000000..554702a03
--- /dev/null
+++ b/tests/new/t2421_delitedsl.scala
@@ -0,0 +1,39 @@
+trait DeliteDSL {
+ abstract class <~<[-From, +To] extends (From => To)
+ implicit def trivial[A]: A <~< A = new (A <~< A) {def apply(x: A) = x}
+
+ trait Forcible[T]
+ object Forcible {
+ def factory[T](f: T => Forcible[T]) = new (T <~< Forcible[T]){def apply(x: T) = f(x)}
+ }
+
+ case class DeliteInt(x: Int) extends Forcible[Int]
+
+ implicit val forcibleInt: DeliteDSL.this.<~<[Int,DeliteDSL.this.Forcible[Int]] =
+ Forcible.factory((x: Int) => DeliteInt(x))
+
+ import scala.collection.Traversable
+ class DeliteCollection[T](val xs: Traversable[T]) {
+ // must use existential in bound of P, instead of T itself, because we cannot both have:
+ // Test.x below: DeliteCollection[T=Int] -> P=DeliteInt <: Forcible[T=Int], as T=Int <~< P=DeliteInt
+ // Test.xAlready below: DeliteCollection[T=DeliteInt] -> P=DeliteInt <: Forcible[T=DeliteInt], as T=DeliteInt <~< P=DeliteInt
+ // this would required DeliteInt <: Forcible[Int] with Forcible[DeliteInt]
+
+ def headProxy[P <: Forcible[_]](implicit w: T <~< P): P = xs.head
+ }
+ // If T is already a proxy (it is forcible), the compiler should use
+ // forcibleIdentity to deduce that P=T. If T is Int, the compiler
+ // should use intToForcible to deduce that P=DeliteInt.
+ //
+ // Without this feature, the user must write 'xs.proxyOfFirst[DeliteInt]',
+ // with the feature they can write 'xs.proxyOfFirst', which is shorter and
+ // avoids exposing internal DELITE types to the world.
+
+ object Test {
+ val x = new DeliteCollection(List(1,2,3)).headProxy
+ // inferred: val x: Forcible[Int] = new DeliteCollection[Int](List.apply[Int](1, 2, 3)).headProxy[Forcible[Int]](forcibleInt);
+
+ val xAlready = new DeliteCollection(List(DeliteInt(1),DeliteInt(2),DeliteInt(3))).headProxy
+ // inferred: val xAlready: DeliteInt = new DeliteCollection[DeliteInt](List.apply[DeliteInt](DeliteInt(1), DeliteInt(2), DeliteInt(3))).headProxy[DeliteInt](trivial[DeliteInt]);
+ }
+}