Skip to content

Commit 891100e

Browse files
committed
Always traverse Inlined.call in linter
Previously it incorrectly only looked at call after typer, but it must also look at call after inlining, for intermediate expansions which are not directly written by user.
1 parent e8ae44e commit 891100e

File tree

5 files changed

+143
-10
lines changed

5 files changed

+143
-10
lines changed

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,8 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
156156
refInfos.inlined.push(tree.call.srcPos)
157157
ctx
158158
override def transformInlined(tree: Inlined)(using Context): tree.type =
159-
//transformAllDeep(tree.expansion) // traverse expansion with nonempty inlined stack to avoid registering defs
159+
transformAllDeep(tree.call)
160160
val _ = refInfos.inlined.pop()
161-
if !tree.call.isEmpty && phaseMode.eq(PhaseMode.Aggregate) then
162-
transformAllDeep(tree.call)
163161
tree
164162

165163
override def prepareForBind(tree: Bind)(using Context): Context =

tests/warn/i15503a.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ object FooGiven:
3939

4040
val foo = summon[Int]
4141

42+
object SomeGivenImports:
43+
given Int = 0
44+
given String = "foo"
45+
4246
/**
4347
* Import used as type name are considered
4448
* as used.
@@ -69,7 +73,7 @@ object InlineChecks:
6973
object InlinedBar:
7074
import collection.mutable.Set // warn (don't be fooled by inline expansion)
7175
import collection.mutable.Map // warn
72-
val a = InlineFoo.getSet
76+
val a = InlineFoo.getSet // expansion is attributed mutable.Set.apply(1)
7377

7478
object MacroChecks:
7579
object StringInterpol:
@@ -91,12 +95,6 @@ object IgnoreExclusion:
9195
val a = Set(1)
9296
val b = Map(1 -> 2)
9397
def c = Seq(42)
94-
/**
95-
* Some given values for the test
96-
*/
97-
object SomeGivenImports:
98-
given Int = 0
99-
given String = "foo"
10098

10199
/* BEGIN : Check on packages*/
102100
package nestedpackageimport:

