@@ -86,24 +86,51 @@ class Definitions {
86
86
newClassSymbol(ScalaPackageClass , name, EmptyFlags , completer).entered
87
87
}
88
88
89
- /** The trait FunctionN, for some N */
90
- private def newFunctionNTrait (n : Int ) = {
89
+ /** The trait FunctionN or ImplicitFunctionN, for some N
90
+ * @param name The name of the trait to be created
91
+ *
92
+ * FunctionN traits follow this template:
93
+ *
94
+ * trait FunctionN[T0,...T{N-1}, R] extends Object {
95
+ * def apply($x0: T0, ..., $x{N_1}: T{N-1}): R
96
+ * }
97
+ *
98
+ * That is, they follow the template given for Function2..Function22 in the
99
+ * standard library, but without `tupled` and `curried` methods and without
100
+ * a `toString`.
101
+ *
102
+ * ImplicitFunctionN traits follow this template:
103
+ *
104
+ * trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object with FunctionN[T0,...,T{N-1}, R] {
105
+ * def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
106
+ * }
107
+ */
108
+ private def newFunctionNTrait (name : TypeName ) = {
91
109
val completer = new LazyType {
92
110
def complete (denot : SymDenotation )(implicit ctx : Context ): Unit = {
93
111
val cls = denot.asClass.classSymbol
94
112
val decls = newScope
113
+ val arity = name.functionArity
95
114
val argParams =
96
- for (i <- List .range(0 , n)) yield
97
- enterTypeParam(cls, s " T $i" .toTypeName, Contravariant , decls)
98
- val resParam = enterTypeParam(cls, s " R " .toTypeName, Covariant , decls)
115
+ for (i <- List .range(0 , arity)) yield
116
+ enterTypeParam(cls, name ++ " $T" ++ i.toString, Contravariant , decls)
117
+ val resParam = enterTypeParam(cls, name ++ " $R" , Covariant , decls)
118
+ val (methodType, parentTraits) =
119
+ if (name.startsWith(tpnme.ImplicitFunction )) {
120
+ val superTrait =
121
+ FunctionType (arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil )
122
+ (ImplicitMethodType , ctx.normalizeToClassRefs(superTrait :: Nil , cls, decls))
123
+ }
124
+ else (MethodType , Nil )
99
125
val applyMeth =
100
126
decls.enter(
101
127
newMethod(cls, nme.apply,
102
- MethodType (argParams.map(_.typeRef), resParam.typeRef), Deferred ))
103
- denot.info = ClassInfo (ScalaPackageClass .thisType, cls, ObjectType :: Nil , decls)
128
+ methodType(argParams.map(_.typeRef), resParam.typeRef), Deferred ))
129
+ denot.info =
130
+ ClassInfo (ScalaPackageClass .thisType, cls, ObjectType :: parentTraits, decls)
104
131
}
105
132
}
106
- newClassSymbol(ScalaPackageClass , s " Function $n " .toTypeName , Trait , completer)
133
+ newClassSymbol(ScalaPackageClass , name , Trait , completer)
107
134
}
108
135
109
136
private def newMethod (cls : ClassSymbol , name : TermName , info : Type , flags : FlagSet = EmptyFlags ): TermSymbol =
@@ -590,15 +617,16 @@ class Definitions {
590
617
sym.owner.linkedClass.typeRef
591
618
592
619
object FunctionOf {
593
- def apply (args : List [Type ], resultType : Type )(implicit ctx : Context ) =
594
- FunctionType (args.length).appliedTo(args ::: resultType :: Nil )
620
+ def apply (args : List [Type ], resultType : Type , isImplicit : Boolean = false )(implicit ctx : Context ) =
621
+ FunctionType (args.length, isImplicit ).appliedTo(args ::: resultType :: Nil )
595
622
def unapply (ft : Type )(implicit ctx : Context ) = {
596
623
val tsym = ft.typeSymbol
597
- if (isFunctionClass(tsym)) {
598
- lazy val targs = ft.argInfos
624
+ val isImplicitFun = isImplicitFunctionClass(tsym)
625
+ if (isImplicitFun || isFunctionClass(tsym)) {
626
+ val targs = ft.argInfos
599
627
val numArgs = targs.length - 1
600
- if (numArgs >= 0 && FunctionType (numArgs).symbol == tsym)
601
- Some (targs.init, targs.last)
628
+ if (numArgs >= 0 && FunctionType (numArgs, isImplicitFun ).symbol == tsym)
629
+ Some (targs.init, targs.last, isImplicitFun )
602
630
else None
603
631
}
604
632
else None
@@ -659,8 +687,12 @@ class Definitions {
659
687
lazy val Function0_applyR = ImplementedFunctionType (0 ).symbol.requiredMethodRef(nme.apply)
660
688
def Function0_apply (implicit ctx : Context ) = Function0_applyR .symbol
661
689
662
- def FunctionType (n : Int )(implicit ctx : Context ): TypeRef =
663
- if (n < MaxImplementedFunctionArity ) ImplementedFunctionType (n)
690
+ def ImplicitFunctionClass (n : Int )(implicit ctx : Context ) =
691
+ ctx.requiredClass(" scala.ImplicitFunction" + n.toString)
692
+
693
+ def FunctionType (n : Int , isImplicit : Boolean = false )(implicit ctx : Context ): TypeRef =
694
+ if (isImplicit && ! ctx.erasedTypes) ImplicitFunctionClass (n).typeRef
695
+ else if (n < MaxImplementedFunctionArity ) ImplementedFunctionType (n)
664
696
else FunctionClass (n).typeRef
665
697
666
698
private lazy val TupleTypes : Set [TypeRef ] = TupleType .toSet
@@ -686,6 +718,7 @@ class Definitions {
686
718
tp.derivesFrom(NothingClass ) || tp.derivesFrom(NullClass )
687
719
688
720
def isFunctionClass (cls : Symbol ) = isVarArityClass(cls, tpnme.Function )
721
+ def isImplicitFunctionClass (cls : Symbol ) = isVarArityClass(cls, tpnme.ImplicitFunction )
689
722
def isUnimplementedFunctionClass (cls : Symbol ) =
690
723
isFunctionClass(cls) && cls.name.functionArity > MaxImplementedFunctionArity
691
724
def isAbstractFunctionClass (cls : Symbol ) = isVarArityClass(cls, tpnme.AbstractFunction )
@@ -745,14 +778,21 @@ class Definitions {
745
778
}
746
779
else - 1
747
780
748
- def isFunctionType (tp : Type )(implicit ctx : Context ) =
749
- isFunctionClass(tp.dealias.typeSymbol) && {
750
- val arity = functionArity(tp)
751
- arity >= 0 && tp.isRef(FunctionType (functionArity(tp)).typeSymbol)
752
- }
781
+ /** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN ? */
782
+ def isFunctionType (tp : Type )(implicit ctx : Context ) = {
783
+ val arity = functionArity(tp)
784
+ val sym = tp.dealias.typeSymbol
785
+ arity >= 0 && (
786
+ isFunctionClass(sym) && tp.isRef(FunctionType (arity, isImplicit = false ).typeSymbol) ||
787
+ isImplicitFunctionClass(sym) && tp.isRef(FunctionType (arity, isImplicit = true ).typeSymbol)
788
+ )
789
+ }
753
790
754
791
def functionArity (tp : Type )(implicit ctx : Context ) = tp.dealias.argInfos.length - 1
755
792
793
+ def isImplicitFunctionType (tp : Type )(implicit ctx : Context ) =
794
+ isFunctionType(tp) && tp.dealias.typeSymbol.name.startsWith(tpnme.ImplicitFunction )
795
+
756
796
// ----- primitive value class machinery ------------------------------------------
757
797
758
798
/** This class would also be obviated by the implicit function type design */
@@ -825,6 +865,9 @@ class Definitions {
825
865
826
866
// ----- Initialization ---------------------------------------------------
827
867
868
+ private def maxImplemented (name : Name ) =
869
+ if (name `startsWith` tpnme.Function ) MaxImplementedFunctionArity else 0
870
+
828
871
/** Give the scala package a scope where a FunctionN trait is automatically
829
872
* added when someone looks for it.
830
873
*/
@@ -834,8 +877,8 @@ class Definitions {
834
877
val newDecls = new MutableScope (oldDecls) {
835
878
override def lookupEntry (name : Name )(implicit ctx : Context ): ScopeEntry = {
836
879
val res = super .lookupEntry(name)
837
- if (res == null && name.functionArity > MaxImplementedFunctionArity )
838
- newScopeEntry(newFunctionNTrait(name.functionArity ))
880
+ if (res == null && name.isTypeName && name. functionArity > maxImplemented(name) )
881
+ newScopeEntry(newFunctionNTrait(name.asTypeName ))
839
882
else res
840
883
}
841
884
}
0 commit comments