diff options
-rw-r--r-- | src/dotty/tools/dotc/ast/CheckTrees.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/TypeAssigner.scala | 12 | ||||
-rw-r--r-- | tests/neg/blockescapesNeg.scala | 5 | ||||
-rw-r--r-- | tests/new/t2421_delitedsl.scala | 39 |
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]); + } +} |