@@ -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,32 +108,30 @@ 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 argParams =
118
120
for (i <- List .range(0 , arity)) yield
119
- enterTypeParam(cls, name ++ " $T" ++ i.toString, Contravariant , decls)
120
- val resParam = enterTypeParam(cls, name ++ " $R" , Covariant , decls)
121
+ enterTypeParam(cls, name ++ " $T" ++ i.toString, Contravariant , decls, TypeBounds (bottom, top)).typeRef
122
+ val resParam = enterTypeParam(cls, name ++ " $R" , Covariant , decls, TypeBounds .empty).typeRef
121
123
val (methodType, parentTraits) =
122
124
if (name.firstPart.startsWith(str.ImplicitFunction )) {
123
125
val superTrait =
124
- FunctionType (arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil )
126
+ FunctionType (arity, isImplicit = false , top ).appliedTo(argParams ::: resParam :: Nil )
125
127
(ImplicitMethodType , ctx.normalizeToClassRefs(superTrait :: Nil , cls, decls))
126
128
}
127
129
else (MethodType , Nil )
128
- val applyMeth =
129
- decls.enter(
130
- newMethod(cls, nme.apply,
131
- methodType(argParams.map(_.typeRef), resParam.typeRef), Deferred ))
132
- denot.info =
133
- ClassInfo (ScalaPackageClass .thisType, cls, ObjectType :: parentTraits, decls)
130
+ decls.enter(newMethod(cls, nme.apply, methodType(argParams, resParam), Deferred ))
131
+ denot.info = ClassInfo (lattice.thisType, cls, ObjectType :: parentTraits, decls)
134
132
}
135
133
}
136
- newClassSymbol(ScalaPackageClass , name, Trait | NoInits , completer)
134
+ newClassSymbol(lattice , name, Trait | NoInits , completer)
137
135
}
138
136
139
137
private def newMethod (cls : ClassSymbol , name : TermName , info : Type , flags : FlagSet = EmptyFlags ): TermSymbol =
@@ -193,7 +191,7 @@ class Definitions {
193
191
val cls = ScalaPackageVal .moduleClass.asClass
194
192
cls.info.decls.openForMutations.useSynthesizer(
195
193
name => ctx =>
196
- if (name.isTypeName && name.isSyntheticFunction ) newFunctionNTrait(name.asTypeName)
194
+ if (name.isTypeName && name.isSyntheticScalaFunction ) newFunctionNTrait(name.asTypeName, cls )
197
195
else NoSymbol )
198
196
cls
199
197
}
@@ -654,7 +652,7 @@ class Definitions {
654
652
655
653
object FunctionOf {
656
654
def apply (args : List [Type ], resultType : Type , isImplicit : Boolean = false )(implicit ctx : Context ) =
657
- FunctionType (args.length , isImplicit).appliedTo(args ::: resultType :: Nil )
655
+ FunctionType (args, resultType , isImplicit).appliedTo(args ::: resultType :: Nil )
658
656
def unapply (ft : Type )(implicit ctx : Context ) = {
659
657
val tsym = ft.typeSymbol
660
658
if (isFunctionClass(tsym)) {
@@ -719,16 +717,38 @@ class Definitions {
719
717
lazy val Function0_applyR = ImplementedFunctionType (0 ).symbol.requiredMethodRef(nme.apply)
720
718
def Function0_apply (implicit ctx : Context ) = Function0_applyR .symbol
721
719
722
- def FunctionType (n : Int , isImplicit : Boolean = false )(implicit ctx : Context ): TypeRef =
723
- if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
720
+ def FunctionType (n : Int , isImplicit : Boolean = false , top : Type = AnyType )(implicit ctx : Context ): TypeRef = {
721
+ if (top.isPhantom) {
722
+ val functionPrefix = if (isImplicit) str.ImplicitFunction else str.Function
723
+ val functionName = (functionPrefix + n).toTypeName
724
+ val functionType = top.normalizedPrefix.select(functionName)
725
+ assert(functionType.classSymbol.exists)
726
+ functionType.asInstanceOf [TypeRef ]
727
+ }
728
+ else if (n <= MaxImplementedFunctionArity && (! isImplicit || ctx.erasedTypes)) ImplementedFunctionType (n)
724
729
else FunctionClass (n, isImplicit).typeRef
730
+ }
731
+
732
+ def FunctionType (args : List [Type ], resultType : Type , isImplicit : Boolean )(implicit ctx : Context ): TypeRef =
733
+ FunctionType (args.length, isImplicit, topInSameUniverse(args, " function arguments." ))
734
+
735
+ private def topInSameUniverse (types : List [Type ], relationship : => String )(implicit ctx : Context ): Type = {
736
+ types match {
737
+ case first :: rest => (first /: rest)(inSameUniverse((t1, _) => t1.topType, _, _, relationship, ctx.owner.pos))
738
+ case Nil => defn.AnyType
739
+ }
740
+ }
725
741
726
742
private lazy val TupleTypes : Set [TypeRef ] = TupleType .toSet
727
743
728
744
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
729
745
def scalaClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
730
746
if (cls.isClass && cls.owner == ScalaPackageClass ) cls.asClass.name else EmptyTypeName
731
747
748
+ /** If `cls` is a class in an object extending scala.Phantom, its name, otherwise EmptyTypeName */
749
+ def phantomClassName (cls : Symbol )(implicit ctx : Context ): TypeName =
750
+ if (cls.isClass && cls.owner.derivesFrom(PhantomClass )) cls.asClass.name else EmptyTypeName
751
+
732
752
/** If type `ref` refers to a class in the scala package, its name, otherwise EmptyTypeName */
733
753
def scalaClassName (ref : Type )(implicit ctx : Context ): TypeName = scalaClassName(ref.classSymbol)
734
754
@@ -747,24 +767,28 @@ class Definitions {
747
767
* - FunctionN for N >= 0
748
768
* - ImplicitFunctionN for N >= 0
749
769
*/
750
- def isFunctionClass (cls : Symbol ) = scalaClassName(cls).isFunction
770
+ def isFunctionClass (cls : Symbol ) =
771
+ scalaClassName(cls).isFunction || phantomClassName(cls).isFunction
751
772
752
773
/** Is an implicit function class.
753
774
* - ImplicitFunctionN for N >= 0
754
775
*/
755
- def isImplicitFunctionClass (cls : Symbol ) = scalaClassName(cls).isImplicitFunction
776
+ def isImplicitFunctionClass (cls : Symbol ) =
777
+ scalaClassName(cls).isImplicitFunction || phantomClassName(cls).isImplicitFunction
756
778
757
779
/** Is a class that will be erased to FunctionXXL
758
780
* - FunctionN for N >= 22
759
781
* - ImplicitFunctionN for N >= 22
760
782
*/
761
- def isXXLFunctionClass (cls : Symbol ) = scalaClassName(cls).functionArity > MaxImplementedFunctionArity
783
+ def isXXLFunctionClass (cls : Symbol ) =
784
+ scalaClassName(cls).functionArity > MaxImplementedFunctionArity
762
785
763
786
/** Is a synthetic function class
764
787
* - FunctionN for N > 22
765
788
* - ImplicitFunctionN for N >= 0
766
789
*/
767
- def isSyntheticFunctionClass (cls : Symbol ) = scalaClassName(cls).isSyntheticFunction
790
+ def isSyntheticFunctionClass (cls : Symbol ) =
791
+ scalaClassName(cls).isSyntheticScalaFunction || phantomClassName(cls).isFunction
768
792
769
793
def isAbstractFunctionClass (cls : Symbol ) = isVarArityClass(cls, str.AbstractFunction )
770
794
def isTupleClass (cls : Symbol ) = isVarArityClass(cls, str.Tuple )
@@ -781,6 +805,7 @@ class Definitions {
781
805
val arity = scalaClassName(cls).functionArity
782
806
if (arity > 22 ) defn.FunctionXXLClass
783
807
else if (arity >= 0 ) defn.FunctionClass (arity)
808
+ else if (phantomClassName(cls).isFunction) defn.FunctionClass (0 )
784
809
else NoSymbol
785
810
}
786
811
@@ -795,6 +820,7 @@ class Definitions {
795
820
val arity = scalaClassName(cls).functionArity
796
821
if (arity > 22 ) defn.FunctionXXLType
797
822
else if (arity >= 0 ) defn.FunctionType (arity)
823
+ else if (phantomClassName(cls).isFunction) defn.FunctionType (0 )
798
824
else NoType
799
825
}
800
826
@@ -839,7 +865,10 @@ class Definitions {
839
865
* trait gets screwed up. Therefore, it is mandatory that FunctionXXL
840
866
* is treated as a NoInit trait.
841
867
*/
842
- lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
868
+ private lazy val NoInitClasses = NotRuntimeClasses + FunctionXXLClass
869
+
870
+ def isNoInitClass (cls : Symbol ): Boolean =
871
+ cls.is(NoInitsTrait ) || NoInitClasses .contains(cls) || isFunctionClass(cls)
843
872
844
873
def isPolymorphicAfterErasure (sym : Symbol ) =
845
874
(sym eq Any_isInstanceOf ) || (sym eq Any_asInstanceOf )
@@ -860,7 +889,11 @@ class Definitions {
860
889
def isFunctionType (tp : Type )(implicit ctx : Context ) = {
861
890
val arity = functionArity(tp)
862
891
val sym = tp.dealias.typeSymbol
863
- arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType (arity, sym.name.isImplicitFunction).typeSymbol)
892
+ def top =
893
+ if (! sym.owner.derivesFrom(defn.PhantomClass )) defn.AnyType
894
+ else sym.owner.thisType.select(tpnme.Any )
895
+ def funType = FunctionType (arity, sym.name.isImplicitFunction, top)
896
+ arity >= 0 && isFunctionClass(sym) && tp.isRef(funType.typeSymbol)
864
897
}
865
898
866
899
def functionArity (tp : Type )(implicit ctx : Context ) = tp.dealias.argInfos.length - 1
@@ -975,12 +1008,27 @@ class Definitions {
975
1008
// ----- Phantoms ---------------------------------------------------------
976
1009
977
1010
lazy val PhantomClass : ClassSymbol = {
978
- val cls = completeClass(enterCompleteClassSymbol(ScalaPackageClass , tpnme.Phantom , NoInitsTrait , List (AnyType )))
1011
+ val clsScope = newScope.openForMutations
1012
+ val cls = completeClass(enterCompleteClassSymbol(ScalaPackageClass , tpnme.Phantom , NoInitsTrait , List (AnyType ), clsScope))
979
1013
980
1014
val any = enterCompleteClassSymbol(cls, tpnme.Any , Protected | Final | NoInitsTrait , Nil )
981
1015
val nothing = enterCompleteClassSymbol(cls, tpnme.Nothing , Protected | Final | NoInitsTrait , List (any.typeRef))
982
1016
enterMethod(cls, nme.assume_, MethodType (Nil , nothing.typeRef), Protected | Final | Method )
983
1017
1018
+ clsScope.useSynthesizer { name => ctx =>
1019
+ if (name.isTypeName && name.isFunction) newFunctionNTrait(name.asTypeName, cls)
1020
+ else NoSymbol
1021
+ }
1022
+
1023
+ if (config.Config .useFingerPrints) {
1024
+ // FIXME: this should not be required, must create them early to make sure they are
1025
+ // found in the members of objects extending scala.Phantom
1026
+ for (i <- 1 to MaxImplementedFunctionArity ) {
1027
+ clsScope.lookup((str.Function + i).toTypeName)
1028
+ clsScope.lookup((str.ImplicitFunction + i).toTypeName)
1029
+ }
1030
+ }
1031
+
984
1032
cls
985
1033
}
986
1034
lazy val Phantom_AnyClass = PhantomClass .unforcedDecls.find(_.name eq tpnme.Any ).asClass
@@ -990,4 +1038,16 @@ class Definitions {
990
1038
/** If the symbol is of the class scala.Phantom.Any or scala.Phantom.Nothing */
991
1039
def isPhantomTerminalClass (sym : Symbol ) = (sym eq Phantom_AnyClass ) || (sym eq Phantom_NothingClass )
992
1040
1041
+ /** Ensure that `tp2`' is in the same universe as `tp1`. If that's the case, return
1042
+ * `op` applied to both types.
1043
+ * If not, issue an error and return `tp1`'.
1044
+ */
1045
+ def inSameUniverse (op : (Type , Type ) => Type , tp1 : Type , tp2 : Type , relationship : => String , pos : Position )(implicit ctx : Context ): Type =
1046
+ if (tp1.topType == tp2.topType)
1047
+ op(tp1, tp2)
1048
+ else {
1049
+ ctx.error(ex " $tp1 and $tp2 are in different universes. They cannot be combined in $relationship" , pos)
1050
+ tp1
1051
+ }
1052
+
993
1053
}
0 commit comments