Skip to content
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

Add reflect Symbol.info and ClassInfo #11664

Closed
wants to merge 2 commits into from

Conversation

nicolasstucki
Copy link
Contributor

Also fix TypeReprStructure printer for Binder to avoid cycles and remove workaround in TypeLambda.

Fixes #11657

trait ClassInfoMethods:
extension (self: ClassInfo)
/** The prefix on which parents, decls, and selfType need to be rebased. */
def prefix: TypeRepr
Copy link
Contributor

Choose a reason for hiding this comment

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

Is prefix here a different thing from qualifier in TypeRef?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is a similar qualification. We have used qualifier in all the cases of the API, I will do the same here to be homogeneous. There is a similar case with NamedType.

Copy link
Contributor

Choose a reason for hiding this comment

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

@nicolasstucki Right, although I wonder if it's not too late to name it prefix everywhere instead of qualifier, for consistency with Scala 2 and previous literature

Also fix TypeReprStructure printer for Binder to avoid cycles and remove workaround in TypeLambda.

Fixes scala#11657
extension (self: ClassInfo)
def qualifier: TypeRepr = self.prefix
def decls: List[Symbol] = self.decls.toList
def declaredParents: List[TypeRepr] = self.declaredParents
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But then we would have to always go to the tree which is the thing we are trying to avoid.

Copy link
Member

Choose a reason for hiding this comment

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

But then we would have to always go to the tree

No, we should expose Type#parents which doesn't involve trees.

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

this += "TypeLambda(" ++= argNames += ", " ++= argBounds += ", _)"
this += "TypeLambda(" ++= argNames += ", " ++= argBounds += ", " += resType += ")"
case ClassInfo(prefix, cls, parents, decls, selfInfo) =>
this += "ClassInfo(" += prefix += ", cls/*" += cls.fullName += "*/, " ++= parents += ", decls, " += selfInfo += ")"
Copy link
Contributor

Choose a reason for hiding this comment

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

Is cls added by accident?

Suggested change
this += "ClassInfo(" += prefix += ", cls/*" += cls.fullName += "*/, " ++= parents += ", decls, " += selfInfo += ")"
this += "ClassInfo(" += prefix += ", /*" += cls.fullName += "*/, " ++= parents += ", decls, " += selfInfo += ")"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, we want to generate something like ClassInfo(X, cls /*...*/, ..., ...). If we remove the cls it would not parse as valid scala code. The comment is there to hint at what is in that parameter but there is no structure to it.

@@ -3437,6 +3472,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
trait SymbolMethods {
extension (self: Symbol)

/** TypeRepr of the definitions of this symbol */
def info: TypeRepr

Copy link
Contributor

Choose a reason for hiding this comment

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

If we expose info on symbols, logically we need to expose Type.asSeenFrom as well to rebase the prefix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a document here saying

Warning: you may need to perform asSeenFrom in case Symbol.info contains parameterized types, such as class type parameter, types depend on this, etc.

For example, if the owner of the current symbol is a class, using the following code to rebase the type:

symbol.info.asSeenFrom(prefix, symbol.owner)

What about a method like symbol.infoAsSeenFrom(prefix)?

extension (self: ClassInfo)
def qualifier: TypeRepr = self.prefix
def decls: List[Symbol] = self.decls.toList
def declaredParents: List[TypeRepr] = self.declaredParents
Copy link
Member

Choose a reason for hiding this comment

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

But then we would have to always go to the tree

No, we should expose Type#parents which doesn't involve trees.

@@ -1695,6 +1695,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
dotc.core.Types.decorateTypeApplications(self).appliedTo(targ)
def appliedTo(targs: List[TypeRepr]): TypeRepr =
dotc.core.Types.decorateTypeApplications(self).appliedTo(targs)
def asSeenFrom(pre: TypeRepr, clazz: Symbol): TypeRepr =
self.asSeenFrom(pre, clazz)
Copy link
Member

Choose a reason for hiding this comment

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

We already expose memberInfo which calls asSeenFrom, in what situation would you need the raw asSeenFrom?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

If we expose symbol.info, without asSeenFrom, the info cannot be safely used.

Copy link
Member

Choose a reason for hiding this comment

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

symbol.info is the info of the symbol itself, I don't see what's unsafe about it, and if you want to see the info from some specific prefix you can do prefix.memberType(symbol). Are there situations where you need to use asSeenFrom directly instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

symbol.info is the info of the symbol itself, I don't see what's unsafe about it, if you want to see the info from some specific prefix you can do prefix.memberType(symbol). Are there situations where you need to use asSeenFrom directly instead?

The concern is that users use symbol.info without rebasing, resulting in error-prone macros. I see that we already have TypeEpr.memberType, thus we don't need asSeenFrom. However, it is good to add the following doc to Symbol.info:

Warning: Symbol.info may contain parameterized types, such as class type parameter, types that depend on this, etc. The method call prefix.memberType(symbol) can be used to get the concrete type of the symbol relative to a prefix.

@nicolasstucki
Copy link
Contributor Author

The point of this was to make the API simpler to use, but by using info everything gets more complex.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Symbol.info to Quotes.reflect
5 participants