@@ -60,14 +60,14 @@ class Definitions {
60
60
private def enterCompleteClassSymbol (owner : Symbol , name : TypeName , flags : FlagSet , parents : List [TypeRef ], decls : Scope = newScope) =
61
61
ctx.newCompleteClassSymbol(owner, name, flags | Permanent , parents, decls).entered
62
62
63
- private def enterTypeField (cls : ClassSymbol , name : TypeName , flags : FlagSet , scope : MutableScope ) =
64
- scope.enter(newSymbol(cls, name, flags, TypeBounds .empty ))
63
+ private def enterTypeField (cls : ClassSymbol , name : TypeName , flags : FlagSet , scope : MutableScope , typeBounds : TypeBounds ) =
64
+ scope.enter(newSymbol(cls, name, flags, typeBounds ))
65
65
66
- private def enterTypeParam (cls : ClassSymbol , name : TypeName , flags : FlagSet , scope : MutableScope ) =
67
- enterTypeField(cls, name, flags | ClassTypeParamCreationFlags , scope)
66
+ private def enterTypeParam (cls : ClassSymbol , name : TypeName , flags : FlagSet , scope : MutableScope , typeBounds : TypeBounds ) =
67
+ enterTypeField(cls, name, flags | ClassTypeParamCreationFlags , scope, typeBounds )
68
68
69
69
private def enterSyntheticTypeParam (cls : ClassSymbol , paramFlags : FlagSet , scope : MutableScope , suffix : String = " T0" ) =
70
- enterTypeParam(cls, suffix.toTypeName.expandedName(cls), paramFlags, scope)
70
+ enterTypeParam(cls, suffix.toTypeName.expandedName(cls), paramFlags, scope, TypeBounds .empty )
71
71
72
72
// NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only
73
73
// implemented in Dotty and not in Scala 2.
@@ -104,33 +104,31 @@ class Definitions {
104
104
* def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
105
105
* }
106
106
*/
107
- def newFunctionNTrait (name : TypeName ): ClassSymbol = {
107
+ def newFunctionNTrait (name : TypeName , lattice : Symbol ): ClassSymbol = {
108
108
val completer = new LazyType {
109
109
def complete (denot : SymDenotation )(implicit ctx : Context ): Unit = {
110
110
val cls = denot.asClass.classSymbol
111
111
val decls = newScope
112
112
val arity = name.functionArity
113
+ val top = lattice.thisType.select(tpnme.Any )
114
+ val bottom = lattice.thisType.select(tpnme.Nothing )
113
115
val paramNamePrefix = tpnme.scala_ ++ str.NAME_JOIN ++ name ++ str.EXPAND_SEPARATOR
114
116
val argParams =
115
117
for (i <- List .range(1 , arity + 1 )) yield
116
- enterTypeParam(cls, paramNamePrefix ++ " T" ++ i.toString, Contravariant , decls)
117
- val resParam = enterTypeParam(cls, paramNamePrefix ++ " R" , Covariant , decls)
118
+ enterTypeParam(cls, paramNamePrefix ++ " T" ++ i.toString, Contravariant , decls, TypeBounds (bottom, top)).typeRef
119
+ val resParam = enterTypeParam(cls, paramNamePrefix ++ " R" , Covariant , decls, TypeBounds .empty).typeRef
118
120
val (methodType, parentTraits) =
119
121
if (name.firstPart.startsWith(str.ImplicitFunction )) {
120
122
val superTrait =
121
- FunctionType (arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil )
123
+ FunctionType (arity, isImplicit = false , top ).appliedTo(argParams ::: resParam :: Nil )
122
124
(ImplicitMethodType , superTrait :: Nil )
123
125
}
124
126
else (MethodType , Nil )
125
- val applyMeth =
126
- decls.enter(
127
- newMethod(cls, nme.apply,
128
- methodType(argParams.map(_.typeRef), resParam.typeRef), Deferred ))
129
- denot.info =
130
- ClassInfo (ScalaPackageClass .thisType, cls, ObjectType :: parentTraits, decls)
127
+ decls.enter(newMethod(cls, nme.apply, methodType(argParams, resParam), Deferred ))
128
+ denot.info = ClassInfo (lattice.thisType, cls, ObjectType :: parentTraits, decls)
131
129
}
132
130
}
133
- newClassSymbol(ScalaPackageClass , name, Trait | NoInits , completer)
131
+ newClassSymbol(lattice , name, Trait | NoInits , completer)
134
132
}
135
133
136
134
private def newMethod (cls : ClassSymbol , name : TermName , info : Type , flags : FlagSet = EmptyFlags ): TermSymbol =
@@ -190,7 +188,7 @@ class Definitions {
190
188
val cls = ScalaPackageVal .moduleClass.asClass
191
189
cls.info.decls.openForMutations.useSynthesizer(
192
190
name => ctx =>
193
- if (name.isTypeName && name.isSyntheticFunction ) newFunctionNTrait(name.asTypeName)
191
+ if (name.isTypeName && name.isSyntheticScalaFunction ) newFunctionNTrait(name.asTypeName, cls )
194
192
else NoSymbol )
195
193
cls
196
194
}
@@ -687,7 +685,7 @@ class Definitions {
687
685
688
686
object FunctionOf {
689
687
def apply (args : List [Type ], resultType : Type , isImplicit : Boolean = false )(implicit ctx : Context ) =
690
- FunctionType (args.length , isImplicit).appliedTo(args ::: resultType :: Nil )
688
+ FunctionType (args, resultType , isImplicit).appliedTo(args ::: resultType :: Nil )
691
689
def unapply (ft : Type )(implicit ctx : Context ) = {
692
690
val tsym = ft.typeSymbol
693
691
if (isFunctionClass(tsym)) {
@@ -767,16 +765,39 @@ class Definitions {
767
765
lazy val Function0_applyR = ImplementedFunctionType (0 ).symbol.requiredMethodRef(nme.apply)
768
766
def Function0_apply (implicit ctx : Context ) = Function0_applyR .symbol
769
767
770
- def FunctionType (n : Int , isImplicit : Boolean = false )(implicit ctx : Context ): TypeRef =
771
- if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
768
+ def FunctionType (n : Int , isImplicit : Boolean = false , top : Type = AnyType )(implicit ctx : Context ): TypeRef = {
769
+ if (top.isPhantom) {
770
+ val functionPrefix = if (isImplicit) str.ImplicitFunction else str.Function
771
+ val functionName = (functionPrefix + n).toTypeName
772
+ val functionType = top.normalizedPrefix.select(functionName)
773
+ assert(functionType.classSymbol.exists)
774
+ functionType.asInstanceOf [TypeRef ]
775
+ }
776
+ else if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
772
777
else FunctionClass (n, isImplicit).typeRef
778
+ }
779
+
780
+ def FunctionType (args : List [Type ], resultType : Type , isImplicit : Boolean )(implicit ctx : Context ): TypeRef =
781
+ FunctionType (args.length, isImplicit, topInSameUniverse(args, " function arguments." ))
782
+
783
+ private def topInSameUniverse (types : List [Type ], relationship : => String )(implicit ctx : Context ): Type = {
784
+ types match {
785
+ case first :: Nil => first.topType
786
+ case first :: rest => (first /: rest)(inSameUniverse((t1, _) => t1.topType, _, _, relationship, ctx.owner.pos))
787
+ case Nil => defn.AnyType
788
+ }
789
+ }
773
790
774
791
private lazy val TupleTypes : Set [TypeRef ] = TupleType .toSet
775
792
776
793
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
777
794
def scalaClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
778
795
if (cls.isClass && cls.owner == ScalaPackageClass ) cls.asClass.name else EmptyTypeName
779
796
797
+ /** If `cls` is a class in an object extending scala.Phantom, its name, otherwise EmptyTypeName */
798
+ def phantomClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
799
+ if (cls.isClass && cls.owner.derivesFrom(PhantomClass )) cls.asClass.name else EmptyTypeName
800
+
780
801
/** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */
781
802
def scalaClassName (ref : Type )(implicit ctx : Context ): TypeName = scalaClassName(ref.classSymbol)
782
803
@@ -795,24 +816,28 @@ class Definitions {
795
816
* - FunctionN for N >= 0
796
817
* - ImplicitFunctionN for N > 0
797
818
*/
798
- def isFunctionClass (cls : Symbol ) = scalaClassName(cls).isFunction
819
+ def isFunctionClass (cls : Symbol ) =
820
+ scalaClassName(cls).isFunction || phantomClassName(cls).isFunction
799
821
800
822
/** Is an implicit function class.
801
823
* - ImplicitFunctionN for N > 0
802
824
*/
803
- def isImplicitFunctionClass (cls : Symbol ) = scalaClassName(cls).isImplicitFunction
825
+ def isImplicitFunctionClass (cls : Symbol ) =
826
+ scalaClassName(cls).isImplicitFunction || phantomClassName(cls).isImplicitFunction
804
827
805
828
/** Is a class that will be erased to FunctionXXL
806
829
* - FunctionN for N >= 22
807
830
* - ImplicitFunctionN for N >= 22
808
831
*/
809
- def isXXLFunctionClass (cls : Symbol ) = scalaClassName(cls).functionArity > MaxImplementedFunctionArity
832
+ def isXXLFunctionClass (cls : Symbol ) =
833
+ scalaClassName(cls).functionArity > MaxImplementedFunctionArity
810
834
811
835
/** Is a synthetic function class
812
836
* - FunctionN for N > 22
813
837
* - ImplicitFunctionN for N > 0
814
838
*/
815
- def isSyntheticFunctionClass (cls : Symbol ) = scalaClassName(cls).isSyntheticFunction
839
+ def isSyntheticFunctionClass (cls : Symbol ) =
840
+ scalaClassName(cls).isSyntheticScalaFunction || phantomClassName(cls).isFunction
816
841
817
842
def isAbstractFunctionClass (cls : Symbol ) = isVarArityClass(cls, str.AbstractFunction )
818
843
def isTupleClass (cls : Symbol ) = isVarArityClass(cls, str.Tuple )
@@ -829,6 +854,7 @@ class Definitions {
829
854
val arity = scalaClassName(cls).functionArity
830
855
if (arity > 22 ) FunctionXXLClass
831
856
else if (arity >= 0 ) FunctionClass (arity)
857
+ else if (phantomClassName(cls).isFunction) FunctionClass (0 )
832
858
else NoSymbol
833
859
}
834
860
@@ -841,8 +867,9 @@ class Definitions {
841
867
*/
842
868
def erasedFunctionType (cls : Symbol ): Type = {
843
869
val arity = scalaClassName(cls).functionArity
844
- if (arity > 22 ) defn.FunctionXXLType
845
- else if (arity >= 0 ) defn.FunctionType (arity)
870
+ if (arity > 22 ) FunctionXXLType
871
+ else if (arity >= 0 ) FunctionType (arity)
872
+ else if (phantomClassName(cls).isFunction) FunctionType (0 )
846
873
else NoType
847
874
}
848
875
@@ -887,7 +914,10 @@ class Definitions {
887
914
* trait gets screwed up. Therefore, it is mandatory that FunctionXXL
888
915
* is treated as a NoInit trait.
889
916
*/
890
- lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
917
+ private lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
918
+
919
+ def isNoInitClass (cls : Symbol ): Boolean =
920
+ cls.is(NoInitsTrait ) || NoInitClasses .contains(cls) || isFunctionClass(cls)
891
921
892
922
def isPolymorphicAfterErasure (sym : Symbol ) =
893
923
(sym eq Any_isInstanceOf ) || (sym eq Any_asInstanceOf )
@@ -908,7 +938,11 @@ class Definitions {
908
938
def isFunctionType (tp : Type )(implicit ctx : Context ) = {
909
939
val arity = functionArity(tp)
910
940
val sym = tp.dealias.typeSymbol
911
- arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType (arity, sym.name.isImplicitFunction).typeSymbol)
941
+ def top =
942
+ if (! sym.owner.derivesFrom(defn.PhantomClass )) defn.AnyType
943
+ else sym.owner.thisType.select(tpnme.Any )
944
+ def funType = FunctionType (arity, sym.name.isImplicitFunction, top)
945
+ arity >= 0 && isFunctionClass(sym) && tp.isRef(funType.typeSymbol)
912
946
}
913
947
914
948
def functionArity (tp : Type )(implicit ctx : Context ) = tp.dealias.argInfos.length - 1
@@ -1024,6 +1058,10 @@ class Definitions {
1024
1058
1025
1059
lazy val PhantomClass : ClassSymbol = {
1026
1060
val cls = completeClass(enterCompleteClassSymbol(ScalaPackageClass , tpnme.Phantom , NoInitsTrait , List (AnyType )))
1061
+ cls.unforcedDecls.openForMutations.useSynthesizer { name => ctx =>
1062
+ if (name.isTypeName && name.isFunction) newFunctionNTrait(name.asTypeName, cls)
1063
+ else NoSymbol
1064
+ }
1027
1065
1028
1066
val any = enterCompleteClassSymbol(cls, tpnme.Any , Protected | Final | NoInitsTrait , Nil )
1029
1067
val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing , Protected | Final | NoInitsTrait , List (any.typeRef))
@@ -1044,4 +1082,16 @@ class Definitions {
1044
1082
1045
1083
def ErasedPhantom_UNIT (implicit ctx : Context ) = ErasedPhantomClass .linkedClass.requiredValue(" UNIT" )
1046
1084
1085
+ /** Ensure that `tp2`' is in the same universe as `tp1`. If that's the case, return
1086
+ * `op` applied to both types.
1087
+ * If not, issue an error and return `tp1`'.
1088
+ */
1089
+ def inSameUniverse (op : (Type , Type ) => Type , tp1 : Type , tp2 : Type , relationship : => String , pos : Position )(implicit ctx : Context ): Type =
1090
+ if (tp1.topType == tp2.topType)
1091
+ op(tp1, tp2)
1092
+ else {
1093
+ ctx.error(ex " $tp1 and $tp2 are in different universes. They cannot be combined in $relationship" , pos)
1094
+ tp1
1095
+ }
1096
+
1047
1097
}
0 commit comments