Skip to content

Commit 8b4f389

Browse files
authored
Merge branch 'main' into wunused-disable-for-public-defs
2 parents 14dd04b + af8790c commit 8b4f389

File tree

12 files changed

+128
-33
lines changed

12 files changed

+128
-33
lines changed

compiler/src/dotty/tools/dotc/staging/CrossStageSafety.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class CrossStageSafety extends TreeMapWithStages {
6060
val healedType = healType(tree.srcPos)(tp1)
6161
if healedType == tree.tpe then tree
6262
else TypeTree(healedType).withSpan(tree.span)
63-
case _: RefTree if tree.isType =>
63+
case _: RefTree | _: SingletonTypeTree if tree.isType =>
6464
val healedType = healType(tree.srcPos)(tree.tpe)
6565
if healedType == tree.tpe then tree
6666
else TypeTree(healedType).withSpan(tree.span)

compiler/src/dotty/tools/dotc/transform/CheckUnused.scala

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import dotty.tools.dotc.core.Annotations
2424
import dotty.tools.dotc.core.Definitions
2525
import dotty.tools.dotc.core.NameKinds.WildcardParamName
2626
import dotty.tools.dotc.core.Symbols.Symbol
27-
27+
import dotty.tools.dotc.core.StdNames.nme
2828

2929

3030
/**
@@ -109,6 +109,9 @@ class CheckUnused extends MiniPhase:
109109
traverseAnnotations(tree.symbol)
110110
if !tree.symbol.is(Module) then
111111
ud.registerDef(tree)
112+
if tree.name.mangledString.startsWith(nme.derived.mangledString + "$")
113+
&& tree.typeOpt != NoType then
114+
ud.registerUsed(tree.typeOpt.typeSymbol, None, true)
112115
ud.addIgnoredUsage(tree.symbol)
113116
}
114117

@@ -308,7 +311,7 @@ object CheckUnused:
308311
*
309312
* See the `isAccessibleAsIdent` extension method below in the file
310313
*/
311-
private val usedInScope = MutStack(MutSet[(Symbol,Boolean, Option[Name])]())
314+
private val usedInScope = MutStack(MutSet[(Symbol,Boolean, Option[Name], Boolean)]())
312315
private val usedInPosition = MutSet[(SrcPos, Name)]()
313316
/* unused import collected during traversal */
314317
private val unusedImport = MutSet[ImportSelector]()
@@ -353,15 +356,16 @@ object CheckUnused:
353356
* The optional name will be used to target the right import
354357
* as the same element can be imported with different renaming
355358
*/
356-
def registerUsed(sym: Symbol, name: Option[Name])(using Context): Unit =
359+
def registerUsed(sym: Symbol, name: Option[Name], isDerived: Boolean = false)(using Context): Unit =
357360
if !isConstructorOfSynth(sym) && !doNotRegister(sym) then
358361
if sym.isConstructor && sym.exists then
359362
registerUsed(sym.owner, None) // constructor are "implicitly" imported with the class
360363
else
361-
usedInScope.top += ((sym, sym.isAccessibleAsIdent, name))
362-
usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name))
363-
usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name))
364-
name.map(n => usedInPosition += ((sym.sourcePos, n)))
364+
usedInScope.top += ((sym, sym.isAccessibleAsIdent, name, isDerived))
365+
usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name, isDerived))
366+
usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name, isDerived))
367+
if sym.sourcePos.exists then
368+
name.map(n => usedInPosition += ((sym.sourcePos, n)))
365369

366370
/** Register a symbol that should be ignored */
367371
def addIgnoredUsage(sym: Symbol)(using Context): Unit =
@@ -417,15 +421,15 @@ object CheckUnused:
417421
// used symbol in this scope
418422
val used = usedInScope.pop().toSet
419423
// used imports in this scope
420-
val imports = impInScope.pop().toSet
424+
val imports = impInScope.pop()
421425
val kept = used.filterNot { t =>
422-
val (sym, isAccessible, optName) = t
426+
val (sym, isAccessible, optName, isDerived) = t
423427
// keep the symbol for outer scope, if it matches **no** import
424428
// This is the first matching wildcard selector
425429
var selWildCard: Option[ImportSelector] = None
426430

427431
val exists = imports.exists { imp =>
428-
sym.isInImport(imp, isAccessible, optName) match
432+
sym.isInImport(imp, isAccessible, optName, isDerived) match
429433
case None => false
430434
case optSel@Some(sel) if sel.isWildcard =>
431435
if selWildCard.isEmpty then selWildCard = optSel
@@ -479,6 +483,7 @@ object CheckUnused:
479483
if ctx.settings.WunusedHas.explicits then
480484
explicitParamInScope
481485
.filterNot(d => d.symbol.usedDefContains)
486+
.filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name})
482487
.filterNot(d => containsSyntheticSuffix(d.symbol))
483488
.map(d => d.namePos -> WarnTypes.ExplicitParams).toList
484489
else
@@ -596,16 +601,31 @@ object CheckUnused:
596601
}
597602

598603
/** Given an import and accessibility, return an option of selector that match import<->symbol */
599-
private def isInImport(imp: tpd.Import, isAccessible: Boolean, symName: Option[Name])(using Context): Option[ImportSelector] =
604+
private def isInImport(imp: tpd.Import, isAccessible: Boolean, symName: Option[Name], isDerived: Boolean)(using Context): Option[ImportSelector] =
600605
val tpd.Import(qual, sels) = imp
601-
val qualHasSymbol = qual.tpe.member(sym.name).alternatives.map(_.symbol).contains(sym)
606+
val dealiasedSym = dealias(sym)
607+
val simpleSelections = qual.tpe.member(sym.name).alternatives
608+
val typeSelections = sels.flatMap(n => qual.tpe.member(n.name.toTypeName).alternatives)
609+
val termSelections = sels.flatMap(n => qual.tpe.member(n.name.toTermName).alternatives)
610+
val selectionsToDealias = typeSelections ::: termSelections
611+
val qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(dealias).contains(dealiasedSym)
602612
def selector = sels.find(sel => (sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name) && symName.map(n => n.toTermName == sel.rename).getOrElse(true))
613+
def dealiasedSelector = if(isDerived) sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
614+
case (sel, sym) if dealias(sym) == dealiasedSym => sel
615+
}.headOption else None
603616
def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given) == sel.isGiven) || sym.is(Implicit)))
604-
if qualHasSymbol && !isAccessible && sym.exists then
605-
selector.orElse(wildcard) // selector with name or wildcard (or given)
617+
if qualHasSymbol && (!isAccessible || sym.isRenamedSymbol(symName)) && sym.exists then
618+
selector.orElse(dealiasedSelector).orElse(wildcard) // selector with name or wildcard (or given)
606619
else
607620
None
608621

622+
private def isRenamedSymbol(symNameInScope: Option[Name])(using Context) =
623+
sym.name != nme.NO_NAME && symNameInScope.exists(_.toSimpleName != sym.name.toSimpleName)
624+
625+
private def dealias(symbol: Symbol)(using Context): Symbol =
626+
if(symbol.isType && symbol.asType.denot.isAliasType) then
627+
symbol.asType.typeRef.dealias.typeSymbol
628+
else symbol
609629
/** Annotated with @unused */
610630
private def isUnusedAnnot(using Context): Boolean =
611631
sym.annotations.exists(a => a.symbol == ctx.definitions.UnusedAnnot)
@@ -660,7 +680,7 @@ object CheckUnused:
660680

661681
extension (memDef: tpd.MemberDef)
662682
private def isValidMemberDef(using Context): Boolean =
663-
!memDef.symbol.isUnusedAnnot && !memDef.symbol.isAllOf(Flags.AccessorCreationFlags) && !memDef.name.isWildcard
683+
!memDef.symbol.isUnusedAnnot && !memDef.symbol.isAllOf(Flags.AccessorCreationFlags) && !memDef.name.isWildcard && !memDef.symbol.owner.is(Extension)
664684

665685
private def isValidParam(using Context): Boolean =
666686
val sym = memDef.symbol

docs/_docs/reference/changed-features/lazy-vals-init.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ title: Lazy Vals Initialization
44
nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/lazy-vals-init.html
55
---
66

7-
Scala 3 implements [Version 6](https://docs.scala-lang.org/sips/improved-lazy-val-initialization.html#version-6---no-synchronization-on-this-and-concurrent-initialization-of-fields)
8-
of the [SIP-20] improved lazy vals initialization proposal.
7+
Scala 3 implements Version 6 of the [SIP-20] improved lazy vals initialization proposal.
98

109
## Motivation
1110

@@ -77,4 +76,4 @@ recursive lazy vals is undefined (initialization may result in a deadlock).
7776

7877
* [SIP-20]
7978

80-
[SIP-20]: https://docs.scala-lang.org/sips/improved-lazy-val-initialization.html
79+
[SIP-20]: https://github.com/scala/improvement-proposals/pull/19

docs/_docs/reference/metaprogramming/tasty-inspect.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,33 @@ title: "TASTy Inspection"
44
nightlyOf: https://docs.scala-lang.org/scala3/reference/metaprogramming/tasty-inspect.html
55
---
66

7-
```scala
8-
libraryDependencies += "org.scala-lang" %% "scala3-tasty-inspector" % scalaVersion.value
9-
```
10-
117
TASTy files contain the full typed tree of a class including source positions
128
and documentation. This is ideal for tools that analyze or extract semantic
13-
information from the code. To avoid the hassle of working directly with the TASTy
9+
information from the code.
10+
11+
To avoid the hassle of working directly with the TASTy
1412
file we provide the `Inspector` which loads the contents and exposes it
1513
through the TASTy reflect API.
1614

17-
## Inspecting TASTy files
15+
We also showcase TASTyViz, a visualiser for tasty, useful for debugging and checking your understanding of TASTy
16+
17+
## TASTyViz
18+
19+
<!-- Keep synced with https://github.com/scala/docs.scala-lang/blob/main/scala3/guides/tasty-overview.md -->
20+
21+
TASTyViz is a tool to inspect TASTy files visually.
22+
At the time of writing, it is still in the early stages of developement, therefore you can expect missing functionality and less-than-ideal user experience, but it could still prove useful when debugging.
23+
You can check it out [here](https://github.com/shardulc/tastyviz).
24+
25+
## `Inspector`
26+
27+
`Inspector` is a tool which provides API access to TASTy.
28+
29+
You can add the depency to your sbt build like so:
30+
```scala
31+
libraryDependencies += "org.scala-lang" %% "scala3-tasty-inspector" % scalaVersion.value
32+
```
33+
1834

1935
To inspect the trees of a TASTy file a consumer can be defined in the following way.
2036

docs/_docs/reference/new-types/union-types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: "Union Types"
44
nightlyOf: https://docs.scala-lang.org/scala3/reference/new-types/union-types.html
55
---
66

7-
A union type `A | B` has as values all values of type `A` and also all values of type `B`.
7+
A union type `A | B` includes all values of both types.
88

99

1010
```scala

scaladoc/resources/dotty_res/styles/theme/layout/header.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@
6363
align-items: center;
6464
}
6565

66+
.logo-container .project-logo {
67+
max-width: 40px;
68+
}
69+
70+
.logo-container .project-logo img {
71+
max-width: 100%;
72+
}
73+
6674
#mobile-menu-toggle {
6775
display: none;
6876
}

tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class Revaluing(u: Int) { def f = u } // OK
6060

6161
case class CaseyKasem(k: Int) // OK
6262

63-
case class CaseyAtTheBat(k: Int)(s: String) // error
63+
case class CaseyAtTheBat(k: Int)(s: String) // ok
6464

6565
trait Ignorance {
6666
def f(readResolve: Int) = answer // ok

tests/neg-custom-args/fatal-warnings/i15503g.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,11 @@ object Foo {
1313
/* --- Trivial method check --- */
1414
private def g1(x: Int) = 1 // OK
1515
private def g2(x: Int) = ??? // OK
16-
}
16+
}
17+
18+
package foo.test.i17101:
19+
type Test[A] = A
20+
extension[A] (x: Test[A]) { // OK
21+
def value: A = x
22+
def causesIssue: Unit = println("oh no")
23+
}

tests/neg-custom-args/fatal-warnings/i15503i.scala

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ package foo.test.possibleclasses:
9494
k: Int, // OK
9595
private val y: Int // OK /* Kept as it can be taken from pattern */
9696
)(
97-
s: Int, // error /* But not these */
97+
s: Int,
9898
val t: Int, // OK
9999
private val z: Int // error
100100
)
@@ -135,7 +135,7 @@ package foo.test.possibleclasses.withvar:
135135
k: Int, // OK
136136
private var y: Int // OK /* Kept as it can be taken from pattern */
137137
)(
138-
s: Int, // error /* But not these */
138+
s: Int,
139139
var t: Int, // OK
140140
private var z: Int // error
141141
)
@@ -277,3 +277,42 @@ package foo.test.i16679b:
277277
import Foo.x
278278
case class CoolClass(i: Int)
279279
println(summon[myPackage.CaseClassName[CoolClass]])
280+
281+
package foo.test.i17156:
282+
package a:
283+
trait Foo[A]
284+
object Foo:
285+
inline def derived[T]: Foo[T] = new Foo{}
286+
287+
package b:
288+
import a.Foo
289+
type Xd[A] = Foo[A]
290+
291+
package c:
292+
import b.Xd
293+
trait Z derives Xd
294+
295+
296+
package foo.test.i17175:
297+
val continue = true
298+
def foo =
299+
for {
300+
i <- 1.until(10) // OK
301+
if continue
302+
} {
303+
println(i)
304+
}
305+
306+
package foo.test.i17117:
307+
package example {
308+
object test1 {
309+
val test = "test"
310+
}
311+
312+
object test2 {
313+
314+
import example.test1 as t1
315+
316+
val test = t1.test
317+
}
318+
}

tests/neg-macros/i8887.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import scala.quoted._
2+
3+
def expr[X](x: Any)(using Quotes): Expr[Any] =
4+
'{ foo[x.type] } // error
5+
def foo[X]: Any = ???

tests/neg-macros/quote-this-a.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ class Foo {
44

55
def f(using Quotes): Unit = '{
66
def bar[T](x: T): T = x
7-
bar[
8-
this.type // error
9-
] {
7+
bar[this.type] {
108
this // error
119
}
1210
}

tests/pos-macros/i8887.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import scala.quoted._
2+
inline def foo(x: Any): Any = ${ expr[x.type] }
3+
def expr[X](using Quotes): Expr[Any] = ???

0 commit comments

Comments
 (0)