tests/warn/i24034/circe.scala

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
2+
// circe.scala
3+
4+
package io.circe
5+
6+
import scala.compiletime.*
7+
import scala.deriving.Mirror
8+
import scala.quoted.*
9+
10+
trait Encoder[A]:
11+
def encode(value: A): String
12+
13+
object Encoder:
14+
trait AsObject[A] extends Encoder[A]
15+
given Encoder[String] = ???
16+
17+
trait Configuration
18+
object Configuration:
19+
val default: Configuration = ???
20+
21+
object Default:
22+
given [A]: Default[A] = ???
23+
trait Default[T]
24+
25+
trait Codec[A] extends Encoder[A]
26+
object Codec:
27+
trait AsObject[A] extends Encoder.AsObject[A]
28+
object AsObject:
29+
inline final def derived[A](using inline A: Mirror.Of[A]): Codec.AsObject[A] =
30+
ConfiguredCodec.derived[A](using Configuration.default)
31+
inline final def derivedConfigured[A](using
32+
inline A: Mirror.Of[A],
33+
inline conf: Configuration
34+
): Codec.AsObject[A] = ConfiguredCodec.derived[A]
35+
36+
trait ConfiguredEncoder[A](using conf: Configuration) extends Encoder.AsObject[A]
37+
trait ConfiguredCodec[A] extends Codec.AsObject[A], ConfiguredEncoder[A]
38+
object ConfiguredCodec:
39+
inline final def derive[A: Mirror.Of](): ConfiguredCodec[A] =
40+
derived[A](using Configuration.default)
41+
inline final def derived[A](using
42+
conf: Configuration,
43+
inline mirror: Mirror.Of[A]
44+
): ConfiguredCodec[A] = ${ derivedImpl[A]('conf, 'mirror) }
45+
def ofProduct[A](
46+
encoders: => List[Encoder[?]]
47+
)(using Configuration, Default[A]): ConfiguredCodec[A] = ???
48+
def derivedImpl[A: Type](conf: Expr[Configuration], mirror: Expr[Mirror.Of[A]])(using
49+
q: Quotes
50+
): Expr[ConfiguredCodec[A]] = {
51+
mirror match {
52+
case '{
53+
${ _ }: Mirror.ProductOf[A] {
54+
type MirroredLabel = l
55+
type MirroredElemLabels = el
56+
type MirroredElemTypes = et
57+
}
58+
} =>
59+
'{
60+
ConfiguredCodec.ofProduct[A](
61+
derivation.summonEncoders[et & Tuple](false)(using $conf)
62+
)(using $conf)
63+
}
64+
}
65+
}
66+
67+
object derivation:
68+
sealed trait Inliner[A, Arg]:
69+
inline def apply[T](inline arg: Arg): A
70+
71+
class EncoderNotDeriveSum(using config: Configuration) extends Inliner[Encoder[?], Unit]:
72+
inline def apply[T](inline arg: Unit): Encoder[?] = summonEncoder[T](false)
73+
74+
inline final def loopUnrolled[A, Arg, T <: Tuple](f: Inliner[A, Arg], inline arg: Arg): List[A] =
75+
inline erasedValue[T] match
76+
case _: EmptyTuple => Nil
77+
case _: (h *: ts) => f[h](arg) :: loopUnrolled[A, Arg, ts](f, arg)
78+
79+
inline def loopUnrolledNoArg[A, T <: Tuple](f: Inliner[A, Unit]): List[A] =
80+
loopUnrolled[A, Unit, T](f, ())
81+
82+
inline final def summonEncoders[T <: Tuple](inline derivingForSum: Boolean)(using
83+
Configuration
84+
): List[Encoder[?]] =
85+
loopUnrolledNoArg[Encoder[?], T](
86+
inline if (derivingForSum) compiletime.error("unreachable")
87+
else new EncoderNotDeriveSum
88+
)
89+
90+
private[circe] inline final def summonEncoder[A](
91+
inline derivingForSum: Boolean
92+
)(using Configuration): Encoder[A] = summonFrom {
93+
case encodeA: Encoder[A] => encodeA
94+
case _: Mirror.Of[A] =>
95+
inline if (derivingForSum) compiletime.error("unreachable")
96+
else error("Failed to find an instance of Encoder[]")
97+
}

tests/warn/i24034/iron.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
// iron.scala
3+
4+
package iron
5+
6+
import io.circe.*
7+
8+
opaque type IronType[A, C] <: A = A
9+
type :|[A, C] = IronType[A, C]
10+
trait Constraint[A, C]
11+
12+
package constraint:
13+
object string:
14+
final class StartWith[V <: String]
15+
object StartWith:
16+
inline given [V <: String]: Constraint[String, StartWith[V]] = ???
17+
18+
object circe:
19+
inline given XXX[A, B](using inline encoder: Encoder[A]): Encoder[A :| B] = ???
20+
inline given YYY[A, B](using inline encoder: Encoder[A], dummy: scala.util.NotGiven[DummyImplicit]): Encoder[A :| B] = ???
21+
// inline given [T](using mirror: RefinedTypeOps.Mirror[T], ev: Encoder[mirror.IronType]): Encoder[T] = ???
22+
23+
// trait RefinedTypeOps[A, C, T]:
24+
// inline given RefinedTypeOps.Mirror[T] = ???
25+
// object RefinedTypeOps:
26+
// trait Mirror[T]:
27+
// type BaseType
28+
// type ConstraintType
29+
// type IronType = BaseType :| ConstraintType
30+

tests/warn/i24034/test.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//> using options -Wunused:all
2+
3+
import io.circe.Codec
4+
5+
import iron.:|
6+
import iron.circe.given
7+
import iron.constraint.string.StartWith
8+
9+
case class Alien(name: String :| StartWith["alen"]) derives Codec.AsObject
10+

0 commit comments

Comments
 (0)