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

Fix #213: Support refinement types. #259

Merged
merged 13 commits into from
Feb 17, 2023
Merged

Conversation

sjrd
Copy link
Contributor

@sjrd sjrd commented Feb 15, 2023

Some API cleanups first.


Then a bunch of refactorings.


Then we get to the meat:

Member resolution from Type that can handle multiple- or no symbols.

Instead of having Type.findMember which returns an Option[Symbol], we now have a resolveMember method that returns a ResolveMemberResult. A ResolveMemberResult retains all the possible target symbols (that are not overridden by another one), along with the resolved, asSeenFromed type or type bounds. For type members, the list of symbols can be empty.

TypeRef and TermRef now use this method, and rely on the parts of ResolveMemberResult to provide underlying types, type bounds, etc., instead of relying on a unique resolved Symbol.

In this commit, the list of symbols is always non-empty, but it will be possibly empty when we add support for type refinements.


And finally the integration of RefinedTypes:

Fix #213: Support refinement types.

  • Actually create RefinedTypes from RefinedTypeTree.toType.
  • Implement RefinedType.resolveMember to take the refinements into account.

@sjrd sjrd force-pushed the refinement-members branch 7 times, most recently from bec479a to a3bf5a2 Compare February 16, 2023 13:52
@sjrd sjrd marked this pull request as ready for review February 16, 2023 13:59
@sjrd sjrd requested a review from bishabosha February 16, 2023 13:59
Instead of having to through `cls.typeRef`.

We make `Type.member` private. Since later, selecting a member on
a `Type` will not always return a `Symbol` anymore, this method
will not make sense. Users can still construct a `NamedType` out
of a `Type` and `Name` (notably with the `select` methods) and
query information through it.
It was dead code in our codebase, and it is not clear how users
could use it anyway.
@sjrd sjrd force-pushed the refinement-members branch 4 times, most recently from 01e9e48 to 55f2fff Compare February 17, 2023 09:29
TermRefinement(parent, name, tpt.toType)

case DefDef(name, paramClauses, resultType, _, _) =>
TermRefinement(parent, name, ParamsClause.makeDefDefType(paramClauses, resultType))
Copy link
Member

Choose a reason for hiding this comment

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

I believe that this does not distinguish Foo { val x: Int } from Foo { def x: Int }, in the future we may want to add an api here for consumers to tell the difference (e.g. for detecting "caching" opportunities)

It was carried from dotc, but it does not make sense in
tasty-query. All overloads are resolved at the TASTy level, so no
reference can still be overloaded.

This means that `widen` and `widenOverloads` become the same thing.
We merge them as `widen`.
This makes things a bit more type-safe, and declutter `NamedType`.

We also make isArgPrefixOf take a `ClassTypeParamSymbol`, which
further improves type safety for the handling of "arg prefixes".
…ymbols.

The `NamedType.symbol` method is conceptually moved to
`TermRef.symbol`. Instead, we introduce `NamedType.optSymbol`,
and adapt the codebase to be ready to support `TypeRef`s that
do not have an underlying `symbol`.

In this commit, we actually keep `NamedType.symbol` in the API
to separate API changes from the internal refactorings.

We add some more convenience helpers for detecting and dealing
with `TypeRef`s that point to classes. Those will always have a
symbol which is a `ClassSymbol`.

Opaque type aliases will always have a symbol, but other kinds of
type members will not always have one. So when we need to access
bounds, we use dedicated new accessors in `TypeRef`.
So that the "complex" logic is better isolated, and can be reused
more easily once we distribute `computeSymbol()` to `TermRef` and
`TypeRef`.
Only `TermRef.symbol` is still exposed. `TypeRef`s won't always
have a symbol, so `optSymbol` must be used instead.
The common aspects that were remaining did not outweigh the
aspects that were specific to terms v types, and it will get even
worse when we add support for type refinements.
dotc has the same assumption in its unpickler, so this seems safe.

This way, we avoid use `Type.member` to resolve something that
must be a symbol. This will not be possible in the coming commits.
When the prefix of a `NamedType` changes, in some cases we must
re-resolve the symbol, as it can be specialized in a subclass (or
later in a refinement type).

Previously, we did this immediately during
`normalizedDerivedSelect` to get a new symbol. Now, we only
preserve the (signed) name, and delay the re-resolution to when
the produced `NamedType` will need it.

We must preserve the symbol if it is `Private`, since re-resolving
it by name would be incorrect.

This change also removes more uses of `Type.member` to get to a
symbol, which will not be possible with the coming changes.
Instead of having `Type.findMember` which returns an
`Option[Symbol]`, we now have a `resolveMember` method that
returns a `ResolveMemberResult`. A `ResolveMemberResult` retains
all the possible target symbols (that are not overridden by
another one), along with the resolved, `asSeenFrom`ed type or
type bounds. For type members, the list of symbols can be empty.

`TypeRef` and `TermRef` now use this method, and rely on the
parts of `ResolveMemberResult` to provide underlying types, type
bounds, etc., instead of relying on a unique resolved `Symbol`.

In this commit, the list of symbols is always non-empty, but it
will be possibly empty when we add support for type refinements.
* Actually create RefinedTypes from RefinedTypeTree.toType.
* Implement `RefinedType.resolveMember` to take the refinements
  into account.
@sjrd sjrd merged commit d8cb675 into scalacenter:main Feb 17, 2023
@sjrd sjrd deleted the refinement-members branch February 17, 2023 13:47
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.

Support for refinement types
2 participants