@@ -60,14 +60,14 @@ class Definitions {
6060  private  def  enterCompleteClassSymbol (owner : Symbol , name : TypeName , flags : FlagSet , parents : List [TypeRef ], decls : Scope  =  newScope) = 
6161    ctx.newCompleteClassSymbol(owner, name, flags |  Permanent , parents, decls).entered
6262
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 ))
6565
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 )
6868
6969  private  def  enterSyntheticTypeParam (cls : ClassSymbol , paramFlags : FlagSet , scope : MutableScope , suffix : String  =  " T0" = 
70-     enterTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName  |  paramFlags, scope)
70+     enterTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName  |  paramFlags, scope,  TypeBounds .empty )
7171
7272  //  NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only
7373  //  implemented in Dotty and not in Scala 2.
@@ -89,7 +89,7 @@ class Definitions {
8989    newClassSymbol(ScalaPackageClass , name, EmptyFlags , completer).entered
9090  }
9191
92-   /**  The trait FunctionN or  ImplicitFunctionN, for some N 
92+   /**  The trait FunctionN,  ImplicitFunctionN, PhantomFunctionM, ImplicitPhantomFunctionM , for some N 
9393   *  @param   name    The name of the trait to be created 
9494   * 
9595   *  FunctionN traits follow this template: 
@@ -107,30 +107,45 @@ class Definitions {
107107   *      trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object with FunctionN[T0,...,T{N-1}, R] { 
108108   *        def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R 
109109   *      } 
110+    * 
111+    *  PhantomFunctionM traits follow this template: 
112+    * 
113+    *      trait PhantomFunctionM[T0,...T{N-1}, R] extends Object { 
114+    *        def apply($x0: T0, ..., $x{N_1}: T{N-1}): R 
115+    *      } 
116+    * 
117+    *      where M represents the phantomicity of all Ti. 
118+    * 
119+    *  ImplicitPhantomFunctionM traits follow this template: 
120+    * 
121+    *      trait ImplicitPhantomFunctionM[T0,...,T{N-1}, R] extends Object with PhantomFunctionM[T0,...,T{N-1}, R] { 
122+    *        def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R 
123+    *      } 
124+    * 
125+    *      where M represents the phantomicity of all Ti. 
126+    * 
110127   */  
111128  private  def  newFunctionNTrait (name : TypeName ) =  {
112129    val  completer  =  new  LazyType  {
113130      def  complete (denot : SymDenotation )(implicit  ctx : Context ):  Unit  =  {
114131        val  cls  =  denot.asClass.classSymbol
115132        val  decls  =  newScope
116-         val  arity  =  name.functionArity
133+         val  phantomicity  =  name.phantomicity
134+         val  arity  =  phantomicity.arity
117135        val  argParams  = 
118136          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) 
137+             enterTypeParam(cls, name ++  " $T" ++  i.toString, Contravariant , decls, phantomicity.tParamBounds(i)).typeRef 
138+         val  resParam  =  enterTypeParam(cls, name ++  " $R" Covariant , decls, phantomicity.tParamBounds(arity)).typeRef 
121139        val  (methodType, parentTraits) = 
122-           if  (name.startsWith(tpnme. ImplicitFunction ) ) {
123-             val  superTrait  = 
124-                FunctionType (arity) .appliedTo(argParams.map(_.typeRef)  :::  resParam.typeRef  ::  Nil )
125-             (ImplicitMethodType , ctx.normalizeToClassRefs(superTrait  ::  Nil , cls, decls))
140+           if  (name.isImplicitFunction ) {
141+             val  superTrait  =   FunctionType (phantomicity, isImplicit  =   false ) 
142+             val   appliedSuperTrait   =  superTrait .appliedTo(argParams :::  resParam ::  Nil )
143+             (ImplicitMethodType , ctx.normalizeToClassRefs(appliedSuperTrait  ::  Nil , cls, decls))
126144          }
127145          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)
146+ 
147+         decls.enter(newMethod(cls, nme.apply, methodType(argParams, resParam), Deferred ))
148+         denot.info =  ClassInfo (ScalaPackageClass .thisType, cls, ObjectType  ::  parentTraits, decls)
134149      }
135150    }
136151    newClassSymbol(ScalaPackageClass , name, Trait  |  NoInits , completer)
@@ -640,7 +655,7 @@ class Definitions {
640655
641656  object  FunctionOf  {
642657    def  apply (args : List [Type ], resultType : Type , isImplicit : Boolean  =  false )(implicit  ctx : Context ) = 
643-       FunctionType (args.length , isImplicit).appliedTo(args :::  resultType ::  Nil )
658+       FunctionType (Phantomicity ( args  :+  resultType) , isImplicit).appliedTo(args :::  resultType ::  Nil )
644659    def  unapply (ft : Type )(implicit  ctx : Context ) =  {
645660      val  tsym  =  ft.typeSymbol
646661      if  (isFunctionClass(tsym)) {
@@ -698,18 +713,30 @@ class Definitions {
698713  lazy  val  TupleType  =  mkArityArray(" scala.Tuple" MaxTupleArity , 2 )
699714  lazy  val  ProductNType  =  mkArityArray(" scala.Product" MaxTupleArity , 0 )
700715
701-   def  FunctionClass (n : Int , isImplicit : Boolean  =  false )(implicit  ctx : Context ) = 
716+   def  FunctionClass (n : Int , isImplicit : Boolean  =  false )(implicit  ctx : Context ):   Symbol  = 
702717    if  (isImplicit) ctx.requiredClass(" scala.ImplicitFunction" +  n.toString)
703718    else  if  (n <=  MaxImplementedFunctionArity ) FunctionClassPerRun ()(ctx)(n)
704719    else  ctx.requiredClass(" scala.Function" +  n.toString)
705720
721+   def  FunctionClass (phantomicity : Phantomicity , isImplicit : Boolean )(implicit  ctx : Context ):  Symbol  =  {
722+     if  (phantomicity.hasPhantoms) {
723+       val  prefix  =  if  (isImplicit) " scala.ImplicitPhantomFunction" else  " scala.PhantomFunction" 
724+       ctx.requiredClass(prefix +  phantomicity.encodedString)
725+     } else  FunctionClass (phantomicity.arity, isImplicit)
726+   }
727+ 
706728    lazy  val  Function0_applyR  =  ImplementedFunctionType (0 ).symbol.requiredMethodRef(nme.apply)
707729    def  Function0_apply (implicit  ctx : Context ) =  Function0_applyR .symbol
708730
709731  def  FunctionType (n : Int , isImplicit : Boolean  =  false )(implicit  ctx : Context ):  TypeRef  = 
710732    if  (n <=  MaxImplementedFunctionArity  &&  (! isImplicit ||  ctx.erasedTypes)) ImplementedFunctionType (n)
711733    else  FunctionClass (n, isImplicit).typeRef
712734
735+   def  FunctionType (phantomicity : Phantomicity , isImplicit : Boolean )(implicit  ctx : Context ):  TypeRef  =  {
736+     if  (phantomicity.hasPhantoms) FunctionClass (phantomicity, isImplicit).typeRef
737+     else  FunctionType (phantomicity.arity, isImplicit)
738+   }
739+ 
713740  private  lazy  val  TupleTypes :  Set [TypeRef ] =  TupleType .toSet
714741  private  lazy  val  ProductTypes :  Set [TypeRef ] =  ProductNType .toSet
715742
@@ -735,23 +762,37 @@ class Definitions {
735762  /**  Is a function class. 
736763   *   - FunctionN for N >= 0 
737764   *   - ImplicitFunctionN for N >= 0 
765+    *   - PhantomFunctionM for a valid M 
766+    *   - ImplicitPhantomFunctionM for a valid M 
738767   */  
739768  def  isFunctionClass (cls : Symbol ) =  scalaClassName(cls).isFunction
740769
741770  /**  Is an implicit function class. 
742771   *   - ImplicitFunctionN for N >= 0 
772+    *   - ImplicitPhantomFunctionN for a valid M 
743773   */  
744774  def  isImplicitFunctionClass (cls : Symbol ) =  scalaClassName(cls).isImplicitFunction
745775
776+   /**  Is a phantom function class. 
777+     *   - PhantomFunctionM for a valid M 
778+     *   - ImplicitPhantomFunctionM for a valid M 
779+     */  
780+   def  isPhantomFunctionClass (cls : Symbol ) =  scalaClassName(cls).isPhantomFunction
781+ 
746782  /**  Is a class that will be erased to FunctionXXL 
747783   *   - FunctionN for N >= 22 
748784   *   - ImplicitFunctionN for N >= 22 
785+    *   - PhantomFunctionM for N >= 22, where N is the number of non phantoms in M 
786+    *   - ImplicitPhantomFunctionM for N >= 22, where N is the number of non phantoms in M 
749787   */  
750-   def  isXXLFunctionClass (cls : Symbol ) =  scalaClassName(cls).functionArity >  MaxImplementedFunctionArity 
788+   def  isXXLFunctionClass (cls : Symbol ) = 
789+     scalaClassName(cls).phantomicity.erasedArity >  MaxImplementedFunctionArity 
751790
752791  /**  Is a synthetic function class 
753792   *    - FunctionN for N > 22 
754793   *    - ImplicitFunctionN for N >= 0 
794+    *    - PhantomFunctionM for a valid M 
795+    *    - ImplicitPhantomFunctionM for a valid M 
755796   */  
756797  def  isSyntheticFunctionClass (cls : Symbol ) =  scalaClassName(cls).isSyntheticFunction
757798
@@ -760,31 +801,42 @@ class Definitions {
760801  def  isProductClass (cls : Symbol ) =  isVarArityClass(cls, tpnme.Product )
761802
762803  /**  Returns the erased class of the function class `cls` 
763-    *    - FunctionN for N > 22 becomes FunctionXXL 
764804   *    - FunctionN for 22 > N >= 0 remains as FunctionN 
765-    *    - ImplicitFunctionN  for N > 22 becomes FunctionXXL 
805+    *    - FunctionN  for N > 22 becomes FunctionXXL 
766806   *    - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN 
807+    *    - ImplicitFunctionN for N > 22 becomes FunctionXXL 
767808   *    - anything else becomes a NoSymbol 
768809   */  
769810  def  erasedFunctionClass (cls : Symbol ):  Symbol  =  {
770-     val  arity  =  scalaClassName(cls).functionArity
771-     if  (arity >  22 ) defn.FunctionXXLClass 
772-     else  if  (arity >=  0 ) defn.FunctionClass (arity)
773-     else  NoSymbol 
811+     val  phantomicity  =  scalaClassName(cls).phantomicity
812+     if  (! phantomicity.isValid) NoSymbol 
813+     else  if  (phantomicity.erasedArity >  22 ) defn.FunctionXXLClass 
814+     else  defn.FunctionClass (phantomicity.erasedArity)
815+   }
816+ 
817+   /**  Returns the erased class of the function class `cls` 
818+    *    - PhantomFunctionM becomes FunctionN where N is the number of non phantoms in M 
819+    *    - ImplicitPhantomFunctionM becomes ImplicitFunctionN where N is the number of non phantoms in M 
820+    *    - cls otherwise 
821+    */  
822+   def  erasedPhantomsFunctionClass (cls : Symbol ):  Symbol  =  {
823+     val  phantomicity  =  scalaClassName(cls).phantomicity
824+     if  (! phantomicity.isValid) cls
825+     else  defn.FunctionClass (phantomicity.erasedArity, cls.name.isImplicitFunction)
774826  }
775827
776828  /**  Returns the erased type of the function class `cls` 
777-    *    - FunctionN for N > 22 becomes FunctionXXL 
778829   *    - FunctionN for 22 > N >= 0 remains as FunctionN 
779-    *    - ImplicitFunctionN  for N > 22 becomes FunctionXXL 
830+    *    - FunctionN  for N > 22 becomes FunctionXXL 
780831   *    - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN 
832+    *    - ImplicitFunctionN for N > 22 becomes FunctionXXL 
781833   *    - anything else becomes a NoType 
782834   */  
783835  def  erasedFunctionType (cls : Symbol ):  Type  =  {
784-     val  arity  =  scalaClassName(cls).functionArity 
785-     if  (arity  >   22 ) defn. FunctionXXLType 
786-     else  if  (arity  >=   0 ) defn.FunctionType (arity) 
787-     else  NoType 
836+     val  phantomicity  =  scalaClassName(cls).phantomicity 
837+     if  (! phantomicity.isValid)  NoType 
838+     else  if  (phantomicity.erasedArity  >   22 ) defn.FunctionXXLType 
839+     else  defn. FunctionType (phantomicity.erasedArity) 
788840  }
789841
790842  val  predefClassNames :  Set [Name ] = 
@@ -828,7 +880,10 @@ class Definitions {
828880   *  trait gets screwed up. Therefore, it is mandatory that FunctionXXL 
829881   *  is treated as a NoInit trait. 
830882   */  
831-   lazy  val  NoInitClasses  =  NotRuntimeClasses  +  FunctionXXLClass 
883+   private  lazy  val  NoInitClasses  =  NotRuntimeClasses  +  FunctionXXLClass 
884+ 
885+   def  isNoInitClass (cls : Symbol ):  Boolean  = 
886+     cls.is(NoInitsTrait ) ||  NoInitClasses .contains(cls) ||  isFunctionClass(cls)
832887
833888  def  isPolymorphicAfterErasure (sym : Symbol ) = 
834889     (sym eq Any_isInstanceOf ) ||  (sym eq Any_asInstanceOf )
@@ -857,7 +912,7 @@ class Definitions {
857912  def  isFunctionType (tp : Type )(implicit  ctx : Context ) =  {
858913    val  arity  =  functionArity(tp)
859914    val  sym  =  tp.dealias.typeSymbol
860-     arity >=  0  &&  isFunctionClass(sym) &&  tp.isRef(FunctionType (arity , sym.name.isImplicitFunction).typeSymbol)
915+     arity >=  0  &&  isFunctionClass(sym) &&  tp.isRef(FunctionType (sym.name.phantomicity , sym.name.isImplicitFunction).typeSymbol)
861916  }
862917
863918  def  functionArity (tp : Type )(implicit  ctx : Context ) =  tp.dealias.argInfos.length -  1 
@@ -1013,14 +1068,16 @@ class Definitions {
10131068  def  isPhantomAssume (sym : Symbol )(implicit  ctx : Context ):  Boolean  = 
10141069    sym.exists &&  (sym.owner eq PhantomClass ) &&  sym.name ==  nme.assume_
10151070
1016-   def  topOf (tp : Type )(implicit  ctx : Context ):  Type  =  tp.phantomTopClass match  {
1017-     case  top : ClassInfo  =>  top.prefix.select(tpnme.Any )
1018-     case  _ =>  defn.AnyType 
1071+   def  topOf (tp : Type )(implicit  ctx : Context ):  Type  =  {
1072+     val  lattice  =  tp.phantomLatticeClass
1073+     if  (lattice.exists) lattice.select(tpnme.Any )
1074+     else  defn.AnyType 
10191075  }
10201076
1021-   def  bottomOf (tp : Type )(implicit  ctx : Context ):  Type  =  tp.phantomTopClass match  {
1022-     case  top : ClassInfo  =>  top.prefix.select(tpnme.Nothing )
1023-     case  _ =>  defn.NothingType 
1077+   def  bottomOf (tp : Type )(implicit  ctx : Context ):  Type  =  {
1078+     val  lattice  =  tp.phantomLatticeClass
1079+     if  (lattice.exists) lattice.select(tpnme.Nothing )
1080+     else  defn.NothingType 
10241081  }
10251082
10261083  lazy  val  ErasedPhantomClass  =  ctx.requiredClass(" dotty.runtime.ErasedPhantom" 
0 commit comments