summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala28
1 files changed, 14 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index f581eab00f..4f006fe9a9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2726,7 +2726,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
*
* ```
* new S {
- * <static> def apply$body(p1: T1, ..., pN: TN): T = body
+ * def apply$body(p1: T1, ..., pN: TN): T = body
* def apply(p1: T1', ..., pN: TN'): T' = apply$body(p1,..., pN)
* }
* ```
@@ -2737,27 +2737,28 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* The types T1' ... TN' and T' are derived from the method signature of the sam method,
* as seen from the fully defined `samClassTpFullyDefined`.
*
- * The function's body is put in a static method in the class definition to enforce scoping.
+ * The function's body is put in a (static) method in the class definition to enforce scoping.
* S's members should not be in scope in `body`. (Putting it in the block outside the class runs into implementation problems described below)
*
* The restriction on implicit arguments (neither S's constructor, nor sam may take an implicit argument list),
- * is largely to keep the implementation of type inference (the computation of `samClassTpFullyDefined`) simple.
+ * is to keep the implementation of type inference (the computation of `samClassTpFullyDefined`) simple.
+ *
+ * Impl notes:
+ * - `fun` has a FunctionType, but the expected type `pt` is some SAM type -- let's remedy that
+ * - `fun` is fully attributed, so we'll have to wrangle some symbols into shape (owner change, vparam syms)
+ * - after experimentation, it works best to type check function literals fully first and then adapt to a sam type,
+ * as opposed to a sam-specific code paths earlier on in type checking (in typedFunction).
+ * For one, we want to emit the same bytecode regardless of whether the expected
+ * function type is a built-in FunctionN or some SAM type
*
*/
def adaptToSAM(sam: Symbol, fun: Function, pt: Type, mode: Mode): Tree = {
- // `fun` has a FunctionType, but the expected type `pt` is some SAM type -- let's remedy that
- // `fun` is fully attributed, so we'll have to wrangle some symbols into shape (owner change, vparam syms)
- // I tried very hard to leave `fun` untyped and rework everything into the right shape and type check once,
- // but couldn't make it work due to retyping that happens down the line
- // (implicit conversion retries/retypechecking, CBN transform, super call arg context nesting weirdness)
-
- def funTpMatchesExpected(pt: Type): Boolean = isFullyDefined(pt) && {
- // what's the signature of the method that we should actually be overriding?
+ def fullyDefinedMeetsExpectedFunTp(pt: Type): Boolean = isFullyDefined(pt) && {
val samMethType = pt memberInfo sam
fun.tpe <:< functionType(samMethType.paramTypes, samMethType.resultType)
}
- if (funTpMatchesExpected(pt)) fun.setType(pt)
+ if (fullyDefinedMeetsExpectedFunTp(pt)) fun.setType(pt)
else try {
val samClassSym = pt.typeSymbol
@@ -2786,9 +2787,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
debuglog(s"sam infer: $pt --> ${appliedType(samTyCon, targs)} by ${fun.tpe} <:< $samInfoWithTVars --> $targs for $tparams")
- // a fully defined samClassTp
val ptFullyDefined = appliedType(samTyCon, targs)
- if (funTpMatchesExpected(ptFullyDefined)) {
+ if (ptFullyDefined <:< pt && fullyDefinedMeetsExpectedFunTp(ptFullyDefined)) {
debuglog(s"sam fully defined expected type: $ptFullyDefined from $pt for ${fun.tpe}")
fun.setType(ptFullyDefined)
} else {