@@ -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
}
@@ -693,7 +691,7 @@ class Definitions {
693
691
694
692
object FunctionOf {
695
693
def apply (args : List [Type ], resultType : Type , isImplicit : Boolean = false )(implicit ctx : Context ) =
696
- FunctionType (args.length , isImplicit).appliedTo(args ::: resultType :: Nil )
694
+ FunctionType (args, resultType , isImplicit).appliedTo(args ::: resultType :: Nil )
697
695
def unapply (ft : Type )(implicit ctx : Context ) = {
698
696
val tsym = ft.typeSymbol
699
697
if (isFunctionClass(tsym)) {
@@ -773,16 +771,39 @@ class Definitions {
773
771
lazy val Function0_applyR = ImplementedFunctionType (0 ).symbol.requiredMethodRef(nme.apply)
774
772
def Function0_apply (implicit ctx : Context ) = Function0_applyR .symbol
775
773
776
- def FunctionType (n : Int , isImplicit : Boolean = false )(implicit ctx : Context ): TypeRef =
777
- if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
774
+ def FunctionType (n : Int , isImplicit : Boolean = false , top : Type = AnyType )(implicit ctx : Context ): TypeRef = {
775
+ if (top.isPhantom) {
776
+ val functionPrefix = if (isImplicit) str.ImplicitFunction else str.Function
777
+ val functionName = (functionPrefix + n).toTypeName
778
+ val functionType = top.normalizedPrefix.select(functionName)
779
+ assert(functionType.classSymbol.exists)
780
+ functionType.asInstanceOf [TypeRef ]
781
+ }
782
+ else if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
778
783
else FunctionClass (n, isImplicit).typeRef
784
+ }
785
+
786
+ def FunctionType (args : List [Type ], resultType : Type , isImplicit : Boolean )(implicit ctx : Context ): TypeRef =
787
+ FunctionType (args.length, isImplicit, topInSameUniverse(args, " function arguments." ))
788
+
789
+ private def topInSameUniverse (types : List [Type ], relationship : => String )(implicit ctx : Context ): Type = {
790
+ types match {
791
+ case first :: Nil => first.topType
792
+ case first :: rest => (first /: rest)(inSameUniverse((t1, _) => t1.topType, _, _, relationship, ctx.owner.pos))
793
+ case Nil => defn.AnyType
794
+ }
795
+ }
779
796
780
797
private lazy val TupleTypes : Set [TypeRef ] = TupleType .toSet
781
798
782
799
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
783
800
def scalaClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
784
801
if (cls.isClass && cls.owner == ScalaPackageClass ) cls.asClass.name else EmptyTypeName
785
802
803
+ /** If `cls` is a class in an object extending scala.Phantom, its name, otherwise EmptyTypeName */
804
+ def phantomClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
805
+ if (cls.isClass && cls.owner.derivesFrom(PhantomClass )) cls.asClass.name else EmptyTypeName
806
+
786
807
/** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */
787
808
def scalaClassName (ref : Type )(implicit ctx : Context ): TypeName = scalaClassName(ref.classSymbol)
788
809
@@ -801,24 +822,28 @@ class Definitions {
801
822
* - FunctionN for N >= 0
802
823
* - ImplicitFunctionN for N > 0
803
824
*/
804
- def isFunctionClass (cls : Symbol ) = scalaClassName(cls).isFunction
825
+ def isFunctionClass (cls : Symbol ) =
826
+ scalaClassName(cls).isFunction || phantomClassName(cls).isFunction
805
827
806
828
/** Is an implicit function class.
807
829
* - ImplicitFunctionN for N > 0
808
830
*/
809
- def isImplicitFunctionClass (cls : Symbol ) = scalaClassName(cls).isImplicitFunction
831
+ def isImplicitFunctionClass (cls : Symbol ) =
832
+ scalaClassName(cls).isImplicitFunction || phantomClassName(cls).isImplicitFunction
810
833
811
834
/** Is a class that will be erased to FunctionXXL
812
835
* - FunctionN for N >= 22
813
836
* - ImplicitFunctionN for N >= 22
814
837
*/
815
- def isXXLFunctionClass (cls : Symbol ) = scalaClassName(cls).functionArity > MaxImplementedFunctionArity
838
+ def isXXLFunctionClass (cls : Symbol ) =
839
+ scalaClassName(cls).functionArity > MaxImplementedFunctionArity
816
840
817
841
/** Is a synthetic function class
818
842
* - FunctionN for N > 22
819
843
* - ImplicitFunctionN for N > 0
820
844
*/
821
- def isSyntheticFunctionClass (cls : Symbol ) = scalaClassName(cls).isSyntheticFunction
845
+ def isSyntheticFunctionClass (cls : Symbol ) =
846
+ scalaClassName(cls).isSyntheticScalaFunction || phantomClassName(cls).isFunction
822
847
823
848
def isAbstractFunctionClass (cls : Symbol ) = isVarArityClass(cls, str.AbstractFunction )
824
849
def isTupleClass (cls : Symbol ) = isVarArityClass(cls, str.Tuple )
@@ -835,6 +860,7 @@ class Definitions {
835
860
val arity = scalaClassName(cls).functionArity
836
861
if (arity > 22 ) FunctionXXLClass
837
862
else if (arity >= 0 ) FunctionClass (arity)
863
+ else if (phantomClassName(cls).isFunction) FunctionClass (0 )
838
864
else NoSymbol
839
865
}
840
866
@@ -847,8 +873,9 @@ class Definitions {
847
873
*/
848
874
def erasedFunctionType (cls : Symbol ): Type = {
849
875
val arity = scalaClassName(cls).functionArity
850
- if (arity > 22 ) defn.FunctionXXLType
851
- else if (arity >= 0 ) defn.FunctionType (arity)
876
+ if (arity > 22 ) FunctionXXLType
877
+ else if (arity >= 0 ) FunctionType (arity)
878
+ else if (phantomClassName(cls).isFunction) FunctionType (0 )
852
879
else NoType
853
880
}
854
881
@@ -893,7 +920,10 @@ class Definitions {
893
920
* trait gets screwed up. Therefore, it is mandatory that FunctionXXL
894
921
* is treated as a NoInit trait.
895
922
*/
896
- lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
923
+ private lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
924
+
925
+ def isNoInitClass (cls : Symbol ): Boolean =
926
+ cls.is(NoInitsTrait ) || NoInitClasses .contains(cls) || isFunctionClass(cls)
897
927
898
928
def isPolymorphicAfterErasure (sym : Symbol ) =
899
929
(sym eq Any_isInstanceOf ) || (sym eq Any_asInstanceOf )
@@ -914,7 +944,11 @@ class Definitions {
914
944
def isFunctionType (tp : Type )(implicit ctx : Context ) = {
915
945
val arity = functionArity(tp)
916
946
val sym = tp.dealias.typeSymbol
917
- arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType (arity, sym.name.isImplicitFunction).typeSymbol)
947
+ def top =
948
+ if (! sym.owner.derivesFrom(defn.PhantomClass )) defn.AnyType
949
+ else sym.owner.thisType.select(tpnme.Any )
950
+ def funType = FunctionType (arity, sym.name.isImplicitFunction, top)
951
+ arity >= 0 && isFunctionClass(sym) && tp.isRef(funType.typeSymbol)
918
952
}
919
953
920
954
def functionArity (tp : Type )(implicit ctx : Context ) = tp.dealias.argInfos.length - 1
@@ -1030,6 +1064,10 @@ class Definitions {
1030
1064
1031
1065
lazy val PhantomClass : ClassSymbol = {
1032
1066
val cls = completeClass(enterCompleteClassSymbol(ScalaPackageClass , tpnme.Phantom , NoInitsTrait , List (AnyType )))
1067
+ cls.unforcedDecls.openForMutations.useSynthesizer { name => ctx =>
1068
+ if (name.isTypeName && name.isFunction) newFunctionNTrait(name.asTypeName, cls)
1069
+ else NoSymbol
1070
+ }
1033
1071
1034
1072
val any = enterCompleteClassSymbol(cls, tpnme.Any , Protected | Final | NoInitsTrait , Nil )
1035
1073
val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing , Protected | Final | NoInitsTrait , List (any.typeRef))
@@ -1050,4 +1088,16 @@ class Definitions {
1050
1088
1051
1089
def ErasedPhantom_UNIT (implicit ctx : Context ) = ErasedPhantomClass .linkedClass.requiredValue(" UNIT" )
1052
1090
1091
+ /** Ensure that `tp2`' is in the same universe as `tp1`. If that's the case, return
1092
+ * `op` applied to both types.
1093
+ * If not, issue an error and return `tp1`'.
1094
+ */
1095
+ def inSameUniverse (op : (Type , Type ) => Type , tp1 : Type , tp2 : Type , relationship : => String , pos : Position )(implicit ctx : Context ): Type =
1096
+ if (tp1.topType == tp2.topType)
1097
+ op(tp1, tp2)
1098
+ else {
1099
+ ctx.error(ex " $tp1 and $tp2 are in different universes. They cannot be combined in $relationship" , pos)
1100
+ tp1
1101
+ }
1102
+
1053
1103
}
0 commit comments