Skip to content

Make quoted.Type fully contextual #10207

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

Conversation

nicolasstucki
Copy link
Contributor

Type is designed to be a contextual value. As such we should be able to use it without needing to name it and use it explicitly. Now that quoted pattterns provide the name of the type we can do this.

  • Replaced methods show/showAnsiColored by equivalent methods in object Type
  • Remove unseal, it can be replaced directly with TypeRepr.of in most cases

Migration

  • Type[T].show -> Type.show[T]
  • Type[T].unseal.tpe -> TypeRepr.of[T]
  • Type[T].unseal -> TypeTree.of[T]

@nicolasstucki nicolasstucki self-assigned this Nov 6, 2020
@nicolasstucki nicolasstucki force-pushed the make-quoted-type-api-fully-contextual branch 4 times, most recently from 839901d to 8691aae Compare November 7, 2020 15:24
object TypeTree extends TypeTreeModule
object TypeTree extends TypeTreeModule:
def of[T <: AnyKind](using tp: scala.quoted.Type[T]): TypeTree =
tp.asInstanceOf[scala.internal.quoted.Type[TypeTree]].typeTree
Copy link
Member

Choose a reason for hiding this comment

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

Why is that cast needed?

Copy link
Member

Choose a reason for hiding this comment

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

More precisely, why is it Type[TypeTree] and not Type[T]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because it is the scala.internal.quoted.Type and not scala.quoted.Type. That variant is parametrised with the tree type to make it easier to cast and extract internally.

@nicolasstucki nicolasstucki marked this pull request as ready for review November 8, 2020 09:03
@nicolasstucki nicolasstucki removed their assignment Nov 8, 2020
@@ -5,8 +5,6 @@ import scala.annotation.compileTimeOnly
abstract class Type[T <: AnyKind] private[scala]:
type Underlying = T

def unseal(using qctx: QuoteContext): qctx.reflect.TypeTree
Copy link
Contributor

Choose a reason for hiding this comment

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

From the tests, it seems this method is more convenient and shorter than the proposed alternative. Conceptually, it also helps reinforce the boundary between the safer quoted world and the unsafe reflect world. In addition, the method is also symmetric to the Expr[T] variant, which is good for usability.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea is that the Type API should be symmetric with the Type/TypeRepr/TypeTree. As Type does not share the level symmetry of Expr, Type should not try to have an API that reflects the level symmetry as Expr does. Usability wise, this symmetry between the APIs has been the source of confusion of what and how Type works.

The most common use case is to inspect the type for which Type[A].unseal.tpe becomes TypeRepr.of[T] which is shorter and much clearer as it states exactly what we want to get for this T.

There are some tests that used to give a name to the Type[T] and then call t.unseal.tpe which was slightly shorter at the cost of a summon[Type[T]] or using [T](using t: Type[T]) instead of [T: Type] which made code larger before the .unseal call.

Another classical mistake is to start with [T](...)(t: Type[T]) and call t.unseal.tpe and then realize that somewhere else it is needed implicitly and modify the signature to [T: Type](....)(t: Type[T]).

Copy link
Contributor

Choose a reason for hiding this comment

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

I see in #10232 Type.seal is changed to asType, which is consistent with the asymmetry you mentioned above. I think it's fine as long as the whole design is consistent.

One ergonomics issue (might just be personal preference) is that I find dot-style API (tp.unseal.tpe) is more friendly than bureaucratic-style API (TypeRepr.of(tp)). However, I do see the consistency of the overall APIs is more important. So feel free to choose the one that makes more sense overall.

Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

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

LGTM

Type is designed to be a contextual value. As such we should be able to use it without needing to name it and use it explicitly. Now that quoted pattterns provide the name of the type we can do this.

* Replaced methods `show`/`showAnsiColored` by equivalent methods in `object Type`
* Remove `unseal`, it can be replaced directly with `TypeRepr.of` in most cases

__Migration__

* `Type[T].show` -> `Type.show[T]`
* `Type[T].unseal.tpe` -> `TypeRepr.of[T]`
* `Type[T].unseal` -> `TypeTree.of[T]`
@nicolasstucki nicolasstucki force-pushed the make-quoted-type-api-fully-contextual branch from 8691aae to 4d33dbf Compare November 9, 2020 08:59
@nicolasstucki
Copy link
Contributor Author

Rebased and resolved a trivial conflict

@nicolasstucki nicolasstucki merged commit cda0338 into scala:master Nov 9, 2020
@nicolasstucki nicolasstucki deleted the make-quoted-type-api-fully-contextual branch November 9, 2020 12:10
@Kordyjan Kordyjan added this to the 3.0.0 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants