From c01389d170bb0f1c8a925a25c145396007a75106 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 23 Apr 2015 13:38:55 +0200 Subject: [PATCH 1/2] Fix #492. Traits that require an outer pointer are not SAMs. --- src/dotty/tools/dotc/core/Types.scala | 8 ++++---- src/dotty/tools/dotc/transform/ExplicitOuter.scala | 10 ++++++++++ tests/neg/sammy_poly.scala | 7 +++++++ tests/pos/sammy_poly.scala | 12 +++++++++--- 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tests/neg/sammy_poly.scala diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index fe95219b8415..e290e8868664 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1788,12 +1788,12 @@ object Types { if (false) RefinedType(parent, refinedName, refinedInfo) else RefinedType(parent, refinedName, rt => refinedInfo.substSkolem(this, SkolemType(rt))) } - + /** Add this refinement to `parent`, provided If `refinedName` is a member of `parent`. */ def wrapIfMember(parent: Type)(implicit ctx: Context): Type = if (parent.member(refinedName).exists) derivedRefinedType(parent, refinedName, refinedInfo) else parent - + override def equals(that: Any) = that match { case that: RefinedType => this.parent == that.parent && @@ -2414,7 +2414,7 @@ object Types { selfTypeCache = { def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams) val given = givenSelfType - val raw = + val raw = if (!given.exists) fullRef else if (cls is Module) given else if (ctx.erasedTypes) fullRef @@ -2423,7 +2423,7 @@ object Types { } selfTypeCache } - + /** The explicitly given self type (self types of modules are assumed to be * explcitly given here). */ diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 8baaa3a1169c..9fc164d3b4b9 100644 --- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -13,6 +13,7 @@ import core.Names._ import core.NameOps._ import ast.Trees._ import SymUtils._ +import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.core.Phases.Phase import util.Attachment import collection.mutable @@ -102,6 +103,15 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf } else impl } + + override def transformClosure(tree: Closure)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + if (tree.tpt ne EmptyTree) { + val cls = tree.tpt.asInstanceOf[TypeTree].tpe.classSymbol + if (cls.exists && hasOuter(cls.asClass)) + ctx.error("Not a single abstract method type, requires an outer pointer", tree.pos) + } + tree + } } object ExplicitOuter { diff --git a/tests/neg/sammy_poly.scala b/tests/neg/sammy_poly.scala new file mode 100644 index 000000000000..8d0236496917 --- /dev/null +++ b/tests/neg/sammy_poly.scala @@ -0,0 +1,7 @@ +// test synthesizeSAMFunction where the sam type is not fully defined +class T { + trait F[T, U] { def apply(x: T): U } + // this is an inner trait, that will recieve an abstract $outer pointer. Not a SAM. + def app[T, U](x: T)(f: F[T, U]): U = f(x) + app(1)(x => List(x)) +} diff --git a/tests/pos/sammy_poly.scala b/tests/pos/sammy_poly.scala index f43fa292c541..ff20b5c9cbc6 100644 --- a/tests/pos/sammy_poly.scala +++ b/tests/pos/sammy_poly.scala @@ -1,7 +1,13 @@ // test synthesizeSAMFunction where the sam type is not fully defined + +trait F1[T, U] { def apply(x: T): U } class T { - trait F[T, U] { def apply(x: T): U } // NOTE: the f(x) desugaring for now assumes the single abstract method is called 'apply' - def app[T, U](x: T)(f: F[T, U]): U = f(x) - app(1)(x => List(x)) + def app1[T, U](x: T)(f: F1[T, U]): U = f(x) + def app2[T, U](x: T)(f: F2[T, U]): U = f(x) + app1(1)(x => List(x)) + app2(1)(x => List(x)) +} +object T{ + trait F2[T, U] { def apply(x: T): U } } From dee11526fc5f917589a5148b776de74752f4d57a Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 23 Apr 2015 13:41:38 +0200 Subject: [PATCH 2/2] Add a neg test for SAMs. --- test/dotc/tests.scala | 1 + tests/pos/sammy_poly.scala | 1 + 2 files changed, 2 insertions(+) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 85a3e317ac56..9cc64c725183 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -110,6 +110,7 @@ class tests extends CompilerTest { @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 6) @Test def neg_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1) @Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 12) + @Test def neg_sam = compileFile(negDir, "sammy_poly", xerrors = 1) // TODO: this test file doesn't exist (anymore?), remove? // @Test def neg_t1192_legalPrefix = compileFile(negDir, "t1192", xerrors = 1) diff --git a/tests/pos/sammy_poly.scala b/tests/pos/sammy_poly.scala index ff20b5c9cbc6..3291493c52da 100644 --- a/tests/pos/sammy_poly.scala +++ b/tests/pos/sammy_poly.scala @@ -2,6 +2,7 @@ trait F1[T, U] { def apply(x: T): U } class T { + import T._ // NOTE: the f(x) desugaring for now assumes the single abstract method is called 'apply' def app1[T, U](x: T)(f: F1[T, U]): U = f(x) def app2[T, U](x: T)(f: F2[T, U]): U = f(x)