From 3922a04ee0aea298f0cceb9ac0bf6b7d7c19cbd3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 13 Jul 2019 19:36:32 +0200 Subject: [PATCH 1/5] Fix computation of inlineCallPrefix --- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 2452081bf98c..357e3fa47206 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -201,7 +201,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { private val (methPart, callTypeArgs, callValueArgss) = decomposeCall(call) private val inlinedMethod = methPart.symbol - private val inlineCallPrefix = qualifier(methPart) + private val inlineCallPrefix = + qualifier(methPart).orElse(This(inlinedMethod.enclosingClass.asClass)) // Make sure all type arguments to the call are fully determined for (targ <- callTypeArgs) fullyDefinedType(targ.tpe, "inlined type argument", targ.span) From 6ebe141aad2adee9a2f4db27caef67639876dff4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 14 Jul 2019 15:07:40 +0200 Subject: [PATCH 2/5] Fix SymDenotations#seesOpaques --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 19f7ee238d99..9644313e925d 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -592,7 +592,7 @@ object SymDenotations { def seesOpaques(implicit ctx: Context): Boolean = containsOpaques || - is(Module, butNot = Package) && owner.containsOpaques + is(Module, butNot = Package) && owner.seesOpaques /** Is this the denotation of a self symbol of some class? * This is the case if one of two conditions holds: diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index fd000257c75c..7c194b3a7283 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2463,9 +2463,9 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { if (skipped) op else { indent += 2 - b append "\n" append (" " * indent) append "==> " append str + b.append("\n").append(" " * indent).append("==> ").append(str) val res = op - b append "\n" append (" " * indent) append "<== " append str append " = " append show(res) + b.append("\n").append(" " * indent).append("<== ").append(str).append(" = ").append(show(res)) indent -= 2 res } From 0b77e07d7e7b7bad5a9ec81a04804d1614dda111 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 15 Jul 2019 13:12:27 +0200 Subject: [PATCH 3/5] Print diagnostics when inliner starts --- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 357e3fa47206..968d93537d70 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -204,6 +204,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { private val inlineCallPrefix = qualifier(methPart).orElse(This(inlinedMethod.enclosingClass.asClass)) + inlining.println("-----------------------\nInlining $call\nWith RHS $rhsToInline") + // Make sure all type arguments to the call are fully determined for (targ <- callTypeArgs) fullyDefinedType(targ.tpe, "inlined type argument", targ.span) From 6be0b8137b4447ed62cfd91b75fa07d4bfe266bb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 15 Jul 2019 14:14:59 +0200 Subject: [PATCH 4/5] Don't treat Array[_ <: Int] as unbounded generic --- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 6246b4ef1636..3108e4d2f98c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -244,7 +244,10 @@ object TypeErasure { !classify(tp).derivesFrom(defn.ObjectClass) && !tp.binder.resultType.isJavaMethod case tp: TypeAlias => isUnboundedGeneric(tp.alias) - case tp: TypeBounds => !classify(tp.hi).derivesFrom(defn.ObjectClass) + case tp: TypeBounds => + val upper = classify(tp.hi) + !upper.derivesFrom(defn.ObjectClass) && + !upper.isPrimitiveValueType case tp: TypeProxy => isUnboundedGeneric(tp.translucentSuperType) case tp: AndType => isUnboundedGeneric(tp.tp1) && isUnboundedGeneric(tp.tp2) case tp: OrType => isUnboundedGeneric(tp.tp1) || isUnboundedGeneric(tp.tp2) From f8dded5924d9c8edac8f0074e4ebffeeb76b757b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 15 Jul 2019 14:21:04 +0200 Subject: [PATCH 5/5] Disallow inline methods and opaque types in same scope --- .../src/dotty/tools/dotc/typer/Namer.scala | 2 ++ library/src-bootstrapped/scala/IArray.scala | 20 +++++++++++-- tests/neg/inline3.scala | 28 +++++++++++++++++++ tests/run/opaque-immutable-array-xm.scala | 2 +- 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/neg/inline3.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 9f2a64d555f8..17842ee8b63f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -803,6 +803,8 @@ class Namer { typer: Typer => private def addInlineInfo(sym: Symbol) = original match { case original: untpd.DefDef if sym.isInlineMethod => + if (sym.owner.isClass && sym.owner.seesOpaques) + ctx.error(em"Implementation restriction: No inline methods allowed where opaque type aliases are in scope", sym.sourcePos) PrepareInlineable.registerInlineInfo( sym, implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 98697f41121b..16d92077b9ad 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -15,12 +15,28 @@ implicit object arrayOps { * @param n the index of the element to select * @return the element of the array at the given index */ - inline def (arr: IArray[T]) apply[T] (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) + def (arr: IArray[Byte]) apply (n: Int): Byte = arr.asInstanceOf[Array[Byte]].apply(n) + def (arr: IArray[Short]) apply (n: Int): Short = arr.asInstanceOf[Array[Short]].apply(n) + def (arr: IArray[Char]) apply (n: Int): Char = arr.asInstanceOf[Array[Char]].apply(n) + def (arr: IArray[Int]) apply (n: Int): Int = arr.asInstanceOf[Array[Int]].apply(n) + def (arr: IArray[Long]) apply (n: Int): Long = arr.asInstanceOf[Array[Long]].apply(n) + def (arr: IArray[Float]) apply (n: Int): Float = arr.asInstanceOf[Array[Float]].apply(n) + def (arr: IArray[Double]) apply (n: Int): Double = arr.asInstanceOf[Array[Double]].apply(n) + def (arr: IArray[T]) apply[T <: Object] (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) + def (arr: IArray[T]) apply[T] (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) /** The number of elements in an immutable array * @param arr the immutable array */ - inline def (arr: IArray[T]) length[T] : Int = arr.asInstanceOf[Array[T]].length + def (arr: IArray[Byte]) length: Int = arr.asInstanceOf[Array[Byte]].length + def (arr: IArray[Short]) length: Int = arr.asInstanceOf[Array[Short]].length + def (arr: IArray[Char]) length: Int = arr.asInstanceOf[Array[Char]].length + def (arr: IArray[Int]) length: Int = arr.asInstanceOf[Array[Int]].length + def (arr: IArray[Long]) length: Int = arr.asInstanceOf[Array[Long]].length + def (arr: IArray[Float]) length: Int = arr.asInstanceOf[Array[Float]].length + def (arr: IArray[Double]) length: Int = arr.asInstanceOf[Array[Double]].length + def (arr: IArray[Object]) length: Int = arr.asInstanceOf[Array[Object]].length + def (arr: IArray[T]) length[T] : Int = arr.asInstanceOf[Array[T]].length } object IArray { diff --git a/tests/neg/inline3.scala b/tests/neg/inline3.scala new file mode 100644 index 000000000000..90a8ea9bb788 --- /dev/null +++ b/tests/neg/inline3.scala @@ -0,0 +1,28 @@ +object K0 { + + type T = String + + opaque type ProductInstances[F[_], T] = ErasedProductInstances[F[T]] + + inline def summonAsArray[F[_], T]: Array[Any] = ??? // error: Implementation restriction: No inline methods allowed + + inline def mkProductInstances[F[_], T]: ProductInstances[F, T] = // error: Implementation restriction: No inline methods allowed + new ErasedProductInstances(summonAsArray[F, T]).asInstanceOf[ProductInstances[F, T]] + + val x: T = "" + + inline def foo(x: T): T = "foo".asInstanceOf[T] // error: Implementation restriction: No inline methods allowed + +} + +final class ErasedProductInstances[FT](is0: => Array[Any]) + +trait Monoid[A] +case class ISB(i: Int) + +object Test { + //val K0 = new K0 + K0.foo(K0.x) + K0.mkProductInstances[Monoid, ISB] + +} \ No newline at end of file diff --git a/tests/run/opaque-immutable-array-xm.scala b/tests/run/opaque-immutable-array-xm.scala index ffd07c59047e..0052c7330d06 100644 --- a/tests/run/opaque-immutable-array-xm.scala +++ b/tests/run/opaque-immutable-array-xm.scala @@ -6,7 +6,7 @@ object Test extends App { opaque type IArray[A1] = Array[A1] implicit object IArray { - inline def initialize[A](body: => Array[A]): IArray[A] = body + def initialize[A](body: => Array[A]): IArray[A] = body def apply[A: ClassTag](xs: A*): IArray[A] = initialize(Array(xs: _*)) // These should be inline but that does not work currently. Try again