Skip to content

Homogenize Reflect Type constructors #9744

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1128,7 +1128,7 @@ class ReflectionCompilerInterface(val rootContext: Context) extends CompilerInte
case _ => None
}

def Type_apply(clazz: Class[?])(using Context): Type =
def Type_ofClass(clazz: Class[?])(using Context): Type =
if (clazz.isPrimitive)
if (clazz == classOf[Boolean]) defn.BooleanType
else if (clazz == classOf[Byte]) defn.ByteType
Expand All @@ -1140,10 +1140,10 @@ class ReflectionCompilerInterface(val rootContext: Context) extends CompilerInte
else if (clazz == classOf[Double]) defn.DoubleType
else defn.UnitType
else if (clazz.isArray)
defn.ArrayType.appliedTo(Type_apply(clazz.getComponentType))
defn.ArrayType.appliedTo(Type_ofClass(clazz.getComponentType))
else if (clazz.isMemberClass) {
val name = clazz.getSimpleName.toTypeName
val enclosing = Type_apply(clazz.getEnclosingClass)
val enclosing = Type_ofClass(clazz.getEnclosingClass)
if (enclosing.member(name).exists) enclosing.select(name)
else
enclosing.classSymbol.companionModule.termRef.select(name)
Expand Down
14 changes: 7 additions & 7 deletions library/src-bootstrapped/dotty/internal/StringContextMacro.scala
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,9 @@ object StringContextMacro {
*/
def checkTypeWithArgs(argument : (Type, Int), conversionChar : Char, partIndex : Int, flags : List[(Char, Int)]) = {
val booleans = List(defn.BooleanType, defn.NullType)
val dates = List(defn.LongType, typeOf[java.util.Calendar], typeOf[java.util.Date])
val floatingPoints = List(defn.DoubleType, defn.FloatType, typeOf[java.math.BigDecimal])
val integral = List(defn.IntType, defn.LongType, defn.ShortType, defn.ByteType, typeOf[java.math.BigInteger])
val dates = List(defn.LongType, Type.ofClass[java.util.Calendar], Type.ofClass[java.util.Date])
val floatingPoints = List(defn.DoubleType, defn.FloatType, Type.ofClass[java.math.BigDecimal])
val integral = List(defn.IntType, defn.LongType, defn.ShortType, defn.ByteType, Type.ofClass[java.math.BigInteger])
val character = List(defn.CharType, defn.ByteType, defn.ShortType, defn.IntType)

val (argType, argIndex) = argument
Expand All @@ -597,9 +597,9 @@ object StringContextMacro {
case 'd' | 'o' | 'x' | 'X' => {
checkSubtype(argType, "Int", argIndex, integral : _*)
if (conversionChar != 'd') {
val notAllowedFlagOnCondition = List(('+', !(argType <:< typeOf[java.math.BigInteger]), "only use '+' for BigInt conversions to o, x, X"),
(' ', !(argType <:< typeOf[java.math.BigInteger]), "only use ' ' for BigInt conversions to o, x, X"),
('(', !(argType <:< typeOf[java.math.BigInteger]), "only use '(' for BigInt conversions to o, x, X"),
val notAllowedFlagOnCondition = List(('+', !(argType <:< Type.ofClass[java.math.BigInteger]), "only use '+' for BigInt conversions to o, x, X"),
(' ', !(argType <:< Type.ofClass[java.math.BigInteger]), "only use ' ' for BigInt conversions to o, x, X"),
('(', !(argType <:< Type.ofClass[java.math.BigInteger]), "only use '(' for BigInt conversions to o, x, X"),
(',', true, "',' only allowed for d conversion of integral types"))
checkFlags(partIndex, flags, notAllowedFlagOnCondition : _*)
}
Expand All @@ -608,7 +608,7 @@ object StringContextMacro {
case 't' | 'T' => checkSubtype(argType, "Date", argIndex, dates : _*)
case 'b' | 'B' => checkSubtype(argType, "Boolean", argIndex, booleans : _*)
case 'h' | 'H' | 'S' | 's' =>
if (!(argType <:< typeOf[java.util.Formattable]))
if (!(argType <:< Type.ofClass[java.util.Formattable]))
for {flag <- flags ; if (flag._1 == '#')}
reporter.argError("type mismatch;\n found : " + argType.widen.show.stripPrefix("scala.Predef.").stripPrefix("java.lang.").stripPrefix("scala.") + "\n required: java.util.Formattable", argIndex)
case 'n' | '%' =>
Expand Down
2 changes: 1 addition & 1 deletion library/src-bootstrapped/scala/quoted/Liftable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ object Liftable {
given ClassLiftable[T] as Liftable[Class[T]] = new Liftable[Class[T]] {
def toExpr(x: Class[T]) = qctx ?=> {
import qctx.tasty._
Ref(defn.Predef_classOf).appliedToType(Type(x)).seal.asInstanceOf[Expr[Class[T]]]
Ref(defn.Predef_classOf).appliedToType(Type.ofClass(using ClassTag(x))).seal.asInstanceOf[Expr[Class[T]]]
}
}

Expand Down
2 changes: 1 addition & 1 deletion library/src-bootstrapped/scala/quoted/util/ExprMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ trait ExprMap {
case Typed(expr, tpt) =>
val tp = tpt.tpe match
case AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "<repeated>"), List(tp0: Type)) =>
Type(classOf[Seq[_]]).appliedTo(tp0)
Type.ofClass[Seq[_]].appliedTo(tp0)
case tp => tp
Typed.copy(tree)(transformTerm(expr, tp), transformTypeTree(tpt))
case tree: NamedArg =>
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/internal/tasty/CompilerInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ trait CompilerInterface extends scala.tasty.reflect.Types {

def Type_TypeTest(using ctx: Context): TypeTest[Type, Type]

def Type_apply(clazz: Class[_])(using ctx: Context): Type
def Type_ofClass(clazz: Class[_])(using ctx: Context): Type

/** Is `self` type the same as `that` type?
* This is the case iff `Type_isSubType(self, that)` and `Type_isSubType(that, self)`.
Expand Down
24 changes: 10 additions & 14 deletions library/src/scala/tasty/Reflection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1336,20 +1336,20 @@ trait Reflection extends reflect.Types { reflectSelf: CompilerInterface =>
// TYPES //
///////////////

/** Returns the type (Type) of T */
def typeOf[T](using qtype: scala.quoted.Type[T], ctx: Context): Type =
qtype.asInstanceOf[scala.internal.quoted.Type[T]].typeTree.asInstanceOf[TypeTree].tpe


// ----- Types ----------------------------------------------------

given (using ctx: Context) as TypeTest[Type, Type] = reflectSelf.Type_TypeTest
given TypeOps as Type.type = Type

object Type:

def apply(clazz: Class[_])(using ctx: Context): Type =
reflectSelf.Type_apply(clazz)
/** Returns the type or kind (Type) of T */
def of[T <: AnyKind](using qtype: scala.quoted.Type[T], ctx: Context): Type =
qtype.asInstanceOf[scala.internal.quoted.Type[TypeTree]].typeTree.tpe

/** Returns the type or kind of the class of the type T */
def ofClass[T](using ct: scala.reflect.ClassTag[T]): Type =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existence of both Type.of and Type.ofClass can cause confusion. What about change Type.of to Type.apply. We can also change return type of Type.of to Type[T]:

def apply[T <: AnyKind](using qtype: scala.quoted.Type[T]): Type[T] = qtype

// usage
Type[T]

I see in the test code we write Type.of[T].seal in many places. Without the change above, it's simpler.

Then we can rename Type.ofClass to Type.of.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can Type.of subsumes all usage of Type.ofClass?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not notice the Type.of[T].seal. That is just bad code, they should be replaced with '[T] unless that are tests on the seal operation. I will check all those occurrences.

Type.of does subsume most cases of Type.ofClass. The only case it does not is if you get a Class[_] at runtime and want to recover the Type from it. The second is also slightly more performant.

The apply is not good because it leads to easy mistakes as quoted.Type[T] and Reflect.Type[T] dot not return the same thing. Knowing that you need to use Type.of helps users find the correct version and autocompletion may help to find the other variants that are more specific/performant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually Type.of[T].seal is equivalent to '[T].asInstanceOf[Type[?]] which is relly bad code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see 2 tests files with Type.of[T].seal where we explicitly test the seal operation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it takes an explicit argument no one will use it as they would have to write much more code for something that they should be encouraged to do. Type.ofClass[Foo] would become Type.ofClass(classOf[Foo]). Additionally, that would introduce extra redundancy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This concept is in the middle between Type.of and classOf and it makes sense to have a name that intuitively makes allusion to both those concepts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I have exhausted my arguments ;)
I'm happy to hear what others think about it.
I'm open to any agreed decision in order to move on.

/cc: @anatoliykmetyuk @bishabosha

Copy link
Member

@bishabosha bishabosha Sep 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind the name but I am not sure what the benefit is except to conveniently have an unapplied polymorphic type (when generating ClassTag still requires a statically known type)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is unfortunately unavoidable for any ClassTag or classOf.

reflectSelf.Type_ofClass(ct.runtimeClass)

extension (self: Type):

Expand Down Expand Up @@ -1626,13 +1626,9 @@ trait Reflection extends reflect.Types { reflectSelf: CompilerInterface =>
end MatchType


/**
* An accessor for `scala.internal.MatchCase[_,_]`, the representation of a `MatchType` case.
*/
def MatchCaseType(using ctx: Context): Type = {
import scala.internal.MatchCase
Type(classOf[MatchCase[_,_]])
}
/** An accessor for `scala.internal.MatchCase[_,_]`, the representation of a `MatchType` case. */
def MatchCaseType(using ctx: Context): Type =
Type.ofClass[scala.internal.MatchCase[_,_]]

given (using ctx: Context) as TypeTest[Type, ByNameType] = reflectSelf.ByNameType_TypeTest
given ByNameTypeOps as ByNameType.type = ByNameType
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/tasty/reflect/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ trait Types {
/** Pattern representing `X | Y | ...` alternatives. */
type Alternatives <: Tree

/** A type */
/** A type, kind, type bounds or NoPrefix */
type Type

/** A singleton type representing a known constant value */
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/i7919.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ object Test {
import qctx.tasty._
given typeT as quoted.Type[T] // error
val tTypeTree = typeT.unseal
val tt = typeOf[T]
val tt = Type.of[T]
'{ "in staged" }
}

Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/i8871.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import scala.quoted._
object Macro {
def impl[A : Type](using qctx: QuoteContext): Unit = {
import qctx.tasty._
val tpe = typeOf[A].seal.asInstanceOf[quoted.Type[_ <: AnyRef]]
val tpe = Type.of[A].seal.asInstanceOf[quoted.Type[_ <: AnyRef]]
'{ (a: ${tpe}) => ???} // error
}
}
2 changes: 1 addition & 1 deletion tests/neg-macros/i8871b.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import scala.quoted._
object Macro {
def impl[A : Type](using qctx: QuoteContext): Unit = {
import qctx.tasty._
val tpe/*: quoted.Type[? <: AnyKind]*/ = typeOf[A].seal
val tpe/*: quoted.Type[? <: AnyKind]*/ = Type.of[A].seal
'{ f[$tpe] } // error
}
def f[T <: AnyKind]: Unit = ()
Expand Down
2 changes: 1 addition & 1 deletion tests/pos-macros/i8879/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Test {
import qctx.tasty._
import util._

val foo = typeOf[Foo[String]]
val foo = Type.of[Foo[String]]
val symbol = foo.typeSymbol.field("a")
val a = foo.select(symbol)
assert(a <:< defn.StringType)
Expand Down
2 changes: 1 addition & 1 deletion tests/pos-macros/i9240/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ inline def diveInto[T]: String = ${ diveIntoImpl[T]() }

def diveIntoImpl[T]()(implicit qctx: QuoteContext, ttype: scala.quoted.Type[T]): Expr[String] =
import qctx.tasty._
Expr( unwindType(qctx.tasty)(typeOf[T]) )
Expr( unwindType(qctx.tasty)(Type.of[T]) )

def unwindType(reflect: Reflection)(aType: reflect.Type): String =
import reflect._
Expand Down
2 changes: 1 addition & 1 deletion tests/pos-macros/i9518/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def shiftTerm(using QuoteContext): Expr[Unit] = {
val tp2 = '[([X] =>> CB[X])[Int]].unseal.tpe
val ta = '[[X] =>> CB[X]]
val tp3 = '[ta.T[Int]].unseal.tpe
val tp4 = '[CB].unseal.tpe.appliedTo(typeOf[Int])
val tp4 = '[CB].unseal.tpe.appliedTo(Type.of[Int])
assert(nTree.tpe <:< tp1)
assert(nTree.tpe <:< tp2)
assert(nTree.tpe <:< tp3)
Expand Down
6 changes: 3 additions & 3 deletions tests/run-macros/i5941/macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ object Iso {
import qctx.tasty._
import util._

val tpS = typeOf[S]
val tpA = typeOf[A]
val tpS = Type.of[S]
val tpA = Type.of[A]

// 1. S must be a case class
// 2. A must be a tuple
Expand Down Expand Up @@ -127,7 +127,7 @@ object Iso {
import qctx.tasty._
import util._

val tpS = typeOf[S]
val tpS = Type.of[S]

if (tpS.isSingleton) {
val ident = Ident(tpS.asInstanceOf[TermRef]).seal.cast[S]
Expand Down
2 changes: 1 addition & 1 deletion tests/run-macros/i6518/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object Macros {

private def testImpl(using qctx: QuoteContext) : Expr[String] = {
import qctx.tasty._
val classSym = typeOf[Function1[_, _]].classSymbol.get
val classSym = Type.ofClass[Function1[_, _]].classSymbol.get
classSym.classMethod("apply")
classSym.classMethods
classSym.method("apply")
Expand Down
18 changes: 9 additions & 9 deletions tests/run-macros/tasty-construct-types/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,28 @@ object Macros {

val x1T = ConstantType(Constant(1))
val x2T = OrType(ConstantType(Constant(1)), ConstantType(Constant(2)))
val x3T = AndType(ConstantType(Constant(3)), typeOf[Any])
val x3T = AndType(ConstantType(Constant(3)), Type.of[Any])
val x4T =
TypeLambda(
List("A","B"),
_ => List(TypeBounds(typeOf[Nothing], typeOf[Any]), TypeBounds(typeOf[Nothing], typeOf[Any])),
_ => List(TypeBounds(Type.of[Nothing], Type.of[Any]), TypeBounds(Type.of[Nothing], Type.of[Any])),
(tl : TypeLambda) => tl.param(1))
val x5T =
Refinement(
typeOf[RefineMe],
Type.of[RefineMe],
"T",
TypeBounds(typeOf[Int], typeOf[Int]))
val x6T = Type(classOf[List[_]]).appliedTo(List(typeOf[Int]))
TypeBounds(Type.of[Int], Type.of[Int]))
val x6T = Type.ofClass[List[_]].appliedTo(List(Type.of[Int]))
val x7T = AnnotatedType(ConstantType(Constant(7)), '{ new TestAnnotation }.unseal)
val x8T =
MatchType(
typeOf[Int],
typeOf[List[8]],
Type.of[Int],
Type.of[List[8]],
List(
TypeLambda(
List("t"),
_ => List(TypeBounds(typeOf[Nothing], typeOf[Any])),
tl => MatchCaseType.appliedTo(List(Type(classOf[List[_]]).appliedTo(tl.param(0)), tl.param(0)))))
_ => List(TypeBounds(Type.of[Nothing], Type.of[Any])),
tl => MatchCaseType.appliedTo(List(Type.ofClass[List[_]].appliedTo(tl.param(0)), tl.param(0)))))
)

assert(x1T =:= '[1].unseal.tpe)
Expand Down
32 changes: 16 additions & 16 deletions tests/run-macros/tasty-create-method-symbol/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ object Macros {
Symbol.currentOwner,
"sym1",
MethodType(List("a","b"))(
_ => List(typeOf[Int], typeOf[Int]),
_ => typeOf[Int]))
_ => List(Type.of[Int], Type.of[Int]),
_ => Type.of[Int]))
assert(sym1.isDefDef)
assert(sym1.name == "sym1")
val sym1Statements : List[Statement] = List(
Expand All @@ -29,7 +29,7 @@ object Macros {
val sym2 : Symbol = Symbol.newMethod(
Symbol.currentOwner,
"sym2",
ByNameType(typeOf[Int]))
ByNameType(Type.of[Int]))
assert(sym2.isDefDef)
assert(sym2.name == "sym2")
val sym2Statements : List[Statement] = List(
Expand All @@ -46,7 +46,7 @@ object Macros {
Symbol.currentOwner,
"sym3",
MethodType(List("a"))(
_ => List(typeOf[Int]),
_ => List(Type.of[Int]),
mt => MethodType(List("b"))(
_ => List(mt.param(0)),
_ => mt.param(0))))
Expand All @@ -66,8 +66,8 @@ object Macros {
Symbol.currentOwner,
"sym4",
MethodType(List("x"))(
_ => List(typeOf[Int]),
_ => typeOf[Int]))
_ => List(Type.of[Int]),
_ => Type.of[Int]))
assert(sym4.isDefDef)
assert(sym4.name == "sym4")
val sym4Statements : List[Statement] = List(
Expand All @@ -88,8 +88,8 @@ object Macros {
Symbol.currentOwner,
"sym5",
MethodType(List("x"))(
_ => List(typeOf[Int]),
_ => typeOf[Int=>Int]))
_ => List(Type.of[Int]),
_ => Type.of[Int=>Int]))
assert(sym5.isDefDef)
assert(sym5.name == "sym5")
val sym5Statements : List[Statement] = List(
Expand All @@ -101,8 +101,8 @@ object Macros {
sym5,
"sym51",
MethodType(List("x"))(
_ => List(typeOf[Int]),
_ => typeOf[Int]))
_ => List(Type.of[Int]),
_ => Type.of[Int]))
Block(
List(
DefDef(sym51, {
Expand All @@ -122,14 +122,14 @@ object Macros {
Symbol.currentOwner,
"sym6_1",
MethodType(List("x"))(
_ => List(typeOf[Int]),
_ => typeOf[Int]))
_ => List(Type.of[Int]),
_ => Type.of[Int]))
val sym6_2 : Symbol = Symbol.newMethod(
Symbol.currentOwner,
"sym6_2",
MethodType(List("x"))(
_ => List(typeOf[Int]),
_ => typeOf[Int]))
_ => List(Type.of[Int]),
_ => Type.of[Int]))
assert(sym6_1.isDefDef)
assert(sym6_2.isDefDef)
assert(sym6_1.name == "sym6_1")
Expand Down Expand Up @@ -169,7 +169,7 @@ object Macros {
Symbol.currentOwner,
"sym7",
PolyType(List("T"))(
tp => List(TypeBounds(typeOf[Nothing], typeOf[Any])),
tp => List(TypeBounds(Type.of[Nothing], Type.of[Any])),
tp => MethodType(List("t"))(
_ => List(tp.param(0)),
_ => tp.param(0))))
Expand All @@ -182,7 +182,7 @@ object Macros {
Some(Typed(x, Inferred(t)))
}
}),
'{ assert(${ Apply(TypeApply(Ref(sym7), List(Inferred(typeOf[Int]))), List(Literal(Constant(7)))).seal.asInstanceOf[Expr[Int]] } == 7) }.unseal)
'{ assert(${ Apply(TypeApply(Ref(sym7), List(Inferred(Type.of[Int]))), List(Literal(Constant(7)))).seal.asInstanceOf[Expr[Int]] } == 7) }.unseal)

Block(
sym1Statements ++
Expand Down
2 changes: 1 addition & 1 deletion tests/run-macros/tasty-simplified/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ object Macros {
loop(tp, Nil).reverse
}

val tps = unpackTuple(typeOf[T])
val tps = unpackTuple(Type.of[T])
Varargs(tps.map(x => Expr(x.show)))
}
}
Loading