@@ -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.
@@ -108,33 +108,31 @@ class Definitions {
108
108
* def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
109
109
* }
110
110
*/
111
- def newFunctionNTrait (name : TypeName ): ClassSymbol = {
111
+ def newFunctionNTrait (name : TypeName , lattice : Symbol ): ClassSymbol = {
112
112
val completer = new LazyType {
113
113
def complete (denot : SymDenotation )(implicit ctx : Context ): Unit = {
114
114
val cls = denot.asClass.classSymbol
115
115
val decls = newScope
116
116
val arity = name.functionArity
117
+ val top = lattice.thisType.select(tpnme.Any )
118
+ val bottom = lattice.thisType.select(tpnme.Nothing )
117
119
val paramNamePrefix = tpnme.scala_ ++ str.NAME_JOIN ++ name ++ str.EXPAND_SEPARATOR
118
120
val argParams =
119
121
for (i <- List .range(1 , arity + 1 )) yield
120
- enterTypeParam(cls, paramNamePrefix ++ " T" ++ i.toString, Contravariant , decls)
121
- val resParam = enterTypeParam(cls, paramNamePrefix ++ " R" , Covariant , decls)
122
+ enterTypeParam(cls, paramNamePrefix ++ " T" ++ i.toString, Contravariant , decls, TypeBounds (bottom, top)).typeRef
123
+ val resParam = enterTypeParam(cls, paramNamePrefix ++ " R" , Covariant , decls, TypeBounds .empty).typeRef
122
124
val (methodType, parentTraits) =
123
125
if (name.firstPart.startsWith(str.ImplicitFunction )) {
124
126
val superTrait =
125
- FunctionType (arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil )
127
+ FunctionType (arity, isImplicit = false , top ).appliedTo(argParams ::: resParam :: Nil )
126
128
(ImplicitMethodType , ctx.normalizeToClassRefs(superTrait :: Nil , cls, decls))
127
129
}
128
130
else (MethodType , Nil )
129
- val applyMeth =
130
- decls.enter(
131
- newMethod(cls, nme.apply,
132
- methodType(argParams.map(_.typeRef), resParam.typeRef), Deferred ))
133
- denot.info =
134
- ClassInfo (ScalaPackageClass .thisType, cls, ObjectType :: parentTraits, decls)
131
+ decls.enter(newMethod(cls, nme.apply, methodType(argParams, resParam), Deferred ))
132
+ denot.info = ClassInfo (lattice.thisType, cls, ObjectType :: parentTraits, decls)
135
133
}
136
134
}
137
- newClassSymbol(ScalaPackageClass , name, Trait | NoInits , completer)
135
+ newClassSymbol(lattice , name, Trait | NoInits , completer)
138
136
}
139
137
140
138
private def newMethod (cls : ClassSymbol , name : TermName , info : Type , flags : FlagSet = EmptyFlags ): TermSymbol =
@@ -194,7 +192,7 @@ class Definitions {
194
192
val cls = ScalaPackageVal .moduleClass.asClass
195
193
cls.info.decls.openForMutations.useSynthesizer(
196
194
name => ctx =>
197
- if (name.isTypeName && name.isSyntheticFunction ) newFunctionNTrait(name.asTypeName)
195
+ if (name.isTypeName && name.isSyntheticScalaFunction ) newFunctionNTrait(name.asTypeName, cls )
198
196
else NoSymbol )
199
197
cls
200
198
}
@@ -682,7 +680,7 @@ class Definitions {
682
680
683
681
object FunctionOf {
684
682
def apply (args : List [Type ], resultType : Type , isImplicit : Boolean = false )(implicit ctx : Context ) =
685
- FunctionType (args.length , isImplicit).appliedTo(args ::: resultType :: Nil )
683
+ FunctionType (args, resultType , isImplicit).appliedTo(args ::: resultType :: Nil )
686
684
def unapply (ft : Type )(implicit ctx : Context ) = {
687
685
val tsym = ft.typeSymbol
688
686
if (isFunctionClass(tsym)) {
@@ -747,16 +745,38 @@ class Definitions {
747
745
lazy val Function0_applyR = ImplementedFunctionType (0 ).symbol.requiredMethodRef(nme.apply)
748
746
def Function0_apply (implicit ctx : Context ) = Function0_applyR .symbol
749
747
750
- def FunctionType (n : Int , isImplicit : Boolean = false )(implicit ctx : Context ): TypeRef =
751
- if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
748
+ def FunctionType (n : Int , isImplicit : Boolean = false , top : Type = AnyType )(implicit ctx : Context ): TypeRef = {
749
+ if (top.isPhantom) {
750
+ val functionPrefix = if (isImplicit) str.ImplicitFunction else str.Function
751
+ val functionName = (functionPrefix + n).toTypeName
752
+ val functionType = top.normalizedPrefix.select(functionName)
753
+ assert(functionType.classSymbol.exists)
754
+ functionType.asInstanceOf [TypeRef ]
755
+ }
756
+ else if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
752
757
else FunctionClass (n, isImplicit).typeRef
758
+ }
759
+
760
+ def FunctionType (args : List [Type ], resultType : Type , isImplicit : Boolean )(implicit ctx : Context ): TypeRef =
761
+ FunctionType (args.length, isImplicit, topInSameUniverse(args, " function arguments." ))
762
+
763
+ private def topInSameUniverse (types : List [Type ], relationship : => String )(implicit ctx : Context ): Type = {
764
+ types match {
765
+ case first :: rest => (first /: rest)(inSameUniverse((t1, _) => t1.topType, _, _, relationship, ctx.owner.pos))
766
+ case Nil => defn.AnyType
767
+ }
768
+ }
753
769
754
770
private lazy val TupleTypes : Set [TypeRef ] = TupleType .toSet
755
771
756
772
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
757
773
def scalaClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
758
774
if (cls.isClass && cls.owner == ScalaPackageClass ) cls.asClass.name else EmptyTypeName
759
775
776
+ /** If `cls` is a class in an object extending scala.Phantom, its name, otherwise EmptyTypeName */
777
+ def phantomClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
778
+ if (cls.isClass && cls.owner.derivesFrom(PhantomClass )) cls.asClass.name else EmptyTypeName
779
+
760
780
/** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */
761
781
def scalaClassName (ref : Type )(implicit ctx : Context ): TypeName = scalaClassName(ref.classSymbol)
762
782
@@ -775,24 +795,28 @@ class Definitions {
775
795
* - FunctionN for N >= 0
776
796
* - ImplicitFunctionN for N >= 0
777
797
*/
778
- def isFunctionClass (cls : Symbol ) = scalaClassName(cls).isFunction
798
+ def isFunctionClass (cls : Symbol ) =
799
+ scalaClassName(cls).isFunction || phantomClassName(cls).isFunction
779
800
780
801
/** Is an implicit function class.
781
802
* - ImplicitFunctionN for N >= 0
782
803
*/
783
- def isImplicitFunctionClass (cls : Symbol ) = scalaClassName(cls).isImplicitFunction
804
+ def isImplicitFunctionClass (cls : Symbol ) =
805
+ scalaClassName(cls).isImplicitFunction || phantomClassName(cls).isImplicitFunction
784
806
785
807
/** Is a class that will be erased to FunctionXXL
786
808
* - FunctionN for N >= 22
787
809
* - ImplicitFunctionN for N >= 22
788
810
*/
789
- def isXXLFunctionClass (cls : Symbol ) = scalaClassName(cls).functionArity > MaxImplementedFunctionArity
811
+ def isXXLFunctionClass (cls : Symbol ) =
812
+ scalaClassName(cls).functionArity > MaxImplementedFunctionArity
790
813
791
814
/** Is a synthetic function class
792
815
* - FunctionN for N > 22
793
816
* - ImplicitFunctionN for N >= 0
794
817
*/
795
- def isSyntheticFunctionClass (cls : Symbol ) = scalaClassName(cls).isSyntheticFunction
818
+ def isSyntheticFunctionClass (cls : Symbol ) =
819
+ scalaClassName(cls).isSyntheticScalaFunction || phantomClassName(cls).isFunction
796
820
797
821
def isAbstractFunctionClass (cls : Symbol ) = isVarArityClass(cls, str.AbstractFunction )
798
822
def isTupleClass (cls : Symbol ) = isVarArityClass(cls, str.Tuple )
@@ -809,6 +833,7 @@ class Definitions {
809
833
val arity = scalaClassName(cls).functionArity
810
834
if (arity > 22 ) defn.FunctionXXLClass
811
835
else if (arity >= 0 ) defn.FunctionClass (arity)
836
+ else if (phantomClassName(cls).isFunction) defn.FunctionClass (0 )
812
837
else NoSymbol
813
838
}
814
839
@@ -823,6 +848,7 @@ class Definitions {
823
848
val arity = scalaClassName(cls).functionArity
824
849
if (arity > 22 ) defn.FunctionXXLType
825
850
else if (arity >= 0 ) defn.FunctionType (arity)
851
+ else if (phantomClassName(cls).isFunction) defn.FunctionType (0 )
826
852
else NoType
827
853
}
828
854
@@ -867,7 +893,10 @@ class Definitions {
867
893
* trait gets screwed up. Therefore, it is mandatory that FunctionXXL
868
894
* is treated as a NoInit trait.
869
895
*/
870
- lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
896
+ private lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
897
+
898
+ def isNoInitClass (cls : Symbol ): Boolean =
899
+ cls.is(NoInitsTrait ) || NoInitClasses .contains(cls) || isFunctionClass(cls)
871
900
872
901
def isPolymorphicAfterErasure (sym : Symbol ) =
873
902
(sym eq Any_isInstanceOf ) || (sym eq Any_asInstanceOf )
@@ -888,7 +917,11 @@ class Definitions {
888
917
def isFunctionType (tp : Type )(implicit ctx : Context ) = {
889
918
val arity = functionArity(tp)
890
919
val sym = tp.dealias.typeSymbol
891
- arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType (arity, sym.name.isImplicitFunction).typeSymbol)
920
+ def top =
921
+ if (! sym.owner.derivesFrom(defn.PhantomClass )) defn.AnyType
922
+ else sym.owner.thisType.select(tpnme.Any )
923
+ def funType = FunctionType (arity, sym.name.isImplicitFunction, top)
924
+ arity >= 0 && isFunctionClass(sym) && tp.isRef(funType.typeSymbol)
892
925
}
893
926
894
927
def functionArity (tp : Type )(implicit ctx : Context ) = tp.dealias.argInfos.length - 1
@@ -1004,6 +1037,10 @@ class Definitions {
1004
1037
1005
1038
lazy val PhantomClass : ClassSymbol = {
1006
1039
val cls = completeClass(enterCompleteClassSymbol(ScalaPackageClass , tpnme.Phantom , NoInitsTrait , List (AnyType )))
1040
+ cls.unforcedDecls.openForMutations.useSynthesizer { name => ctx =>
1041
+ if (name.isTypeName && name.isFunction) newFunctionNTrait(name.asTypeName, cls)
1042
+ else NoSymbol
1043
+ }
1007
1044
1008
1045
val any = enterCompleteClassSymbol(cls, tpnme.Any , Protected | Final | NoInitsTrait , Nil )
1009
1046
val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing , Protected | Final | NoInitsTrait , List (any.typeRef))
@@ -1024,4 +1061,16 @@ class Definitions {
1024
1061
1025
1062
def ErasedPhantom_UNIT (implicit ctx : Context ) = ErasedPhantomClass .linkedClass.requiredValue(" UNIT" )
1026
1063
1064
+ /** Ensure that `tp2`' is in the same universe as `tp1`. If that's the case, return
1065
+ * `op` applied to both types.
1066
+ * If not, issue an error and return `tp1`'.
1067
+ */
1068
+ def inSameUniverse (op : (Type , Type ) => Type , tp1 : Type , tp2 : Type , relationship : => String , pos : Position )(implicit ctx : Context ): Type =
1069
+ if (tp1.topType == tp2.topType)
1070
+ op(tp1, tp2)
1071
+ else {
1072
+ ctx.error(ex " $tp1 and $tp2 are in different universes. They cannot be combined in $relationship" , pos)
1073
+ tp1
1074
+ }
1075
+
1027
1076
}
0 commit comments