aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/backend/jvm/DottyBackendInterface.scala4
-rw-r--r--src/dotty/tools/dotc/Compiler.scala1
-rw-r--r--src/dotty/tools/dotc/Run.scala2
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala33
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala2
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala24
-rw-r--r--src/dotty/tools/dotc/core/Types.scala10
-rw-r--r--src/dotty/tools/dotc/transform/ExpandSAMs.scala88
-rw-r--r--src/dotty/tools/dotc/transform/SymUtils.scala24
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala9
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala5
-rw-r--r--test/dotc/tests.scala3
-rw-r--r--tests/disabled/simplesams.scala9
-rw-r--r--tests/neg/sammy_poly.scala7
-rw-r--r--tests/pos/Patterns.scala5
-rw-r--r--tests/pos/sams.scala75
17 files changed, 265 insertions, 37 deletions
diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
index 7313070e0..dc6752460 100644
--- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -647,7 +647,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
}
def parentSymbols: List[Symbol] = toDenot(sym).info.parents.map(_.typeSymbol)
def superClass: Symbol = {
- val t = toDenot(sym).superClass
+ val t = toDenot(sym).asClass.superClass
if (t.exists) t
else if (sym is Flags.ModuleClass) {
// workaround #371
@@ -712,7 +712,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{
* All interfaces implemented by a class, except for those inherited through the superclass.
*
*/
- def superInterfaces: List[Symbol] = decorateSymbol(sym).superInterfaces
+ def superInterfaces: List[Symbol] = decorateSymbol(sym).directlyInheritedTraits
/**
* True for module classes of package level objects. The backend will generate a mirror class for
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 93a4edd6f..d4837ae74 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -45,6 +45,7 @@ class Compiler {
new ElimRepeated,
new NormalizeFlags,
new ExtensionMethods,
+ new ExpandSAMs,
new TailRec),
List(new PatternMatcher,
new ExplicitOuter,
diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala
index c99f5efb9..151288d23 100644
--- a/src/dotty/tools/dotc/Run.scala
+++ b/src/dotty/tools/dotc/Run.scala
@@ -33,7 +33,7 @@ class Run(comp: Compiler)(implicit ctx: Context) {
compileSources(sources)
} catch {
case NonFatal(ex) =>
- println(s"exception occurred while compiling $units%, %")
+ println(i"exception occurred while compiling $units%, %")
throw ex
}
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index de0ef3344..dce06da95 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -210,7 +210,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym)
def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = {
- val firstParent :: otherParents = cls.info.parents
+ val firstParentRef :: otherParentRefs = cls.info.parents
+ val firstParent = cls.typeRef.baseTypeWithArgs(firstParentRef.symbol)
val superRef =
if (cls is Trait) TypeTree(firstParent)
else {
@@ -225,7 +226,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info))
New(firstParent, constr.symbol.asTerm, superArgs)
}
- val parents = superRef :: otherParents.map(TypeTree(_))
+ val parents = superRef :: otherParentRefs.map(TypeTree(_))
val selfType =
if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls))
@@ -244,6 +245,33 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
ta.assignType(untpd.TypeDef(cls.name, impl), cls)
}
+ /** An anonymous class
+ *
+ * new parents { forwarders }
+ *
+ * where `forwarders` contains forwarders for all functions in `fns`.
+ * @param parents a non-empty list of class types
+ * @param fns a non-empty of functions for which forwarders should be defined in the class.
+ * The class has the same owner as the first function in `fns`.
+ * Its position is the union of all functions in `fns`.
+ */
+ def AnonClass(parents: List[Type], fns: List[TermSymbol], methNames: List[TermName])(implicit ctx: Context): Block = {
+ val owner = fns.head.owner
+ val parents1 =
+ if (parents.head.classSymbol.is(Trait)) defn.ObjectClass.typeRef :: parents
+ else parents
+ val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_FUN, Synthetic, parents1,
+ coord = fns.map(_.pos).reduceLeft(_ union _))
+ val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered
+ def forwarder(fn: TermSymbol, name: TermName) = {
+ val fwdMeth = fn.copy(cls, name, Synthetic | Method).entered.asTerm
+ DefDef(fwdMeth, prefss => ref(fn).appliedToArgss(prefss))
+ }
+ val forwarders = (fns, methNames).zipped.map(forwarder)
+ val cdef = ClassDef(cls, DefDef(constr), forwarders)
+ Block(cdef :: Nil, New(cls.typeRef, Nil))
+ }
+
// { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
def WhileDo(owner: Symbol, cond: Tree, body: List[Tree])(implicit ctx: Context): Tree = {
val sym = ctx.newSymbol(owner, nme.WHILE_PREFIX, Flags.Label | Flags.Synthetic,
@@ -254,7 +282,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
Block(List(DefDef(sym, rhs)), call)
}
-
def Import(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import =
ta.assignType(untpd.Import(expr, selectors), ctx.newImportSymbol(ctx.owner, expr))
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index b6f3c99e7..cfa0faef9 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -332,7 +332,7 @@ object Flags {
final val JavaStaticTerm = JavaStatic.toTermFlags
final val JavaStaticType = JavaStatic.toTypeFlags
- /** Trait is not an interface, but does not have fields or initialization code */
+ /** Trait does not have fields or initialization code */
final val NoInits = typeFlag(32, "<noInits>")
/** Variable is accessed from nested function. */
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 74a121b47..826cbe2c6 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -418,6 +418,7 @@ object StdNames {
val isArray: N = "isArray"
val isDefined: N = "isDefined"
val isDefinedAt: N = "isDefinedAt"
+ val isDefinedAtImpl: N = "$isDefinedAt"
val isEmpty: N = "isEmpty"
val isInstanceOf_ : N = "isInstanceOf"
val java: N = "java"
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 2b91efbcd..94ac258da 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -109,6 +109,30 @@ trait Symbols { this: Context =>
ClassInfo(owner.thisType, _, parents, decls, selfInfo),
privateWithin, coord, assocFile)
+ /** Same as `newCompleteClassSymbol` except that `parents` can be a list of arbitary
+ * types which get normalized into type refs and parameter bindings.
+ */
+ def newNormalizedClassSymbol(
+ owner: Symbol,
+ name: TypeName,
+ flags: FlagSet,
+ parentTypes: List[Type],
+ decls: Scope = newScope,
+ selfInfo: Type = NoType,
+ privateWithin: Symbol = NoSymbol,
+ coord: Coord = NoCoord,
+ assocFile: AbstractFile = null): ClassSymbol = {
+ def completer = new LazyType {
+ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
+ val cls = denot.asClass.classSymbol
+ val decls = newScope
+ val parentRefs: List[TypeRef] = normalizeToClassRefs(parentTypes, cls, decls)
+ denot.info = ClassInfo(owner.thisType, cls, parentRefs, decls)
+ }
+ }
+ newClassSymbol(owner, name, flags, completer, privateWithin, coord, assocFile)
+ }
+
/** Create a module symbol with associated module class
* from its non-info fields and a function producing the info
* of the module class (this info may be lazy).
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 595732b37..80cceed38 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -545,6 +545,11 @@ object Types {
(name, buf) => buf ++= member(name).altsWith(x => x.isClass))
}
+ final def fields(implicit ctx: Context): Seq[SingleDenotation] = track("fields") {
+ memberDenots(fieldFilter,
+ (name, buf) => buf ++= member(name).altsWith(x => !x.is(Method)))
+ }
+
/** The set of members of this type having at least one of `requiredFlags` but none of `excludedFlags` set */
final def membersBasedOnFlags(requiredFlags: FlagSet, excludedFlags: FlagSet)(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") {
memberDenots(takeAllFilter,
@@ -3049,6 +3054,11 @@ object Types {
def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = name.isTypeName
}
+ object fieldFilter extends NameFilter {
+ def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean =
+ name.isTermName && (pre member name).hasAltWith(!_.symbol.is(Method))
+ }
+
object takeAllFilter extends NameFilter {
def apply(pre: Type, name: Name)(implicit ctx: Context): Boolean = true
}
diff --git a/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/src/dotty/tools/dotc/transform/ExpandSAMs.scala
new file mode 100644
index 000000000..bba42f403
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ExpandSAMs.scala
@@ -0,0 +1,88 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Contexts._, Symbols._, Types._, Flags._, Decorators._, StdNames._, Constants._
+import SymDenotations.SymDenotation
+import TreeTransforms._
+import SymUtils._
+import ast.untpd
+import ast.Trees._
+
+/** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes.
+ * These fall into five categories
+ *
+ * 1. Partial function closures, we need to generate a isDefinedAt method for these.
+ * 2. Closures implementing non-trait classes.
+ * 3. Closures implementing classes that inherit from a class other than Object
+ * (a lambda cannot not be a run-time subtype of such a class)
+ * 4. Closures that implement traits which run initialization code.
+ * 5. Closures that get synthesized abstract methods in the transformation pipeline. These methods can be
+ * (1) superaccessors, (2) outer references, (3) accessors for fields.
+ */
+class ExpandSAMs extends MiniPhaseTransform { thisTransformer =>
+ override def phaseName = "expandSAMs"
+
+ import ast.tpd._
+
+ def noJvmSam(cls: ClassSymbol)(implicit ctx: Context): Boolean =
+ !cls.is(Trait) ||
+ cls.superClass != defn.ObjectClass ||
+ !cls.is(NoInits) ||
+ !cls.directlyInheritedTraits.forall(_.is(NoInits)) ||
+ ExplicitOuter.needsOuterIfReferenced(cls) ||
+ cls.typeRef.fields.nonEmpty // Superaccessors already show up as abstract methods here, so no test necessary
+
+
+ override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree = tree match {
+ case Block(stats @ (fn: DefDef) :: Nil, Closure(_, fnRef, tpt)) if fnRef.symbol == fn.symbol =>
+ tpt.tpe match {
+ case NoType => tree // it's a plain function
+ case tpe @ SAMType(_) if !noJvmSam(tpe.classSymbol.asClass) =>
+ if (tpe isRef defn.PartialFunctionClass) toPartialFunction(tree)
+ else tree
+ case tpe =>
+ cpy.Block(tree)(stats,
+ AnonClass(tpe :: Nil, fn.symbol.asTerm :: Nil, nme.apply :: Nil))
+ }
+ case _ =>
+ tree
+ }
+
+ private def toPartialFunction(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val Block(
+ (applyDef @ DefDef(nme.ANON_FUN, Nil, List(List(param)), _, _)) :: Nil,
+ Closure(_, _, tpt)) = tree
+ val applyRhs: Tree = applyDef.rhs
+ val applyFn = applyDef.symbol.asTerm
+
+ val MethodType(paramNames, paramTypes) = applyFn.info
+ val isDefinedAtFn = applyFn.copy(
+ name = nme.isDefinedAtImpl,
+ flags = Synthetic | Method,
+ info = MethodType(paramNames, paramTypes, defn.BooleanType)).asTerm
+ val tru = Literal(Constant(true))
+ def isDefinedAtRhs(paramRefss: List[List[Tree]]) = applyRhs match {
+ case Match(selector, cases) =>
+ assert(selector.symbol == param.symbol)
+ val paramRef = paramRefss.head.head
+ // Again, the alternative
+ // val List(List(paramRef)) = paramRefs
+ // fails with a similar self instantiation error
+ def translateCase(cdef: CaseDef): CaseDef =
+ cpy.CaseDef(cdef)(body = tru).changeOwner(applyFn, isDefinedAtFn)
+ val defaultSym = ctx.newSymbol(isDefinedAtFn, nme.WILDCARD, Synthetic, selector.tpe.widen)
+ val defaultCase =
+ CaseDef(
+ Bind(defaultSym, untpd.Ident(nme.WILDCARD).withType(selector.tpe.widen)),
+ EmptyTree,
+ Literal(Constant(false)))
+ cpy.Match(applyRhs)(paramRef, cases.map(translateCase) :+ defaultCase)
+ case _ =>
+ tru
+ }
+ val isDefinedAtDef = transformFollowingDeep(DefDef(isDefinedAtFn, isDefinedAtRhs(_)))
+ val anonCls = AnonClass(tpt.tpe :: Nil, List(applyFn, isDefinedAtFn), List(nme.apply, nme.isDefinedAt))
+ cpy.Block(tree)(List(applyDef, isDefinedAtDef), anonCls)
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala
index 41a0938b8..9b4b06601 100644
--- a/src/dotty/tools/dotc/transform/SymUtils.scala
+++ b/src/dotty/tools/dotc/transform/SymUtils.scala
@@ -24,30 +24,20 @@ object SymUtils {
class SymUtils(val self: Symbol) extends AnyVal {
import SymUtils._
- def superClass(implicit ctx: Context) = {
- val parents = self.asClass.classInfo.parents
- if (parents.isEmpty) NoSymbol
- else parents.head.symbol
- }
-
-
- /**
- * For a class: All interfaces implemented by a class except for those inherited through the superclass.
- * For a trait: all parent traits
- */
-
- def superInterfaces(implicit ctx: Context) = {
- val superCls = self.superClass
+ /** All traits implemented by a class or trait except for those inherited through the superclass. */
+ def directlyInheritedTraits(implicit ctx: Context) = {
+ val superCls = self.asClass.superClass
val baseClasses = self.asClass.baseClasses
if (baseClasses.isEmpty) Nil
else baseClasses.tail.takeWhile(_ ne superCls).reverse
-
}
- /** All interfaces implemented by a class, except for those inherited through the superclass. */
+ /** All traits implemented by a class, except for those inherited through the superclass.
+ * The empty list if `self` is a trait.
+ */
def mixins(implicit ctx: Context) = {
if (self is Trait) Nil
- else superInterfaces
+ else directlyInheritedTraits
}
def isTypeTestOrCast(implicit ctx: Context): Boolean =
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index 3bd005991..0aba1e213 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -486,7 +486,14 @@ object TreeTransforms {
var nxCopied = false
var result = info.transformers
var resultNX = info.nx
- var i = mutationPlan(0) // if TreeTransform.transform() method didn't exist we could have used mutationPlan(cur)
+ var i = mutationPlan(cur)
+ // @DarkDimius You commented on the previous version
+ //
+ // var i = mutationPlan(0) // if TreeTransform.transform() method didn't exist we could have used mutationPlan(cur)
+ //
+ // But we need to use `cur` or otherwise we call prepare actions preceding the
+ // phase that issued a transformFollowing. This can lead to "denotation not defined
+ // here" errors. Note that tests still pass with the current modified code.
val l = result.length
var allDone = i < l
while (i < l) {
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index b58f48728..191a13ad0 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -844,8 +844,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = track("typedBind") {
- val body1 = typed(tree.body, pt)
- typr.println(i"typed bind $tree pt = $pt bodytpe = ${body1.tpe}")
+ val pt1 = fullyDefinedType(pt, "pattern variable", tree.pos)
+ val body1 = typed(tree.body, pt1)
+ typr.println(i"typed bind $tree pt = $pt1 bodytpe = ${body1.tpe}")
val flags = if (tree.isType) BindDefinedType else EmptyFlags
val sym = ctx.newSymbol(ctx.owner, tree.name, flags, body1.tpe, coord = tree.pos)
assignType(cpy.Bind(tree)(tree.name, body1), sym)
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 7761589ad..0e86303a2 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -106,9 +106,6 @@ 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)
val negTailcallDir = negDir + "tailcall/"
@Test def neg_tailcall_t1672b = compileFile(negTailcallDir, "t1672b", xerrors = 6)
diff --git a/tests/disabled/simplesams.scala b/tests/disabled/simplesams.scala
new file mode 100644
index 000000000..14a7ba6c0
--- /dev/null
+++ b/tests/disabled/simplesams.scala
@@ -0,0 +1,9 @@
+package test
+
+trait X { def foo(x: Int): Int; def bar = foo(2) }
+trait XX extends X
+
+object test {
+ val x: X = (x: Int) => 2 // should be a closure
+ val xx: XX = (x: Int) => 2 // should be a closure, but blows up in backend
+}
diff --git a/tests/neg/sammy_poly.scala b/tests/neg/sammy_poly.scala
deleted file mode 100644
index 8d0236496..000000000
--- a/tests/neg/sammy_poly.scala
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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/Patterns.scala b/tests/pos/Patterns.scala
index e443c2ab5..e9bce87a9 100644
--- a/tests/pos/Patterns.scala
+++ b/tests/pos/Patterns.scala
@@ -94,3 +94,8 @@ object Patterns {
t
}
}
+
+object NestedPattern {
+ val xss: List[List[String]] = ???
+ val List(List(x)) = xss
+}
diff --git a/tests/pos/sams.scala b/tests/pos/sams.scala
new file mode 100644
index 000000000..b7ef7dd2d
--- /dev/null
+++ b/tests/pos/sams.scala
@@ -0,0 +1,75 @@
+object test {
+
+ trait X { def foo(x: Int): Int; def bar = foo(2) }
+
+ val x: X = (x: Int) => 2 // should be a closure
+
+ trait T {
+ var f = 2
+ def foo(x: Int): Int
+ }
+
+ val t: T = (x: Int) => 2 // needs to be an anonymous class because of defined field
+
+ trait U extends T
+
+ val u: U = (x: Int) => 2 // needs to be an anonymous class because of inherited field
+
+ trait V extends Exception { def foo(x: Int): Int }
+
+ val v: V = (x: Int) => 2 // needs to be an anonymous class because the trait extends a non-object class
+
+ trait Y extends X {
+ def baz = super.bar
+ }
+
+ val y: Y = (x: Int) => 2 // needs to be an anonymous class because of super accessor
+
+ trait Z {
+ def foo(x: Int): Int; println("hi there!")
+ }
+ trait ZZ extends Z
+
+ val z: Z = (x: Int) => 2 // needs to be an anonymous class because trait has initialization code
+ val zz: ZZ = (x: Int) => 2 // needs to be an anonymous class becaiuse trait has initialization code
+
+ abstract class C {
+ def foo(x: Int): Int
+
+ trait I { def foo(x: Int): Int }
+
+ }
+
+ val c: C = (x: Int) => 2 // needs to be an anonymous class because C is not a trait
+
+ val ci: c.I = (x: Int) => 2 // needs to be an anonymous class because it needs an outer pointer
+
+
+ val pf: PartialFunction[Int, Int] = {
+ case 1 => 1
+ case 2 => 2
+ }
+
+ val qf: PartialFunction[(Int, String), Int] = {
+ case (1, "abc") => 1
+ case _ => 2
+ }
+
+ val rf: PartialFunction[(Int, AnyRef), Int] = {
+ case (_: Int, _: String) => 1
+ case _ => 2
+ }
+
+ val sf: PartialFunction[Any, Int] = {
+ case x: String if x == "abc" => 1
+ }
+}
+
+// From: neg/sammy_poly
+// 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))
+}