Fixes #25702: Avoid AnyClass fallback in requiredClass#26010
Open
soronpo wants to merge 3 commits into
Open
Conversation
When `requiredClass` lookup didn't resolve to a class (because an intermediate package was missing on the classpath, e.g. a stale `scala3-library` without `scala.caps.internal`), it returned `defn.AnyClass`. Two consequences: - `param.hasAnnotation(missingAnnot)` matched for every annotation (every annotation derives from `Any`), and - the subsequent `Annotation(missingAnnot, span)` -> `tpd.New` crashed with `assertion failed: asTerm called on not-a-Term val <none>` because `AnyClass` has no primary constructor. Return a fresh stub class with the requested name instead. Adds a unit test for the new behavior plus a `neg` regression test guarding the surrounding "missing-method" diagnostic. https://claude.ai/code/session_01YbGL1r2aekT7qSTxtaQ4M8
The previous fix used a stub class as the fallback for *any* non-class
result of `requiredClass`, but that broke `requiredClass("scala.AnyRef")`
and `requiredClass("scala.EmptyTuple")` (and other type aliases): those
paths resolve to a real `TypeSymbol`, and downstream tests
(`tests/run-macros/requiredSymbols`, `i12417`, `i17257`,
`expr-mirror-info`, ...) relied on the historical `defn.AnyClass`
fallback for that case.
Restrict the new stub-class fallback to the case where `staticRef` itself
returns `MissingRef` — i.e. the path doesn't resolve at all. For paths
that resolve to a non-class symbol, keep the original `defn.AnyClass`
fallback. Update the unit test accordingly.
https://claude.ai/code/session_01YbGL1r2aekT7qSTxtaQ4M8
The previous attempts changed `requiredClass` to return a stub class
when the path didn't resolve, but every variant broke a different set
of callers — notably the Java `ClassfileParser` (which forces the
fallback symbol's owner chain in `innerType` and crashes on `NoSymbol`),
and macro tests that rely on `requiredClass("scala.AnyRef")` /
`requiredClass("scala.EmptyTuple")` returning `defn.AnyClass`.
Restore `requiredClass` to its original form and instead guard the
actual crash site: in `Types.MethodTypeCompanion.adaptParamInfo`, skip
the `param.hasAnnotation(cls)` check when `cls eq defn.AnyClass`. That
fallback means the annotation class wasn't found on the classpath; if
we let the check run, it would match every annotation (since they all
derive from `Any`) and then crash in `tpd.New` because `AnyClass` has
no primary constructor.
The unit test added previously asserted the now-reverted `requiredClass`
behaviour, so it's removed; `tests/neg/i25702.scala` keeps the
"missing-method" diagnostic from regressing.
https://claude.ai/code/session_01YbGL1r2aekT7qSTxtaQ4M8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When
requiredClasslookup didn't resolve to a class (because an intermediate package was missing on the classpath, e.g. a stalescala3-librarywithoutscala.caps.internal), it returneddefn.AnyClass. Two consequences:param.hasAnnotation(missingAnnot)matched for every annotation (every annotation derives fromAny), andAnnotation(missingAnnot, span)->tpd.Newcrashed withassertion failed: asTerm called on not-a-Term val <none>becauseAnyClasshas no primary constructor.Return a fresh stub class with the requested name instead. Adds a unit test for the new behavior plus a
negregression test guarding the surrounding "missing-method" diagnostic.Fixes #25702
How much have you relied on LLM-based tools in this contribution?
Extensively, but it's a small fix.
How was the solution tested?
New automated tests (including the issue's reproducer, if applicable)