@@ -2700,7 +2700,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
2700
2700
* `{
2701
2701
* def apply$body(p1: T1, ..., pN: TN): T = body
2702
2702
* new S {
2703
- * def apply(p1: T1, ..., pN: TN): T = apply$body(p1,..., pN)
2703
+ * def apply(p1: T1' , ..., pN: TN' ): T' = apply$body(p1,..., pN)
2704
2704
* }
2705
2705
* }`
2706
2706
*
@@ -2710,6 +2710,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
2710
2710
*
2711
2711
* The `apply` method is identified by the argument `sam`; `S` corresponds to the argument `samClassTp`,
2712
2712
* and `resPt` is derived from `samClassTp` -- it may be fully defined, or not...
2713
+ * If it is not fully defined, we derive `samClassTpFullyDefined` by inferring any unknown type parameters.
2714
+ *
2715
+ * The types T1' ... TN' and T' are derived from the method signature of the sam method,
2716
+ * as seen from the fully defined `samClassTpFullyDefined`.
2713
2717
*
2714
2718
* The function's body is put in a method outside of the class definition to enforce scoping.
2715
2719
* S's members should not be in scope in `body`.
@@ -2721,6 +2725,35 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
2721
2725
* However T must be fully defined before we type the instantiation, as it'll end up as a parent type,
2722
2726
* which must be fully defined. Would be nice to have some kind of mechanism to insert type vars in a block of code,
2723
2727
* and have the instantiation of the first occurrence propagate to the rest of the block.
2728
+ *
2729
+ * TODO: repeated and by-name params
2730
+ * scala> trait LazySink { def accept(a: => Any): Unit }
2731
+ * defined trait LazySink
2732
+ *
2733
+ * scala> val f: LazySink = (a) => (a, a)
2734
+ * f: LazySink = $anonfun$1@1fb26910
2735
+ *
2736
+ * scala> f(println("!"))
2737
+ * <console>:10: error: LazySink does not take parameters
2738
+ * f(println("!"))
2739
+ * ^
2740
+ *
2741
+ * scala> f.accept(println("!"))
2742
+ * !
2743
+ * !
2744
+ * This looks like a bug:
2745
+ *
2746
+ * scala> trait RepeatedSink { def accept(a: Any*): Unit }
2747
+ * defined trait RepeatedSink
2748
+ *
2749
+ * scala> val f: RepeatedSink = (a) => println(a)
2750
+ * f: RepeatedSink = $anonfun$1@4799abc2
2751
+ *
2752
+ * scala> f.accept(1)
2753
+ * WrappedArray(WrappedArray(1))
2754
+ *
2755
+ * scala> f.accept(1, 2)
2756
+ * WrappedArray(WrappedArray(1, 2))
2724
2757
*/
2725
2758
def synthesizeSAMFunction (sam : Symbol , fun : Function , resPt : Type , samClassTp : Type , mode : Mode ): Tree = {
2726
2759
// assert(fun.vparams forall (vp => isFullyDefined(vp.tpt.tpe))) -- by construction, as we take them from sam's info
@@ -2801,13 +2834,20 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
2801
2834
samClassTp
2802
2835
}
2803
2836
2804
- // `final override def ${sam.name}($p1: $T1, ..., $pN: $TN): $resPt = ${sam.name}\$body'($p1, ..., $pN)`
2837
+ // what's the signature of the method that we should actually be overriding?
2838
+ val samMethTp = samClassTpFullyDefined memberInfo sam
2839
+ // Before the mutation, `tp <:< vpar.tpt.tpe` should hold.
2840
+ // TODO: error message when this is not the case, as the expansion won't type check
2841
+ // - Ti' <:< Ti and T <: T' must hold for the samDef body to type check
2842
+ val funArgTps = foreach2(samMethTp.paramTypes, fun.vparams)((tp, vpar) => vpar.tpt setType tp)
2843
+
2844
+ // `final override def ${sam.name}($p1: $T1', ..., $pN: $TN'): ${samMethTp.finalResultType} = ${sam.name}\$body'($p1, ..., $pN)`
2805
2845
val samDef =
2806
2846
DefDef (Modifiers (FINAL | OVERRIDE | SYNTHETIC ),
2807
2847
sam.name.toTermName,
2808
2848
Nil ,
2809
2849
List (fun.vparams),
2810
- TypeTree (samBodyDef.tpt.tpe ) setPos sampos.focus,
2850
+ TypeTree (samMethTp.finalResultType ) setPos sampos.focus,
2811
2851
Apply (Ident (bodyName), fun.vparams map (p => Ident (p.name)))
2812
2852
)
2813
2853
@@ -2838,6 +2878,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
2838
2878
)
2839
2879
}
2840
2880
2881
+ // TODO: improve error reporting -- when we're in silent mode (from `silent(_.doTypedApply(tree, fun, args, mode, pt)) orElse onError`)
2882
+ // the errors in the function don't get out...
2883
+ if (block exists (_.isErroneous))
2884
+ context.error(fun.pos, s " Could not derive subclass of $samClassTp\n (with SAM `def $sam$samMethTp`) \n based on: $fun. " )
2885
+
2841
2886
classDef.symbol addAnnotation SerialVersionUIDAnnotation
2842
2887
block
2843
2888
}
0 commit comments